Completely fix tradeCattle folder

This commit is contained in:
xuqiuyun
2025-10-21 09:01:11 +08:00
parent 361d5ab1ae
commit 5fe7a5c48a
229 changed files with 23811 additions and 1 deletions

Submodule tradeCattle deleted from 30bb0dad3b

29
tradeCattle/.gitignore vendored Normal file
View File

@@ -0,0 +1,29 @@
# ---> Java
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*
/.idea/
/aiotagro-cattle-trade/target/
/aiotagro-core/target/

View File

@@ -0,0 +1,68 @@
# 数据库迁移:添加身份证字段
## 概述
`member_driver` 表添加 `id_card` 字段用于存储司机身份证前后面照片的URL地址。
## 字段信息
- **字段名**: `id_card`
- **数据类型**: `TEXT`
- **允许空值**: `YES`
- **默认值**: `NULL`
- **注释**: 身份证前后面照片地址多个URL用逗号分隔
- **位置**: 在 `car_img` 字段之后
## 执行步骤
### 方法1使用 MySQL 命令行
```bash
# 连接到数据库
mysql -h 129.211.213.226 -P 3306 -u root -p cattletrade
# 执行 SQL 脚本
source /path/to/add_id_card_field.sql
```
### 方法2使用 MySQL Workbench 或其他数据库管理工具
1. 连接到数据库服务器:`129.211.213.226:3306`
2. 选择数据库:`cattletrade`
3. 执行 `add_id_card_field.sql` 文件中的 SQL 语句
### 方法3直接在应用服务器上执行
```bash
# 在服务器上执行
mysql -h 129.211.213.226 -P 3306 -u root -p cattletrade < add_id_card_field.sql
```
## 验证
执行完成后,可以通过以下 SQL 验证字段是否添加成功:
```sql
-- 查看字段信息
SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_COMMENT
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'cattletrade'
AND TABLE_NAME = 'member_driver'
AND COLUMN_NAME = 'id_card';
-- 查看完整表结构
DESCRIBE member_driver;
```
## 注意事项
1. 执行前请备份数据库
2. 确保有足够的数据库权限
3. 建议在维护时间窗口执行
4. 执行后重启应用服务以确保更改生效
## 相关代码更改
此数据库更改配合以下代码更改:
- ✅ 后端 Mapper 层已更新,支持 `id_card` 字段的增删改查
- ✅ 后端 Controller 层已更新,处理 `idCard` 参数
- ✅ 前端表单已添加身份证图片上传组件
- ✅ 前端详情页面已添加身份证图片显示组件
## 回滚方案
如果需要回滚,可以执行:
```sql
ALTER TABLE member_driver DROP COLUMN id_card;
```

98
tradeCattle/README.md Normal file
View File

@@ -0,0 +1,98 @@
# 牛只交易管理系统
## 项目简介
牛只交易管理系统是一个基于 Spring Boot 的现代化交易管理平台,提供牛只交付管理、设备监控、用户权限管理等功能。系统采用前后端分离架构,后端使用 Spring Boot + MyBatis-Plus 技术栈,集成多种高效的第三方服务和组件。
## 技术栈
- **基础框架**Spring Boot 2.6.0
- **ORM 框架**MyBatis-Plus 3.5.3.2
- **权限认证**Sa-Token 1.37.0
- **数据库连接池**Druid
- **任务调度**XXL-Job
- **API 文档**Swagger Fox 3.0.0
- **工具库**Hutool 5.8.25
- **云服务**:腾讯云短信、对象存储服务
## 项目结构
```
tradeCattle
├── aiotagro-core // 核心模块
├── aiotagro-redis // Redis 操作模块
└── aiotagro-cattle-trade // 业务模块
├── controller // 控制器层
├── service // 服务层
├── mapper // 数据访问层
├── entity // 实体类
├── dto // 数据传输对象
├── vo // 视图对象
├── config // 配置类
└── constant // 常量定义
```
## 核心功能
1. **交付管理**
- 交付信息录入和管理
- 设备绑定和监控
- 交付状态追踪
2. **设备管理**
- 客户端设备管理JbqClient
- 服务器设备管理JbqServer
- 设备日志记录和监控
- 设备告警管理
3. **用户权限管理**
- 用户管理
- 角色管理
- 菜单权限管理
- 基于 Sa-Token 的认证授权
4. **系统监控**
- 设备运行状态监控
- 告警日志管理
- 系统操作日志
## 特色功能
- **短信通知**:集成腾讯云短信服务,支持验证码发送和通知推送
- **文件存储**:使用腾讯云对象存储服务,提供可靠的文件存储方案
- **任务调度**:集成 XXL-Job支持分布式任务调度
- **接口文档**:集成 Swagger Fox提供在线 API 文档和调试功能
## 项目配置
1. **数据库配置**
- 使用 Druid 数据库连接池
- 支持多数据源配置
2. **Redis 配置**
- 独立的 Redis 模块
- 支持缓存和会话管理
3. **权限配置**
- 基于 Sa-Token 的权限认证
- 支持多种登录方式
- 灵活的权限控制策略
## 开发环境要求
- JDK 8+
- Maven 3.6+
- MySQL 5.7+
- Redis 5.0+
## 部署说明
1. 克隆项目到本地
2. 配置数据库连接信息
3. 配置 Redis 连接信息
4. 配置腾讯云相关服务密钥
5. 执行数据库初始化脚本
6. 使用 Maven 打包项目
7. 部署运行
## 注意事项
- 确保已正确配置腾讯云服务相关密钥
- 注意数据库的字符集设置
- 建议在生产环境使用 Redis 集群
- 建议配置适当的日志级别和日志存储策略
## 版本信息
- 当前版本1.0.1
- 更新日期2024年

View File

@@ -0,0 +1,24 @@
-- =============================================
-- 数据库迁移脚本:为 member_driver 表添加 id_card 字段
-- 用途:存储司机身份证前后面照片地址
-- 创建时间2025-10-20
-- 数据库MySQL
-- =============================================
-- 为 member_driver 表添加 id_card 字段
-- 字段类型TEXT支持长文本
-- 位置:在 car_img 字段之后
-- 注释身份证前后面照片地址多个URL用逗号分隔
ALTER TABLE member_driver
ADD COLUMN id_card TEXT COMMENT '身份证前后面照片地址多个URL用逗号分隔'
AFTER car_img;
-- 验证字段是否添加成功
SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_COMMENT
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'member_driver'
AND COLUMN_NAME = 'id_card';
-- 显示完整的表结构
DESCRIBE member_driver;

View File

@@ -0,0 +1,80 @@
-- =============================================
-- 数据库迁移脚本:为 member_driver 表添加 id_card 字段
-- 用途:存储司机身份证前后面照片地址
-- 创建时间2025-10-20
-- 数据库MySQL
-- 版本:安全版本(包含错误处理)
-- =============================================
-- 开始事务
START TRANSACTION;
-- 检查表是否存在
SET @table_exists = (
SELECT COUNT(*)
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'member_driver'
);
-- 如果表不存在,回滚并退出
IF @table_exists = 0 THEN
ROLLBACK;
SELECT 'ERROR: member_driver 表不存在' AS result;
LEAVE;
END IF;
-- 检查字段是否已存在
SET @column_exists = (
SELECT COUNT(*)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'member_driver'
AND COLUMN_NAME = 'id_card'
);
-- 如果字段已存在,回滚并退出
IF @column_exists > 0 THEN
ROLLBACK;
SELECT 'WARNING: id_card 字段已存在,无需添加' AS result;
LEAVE;
END IF;
-- 添加 id_card 字段
ALTER TABLE member_driver
ADD COLUMN id_card TEXT COMMENT '身份证前后面照片地址多个URL用逗号分隔'
AFTER car_img;
-- 验证字段是否添加成功
SET @verify_result = (
SELECT COUNT(*)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'member_driver'
AND COLUMN_NAME = 'id_card'
);
-- 如果验证失败,回滚
IF @verify_result = 0 THEN
ROLLBACK;
SELECT 'ERROR: id_card 字段添加失败' AS result;
LEAVE;
END IF;
-- 提交事务
COMMIT;
-- 显示成功信息
SELECT 'SUCCESS: id_card 字段添加成功' AS result;
-- 显示字段信息
SELECT
COLUMN_NAME as '字段名',
DATA_TYPE as '数据类型',
IS_NULLABLE as '允许空值',
COLUMN_DEFAULT as '默认值',
COLUMN_COMMENT as '注释'
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'member_driver'
AND COLUMN_NAME = 'id_card';

View File

@@ -0,0 +1,24 @@
-- =============================================
-- 数据库迁移脚本:为 delivery 表添加 landing_entruck_weight 字段
-- 用途:存储约定单价(元/公斤)
-- 创建时间2025-01-27
-- 数据库MySQL
-- =============================================
-- 为 delivery 表添加 landing_entruck_weight 字段
-- 字段类型DECIMAL(10,2)支持小数点后2位
-- 位置:在 sale_price 字段之后
-- 注释:约定单价(元/公斤)
ALTER TABLE delivery
ADD COLUMN firm_price DECIMAL(10,2) COMMENT '约定单价(元/公斤)'
AFTER sale_price;
-- 验证字段是否添加成功
SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_DEFAULT, COLUMN_COMMENT
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'delivery'
AND COLUMN_NAME = 'firm_price';
-- 显示完整的表结构
DESCRIBE delivery;

View File

@@ -0,0 +1,264 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.aiotagro</groupId>
<artifactId>cattletrade</artifactId>
<version>1.0.1</version>
</parent>
<artifactId>aiotagro-cattletrade</artifactId>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
<spring-boot.version>2.6.13</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!--支持热部署 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- SpringBoot 依赖配置 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- FastDFS 分布式文件系统 -->
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
</dependency>
<!-- 阿里数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<!-- Mysql驱动包 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.4.0</version>
</dependency>
<!--- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!--pagehelper分页插件 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.7</version>
</dependency>
<!-- 解析客户端操作系统、浏览器等 -->
<dependency>
<groupId>eu.bitwalker</groupId>
<artifactId>UserAgentUtils</artifactId>
</dependency>
<!-- 获取系统信息 -->
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
</dependency>
<!-- io常用工具类 -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<!-- excel工具 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
<!-- JSON 解析器和生成器 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
</dependency>
<!-- 线程传递值 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
</dependency>
<!-- 提供Redis连接池 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<!-- aiotagro Common redis-->
<dependency>
<groupId>com.aiotagro</groupId>
<artifactId>aiotagro-redis</artifactId>
</dependency>
<!--Retrofit依赖-->
<dependency>
<groupId>com.github.lianjiatech</groupId>
<artifactId>retrofit-spring-boot-starter</artifactId>
</dependency>
<!--EasyExcel相关依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.0</version>
<exclusions>
<exclusion>
<artifactId>poi-ooxml-schemas</artifactId>
<groupId>org.apache.poi</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-miniapp</artifactId>
<version>3.3.0</version>
</dependency>
<!-- 扫呗sdk及工具对应版本-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.4.1</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<fork>true</fork>
<includeSystemScope>true</includeSystemScope>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>public</id>
<name>aliyun nexus</name>
<url>https://maven.aliyun.com/repository/public</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>public</id>
<name>aliyun nexus</name>
<url>https://maven.aliyun.com/repository/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>

View File

@@ -0,0 +1,22 @@
package com.aiotagro.cattletrade;
import cn.dev33.satoken.SaManager;
import com.mzt.logapi.starter.annotation.EnableLogRecord;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication(scanBasePackages = {"com.aiotagro.cattletrade", "com.aiotagro.common"})
@EnableTransactionManagement
@EnableScheduling
@EnableLogRecord(tenant = "com.aiotagro.cattletrade")
@MapperScan("com.aiotagro.cattletrade.domain.mapper")
public class AiotagroCattleTradeApplication {
public static void main(String[] args) {
SpringApplication.run(AiotagroCattleTradeApplication.class, args);
System.out.println(SaManager.getConfig());
}
}

View File

@@ -0,0 +1,42 @@
package com.aiotagro.cattletrade.business.controller;
import com.aiotagro.cattletrade.business.dto.FileDto;
import com.aiotagro.common.core.utils.TencentCloudUtil;
import com.aiotagro.common.core.web.domain.AjaxResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("/common")
public class CommonControl {
private static final Logger logger = LoggerFactory.getLogger(CommonControl.class);
/**
* 文件上传
*
* @param file
* @return
*/
@PostMapping("/upload")
public AjaxResult upload(@RequestParam("file") MultipartFile file) {
logger.info("文件上传...");
try {
String fileUrl = TencentCloudUtil.upload(file);
FileDto fileDto = new FileDto();
fileDto.setSrc(fileUrl);
return AjaxResult.success("上传成功!", fileDto);
} catch (Exception e) {
logger.error("图片上传异常", e);
}
return AjaxResult.error("上传失败!");
}
}

View File

@@ -0,0 +1,545 @@
package com.aiotagro.cattletrade.business.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.aiotagro.cattletrade.business.dto.DeliverListDto;
import com.aiotagro.cattletrade.business.dto.DeliveryAddDto;
import com.aiotagro.cattletrade.business.dto.DeliveryCreateDto;
import com.aiotagro.cattletrade.business.dto.DeliveryEditDto;
import com.aiotagro.cattletrade.business.dto.DeliveryQueryDto;
import com.aiotagro.cattletrade.business.dto.DeviceAssignDto;
import com.aiotagro.cattletrade.business.entity.Delivery;
import com.aiotagro.cattletrade.business.entity.DeliveryDevice;
import com.aiotagro.cattletrade.business.entity.JbqClient;
import com.aiotagro.cattletrade.business.entity.XqClient;
import com.aiotagro.cattletrade.business.service.IDeliveryService;
import com.aiotagro.cattletrade.business.service.IDeliveryDeviceService;
import com.aiotagro.cattletrade.business.service.IJbqClientService;
import com.aiotagro.cattletrade.business.service.IXqClientService;
import com.aiotagro.common.core.context.SecurityContextHolder;
import com.aiotagro.common.core.utils.SecurityUtil;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 运送清单表 前端控制器
*
* @author admin
* @since 2024-12-26
*/
@RestController
@RequestMapping("/delivery")
public class DeliveryController {
@Autowired
private IDeliveryService deliveryService;
@Autowired
private IDeliveryDeviceService deliveryDeviceService;
@Autowired
private IJbqClientService jbqClientService;
@Autowired
private IXqClientService xqClientService;
/**
* 小程序运送清单-分页查询
*
* @param dto
* @return
*/
@SaCheckPermission("delivery:list")
@PostMapping(value = "/pageQuery")
public PageResultResponse<Delivery> pageQuery(@RequestBody DeliveryQueryDto dto) {
return deliveryService.pageQuery(dto);
}
/**
* 小程序运送清单-我要装车
* @param dto
* @return
*/
@SaCheckPermission("delivery:add")
@PostMapping(value = "/add")
public AjaxResult add(@RequestBody DeliveryAddDto dto) {
try{
return deliveryService.addDelivery(dto);
}catch (Exception e){
e.printStackTrace();
return AjaxResult.error(e.getMessage());
}
}
/**
* 运送清单-创建PC端新增接口
* @param dto
* @return
*/
@SaCheckPermission("delivery:add")
@PostMapping(value = "/create")
public AjaxResult create(@Validated @RequestBody DeliveryCreateDto dto) {
try{
return deliveryService.createDelivery(dto);
}catch (Exception e){
e.printStackTrace();
return AjaxResult.error(e.getMessage());
}
}
/**
* 装车订单-新增PC端装车订单创建接口
* @param params
* @return
*/
@SaCheckPermission("delivery:add")
@PostMapping(value = "/addDeliveryOrder")
public AjaxResult addDeliveryOrder(@RequestBody Map<String, Object> params) {
try {
// 获取参数值
String deliveryTitle = (String) params.get("deliveryTitle");
Integer ratedQuantity = null;
if (params.get("ratedQuantity") != null) {
Object ratedQuantityObj = params.get("ratedQuantity");
if (ratedQuantityObj instanceof Integer) {
ratedQuantity = (Integer) ratedQuantityObj;
} else if (ratedQuantityObj instanceof String) {
try {
ratedQuantity = Integer.parseInt((String) ratedQuantityObj);
} catch (NumberFormatException e) {
return AjaxResult.error("装车数量格式不正确");
}
}
}
String supplierId = (String) params.get("supplierId");
Integer fundId = null;
if (params.get("fundId") != null) {
Object fundIdObj = params.get("fundId");
if (fundIdObj instanceof Integer) {
fundId = (Integer) fundIdObj;
} else if (fundIdObj instanceof String) {
try {
fundId = Integer.parseInt((String) fundIdObj);
} catch (NumberFormatException e) {
return AjaxResult.error("资金方ID格式不正确");
}
}
}
Integer driverId = null;
if (params.get("driverId") != null) {
Object driverIdObj = params.get("driverId");
if (driverIdObj instanceof Integer) {
driverId = (Integer) driverIdObj;
} else if (driverIdObj instanceof String) {
try {
driverId = Integer.parseInt((String) driverIdObj);
} catch (NumberFormatException e) {
return AjaxResult.error("司机ID格式不正确");
}
}
}
Integer buyerId = null;
if (params.get("buyerId") != null) {
Object buyerIdObj = params.get("buyerId");
if (buyerIdObj instanceof Integer) {
buyerId = (Integer) buyerIdObj;
} else if (buyerIdObj instanceof String) {
try {
buyerId = Integer.parseInt((String) buyerIdObj);
} catch (NumberFormatException e) {
return AjaxResult.error("采购商ID格式不正确");
}
}
}
Double buyerPrice = null;
if (params.get("buyerPrice") != null) {
Object buyerPriceObj = params.get("buyerPrice");
if (buyerPriceObj instanceof Double) {
buyerPrice = (Double) buyerPriceObj;
} else if (buyerPriceObj instanceof String) {
try {
buyerPrice = Double.parseDouble((String) buyerPriceObj);
} catch (NumberFormatException e) {
return AjaxResult.error("采购价格格式不正确");
}
}
}
Double salePrice = null;
if (params.get("salePrice") != null) {
Object salePriceObj = params.get("salePrice");
if (salePriceObj instanceof Double) {
salePrice = (Double) salePriceObj;
} else if (salePriceObj instanceof String) {
try {
salePrice = Double.parseDouble((String) salePriceObj);
} catch (NumberFormatException e) {
return AjaxResult.error("销售价格格式不正确");
}
}
}
Double firmPrice = null;
if (params.get("firmPrice") != null) {
Object firmPriceObj = params.get("firmPrice");
if (firmPriceObj instanceof Double) {
firmPrice = (Double) firmPriceObj;
} else if (firmPriceObj instanceof String) {
try {
firmPrice = Double.parseDouble((String) firmPriceObj);
} catch (NumberFormatException e) {
return AjaxResult.error("约定单价格式不正确");
}
}
}
String startLocation = (String) params.get("startLocation");
String startLat = null;
if (params.get("startLat") != null) {
Object startLatObj = params.get("startLat");
if (startLatObj instanceof String) {
startLat = (String) startLatObj;
} else if (startLatObj instanceof Double) {
startLat = String.valueOf((Double) startLatObj);
} else if (startLatObj instanceof Integer) {
startLat = String.valueOf((Integer) startLatObj);
}
}
String startLon = null;
if (params.get("startLon") != null) {
Object startLonObj = params.get("startLon");
if (startLonObj instanceof String) {
startLon = (String) startLonObj;
} else if (startLonObj instanceof Double) {
startLon = String.valueOf((Double) startLonObj);
} else if (startLonObj instanceof Integer) {
startLon = String.valueOf((Integer) startLonObj);
}
}
String endLocation = (String) params.get("endLocation");
String endLat = null;
if (params.get("endLat") != null) {
Object endLatObj = params.get("endLat");
if (endLatObj instanceof String) {
endLat = (String) endLatObj;
} else if (endLatObj instanceof Double) {
endLat = String.valueOf((Double) endLatObj);
} else if (endLatObj instanceof Integer) {
endLat = String.valueOf((Integer) endLatObj);
}
}
String endLon = null;
if (params.get("endLon") != null) {
Object endLonObj = params.get("endLon");
if (endLonObj instanceof String) {
endLon = (String) endLonObj;
} else if (endLonObj instanceof Double) {
endLon = String.valueOf((Double) endLonObj);
} else if (endLonObj instanceof Integer) {
endLon = String.valueOf((Integer) endLonObj);
}
}
// 参数验证
if (deliveryTitle == null || deliveryTitle.trim().isEmpty()) {
return AjaxResult.error("订单标题不能为空");
}
if (ratedQuantity == null || ratedQuantity <= 0) {
return AjaxResult.error("装车数量必须大于0");
}
if (startLocation == null || startLocation.trim().isEmpty()) {
return AjaxResult.error("起始地不能为空");
}
if (endLocation == null || endLocation.trim().isEmpty()) {
return AjaxResult.error("目的地不能为空");
}
// 获取当前登录用户
Integer userId = SecurityUtil.getCurrentUserId();
String userName = SecurityContextHolder.getUserName(); // 使用SecurityContextHolder获取用户名
// 生成运输单号
LocalDateTime now = LocalDateTime.now();
String deliveryNumber = "ZC" + now.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
// 创建装车订单
Delivery delivery = new Delivery();
delivery.setDeliveryNumber(deliveryNumber);
delivery.setDeliveryTitle(deliveryTitle);
delivery.setRatedQuantity(ratedQuantity);
delivery.setSupplierId(supplierId);
delivery.setFundId(fundId);
delivery.setDriverId(driverId);
delivery.setBuyerId(buyerId);
delivery.setBuyerPrice(buyerPrice);
delivery.setSalePrice(salePrice);
delivery.setFirmPrice(firmPrice);
delivery.setStartLocation(startLocation);
delivery.setStartLat(startLat);
delivery.setStartLon(startLon);
delivery.setEndLocation(endLocation);
delivery.setEndLat(endLat);
delivery.setEndLon(endLon);
delivery.setStatus(1); // 待装车
delivery.setCreatedBy(userId);
delivery.setCreateByName(userName);
delivery.setCreateTime(new Date());
// 保存装车订单
boolean saved = deliveryService.save(delivery);
if (!saved) {
return AjaxResult.error("创建装车订单失败");
}
return AjaxResult.success("装车订单创建成功");
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("创建装车订单失败:" + e.getMessage());
}
}
/**
* 运送清单-编辑PC端编辑接口
* @param dto
* @return
*/
@SaCheckPermission("delivery:edit")
@PostMapping(value = "/updateDeliveryInfo")
public AjaxResult updateDeliveryInfo(@Validated @RequestBody DeliveryEditDto dto) {
try{
return deliveryService.updateDeliveryInfo(dto);
}catch (Exception e){
e.printStackTrace();
return AjaxResult.error(e.getMessage());
}
}
/**
* 小程序运送清单-查询详情
* @param id
* @return
*/
@SaCheckPermission("delivery:view")
@GetMapping(value = "/view")
public AjaxResult view(@RequestParam Integer id) {
return deliveryService.viewDelivery(id);
}
/**
* 小程序运送清单-核验提交
* @param delivery
* @return
*/
@SaCheckPermission("delivery:check")
@PostMapping(value = "/submitCheck")
public AjaxResult submitCheck(@RequestBody Delivery delivery) {
try{
//查询当前的登录用户,即核验人
delivery.setCheckBy(SecurityUtil.getCurrentUserId());
delivery.setCheckTime(new Date());
delivery.setCheckByName(SecurityUtil.getUserName());
boolean b = deliveryService.updateById(delivery);
if(b){
return AjaxResult.success("核验提交成功!");
}else{
return AjaxResult.error("核验提交失败!");
}
}catch (Exception e){
return AjaxResult.error("核验提交失败!");
}
}
/**
* 后台系统运送清单-分页查询
*
* @param dto
* @return
*/
@SaCheckPermission("delivery:list")
@PostMapping(value = "/pageQueryList")
public PageResultResponse<Delivery> pageQueryList(@RequestBody DeliveryQueryDto dto) {
return deliveryService.pageQuery(dto);
}
/**
* 后台系统运送清单-分页查询(别名)
*
* @param dto
* @return
*/
@SaCheckPermission("delivery:list")
@PostMapping(value = "/pageDeliveryOrderList")
public PageResultResponse<Delivery> pageDeliveryOrderList(@RequestBody DeliverListDto dto) {
return deliveryService.pageQueryListLog(dto);
}
/**
* 后台运单详情
*/
@SaCheckPermission("delivery:view")
@GetMapping("/detail")
public AjaxResult detail(@RequestParam Integer id) {
return deliveryService.detail(id);
}
/**
* 查看运送订单详情(别名)
*/
@SaCheckPermission("delivery:view")
@GetMapping("/viewDeliveryOrder")
public AjaxResult viewDeliveryOrder(@RequestParam Integer deliveryId) {
return deliveryService.detail(deliveryId);
}
/**
* 测试司机信息查询
*/
@GetMapping("/testDriverQuery/{deliveryId}")
public AjaxResult testDriverQuery(@PathVariable("deliveryId") Integer deliveryId) {
try {
System.out.println("测试司机信息查询deliveryId: " + deliveryId);
AjaxResult result = deliveryService.detail(deliveryId);
System.out.println("查询结果: " + result);
return result;
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("测试失败: " + e.getMessage());
}
}
/**
* 分配设备(支持智能耳标和智能项圈)
* @param dto
* @return
*/
@SaCheckPermission("delivery:assign")
@PostMapping(value = "/arrangeJbq")
public AjaxResult arrangeJbq(@RequestBody DeviceAssignDto dto) {
try {
if (dto.getDeviceIds() == null || dto.getDeviceIds().isEmpty()) {
return AjaxResult.error("请选择要分配的设备");
}
// 按设备类型分组
Map<Integer, List<DeviceAssignDto.DeviceInfo>> deviceGroups = dto.getDeviceIds().stream()
.collect(Collectors.groupingBy(DeviceAssignDto.DeviceInfo::getDeviceTypeId));
// 处理每种设备类型
for (Map.Entry<Integer, List<DeviceAssignDto.DeviceInfo>> entry : deviceGroups.entrySet()) {
Integer deviceType = entry.getKey();
List<DeviceAssignDto.DeviceInfo> devices = entry.getValue();
// 先删除该运单的现有设备分配(按设备类型)
deliveryDeviceService.lambdaUpdate()
.eq(DeliveryDevice::getDeliveryId, dto.getDeliveryId())
.eq(DeliveryDevice::getDeviceType, deviceType)
.remove();
// 添加新的设备分配
for (DeviceAssignDto.DeviceInfo deviceInfo : devices) {
DeliveryDevice deliveryDevice = new DeliveryDevice();
deliveryDevice.setDeliveryId(dto.getDeliveryId());
deliveryDevice.setDeviceId(deviceInfo.getDeviceId());
deliveryDevice.setDeviceType(deviceType);
deliveryDeviceService.save(deliveryDevice);
// 更新设备的运单号和车牌号
updateDeviceDeliveryInfo(deviceInfo.getDeviceId(), deviceType, dto.getDeliveryId(), dto.getLicensePlate());
}
}
return AjaxResult.success("设备分配成功!");
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("设备分配失败:" + e.getMessage());
}
}
/**
* 更新设备的运单号和车牌号
*/
private void updateDeviceDeliveryInfo(String deviceId, Integer deviceType, Integer deliveryId, String licensePlate) {
try {
// 获取运单号
Delivery delivery = deliveryService.getById(deliveryId);
String deliveryNumber = delivery != null ? delivery.getDeliveryNumber() : "";
if (deviceType == 2) {
// 更新智能耳标
LambdaUpdateWrapper<JbqClient> jbqUpdateWrapper = new LambdaUpdateWrapper<>();
jbqUpdateWrapper.eq(JbqClient::getDeviceId, deviceId);
jbqUpdateWrapper.set(JbqClient::getDeliveryNumber, deliveryNumber);
jbqUpdateWrapper.set(JbqClient::getLicensePlate, licensePlate);
jbqClientService.update(jbqUpdateWrapper);
} else if (deviceType == 3) {
// 更新智能项圈 - 兼容deviceId和sn两种字段
LambdaUpdateWrapper<XqClient> xqUpdateWrapper = new LambdaUpdateWrapper<>();
xqUpdateWrapper.and(w -> w.eq(XqClient::getDeviceId, deviceId)
.or()
.eq(XqClient::getSn, Long.parseLong(deviceId)));
xqUpdateWrapper.set(XqClient::getDeliveryId, deliveryId);
xqUpdateWrapper.set(XqClient::getDeliveryNumber, deliveryNumber);
xqUpdateWrapper.set(XqClient::getLicensePlate, licensePlate);
xqClientService.update(xqUpdateWrapper);
}
} catch (Exception e) {
System.out.println("更新设备运单信息失败: " + e.getMessage());
e.printStackTrace();
}
}
/**
* 更新运单状态
*/
@SaCheckPermission("delivery:status")
@PostMapping("/updateStatus")
public AjaxResult updateStatus(@RequestBody Map<String, Object> params) {
try {
Integer id = (Integer) params.get("id");
Integer status = (Integer) params.get("status");
if (id == null || status == null) {
return AjaxResult.error("运单ID和状态不能为空");
}
Delivery delivery = new Delivery();
delivery.setId(id);
delivery.setStatus(status);
boolean success = deliveryService.updateById(delivery);
if (success) {
return AjaxResult.success("状态更新成功");
} else {
return AjaxResult.error("状态更新失败");
}
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("状态更新失败:" + e.getMessage());
}
}
}

View File

@@ -0,0 +1,153 @@
package com.aiotagro.cattletrade.business.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.aiotagro.cattletrade.business.entity.DeliveryDevice;
import com.aiotagro.cattletrade.business.entity.JbqClient;
import com.aiotagro.cattletrade.business.entity.XqClient;
import com.aiotagro.cattletrade.business.service.IDeliveryDeviceService;
import com.aiotagro.cattletrade.business.service.IJbqClientService;
import com.aiotagro.cattletrade.business.service.IXqClientService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.aiotagro.common.core.web.domain.AjaxResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* <p>
* 运单设备表 前端控制器
* </p>
*
* @author admin
* @since 2024-12-26
*/
@RestController
@RequestMapping("/deliveryDevice")
public class DeliveryDeviceController {
@Autowired
private IDeliveryDeviceService deliveryDeviceService;
@Autowired
private IJbqClientService jbqClientService;
@Autowired
private IXqClientService xqClientService;
/**
* 根据运送清单ID查询耳标列表
*/
@SaCheckPermission("delivery:view")
@PostMapping(value = "/pageJbqList")
public AjaxResult pageJbqList(@RequestBody Map<String, Object> params) {
Integer deliveryId = (Integer) params.get("deliveryId");
return jbqClientService.getDevicesByDeliveryId(deliveryId, 2); // 2表示耳标类型
}
/**
* 根据运送清单ID查询所有设备列表耳标+项圈)
*/
@SaCheckPermission("delivery:view")
@PostMapping(value = "/pageDeviceList")
public AjaxResult pageDeviceList(@RequestBody Map<String, Object> params) {
Integer deliveryId = (Integer) params.get("deliveryId");
if (deliveryId == null) {
return AjaxResult.error("运送清单ID不能为空");
}
List<Map<String, Object>> allDevices = new ArrayList<>();
try {
// 查询delivery_device表中的图片数据
LambdaQueryWrapper<DeliveryDevice> deliveryDeviceWrapper = new LambdaQueryWrapper<>();
deliveryDeviceWrapper.eq(DeliveryDevice::getDeliveryId, deliveryId);
List<DeliveryDevice> deliveryDevices = deliveryDeviceService.list(deliveryDeviceWrapper);
// 创建设备ID到图片数据的映射
Map<String, DeliveryDevice> deviceImageMap = new HashMap<>();
for (DeliveryDevice dd : deliveryDevices) {
deviceImageMap.put(dd.getDeviceId(), dd);
}
// 查询耳标设备
AjaxResult earTagResult = jbqClientService.getDevicesByDeliveryId(deliveryId, 2);
if (earTagResult.get("code").equals(200) && earTagResult.get("data") != null) {
Object earDataObj = earTagResult.get("data");
List<JbqClient> earTagDevices;
if (earDataObj instanceof Map) {
Map<String, Object> earTagData = (Map<String, Object>) earDataObj;
earTagDevices = (List<JbqClient>) earTagData.get("rows");
} else {
earTagDevices = (List<JbqClient>) earDataObj; // 兼容空列表直接返回的情况
}
for (JbqClient device : earTagDevices) {
Map<String, Object> deviceMap = new HashMap<>();
deviceMap.put("deviceId", device.getDeviceId());
deviceMap.put("deviceType", "2");
deviceMap.put("deviceTypeName", "智能耳标");
deviceMap.put("deviceVoltage", device.getDeviceVoltage());
deviceMap.put("deviceTemp", device.getDeviceTemp());
deviceMap.put("latitude", device.getLatitude());
deviceMap.put("longitude", device.getLongitude());
deviceMap.put("walkSteps", device.getWalkSteps());
deviceMap.put("yWalkSteps", device.getYWalkSteps());
deviceMap.put("isWare", "0"); // 耳标默认未佩戴
// 获取实际的图片数据
DeliveryDevice deviceImages = deviceImageMap.get(device.getDeviceId());
deviceMap.put("frontImg", deviceImages != null ? deviceImages.getFrontImg() : "");
deviceMap.put("sideImg", deviceImages != null ? deviceImages.getSideImg() : "");
deviceMap.put("hipImg", deviceImages != null ? deviceImages.getHipImg() : "");
allDevices.add(deviceMap);
}
}
// 查询项圈设备
AjaxResult collarResult = xqClientService.getDevicesByDeliveryId(deliveryId, 3);
if (collarResult.get("code").equals(200) && collarResult.get("data") != null) {
Object collarDataObj = collarResult.get("data");
List<XqClient> collarDevices;
if (collarDataObj instanceof Map) {
Map<String, Object> collarData = (Map<String, Object>) collarDataObj;
collarDevices = (List<XqClient>) collarData.get("rows");
} else {
collarDevices = (List<XqClient>) collarDataObj; // 兼容空列表直接返回的情况
}
for (XqClient device : collarDevices) {
Map<String, Object> deviceMap = new HashMap<>();
String deviceId = device.getSn() != null ? device.getSn().toString() : device.getDeviceId();
deviceMap.put("deviceId", deviceId);
deviceMap.put("deviceType", "3");
deviceMap.put("deviceTypeName", "智能项圈");
deviceMap.put("battery", device.getBattery());
deviceMap.put("temperature", device.getTemperature());
deviceMap.put("latitude", device.getLatitude());
deviceMap.put("longitude", device.getLongitude());
deviceMap.put("steps", device.getSteps());
deviceMap.put("ySteps", device.getYSteps());
deviceMap.put("isWare", device.getIsWear() != null ? device.getIsWear().toString() : "0");
// 获取实际的图片数据
DeliveryDevice deviceImages = deviceImageMap.get(deviceId);
deviceMap.put("frontImg", deviceImages != null ? deviceImages.getFrontImg() : "");
deviceMap.put("sideImg", deviceImages != null ? deviceImages.getSideImg() : "");
deviceMap.put("hipImg", deviceImages != null ? deviceImages.getHipImg() : "");
allDevices.add(deviceMap);
}
}
return AjaxResult.success(allDevices);
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("查询设备列表失败:" + e.getMessage());
}
}
}

View File

@@ -0,0 +1,147 @@
package com.aiotagro.cattletrade.business.controller;
import com.aiotagro.cattletrade.business.dto.DeviceDto;
import com.aiotagro.cattletrade.business.entity.JbqClient;
import com.aiotagro.cattletrade.business.entity.DeliveryDevice;
import com.aiotagro.cattletrade.business.mapper.DeliveryDeviceMapper;
import com.aiotagro.cattletrade.business.service.IJbqClientService;
import com.aiotagro.cattletrade.business.service.IDeliveryDeviceService;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.stream.Collectors;
/**
* <p>
* 智能耳标表 前端控制器
* </p>
*
* @author admin
* @since 2024-12-26
*/
@RestController
@RequestMapping("/jbqClient")
public class JbqClientController {
@Autowired
private IJbqClientService jbqClientService;
@Autowired
private IDeliveryDeviceService deliveryDeviceService;
@Autowired
private DeliveryDeviceMapper deliveryDeviceMapper;
/**
* 查询分页列表
*/
@PostMapping(value = "/list")
public PageResultResponse jbqList(@RequestBody DeviceDto dto) {
return jbqClientService.jbqList(dto);
}
/**
* 根据运送清单ID查询耳标列表
*/
@PostMapping(value = "/pageJbqListByDeliveryId")
public AjaxResult pageJbqListByDeliveryId(@RequestBody Map<String, Object> params) {
Object deliveryIdObj = params.get("deliveryId");
Integer deliveryId = null;
if (deliveryIdObj != null) {
if (deliveryIdObj instanceof Integer) {
deliveryId = (Integer) deliveryIdObj;
} else if (deliveryIdObj instanceof String) {
deliveryId = Integer.valueOf((String) deliveryIdObj);
}
}
return jbqClientService.getDevicesByDeliveryId(deliveryId, 2); // 2表示耳标类型
}
/**
* 测试查询运单设备关联
*/
@PostMapping(value = "/testDeliveryDevices")
public AjaxResult testDeliveryDevices(@RequestBody Map<String, Object> params) {
Object deliveryIdObj = params.get("deliveryId");
Integer deliveryId = null;
if (deliveryIdObj != null) {
if (deliveryIdObj instanceof Integer) {
deliveryId = (Integer) deliveryIdObj;
} else if (deliveryIdObj instanceof String) {
deliveryId = Integer.valueOf((String) deliveryIdObj);
}
}
System.out.println("=== 测试查询运单设备关联deliveryId: " + deliveryId);
if (deliveryId == null) {
return AjaxResult.error("运送清单ID不能为空");
}
// 查询所有设备类型
LambdaQueryWrapper<DeliveryDevice> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DeliveryDevice::getDeliveryId, deliveryId);
List<DeliveryDevice> allDevices = deliveryDeviceMapper.selectList(wrapper);
System.out.println("=== 运单 " + deliveryId + " 关联的所有设备记录数: " + allDevices.size());
for (DeliveryDevice device : allDevices) {
System.out.println("=== 设备记录: " + device);
}
// 按设备类型分组
Map<Integer, List<DeliveryDevice>> devicesByType = allDevices.stream()
.collect(Collectors.groupingBy(DeliveryDevice::getDeviceType));
Map<String, Object> result = new HashMap<>();
result.put("totalDevices", allDevices.size());
result.put("devicesByType", devicesByType);
result.put("allDevices", allDevices);
return AjaxResult.success(result);
}
/**
* 测试查询未分配设备
*/
@PostMapping(value = "/testUnassigned")
public AjaxResult testUnassigned(@RequestBody Map<String, Object> params) {
try {
System.out.println("测试查询未分配智能耳标,参数: " + params);
// 直接查询jbq_client表
LambdaQueryWrapper<JbqClient> wrapper = new LambdaQueryWrapper<>();
List<JbqClient> devices = jbqClientService.list(wrapper);
System.out.println("智能耳标总数: " + devices.size());
// 查询已分配的设备ID
LambdaQueryWrapper<DeliveryDevice> deliveryWrapper = new LambdaQueryWrapper<>();
deliveryWrapper.eq(DeliveryDevice::getDeviceType, 2);
List<DeliveryDevice> assignedDevices = deliveryDeviceService.list(deliveryWrapper);
System.out.println("已分配智能耳标数量: " + assignedDevices.size());
// 筛选未分配的设备
List<String> assignedDeviceIds = assignedDevices.stream()
.map(DeliveryDevice::getDeviceId)
.collect(Collectors.toList());
List<JbqClient> unassignedDevices = devices.stream()
.filter(device -> !assignedDeviceIds.contains(device.getDeviceId()))
.collect(Collectors.toList());
System.out.println("未分配智能耳标数量: " + unassignedDevices.size());
return AjaxResult.success("测试成功", unassignedDevices);
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("测试失败: " + e.getMessage());
}
}
}

View File

@@ -0,0 +1,34 @@
package com.aiotagro.cattletrade.business.controller;
import com.aiotagro.cattletrade.business.dto.JbqLogDto;
import com.aiotagro.cattletrade.business.service.IJbqClientLogService;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* <p>
* 智能耳标日志表 前端控制器
* </p>
*
* @author admin
* @since 2024-12-26
*/
@RestController
@RequestMapping("/jbqClientLog")
public class JbqClientLogController {
@Autowired
private IJbqClientLogService jbqClientLogService;
/**
* 查询分页列表
*/
@PostMapping(value = "/jbqLogList")
public PageResultResponse jbqList(@RequestBody JbqLogDto dto) {
return jbqClientLogService.jbqLogList(dto);
}
}

View File

@@ -0,0 +1,114 @@
package com.aiotagro.cattletrade.business.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.aiotagro.cattletrade.business.service.IJbqServerService;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* 主机设备控制器
*
* @author System
* @date 2025-01-16
*/
@RestController
@RequestMapping("/jbqServer")
public class JbqServerController {
@Autowired
private IJbqServerService jbqServerService;
/**
* 主机设备列表查询
*/
@SaCheckPermission("delivery:view")
@PostMapping("/jbqCheckList")
public PageResultResponse<Map<String, Object>> jbqCheckList(@RequestBody Map<String, Object> params) {
try {
Integer pageNum = params.get("pageNum") != null ? (Integer) params.get("pageNum") : 1;
Integer pageSize = params.get("pageSize") != null ? (Integer) params.get("pageSize") : 10;
String deviceId = (String) params.get("deviceId");
Page<Map<String, Object>> result = PageHelper.startPage(pageNum, pageSize);
// 查询主机设备列表
// 这里可以根据实际需求实现主机设备查询逻辑
// 暂时返回空列表,避免编译错误
return new PageResultResponse<>(0L, java.util.Collections.emptyList());
} catch (Exception e) {
e.printStackTrace();
return new PageResultResponse<>(0L, java.util.Collections.emptyList());
}
}
@SaCheckPermission("delivery:view")
@PostMapping("/serverList")
public PageResultResponse<Map<String, Object>> serverList(@RequestBody Map<String, Object> params) {
try {
Integer pageNum = params.get("pageNum") != null ? (Integer) params.get("pageNum") : 1;
Integer pageSize = params.get("pageSize") != null ? (Integer) params.get("pageSize") : 10;
String deviceId = (String) params.get("deviceId");
Page<Map<String, Object>> result = PageHelper.startPage(pageNum, pageSize);
// 调用服务层查询主机设备列表
com.aiotagro.cattletrade.business.dto.DeviceDto dto = new com.aiotagro.cattletrade.business.dto.DeviceDto();
dto.setDeviceId(deviceId);
PageResultResponse response = jbqServerService.serverList(dto);
return response;
} catch (Exception e) {
e.printStackTrace();
return new PageResultResponse<>(0L, java.util.Collections.emptyList());
}
}
/**
* 查询分页列表(通用)
*/
@PostMapping(value = "/pageQuery")
public PageResultResponse pageQuery(@RequestBody Map<String, Object> params) {
try {
Integer pageNum = params.get("pageNum") != null ? (Integer) params.get("pageNum") : 1;
Integer pageSize = params.get("pageSize") != null ? (Integer) params.get("pageSize") : 10;
String deviceId = (String) params.get("deviceId");
Page<Map<String, Object>> result = PageHelper.startPage(pageNum, pageSize);
// 调用服务层查询主机设备列表
com.aiotagro.cattletrade.business.dto.DeviceDto dto = new com.aiotagro.cattletrade.business.dto.DeviceDto();
dto.setDeviceId(deviceId);
dto.setPageNum(pageNum);
dto.setPageSize(pageSize);
PageResultResponse response = jbqServerService.serverList(dto);
return response;
} catch (Exception e) {
e.printStackTrace();
return new PageResultResponse<>(0L, java.util.Collections.emptyList());
}
}
/**
* 测试智能主机查询
*/
@GetMapping("/testServerList")
public AjaxResult testServerList() {
try {
System.out.println("Testing server list query");
com.aiotagro.cattletrade.business.dto.DeviceDto dto = new com.aiotagro.cattletrade.business.dto.DeviceDto();
PageResultResponse response = jbqServerService.serverList(dto);
System.out.println("Server list query completed");
return AjaxResult.success("测试结果", response);
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("测试失败: " + e.getMessage());
}
}
}

View File

@@ -0,0 +1,20 @@
package com.aiotagro.cattletrade.business.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 智能主机日志表 前端控制器
* </p>
*
* @author admin
* @since 2024-12-26
*/
@RestController
@RequestMapping("/jbqServerLog")
public class JbqServerLogController {
}

View File

@@ -0,0 +1,65 @@
package com.aiotagro.cattletrade.business.controller;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.stp.StpUtil;
import com.aiotagro.cattletrade.business.dto.LoginDto;
import com.aiotagro.cattletrade.business.service.LoginService;
import com.aiotagro.common.core.web.domain.AjaxResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* 登录
*/
@RestController
public class LoginControl {
@Resource
private LoginService loginService;
/**
* 获取登录验证码
*/
@SaIgnore
@GetMapping("/sendLoginSmsCode")
public AjaxResult sendLoginSmsCode(@RequestParam String mobile) {
return loginService.sendLoginSmsCode(mobile);
}
/**
* 登录
*/
@SaIgnore
@PostMapping("/login")
public AjaxResult login(@Validated @RequestBody LoginDto dto) {
return loginService.login(dto);
}
/**
* 根据登录用户获取菜单列表
**/
@GetMapping("/getUserMenus")
public AjaxResult getUserMenus() {
return loginService.getUserMenus();
}
/**
* 退出登录
*/
@GetMapping("/logout")
public AjaxResult logout() {
StpUtil.logout();
return AjaxResult.success("退出成功");
}
/**
* 小程序我的
**/
@GetMapping("/getUserInfo")
public AjaxResult getUserInfo() {
return loginService.getUserInfo();
}
}

View File

@@ -0,0 +1,655 @@
package com.aiotagro.cattletrade.business.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.crypto.digest.DigestUtil;
import com.aiotagro.cattletrade.business.entity.SysRole;
import com.aiotagro.cattletrade.business.entity.SysUser;
import com.aiotagro.cattletrade.business.mapper.MemberDriverMapper;
import com.aiotagro.cattletrade.business.mapper.MemberMapper;
import com.aiotagro.cattletrade.business.mapper.SysRoleMapper;
import com.aiotagro.cattletrade.business.mapper.SysUserMapper;
import com.aiotagro.common.core.constant.Constants;
import com.aiotagro.common.core.utils.SecurityUtil;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.transaction.annotation.Transactional;
/**
* 会员用户控制器
*
* @author System
* @date 2025-01-16
*/
@RestController
@RequestMapping("/member")
public class MemberController {
@Resource
private SysUserMapper sysUserMapper;
@Resource
private MemberDriverMapper memberDriverMapper;
@Resource
private MemberMapper memberMapper;
@Resource
private SysRoleMapper sysRoleMapper;
/**
* 获取用户列表(用于权限分配)
*/
@SaCheckPermission("permission:menu:list")
@GetMapping("/userList")
public AjaxResult getUserList() {
// 查询所有用户从sys_user表
List<SysUser> userList = sysUserMapper.selectUserListForPermission();
return AjaxResult.success(userList);
}
/**
* 获取用户列表(分页,用于用户管理页面)
* 查询member表和member_user表关联数据
*/
@PostMapping("/userList")
public PageResultResponse<Map<String, Object>> getUserListWithPagination(@RequestBody Map<String, Object> params) {
try {
Integer pageNum = params.get("pageNum") != null ? (Integer) params.get("pageNum") : 1;
Integer pageSize = params.get("pageSize") != null ? (Integer) params.get("pageSize") : 10;
String username = (String) params.get("username");
String mobile = (String) params.get("mobile");
Integer type = params.get("type") != null ? (Integer) params.get("type") : null;
Boolean usernameExact = params.get("usernameExact") != null ? (Boolean) params.get("usernameExact") : false;
Boolean mobileExact = params.get("mobileExact") != null ? (Boolean) params.get("mobileExact") : false;
// 计算偏移量
Integer offset = (pageNum - 1) * pageSize;
// 查询用户列表从member表和member_user表
List<Map<String, Object>> userList = memberMapper.selectUserListForManagement(username, mobile, type, usernameExact, mobileExact, offset, pageSize);
// 查询总数
Long total = memberMapper.countUserListForManagement(username, mobile, type, usernameExact, mobileExact);
return new PageResultResponse<>(total, userList);
} catch (Exception e) {
e.printStackTrace();
return new PageResultResponse<>(0L, java.util.Collections.emptyList());
}
}
/**
* 新增司机
*/
@PostMapping("/addDriver")
public AjaxResult addDriver(@RequestBody Map<String, Object> params) {
try {
// 获取参数值
String username = (String) params.get("username");
String mobile = (String) params.get("mobile");
String carNumber = (String) params.get("carNumber");
String driverLicense = (String) params.get("driverLicense");
String drivingLicense = (String) params.get("drivingLicense");
String carImg = (String) params.get("carImg");
String recordCode = (String) params.get("recordCode");
String idCard = (String) params.get("idCard");
String remark = (String) params.get("remark");
Integer status = params.get("status") != null ? (Integer) params.get("status") : 0; // 默认启用
// 参数验证
if (mobile == null || mobile.trim().isEmpty()) {
return AjaxResult.error("手机号不能为空");
}
if (username == null || username.trim().isEmpty()) {
return AjaxResult.error("司机姓名不能为空");
}
// 检查手机号是否已存在
Integer existingMemberId = memberMapper.selectMemberIdByMobile(mobile);
if (existingMemberId != null) {
return AjaxResult.error("该手机号已存在");
}
// 先插入member表
int memberResult = memberMapper.insertMember(mobile, 1, status); // type=1表示司机
if (memberResult <= 0) {
return AjaxResult.error("司机基础信息插入失败");
}
// 获取刚插入的member记录的ID
Integer memberId = memberMapper.selectMemberIdByMobile(mobile);
if (memberId == null) {
return AjaxResult.error("获取新司机ID失败");
}
// 插入member_driver表
int driverResult = memberDriverMapper.insertDriver(memberId, username, carNumber,
driverLicense, drivingLicense, carImg, recordCode, idCard, remark);
if (driverResult <= 0) {
return AjaxResult.error("司机详细信息插入失败");
}
return AjaxResult.success("司机新增成功");
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("新增司机失败:" + e.getMessage());
}
}
/**
* 获取司机列表(分页)
*/
@PostMapping("/driverList")
public PageResultResponse<Map<String, Object>> driverList(@RequestBody Map<String, Object> params) {
Integer pageNum = params.get("pageNum") != null ? (Integer) params.get("pageNum") : 1;
Integer pageSize = params.get("pageSize") != null ? (Integer) params.get("pageSize") : 10;
String username = (String) params.get("username");
String mobile = (String) params.get("mobile");
// 添加调试日志
System.out.println("DriverList API called with params:");
System.out.println("username: " + username);
System.out.println("mobile: " + mobile);
Page<Map<String, Object>> result = PageHelper.startPage(pageNum, pageSize);
List<Map<String, Object>> list;
// 如果只查询手机号,使用简化的精确查询
if (mobile != null && !mobile.trim().isEmpty() && (username == null || username.trim().isEmpty())) {
System.out.println("Using mobile-only search method");
list = memberDriverMapper.selectDriverListByMobile(mobile);
} else if ((username != null && !username.trim().isEmpty()) || (mobile != null && !mobile.trim().isEmpty())) {
System.out.println("Using combined search method");
list = memberDriverMapper.selectDriverListBySearch(username, mobile, true);
} else {
System.out.println("Using default list method");
list = memberDriverMapper.selectDriverList();
}
System.out.println("Found " + list.size() + " drivers");
return new PageResultResponse<>(result.getTotal(), list);
}
@PostMapping("/memberListByType")
public PageResultResponse<Map<String, Object>> getMemberListByType(@RequestBody Map<String, Object> params) {
Integer pageNum = params.get("pageNum") != null ? (Integer) params.get("pageNum") : 1;
Integer pageSize = params.get("pageSize") != null ? (Integer) params.get("pageSize") : 10;
String username = (String) params.get("username");
Integer type = params.get("type") != null ? (Integer) params.get("type") : null;
// 计算偏移量
Integer offset = (pageNum - 1) * pageSize;
// 查询数据
List<Map<String, Object>> list = memberMapper.selectMemberListByType(type, username, offset, pageSize);
// 查询总数
Long total = memberMapper.countMemberListByType(type, username);
return new PageResultResponse<>(total, list);
}
/**
* 插入测试数据(仅用于开发测试)
*/
@PostMapping("/insertTestData")
public AjaxResult insertTestData() {
try {
// 这里可以添加插入测试数据的逻辑
// 由于没有直接的SQL执行方法我们返回成功信息
return AjaxResult.success("测试数据插入功能已准备就绪请手动执行SQL脚本");
} catch (Exception e) {
return AjaxResult.error("插入测试数据失败: " + e.getMessage());
}
}
/**
* 调试接口直接查询member表数据
*/
@GetMapping("/debugMemberData")
public AjaxResult debugMemberData() {
try {
// 直接查询member表的所有数据
List<Map<String, Object>> allMembers = memberMapper.selectMemberUserList();
return AjaxResult.success("member表数据", allMembers);
} catch (Exception e) {
return AjaxResult.error("查询失败: " + e.getMessage());
}
}
/**
* 更新司机信息
*/
@SaCheckPermission("member:edit")
@PostMapping("/updateDriver")
public AjaxResult updateDriver(@RequestBody Map<String, Object> params) {
try {
Integer id = (Integer) params.get("id");
if (id == null) {
return AjaxResult.error("司机ID不能为空");
}
// 获取参数值
String username = (String) params.get("username");
String carNumber = (String) params.get("carNumber");
String driverLicense = (String) params.get("driverLicense");
String drivingLicense = (String) params.get("drivingLicense");
String carImg = (String) params.get("carImg");
String recordCode = (String) params.get("recordCode");
String idCard = (String) params.get("idCard");
String remark = (String) params.get("remark");
// 执行更新
int result = memberDriverMapper.updateDriver(id, username, carNumber, driverLicense,
drivingLicense, carImg, recordCode, idCard, remark);
if (result > 0) {
return AjaxResult.success("司机信息更新成功");
} else {
return AjaxResult.error("司机信息更新失败");
}
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("更新司机信息失败:" + e.getMessage());
}
}
/**
* 更新用户信息
*/
@SaCheckPermission("member:edit")
@PostMapping("/updateUser")
public AjaxResult updateUser(@RequestBody Map<String, Object> params) {
try {
Integer id = (Integer) params.get("id");
if (id == null) {
return AjaxResult.error("用户ID不能为空");
}
// 获取参数值
String mobile = (String) params.get("mobile");
Integer type = params.get("type") != null ? (Integer) params.get("type") : null;
Integer status = params.get("status") != null ? (Integer) params.get("status") : null;
String username = (String) params.get("username");
String cbkAccount = (String) params.get("cbkAccount");
String remark = (String) params.get("remark");
// 执行更新
int result = memberMapper.updateUserInfo(id, mobile, type, status, username, cbkAccount, remark);
if (result > 0) {
return AjaxResult.success("用户信息更新成功");
} else {
return AjaxResult.error("用户信息更新失败");
}
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("更新用户信息失败:" + e.getMessage());
}
}
/**
* 新增用户
*/
@PostMapping("/addUser")
@Transactional
public AjaxResult addUser(@RequestBody Map<String, Object> params) {
try {
// 获取参数值
String mobile = (String) params.get("mobile");
Integer type = params.get("type") != null ? (Integer) params.get("type") : null;
Integer status = params.get("status") != null ? (Integer) params.get("status") : 0; // 默认启用
String username = (String) params.get("username");
String cbkAccount = (String) params.get("cbkAccount");
String remark = (String) params.get("remark");
// 参数验证
if (mobile == null || mobile.trim().isEmpty()) {
return AjaxResult.error("手机号不能为空");
}
if (username == null || username.trim().isEmpty()) {
return AjaxResult.error("用户姓名不能为空");
}
if (type == null) {
return AjaxResult.error("用户类型不能为空");
}
// 检查手机号是否已存在直接查询member表
Integer existingMemberId = memberMapper.selectMemberIdByMobile(mobile);
if (existingMemberId != null) {
return AjaxResult.error("该手机号已存在");
}
// 先插入member表
int memberResult = memberMapper.insertMember(mobile, type, status);
if (memberResult <= 0) {
return AjaxResult.error("用户基础信息插入失败");
}
// 获取刚插入的member记录的ID通过查询最新记录
Integer memberId = memberMapper.selectMemberIdByMobile(mobile);
if (memberId == null) {
return AjaxResult.error("获取新用户ID失败");
}
// 再插入member_user表
int userResult = memberMapper.insertMemberUser(memberId, username, cbkAccount, remark);
if (userResult <= 0) {
return AjaxResult.error("用户详细信息插入失败");
}
// 自动创建员工记录
try {
createEmployeeRecord(username, mobile, type, status);
} catch (Exception e) {
// 员工记录创建失败不影响用户创建,只记录日志
System.err.println("创建员工记录失败: " + e.getMessage());
}
return AjaxResult.success("用户新增成功");
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("新增用户失败:" + e.getMessage());
}
}
/**
* 根据ID获取司机详情
*/
@SaCheckPermission("member:view")
@GetMapping("/driverDetail/{id}")
public AjaxResult getDriverDetail(@PathVariable("id") Integer id) {
try {
if (id == null) {
return AjaxResult.error("司机ID不能为空");
}
Map<String, Object> driverInfo = memberDriverMapper.selectDriverById(id);
if (driverInfo != null) {
return AjaxResult.success(driverInfo);
} else {
return AjaxResult.error("司机信息不存在");
}
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("获取司机详情失败:" + e.getMessage());
}
}
/**
* 根据用户类型自动创建员工记录
*
* @param username 用户姓名
* @param mobile 手机号
* @param userType 用户类型 (1:司机, 2:供应商, 3:资金方, 4:采购商)
* @param status 状态
*/
private void createEmployeeRecord(String username, String mobile, Integer userType, Integer status) {
// 检查手机号是否已存在于员工表中
List<SysUser> existingUsers = sysUserMapper.selectList(
new LambdaQueryWrapper<SysUser>()
.eq(SysUser::getMobile, mobile)
.eq(SysUser::getIsDelete, 0)
);
if (!existingUsers.isEmpty()) {
System.out.println("手机号 " + mobile + " 已存在于员工表中,跳过创建");
return;
}
// 根据用户类型获取或创建对应的岗位
Integer roleId = getOrCreateRoleByUserType(userType);
if (roleId == null) {
throw new RuntimeException("无法获取或创建岗位");
}
// 创建员工记录
SysUser sysUser = new SysUser();
sysUser.setName(username);
sysUser.setMobile(mobile);
sysUser.setRoleId(roleId);
sysUser.setPassword(DigestUtil.md5Hex(Constants.USER_PASSWORD_PREFIX + "123456")); // 默认密码123456
sysUser.setStatus(status != null ? status : 1); // 默认启用
sysUser.setCreateTime(new Date());
sysUser.setCreateBy(SecurityUtil.getCurrentUserId());
sysUser.setIsDelete(0);
int result = sysUserMapper.insert(sysUser);
if (result <= 0) {
throw new RuntimeException("员工记录插入失败");
}
System.out.println("成功为用户 " + username + " 创建员工记录岗位ID: " + roleId);
}
/**
* 根据用户类型获取或创建对应的岗位
*
* @param userType 用户类型
* @return 岗位ID
*/
private Integer getOrCreateRoleByUserType(Integer userType) {
String roleName;
String roleDescription;
// 根据用户类型确定岗位名称和描述
switch (userType) {
case 1:
roleName = "司机";
roleDescription = "司机用户岗位";
break;
case 2:
roleName = "供应商";
roleDescription = "供应商用户岗位";
break;
case 3:
roleName = "资金方";
roleDescription = "资金方用户岗位";
break;
case 4:
roleName = "采购商";
roleDescription = "采购商用户岗位";
break;
default:
roleName = "普通用户";
roleDescription = "普通用户岗位";
break;
}
// 查询是否已存在该岗位
List<SysRole> existingRoles = sysRoleMapper.selectList(
new LambdaQueryWrapper<SysRole>()
.eq(SysRole::getName, roleName)
.eq(SysRole::getIsDelete, 0)
);
if (!existingRoles.isEmpty()) {
return existingRoles.get(0).getId();
}
// 创建新岗位
SysRole newRole = new SysRole();
newRole.setName(roleName);
newRole.setDescription(roleDescription);
newRole.setCreateTime(new Date());
newRole.setIsDelete(0);
int result = sysRoleMapper.insert(newRole);
if (result <= 0) {
throw new RuntimeException("创建岗位失败");
}
System.out.println("成功创建岗位: " + roleName + ", ID: " + newRole.getId());
return newRole.getId();
}
/**
* 图片代理接口 - 解决CORS跨域问题
* 通过后端代理访问外部图片资源
*/
@GetMapping("/proxy/image")
public ResponseEntity<byte[]> proxyImage(@RequestParam("url") String imageUrl) {
try {
// 验证URL格式
if (imageUrl == null || imageUrl.trim().isEmpty()) {
return ResponseEntity.badRequest().build();
}
// 安全检查只允许HTTPS协议
if (!imageUrl.startsWith("https://")) {
return ResponseEntity.badRequest().build();
}
System.out.println("代理图片请求: " + imageUrl);
// 创建URL连接
URL url = new URL(imageUrl);
URLConnection connection = url.openConnection();
// 设置请求头,模拟浏览器请求
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
connection.setRequestProperty("Accept", "image/*");
connection.setConnectTimeout(10000); // 10秒连接超时
connection.setReadTimeout(30000); // 30秒读取超时
// 获取输入流
InputStream inputStream = connection.getInputStream();
// 读取图片数据
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
byte[] imageData = outputStream.toByteArray();
// 关闭流
inputStream.close();
outputStream.close();
// 设置响应头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.IMAGE_JPEG); // 默认设置为JPEG
headers.setContentLength(imageData.length);
// 设置缓存头,减少重复请求
headers.setCacheControl("public, max-age=3600"); // 缓存1小时
// 根据文件扩展名设置正确的Content-Type
String contentType = connection.getContentType();
if (contentType != null && contentType.startsWith("image/")) {
headers.setContentType(MediaType.parseMediaType(contentType));
}
System.out.println("图片代理成功,大小: " + imageData.length + " bytes");
return new ResponseEntity<>(imageData, headers, HttpStatus.OK);
} catch (Exception e) {
System.err.println("图片代理失败: " + e.getMessage());
e.printStackTrace();
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
}
}
/**
* 调试接口:查看司机图片数据详情
*/
@GetMapping("/debug/driverImages")
public AjaxResult debugDriverImages() {
try {
// 查询所有司机的图片数据
List<Map<String, Object>> drivers = memberDriverMapper.selectDriverList();
System.out.println("=== 司机图片数据调试 ===");
for (Map<String, Object> driver : drivers) {
String username = (String) driver.get("username");
String carImg = (String) driver.get("car_img");
String mobile = (String) driver.get("mobile");
System.out.println("司机: " + username + " (手机: " + mobile + ")");
System.out.println("car_img字段: " + carImg);
if (carImg != null && !carImg.trim().isEmpty()) {
String[] urls = carImg.split(",");
System.out.println("解析后的URL数量: " + urls.length);
for (int i = 0; i < urls.length; i++) {
String url = urls[i].trim();
System.out.println(" URL " + (i + 1) + ": " + url);
System.out.println(" URL " + (i + 1) + " 长度: " + url.length());
System.out.println(" URL " + (i + 1) + " 是否HTTPS: " + url.startsWith("https://"));
}
} else {
System.out.println("car_img字段为空");
}
System.out.println("---");
}
return AjaxResult.success("司机图片数据调试完成,请查看控制台输出", drivers);
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("调试失败: " + e.getMessage());
}
}
@GetMapping("/debug/carImgSplit")
public AjaxResult debugCarImgSplit() {
try {
// 测试分割逻辑
String testCarImg = "https://smart-1251449951.cos.ap-guangzhou.myqcloud.com/iotPlateform/2025/10/16/4c4e20251016142427.jpg,https://smart-1251449951.cos.ap-guangzhou.myqcloud.com/iotPlateform/2025/10/16/4c4e20251016142429.jpg";
System.out.println("=== 测试car_img分割逻辑 ===");
System.out.println("原始car_img: " + testCarImg);
String[] carImgUrls = testCarImg.split(",");
System.out.println("分割后数组长度: " + carImgUrls.length);
if (carImgUrls.length >= 2) {
String carBehindPhoto = carImgUrls[0].trim();
String carFrontPhoto = carImgUrls[1].trim();
System.out.println("车尾照片 (carBehindPhoto): " + carBehindPhoto);
System.out.println("车头照片 (carFrontPhoto): " + carFrontPhoto);
Map<String, Object> result = new HashMap<>();
result.put("originalCarImg", testCarImg);
result.put("carBehindPhoto", carBehindPhoto);
result.put("carFrontPhoto", carFrontPhoto);
result.put("splitCount", carImgUrls.length);
return AjaxResult.success("分割测试完成", result);
} else {
return AjaxResult.error("分割失败URL数量不足");
}
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("分割测试失败: " + e.getMessage());
}
}
}

View File

@@ -0,0 +1,209 @@
package com.aiotagro.cattletrade.business.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.aiotagro.cattletrade.business.entity.SysMenu;
import com.aiotagro.cattletrade.business.entity.SysRoleMenu;
import com.aiotagro.cattletrade.business.mapper.SysMenuMapper;
import com.aiotagro.cattletrade.business.mapper.SysRoleMenuMapper;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
/**
* 菜单权限管理控制器
*
* @author System
* @date 2025-10-11
*/
@Slf4j
@RestController
@RequestMapping("/sysMenu")
public class SysMenuController {
@Resource
private SysMenuMapper sysMenuMapper;
@Resource
private SysRoleMenuMapper sysRoleMenuMapper;
/**
* 获取菜单树(所有菜单)
*/
@SaCheckPermission("permission:menu:list")
@GetMapping("/tree")
public AjaxResult getMenuTree() {
List<SysMenu> allMenus = sysMenuMapper.selectList(
new LambdaQueryWrapper<SysMenu>()
.eq(SysMenu::getIsDelete, 0)
.orderByAsc(SysMenu::getSort)
);
List<Map<String, Object>> tree = buildMenuTree(allMenus, 0);
return AjaxResult.success(tree);
}
/**
* 获取菜单列表(扁平)
*/
@SaCheckPermission("permission:menu:list")
@GetMapping("/list")
public AjaxResult getMenuList() {
List<SysMenu> menus = sysMenuMapper.selectList(
new LambdaQueryWrapper<SysMenu>()
.eq(SysMenu::getIsDelete, 0)
.orderByAsc(SysMenu::getSort)
);
return AjaxResult.success(menus);
}
/**
* 根据角色ID获取菜单列表用于角色权限分配
*/
@SaCheckPermission("permission:menu:list")
@GetMapping("/listByRoleId")
public AjaxResult getMenuListByRoleId(@RequestParam Integer roleId) {
List<SysMenu> menus = sysMenuMapper.queryListByRoleId(roleId);
return AjaxResult.success(menus);
}
/**
* 获取角色已分配的菜单ID列表
*/
@SaCheckPermission("permission:menu:list")
@GetMapping("/roleMenuIds")
public AjaxResult getRoleMenuIds(@RequestParam Integer roleId) {
log.info("=== 获取角色菜单权限 === roleId: {}", roleId);
List<SysRoleMenu> roleMenus = sysRoleMenuMapper.selectList(
new LambdaQueryWrapper<SysRoleMenu>()
.eq(SysRoleMenu::getRoleId, roleId)
);
log.info("=== 查询到的角色菜单关联记录数: {}", roleMenus.size());
List<Integer> menuIds = roleMenus.stream()
.map(SysRoleMenu::getMenuId)
.collect(Collectors.toList());
log.info("=== 返回的菜单ID列表: {}", menuIds);
return AjaxResult.success(menuIds);
}
/**
* 新增菜单
*/
@SaCheckPermission("permission:menu:add")
@PostMapping("/add")
public AjaxResult addMenu(@RequestBody SysMenu menu) {
menu.setIsDelete(0);
menu.setCreateTime(new Date());
int result = sysMenuMapper.insert(menu);
return result > 0 ? AjaxResult.success("添加成功") : AjaxResult.error("添加失败");
}
/**
* 更新菜单
*/
@SaCheckPermission("permission:menu:edit")
@PostMapping("/update")
public AjaxResult updateMenu(@RequestBody SysMenu menu) {
menu.setUpdateTime(new Date());
int result = sysMenuMapper.updateById(menu);
return result > 0 ? AjaxResult.success("更新成功") : AjaxResult.error("更新失败");
}
/**
* 删除菜单(软删除)
*/
@SaCheckPermission("permission:menu:delete")
@GetMapping("/delete")
public AjaxResult deleteMenu(@RequestParam Integer id) {
SysMenu menu = new SysMenu();
menu.setId(id);
menu.setIsDelete(1);
menu.setUpdateTime(new Date());
int result = sysMenuMapper.updateById(menu);
return result > 0 ? AjaxResult.success("删除成功") : AjaxResult.error("删除失败");
}
/**
* 为角色分配菜单权限
*/
@SaCheckPermission("permission:menu:assign")
@PostMapping("/assignRoleMenus")
public AjaxResult assignRoleMenus(@RequestBody Map<String, Object> params) {
Integer roleId = (Integer) params.get("roleId");
@SuppressWarnings("unchecked")
List<Integer> menuIds = (List<Integer>) params.get("menuIds");
log.info("=== 分配角色菜单权限 ===");
log.info("roleId: {}", roleId);
log.info("menuIds: {}", menuIds);
if (roleId == null) {
log.error("角色ID不能为空");
return AjaxResult.error("角色ID不能为空");
}
// 删除原有权限
int deletedCount = sysRoleMenuMapper.delete(
new LambdaQueryWrapper<SysRoleMenu>()
.eq(SysRoleMenu::getRoleId, roleId)
);
log.info("=== 删除原有权限记录数: {}", deletedCount);
// 添加新权限
if (menuIds != null && !menuIds.isEmpty()) {
for (Integer menuId : menuIds) {
SysRoleMenu roleMenu = new SysRoleMenu();
roleMenu.setRoleId(roleId);
roleMenu.setMenuId(menuId);
int insertResult = sysRoleMenuMapper.insert(roleMenu);
log.info("=== 插入权限记录 menuId: {}, 结果: {}", menuId, insertResult);
}
log.info("=== 成功分配 {} 个权限", menuIds.size());
} else {
log.info("=== 没有要分配的权限,清空所有权限");
}
return AjaxResult.success("分配成功");
}
/**
* 构建菜单树
*/
private List<Map<String, Object>> buildMenuTree(List<SysMenu> menus, Integer parentId) {
List<Map<String, Object>> tree = new ArrayList<>();
for (SysMenu menu : menus) {
if (menu.getParentId() != null && menu.getParentId().equals(parentId)) {
Map<String, Object> node = new HashMap<>();
node.put("id", menu.getId());
node.put("label", menu.getName());
node.put("parentId", menu.getParentId());
node.put("type", menu.getType());
node.put("icon", menu.getIcon());
node.put("sort", menu.getSort());
node.put("routeUrl", menu.getRouteUrl());
node.put("pageUrl", menu.getPageUrl());
node.put("authority", menu.getAuthority());
List<Map<String, Object>> children = buildMenuTree(menus, menu.getId());
if (!children.isEmpty()) {
node.put("children", children);
}
tree.add(node);
}
}
return tree;
}
}

View File

@@ -0,0 +1,90 @@
package com.aiotagro.cattletrade.business.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.aiotagro.cattletrade.business.dto.SysRoleDto;
import com.aiotagro.cattletrade.business.entity.SysRole;
import com.aiotagro.cattletrade.business.service.ISysRoleService;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* <p>
* 岗色管理表 前端控制器
* </p>
*
* @author admin
* @since 2024-12-26
*/
@RestController
@RequestMapping("/sysRole")
public class SysRoleController {
@Autowired
private ISysRoleService roleService;
/**
* 查询分页列表
*/
@SaCheckPermission("permission:operation:list")
@PostMapping(value = "/queryList")
public PageResultResponse queryList(@RequestBody SysRoleDto dto) {
return roleService.queryList(dto);
}
/**
* 查询角色列表(权限管理页面使用)
*/
@SaCheckPermission("permission:operation:list")
@PostMapping(value = "/list")
public PageResultResponse list(@RequestBody SysRoleDto dto) {
return roleService.queryList(dto);
}
/**
* 新增、编辑
**/
@SaCheckPermission("permission:operation:role")
@PostMapping("/save")
public AjaxResult saveRole(@RequestBody SysRole role) {
return roleService.saveRole(role);
}
/**
* 新增角色
**/
@SaCheckPermission("permission:operation:role")
@PostMapping("/add")
public AjaxResult add(@RequestBody SysRole role) {
return roleService.saveRole(role);
}
/**
* 更新角色
**/
@SaCheckPermission("permission:operation:role")
@PostMapping("/update")
public AjaxResult update(@RequestBody SysRole role) {
return roleService.saveRole(role);
}
/**
* 删除
**/
@SaCheckPermission("permission:operation:role")
@GetMapping("/delete")
public AjaxResult delete(@RequestParam Integer id) {
return roleService.delete(id);
}
/**
* 查询菜单列表
**/
@SaCheckPermission("permission:menu:list")
@GetMapping("/getMenus")
public AjaxResult getMenus(@RequestParam(required = false) Integer id) {
return roleService.getMenus(id);
}
}

View File

@@ -0,0 +1,113 @@
package com.aiotagro.cattletrade.business.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.aiotagro.cattletrade.business.entity.SysTenant;
import com.aiotagro.cattletrade.business.mapper.SysTenantMapper;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 租户管理控制器
*
* @author System
* @date 2025-01-16
*/
@RestController
@RequestMapping("/sysTenant")
public class SysTenantController {
@Resource
private SysTenantMapper tenantMapper;
/**
* 租户列表查询(分页)
*/
@SaCheckPermission("system:tenant:list")
@PostMapping("/queryList")
public PageResultResponse<SysTenant> queryList(@RequestBody Map<String, Object> params) {
Integer pageNum = params.get("pageNum") != null ? (Integer) params.get("pageNum") : 1;
Integer pageSize = params.get("pageSize") != null ? (Integer) params.get("pageSize") : 10;
String name = (String) params.get("name");
Page<SysTenant> result = PageHelper.startPage(pageNum, pageSize);
LambdaQueryWrapper<SysTenant> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysTenant::getIsDelete, 0);
if (name != null && !name.trim().isEmpty()) {
wrapper.like(SysTenant::getName, name);
}
wrapper.orderByDesc(SysTenant::getId);
List<SysTenant> list = tenantMapper.selectList(wrapper);
return new PageResultResponse<>(result.getTotal(), list);
}
/**
* 新增租户
*/
@SaCheckPermission("system:tenant:add")
@PostMapping("/add")
public AjaxResult add(@RequestBody SysTenant tenant) {
tenant.setCreateTime(new Date());
tenant.setIsDelete(0);
int rows = tenantMapper.insert(tenant);
return rows > 0 ? AjaxResult.success("新增成功") : AjaxResult.error("新增失败");
}
/**
* 更新租户
*/
@SaCheckPermission("system:tenant:edit")
@PostMapping("/update")
public AjaxResult update(@RequestBody SysTenant tenant) {
int rows = tenantMapper.updateById(tenant);
return rows > 0 ? AjaxResult.success("更新成功") : AjaxResult.error("更新失败");
}
/**
* 删除租户(逻辑删除)
*/
@SaCheckPermission("system:tenant:delete")
@PostMapping("/delete")
public AjaxResult delete(@RequestParam Integer id) {
SysTenant tenant = new SysTenant();
tenant.setId(id);
tenant.setIsDelete(1);
int rows = tenantMapper.updateById(tenant);
return rows > 0 ? AjaxResult.success("删除成功") : AjaxResult.error("删除失败");
}
/**
* 获取租户详情
*/
@SaCheckPermission("system:tenant:view")
@GetMapping("/detail")
public AjaxResult detail(@RequestParam Integer id) {
SysTenant tenant = tenantMapper.selectById(id);
return AjaxResult.success(tenant);
}
/**
* 获取租户分配列表(用于下拉框等)
*/
@GetMapping("/allotList")
public AjaxResult allotList() {
LambdaQueryWrapper<SysTenant> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysTenant::getIsDelete, 0);
wrapper.orderByDesc(SysTenant::getId);
List<SysTenant> list = tenantMapper.selectList(wrapper);
return AjaxResult.success(list);
}
}

View File

@@ -0,0 +1,51 @@
package com.aiotagro.cattletrade.business.controller;
import com.aiotagro.cattletrade.business.dto.SysUserDto;
import com.aiotagro.cattletrade.business.entity.SysUser;
import com.aiotagro.cattletrade.business.service.ISysUserService;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* <p>
* 员工管理表 前端控制器
* </p>
*
* @author admin
* @since 2024-12-26
*/
@RestController
@RequestMapping("/sysUser")
public class SysUserController {
@Autowired
private ISysUserService userService;
/**
* 查询分页列表
*/
@PostMapping(value = "/queryList")
public PageResultResponse queryList(@RequestBody SysUserDto dto) {
return userService.queryList(dto);
}
/**
* 新增、编辑
**/
@PostMapping("/save")
public AjaxResult saveUser(@RequestBody SysUser user) {
return userService.saveUser(user);
}
/**
* 删除
**/
@GetMapping("/delete")
public AjaxResult delete(@RequestParam Integer id) {
return userService.delete(id);
}
}

View File

@@ -0,0 +1,82 @@
package com.aiotagro.cattletrade.business.controller;
import com.aiotagro.cattletrade.business.dto.DeliveryQueryDto;
import com.aiotagro.cattletrade.business.dto.DeliverListDto;
import com.aiotagro.cattletrade.business.service.IDeliveryService;
import com.aiotagro.cattletrade.business.service.IWarningLogService;
import com.aiotagro.cattletrade.business.vo.DeliveryLogVo;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* 预警记录表
*
* @author admin
* @since 2024-12-26
*/
@RestController
@RequestMapping("/warningLog")
public class WarningLogController {
@Autowired
private IWarningLogService warningLogService;
@Autowired
private IDeliveryService deliveryService;
/**
* 供远程调用-保存预警日志
*/
@GetMapping("/savaWarn")
public AjaxResult savaWarn(@RequestParam String deviceId) {
return warningLogService.savaWarn(deviceId);
}
/**
* 运单预警-预警统计
*/
@RequestMapping("/warningCount")
public AjaxResult warningCount() {
return warningLogService.warningCount();
}
/**
* 运单预警-分页查询
*
* @param dto
* @return
*/
@PostMapping(value = "/queryList")
public PageResultResponse<DeliveryLogVo> queryList(@RequestBody @Validated DeliveryQueryDto dto) {
return warningLogService.queryList(dto);
}
/**
* 预警记录详情
*/
@RequestMapping("/warningDetail")
public AjaxResult warningDetail(@RequestParam Integer id) {
return warningLogService.warningDetail(id);
}
/**
* 后台系统,预警记录
*
* @param dto
* @return
*/
@PostMapping(value = "/pageQuery")
public PageResultResponse<DeliveryLogVo> pageQuery(@RequestBody DeliverListDto dto) {
return deliveryService.pageQueryList(dto);
}
}

View File

@@ -0,0 +1,199 @@
package com.aiotagro.cattletrade.business.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.aiotagro.cattletrade.business.entity.Delivery;
import com.aiotagro.cattletrade.business.entity.DeliveryDevice;
import com.aiotagro.cattletrade.business.service.IDeliveryDeviceService;
import com.aiotagro.cattletrade.business.service.IDeliveryService;
import com.aiotagro.cattletrade.business.service.IJbqClientService;
import com.aiotagro.cattletrade.business.service.IJbqServerService;
import com.aiotagro.cattletrade.business.service.IXqClientService;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 微信端运送清单控制器
*
* @author System
* @date 2025-01-16
*/
@RestController
@RequestMapping("/wechatDelivery")
public class WechatDeliveryController {
@Autowired
private IDeliveryDeviceService deliveryDeviceService;
@Autowired
private IDeliveryService deliveryService;
@Autowired
private IXqClientService xqClientService;
@Autowired
private IJbqClientService jbqClientService;
@Autowired
private IJbqServerService jbqServerService;
/**
* 获取装车信息
*/
@SaCheckPermission("delivery:view")
@PostMapping("/carLoadInfo")
public AjaxResult carLoadInfo(@RequestBody Map<String, Object> params) {
try {
Integer deliveryId = (Integer) params.get("deliveryId");
if (deliveryId == null) {
return AjaxResult.error("运送清单ID不能为空");
}
Map<String, Object> result = new HashMap<>();
// 查询耳标设备
AjaxResult earResult = jbqClientService.getDevicesByDeliveryId(deliveryId, 2);
if (earResult.get("code").equals(200)) {
result.put("deliveryDevices", earResult.get("data"));
} else {
result.put("deliveryDevices", java.util.Collections.emptyList());
}
// 查询项圈设备
AjaxResult collarResult = xqClientService.getDevicesByDeliveryId(deliveryId, 3);
if (collarResult.get("code").equals(200)) {
result.put("xqDevices", collarResult.get("data"));
} else {
result.put("xqDevices", java.util.Collections.emptyList());
}
return AjaxResult.success(result);
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("查询装车信息失败:" + e.getMessage());
}
}
/**
* 测试数据库连接
*/
@GetMapping("/testConnection")
public AjaxResult testConnection() {
try {
// 测试基本查询
List<Delivery> deliveries = deliveryService.list();
Map<String, Object> result = new HashMap<>();
result.put("deliveryCount", deliveries.size());
result.put("status", "数据库连接正常");
return AjaxResult.success("测试成功", result);
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("测试失败: " + e.getMessage());
}
}
/**
* 更新装车信息
*/
@SaCheckPermission("delivery:edit")
@PostMapping("/updateLoadInfo")
public AjaxResult updateLoadInfo(@RequestBody Map<String, Object> params) {
try {
Integer deliveryId = (Integer) params.get("deliveryId");
if (deliveryId == null) {
return AjaxResult.error("运送清单ID不能为空");
}
// 更新运送清单基本信息
LambdaUpdateWrapper<Delivery> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(Delivery::getId, deliveryId);
// 更新预计送达时间
if (params.get("estimatedDeliveryTime") != null) {
updateWrapper.set(Delivery::getEstimatedDeliveryTime, params.get("estimatedDeliveryTime"));
}
// 更新空车过磅重量
if (params.get("emptyWeight") != null) {
updateWrapper.set(Delivery::getEmptyWeight, params.get("emptyWeight"));
}
// 更新装车过磅重量
if (params.get("entruckWeight") != null) {
updateWrapper.set(Delivery::getEntruckWeight, params.get("entruckWeight"));
}
// 更新检疫票
if (params.get("quarantineTickeyUrl") != null) {
updateWrapper.set(Delivery::getQuarantineTickeyUrl, params.get("quarantineTickeyUrl"));
}
// 更新传纸质磅单(双章)
if (params.get("poundListImg") != null) {
updateWrapper.set(Delivery::getPoundListImg, params.get("poundListImg"));
}
// 更新装车过磅视频
if (params.get("entruckWeightVideo") != null) {
updateWrapper.set(Delivery::getEntruckWeightVideo, params.get("entruckWeightVideo"));
}
// 更新空车过磅视频
if (params.get("emptyWeightVideo") != null) {
updateWrapper.set(Delivery::getEmptyWeightVideo, params.get("emptyWeightVideo"));
}
// 更新上传装牛视频
if (params.get("entruckVideo") != null) {
updateWrapper.set(Delivery::getEntruckVideo, params.get("entruckVideo"));
}
// 更新控槽视频
if (params.get("controlSlotVideo") != null) {
updateWrapper.set(Delivery::getControlSlotVideo, params.get("controlSlotVideo"));
}
// 更新车辆空磅上磅车头照片
if (params.get("emptyVehicleFrontPhoto") != null) {
updateWrapper.set(Delivery::getEmptyVehicleFrontPhoto, params.get("emptyVehicleFrontPhoto"));
}
// 更新装完牛绕车一圈视频
if (params.get("cattleLoadingCircleVideo") != null) {
updateWrapper.set(Delivery::getCattleLoadingCircleVideo, params.get("cattleLoadingCircleVideo"));
}
// 更新车辆过重磅车头照片
if (params.get("loadedVehicleFrontPhoto") != null) {
updateWrapper.set(Delivery::getLoadedVehicleFrontPhoto, params.get("loadedVehicleFrontPhoto"));
}
// 更新车辆重磅照片
if (params.get("loadedVehicleWeightPhoto") != null) {
updateWrapper.set(Delivery::getLoadedVehicleWeightPhoto, params.get("loadedVehicleWeightPhoto"));
}
// 更新驾驶员手持身份证站车头照片
if (params.get("driverIdCardPhoto") != null) {
updateWrapper.set(Delivery::getDriverIdCardPhoto, params.get("driverIdCardPhoto"));
}
// 执行更新
boolean updateResult = deliveryService.update(updateWrapper);
if (updateResult) {
return AjaxResult.success("装车信息更新成功");
} else {
return AjaxResult.error("装车信息更新失败");
}
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("更新装车信息失败:" + e.getMessage());
}
}
}

View File

@@ -0,0 +1,107 @@
package com.aiotagro.cattletrade.business.controller;
import com.aiotagro.cattletrade.business.service.IXqClientService;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.Map;
/**
* 项圈客户端控制器
*
* @author System
* @date 2025-01-16
*/
@RestController
@RequestMapping("/xqClient")
public class XqClientController {
@Resource
private IXqClientService xqClientService;
/**
* 项圈列表(分页查询)
*/
@PostMapping(value = "/list")
public PageResultResponse list(@RequestBody Map<String, Object> params) {
return xqClientService.xqList(params);
}
/**
* 根据运送清单ID查询项圈列表
*/
@PostMapping(value = "/pageXqListByDeliveryId")
public AjaxResult pageXqListByDeliveryId(@RequestBody Map<String, Object> params) {
Object deliveryIdObj = params.get("deliveryId");
Integer deliveryId = null;
if (deliveryIdObj != null) {
if (deliveryIdObj instanceof Integer) {
deliveryId = (Integer) deliveryIdObj;
} else if (deliveryIdObj instanceof String) {
deliveryId = Integer.valueOf((String) deliveryIdObj);
}
}
return xqClientService.getDevicesByDeliveryId(deliveryId, 3); // 3表示项圈
}
/**
* 查询分页列表(通用)
*/
@PostMapping(value = "/pageQuery")
public PageResultResponse pageQuery(@RequestBody Map<String, Object> params) {
return xqClientService.xqList(params);
}
/**
* 项圈轨迹
*/
@PostMapping(value = "/xqTrack")
public AjaxResult xqTrack(@RequestBody Map<String, Object> params) {
String deliveryId = params.get("deliveryId") == null ? null : String.valueOf(params.get("deliveryId"));
String xqDeviceId = params.get("xqDeviceId") == null ? null : String.valueOf(params.get("xqDeviceId"));
String trackTime = params.get("trackTime") == null ? null : String.valueOf(params.get("trackTime"));
String trackEndTime = params.get("trackEndTime") == null ? null : String.valueOf(params.get("trackEndTime"));
return xqClientService.getCollarTrack(deliveryId, xqDeviceId, trackTime, trackEndTime);
}
/**
* 项圈位置
*/
@PostMapping(value = "/xqLocation")
public AjaxResult xqLocation(@RequestBody Map<String, Object> params) {
String deliveryId = params.get("deliveryId") == null ? null : String.valueOf(params.get("deliveryId"));
String xqDeviceId = params.get("xqDeviceId") == null ? null : String.valueOf(params.get("xqDeviceId"));
return xqClientService.getCollarLocation(deliveryId, xqDeviceId);
}
/**
* 测试项圈定位接口
*/
@GetMapping("/testLocation/{deviceId}")
public AjaxResult testLocation(@PathVariable("deviceId") String deviceId) {
try {
System.out.println("Testing collar location for device: " + deviceId);
AjaxResult result = xqClientService.getCollarLocation(null, deviceId);
System.out.println("Location test completed");
return result;
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("测试失败: " + e.getMessage());
}
}
/**
* 设备轨迹
*/
@PostMapping(value = "/xqDeviceTrack")
public AjaxResult xqDeviceTrack(@RequestBody Map<String, Object> params) {
String deliveryId = params.get("deliveryId") == null ? null : String.valueOf(params.get("deliveryId"));
String xqDeviceId = params.get("xqDeviceId") == null ? null : String.valueOf(params.get("xqDeviceId"));
String trackTime = params.get("trackTime") == null ? null : String.valueOf(params.get("trackTime"));
String trackEndTime = params.get("trackEndTime") == null ? null : String.valueOf(params.get("trackEndTime"));
return xqClientService.getCollarDeviceTrack(deliveryId, xqDeviceId, trackTime, trackEndTime);
}
}

View File

@@ -0,0 +1,18 @@
package com.aiotagro.cattletrade.business.dto;
import lombok.Data;
/**
* @author Carson
* @package_name com.aiotagro.payinfo.domain.dto
* @date 2024/2/18 16:38
*/
@Data
public class BaseDto {
private Integer pageNum = 1;
private Integer pageSize = 10;
}

View File

@@ -0,0 +1,44 @@
package com.aiotagro.cattletrade.business.dto;
import lombok.Data;
@Data
public class DeliverListDto extends BaseDto{
/**
* 运单号
*/
private String deliveryNumber;
/**
* 车牌号
*/
private String licensePlate;
/**
* 创建时间-开始
*/
private String startTime;
/**
* 创建时间-结束
*/
private String endTime;
/**
* 预警类型
*/
private Integer warningType;
/**
* 当前用户id
*/
private Integer currentUserId;
/**
* 核验状态
*/
private Integer status;
/**
* 订单标题
*/
private String deliveryTitle;
/**
* 目的地
*/
private String endLocation;
}

View File

@@ -0,0 +1,84 @@
package com.aiotagro.cattletrade.business.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* 我要装车对象
*/
@Data
public class DeliveryAddDto implements Serializable {
/**
* 起始地
*/
private String startLocation;
/**
* 起始纬度
*/
private String startLat;
/**
* 起始经度
*/
private String startLon;
/**
* 送达目的地
*/
private String endLocation;
/**
* 目的地纬度
*/
private String endLat;
/**
* 目的地经度
*/
private String endLon;
/**
* 预计送达时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date estimatedDeliveryTime;
/**
* 司机姓名
*/
private String driverName;
/**
* 司机手机号
*/
private String driverMobile;
/**
* 车牌号
*/
private String licensePlate;
/**
* 车头照片
*/
private String carFrontPhoto;
/**
* 车尾照片
*/
private String carBehindPhoto;
/**
* 车视频
*/
private String carVideo;
/**
* 登记智能耳标数
*/
private Integer registeredJbqCount;
/**
* 主机编号
*/
private String serverDeviceSn;
/**
* 耳标编号集合
*/
private List<String> jbqDeviceSn;
/**
* 核验人
*/
private String checkBy;
}

View File

@@ -0,0 +1,114 @@
package com.aiotagro.cattletrade.business.dto;
import lombok.Data;
import javax.validation.constraints.*;
import java.util.Date;
import java.util.List;
/**
* 运送清单创建DTO
*
* @author System
* @date 2025-10-11
*/
@Data
public class DeliveryCreateDto {
/**
* 发货方
*/
@NotBlank(message = "发货方不能为空")
private String shipper;
/**
* 采购方
*/
@NotBlank(message = "采购方不能为空")
private String buyer;
/**
* 车牌号
*/
@NotBlank(message = "车牌号不能为空")
@Pattern(regexp = "^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-Z0-9]{5}[A-Z0-9挂学警港澳]$",
message = "车牌号格式不正确")
private String plateNumber;
/**
* 司机姓名
*/
@NotBlank(message = "司机姓名不能为空")
private String driverName;
/**
* 司机电话
*/
@NotBlank(message = "司机电话不能为空")
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
private String driverPhone;
/**
* 主机设备ID
*/
private Integer serverId;
/**
* 耳标设备ID列表
*/
private List<Integer> eartagIds;
/**
* 项圈设备ID列表
*/
private List<Integer> collarIds;
/**
* 预计出发时间
*/
@NotNull(message = "预计出发时间不能为空")
private Date estimatedDepartureTime;
/**
* 预计到达时间
*/
@NotNull(message = "预计到达时间不能为空")
private Date estimatedArrivalTime;
/**
* 起点地址
*/
@NotBlank(message = "起点地址不能为空")
private String startLocation;
/**
* 目的地地址
*/
@NotBlank(message = "目的地地址不能为空")
private String endLocation;
/**
* 牛只数量
*/
@NotNull(message = "牛只数量不能为空")
@Min(value = 1, message = "牛只数量至少为1")
private Integer cattleCount;
/**
* 预估重量(公斤)
*/
@NotNull(message = "预估重量不能为空")
@DecimalMin(value = "0.01", message = "预估重量必须大于0")
private Double estimatedWeight;
/**
* 检疫证号
*/
private String quarantineCertNo;
/**
* 备注
*/
@Size(max = 500, message = "备注不能超过500字")
private String remark;
}

View File

@@ -0,0 +1,48 @@
package com.aiotagro.cattletrade.business.dto;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 运送清单编辑DTO
*/
@Data
public class DeliveryEditDto {
@NotNull(message = "运送清单ID不能为空")
private Integer deliveryId;
private String deliveryTitle;
private Integer ratedQuantity;
private String supplierId;
private Integer fundId;
private Integer driverId;
private String driverMobile;
private Integer buyerId;
private Double buyerPrice;
private Double salePrice;
private Double firmPrice;
private String startLocation;
private String startLat;
private String startLon;
private String endLocation;
private String endLat;
private String endLon;
}

View File

@@ -0,0 +1,23 @@
package com.aiotagro.cattletrade.business.dto;
import com.aiotagro.cattletrade.business.dto.BaseDto;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
public class DeliveryQueryDto extends BaseDto {
/**
* 运单号
*/
private String deliveryNumber;
/**
* 预警类型
*/
private Integer warningType;
/**
* 当前登陆人
*/
private Integer userId;
}

View File

@@ -0,0 +1,38 @@
package com.aiotagro.cattletrade.business.dto;
import lombok.Data;
import java.util.List;
/**
* 设备分配DTO
*
* @author admin
* @since 2024-12-26
*/
@Data
public class DeviceAssignDto {
/**
* 运单ID
*/
private Integer deliveryId;
/**
* 设备信息列表
*/
private List<DeviceInfo> deviceIds;
/**
* 车牌号
*/
private String licensePlate;
/**
* 设备信息内部类
*/
@Data
public static class DeviceInfo {
private String deviceId;
private Integer deviceTypeId;
}
}

View File

@@ -0,0 +1,32 @@
package com.aiotagro.cattletrade.business.dto;
import lombok.Data;
@Data
public class DeviceDto extends BaseDto{
/**
* 耳标编号
*/
private String deviceId;
/**
* 开始号段
*/
private String startNo;
/**
* 结束号段
*/
private String endNo;
/**
* 设备类型1=智能主机2=智能耳标3=智能项圈
*/
private Integer deviceType;
/**
* 是否只查询未分配的设备
*/
private Boolean unassignedOnly;
}

View File

@@ -0,0 +1,10 @@
package com.aiotagro.cattletrade.business.dto;
import lombok.Data;
@Data
public class FileDto {
private String src;
}

View File

@@ -0,0 +1,8 @@
package com.aiotagro.cattletrade.business.dto;
import lombok.Data;
@Data
public class JbqLogDto extends BaseDto{
private Integer deliveryId;
}

View File

@@ -0,0 +1,25 @@
package com.aiotagro.cattletrade.business.dto;
import lombok.Data;
import javax.validation.constraints.NotBlank;
@Data
public class LoginDto {
/**
* 手机号
*/
@NotBlank(message = "手机号不能为空")
private String mobile;
/**
* 用户密码
*/
private String password;
/**
* 登录类型0-密码 1-验证码
*/
private Integer loginType;
}

View File

@@ -0,0 +1,15 @@
package com.aiotagro.cattletrade.business.dto;
import lombok.Data;
@Data
public class ServerLocationDto {
/**
* 运单id
*/
private Integer deliveryId;
/**
* 主机id
*/
private String serverDeviceId;
}

View File

@@ -0,0 +1,16 @@
package com.aiotagro.cattletrade.business.dto;
import lombok.Data;
/**
* @author xiefan
*/
@Data
public class SysRoleDto extends BaseDto {
/**
* 岗位名称/角色名称
*/
private String name;
}

View File

@@ -0,0 +1,16 @@
package com.aiotagro.cattletrade.business.dto;
import lombok.Data;
/**
* @author xiefan
*/
@Data
public class SysUserDto extends BaseDto {
/**
* 员工姓名
*/
private String name;
}

View File

@@ -0,0 +1,110 @@
package com.aiotagro.cattletrade.business.dto;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
@Data
public class WarningDetailDto implements Serializable {
/**
* 预警原因
*/
private String warningReason;
/**
* 预警时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date warningTime;
/**
* 应行驶距离
*/
private String expectedDistance;
/**
* 实际行驶距离
*/
private String actualDistance;
/**
* 起始地
*/
private String startLocation;
/**
* 起始纬度
*/
private String startLat;
/**
* 起始经度
*/
private String startLon;
/**
* 送达目的地
*/
private String endLocation;
/**
* 目的地纬度
*/
private String endLat;
/**
* 目的地经度
*/
private String endLon;
/**
* 预计送达时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date estimatedDeliveryTime;
/**
* 司机姓名
*/
private String driverName;
/**
* 司机手机号
*/
private String driverMobile;
/**
* 车牌号
*/
private String licensePlate;
/**
* 车头照片
*/
private String carFrontPhoto;
/**
* 车尾照片
*/
private String carBehindPhoto;
/**
* 车视频
*/
private String carVideo;
/**
* 登记智能耳标数
*/
private Integer registeredJbqCount;
/**
* 主机编号
*/
private String serverDeviceSn;
/**
* 耳标编号集合
*/
private List<String> jbqDeviceSn;
/**
* 核验人
*/
private Integer checkBy;
/**
* 预警类型2数量盘点预警3距离盘点预警
*/
private String warningType;
/**
* 车内盘点数量
*/
private Integer inventoryJbqCount;
}

View File

@@ -0,0 +1,412 @@
package com.aiotagro.cattletrade.business.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.Setter;
/**
* <p>
* 运送清单表
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Getter
@Setter
@TableName("delivery")
public class Delivery implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 自增ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 运单号
*/
@TableField("delivery_number")
private String deliveryNumber;
/**
* 订单标题
*/
@TableField("delivery_title")
private String deliveryTitle;
/**
* 装车数量
*/
@TableField("rated_quantity")
private Integer ratedQuantity;
/**
* 供应商ID
*/
@TableField("supplier_id")
private String supplierId;
/**
* 资金方ID
*/
@TableField("fund_id")
private Integer fundId;
/**
* 司机ID
*/
@TableField("driver_id")
private Integer driverId;
/**
* 采购商ID
*/
@TableField("buyer_id")
private Integer buyerId;
/**
* 采购价格
*/
@TableField("buyer_price")
private Double buyerPrice;
/**
* 销售价格
*/
@TableField("sale_price")
private Double salePrice;
/**
* 约定单价
*/
@TableField("firm_price")
private Double firmPrice;
/**
* 状态1-待核验2-已核验
*/
@TableField("status")
private Integer status;
/**
* 车牌号
*/
@TableField("license_plate")
private String licensePlate;
/**
* 车头照片
*/
@TableField("car_front_photo")
private String carFrontPhoto;
/**
* 车尾照片
*/
@TableField("car_behind_photo")
private String carBehindPhoto;
/**
* 车视频
*/
@TableField("car_video")
private String carVideo;
/**
* 起始地
*/
@TableField("start_location")
private String startLocation;
/**
* 起始经度
*/
@TableField("start_lat")
private String startLat;
/**
* 起始纬度
*/
@TableField("start_lon")
private String startLon;
/**
* 送达目的地
*/
@TableField("end_location")
private String endLocation;
/**
* 目的地经度
*/
@TableField("end_lat")
private String endLat;
/**
* 目的地纬度
*/
@TableField("end_lon")
private String endLon;
/**
* 预计送达时间
*/
@TableField("estimated_delivery_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date estimatedDeliveryTime;
/**
* 登记智能耳标数
*/
@TableField("registered_jbq_count")
private Integer registeredJbqCount;
/**
* 已分配设备数量
*/
@TableField(exist = false)
private Integer bindJbqCount;
/**
* 已佩戴设备数量
*/
@TableField(exist = false)
private Integer wareCount;
/**
* 司机姓名
*/
@TableField("driver_name")
private String driverName;
/**
* 司机手机号
*/
@TableField("driver_mobile")
private String driverMobile;
/**
* 创建时间
*/
@TableField("create_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/**
* 创建人
*/
@TableField("created_by")
private Integer createdBy;
/**
* 核验人
*/
@TableField("check_by")
private Integer checkBy;
/**
* 核验时间
*/
@TableField("check_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date checkTime;
/**
* 核验视频
*/
@TableField("check_video")
private String checkVideo;
/**
* 空车过磅重量
*/
@TableField("empty_weight")
private String emptyWeight;
/**
* 装车过磅重量
*/
@TableField("entruck_weight")
private String entruckWeight;
/**
* 检疫票
*/
@TableField("quarantine_tickey_url")
private String quarantineTickeyUrl;
/**
* 传纸质磅单(双章)
*/
@TableField("pound_list_img")
private String poundListImg;
/**
* 装车过磅视频
*/
@TableField("entruck_weight_video")
private String entruckWeightVideo;
/**
* 空车过磅视频
*/
@TableField("empty_weight_video")
private String emptyWeightVideo;
/**
* 上传装牛视频
*/
@TableField("entruck_video")
private String entruckVideo;
/**
* 控槽视频
*/
@TableField("control_slot_video")
private String controlSlotVideo;
/**
* 车辆空磅上磅车头照片
*/
@TableField("empty_vehicle_front_photo")
private String emptyVehicleFrontPhoto;
/**
* 装完牛绕车一圈视频
*/
@TableField("cattle_loading_circle_video")
private String cattleLoadingCircleVideo;
/**
* 车辆过重磅车头照片
*/
@TableField("loaded_vehicle_front_photo")
private String loadedVehicleFrontPhoto;
/**
* 车辆重磅照片
*/
@TableField("loaded_vehicle_weight_photo")
private String loadedVehicleWeightPhoto;
/**
* 驾驶员手持身份证站车头照片
*/
@TableField("driver_id_card_photo")
private String driverIdCardPhoto;
/**
* 主机设备编号
*/
@TableField(exist = false)
private String serverDeviceId;
/**
* 耳标设备编号
*/
@TableField(exist = false)
private List<String> deviceIds;
/**
* 是否需要核验1需要核验2不需要核验
*/
@TableField(exist = false)
private Integer ifCheck;
/**
* 预警类型
*/
@TableField(exist = false)
private String warningType;
/**
* 预警时间
*/
@TableField(exist = false)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date warningTime;
/**
* 车内盘点数量
*/
@TableField(exist = false)
private Integer inventoryJbqCount;
/**
* 核验人姓名
*/
@TableField(exist = false)
private String checkByName;
/**
* 预警类型描述, 1-正常 2-盘点预警 3-距离预警
*/
@TableField(exist = false)
private String warningTypeDesc;
@TableField(exist = false)
private List<String> warningTypeList;
/**
* 创建人姓名
*/
@TableField(exist = false)
private String createByName;
/**
* 供应商名称
*/
@TableField(exist = false)
private String supplierName;
/**
* 资金方名称
*/
@TableField(exist = false)
private String fundName;
/**
* 采购商名称
*/
@TableField(exist = false)
private String buyerName;
/**
* 核验状态描述
*/
@TableField(exist = false)
private String statusDesc;
/**
* 耳标设备数量
*/
@TableField(exist = false)
private Integer earTagCount;
/**
* 供应商手机号(逗号分隔)
*/
@TableField(exist = false)
private String supplierMobile;
/**
* 资金方手机号
*/
@TableField(exist = false)
private String fundMobile;
/**
* 采购商手机号
*/
@TableField(exist = false)
private String buyerMobile;
}

View File

@@ -0,0 +1,112 @@
package com.aiotagro.cattletrade.business.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import lombok.Getter;
import lombok.Setter;
/**
* <p>
* 运单设备表
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Getter
@Setter
@TableName("delivery_device")
public class DeliveryDevice implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 运单ID
*/
@TableField("delivery_id")
private Integer deliveryId;
/**
* 设备编号
*/
@TableField("device_id")
private String deviceId;
/**
* 设备类型: 1 主机 2 耳标 3 项圈
*/
@TableField("device_type")
private Integer deviceType;
/**
* 设备用户
*/
@TableField("device_user")
private String deviceUser;
/**
* 是否佩戴
*/
@TableField("is_ware")
private Integer isWare;
/**
* 正面图片
*/
@TableField("front_img")
private String frontImg;
/**
* 侧面图片
*/
@TableField("side_img")
private String sideImg;
/**
* 臀部图片
*/
@TableField("hip_img")
private String hipImg;
/**
* 绑定时间
*/
@TableField("bind_time")
private Date bindTime;
/**
* 创建时间
*/
@TableField("create_time")
private Date createTime;
/**
* 绑定重量
*/
@TableField("bind_weight")
private BigDecimal bindWeight;
/**
* 删除标志
*/
@TableField("deleted")
private Integer deleted;
/**
* 租户ID
*/
@TableField("tenant_id")
private Integer tenantId;
}

View File

@@ -0,0 +1,123 @@
package com.aiotagro.cattletrade.business.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import lombok.Getter;
import lombok.Setter;
/**
* <p>
* 智能耳标表
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Getter
@Setter
@TableName("jbq_client")
public class JbqClient implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 数据主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 耳标编号
*/
@TableField("device_id")
private String deviceId;
/**
* 设备电量
*/
@TableField("device_voltage")
private String deviceVoltage;
/**
* 设备温度
*/
@TableField("device_temp")
private String deviceTemp;
/**
* 主机编号
*/
@TableField("server_device_id")
private String serverDeviceId;
/**
* 纬度
*/
@TableField("latitude")
private String latitude;
/**
* 经度
*/
@TableField("longitude")
private String longitude;
/**
* 总步数
*/
@TableField("walk_steps")
private Long walkSteps;
/**
* 昨日总步数
*/
@TableField("y_walk_steps")
private Long yWalkSteps;
/**
* 创建时间
*/
@TableField("create_time")
private Date createTime;
/**
* 创建人
*/
@TableField("create_by")
private String createBy;
/**
* 更新时间
*/
@TableField("update_time")
private Date updateTime;
/**
* 更新人
*/
@TableField("update_by")
private String updateBy;
/**
* 物联网平台同步标识
*/
@TableField("source_id")
private Long sourceId;
/**
* 运单号
*/
@TableField("delivery_number")
private String deliveryNumber;
/**
* 车牌号
*/
@TableField("license_plate")
private String licensePlate;
}

View File

@@ -0,0 +1,110 @@
package com.aiotagro.cattletrade.business.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.Setter;
/**
* <p>
* 智能耳标日志表
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Getter
@Setter
@TableName("jbq_client_log")
public class JbqClientLog implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 数据主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 耳标编号
*/
@TableField("device_id")
private String deviceId;
/**
* 设备电量
*/
@TableField("device_voltage")
private String deviceVoltage;
/**
* 设备温度
*/
@TableField("device_temp")
private String deviceTemp;
/**
* 主机编号
*/
@TableField("server_device_id")
private String serverDeviceId;
/**
* 纬度
*/
@TableField("latitude")
private String latitude;
/**
* 经度
*/
@TableField("longitude")
private String longitude;
/**
* 总步数
*/
@TableField("walk_steps")
private Long walkSteps;
/**
* 昨日总步数
*/
@TableField("y_walk_steps")
private Long yWalkSteps;
/**
* 创建时间
*/
@TableField("create_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
/**
* 创建人
*/
@TableField("create_by")
private String createBy;
/**
* 更新时间
*/
@TableField("update_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
/**
* 更新人
*/
@TableField("update_by")
private String updateBy;
}

View File

@@ -0,0 +1,106 @@
package com.aiotagro.cattletrade.business.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import lombok.Getter;
import lombok.Setter;
/**
* <p>
* 智能主机表
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Getter
@Setter
@TableName("jbq_server")
public class JbqServer implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 数据主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 主机编号
*/
@TableField("device_id")
private String deviceId;
/**
* 设备电量
*/
@TableField("device_voltage")
private String deviceVoltage;
/**
* 设备温度
*/
@TableField("device_temp")
private String deviceTemp;
/**
* 纬度
*/
@TableField("latitude")
private String latitude;
/**
* 经度
*/
@TableField("longitude")
private String longitude;
/**
* 总步数
*/
@TableField("walk_steps")
private Long walkSteps;
/**
* 昨日总步数
*/
@TableField("y_walk_steps")
private Long yWalkSteps;
/**
* 创建时间
*/
@TableField("create_time")
private Date createTime;
/**
* 创建人
*/
@TableField("create_by")
private String createBy;
/**
* 更新时间
*/
@TableField("update_time")
private Date updateTime;
/**
* 更新人
*/
@TableField("update_by")
private String updateBy;
/**
* 物联网平台同步标识
*/
@TableField("source_id")
private Long sourceId;
}

View File

@@ -0,0 +1,100 @@
package com.aiotagro.cattletrade.business.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import lombok.Getter;
import lombok.Setter;
/**
* <p>
* 智能主机日志表
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Getter
@Setter
@TableName("jbq_server_log")
public class JbqServerLog implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 数据主键
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 主机编号
*/
@TableField("device_id")
private String deviceId;
/**
* 设备电量
*/
@TableField("device_voltage")
private String deviceVoltage;
/**
* 设备温度
*/
@TableField("device_temp")
private String deviceTemp;
/**
* 纬度
*/
@TableField("latitude")
private String latitude;
/**
* 经度
*/
@TableField("longitude")
private String longitude;
/**
* 总步数
*/
@TableField("walk_steps")
private Long walkSteps;
/**
* 昨日总步数
*/
@TableField("y_walk_steps")
private Long yWalkSteps;
/**
* 创建时间
*/
@TableField("create_time")
private Date createTime;
/**
* 创建人
*/
@TableField("create_by")
private String createBy;
/**
* 更新时间
*/
@TableField("update_time")
private Date updateTime;
/**
* 更新人
*/
@TableField("update_by")
private String updateBy;
}

View File

@@ -0,0 +1,39 @@
package com.aiotagro.cattletrade.business.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
/**
* Member实体
*
* @author System
* @date 2025-01-16
*/
@Data
@TableName("member")
public class Member {
@TableId(type = IdType.AUTO)
private Integer id;
private String mobile;
private Integer type;
private Boolean status;
private Date lastLoginTime;
private Integer createBy;
private Date createTime;
private Date updateTime;
private Integer tenantId;
}

View File

@@ -0,0 +1,104 @@
package com.aiotagro.cattletrade.business.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
* 系统菜单表
* </p>
*
* @author admin
* @since 2024-12-07
*/
@Getter
@Setter
@TableName("sys_menu")
public class SysMenu implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 上级id
*/
@TableField("parent_id")
private Integer parentId;
/**
* 菜单类型 0-目录 1-菜单 2-按钮
*/
@TableField("type")
private Integer type;
/**
* 菜单图标
*/
@TableField("icon")
private String icon;
/**
* 菜单名称
*/
@TableField("name")
private String name;
/**
* 排序 数字越小越靠前
*/
@TableField("sort")
private Integer sort;
/**
* 后端路由地址
*/
@TableField("route_url")
private String routeUrl;
/**
* 前端路由地址
*/
@TableField("page_url")
private String pageUrl;
/**
* 所属机构 1-海关端 2-企业端 3海关企业共用
*/
@TableField("org_type")
private Integer orgType;
/**
* 权限字符串
*/
@TableField("authority")
private String authority;
/**
* 创建时间
*/
@TableField("create_time")
private Date createTime;
/**
* 修改时间
*/
@TableField("update_time")
private Date updateTime;
/**
* 是否删除 0-未删除 1-已删除
*/
@TableLogic("is_delete")
private Integer isDelete;
/**
* 是否被选中 0-未选中 1-选中
*/
private Integer isSelected;
}

View File

@@ -0,0 +1,73 @@
package com.aiotagro.cattletrade.business.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* <p>
* 岗位管理表
* </p>
*
* @author admin
* @since 2024-12-07
*/
@Getter
@Setter
@TableName("sys_role")
public class SysRole implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 岗位名称
*/
@TableField("name")
private String name;
/**
* 岗位描述
*/
@TableField("description")
private String description;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField("create_time")
private Date createTime;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField("update_time")
private Date updateTime;
/**
* 是否删除 0-未删除 1-已删除
*/
@TableLogic("is_delete")
private Integer isDelete;
/**
* 菜单id
*/
@TableField(exist = false)
private List<Integer> menuIds;
/**
* 菜单
*/
@TableField(exist = false)
private List<SysMenu> menuList;
}

View File

@@ -0,0 +1,43 @@
package com.aiotagro.cattletrade.business.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
/**
* <p>
* 岗位菜单表
* </p>
*
* @author admin
* @since 2024-12-07
*/
@Getter
@Setter
@TableName("sys_role_menu")
public class SysRoleMenu implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 岗位id
*/
@TableField("role_id")
private Integer roleId;
/**
* 菜单id
*/
@TableField("menu_id")
private Integer menuId;
}

View File

@@ -0,0 +1,31 @@
package com.aiotagro.cattletrade.business.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
/**
* 租户表实体
*
* @author System
* @date 2025-01-16
*/
@Data
@TableName("sys_tenant")
public class SysTenant {
@TableId(type = IdType.AUTO)
private Integer id;
private String name;
private String mobile;
private Date createTime;
private Integer isDelete;
}

View File

@@ -0,0 +1,109 @@
package com.aiotagro.cattletrade.business.entity;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.util.Date;
/**
* <p>
* 员工管理表
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Getter
@Setter
@TableName("sys_user")
public class SysUser implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 员工姓名
*/
@TableField("name")
private String name;
/**
* 手机号
*/
@TableField("mobile")
private String mobile;
/**
* 岗位id
*/
@TableField("role_id")
private Integer roleId;
/**
* 密码
*/
@TableField("password")
private String password;
/**
* 状态 1-正常 0-禁用
*/
@TableField("status")
private Integer status;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField("create_time")
private Date createTime;
/**
* 创建人id
*/
@TableField("create_by")
private Integer createBy;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField("update_time")
private Date updateTime;
/**
* 更新人id
*/
@TableField("update_by")
private Integer updateBy;
/**
* 最后登录时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField("last_login_time")
private Date lastLoginTime;
/**
* 删除状态 0-正常 1-已删除
*/
@TableLogic("is_delete")
private Integer isDelete;
/**
* 创建人
*/
@TableField(exist = false)
private String createName;
/**
* 岗位/角色
*/
@TableField(exist = false)
private String roleName;
}

View File

@@ -0,0 +1,79 @@
package com.aiotagro.cattletrade.business.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.Setter;
/**
* <p>
* 预警记录表
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Getter
@Setter
@TableName("warning_log")
public class WarningLog implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 自增ID
*/
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 运单ID
*/
@TableField("delivery_id")
private Integer deliveryId;
/**
* 预警类型, 1-正常 2-盘点预警 3-距离预警
*/
@TableField("warning_type")
private String warningType;
/**
* 车内盘点耳标数量
*/
@TableField("inventory_jbq_count")
private Integer inventoryJbqCount;
/**
* 应行驶距离
*/
@TableField("expected_distance")
private String expectedDistance;
/**
* 实际行驶距离
*/
@TableField("actual_distance")
private String actualDistance;
/**
* 预警时间
*/
@TableField("warning_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date warningTime;
/**
* 预警描述
*/
@TableField(exist = false)
private String warningTypeDesc;
}

View File

@@ -0,0 +1,118 @@
package com.aiotagro.cattletrade.business.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.util.Date;
/**
* 项圈客户端实体
*
* @author System
* @date 2025-01-16
*/
@Data
@TableName(value = "xq_client", autoResultMap = true)
public class XqClient {
@TableId(type = IdType.AUTO)
private Integer id;
@TableField("org_id")
private Integer orgId;
private Integer uid;
@TableField("deviceId")
private String deviceId;
private Long sn;
private Integer state;
private String longitude;
private String latitude;
private String altitude;
@TableField("gps_state")
private String gpsState;
private Integer nsat;
private String rsrp;
private String battery;
private String temperature;
private Long steps;
@TableField("acc_x")
private String accX;
@TableField("acc_y")
private String accY;
@TableField("acc_z")
private String accZ;
@TableField("bandge_status")
private Integer bandgeStatus;
private String ver;
private Date time;
private Date uptime;
@TableField("y_steps")
private Long ySteps;
@TableField("is_wear")
private Integer isWear;
@TableField("is_temperature")
private Integer isTemperature;
@TableField("source_id")
private Long sourceId;
private String loctime;
@TableField("subType")
private Integer subType;
private Integer frequency;
@TableField("vehicle_id")
private Integer vehicleId;
@TableField("evening_frequency")
private Integer eveningFrequency;
@TableField("tenant_id")
private Integer tenantId;
/**
* 运单ID
*/
@TableField("delivery_id")
private Integer deliveryId;
/**
* 运单号
*/
@TableField("delivery_number")
private String deliveryNumber;
/**
* 车牌号
*/
@TableField("license_plate")
private String licensePlate;
}

View File

@@ -0,0 +1,18 @@
package com.aiotagro.cattletrade.business.mapper;
import com.aiotagro.cattletrade.business.entity.DeliveryDevice;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 运单设备表 Mapper 接口
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Mapper
public interface DeliveryDeviceMapper extends BaseMapper<DeliveryDevice> {
}

View File

@@ -0,0 +1,25 @@
package com.aiotagro.cattletrade.business.mapper;
import com.aiotagro.cattletrade.business.dto.DeliverListDto;
import com.aiotagro.cattletrade.business.entity.Delivery;
import com.aiotagro.cattletrade.business.vo.DeliveryLogVo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* <p>
* 运送清单表 Mapper 接口
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Mapper
public interface DeliveryMapper extends BaseMapper<Delivery> {
List<Delivery> getPageWarningLog(@Param("dto") DeliverListDto dto);
}

View File

@@ -0,0 +1,23 @@
package com.aiotagro.cattletrade.business.mapper;
import com.aiotagro.cattletrade.business.entity.JbqClientLog;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.Date;
import java.util.List;
/**
* <p>
* 智能耳标日志表 Mapper 接口
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Mapper
public interface JbqClientLogMapper extends BaseMapper<JbqClientLog> {
List<JbqClientLog> jbqLogList(@Param("deliveryId") Integer deliveryId,@Param("createTime") Date createTime,@Param("checkTime") Date checkTime);
}

View File

@@ -0,0 +1,29 @@
package com.aiotagro.cattletrade.business.mapper;
import com.aiotagro.cattletrade.business.dto.DeviceDto;
import com.aiotagro.cattletrade.business.entity.JbqClient;
import com.aiotagro.cattletrade.business.vo.JbqClientVo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* <p>
* 智能耳标表 Mapper 接口
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Mapper
public interface JbqClientMapper extends BaseMapper<JbqClient> {
List<JbqClientVo> JbqList(@Param("item") DeviceDto dto);
/**
* 查询未分配的智能耳标列表
*/
List<JbqClientVo> selectUnassignedJbqList(@Param("item") DeviceDto dto);
}

View File

@@ -0,0 +1,24 @@
package com.aiotagro.cattletrade.business.mapper;
import com.aiotagro.cattletrade.business.entity.JbqServerLog;
import com.aiotagro.cattletrade.business.vo.ServerLocationVo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.Date;
import java.util.List;
/**
* <p>
* 智能主机日志表 Mapper 接口
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Mapper
public interface JbqServerLogMapper extends BaseMapper<JbqServerLog> {
List<ServerLocationVo> selectServerLocationByTime(@Param("deviceId") String serverDeviceId,@Param("deliverTime") Date deliverTime,@Param("checkTime") Date checkTime);
}

View File

@@ -0,0 +1,24 @@
package com.aiotagro.cattletrade.business.mapper;
import com.aiotagro.cattletrade.business.dto.DeviceDto;
import com.aiotagro.cattletrade.business.entity.JbqServer;
import com.aiotagro.cattletrade.business.vo.ServerClientVo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* <p>
* 智能主机表 Mapper 接口
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Mapper
public interface JbqServerMapper extends BaseMapper<JbqServer> {
List<ServerClientVo> serverList(@Param("item") DeviceDto dto);
}

View File

@@ -0,0 +1,138 @@
package com.aiotagro.cattletrade.business.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
import java.util.Map;
/**
* Member Driver Mapper
*
* @author System
* @date 2025-01-16
*/
@Mapper
public interface MemberDriverMapper extends BaseMapper<Map<String, Object>> {
/**
* 查询司机列表关联member表获取手机号
*/
@Select("SELECT md.id, md.member_id, md.username, md.car_number, " +
"md.driving_license, md.driver_license, md.record_code, " +
"md.car_img, md.id_card, md.remark, md.create_time, m.mobile, m.status " +
"FROM member_driver md " +
"LEFT JOIN member m ON md.member_id = m.id " +
"ORDER BY md.id DESC")
List<Map<String, Object>> selectDriverList();
/**
* 根据用户名搜索司机列表关联member表获取手机号
*/
@Select("<script>" +
"SELECT md.id, md.member_id, md.username, md.car_number, " +
"md.driving_license, md.driver_license, md.record_code, " +
"md.car_img, md.id_card, md.remark, md.create_time, m.mobile, m.status " +
"FROM member_driver md " +
"LEFT JOIN member m ON md.member_id = m.id " +
"<if test='username != null and username != \"\"'>" +
"WHERE md.username LIKE CONCAT('%', #{username}, '%') OR m.mobile LIKE CONCAT('%', #{username}, '%') " +
"</if>" +
"ORDER BY md.id DESC " +
"</script>")
List<Map<String, Object>> selectDriverListByUsername(@Param("username") String username);
/**
* 根据用户名和手机号搜索司机列表(支持精确查询)
*/
@Select("SELECT md.id, md.member_id, md.username, md.car_number, " +
"md.driving_license, md.driver_license, md.record_code, " +
"md.car_img, md.id_card, md.remark, md.create_time, m.mobile, m.status " +
"FROM member_driver md " +
"LEFT JOIN member m ON md.member_id = m.id " +
"WHERE m.mobile = #{mobile} " +
"ORDER BY md.id DESC")
List<Map<String, Object>> selectDriverListByMobile(@Param("mobile") String mobile);
/**
* 根据用户名和手机号搜索司机列表(支持精确查询)
*/
@Select("<script>" +
"SELECT md.id, md.member_id, md.username, md.car_number, " +
"md.driving_license, md.driver_license, md.record_code, " +
"md.car_img, md.id_card, md.remark, md.create_time, m.mobile, m.status " +
"FROM member_driver md " +
"LEFT JOIN member m ON md.member_id = m.id " +
"WHERE 1=1 " +
"<if test='username != null and username != \"\"'>" +
" AND md.username LIKE CONCAT('%', #{username}, '%') " +
"</if>" +
"<if test='mobile != null and mobile != \"\"'>" +
" AND m.mobile = #{mobile} " +
"</if>" +
"ORDER BY md.id DESC " +
"</script>")
List<Map<String, Object>> selectDriverListBySearch(@Param("username") String username,
@Param("mobile") String mobile,
@Param("mobileExact") Boolean mobileExact);
/**
* 根据司机ID查询司机信息关联member表获取手机号
*/
@Select("SELECT md.id, md.member_id, md.username, md.car_number, " +
"md.driving_license, md.driver_license, md.record_code, " +
"md.car_img, md.id_card, md.remark, md.create_time, m.mobile, m.status " +
"FROM member_driver md " +
"LEFT JOIN member m ON md.member_id = m.id " +
"WHERE md.id = #{driverId}")
Map<String, Object> selectDriverById(@Param("driverId") Integer driverId);
/**
* 根据车牌号查询司机信息
*/
@Select("SELECT md.id, md.member_id, md.username, md.car_number, " +
"md.driving_license, md.driver_license, md.record_code, " +
"md.car_img, md.id_card, md.remark, md.create_time, m.mobile, m.status " +
"FROM member_driver md " +
"LEFT JOIN member m ON md.member_id = m.id " +
"WHERE md.car_number = #{licensePlate} " +
"ORDER BY md.create_time DESC LIMIT 1")
Map<String, Object> selectDriverByPlate(@Param("licensePlate") String licensePlate);
/**
* 新增司机信息
*/
@org.apache.ibatis.annotations.Insert("INSERT INTO member_driver (member_id, username, car_number, " +
"driver_license, driving_license, car_img, record_code, id_card, remark, create_time) " +
"VALUES (#{memberId}, #{username}, #{carNumber}, #{driverLicense}, #{drivingLicense}, " +
"#{carImg}, #{recordCode}, #{idCard}, #{remark}, NOW())")
int insertDriver(@Param("memberId") Integer memberId, @Param("username") String username,
@Param("carNumber") String carNumber, @Param("driverLicense") String driverLicense,
@Param("drivingLicense") String drivingLicense, @Param("carImg") String carImg,
@Param("recordCode") String recordCode, @Param("idCard") String idCard, @Param("remark") String remark);
/**
* 更新司机信息
*/
@org.apache.ibatis.annotations.Update("UPDATE member_driver SET username = #{username}, car_number = #{carNumber}, " +
"driver_license = #{driverLicense}, driving_license = #{drivingLicense}, car_img = #{carImg}, " +
"record_code = #{recordCode}, id_card = #{idCard}, remark = #{remark} WHERE id = #{id}")
int updateDriver(@Param("id") Integer id, @Param("username") String username, @Param("carNumber") String carNumber,
@Param("driverLicense") String driverLicense, @Param("drivingLicense") String drivingLicense,
@Param("carImg") String carImg, @Param("recordCode") String recordCode, @Param("idCard") String idCard, @Param("remark") String remark);
/**
* 根据司机姓名和车牌号查询司机信息(包含车身照片)
*/
@Select("SELECT md.id, md.member_id, md.username, md.car_number, " +
"md.driving_license, md.driver_license, md.record_code, " +
"md.car_img, md.id_card, md.remark, md.create_time, m.mobile " +
"FROM member_driver md " +
"LEFT JOIN member m ON md.member_id = m.id " +
"WHERE md.username = #{driverName} AND md.car_number = #{licensePlate}")
Map<String, Object> selectDriverByNameAndPlate(@Param("driverName") String driverName,
@Param("licensePlate") String licensePlate);
}

View File

@@ -0,0 +1,209 @@
package com.aiotagro.cattletrade.business.mapper;
import com.aiotagro.cattletrade.business.entity.Member;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Options;
import java.util.List;
import java.util.Map;
/**
* Member Mapper
*
* @author System
* @date 2025-01-16
*/
@Mapper
public interface MemberMapper extends BaseMapper<Member> {
/**
* 查询用户列表关联member_user表获取用户名
*/
@Select("SELECT m.id, m.mobile, COALESCE(mu.username, m.mobile) as name, m.type " +
"FROM member m " +
"LEFT JOIN member_user mu ON m.id = mu.member_id " +
"WHERE CAST(m.status AS UNSIGNED) = 1 " +
"ORDER BY m.id ASC")
List<Map<String, Object>> selectMemberUserList();
/**
* 根据类型查询会员列表(分页,用于装车订单下拉框)
*/
@Select("<script>" +
"SELECT m.id, m.mobile, COALESCE(mu.username, m.mobile) as username, m.type, " +
" COALESCE(st.name, '未知租户') as tenantName " +
"FROM member m " +
"LEFT JOIN member_user mu ON m.id = mu.member_id " +
"LEFT JOIN sys_tenant st ON m.tenant_id = st.id " +
"WHERE m.status = 0 " +
"<if test='type != null'>" +
" AND m.type = #{type} " +
"</if>" +
"<if test='username != null and username != \"\"'>" +
" AND (mu.username LIKE CONCAT('%', #{username}, '%') OR m.mobile LIKE CONCAT('%', #{username}, '%')) " +
"</if>" +
"ORDER BY m.id DESC " +
"LIMIT #{offset}, #{pageSize}" +
"</script>")
List<Map<String, Object>> selectMemberListByType(@Param("type") Integer type,
@Param("username") String username,
@Param("offset") Integer offset,
@Param("pageSize") Integer pageSize);
/**
* 根据类型查询会员总数
*/
@Select("<script>" +
"SELECT COUNT(*) " +
"FROM member m " +
"LEFT JOIN member_user mu ON m.id = mu.member_id " +
"WHERE m.status = 0 " +
"<if test='type != null'>" +
" AND m.type = #{type} " +
"</if>" +
"<if test='username != null and username != \"\"'>" +
" AND (mu.username LIKE CONCAT('%', #{username}, '%') OR m.mobile LIKE CONCAT('%', #{username}, '%')) " +
"</if>" +
"</script>")
Long countMemberListByType(@Param("type") Integer type, @Param("username") String username);
/**
* 查询用户列表(分页,用于用户管理页面)
* 只查询member_user表中存在的用户
*/
@Select("<script>" +
"SELECT m.id, m.mobile, CAST(m.type AS UNSIGNED) AS type, CAST(m.status AS UNSIGNED) AS status, m.create_time, m.create_by, " +
" mu.username as name, " +
" mu.cbk_account as cbkAccount, " +
" mu.remark, " +
" su.name as createName " +
"FROM member_user mu " +
"INNER JOIN member m ON mu.member_id = m.id " +
"LEFT JOIN sys_user su ON m.create_by = su.id " +
"WHERE m.status = 0 " +
"<if test='username != null and username != \"\"'>" +
" <choose>" +
" <when test='usernameExact == true'>" +
" AND mu.username = #{username} " +
" </when>" +
" <otherwise>" +
" AND mu.username LIKE CONCAT('%', #{username}, '%') " +
" </otherwise>" +
" </choose>" +
"</if>" +
"<if test='mobile != null and mobile != \"\"'>" +
" <choose>" +
" <when test='mobileExact == true'>" +
" AND m.mobile = #{mobile} " +
" </when>" +
" <otherwise>" +
" AND m.mobile LIKE CONCAT('%', #{mobile}, '%') " +
" </otherwise>" +
" </choose>" +
"</if>" +
"<if test='type != null'>" +
" AND m.type = #{type} " +
"</if>" +
"ORDER BY m.id DESC " +
"LIMIT #{offset}, #{pageSize}" +
"</script>")
List<Map<String, Object>> selectUserListForManagement(@Param("username") String username,
@Param("mobile") String mobile,
@Param("type") Integer type,
@Param("usernameExact") Boolean usernameExact,
@Param("mobileExact") Boolean mobileExact,
@Param("offset") Integer offset,
@Param("pageSize") Integer pageSize);
/**
* 查询用户总数(用于用户管理页面)
* 只计算member_user表中存在的用户
*/
@Select("<script>" +
"SELECT COUNT(*) " +
"FROM member_user mu " +
"INNER JOIN member m ON mu.member_id = m.id " +
"WHERE m.status = 0 " +
"<if test='username != null and username != \"\"'>" +
" <choose>" +
" <when test='usernameExact == true'>" +
" AND mu.username = #{username} " +
" </when>" +
" <otherwise>" +
" AND mu.username LIKE CONCAT('%', #{username}, '%') " +
" </otherwise>" +
" </choose>" +
"</if>" +
"<if test='mobile != null and mobile != \"\"'>" +
" <choose>" +
" <when test='mobileExact == true'>" +
" AND m.mobile = #{mobile} " +
" </when>" +
" <otherwise>" +
" AND m.mobile LIKE CONCAT('%', #{mobile}, '%') " +
" </otherwise>" +
" </choose>" +
"</if>" +
"<if test='type != null'>" +
" AND m.type = #{type} " +
"</if>" +
"</script>")
Long countUserListForManagement(@Param("username") String username,
@Param("mobile") String mobile,
@Param("type") Integer type,
@Param("usernameExact") Boolean usernameExact,
@Param("mobileExact") Boolean mobileExact);
/**
* 更新用户信息
* 同时更新member表和member_user表
*/
@org.apache.ibatis.annotations.Update("<script>" +
"UPDATE member m " +
"INNER JOIN member_user mu ON m.id = mu.member_id " +
"SET m.mobile = #{mobile}, " +
"m.type = #{type}, " +
"m.status = #{status}, " +
"m.update_time = NOW(), " +
"mu.username = #{username}, " +
"mu.cbk_account = #{cbkAccount}, " +
"mu.remark = #{remark} " +
"WHERE m.id = #{id}" +
"</script>")
int updateUserInfo(@Param("id") Integer id,
@Param("mobile") String mobile,
@Param("type") Integer type,
@Param("status") Integer status,
@Param("username") String username,
@Param("cbkAccount") String cbkAccount,
@Param("remark") String remark);
/**
* 根据手机号查询member记录用于获取新插入的member ID
*/
@Select("SELECT id FROM member WHERE mobile = #{mobile} ORDER BY id DESC LIMIT 1")
Integer selectMemberIdByMobile(@Param("mobile") String mobile);
/**
* 新增用户基础信息插入member表
*/
@Insert("INSERT INTO member (mobile, type, status, create_time, create_by) " +
"VALUES (#{mobile}, #{type}, #{status}, NOW(), 1)")
int insertMember(@Param("mobile") String mobile,
@Param("type") Integer type,
@Param("status") Integer status);
/**
* 新增用户详细信息插入member_user表
*/
@Insert("INSERT INTO member_user (member_id, username, cbk_account, remark, create_time) " +
"VALUES (#{memberId}, #{username}, #{cbkAccount}, #{remark}, NOW())")
int insertMemberUser(@Param("memberId") Integer memberId,
@Param("username") String username,
@Param("cbkAccount") String cbkAccount,
@Param("remark") String remark);
}

View File

@@ -0,0 +1,45 @@
package com.aiotagro.cattletrade.business.mapper;
import com.aiotagro.cattletrade.business.entity.SysMenu;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* <p>
* 系统菜单表 Mapper 接口
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Mapper
public interface SysMenuMapper extends BaseMapper<SysMenu> {
/**
* 查询用户菜单
*
* @param userId
* @return
*/
List<SysMenu> queryMenusByUserId(@Param("userId") Integer userId);
/**
* 根据岗位/角色查询菜单
*
* @param id
* @return
*/
List<SysMenu> queryListByRoleId(@Param("roleId") Integer id);
/**
* 根据角色ID查询菜单列表包含权限信息
*
* @param roleId 角色ID
* @return 菜单列表
*/
List<SysMenu> selectMenusByRoleId(@Param("roleId") Integer roleId);
}

View File

@@ -0,0 +1,18 @@
package com.aiotagro.cattletrade.business.mapper;
import com.aiotagro.cattletrade.business.entity.SysRole;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 岗位管理表 Mapper 接口
* </p>
*
* @author admin
* @since 2024-12-07
*/
@Mapper
public interface SysRoleMapper extends BaseMapper<SysRole> {
}

View File

@@ -0,0 +1,18 @@
package com.aiotagro.cattletrade.business.mapper;
import com.aiotagro.cattletrade.business.entity.SysRoleMenu;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 岗位菜单表 Mapper 接口
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Mapper
public interface SysRoleMenuMapper extends BaseMapper<SysRoleMenu> {
}

View File

@@ -0,0 +1,16 @@
package com.aiotagro.cattletrade.business.mapper;
import com.aiotagro.cattletrade.business.entity.SysTenant;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* 租户Mapper接口
*
* @author System
* @date 2025-01-16
*/
@Mapper
public interface SysTenantMapper extends BaseMapper<SysTenant> {
}

View File

@@ -0,0 +1,44 @@
package com.aiotagro.cattletrade.business.mapper;
import com.aiotagro.cattletrade.business.dto.SysUserDto;
import com.aiotagro.cattletrade.business.entity.SysUser;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* <p>
* 员工管理表 Mapper 接口
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Mapper
public interface SysUserMapper extends BaseMapper<SysUser> {
/**
* 查询用户
*
* @param dto
* @return
*/
List<SysUser> queryList(@Param("item") SysUserDto dto);
/**
* 获取用户信息
*
* @param currentUserId
* @return
*/
SysUser getUserInfoById(@Param("id") Integer currentUserId);
/**
* 查询所有用户列表(用于权限分配)
*
* @return 用户列表
*/
List<SysUser> selectUserListForPermission();
}

View File

@@ -0,0 +1,24 @@
package com.aiotagro.cattletrade.business.mapper;
import com.aiotagro.cattletrade.business.dto.DeliveryQueryDto;
import com.aiotagro.cattletrade.business.entity.WarningLog;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* <p>
* 预警记录表 Mapper 接口
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Mapper
public interface WarningLogMapper extends BaseMapper<WarningLog> {
public List<WarningLog> getNewWarningLog(@Param("dto") DeliveryQueryDto dto);
}

View File

@@ -0,0 +1,74 @@
package com.aiotagro.cattletrade.business.mapper;
import com.aiotagro.cattletrade.business.entity.XqClient;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
import java.util.Map;
/**
* 项圈客户端Mapper接口
*
* @author System
* @date 2025-01-16
*/
@Mapper
public interface XqClientMapper extends BaseMapper<XqClient> {
/**
* 查询项圈列表(带关联信息)
*/
@Select("SELECT xc.id, xc.org_id, xc.uid, xc.sn AS deviceId, xc.sn, xc.state, " +
" xc.longitude, xc.latitude, xc.altitude, xc.gps_state, " +
" xc.nsat, xc.rsrp, xc.battery, xc.temperature, xc.steps, " +
" xc.acc_x, xc.acc_y, xc.acc_z, xc.bandge_status, xc.ver, " +
" xc.time, xc.uptime, xc.y_steps, xc.is_wear, xc.is_temperature, " +
" xc.source_id, xc.loctime, xc.subType, xc.frequency, " +
" xc.vehicle_id, xc.evening_frequency, xc.tenant_id, " +
" COALESCE(dd.delivery_id, 0) AS delivery_id, " +
" COALESCE(d.delivery_number, '未分配') AS delivery_number, " +
" COALESCE(d.license_plate, md.car_number, '未分配') AS license_plate " +
"FROM xq_client xc " +
"LEFT JOIN ( " +
" SELECT device_id, delivery_id, ROW_NUMBER() OVER (PARTITION BY device_id ORDER BY id DESC) AS rn " +
" FROM delivery_device WHERE device_type = 3 " +
") dd ON CONCAT(xc.sn, '') = dd.device_id AND dd.rn = 1 " +
"LEFT JOIN delivery d ON dd.delivery_id = d.id " +
"LEFT JOIN member_driver md ON xc.vehicle_id = md.id " +
"WHERE (#{sn} IS NULL OR #{sn} = '' OR xc.sn LIKE CONCAT('%', #{sn}, '%')) " +
" AND (#{startNo} IS NULL OR #{startNo} = '' OR xc.sn >= #{startNo}) " +
" AND (#{endNo} IS NULL OR #{endNo} = '' OR xc.sn <= #{endNo}) " +
"ORDER BY xc.id DESC")
List<Map<String, Object>> selectXqClientListWithRelations(@Param("sn") String sn,
@Param("startNo") String startNo,
@Param("endNo") String endNo);
/**
* 查询未分配的智能项圈列表
*/
@Select("SELECT xc.id, xc.org_id, xc.uid, xc.sn AS deviceId, xc.sn, xc.state, " +
" xc.longitude, xc.latitude, xc.altitude, xc.gps_state, " +
" xc.nsat, xc.rsrp, xc.battery, xc.temperature, xc.steps, " +
" xc.acc_x, xc.acc_y, xc.acc_z, xc.bandge_status, xc.ver, " +
" xc.time, xc.uptime, xc.y_steps, xc.is_wear, xc.is_temperature, " +
" xc.source_id, xc.loctime, xc.subType, xc.frequency, " +
" xc.vehicle_id, xc.evening_frequency, xc.tenant_id, " +
" 0 AS delivery_id, '未分配' AS delivery_number, '未分配' AS license_plate " +
"FROM xq_client xc " +
"WHERE xc.deviceId NOT IN (" +
" SELECT DISTINCT device_id " +
" FROM delivery_device " +
" WHERE device_type = 3" +
") " +
"AND (#{sn} IS NULL OR #{sn} = '' OR xc.sn LIKE CONCAT('%', #{sn}, '%')) " +
"AND (#{startNo} IS NULL OR #{startNo} = '' OR xc.sn >= #{startNo}) " +
"AND (#{endNo} IS NULL OR #{endNo} = '' OR xc.sn <= #{endNo}) " +
"ORDER BY xc.id DESC")
List<Map<String, Object>> selectUnassignedXqClientList(@Param("sn") String sn,
@Param("startNo") String startNo,
@Param("endNo") String endNo);
}

View File

@@ -0,0 +1,16 @@
package com.aiotagro.cattletrade.business.service;
import com.aiotagro.cattletrade.business.entity.DeliveryDevice;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 运单设备表 服务类
* </p>
*
* @author admin
* @since 2024-12-26
*/
public interface IDeliveryDeviceService extends IService<DeliveryDevice> {
}

View File

@@ -0,0 +1,51 @@
package com.aiotagro.cattletrade.business.service;
import com.aiotagro.cattletrade.business.dto.DeliverListDto;
import com.aiotagro.cattletrade.business.dto.DeliveryAddDto;
import com.aiotagro.cattletrade.business.dto.DeliveryCreateDto;
import com.aiotagro.cattletrade.business.dto.DeliveryEditDto;
import com.aiotagro.cattletrade.business.dto.DeliveryQueryDto;
import com.aiotagro.cattletrade.business.entity.Delivery;
import com.aiotagro.cattletrade.business.vo.DeliveryLogVo;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 运送清单表 服务类
* </p>
*
* @author admin
* @since 2024-12-26
*/
public interface IDeliveryService extends IService<Delivery> {
AjaxResult addDelivery(DeliveryAddDto dto);
/**
* 创建运送清单PC端
*
* @param dto 运送清单创建DTO
* @return AjaxResult
*/
AjaxResult createDelivery(DeliveryCreateDto dto);
/**
* 编辑运送清单
*
* @param dto 运送清单编辑DTO
* @return AjaxResult
*/
AjaxResult updateDeliveryInfo(DeliveryEditDto dto);
PageResultResponse<Delivery> pageQuery(DeliveryQueryDto dto);
AjaxResult viewDelivery(Integer id);
PageResultResponse<DeliveryLogVo> pageQueryList(DeliverListDto dto);
AjaxResult detail(Integer id);
PageResultResponse<Delivery> pageQueryListLog(DeliverListDto dto);
}

View File

@@ -0,0 +1,19 @@
package com.aiotagro.cattletrade.business.service;
import com.aiotagro.cattletrade.business.dto.JbqLogDto;
import com.aiotagro.cattletrade.business.entity.JbqClientLog;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 智能耳标日志表 服务类
* </p>
*
* @author admin
* @since 2024-12-26
*/
public interface IJbqClientLogService extends IService<JbqClientLog> {
PageResultResponse jbqLogList(JbqLogDto dto);
}

View File

@@ -0,0 +1,29 @@
package com.aiotagro.cattletrade.business.service;
import com.aiotagro.cattletrade.business.dto.DeviceDto;
import com.aiotagro.cattletrade.business.entity.JbqClient;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 智能耳标表 服务类
* </p>
*
* @author admin
* @since 2024-12-26
*/
public interface IJbqClientService extends IService<JbqClient> {
PageResultResponse jbqList(DeviceDto dto);
/**
* 根据运送清单ID查询设备列表
*
* @param deliveryId 运送清单ID
* @param deviceType 设备类型
* @return AjaxResult
*/
AjaxResult getDevicesByDeliveryId(Integer deliveryId, Integer deviceType);
}

View File

@@ -0,0 +1,16 @@
package com.aiotagro.cattletrade.business.service;
import com.aiotagro.cattletrade.business.entity.JbqServerLog;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 智能主机日志表 服务类
* </p>
*
* @author admin
* @since 2024-12-26
*/
public interface IJbqServerLogService extends IService<JbqServerLog> {
}

View File

@@ -0,0 +1,25 @@
package com.aiotagro.cattletrade.business.service;
import com.aiotagro.cattletrade.business.dto.DeviceDto;
import com.aiotagro.cattletrade.business.dto.ServerLocationDto;
import com.aiotagro.cattletrade.business.entity.JbqServer;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 智能主机表 服务类
* </p>
*
* @author admin
* @since 2024-12-26
*/
public interface IJbqServerService extends IService<JbqServer> {
PageResultResponse serverList(DeviceDto dto);
AjaxResult serverLocation(ServerLocationDto dto);
AjaxResult serverTrack(ServerLocationDto dto);
}

View File

@@ -0,0 +1,50 @@
package com.aiotagro.cattletrade.business.service;
import com.aiotagro.cattletrade.business.dto.SysRoleDto;
import com.aiotagro.cattletrade.business.entity.SysRole;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 岗位管理表 服务类
* </p>
*
* @author admin
* @since 2024-12-26
*/
public interface ISysRoleService extends IService<SysRole> {
/**
* 查询分页列表
*
* @param dto
* @return
*/
PageResultResponse queryList(SysRoleDto dto);
/**
* 新增、编辑
*
* @param role
* @return
*/
AjaxResult saveRole(SysRole role);
/**
* 删除
*
* @param id
* @return
*/
AjaxResult delete(Integer id);
/**
* 查询菜单
*
* @return
*/
AjaxResult getMenus(Integer id);
}

View File

@@ -0,0 +1,43 @@
package com.aiotagro.cattletrade.business.service;
import com.aiotagro.cattletrade.business.dto.SysUserDto;
import com.aiotagro.cattletrade.business.entity.SysUser;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 员工管理表 服务类
* </p>
*
* @author admin
* @since 2024-12-26
*/
public interface ISysUserService extends IService<SysUser> {
/**
* 查询分页列表
*
* @param dto
* @return
*/
PageResultResponse queryList(SysUserDto dto);
/**
* 新增、编辑
*
* @param user
* @return
*/
AjaxResult saveUser(SysUser user);
/**
* 删除
*
* @param id
* @return
*/
AjaxResult delete(Integer id);
}

View File

@@ -0,0 +1,40 @@
package com.aiotagro.cattletrade.business.service;
import com.aiotagro.cattletrade.business.dto.DeliveryQueryDto;
import com.aiotagro.cattletrade.business.dto.DeliverListDto;
import com.aiotagro.cattletrade.business.entity.WarningLog;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.cattletrade.business.vo.DeliveryLogVo;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* <p>
* 预警记录表 服务类
* </p>
*
* @author admin
* @since 2024-12-26
*/
public interface IWarningLogService extends IService<WarningLog> {
/**
* 供远程调用-保存预警日志
*
* @param deviceId
* @return
*/
AjaxResult savaWarn(String deviceId);
AjaxResult warningCount();
PageResultResponse<DeliveryLogVo> queryList(DeliveryQueryDto dto);
/**
* 预警详情查看
* @param id
* @return
*/
AjaxResult warningDetail(Integer id);
}

View File

@@ -0,0 +1,43 @@
package com.aiotagro.cattletrade.business.service;
import com.aiotagro.cattletrade.business.entity.XqClient;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.Map;
/**
* 项圈客户端服务接口
*
* @author System
* @date 2025-01-16
*/
public interface IXqClientService extends IService<XqClient> {
/**
* 分页查询项圈列表
*/
PageResultResponse xqList(Map<String, Object> params);
/**
* 根据运送清单ID查询设备列表
*/
AjaxResult getDevicesByDeliveryId(Integer deliveryId, Integer deviceType);
/**
* 查询项圈位置信息
*/
AjaxResult getCollarLocation(String deliveryId, String xqDeviceId);
/**
* 查询项圈轨迹
*/
AjaxResult getCollarTrack(String deliveryId, String xqDeviceId, String trackTime, String trackEndTime);
/**
* 查询设备轨迹
*/
AjaxResult getCollarDeviceTrack(String deliveryId, String xqDeviceId, String trackTime, String trackEndTime);
}

View File

@@ -0,0 +1,37 @@
package com.aiotagro.cattletrade.business.service;
import com.aiotagro.cattletrade.business.dto.LoginDto;
import com.aiotagro.common.core.web.domain.AjaxResult;
public interface LoginService {
/**
* 发送验证码
*
* @param mobile
* @return
*/
AjaxResult sendLoginSmsCode(String mobile);
/**
* 用户登录
*
* @param dto
* @return
*/
AjaxResult login(LoginDto dto);
/**
* 查询菜单
*
* @return
*/
AjaxResult getUserMenus();
/**
* rfid获取用户信息
*
* @return
*/
AjaxResult getUserInfo();
}

View File

@@ -0,0 +1,6 @@
package com.aiotagro.cattletrade.business.service;
public interface TencentSmsCodeService {
String sendSmsCode(String mobile, String code);
}

View File

@@ -0,0 +1,20 @@
package com.aiotagro.cattletrade.business.service.impl;
import com.aiotagro.cattletrade.business.entity.DeliveryDevice;
import com.aiotagro.cattletrade.business.mapper.DeliveryDeviceMapper;
import com.aiotagro.cattletrade.business.service.IDeliveryDeviceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
* 运单设备表 服务实现类
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Service
public class DeliveryDeviceServiceImpl extends ServiceImpl<DeliveryDeviceMapper, DeliveryDevice> implements IDeliveryDeviceService {
}

View File

@@ -0,0 +1,53 @@
package com.aiotagro.cattletrade.business.service.impl;
import com.aiotagro.cattletrade.business.dto.JbqLogDto;
import com.aiotagro.cattletrade.business.entity.Delivery;
import com.aiotagro.cattletrade.business.entity.JbqClientLog;
import com.aiotagro.cattletrade.business.mapper.DeliveryMapper;
import com.aiotagro.cattletrade.business.mapper.JbqClientLogMapper;
import com.aiotagro.cattletrade.business.service.IJbqClientLogService;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
/**
* <p>
* 智能耳标日志表 服务实现类
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Service
public class JbqClientLogServiceImpl extends ServiceImpl<JbqClientLogMapper, JbqClientLog> implements IJbqClientLogService {
@Autowired
private JbqClientLogMapper jbqServerMapper;
@Autowired
private DeliveryMapper deliveryMapper;
@Override
public PageResultResponse jbqLogList(JbqLogDto dto) {
if (dto.getDeliveryId() == null) {
return new PageResultResponse(500, "运单id不能为空");
}
Delivery delivery = deliveryMapper.selectById(dto.getDeliveryId());
if (delivery == null) {
return new PageResultResponse(500, "运单不存在");
}
Integer deliveryId = dto.getDeliveryId();
Date createTime = delivery.getCreateTime();
Date checkTime = delivery.getCheckTime();
if (checkTime == null) {
checkTime = new Date();
}
Page<JbqClientLog> result = PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
List<JbqClientLog> list = jbqServerMapper.jbqLogList(deliveryId,createTime,checkTime);
return new PageResultResponse(result.getTotal(), list);
}
}

View File

@@ -0,0 +1,125 @@
package com.aiotagro.cattletrade.business.service.impl;
import com.aiotagro.cattletrade.business.dto.DeviceDto;
import com.aiotagro.cattletrade.business.entity.DeliveryDevice;
import com.aiotagro.cattletrade.business.entity.JbqClient;
import com.aiotagro.cattletrade.business.mapper.DeliveryDeviceMapper;
import com.aiotagro.cattletrade.business.mapper.JbqClientMapper;
import com.aiotagro.cattletrade.business.service.IJbqClientService;
import com.aiotagro.cattletrade.business.vo.JbqClientVo;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* <p>
* 智能耳标表 服务实现类
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Service
public class JbqClientServiceImpl extends ServiceImpl<JbqClientMapper, JbqClient> implements IJbqClientService {
@Autowired
private JbqClientMapper jbqClientMapper;
@Autowired
private DeliveryDeviceMapper deliveryDeviceMapper;
@Override
public PageResultResponse jbqList(DeviceDto dto) {
Page<JbqClient> result = PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
try {
// 如果指定了只查询未分配的设备
if (dto.getUnassignedOnly() != null && dto.getUnassignedOnly()) {
System.out.println("查询未分配的智能耳标,参数: " + dto);
List<JbqClientVo> list = jbqClientMapper.selectUnassignedJbqList(dto);
System.out.println("未分配智能耳标查询结果数量: " + (list != null ? list.size() : 0));
return new PageResultResponse(result.getTotal(), list);
} else {
System.out.println("查询所有智能耳标,参数: " + dto);
List<JbqClientVo> list = jbqClientMapper.JbqList(dto);
System.out.println("所有智能耳标查询结果数量: " + (list != null ? list.size() : 0));
return new PageResultResponse(result.getTotal(), list);
}
} catch (Exception e) {
System.out.println("查询智能耳标失败: " + e.getMessage());
e.printStackTrace();
return new PageResultResponse(0L, new ArrayList<>());
}
}
@Override
public AjaxResult getDevicesByDeliveryId(Integer deliveryId, Integer deviceType) {
System.out.println("=== 查询耳标设备deliveryId: " + deliveryId + ", deviceType: " + deviceType);
if (deliveryId == null) {
return AjaxResult.error("运送清单ID不能为空");
}
// 查询运送清单关联的设备
LambdaQueryWrapper<DeliveryDevice> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DeliveryDevice::getDeliveryId, deliveryId);
wrapper.eq(DeliveryDevice::getDeviceType, deviceType);
List<DeliveryDevice> deliveryDevices = deliveryDeviceMapper.selectList(wrapper);
System.out.println("=== 查询到delivery_device记录数: " + deliveryDevices.size());
if (!deliveryDevices.isEmpty()) {
System.out.println("=== delivery_device记录详情: " + deliveryDevices);
}
if (deliveryDevices.isEmpty()) {
return AjaxResult.success(new ArrayList<>());
}
// 获取设备ID列表
List<String> deviceIds = deliveryDevices.stream()
.map(DeliveryDevice::getDeviceId)
.collect(Collectors.toList());
// 查询设备详细信息 - 只查询基础字段,避免查询不存在的扩展字段
LambdaQueryWrapper<JbqClient> deviceWrapper = new LambdaQueryWrapper<>();
deviceWrapper.in(JbqClient::getDeviceId, deviceIds)
.select(JbqClient::getId,
JbqClient::getDeviceId,
JbqClient::getDeviceVoltage,
JbqClient::getDeviceTemp,
JbqClient::getServerDeviceId,
JbqClient::getLatitude,
JbqClient::getLongitude,
JbqClient::getWalkSteps,
JbqClient::getYWalkSteps,
JbqClient::getCreateTime,
JbqClient::getCreateBy,
JbqClient::getUpdateTime,
JbqClient::getUpdateBy,
JbqClient::getSourceId);
List<JbqClient> devices = jbqClientMapper.selectList(deviceWrapper);
System.out.println("=== 查询到的耳标设备数量: " + devices.size());
for (JbqClient device : devices) {
System.out.println("=== 耳标设备: " + device);
}
// 返回分页格式数据
Map<String, Object> result = new HashMap<>();
result.put("rows", devices);
result.put("total", devices.size());
return AjaxResult.success(result);
}
}

View File

@@ -0,0 +1,20 @@
package com.aiotagro.cattletrade.business.service.impl;
import com.aiotagro.cattletrade.business.entity.JbqServerLog;
import com.aiotagro.cattletrade.business.mapper.JbqServerLogMapper;
import com.aiotagro.cattletrade.business.service.IJbqServerLogService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
/**
* <p>
* 智能主机日志表 服务实现类
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Service
public class JbqServerLogServiceImpl extends ServiceImpl<JbqServerLogMapper, JbqServerLog> implements IJbqServerLogService {
}

View File

@@ -0,0 +1,142 @@
package com.aiotagro.cattletrade.business.service.impl;
import com.aiotagro.cattletrade.business.dto.DeviceDto;
import com.aiotagro.cattletrade.business.dto.ServerLocationDto;
import com.aiotagro.cattletrade.business.entity.Delivery;
import com.aiotagro.cattletrade.business.entity.JbqServer;
import com.aiotagro.cattletrade.business.mapper.DeliveryMapper;
import com.aiotagro.cattletrade.business.mapper.JbqServerLogMapper;
import com.aiotagro.cattletrade.business.mapper.JbqServerMapper;
import com.aiotagro.cattletrade.business.service.IJbqServerService;
import com.aiotagro.cattletrade.business.vo.ServerClientVo;
import com.aiotagro.cattletrade.business.vo.ServerLocationVo;
import com.aiotagro.common.core.utils.DateUtils;
import com.aiotagro.common.core.utils.LngLonUtil;
import com.aiotagro.common.core.utils.StringUtils;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
/**
* <p>
* 智能主机表 服务实现类
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Service
public class JbqServerServiceImpl extends ServiceImpl<JbqServerMapper, JbqServer> implements IJbqServerService {
@Autowired
private JbqServerMapper jbqServerMapper;
@Autowired
private JbqServerLogMapper jbqServerLogMapper;
@Autowired
private DeliveryMapper deliveryMapper;
@Override
public PageResultResponse serverList(DeviceDto dto) {
Page<ServerClientVo> result = PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
List<ServerClientVo> list = jbqServerMapper.serverList(dto);
return new PageResultResponse(result.getTotal(), list);
}
@Override
public AjaxResult serverLocation(ServerLocationDto dto) {
if (!StringUtils.hasText(dto.getServerDeviceId())){
return AjaxResult.error("主机编号不能为空");
}
LambdaQueryWrapper<JbqServer> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(JbqServer::getDeviceId, dto.getServerDeviceId());
//查询主机数据
JbqServer server = jbqServerMapper.selectOne(wrapper);
if (server == null) {
return AjaxResult.error("未找到对应的设备信息");
}
// 获取设备的经纬度
String latitude = server.getLatitude();
String longitude = server.getLongitude();
// 判断经纬度是否为空或为0
if (isInvalidLocation(latitude, longitude)) {
return AjaxResult.error("暂无定位信息");
}
// 转换为百度经纬度
double lat = Double.parseDouble(latitude);
double lon = Double.parseDouble(longitude);
double[] baiduLocation = LngLonUtil.gps84_To_bd09(lat, lon);
ServerLocationVo serverLocationVo = new ServerLocationVo();
serverLocationVo.setDeviceId(dto.getServerDeviceId());
serverLocationVo.setLatitude(String.valueOf(baiduLocation[0]));
serverLocationVo.setLongitude(String.valueOf(baiduLocation[1]));
serverLocationVo.setUpdateTime(server.getUpdateTime());
return AjaxResult.success(serverLocationVo);
}
@Override
public AjaxResult serverTrack(ServerLocationDto dto) {
if (dto.getDeliveryId() == null) {
return AjaxResult.error("id不能为空");
}
if (!StringUtils.hasText(dto.getServerDeviceId())){
return AjaxResult.error("主机编号不能为空");
}
//启运时间
Delivery delivery = deliveryMapper.selectById(dto.getDeliveryId());
if (delivery == null) {
return AjaxResult.error("未找到相关运单信息");
}
Date deliverTime = delivery.getCreateTime();
Date checkTime = (delivery.getCheckTime() != null) ? delivery.getCheckTime() :
DateUtils.stringToDate(DateUtils.getTime(), DateUtils.YYYY_MM_DD_HH_MM_SS);
if (deliverTime == null) {
return AjaxResult.error("启运时间为空");
}
// 轨迹
List<ServerLocationVo> serverLocations = jbqServerLogMapper.selectServerLocationByTime(dto.getServerDeviceId(), deliverTime, checkTime);
if (serverLocations != null && !serverLocations.isEmpty()) {
// 过滤掉经纬度/坐标转换
serverLocations = serverLocations.stream()
.filter(location -> {
return StringUtils.hasText(location.getLatitude())
&& StringUtils.hasText(location.getLongitude())
&& !"0".equals(location.getLatitude())
&& !"0".equals(location.getLongitude());
})
.peek(location -> {
double latitude = Double.parseDouble(location.getLatitude());
double longitude = Double.parseDouble(location.getLongitude());
double[] bd09 = LngLonUtil.gps84_To_bd09(latitude, longitude);
location.setLatitude(String.valueOf(bd09[0]));
location.setLongitude(String.valueOf(bd09[1]));
})
.collect(Collectors.toList());
return AjaxResult.success(serverLocations);
} else {
return AjaxResult.error("没有找到符合条件的设备位置信息");
}
}
public boolean isInvalidLocation(String latitude, String longitude) {
return latitude == null || latitude.isEmpty() || "0".equals(latitude) ||
longitude == null || longitude.isEmpty() || "0".equals(longitude);
}
}

View File

@@ -0,0 +1,180 @@
package com.aiotagro.cattletrade.business.service.impl;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.stp.SaLoginConfig;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.aiotagro.cattletrade.business.dto.LoginDto;
import com.aiotagro.cattletrade.business.entity.SysMenu;
import com.aiotagro.cattletrade.business.entity.SysRole;
import com.aiotagro.cattletrade.business.entity.SysUser;
import com.aiotagro.cattletrade.business.mapper.SysMenuMapper;
import com.aiotagro.cattletrade.business.mapper.SysRoleMapper;
import com.aiotagro.cattletrade.business.mapper.SysUserMapper;
import com.aiotagro.cattletrade.business.service.LoginService;
import com.aiotagro.cattletrade.business.service.TencentSmsCodeService;
import com.aiotagro.common.core.constant.Constants;
import com.aiotagro.common.core.constant.RoleConstants;
import com.aiotagro.common.core.exception.ServiceException;
import com.aiotagro.common.core.utils.SecurityUtil;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.redis.service.RedisService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import com.aiotagro.common.core.utils.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j
@Service
public class LoginServiceImpl implements LoginService {
@Resource
private RedisService redisService;
@Resource
SysUserMapper userMapper;
@Resource
TencentSmsCodeService tencentSmsCodeService;
@Resource
SysMenuMapper menuMapper;
@Resource
SysRoleMapper roleMapper;
@Override
public AjaxResult sendLoginSmsCode(String mobile) {
// 临时跳过Redis验证码存储直接返回成功
SysUser user = userMapper.selectOne(new QueryWrapper<SysUser>().lambda().eq(SysUser::getMobile, mobile).eq(SysUser::getIsDelete, 0));
if (null == user || user.getIsDelete() == 1) {
return AjaxResult.error("手机号不存在!");
}
if (user.getStatus() == 0) {
return AjaxResult.error("手机号已被禁用!");
}
log.warn("短信验证码发送暂时跳过Redis存储直接返回成功");
return AjaxResult.success("验证码发送成功");
}
@Override
public AjaxResult login(LoginDto dto) {
log.info(dto.toString());
SysUser user = userMapper.selectOne(new QueryWrapper<SysUser>().lambda().eq(SysUser::getMobile, dto.getMobile()).eq(SysUser::getIsDelete, 0));
if (dto.getLoginType() == 0) {
// 判断用户存不存在
if (null == user || user.getIsDelete() == 1) {
return AjaxResult.error("员工不存在!");
}
if (user.getStatus() == 0) {
return AjaxResult.error("此账号已禁用!");
}
// 密码校验
String passwordMd5 = DigestUtil.md5Hex(Constants.USER_PASSWORD_PREFIX + dto.getPassword());
if (!passwordMd5.equals(user.getPassword())) {
throw new ServiceException("密码错误!");
}
} else if (dto.getLoginType() == 1) {
// 短信验证码校验 - 临时跳过Redis验证
log.warn("短信验证码登录暂时跳过Redis验证直接允许登录");
}
// 更新登录时间
user.setLastLoginTime(new Date());
userMapper.updateById(user);
log.info(user.toString());
// 登录成功写入缓存数据并返回token值
StpUtil.login(user.getId(), SaLoginConfig
.setExtra("username", user.getName())
.setExtra("userId", user.getId())
.setExtra("mobile", user.getMobile())
.setExtra("roleId", user.getRoleId())
);
// 存储角色ID到session
StpUtil.getTokenSession().set("roleId", user.getRoleId());
// 存储用户名与手机号到session便于业务侧读取
StpUtil.getTokenSession().set("username", user.getName());
StpUtil.getTokenSession().set("mobile", user.getMobile());
// 调试日志验证TokenSession写入
log.info("=== TokenSession 写入调试 ===");
log.info("写入 username: {}", user.getName());
log.info("写入 mobile: {}", user.getMobile());
log.info("写入 roleId: {}", user.getRoleId());
// 立即验证读取
Object sessionUsername = StpUtil.getTokenSession().get("username");
Object sessionMobile = StpUtil.getTokenSession().get("mobile");
Object sessionRoleId = StpUtil.getTokenSession().get("roleId");
log.info("验证读取 username: {}", sessionUsername);
log.info("验证读取 mobile: {}", sessionMobile);
log.info("验证读取 roleId: {}", sessionRoleId);
// 查询用户权限列表
List<String> permissions = queryUserPermissions(user.getRoleId());
StpUtil.getTokenSession().set("permissions", permissions);
// 查询用户角色信息
SysRole role = roleMapper.selectById(user.getRoleId());
String roleCode = role != null ? role.getName() : "";
StpUtil.getTokenSession().set("roleCode", roleCode);
Map<String, Object> map = new HashMap<String, Object>();
map.put("token", SaManager.getConfig().getTokenPrefix() + " " + StpUtil.getTokenValue());
map.put("username", user.getName());
map.put("userId", user.getId());
map.put("mobile", user.getMobile());
map.put("roleId", user.getRoleId());
map.put("permissions", permissions); // 返回权限列表
return AjaxResult.success("登录成功", map);
}
@Override
public AjaxResult getUserMenus() {
Integer userId = SecurityUtil.getCurrentUserId();
List<SysMenu> menus = menuMapper.queryMenusByUserId(userId);
return AjaxResult.success("查询成功", menus);
}
@Override
public AjaxResult getUserInfo() {
SysUser user = userMapper.getUserInfoById(SecurityUtil.getCurrentUserId());
return AjaxResult.success(user);
}
/**
* 查询用户权限列表
*
* @param roleId 角色ID
* @return 权限列表
*/
private List<String> queryUserPermissions(Integer roleId) {
if (roleId == null) {
return Collections.emptyList();
}
// 如果是超级管理员,返回所有权限
if (roleId.equals(RoleConstants.SUPER_ADMIN_ROLE_ID)) {
return Collections.singletonList(RoleConstants.ALL_PERMISSION);
}
// 查询角色关联的菜单权限
List<SysMenu> menus = menuMapper.selectMenusByRoleId(roleId);
return menus.stream()
.filter(menu -> StringUtils.isNotEmpty(menu.getAuthority()))
.map(SysMenu::getAuthority)
.distinct()
.collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,117 @@
package com.aiotagro.cattletrade.business.service.impl;
import com.aiotagro.cattletrade.business.dto.SysRoleDto;
import com.aiotagro.cattletrade.business.entity.SysMenu;
import com.aiotagro.cattletrade.business.entity.SysRole;
import com.aiotagro.cattletrade.business.entity.SysRoleMenu;
import com.aiotagro.cattletrade.business.entity.SysUser;
import com.aiotagro.cattletrade.business.mapper.SysMenuMapper;
import com.aiotagro.cattletrade.business.mapper.SysRoleMapper;
import com.aiotagro.cattletrade.business.mapper.SysRoleMenuMapper;
import com.aiotagro.cattletrade.business.mapper.SysUserMapper;
import com.aiotagro.cattletrade.business.service.ISysRoleService;
import com.aiotagro.common.core.utils.StringUtils;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.Date;
import java.util.List;
/**
* <p>
* 岗位管理表 服务实现类
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements ISysRoleService {
@Autowired
private SysUserMapper userMapper;
@Autowired
private SysRoleMenuMapper roleMenuMapper;
@Autowired
private SysMenuMapper menuMapper;
@Override
public PageResultResponse queryList(SysRoleDto dto) {
Page<SysRole> result = PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysRole::getIsDelete, 0).orderByDesc(SysRole::getCreateTime);
if (StringUtils.hasText(dto.getName())) {
wrapper.like(SysRole::getName, dto.getName());
}
List<SysRole> list = list(wrapper);
return new PageResultResponse(result.getTotal(), list);
}
@Override
@Transactional(rollbackFor = Exception.class)
public AjaxResult saveRole(SysRole role) {
if (role.getId() == null) {
save(role);
} else {
role.setUpdateTime(new Date());
updateById(role);
}
// 先删除岗位菜单
roleMenuMapper.delete(Wrappers.<SysRoleMenu>query().lambda().eq(SysRoleMenu::getRoleId, role.getId()));
// 再新增
for (Integer menuId : role.getMenuIds()) {
SysRoleMenu roleMenu = new SysRoleMenu();
roleMenu.setRoleId(role.getId());
roleMenu.setMenuId(menuId);
roleMenuMapper.insert(roleMenu);
}
return AjaxResult.success();
}
@Override
@Transactional(rollbackFor = Exception.class)
public AjaxResult delete(Integer id) {
SysRole role = getById(id);
if (null == role || role.getIsDelete() == 1) {
return AjaxResult.error("岗位不存在");
}
List<SysUser> users = userMapper.selectList(Wrappers.<SysUser>query().lambda().eq(SysUser::getIsDelete, 0).eq(SysUser::getRoleId, id));
if (!CollectionUtils.isEmpty(users)) {
return AjaxResult.error("此岗位关联员工,请移除员工后再删除");
}
// 删除岗位/角色
removeById(id);
// 删除岗位/角色菜单
roleMenuMapper.delete(Wrappers.<SysRoleMenu>query().lambda().eq(SysRoleMenu::getRoleId, id));
return AjaxResult.success();
}
@Override
public AjaxResult getMenus(Integer id) {
SysRole role = null;
if (id != null) {
role = getById(id);
}
if (role == null) {
role = new SysRole();
}
List<SysMenu> menus = menuMapper.queryListByRoleId(id);
role.setMenuList(menus);
return AjaxResult.success(role);
}
}

View File

@@ -0,0 +1,86 @@
package com.aiotagro.cattletrade.business.service.impl;
import cn.hutool.crypto.digest.DigestUtil;
import com.aiotagro.cattletrade.business.dto.SysUserDto;
import com.aiotagro.cattletrade.business.entity.SysUser;
import com.aiotagro.cattletrade.business.mapper.SysUserMapper;
import com.aiotagro.cattletrade.business.service.ISysUserService;
import com.aiotagro.common.core.constant.Constants;
import com.aiotagro.common.core.utils.SecurityUtil;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import com.aiotagro.common.core.utils.StringUtils;
import java.util.List;
/**
* <p>
* 员工管理表 服务实现类
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {
@Autowired(required = false)
private SysUserMapper sysUserMapper;
@Override
public PageResultResponse queryList(SysUserDto dto) {
Page<SysUser> result = PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
List<SysUser> list = sysUserMapper.queryList(dto);
return new PageResultResponse(result.getTotal(), list);
}
@Override
@Transactional(rollbackFor = Exception.class)
public AjaxResult saveUser(SysUser user) {
List<SysUser> users = sysUserMapper.selectList(Wrappers.<SysUser>query().lambda().eq(SysUser::getIsDelete, 0).eq(SysUser::getMobile, user.getMobile()));
// 新增
if (user.getId() == null) {
if (!CollectionUtils.isEmpty(users)) {
return AjaxResult.error("手机号已存在");
}
if (StringUtils.isEmpty(user.getPassword())) {
user.setPassword("123456");
}
user.setPassword(DigestUtil.md5Hex(Constants.USER_PASSWORD_PREFIX + user.getPassword()));
user.setCreateBy(SecurityUtil.getCurrentUserId());
save(user);
} else {
// 编辑
if (!CollectionUtils.isEmpty(users) && !users.get(0).getId().equals(user.getId())) {
return AjaxResult.error("手机号已存在");
}
SysUser sysUser = getById(user.getId());
sysUser.setName(user.getName());
sysUser.setRoleId(user.getRoleId());
sysUser.setMobile(user.getMobile());
sysUser.setStatus(user.getStatus());
// 传了新密码才更新
if (StringUtils.isNotEmpty(user.getPassword())) {
sysUser.setPassword(DigestUtil.md5Hex(Constants.USER_PASSWORD_PREFIX + user.getPassword()));
}
sysUser.setUpdateBy(SecurityUtil.getCurrentUserId());
updateById(sysUser);
}
return AjaxResult.success();
}
@Override
public AjaxResult delete(Integer id) {
removeById(id);
return AjaxResult.success();
}
}

View File

@@ -0,0 +1,102 @@
package com.aiotagro.cattletrade.business.service.impl;
import com.aiotagro.cattletrade.business.service.TencentSmsCodeService;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.sms.v20190711.SmsClient;
import com.tencentcloudapi.sms.v20190711.models.SendSmsRequest;
import com.tencentcloudapi.sms.v20190711.models.SendSmsResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@Service
public class TencentSmsCodeServiceImpl implements TencentSmsCodeService {
@Value("${sms.secret-id}")
private String secretId;
@Value("${sms.secret-key}")
private String secretKey;
@Value("${sms.end-point}")
private String endPoint;
@Value("${sms.appid}")
private String appid;
@Value("${sms.sign}")
private String sign;
@Value("${sms.template-id}")
private String templateId;
@Override
public String sendSmsCode(String mobile, String code) {
Credential cred = new Credential(secretId, secretKey);
// 实例化一个 http 选项,可选,无特殊需求时可以跳过
HttpProfile httpProfile = new HttpProfile();
/* SDK 默认使用 POST 方法。
* 如需使用 GET 方法,可以在此处设置,但 GET 方法无法处理较大的请求 */
httpProfile.setReqMethod("POST");
/* SDK 有默认的超时时间,非必要请不要进行调整
* 如有需要请在代码中查阅以获取最新的默认值 */
httpProfile.setConnTimeout(60);
/* SDK 会自动指定域名,通常无需指定域名,但访问金融区的服务时必须手动指定域名
* 例如 SMS 的上海金融区域名为 sms.ap-shanghai-fsi.tencentcloudapi.com */
httpProfile.setEndpoint(endPoint);
/* 非必要步骤:
* 实例化一个客户端配置对象,可以指定超时时间等配置 */
ClientProfile clientProfile = new ClientProfile();
/* SDK 默认用 TC3-HMAC-SHA256 进行签名
* 非必要请不要修改该字段 */
clientProfile.setSignMethod("HmacSHA256");
clientProfile.setHttpProfile(httpProfile);
/* 实例化 SMS 的 client 对象
* 第二个参数是地域信息,可以直接填写字符串 ap-guangzhou或者引用预设的常量 */
SmsClient client = new SmsClient(cred, "ap-guangzhou", clientProfile);
/* 实例化一个请求对象,根据调用的接口和实际情况,可以进一步设置请求参数
* 您可以直接查询 SDK 源码确定接口有哪些属性可以设置
* 属性可能是基本类型,也可能引用了另一个数据结构
* 推荐使用 IDE 进行开发,可以方便地跳转查阅各个接口和数据结构的文档说明 */
SendSmsRequest req = new SendSmsRequest();
/* 填充请求参数,这里 request 对象的成员变量即对应接口的入参
* 您可以通过官网接口文档或跳转到 request 对象的定义处查看请求参数的定义
* 基本类型的设置:
* 帮助链接:
* 短信控制台https://console.cloud.tencent.com/smsv2
* sms helperhttps://cloud.tencent.com/document/product/382/3773 */
/* 短信应用 ID: 在 [短信控制台] 添加应用后生成的实际 SDKAppID例如1400006666 */
req.setSmsSdkAppid(appid);
/* 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名,可登录 [短信控制台] 查看签名信息 */
req.setSign(sign);
/* 模板 ID: 必须填写已审核通过的模板 ID可登录 [短信控制台] 查看模板 ID */
req.setTemplateID(templateId);
/* 下发手机号码,采用 e.164 标准,+[国家或地区码][手机号]
* 例如+8613711112222 其中前面有一个+号 86为国家码13711112222为手机号最多不要超过200个手机号*/
String[] phoneNumbers = {"+86" + mobile};
req.setPhoneNumberSet(phoneNumbers);
/* 模板参数: 若无模板参数,则设置为空*/
String[] templateParams = {code};
req.setTemplateParamSet(templateParams);
try {
/* 通过 client 对象调用 SendSms 方法发起请求。注意请求方法名与请求对象是对应的
* 返回的 res 是一个 SendSmsResponse 类的实例,与请求对象对应 */
SendSmsResponse res = client.SendSms(req);
// 输出 JSON 格式的字符串回包
System.out.println(SendSmsResponse.toJsonString(res));
// 可以取出单个值,您可以通过官网接口文档或跳转到 response 对象的定义处查看返回字段的定义
System.out.println(res.getRequestId());
} catch (Exception e) {
return "发送失败";
}
return null;
}
}

View File

@@ -0,0 +1,239 @@
package com.aiotagro.cattletrade.business.service.impl;
import com.aiotagro.cattletrade.business.dto.DeliveryQueryDto;
import com.aiotagro.cattletrade.business.dto.WarningDetailDto;
import com.aiotagro.cattletrade.business.entity.Delivery;
import com.aiotagro.cattletrade.business.entity.DeliveryDevice;
import com.aiotagro.cattletrade.business.entity.JbqServerLog;
import com.aiotagro.cattletrade.business.entity.WarningLog;
import com.aiotagro.cattletrade.business.mapper.DeliveryDeviceMapper;
import com.aiotagro.cattletrade.business.mapper.DeliveryMapper;
import com.aiotagro.cattletrade.business.mapper.JbqServerLogMapper;
import com.aiotagro.cattletrade.business.mapper.WarningLogMapper;
import com.aiotagro.cattletrade.business.service.IWarningLogService;
import com.aiotagro.cattletrade.business.vo.DeliveryLogVo;
import com.aiotagro.cattletrade.constant.WarningStatusAdminEnum;
import com.aiotagro.cattletrade.constant.WarningStatusEnum;
import com.aiotagro.common.core.utils.EnumUtil;
import com.aiotagro.common.core.utils.LngLonUtil;
import com.aiotagro.common.core.utils.SecurityUtil;
import com.aiotagro.common.core.utils.StringUtils;
import com.aiotagro.common.core.utils.uuid.DistinctUtil;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
/**
* <p>
* 预警记录表 服务实现类
* </p>
*
* @author admin
* @since 2024-12-26
*/
@Service
@Slf4j
public class WarningLogServiceImpl extends ServiceImpl<WarningLogMapper, WarningLog> implements IWarningLogService {
@Autowired
private WarningLogMapper warningLogMapper;
@Autowired
private DeliveryMapper deliveryMapper;
@Autowired
private DeliveryDeviceMapper deliveryDeviceMapper;
@Autowired
private JbqServerLogMapper serverLogMapper;
/**
* 预警统计
*
* @return
*/
@Override
public AjaxResult warningCount() {
//获取当前登录人信息
Integer currentUserId = SecurityUtil.getCurrentUserId();
//返回结果集
Map<String, Object> resMap = new HashMap<>();
resMap.put("checkCount", 0);
resMap.put("rangeCount", 0);
DeliveryQueryDto deliveryQueryDto = new DeliveryQueryDto();
deliveryQueryDto.setUserId(currentUserId);
//查询最新的一条上报数据的预警记录结果
List<WarningLog> newWarningLog = warningLogMapper.getNewWarningLog(deliveryQueryDto);
if (CollectionUtils.isNotEmpty(newWarningLog)) {
//数量盘点预警
long checkCount = newWarningLog.stream().filter(warningLog -> "2".equals(warningLog.getWarningType())).count();
long rangeCount = newWarningLog.stream().filter(warningLog -> "3".equals(warningLog.getWarningType())).count();
resMap.put("checkCount", checkCount);
resMap.put("rangeCount", rangeCount);
}
return AjaxResult.success("查询成功", resMap);
}
@Override
public PageResultResponse<DeliveryLogVo> queryList(DeliveryQueryDto dto) {
//返回结果集对象
List<DeliveryLogVo> resList = new ArrayList<>();
Page<Delivery> result = PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
dto.setUserId(SecurityUtil.getCurrentUserId());//当前登录人
List<WarningLog> newWarningLog = warningLogMapper.getNewWarningLog(dto);
if (CollectionUtils.isNotEmpty(newWarningLog)) {
List<Integer> deliveryIds = newWarningLog.stream().map(WarningLog::getDeliveryId).collect(Collectors.toList());
//根据运单id查询运单的信息
List<Delivery> deliveryList = deliveryMapper.selectBatchIds(deliveryIds);
if (CollectionUtils.isNotEmpty(deliveryList)) {
Map<Integer, Delivery> deliveryMap = deliveryList.stream().collect(Collectors.toMap(Delivery::getId, delivery -> delivery));
newWarningLog.forEach(warningLog -> {
Delivery delivery = deliveryMap.get(warningLog.getDeliveryId());
if (delivery != null) {
DeliveryLogVo deliveryLogVo = new DeliveryLogVo();
deliveryLogVo.setId(warningLog.getId());
deliveryLogVo.setLicensePlate(delivery.getLicensePlate());
deliveryLogVo.setDeliveryId(warningLog.getDeliveryId());
deliveryLogVo.setDeliveryNumber(delivery.getDeliveryNumber());
deliveryLogVo.setStatus(delivery.getStatus());
deliveryLogVo.setStatusDesc(2 == delivery.getStatus() ? "已核验" : "待核验");
deliveryLogVo.setCarFrontPhoto(delivery.getCarFrontPhoto());
deliveryLogVo.setRegisteredJbqCount(delivery.getRegisteredJbqCount());
deliveryLogVo.setInventoryJbqCount(warningLog.getInventoryJbqCount());
deliveryLogVo.setActualDistance(warningLog.getActualDistance());
deliveryLogVo.setExpectedDistance(warningLog.getExpectedDistance());
String warningType = warningLog.getWarningType();
deliveryLogVo.setWarningType(warningType);
if (StringUtils.isNotEmpty(warningType)) {
deliveryLogVo.setWarningTypeDesc(EnumUtil.getEnumConstant(WarningStatusAdminEnum.class , Integer.parseInt(warningType)).getDescription());
}
deliveryLogVo.setWarningTime(warningLog.getWarningTime());
resList.add(deliveryLogVo);
}
});
}
}
return new PageResultResponse(result.getTotal(), resList);
}
@Override
public AjaxResult warningDetail(Integer id) {
WarningDetailDto warningDetailDto = new WarningDetailDto();
//预警记录信息
WarningLog warningLog = warningLogMapper.selectById(id);
BeanUtils.copyProperties(warningLog, warningDetailDto);
String warningType = warningLog.getWarningType();
if (StringUtils.isNotEmpty(warningType)) {
warningDetailDto.setWarningReason(EnumUtil.getEnumConstant(WarningStatusEnum.class , Integer.parseInt(warningType)).getDescription());
}
//获取当前记录的运单信息
Delivery delivery = deliveryMapper.selectById(warningLog.getDeliveryId());
BeanUtils.copyProperties(delivery, warningDetailDto);
warningDetailDto.setWarningTime(warningLog.getWarningTime());
warningDetailDto.setWarningType(warningType);
warningDetailDto.setInventoryJbqCount(warningLog.getInventoryJbqCount());
//获取当前运单关联的设备信息
List<DeliveryDevice> deliveryDevices = deliveryDeviceMapper.selectList(new LambdaQueryWrapper<DeliveryDevice>().eq(DeliveryDevice::getDeliveryId, delivery.getId()));
if (CollectionUtils.isNotEmpty(deliveryDevices)) {
List<String> serverCollect = deliveryDevices.stream().filter(deliveryDevice -> deliveryDevice.getDeviceType() == 1).map(DeliveryDevice::getDeviceId).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(serverCollect)) {
warningDetailDto.setServerDeviceSn(serverCollect.get(0));
}
List<String> jbqDeviceCollect = deliveryDevices.stream().filter(deliveryDevice -> deliveryDevice.getDeviceType() == 2).map(DeliveryDevice::getDeviceId).collect(Collectors.toList());
warningDetailDto.setJbqDeviceSn(jbqDeviceCollect);
}
return AjaxResult.success(warningDetailDto);
}
@Override
public AjaxResult savaWarn(String deviceId) {
// 查询主机关联的最新运单
List<DeliveryDevice> list = deliveryDeviceMapper.selectList(new LambdaQueryWrapper<DeliveryDevice>().eq(DeliveryDevice::getDeviceId, deviceId)
.orderByDesc(DeliveryDevice::getId));
// 主机未绑定运单 无需操作
if (CollectionUtils.isEmpty(list)) {
return AjaxResult.success();
}
Delivery delivery = deliveryMapper.selectById(list.get(0).getDeliveryId());
// 运单已核验 无需操作
if (delivery.getStatus() == 2) {
return AjaxResult.success();
}
// 查询运单创建后的主机上报日志
List<JbqServerLog> logs = serverLogMapper.selectList(new LambdaQueryWrapper<JbqServerLog>().eq(JbqServerLog::getDeviceId, deviceId)
.ge(JbqServerLog::getCreateTime, delivery.getCreateTime()).orderByDesc(JbqServerLog::getCreateTime));
LocalDateTime endTime = logs.get(0).getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
LocalDateTime createTime;
Double endLat = Double.parseDouble(logs.get(0).getLatitude());
Double endLon = Double.parseDouble(logs.get(0).getLongitude());
// 转换成高德经纬度
double[] gcjDouble = LngLonUtil.gps84_To_Gcj02(endLat, endLon);
endLat = gcjDouble[0];
endLon = gcjDouble[1];
Double startLat;
Double startLon;
if (logs.size() == 1) {
// 第一次上报 计算上报时间到运单创建时间的时间段
createTime = delivery.getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
// 腾讯地图经纬度无需转换
startLat = Double.parseDouble(delivery.getStartLat());
startLon = Double.parseDouble(delivery.getStartLon());
} else {
// 多次上报 计算上报时间到上一次上报时间的时间段
createTime = logs.get(1).getCreateTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
startLat = Double.parseDouble(logs.get(1).getLatitude());
startLon = Double.parseDouble(logs.get(1).getLongitude());
// 转换成高德经纬度
double[] gcjDouble1 = LngLonUtil.gps84_To_Gcj02(startLat, startLon);
startLat = gcjDouble1[0];
startLon = gcjDouble1[1];
}
// 计算时间差,单位为小时
double hoursBetween = Duration.between(createTime, endTime).toMinutes() / 60.0;
// 确定当前上报时间是在白天还是晚上
boolean isDayTime = !endTime.toLocalTime().isBefore(LocalTime.of(8, 0)) &&
!endTime.toLocalTime().isAfter(LocalTime.of(20, 0));
// 计算基准距离
double baseDistance = isDayTime ? (80 * hoursBetween * 0.9) : (80 * hoursBetween * 0.8);
// 四舍五入 保留3位小数
baseDistance = BigDecimal.valueOf(baseDistance).setScale(3, RoundingMode.HALF_UP).doubleValue();
// 计算本次上报点 和上次上报点之间的经纬度导航实际距离 km
try {
double distance = DistinctUtil.calculateDistance(startLat, startLon, endLat, endLon);
// 小于基准距离 发起预警
WarningLog log = new WarningLog();
log.setWarningTime(new Date());
if (distance < baseDistance) {
log.setWarningType("3");
} else {
log.setWarningType("1");
}
log.setDeliveryId(delivery.getId());
log.setActualDistance(String.valueOf(distance));
log.setExpectedDistance(String.valueOf(baseDistance));
save(log);
} catch (Exception e) {
log.error("请求高德api计算距离失败", e);
return AjaxResult.error("请求高德api计算距离失败");
}
return AjaxResult.success();
}
}

View File

@@ -0,0 +1,294 @@
package com.aiotagro.cattletrade.business.service.impl;
import com.aiotagro.cattletrade.business.entity.DeliveryDevice;
import com.aiotagro.cattletrade.business.entity.XqClient;
import com.aiotagro.cattletrade.business.mapper.DeliveryDeviceMapper;
import com.aiotagro.cattletrade.business.mapper.XqClientMapper;
import com.aiotagro.cattletrade.business.service.IXqClientService;
import com.aiotagro.common.core.web.domain.AjaxResult;
import com.aiotagro.common.core.web.domain.PageResultResponse;
import com.aiotagro.common.core.utils.LngLonUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.stereotype.Service;
import com.aiotagro.common.core.utils.StringUtils;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 项圈客户端服务实现
*
* @author System
* @date 2025-01-16
*/
@Service
public class XqClientServiceImpl extends ServiceImpl<XqClientMapper, XqClient> implements IXqClientService {
@Resource
private XqClientMapper xqClientMapper;
@Resource
private DeliveryDeviceMapper deliveryDeviceMapper;
@Override
public PageResultResponse xqList(Map<String, Object> params) {
Integer pageNum = params.get("pageNum") != null ? (Integer) params.get("pageNum") : 1;
Integer pageSize = params.get("pageSize") != null ? (Integer) params.get("pageSize") : 10;
String sn = (String) params.get("sn");
String startNo = (String) params.get("startNo");
String endNo = (String) params.get("endNo");
Boolean unassignedOnly = (Boolean) params.get("unassignedOnly");
Page<Map<String, Object>> result = PageHelper.startPage(pageNum, pageSize);
try {
List<Map<String, Object>> list;
if (unassignedOnly != null && unassignedOnly) {
// 查询未分配的智能项圈
System.out.println("查询未分配的智能项圈,参数: " + params);
list = xqClientMapper.selectUnassignedXqClientList(sn, startNo, endNo);
System.out.println("未分配智能项圈查询结果数量: " + (list != null ? list.size() : 0));
} else {
// 使用关联查询获取完整信息
System.out.println("查询所有智能项圈,参数: " + params);
list = xqClientMapper.selectXqClientListWithRelations(sn, startNo, endNo);
System.out.println("所有智能项圈查询结果数量: " + (list != null ? list.size() : 0));
}
return new PageResultResponse(result.getTotal(), list);
} catch (Exception e) {
System.out.println("查询智能项圈失败: " + e.getMessage());
e.printStackTrace();
return new PageResultResponse(0L, new ArrayList<>());
}
}
@Override
public AjaxResult getDevicesByDeliveryId(Integer deliveryId, Integer deviceType) {
System.out.println("=== 查询项圈设备deliveryId: " + deliveryId + ", deviceType: " + deviceType);
if (deliveryId == null) {
return AjaxResult.error("运送清单ID不能为空");
}
// 查询运送清单关联的设备
LambdaQueryWrapper<DeliveryDevice> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DeliveryDevice::getDeliveryId, deliveryId);
wrapper.eq(DeliveryDevice::getDeviceType, deviceType);
List<DeliveryDevice> deliveryDevices = deliveryDeviceMapper.selectList(wrapper);
System.out.println("=== 查询到delivery_device记录数: " + deliveryDevices.size());
if (!deliveryDevices.isEmpty()) {
System.out.println("=== delivery_device记录详情: " + deliveryDevices);
}
if (deliveryDevices.isEmpty()) {
return AjaxResult.success(new ArrayList<>());
}
// 获取设备ID列表
List<String> deviceIds = deliveryDevices.stream()
.map(DeliveryDevice::getDeviceId)
.collect(Collectors.toList());
// 查询设备详细信息
LambdaQueryWrapper<XqClient> deviceWrapper = new LambdaQueryWrapper<>();
if (deviceType != null && deviceType == 3) {
// 项圈:历史上有的存 deviceId有的存 sn需要兼容两种字段
deviceWrapper.and(w -> w.in(XqClient::getDeviceId, deviceIds)
.or()
.in(XqClient::getSn, deviceIds));
} else {
// 耳标部分库没有扩展字段delivery_number、license_plate避免 select * 触发未知列错误
deviceWrapper.in(XqClient::getDeviceId, deviceIds)
.select(XqClient::getId,
XqClient::getDeviceId,
XqClient::getSn,
XqClient::getState,
XqClient::getLongitude,
XqClient::getLatitude,
XqClient::getAltitude,
XqClient::getGpsState,
XqClient::getNsat,
XqClient::getRsrp,
XqClient::getBattery,
XqClient::getTemperature,
XqClient::getSteps,
XqClient::getAccX,
XqClient::getAccY,
XqClient::getAccZ,
XqClient::getBandgeStatus,
XqClient::getVer,
XqClient::getTime,
XqClient::getUptime,
XqClient::getYSteps,
XqClient::getIsWear,
XqClient::getIsTemperature,
XqClient::getSourceId,
XqClient::getLoctime,
XqClient::getSubType,
XqClient::getFrequency,
XqClient::getVehicleId,
XqClient::getEveningFrequency,
XqClient::getTenantId,
XqClient::getDeliveryId,
XqClient::getDeliveryNumber,
XqClient::getLicensePlate);
}
List<XqClient> devices = xqClientMapper.selectList(deviceWrapper);
System.out.println("=== 查询到的项圈设备数量: " + devices.size());
for (XqClient device : devices) {
System.out.println("=== 项圈设备: " + device);
}
// 返回分页格式数据
Map<String, Object> result = new HashMap<>();
result.put("rows", devices);
result.put("total", devices.size());
return AjaxResult.success(result);
}
@Override
public AjaxResult getCollarLocation(String deliveryId, String xqDeviceId) {
if (StringUtils.isEmpty(xqDeviceId)) {
return AjaxResult.error("项圈设备ID不能为空");
}
// 查询项圈设备信息 - 使用selectList避免TooManyResultsException
LambdaQueryWrapper<XqClient> wrapper = new LambdaQueryWrapper<>();
// 兼容老数据:有的记录存 deviceId有的使用 sn 作为设备唯一编号
wrapper.and(w -> w.eq(XqClient::getDeviceId, xqDeviceId)
.or()
.eq(XqClient::getSn, xqDeviceId));
wrapper.orderByDesc(XqClient::getUptime); // 按更新时间倒序,取最新的记录
List<XqClient> collars = xqClientMapper.selectList(wrapper);
if (collars.isEmpty()) {
return AjaxResult.error("未找到对应的项圈设备信息");
}
// 取第一条记录(最新的)
XqClient collar = collars.get(0);
// 获取设备的经纬度
String latitude = collar.getLatitude();
String longitude = collar.getLongitude();
// 判断经纬度是否为空或为0
if (isInvalidLocation(latitude, longitude)) {
return AjaxResult.error("暂无定位信息");
}
// 转换为百度经纬度
double lat = Double.parseDouble(latitude);
double lon = Double.parseDouble(longitude);
double[] baiduLocation = LngLonUtil.gps84_To_bd09(lat, lon);
// 构建返回数据
Map<String, Object> locationData = new java.util.HashMap<>();
locationData.put("deviceId", xqDeviceId);
locationData.put("latitude", String.valueOf(baiduLocation[0]));
locationData.put("longitude", String.valueOf(baiduLocation[1]));
locationData.put("altitude", collar.getAltitude());
locationData.put("battery", collar.getBattery());
locationData.put("temperature", collar.getTemperature());
locationData.put("updateTime", collar.getUptime());
locationData.put("gpsState", collar.getGpsState());
locationData.put("nsat", collar.getNsat());
return AjaxResult.success(locationData);
}
@Override
public AjaxResult getCollarTrack(String deliveryId, String xqDeviceId, String trackTime, String trackEndTime) {
if (StringUtils.isEmpty(xqDeviceId)) {
return AjaxResult.error("项圈设备ID不能为空");
}
try {
// 构建查询条件
LambdaQueryWrapper<XqClient> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(XqClient::getDeviceId, xqDeviceId);
wrapper.orderByAsc(XqClient::getUptime); // 按时间正序排列
// 添加时间范围条件
if (StringUtils.isNotEmpty(trackTime) && StringUtils.isNotEmpty(trackEndTime)) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date startTime = sdf.parse(trackTime);
Date endTime = sdf.parse(trackEndTime);
wrapper.between(XqClient::getUptime, startTime, endTime);
}
// 查询轨迹数据
List<XqClient> trackData = xqClientMapper.selectList(wrapper);
if (trackData.isEmpty()) {
return AjaxResult.error("暂无轨迹数据");
}
// 构建返回数据
List<Map<String, Object>> trackList = new ArrayList<>();
for (XqClient collar : trackData) {
if (!isInvalidLocation(collar.getLatitude(), collar.getLongitude())) {
// 转换为百度经纬度
double lat = Double.parseDouble(collar.getLatitude());
double lon = Double.parseDouble(collar.getLongitude());
double[] baiduLocation = LngLonUtil.gps84_To_bd09(lat, lon);
Map<String, Object> trackPoint = new java.util.HashMap<>();
trackPoint.put("longitude", String.valueOf(baiduLocation[1]));
trackPoint.put("latitude", String.valueOf(baiduLocation[0]));
trackPoint.put("altitude", collar.getAltitude());
trackPoint.put("updateTime", collar.getUptime());
trackPoint.put("battery", collar.getBattery());
trackPoint.put("temperature", collar.getTemperature());
trackList.add(trackPoint);
}
}
if (trackList.isEmpty()) {
return AjaxResult.error("暂无有效轨迹数据");
}
return AjaxResult.success(trackList);
} catch (Exception e) {
e.printStackTrace();
return AjaxResult.error("查询轨迹失败: " + e.getMessage());
}
}
@Override
public AjaxResult getCollarDeviceTrack(String deliveryId, String xqDeviceId, String trackTime, String trackEndTime) {
// 设备轨迹查询逻辑与项圈轨迹相同
return getCollarTrack(deliveryId, xqDeviceId, trackTime, trackEndTime);
}
/**
* 判断位置信息是否无效
*/
private boolean isInvalidLocation(String latitude, String longitude) {
if (StringUtils.isEmpty(latitude) || StringUtils.isEmpty(longitude)) {
return true;
}
try {
double lat = Double.parseDouble(latitude);
double lon = Double.parseDouble(longitude);
return lat == 0.0 && lon == 0.0;
} catch (NumberFormatException e) {
return true;
}
}
}

View File

@@ -0,0 +1,59 @@
package com.aiotagro.cattletrade.business.utils;
import com.aiotagro.common.core.utils.SecurityUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
/**
* 数据权限工具类
*
* @author System
* @date 2025-10-11
*/
public class DataScopeUtil {
/**
* 应用数据权限过滤(基于创建人)
* 超级管理员不过滤,普通用户只能看自己创建的数据
*
* @param wrapper 查询条件包装器
* @param createdByField 创建人字段
* @param <T> 实体类型
*/
public static <T> void applyDataScope(LambdaQueryWrapper<T> wrapper,
SFunction<T, Integer> createdByField) {
// 超级管理员不过滤
if (SecurityUtil.isSuperAdmin()) {
return;
}
// 普通用户只能查看自己创建的数据
Integer currentUserId = SecurityUtil.getCurrentUserId();
wrapper.eq(createdByField, currentUserId);
}
/**
* 应用数据权限过滤(基于创建人或核验人)
* 用户可以看到自己创建或自己核验的数据
*
* @param wrapper 查询条件包装器
* @param createdByField 创建人字段
* @param checkByField 核验人字段
* @param <T> 实体类型
*/
public static <T> void applyDataScopeWithChecker(LambdaQueryWrapper<T> wrapper,
SFunction<T, Integer> createdByField,
SFunction<T, Integer> checkByField) {
// 超级管理员不过滤
if (SecurityUtil.isSuperAdmin()) {
return;
}
// 普通用户可以查看自己创建或自己核验的数据
Integer currentUserId = SecurityUtil.getCurrentUserId();
wrapper.and(w -> w.eq(createdByField, currentUserId)
.or()
.eq(checkByField, currentUserId));
}
}

View File

@@ -0,0 +1,86 @@
package com.aiotagro.cattletrade.business.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
@Data
public class DeliveryLogVo {
/**
* 预警记录主键ID
*/
private Integer id;
/**
* 运单Id
*/
private Integer deliveryId;
/**
* 车头照片
*/
private String carFrontPhoto;
/**
* 运单号
*/
private String deliveryNumber;
/**
* 车牌号
*/
private String licensePlate;
/**
* 登记智能耳标数
*/
private Integer registeredJbqCount;
/**
* 车内盘点耳标数量
*/
private Integer inventoryJbqCount;
/**
* 预警类型, 1-正常 2-盘点预警 3-距离预警
*/
private String warningType;
/**
* 预警类型描述, 1-正常 2-盘点预警 3-距离预警
*/
private String warningTypeDesc;
/**
* 预警时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date warningTime;
/**
* 状态1-待核验2-已核验
*/
private Integer status;
/**
* 状态1-待核验2-已核验
*/
private String statusDesc;
/**
* 预计形式距离
*/
private String expectedDistance;
/**
* 实际行驶距离
*/
private String actualDistance;
/**
* 创建人名称
*/
private String createByDesc;
}

View File

@@ -0,0 +1,47 @@
package com.aiotagro.cattletrade.business.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
@Data
public class JbqClientVo {
/**
* 唯一标识
*/
private Integer id;
/**
* 耳标编号
*/
private String deviceId;
/**
* 设备电量
*/
private String deviceVoltage;
/**
* 设备温度
*/
private String deviceTemp;
/**
* 运单号
*/
private String deliveryNumber;
/**
* 车牌号
*/
private String licensePlate;
/**
* 绑定时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date deliveryCreateTime;
}

View File

@@ -0,0 +1,50 @@
package com.aiotagro.cattletrade.business.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
@Data
public class ServerClientVo {
/**
* 唯一标识
*/
private Integer id;
/**
* 耳标编号
*/
private String deviceId;
/**
* 设备电量
*/
private String deviceVoltage;
/**
* 设备温度
*/
private String deviceTemp;
/**
* 运单号
*/
private String deliveryNumber;
/**
* 车牌号
*/
private String licensePlate;
/**
* 绑定时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date deliveryCreateTime;
/**
* 联网状态描述
*/
private String onlineStatusDesc;
}

View File

@@ -0,0 +1,29 @@
package com.aiotagro.cattletrade.business.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
@Data
public class ServerLocationVo {
/**
* 纬度
*/
private String latitude;
/**
* 经度
*/
private String longitude;
/**
* 主机编号
*/
private String deviceId;
/**
* 更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
}

View File

@@ -0,0 +1,115 @@
package com.aiotagro.cattletrade.config;
import cn.dev33.satoken.stp.StpLogic;
import com.aiotagro.common.core.constant.RoleConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 自定义 StpLogic支持通配符权限匹配
*/
@Slf4j
@Component
public class CustomStpLogic extends StpLogic {
public CustomStpLogic() {
super("login");
}
/**
* 重写权限校验方法,支持通配符匹配
*
* @param permission 需要校验的权限码
* @return 是否拥有该权限
*/
@Override
public boolean hasPermission(String permission) {
try {
// 获取当前用户的权限列表
List<String> permissionList = getPermissionList();
// 如果权限列表为空返回false
if (permissionList == null || permissionList.isEmpty()) {
log.debug("权限列表为空permission={}", permission);
return false;
}
// 检查是否有通配符权限 *:*:*
if (permissionList.contains(RoleConstants.ALL_PERMISSION)) {
log.debug("拥有通配符权限 *:*:*直接放行permission={}", permission);
return true;
}
// 检查是否有精确匹配的权限
if (permissionList.contains(permission)) {
log.debug("精确匹配权限permission={}", permission);
return true;
}
// 支持通配符匹配例如system:* 可以匹配 system:user:list
for (String userPermission : permissionList) {
if (matchPermission(userPermission, permission)) {
log.debug("通配符匹配成功userPermission={}, requirePermission={}", userPermission, permission);
return true;
}
}
log.debug("权限校验失败permission={}, userPermissions={}", permission, permissionList);
return false;
} catch (Exception e) {
log.error("权限校验异常: {}", e.getMessage(), e);
return false;
}
}
/**
* 通配符权限匹配
*
* @param pattern 权限模式(可能包含*
* @param permission 需要匹配的权限
* @return 是否匹配
*/
private boolean matchPermission(String pattern, String permission) {
// 如果完全相等
if (pattern.equals(permission)) {
return true;
}
// 如果是通配符 *:*:*
if ("*:*:*".equals(pattern) || "*".equals(pattern)) {
return true;
}
// 分割权限字符串
String[] patternParts = pattern.split(":");
String[] permissionParts = permission.split(":");
// 如果模式部分数量大于权限部分,肯定不匹配
if (patternParts.length > permissionParts.length) {
return false;
}
// 逐级匹配
for (int i = 0; i < patternParts.length; i++) {
String patternPart = patternParts[i];
String permissionPart = permissionParts[i];
// 如果是*,匹配任意
if ("*".equals(patternPart)) {
return true; // 后续所有部分都匹配
}
// 如果不相等,不匹配
if (!patternPart.equals(permissionPart)) {
return false;
}
}
// 如果模式部分全部匹配,且模式长度等于权限长度,则匹配
return patternParts.length == permissionParts.length;
}
}

View File

@@ -0,0 +1,35 @@
package com.aiotagro.cattletrade.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
/**
* @author Carson
* @package_name com.aiotagro.payinfo.config
* @date 2024/2/6 17:00
*/
@Configuration
public class DruidDataSourceConfig {
//编写方法,注入DruidDataSource
//为什么我们注入自己的DataSource , 默认的HiKariDatasource失效?
//1. 默认的数据源是如配置? @ConditionalOnMissingBean({ DataSource.class, XADataSource.class })
// 解读通过@ConditionalOnMissingBean({ DataSource.class}) 判断如果容器有DataSource Bean 就不注入默认的HiKariDatasource
@ConfigurationProperties("spring.datasource")
@Bean
public DataSource dataSource() {
//1. 配置了 @ConfigurationProperties("spring.datasource")
// 就可以读取到application.yml的配置注意我们需要将bean注入到spring ioc容器中、bean中提供get\set方法
//2. 我们就不需要调用DruidDataSource 对象的setXxx, 会自动关联
DruidDataSource druidDataSource = new DruidDataSource();
//druidDataSource.setUrl();
//druidDataSource.setUsername();
//druidDataSource.setPassword();
return druidDataSource;
}
}

Some files were not shown because too many files have changed in this diff Show More