修改内容
This commit is contained in:
141
tradeCattle/IOT_DEVICE_CLEANUP_FIX_REPORT.md
Normal file
141
tradeCattle/IOT_DEVICE_CLEANUP_FIX_REPORT.md
Normal file
@@ -0,0 +1,141 @@
|
||||
# IoT设备清理功能实现报告
|
||||
|
||||
## 问题描述
|
||||
|
||||
外部物联网系统可以将设备重新分配到其他项目,但该项目中的设备数据仍然保留在数据库中,导致以下问题:
|
||||
- 数据库中存在不属于本项目的设备记录
|
||||
- 这些设备可能会在设备列表中显示,造成混淆
|
||||
- 设备数量统计不准确
|
||||
|
||||
## 解决方案
|
||||
|
||||
在设备数据同步过程中添加清理逻辑,自动删除已被重新分配到其他项目的设备。
|
||||
|
||||
### 实现内容
|
||||
|
||||
#### 1. 修改同步逻辑 (`IotDeviceSyncService.java`)
|
||||
|
||||
##### 添加必要的导入
|
||||
```java
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
```
|
||||
|
||||
##### 在 `syncIotDeviceData()` 方法中添加设备ID集合提取
|
||||
```59:65:tradeCattle/aiotagro-cattle-trade/src/main/java/com/aiotagro/cattletrade/business/service/IotDeviceSyncService.java
|
||||
// 提取API返回的设备ID集合
|
||||
Set<String> apiDeviceIds = new HashSet<>();
|
||||
for (Map<String, Object> deviceData figuring deviceDataList) {
|
||||
if (deviceData.get("deviceId") != null) {
|
||||
apiDeviceIds.add(String.valueOf(deviceData.get("deviceId")));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
##### 添加清理调用
|
||||
```111:116:tradeCattle/aiotagro-cattle-trade/src/main/java/com/aiotagro/cattletrade/business/service/IotDeviceSyncService.java
|
||||
// 清理已被重新分配到其他项目的设备
|
||||
try {
|
||||
cleanupReassignedDevices(apiDeviceIds);
|
||||
} catch (Exception e) {
|
||||
logger.error("清理重新分配设备失败", e);
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. 新增清理方法 `cleanupReassignedDevices()`
|
||||
|
||||
```368:396:tradeCattle/aiotagro-cattle-trade/src/main/java/com/aiotagro/cattletrade/business/service/IotDeviceSyncService.java
|
||||
private void cleanupReassignedDevices(Set<String> apiDeviceIds) {
|
||||
try {
|
||||
logger.info("开始清理已重新分配的设备");
|
||||
|
||||
// 查询数据库中所有设备
|
||||
List<IotDeviceData> allDevices = iotDeviceDataMapper.selectList(null);
|
||||
|
||||
int deletedCount = 0;
|
||||
for (IotDeviceData device : allDevices) {
|
||||
// 如果设备不在API返回列表中
|
||||
if (!apiDeviceIds.contains(device.getDeviceId())) {
|
||||
// 只删除未被分配的设备(tenantId和deliveryId都为null)
|
||||
if (device.getTenantId() == null && device.getDeliveryId() == null) {
|
||||
iotDeviceDataMapper.deleteById(device.getId());
|
||||
logger.info("删除已重新分配的设备: deviceId={}, id={}", device.getDeviceId(), device.getId());
|
||||
deletedCount++;
|
||||
} else {
|
||||
logger.warn("设备不在API返回列表中但已被分配,保留: deviceId={}, tenantId={}, deliveryId={}",
|
||||
device.getDeviceId(), device.getTenantId(), device.getDeliveryId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("清理完成,共删除 {} 个已重新分配的设备", deletedCount);
|
||||
} catch (Exception e) {
|
||||
logger.error("清理已重新分配设备时发生错误", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 清理逻辑说明
|
||||
|
||||
1. **设备对比**:将数据库中所有设备与API返回的设备列表对比
|
||||
2. **安全删除**:只删除满足以下条件的设备:
|
||||
- 设备不在API返回列表中(已被重新分配)
|
||||
- `tenantId` 为 null(未分配给租户)
|
||||
- `deliveryId` 为 null(未分配给装车订单)
|
||||
3. **保护机制**:如果设备已被分配(有 `tenantId` 或 `deliveryId`),则保留该设备,防止误删重要数据
|
||||
4. **日志记录**:记录清理过程和结果,便于问题追踪
|
||||
|
||||
### 工作流程
|
||||
|
||||
1. 从外部API获取设备数据列表
|
||||
2. 提取API返回的设备ID集合
|
||||
3. 同步/更新API中的设备数据
|
||||
4. **新增**:清理数据库中不在API列表且未被分配的设备
|
||||
5. 记录同步日志
|
||||
|
||||
### 优势
|
||||
|
||||
- ✅ 自动清理:在同步过程中自动清理,无需手动操作
|
||||
- ✅ 安全可靠:只删除未分配的设备,已分配的设备不会被误删
|
||||
- ✅ 实时更新:每次同步都会检查并清理
|
||||
- ✅ 日志完整:详细的日志记录,便于问题追踪
|
||||
- ✅ 错误处理:异常捕获,不影响主同步流程
|
||||
|
||||
### 注意事项
|
||||
|
||||
1. **已分配设备保护**:如果设备已被分配给租户或装车订单,即使不在API列表中也不会被删除
|
||||
2. **数据保留**:历史数据(如设备日志)不会受影响,只删除 `iot_device_data` 表中的记录
|
||||
3. **性能考虑**:每次同步都会查询所有设备,如果设备数量很大,可能需要优化查询策略
|
||||
|
||||
### 测试建议
|
||||
|
||||
1. **模拟场景**:在外部物联网系统将某个设备重新分配到其他项目
|
||||
2. **执行同步**:手动触发设备同步(调用 `/api/iotSync/sync` 接口)
|
||||
3. **验证结果**:
|
||||
- 检查数据库中该设备是否被删除
|
||||
- 查看同步日志,确认清理操作记录
|
||||
- 如果设备已被分配,应保留在数据库中
|
||||
|
||||
### 部署步骤
|
||||
|
||||
1. 备份当前代码和数据库
|
||||
2. 更新 `IotDeviceSyncService.java` 文件
|
||||
3. 重新编译并部署后端服务
|
||||
4. 测试同步功能
|
||||
5. 检查日志确保清理功能正常工作
|
||||
|
||||
## 修改文件
|
||||
|
||||
- `tradeCattle/aiotagro-cattle-trade/src/main/java/com/aiotagro/cattletrade/business/service/IotDeviceSyncService.java`
|
||||
|
||||
## 相关接口
|
||||
|
||||
- 设备同步接口:`POST /api/iotSync/sync`
|
||||
- 设备查询接口:`POST /api/iotDevice/queryList`
|
||||
|
||||
## 创建时间
|
||||
|
||||
2025-01-16
|
||||
|
||||
7
tradeCattle/add_order_id_to_delivery.sql
Normal file
7
tradeCattle/add_order_id_to_delivery.sql
Normal file
@@ -0,0 +1,7 @@
|
||||
-- 为 delivery 表添加 order_id 字段,用于关联 order 订单表
|
||||
-- 一个订单可以对应多个装车运单
|
||||
|
||||
ALTER TABLE `delivery`
|
||||
ADD COLUMN `order_id` int(11) DEFAULT NULL COMMENT '订单ID(关联order表)' AFTER `id`,
|
||||
ADD INDEX `idx_order_id` (`order_id`);
|
||||
|
||||
@@ -55,6 +55,9 @@ public class DeliveryController {
|
||||
|
||||
@Autowired
|
||||
private IXqClientService xqClientService;
|
||||
|
||||
@Autowired
|
||||
private com.aiotagro.cattletrade.business.mapper.IotDeviceDataMapper iotDeviceDataMapper;
|
||||
|
||||
|
||||
|
||||
@@ -581,4 +584,58 @@ public class DeliveryController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除装车订单
|
||||
* 删除订单时同时清空关联设备的delivery_id和weight
|
||||
*/
|
||||
@SaCheckPermission("delivery:delete")
|
||||
@GetMapping("/deleteDelivery")
|
||||
public AjaxResult deleteDelivery(@RequestParam Integer id) {
|
||||
try {
|
||||
if (id == null) {
|
||||
return AjaxResult.error("订单ID不能为空");
|
||||
}
|
||||
|
||||
// 查询订单是否存在
|
||||
Delivery delivery = deliveryService.getById(id);
|
||||
if (delivery == null) {
|
||||
return AjaxResult.error("订单不存在");
|
||||
}
|
||||
|
||||
// 权限检查:只有创建者或超级管理员可以删除
|
||||
Integer userId = SecurityUtil.getCurrentUserId();
|
||||
if (!SecurityUtil.isSuperAdmin() && !userId.equals(delivery.getCreatedBy())) {
|
||||
return AjaxResult.error("无权限删除此订单");
|
||||
}
|
||||
|
||||
// 1. 先清空关联设备的delivery_id和weight
|
||||
com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<com.aiotagro.cattletrade.business.entity.IotDeviceData> queryWrapper =
|
||||
new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<>();
|
||||
queryWrapper.eq("delivery_id", id);
|
||||
List<com.aiotagro.cattletrade.business.entity.IotDeviceData> devices = iotDeviceDataMapper.selectList(queryWrapper);
|
||||
|
||||
int updatedCount = 0;
|
||||
for (com.aiotagro.cattletrade.business.entity.IotDeviceData device : devices) {
|
||||
device.setDeliveryId(null);
|
||||
device.setWeight(null);
|
||||
iotDeviceDataMapper.updateById(device);
|
||||
updatedCount++;
|
||||
}
|
||||
|
||||
System.out.println("清空设备数量: " + updatedCount);
|
||||
|
||||
// 2. 删除订单记录
|
||||
boolean deleted = deliveryService.removeById(id);
|
||||
|
||||
if (deleted) {
|
||||
return AjaxResult.success("订单删除成功,已清空 " + updatedCount + " 个设备的绑定信息");
|
||||
} else {
|
||||
return AjaxResult.error("订单删除失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return AjaxResult.error("删除订单失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import com.aiotagro.cattletrade.business.service.IDeliveryDeviceService;
|
||||
import com.aiotagro.cattletrade.business.service.IotDeviceLogSyncService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.aiotagro.common.core.web.domain.AjaxResult;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -368,13 +369,22 @@ public class DeliveryDeviceController {
|
||||
return AjaxResult.error("设备不存在");
|
||||
}
|
||||
|
||||
// 更新delivery_id和weight
|
||||
device.setDeliveryId(deliveryId);
|
||||
// 使用LambdaUpdateWrapper来更新,支持null值
|
||||
LambdaUpdateWrapper<IotDeviceData> updateWrapper = new LambdaUpdateWrapper<>();
|
||||
updateWrapper.eq(IotDeviceData::getDeviceId, deviceId);
|
||||
|
||||
// 设置delivery_id(可以是null)
|
||||
updateWrapper.set(IotDeviceData::getDeliveryId, deliveryId);
|
||||
|
||||
// 设置weight(如果有值)
|
||||
if (weight != null) {
|
||||
device.setWeight(weight);
|
||||
updateWrapper.set(IotDeviceData::getWeight, weight);
|
||||
}
|
||||
|
||||
int result = iotDeviceDataMapper.updateById(device);
|
||||
// 设置更新时间
|
||||
updateWrapper.set(IotDeviceData::getUpdateTime, new Date());
|
||||
|
||||
int result = iotDeviceDataMapper.update(null, updateWrapper);
|
||||
|
||||
if (result > 0) {
|
||||
System.out.println("设备更新成功: " + deviceId);
|
||||
@@ -785,7 +795,21 @@ public class DeliveryDeviceController {
|
||||
@PostMapping(value = "/getCollarTrajectory")
|
||||
public AjaxResult getCollarTrajectory(@RequestBody Map<String, Object> params) {
|
||||
String deviceId = (String) params.get("deviceId");
|
||||
Integer deliveryId = (Integer) params.get("deliveryId");
|
||||
|
||||
// 安全地转换deliveryId为Integer,支持String和Integer两种类型
|
||||
Integer deliveryId = null;
|
||||
Object deliveryIdObj = params.get("deliveryId");
|
||||
if (deliveryIdObj != null) {
|
||||
if (deliveryIdObj instanceof Integer) {
|
||||
deliveryId = (Integer) deliveryIdObj;
|
||||
} else if (deliveryIdObj instanceof String) {
|
||||
try {
|
||||
deliveryId = Integer.parseInt((String) deliveryIdObj);
|
||||
} catch (NumberFormatException e) {
|
||||
return AjaxResult.error("运送清单ID格式错误");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (deviceId == null || deviceId.trim().isEmpty()) {
|
||||
return AjaxResult.error("设备ID不能为空");
|
||||
@@ -818,6 +842,22 @@ public class DeliveryDeviceController {
|
||||
logQuery.isNotNull("longitude");
|
||||
logQuery.ne("latitude", "0");
|
||||
logQuery.ne("longitude", "0");
|
||||
|
||||
// 添加日期范围过滤(如果前端传了日期参数)
|
||||
if (params.get("startTime") != null && params.get("endTime") != null) {
|
||||
String startTime = params.get("startTime").toString();
|
||||
String endTime = params.get("endTime").toString();
|
||||
try {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
Date startDate = sdf.parse(startTime);
|
||||
Date endDate = sdf.parse(endTime);
|
||||
logQuery.between("update_time", startDate, endDate);
|
||||
System.out.println("日期范围: " + startTime + " 到 " + endTime);
|
||||
} catch (Exception e) {
|
||||
System.out.println("日期解析失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
logQuery.orderByAsc("update_time");
|
||||
List<XqClientLog> logs = xqClientLogMapper.selectList(logQuery);
|
||||
|
||||
|
||||
@@ -399,6 +399,62 @@ public class MemberController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除司机
|
||||
*/
|
||||
@SaCheckPermission("member:delete")
|
||||
@PostMapping("/deleteDriver")
|
||||
@Transactional
|
||||
public AjaxResult deleteDriver(@RequestBody Map<String, Object> params) {
|
||||
try {
|
||||
Integer id = (Integer) params.get("id");
|
||||
if (id == null) {
|
||||
return AjaxResult.error("司机ID不能为空");
|
||||
}
|
||||
|
||||
// 查询司机信息,获取member_id
|
||||
Map<String, Object> driverInfo = memberDriverMapper.selectDriverById(id);
|
||||
if (driverInfo == null) {
|
||||
return AjaxResult.error("司机信息不存在");
|
||||
}
|
||||
|
||||
// member_id 从数据库返回时可能是Long类型,需要转换为Integer
|
||||
Object memberIdObj = driverInfo.get("member_id");
|
||||
Integer memberId = null;
|
||||
if (memberIdObj != null) {
|
||||
if (memberIdObj instanceof Long) {
|
||||
memberId = ((Long) memberIdObj).intValue();
|
||||
} else if (memberIdObj instanceof Integer) {
|
||||
memberId = (Integer) memberIdObj;
|
||||
}
|
||||
}
|
||||
|
||||
// 删除司机详情(member_driver表)
|
||||
int driverResult = memberDriverMapper.deleteDriver(id);
|
||||
|
||||
// 如果member_id存在,也删除member表记录
|
||||
if (memberId != null) {
|
||||
int memberResult = memberMapper.deleteById(memberId);
|
||||
if (memberResult > 0 && driverResult > 0) {
|
||||
return AjaxResult.success("删除成功");
|
||||
} else if (driverResult > 0) {
|
||||
return AjaxResult.success("删除司机信息成功");
|
||||
} else {
|
||||
return AjaxResult.error("删除失败");
|
||||
}
|
||||
} else {
|
||||
if (driverResult > 0) {
|
||||
return AjaxResult.success("删除成功");
|
||||
} else {
|
||||
return AjaxResult.error("删除失败");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return AjaxResult.error("删除司机失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户类型自动创建员工记录
|
||||
*
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
package com.aiotagro.cattletrade.business.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.aiotagro.cattletrade.business.entity.Order;
|
||||
import com.aiotagro.cattletrade.business.service.IOrderService;
|
||||
import com.aiotagro.common.core.web.domain.AjaxResult;
|
||||
import com.aiotagro.common.core.web.domain.PageResultResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 订单管理控制器
|
||||
*
|
||||
* @author System
|
||||
* @date 2025-01-20
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/order")
|
||||
public class OrderController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(OrderController.class);
|
||||
|
||||
@Autowired
|
||||
private IOrderService orderService;
|
||||
|
||||
/**
|
||||
* 查询订单列表(分页+搜索)
|
||||
*/
|
||||
@SaCheckPermission("order:list")
|
||||
@PostMapping("/list")
|
||||
public AjaxResult list(@RequestBody Map<String, Object> params) {
|
||||
try {
|
||||
logger.info("查询订单列表,参数:{}", params);
|
||||
PageResultResponse<Order> result = orderService.pageQuery(params);
|
||||
logger.info("查询成功,共{}条记录", result.getData().getTotal());
|
||||
return AjaxResult.success(result);
|
||||
} catch (Exception e) {
|
||||
logger.error("查询订单列表失败:{}", e.getMessage(), e);
|
||||
return AjaxResult.error("查询订单列表失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增订单
|
||||
*/
|
||||
@SaCheckPermission("order:add")
|
||||
@PostMapping("/add")
|
||||
public AjaxResult add(@RequestBody Order order) {
|
||||
try {
|
||||
logger.info("新增订单,买方:{},卖方:{},结算方式:{}", order.getBuyerId(), order.getSellerId(), order.getSettlementType());
|
||||
|
||||
// 参数验证
|
||||
if (order.getSettlementType() == null) {
|
||||
logger.error("新增失败:结算方式不能为空");
|
||||
return AjaxResult.error("结算方式不能为空");
|
||||
}
|
||||
|
||||
return orderService.addOrder(order);
|
||||
} catch (Exception e) {
|
||||
logger.error("新增订单失败:{}", e.getMessage(), e);
|
||||
return AjaxResult.error("新增订单失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑订单
|
||||
*/
|
||||
@SaCheckPermission("order:edit")
|
||||
@PostMapping("/edit")
|
||||
public AjaxResult edit(@RequestBody Order order) {
|
||||
try {
|
||||
logger.info("编辑订单,订单ID:{}", order.getId());
|
||||
|
||||
// 参数验证
|
||||
if (order.getId() == null) {
|
||||
logger.error("编辑失败:订单ID不能为空");
|
||||
return AjaxResult.error("订单ID不能为空");
|
||||
}
|
||||
|
||||
return orderService.updateOrder(order);
|
||||
} catch (Exception e) {
|
||||
logger.error("编辑订单失败:{}", e.getMessage(), e);
|
||||
return AjaxResult.error("编辑订单失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除订单(逻辑删除)
|
||||
*/
|
||||
@SaCheckPermission("order:delete")
|
||||
@GetMapping("/delete")
|
||||
public AjaxResult delete(@RequestParam Integer id) {
|
||||
try {
|
||||
logger.info("删除订单,订单ID:{}", id);
|
||||
|
||||
if (id == null) {
|
||||
logger.error("删除失败:订单ID不能为空");
|
||||
return AjaxResult.error("订单ID不能为空");
|
||||
}
|
||||
|
||||
return orderService.deleteOrder(id);
|
||||
} catch (Exception e) {
|
||||
logger.error("删除订单失败:{}", e.getMessage(), e);
|
||||
return AjaxResult.error("删除订单失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询订单详情
|
||||
*/
|
||||
@SaCheckPermission("order:view")
|
||||
@GetMapping("/detail")
|
||||
public AjaxResult detail(@RequestParam Integer id) {
|
||||
try {
|
||||
logger.info("查询订单详情,订单ID:{}", id);
|
||||
|
||||
if (id == null) {
|
||||
logger.error("查询失败:订单ID不能为空");
|
||||
return AjaxResult.error("订单ID不能为空");
|
||||
}
|
||||
|
||||
return orderService.getOrderDetail(id);
|
||||
} catch (Exception e) {
|
||||
logger.error("查询订单详情失败:{}", e.getMessage(), e);
|
||||
return AjaxResult.error("查询订单详情失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
package com.aiotagro.cattletrade.business.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.aiotagro.cattletrade.business.entity.Vehicle;
|
||||
import com.aiotagro.cattletrade.business.service.IVehicleService;
|
||||
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.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 车辆管理控制器
|
||||
*
|
||||
* @author System
|
||||
* @date 2025-01-20
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/vehicle")
|
||||
public class VehicleController {
|
||||
|
||||
@Autowired
|
||||
private IVehicleService vehicleService;
|
||||
|
||||
/**
|
||||
* 查询车辆列表(分页+搜索)
|
||||
*/
|
||||
@SaCheckPermission("vehicle:query")
|
||||
@PostMapping("/list")
|
||||
public AjaxResult list(@RequestBody Map<String, Object> params) {
|
||||
try {
|
||||
System.out.println("=== 查询车辆列表 ===");
|
||||
System.out.println("参数: " + params);
|
||||
|
||||
PageResultResponse<Vehicle> result = vehicleService.pageQuery(params);
|
||||
|
||||
System.out.println("查询成功");
|
||||
|
||||
return AjaxResult.success(result);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("查询车辆列表失败: " + e.getMessage());
|
||||
return AjaxResult.error("查询车辆列表失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增车辆
|
||||
*/
|
||||
@SaCheckPermission("vehicle:add")
|
||||
@PostMapping("/add")
|
||||
public AjaxResult add(@RequestBody Vehicle vehicle) {
|
||||
try {
|
||||
System.out.println("=== 新增车辆 ===");
|
||||
System.out.println("车牌号: " + vehicle.getLicensePlate());
|
||||
System.out.println("车头照片: " + vehicle.getCarFrontPhoto());
|
||||
System.out.println("车尾照片: " + vehicle.getCarRearPhoto());
|
||||
System.out.println("行驶证照片: " + vehicle.getDrivingLicensePhoto());
|
||||
System.out.println("牧运通备案码: " + vehicle.getRecordCode());
|
||||
System.out.println("备注: " + vehicle.getRemark());
|
||||
|
||||
// 参数验证
|
||||
if (vehicle.getLicensePlate() == null || vehicle.getLicensePlate().trim().isEmpty()) {
|
||||
System.out.println("新增失败: 车牌号不能为空");
|
||||
return AjaxResult.error("车牌号不能为空");
|
||||
}
|
||||
|
||||
AjaxResult result = vehicleService.addVehicle(vehicle);
|
||||
System.out.println("新增操作执行完成");
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("新增车辆失败: " + e.getMessage());
|
||||
return AjaxResult.error("新增车辆失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑车辆
|
||||
*/
|
||||
@SaCheckPermission("vehicle:edit")
|
||||
@PostMapping("/edit")
|
||||
public AjaxResult edit(@RequestBody Vehicle vehicle) {
|
||||
try {
|
||||
System.out.println("=== 编辑车辆 ===");
|
||||
System.out.println("车辆ID: " + vehicle.getId());
|
||||
System.out.println("车牌号: " + vehicle.getLicensePlate());
|
||||
System.out.println("车头照片: " + vehicle.getCarFrontPhoto());
|
||||
System.out.println("车尾照片: " + vehicle.getCarRearPhoto());
|
||||
System.out.println("行驶证照片: " + vehicle.getDrivingLicensePhoto());
|
||||
System.out.println("牧运通备案码: " + vehicle.getRecordCode());
|
||||
System.out.println("备注: " + vehicle.getRemark());
|
||||
|
||||
// 参数验证
|
||||
if (vehicle.getId() == null) {
|
||||
System.out.println("编辑失败: 车辆ID不能为空");
|
||||
return AjaxResult.error("车辆ID不能为空");
|
||||
}
|
||||
|
||||
if (vehicle.getLicensePlate() == null || vehicle.getLicensePlate().trim().isEmpty()) {
|
||||
System.out.println("编辑失败: 车牌号不能为空");
|
||||
return AjaxResult.error("车牌号不能为空");
|
||||
}
|
||||
|
||||
AjaxResult result = vehicleService.updateVehicle(vehicle);
|
||||
System.out.println("编辑操作执行完成");
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("编辑车辆失败: " + e.getMessage());
|
||||
return AjaxResult.error("编辑车辆失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除车辆(逻辑删除)
|
||||
*/
|
||||
@SaCheckPermission("vehicle:delete")
|
||||
@GetMapping("/delete")
|
||||
public AjaxResult delete(@RequestParam Integer id) {
|
||||
try {
|
||||
System.out.println("=== 删除车辆 ===");
|
||||
System.out.println("车辆ID: " + id);
|
||||
|
||||
if (id == null) {
|
||||
System.out.println("删除失败: 车辆ID不能为空");
|
||||
return AjaxResult.error("车辆ID不能为空");
|
||||
}
|
||||
|
||||
AjaxResult result = vehicleService.deleteVehicle(id);
|
||||
System.out.println("删除操作执行完成");
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("删除车辆失败: " + e.getMessage());
|
||||
return AjaxResult.error("删除车辆失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,12 @@ public class Delivery implements Serializable {
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
/**
|
||||
* 订单ID(关联order表)
|
||||
*/
|
||||
@TableField("order_id")
|
||||
private Integer orderId;
|
||||
|
||||
/**
|
||||
* 运单号
|
||||
*/
|
||||
@@ -415,4 +421,10 @@ public class Delivery implements Serializable {
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String buyerMobile;
|
||||
|
||||
/**
|
||||
* 订单信息(关联查询,不存储在数据库中)
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private Order orderInfo;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
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.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 订单管理实体类
|
||||
*
|
||||
* @author System
|
||||
* @date 2025-01-20
|
||||
*/
|
||||
@Data
|
||||
@TableName("`order`")
|
||||
public class Order implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
/**
|
||||
* 买方ID(多个买家用逗号分隔)
|
||||
*/
|
||||
@TableField("buyer_id")
|
||||
private String buyerId;
|
||||
|
||||
/**
|
||||
* 卖方ID(多个卖家用逗号分隔)
|
||||
*/
|
||||
@TableField("seller_id")
|
||||
private String sellerId;
|
||||
|
||||
/**
|
||||
* 结算方式:1-上车重量,2-下车重量,3-按肉价结算
|
||||
*/
|
||||
@TableField("settlement_type")
|
||||
private Integer settlementType;
|
||||
|
||||
/**
|
||||
* 逻辑删除标记(0-正常,1-已删除)
|
||||
*/
|
||||
@TableLogic(value = "0", delval = "1")
|
||||
@TableField("is_delete")
|
||||
private Integer isDelete;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField("create_time")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 创建人ID
|
||||
*/
|
||||
@TableField("created_by")
|
||||
private Integer createdBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField("update_time")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 更新人ID
|
||||
*/
|
||||
@TableField("updated_by")
|
||||
private Integer updatedBy;
|
||||
|
||||
/**
|
||||
* 买方名称(不存储在数据库中,用于显示)
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String buyerName;
|
||||
|
||||
/**
|
||||
* 卖方名称(不存储在数据库中,用于显示)
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String sellerName;
|
||||
|
||||
/**
|
||||
* 创建人姓名(不存储在数据库中,用于显示)
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String createdByName;
|
||||
|
||||
/**
|
||||
* 结算方式描述(不存储在数据库中,用于显示)
|
||||
*/
|
||||
@TableField(exist = false)
|
||||
private String settlementTypeDesc;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
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.TableLogic;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 车辆管理实体类
|
||||
*
|
||||
* @author System
|
||||
* @date 2025-01-20
|
||||
*/
|
||||
@Data
|
||||
@TableName("vehicle")
|
||||
public class Vehicle implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
/**
|
||||
* 车牌号
|
||||
*/
|
||||
@TableField("license_plate")
|
||||
private String licensePlate;
|
||||
|
||||
/**
|
||||
* 车头照片URL
|
||||
*/
|
||||
@TableField("car_front_photo")
|
||||
private String carFrontPhoto;
|
||||
|
||||
/**
|
||||
* 车尾照片URL
|
||||
*/
|
||||
@TableField("car_rear_photo")
|
||||
private String carRearPhoto;
|
||||
|
||||
/**
|
||||
* 行驶证照片URL
|
||||
*/
|
||||
@TableField("driving_license_photo")
|
||||
private String drivingLicensePhoto;
|
||||
|
||||
/**
|
||||
* 牧运通备案码
|
||||
*/
|
||||
@TableField("record_code")
|
||||
private String recordCode;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@TableField("remark")
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 逻辑删除标记(0-正常,1-已删除)
|
||||
*/
|
||||
@TableLogic(value = "0", delval = "1")
|
||||
@TableField("is_delete")
|
||||
private Integer isDelete;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField("create_time")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date createTime;
|
||||
|
||||
/**
|
||||
* 创建人ID
|
||||
*/
|
||||
@TableField("created_by")
|
||||
private Integer createdBy;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@TableField("update_time")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date updateTime;
|
||||
|
||||
/**
|
||||
* 更新人ID
|
||||
*/
|
||||
@TableField("updated_by")
|
||||
private Integer updatedBy;
|
||||
}
|
||||
|
||||
@@ -134,5 +134,11 @@ public interface MemberDriverMapper extends BaseMapper<Map<String, Object>> {
|
||||
"WHERE md.username = #{driverName} AND md.car_number = #{licensePlate}")
|
||||
Map<String, Object> selectDriverByNameAndPlate(@Param("driverName") String driverName,
|
||||
@Param("licensePlate") String licensePlate);
|
||||
|
||||
/**
|
||||
* 删除司机信息
|
||||
*/
|
||||
@org.apache.ibatis.annotations.Delete("DELETE FROM member_driver WHERE id = #{id}")
|
||||
int deleteDriver(@Param("id") Integer id);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.aiotagro.cattletrade.business.mapper;
|
||||
|
||||
import com.aiotagro.cattletrade.business.entity.Order;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 订单管理Mapper接口
|
||||
*
|
||||
* @author System
|
||||
* @date 2025-01-20
|
||||
*/
|
||||
@Mapper
|
||||
public interface OrderMapper extends BaseMapper<Order> {
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.aiotagro.cattletrade.business.mapper;
|
||||
|
||||
import com.aiotagro.cattletrade.business.entity.Vehicle;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 车辆管理 Mapper 接口
|
||||
*
|
||||
* @author System
|
||||
* @date 2025-01-20
|
||||
*/
|
||||
@Mapper
|
||||
public interface VehicleMapper extends BaseMapper<Vehicle> {
|
||||
|
||||
/**
|
||||
* 根据车牌号查询车辆(唯一性校验)
|
||||
* @param licensePlate 车牌号
|
||||
* @return 车辆信息
|
||||
*/
|
||||
@Select("SELECT * FROM vehicle WHERE license_plate = #{licensePlate} AND is_delete = 0")
|
||||
Vehicle selectByLicensePlate(@Param("licensePlate") String licensePlate);
|
||||
|
||||
/**
|
||||
* 根据车牌号模糊查询车辆列表
|
||||
* @param licensePlate 车牌号(可为空)
|
||||
* @return 车辆列表
|
||||
*/
|
||||
@Select("<script>" +
|
||||
"SELECT * FROM vehicle WHERE is_delete = 0 " +
|
||||
"<if test='licensePlate != null and licensePlate != \"\"'>" +
|
||||
"AND license_plate LIKE CONCAT('%', #{licensePlate}, '%') " +
|
||||
"</if>" +
|
||||
"ORDER BY create_time DESC " +
|
||||
"</script>")
|
||||
List<Vehicle> selectVehicleList(@Param("licensePlate") String licensePlate);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,391 @@
|
||||
package com.aiotagro.cattletrade.business.service;
|
||||
|
||||
import com.aiotagro.cattletrade.business.entity.*;
|
||||
import com.aiotagro.cattletrade.business.mapper.*;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 设备预警检测服务
|
||||
* 在设备日志同步时进行预警检测
|
||||
*/
|
||||
@Service
|
||||
public class DeviceWarningService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DeviceWarningService.class);
|
||||
|
||||
@Autowired
|
||||
private DeliveryMapper deliveryMapper;
|
||||
|
||||
@Autowired
|
||||
private WarningLogMapper warningLogMapper;
|
||||
|
||||
@Autowired
|
||||
private XqClientLogMapper xqClientLogMapper;
|
||||
|
||||
@Autowired
|
||||
private IotDeviceDataMapper iotDeviceDataMapper;
|
||||
|
||||
/**
|
||||
* 检测设备预警
|
||||
* 每5分钟执行一次
|
||||
*/
|
||||
public void checkDeviceWarnings() {
|
||||
try {
|
||||
logger.info("开始执行设备预警检测任务");
|
||||
|
||||
// 查询所有未完成的运单 (status < 5)
|
||||
List<Delivery> activeDeliveries = deliveryMapper.selectList(
|
||||
new QueryWrapper<Delivery>()
|
||||
.lt("status", 5)
|
||||
);
|
||||
|
||||
if (activeDeliveries.isEmpty()) {
|
||||
logger.info("没有待检测的运单");
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info("找到 {} 个待检测运单", activeDeliveries.size());
|
||||
|
||||
for (Delivery delivery : activeDeliveries) {
|
||||
try {
|
||||
// 获取运单关联的设备
|
||||
List<String> deviceIds = getDeliveryDevices(delivery.getId());
|
||||
|
||||
// 如果运单没有绑定设备,跳过预警检测
|
||||
if (deviceIds.isEmpty()) {
|
||||
logger.debug("运单 {} 未绑定设备,跳过预警检测", delivery.getDeliveryNumber());
|
||||
continue;
|
||||
}
|
||||
|
||||
logger.debug("运单 {} 有 {} 个设备,开始预警检测", delivery.getDeliveryNumber(), deviceIds.size());
|
||||
|
||||
// 检测停留预警
|
||||
checkStagnationWarning(delivery, deviceIds);
|
||||
|
||||
// 检测温度预警
|
||||
checkTemperatureWarning(delivery, deviceIds);
|
||||
|
||||
// 检测距离偏离预警
|
||||
checkDistanceDeviation(delivery, deviceIds);
|
||||
|
||||
// 检测到达时间预警
|
||||
checkArrivalTimeWarning(delivery, deviceIds);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("检测运单 {} 预警失败", delivery.getDeliveryNumber(), e);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("设备预警检测任务执行完成");
|
||||
} catch (Exception e) {
|
||||
logger.error("执行设备预警检测任务失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测停留预警 - 15分钟位置不动
|
||||
*/
|
||||
private void checkStagnationWarning(Delivery delivery, List<String> deviceIds) {
|
||||
try {
|
||||
for (String deviceId : deviceIds) {
|
||||
// 查询最近15分钟的日志记录(每5分钟一条,共3条)
|
||||
List<XqClientLog> recentLogs = xqClientLogMapper.selectList(
|
||||
new QueryWrapper<XqClientLog>()
|
||||
.eq("device_id", deviceId)
|
||||
.orderByDesc("update_time")
|
||||
.last("LIMIT 3")
|
||||
);
|
||||
|
||||
if (recentLogs.size() >= 3) {
|
||||
// 检查最近3条记录的位置是否相同
|
||||
String firstLat = recentLogs.get(0).getLatitude();
|
||||
String firstLon = recentLogs.get(0).getLongitude();
|
||||
|
||||
boolean isStagnant = true;
|
||||
for (int i = 1; i < recentLogs.size(); i++) {
|
||||
String currentLat = recentLogs.get(i).getLatitude();
|
||||
String currentLon = recentLogs.get(i).getLongitude();
|
||||
|
||||
if (currentLat == null || currentLon == null ||
|
||||
firstLat == null || firstLon == null ||
|
||||
!firstLat.equals(currentLat) || !firstLon.equals(currentLon)) {
|
||||
isStagnant = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isStagnant) {
|
||||
// 保存预警记录
|
||||
saveWarningLog(delivery.getId(), "4", "设备停留预警:15分钟内位置未发生变化");
|
||||
logger.info("运单 {} 设备 {} 触发停留预警", delivery.getDeliveryNumber(), deviceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("检测停留预警失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测温度预警
|
||||
*/
|
||||
private void checkTemperatureWarning(Delivery delivery, List<String> deviceIds) {
|
||||
try {
|
||||
for (String deviceId : deviceIds) {
|
||||
// 查询最新的设备日志
|
||||
XqClientLog latestLog = xqClientLogMapper.selectOne(
|
||||
new QueryWrapper<XqClientLog>()
|
||||
.eq("device_id", deviceId)
|
||||
.orderByDesc("update_time")
|
||||
.last("LIMIT 1")
|
||||
);
|
||||
|
||||
if (latestLog != null && latestLog.getDeviceTemp() != null) {
|
||||
try {
|
||||
double temperature = Double.parseDouble(latestLog.getDeviceTemp());
|
||||
|
||||
if (temperature > 40) {
|
||||
saveWarningLog(delivery.getId(), "5", "高温预警:设备温度 " + temperature + "°C,超过40°C");
|
||||
logger.info("运单 {} 设备 {} 触发高温预警", delivery.getDeliveryNumber(), deviceId);
|
||||
} else if (temperature < 30) {
|
||||
saveWarningLog(delivery.getId(), "6", "低温预警:设备温度 " + temperature + "°C,低于30°C");
|
||||
logger.info("运单 {} 设备 {} 触发低温预警", delivery.getDeliveryNumber(), deviceId);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
logger.warn("设备温度格式错误: {}", latestLog.getDeviceTemp());
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("检测温度预警失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测距离偏离预警 - 当前位置偏离路线的十分之一
|
||||
*/
|
||||
private void checkDistanceDeviation(Delivery delivery, List<String> deviceIds) {
|
||||
try {
|
||||
if (delivery.getStartLat() == null || delivery.getStartLon() == null ||
|
||||
delivery.getEndLat() == null || delivery.getEndLon() == null) {
|
||||
logger.debug("运单 {} 的起终点经纬度不完整,跳过距离检测", delivery.getDeliveryNumber());
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算起始地和目的地的距离
|
||||
double totalDistance = calculateDistance(
|
||||
Double.parseDouble(delivery.getStartLat()),
|
||||
Double.parseDouble(delivery.getStartLon()),
|
||||
Double.parseDouble(delivery.getEndLat()),
|
||||
Double.parseDouble(delivery.getEndLon())
|
||||
);
|
||||
|
||||
double deviationThreshold = totalDistance / 10; // 十分之一的距离
|
||||
|
||||
for (String deviceId : deviceIds) {
|
||||
// 查询最新的设备日志
|
||||
XqClientLog latestLog = xqClientLogMapper.selectOne(
|
||||
new QueryWrapper<XqClientLog>()
|
||||
.eq("device_id", deviceId)
|
||||
.orderByDesc("update_time")
|
||||
.last("LIMIT 1")
|
||||
);
|
||||
|
||||
if (latestLog != null && latestLog.getLatitude() != null && latestLog.getLongitude() != null) {
|
||||
try {
|
||||
double currentLat = Double.parseDouble(latestLog.getLatitude());
|
||||
double currentLon = Double.parseDouble(latestLog.getLongitude());
|
||||
|
||||
// 计算当前位置到起点的距离
|
||||
double distanceFromStart = calculateDistance(
|
||||
Double.parseDouble(delivery.getStartLat()),
|
||||
Double.parseDouble(delivery.getStartLon()),
|
||||
currentLat,
|
||||
currentLon
|
||||
);
|
||||
|
||||
// 计算当前位置到终点的距离
|
||||
double distanceFromEnd = calculateDistance(
|
||||
currentLat,
|
||||
currentLon,
|
||||
Double.parseDouble(delivery.getEndLat()),
|
||||
Double.parseDouble(delivery.getEndLon())
|
||||
);
|
||||
|
||||
// 计算实际路线距离(当前位置到起点的距离 + 当前位置到终点的距离)
|
||||
double actualRouteDistance = distanceFromStart + distanceFromEnd;
|
||||
|
||||
// 如果实际路线距离超出总距离 + 偏离阈值,触发预警
|
||||
if (actualRouteDistance > totalDistance + deviationThreshold) {
|
||||
saveWarningLog(delivery.getId(), "7",
|
||||
String.format("位置偏离预警:当前位置偏离计划路线超过 %.2f 公里", deviationThreshold));
|
||||
logger.info("运单 {} 设备 {} 触发位置偏离预警", delivery.getDeliveryNumber(), deviceId);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
logger.warn("经纬度格式错误");
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("检测距离偏离预警失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测到达时间预警
|
||||
*/
|
||||
private void checkArrivalTimeWarning(Delivery delivery, List<String> deviceIds) {
|
||||
try {
|
||||
if (delivery.getEstimatedDeliveryTime() == null) {
|
||||
logger.debug("运单 {} 没有预计送达时间,跳过到达时间检测", delivery.getDeliveryNumber());
|
||||
return;
|
||||
}
|
||||
|
||||
Date estimatedTime = delivery.getEstimatedDeliveryTime();
|
||||
Date currentTime = new Date();
|
||||
|
||||
// 计算剩余时间(小时)
|
||||
long diffInMillis = estimatedTime.getTime() - currentTime.getTime();
|
||||
double remainingHours = diffInMillis / (1000.0 * 60 * 60);
|
||||
|
||||
if (deviceIds.isEmpty()) {
|
||||
logger.debug("运单 {} 没有设备,跳过到达时间检测", delivery.getDeliveryNumber());
|
||||
return;
|
||||
}
|
||||
|
||||
// 查询最新位置
|
||||
XqClientLog latestLog = xqClientLogMapper.selectOne(
|
||||
new QueryWrapper<XqClientLog>()
|
||||
.in("device_id", deviceIds)
|
||||
.orderByDesc("update_time")
|
||||
.last("LIMIT 1")
|
||||
);
|
||||
|
||||
if (latestLog != null && latestLog.getLatitude() != null && latestLog.getLongitude() != null) {
|
||||
try {
|
||||
double currentLat = Double.parseDouble(latestLog.getLatitude());
|
||||
double currentLon = Double.parseDouble(latestLog.getLongitude());
|
||||
|
||||
if (delivery.getEndLat() == null || delivery.getEndLon() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
double endLat = Double.parseDouble(delivery.getEndLat());
|
||||
double endLon = Double.parseDouble(delivery.getEndLon());
|
||||
|
||||
// 计算剩余距离(公里)
|
||||
double remainingDistance = calculateDistance(currentLat, currentLon, endLat, endLon);
|
||||
|
||||
// 假设平均速度80公里/小时
|
||||
double avgSpeed = 80;
|
||||
double requiredTime = remainingDistance / avgSpeed;
|
||||
|
||||
// 判断是否能在预计时间内到达
|
||||
if (remainingHours > 0 && requiredTime > remainingHours) {
|
||||
// 延误预警
|
||||
saveWarningLog(delivery.getId(), "8",
|
||||
String.format("延误预警:预计无法在约定时间到达,预计延误 %.2f 小时", requiredTime - remainingHours));
|
||||
logger.info("运单 {} 触发延误预警", delivery.getDeliveryNumber());
|
||||
} else if (remainingHours < 0 && Math.abs(remainingHours) > 2) {
|
||||
// 超前到达预警(超过2小时)
|
||||
saveWarningLog(delivery.getId(), "9",
|
||||
String.format("超前到达预警:已提前 %.2f 小时到达目的地", Math.abs(remainingHours)));
|
||||
logger.info("运单 {} 触发超前到达预警", delivery.getDeliveryNumber());
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
logger.warn("经纬度格式错误");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("检测到达时间预警失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取运单关联的设备ID列表(从iot_device_data表查询)
|
||||
*/
|
||||
private List<String> getDeliveryDevices(Integer deliveryId) {
|
||||
try {
|
||||
List<IotDeviceData> devices = iotDeviceDataMapper.selectList(
|
||||
new QueryWrapper<IotDeviceData>()
|
||||
.eq("delivery_id", deliveryId)
|
||||
);
|
||||
|
||||
List<String> deviceIds = new ArrayList<>();
|
||||
for (IotDeviceData device : devices) {
|
||||
if (device.getDeviceId() != null && !device.getDeviceId().isEmpty()) {
|
||||
deviceIds.add(device.getDeviceId());
|
||||
}
|
||||
}
|
||||
|
||||
return deviceIds;
|
||||
} catch (Exception e) {
|
||||
logger.error("查询运单{}的设备失败", deliveryId, e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存预警记录
|
||||
*/
|
||||
private void saveWarningLog(Integer deliveryId, String warningType, String warningDesc) {
|
||||
WarningLog warningLog = new WarningLog();
|
||||
warningLog.setDeliveryId(deliveryId);
|
||||
warningLog.setWarningType(warningType);
|
||||
warningLog.setWarningTime(new Date());
|
||||
|
||||
// 验证是否已有相同类型的最新预警(5分钟内不重复保存)
|
||||
WarningLog latestWarning = warningLogMapper.selectOne(
|
||||
new QueryWrapper<WarningLog>()
|
||||
.eq("delivery_id", deliveryId)
|
||||
.eq("warning_type", warningType)
|
||||
.orderByDesc("warning_time")
|
||||
.last("LIMIT 1")
|
||||
);
|
||||
|
||||
if (latestWarning != null) {
|
||||
long diffMinutes = (new Date().getTime() - latestWarning.getWarningTime().getTime()) / (1000 * 60);
|
||||
if (diffMinutes < 5) {
|
||||
logger.debug("5分钟内已有相同预警,跳过保存");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
warningLogMapper.insert(warningLog);
|
||||
logger.info("保存预警记录:运单ID={}, 预警类型={}", deliveryId, warningType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两点间距离(Haversine公式)
|
||||
*/
|
||||
private double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
|
||||
final int R = 6371; // 地球半径(公里)
|
||||
|
||||
double lat1Rad = Math.toRadians(lat1);
|
||||
double lat2Rad = Math.toRadians(lat2);
|
||||
double deltaLat = Math.toRadians(lat2 - lat1);
|
||||
double deltaLon = Math.toRadians(lon2 - lon1);
|
||||
|
||||
double a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) +
|
||||
Math.cos(lat1Rad) * Math.cos(lat2Rad) *
|
||||
Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2);
|
||||
|
||||
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||
|
||||
return R * c;
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出统计信息
|
||||
*/
|
||||
public void logStatistics() {
|
||||
logger.info("设备预警检测统计信息已更新");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.aiotagro.cattletrade.business.service;
|
||||
|
||||
import com.aiotagro.cattletrade.business.entity.Order;
|
||||
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-20
|
||||
*/
|
||||
public interface IOrderService extends IService<Order> {
|
||||
|
||||
/**
|
||||
* 分页查询订单列表
|
||||
*
|
||||
* @param params 查询参数
|
||||
* @return 分页结果
|
||||
*/
|
||||
PageResultResponse<Order> pageQuery(Map<String, Object> params);
|
||||
|
||||
/**
|
||||
* 新增订单
|
||||
*
|
||||
* @param order 订单信息
|
||||
* @return AjaxResult
|
||||
*/
|
||||
AjaxResult addOrder(Order order);
|
||||
|
||||
/**
|
||||
* 更新订单信息
|
||||
*
|
||||
* @param order 订单信息
|
||||
* @return AjaxResult
|
||||
*/
|
||||
AjaxResult updateOrder(Order order);
|
||||
|
||||
/**
|
||||
* 删除订单(逻辑删除)
|
||||
*
|
||||
* @param id 订单ID
|
||||
* @return AjaxResult
|
||||
*/
|
||||
AjaxResult deleteOrder(Integer id);
|
||||
|
||||
/**
|
||||
* 查询订单详情
|
||||
*
|
||||
* @param id 订单ID
|
||||
* @return AjaxResult
|
||||
*/
|
||||
AjaxResult getOrderDetail(Integer id);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.aiotagro.cattletrade.business.service;
|
||||
|
||||
import com.aiotagro.cattletrade.business.entity.Vehicle;
|
||||
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-20
|
||||
*/
|
||||
public interface IVehicleService extends IService<Vehicle> {
|
||||
|
||||
/**
|
||||
* 分页查询车辆列表
|
||||
*
|
||||
* @param params 查询参数
|
||||
* @return 分页结果
|
||||
*/
|
||||
PageResultResponse<Vehicle> pageQuery(Map<String, Object> params);
|
||||
|
||||
/**
|
||||
* 新增车辆
|
||||
*
|
||||
* @param vehicle 车辆信息
|
||||
* @return AjaxResult
|
||||
*/
|
||||
AjaxResult addVehicle(Vehicle vehicle);
|
||||
|
||||
/**
|
||||
* 更新车辆信息
|
||||
*
|
||||
* @param vehicle 车辆信息
|
||||
* @return AjaxResult
|
||||
*/
|
||||
AjaxResult updateVehicle(Vehicle vehicle);
|
||||
|
||||
/**
|
||||
* 删除车辆(逻辑删除)
|
||||
*
|
||||
* @param id 车辆ID
|
||||
* @return AjaxResult
|
||||
*/
|
||||
AjaxResult deleteVehicle(Integer id);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@ import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
|
||||
/**
|
||||
* IoT设备数据同步服务
|
||||
@@ -53,7 +56,15 @@ public class IotDeviceSyncService {
|
||||
// 调用外部API获取数据
|
||||
List<Map<String, Object>> deviceDataList = fetchDeviceDataFromApi();
|
||||
|
||||
if (deviceDataList.isEmpty()) {
|
||||
// 提取API返回的设备ID集合
|
||||
Set<String> apiDeviceIds = new HashSet<>();
|
||||
for (Map<String, Object> deviceData : deviceDataList) {
|
||||
if (deviceData.get("deviceId") != null) {
|
||||
apiDeviceIds.add(String.valueOf(deviceData.get("deviceId")));
|
||||
}
|
||||
}
|
||||
|
||||
if (apiDeviceIds.isEmpty()) {
|
||||
logger.warn("未获取到设备数据");
|
||||
syncLog.setSyncStatus("SUCCESS");
|
||||
syncLog.setTotalCount(0);
|
||||
@@ -74,7 +85,7 @@ public class IotDeviceSyncService {
|
||||
|
||||
// 检查设备是否已存在
|
||||
IotDeviceData existingDevice = iotDeviceDataMapper.selectOne(
|
||||
new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<IotDeviceData>()
|
||||
new QueryWrapper<IotDeviceData>()
|
||||
.eq("device_id", iotDevice.getDeviceId())
|
||||
);
|
||||
|
||||
@@ -97,6 +108,13 @@ public class IotDeviceSyncService {
|
||||
}
|
||||
}
|
||||
|
||||
// 清理已被重新分配到其他项目的设备
|
||||
try {
|
||||
cleanupReassignedDevices(apiDeviceIds);
|
||||
} catch (Exception e) {
|
||||
logger.error("清理重新分配设备失败", e);
|
||||
}
|
||||
|
||||
syncLog.setSyncStatus(failedCount > 0 ? "FAILED" : "SUCCESS");
|
||||
syncLog.setSuccessCount(successCount);
|
||||
syncLog.setFailedCount(failedCount);
|
||||
@@ -342,4 +360,38 @@ public class IotDeviceSyncService {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理已被重新分配到其他项目的设备
|
||||
* 只删除未被分配给租户或装车订单的设备
|
||||
*/
|
||||
private void cleanupReassignedDevices(Set<String> apiDeviceIds) {
|
||||
try {
|
||||
logger.info("开始清理已重新分配的设备");
|
||||
|
||||
// 查询数据库中所有设备
|
||||
List<IotDeviceData> allDevices = iotDeviceDataMapper.selectList(null);
|
||||
|
||||
int deletedCount = 0;
|
||||
for (IotDeviceData device : allDevices) {
|
||||
// 如果设备不在API返回列表中
|
||||
if (!apiDeviceIds.contains(device.getDeviceId())) {
|
||||
// 只删除未被分配的设备(tenantId和deliveryId都为null)
|
||||
if (device.getTenantId() == null && device.getDeliveryId() == null) {
|
||||
iotDeviceDataMapper.deleteById(device.getId());
|
||||
logger.info("删除已重新分配的设备: deviceId={}, id={}", device.getDeviceId(), device.getId());
|
||||
deletedCount++;
|
||||
} else {
|
||||
logger.warn("设备不在API返回列表中但已被分配,保留: deviceId={}, tenantId={}, deliveryId={}",
|
||||
device.getDeviceId(), device.getTenantId(), device.getDeliveryId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("清理完成,共删除 {} 个已重新分配的设备", deletedCount);
|
||||
} catch (Exception e) {
|
||||
logger.error("清理已重新分配设备时发生错误", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,8 @@ public class DeliveryServiceImpl extends ServiceImpl<DeliveryMapper, Delivery> i
|
||||
private IDeliveryDeviceService deliveryDeviceService;
|
||||
@Autowired
|
||||
private IXqClientService xqClientService;
|
||||
@Autowired
|
||||
private com.aiotagro.cattletrade.business.mapper.OrderMapper orderMapper;
|
||||
|
||||
|
||||
/**
|
||||
@@ -1183,6 +1185,16 @@ public class DeliveryServiceImpl extends ServiceImpl<DeliveryMapper, Delivery> i
|
||||
}
|
||||
}
|
||||
|
||||
// 填充装车订单的关联订单信息
|
||||
for适合 (Delivery delivery : resList) {
|
||||
if (delivery.getOrderId() != null) {
|
||||
com.aiotagro.cattletrade.business.entity.Order order = orderMapper.selectById(delivery.getOrderId());
|
||||
if (order != null) {
|
||||
delivery.setOrderInfo(order);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新分页信息
|
||||
long filteredTotal = resList.size();
|
||||
return new PageResultResponse(filteredTotal, resList);
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
package com.aiotagro.cattletrade.business.service.impl;
|
||||
|
||||
import com.aiotagro.cattletrade.business.entity.Order;
|
||||
import com.aiotagro.cattletrade.business.entity.Member;
|
||||
import com.aiotagro.cattletrade.business.entity.SysUser;
|
||||
import com.aiotagro.cattletrade.business.mapper.OrderMapper;
|
||||
import com.aiotagro.cattletrade.business.mapper.MemberMapper;
|
||||
import com.aiotagro.cattletrade.business.mapper.SysUserMapper;
|
||||
import com.aiotagro.cattletrade.business.service.IOrderService;
|
||||
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.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.github.pagehelper.Page;
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 订单管理服务实现类
|
||||
*
|
||||
* @author System
|
||||
* @date 2025-01-20
|
||||
*/
|
||||
@Service
|
||||
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements IOrderService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(OrderServiceImpl.class);
|
||||
|
||||
@Autowired
|
||||
private OrderMapper orderMapper;
|
||||
|
||||
@Autowired
|
||||
private MemberMapper memberMapper;
|
||||
|
||||
@Autowired
|
||||
private SysUserMapper sysUserMapper;
|
||||
|
||||
/**
|
||||
* 分页查询订单列表
|
||||
*/
|
||||
@Override
|
||||
public PageResultResponse<Order> pageQuery(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;
|
||||
Integer settlementType = params.get("settlementType") != null ? (Integer) params.get("settlementType") : null;
|
||||
|
||||
logger.info("分页查询订单列表,页码:{},每页数量:{}", pageNum, pageSize);
|
||||
|
||||
// 使用PageHelper进行分页
|
||||
Page<Order> page = PageHelper.startPage(pageNum, pageSize);
|
||||
|
||||
// 构建查询条件
|
||||
LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(settlementType != null, Order::getSettlementType, settlementType);
|
||||
queryWrapper.orderByDesc(Order::getCreateTime);
|
||||
|
||||
// 执行查询
|
||||
List<Order> list = orderMapper.selectList(queryWrapper);
|
||||
|
||||
// 填充关联信息
|
||||
list.forEach(this::fillOrderInfo);
|
||||
|
||||
// 构建分页结果
|
||||
logger.info("查询到{}条订单记录", list.size());
|
||||
return new PageResultResponse<>(page.getTotal(), list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增订单
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public AjaxResult addOrder(Order order) {
|
||||
logger.info("开始新增订单,买方:{},卖方:{},结算方式:{}", order.getBuyerId(), order.getSellerId(), order.getSettlementType());
|
||||
|
||||
try {
|
||||
// 验证结算方式
|
||||
if (order.getSettlementType() == null || order.getSettlementType() < 1 || order.getSettlementType() > 3) {
|
||||
logger.error("结算方式无效:{}", order.getSettlementType());
|
||||
return AjaxResult.error("结算方式无效");
|
||||
}
|
||||
|
||||
// 设置创建人和创建时间
|
||||
Integer userId = SecurityUtil.getCurrentUserId();
|
||||
order.setCreatedBy(userId);
|
||||
order.setCreateTime(new Date());
|
||||
|
||||
// 插入数据库
|
||||
int result = orderMapper.insert(order);
|
||||
|
||||
if (result > 0) {
|
||||
logger.info("新增订单成功,订单ID:{}", order.getId());
|
||||
return AjaxResult.success("新增订单成功");
|
||||
} else {
|
||||
logger.error("新增订单失败");
|
||||
return AjaxResult.error("新增订单失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("新增订单异常:{}", e.getMessage(), e);
|
||||
return AjaxResult.error("新增订单失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新订单信息
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public AjaxResult updateOrder(Order order) {
|
||||
if (order.getId() == null) {
|
||||
logger.error("订单ID不能为空");
|
||||
return AjaxResult.error("订单ID不能为空");
|
||||
}
|
||||
|
||||
logger.info("开始更新订单,订单ID:{}", order.getId());
|
||||
|
||||
try {
|
||||
// 验证订单是否存在
|
||||
Order existingOrder = orderMapper.selectById(order.getId());
|
||||
if (existingOrder == null) {
|
||||
logger.error("订单不存在,ID:{}", order.getId());
|
||||
return AjaxResult.error("订单不存在");
|
||||
}
|
||||
|
||||
// 验证结算方式
|
||||
if (order.getSettlementType() != null && (order.getSettlementType() < 1 || order.getSettlementType() > 3)) {
|
||||
logger.error("结算方式无效:{}", order.getSettlementType());
|
||||
return AjaxResult.error("结算方式无效");
|
||||
}
|
||||
|
||||
// 设置更新人和更新时间
|
||||
Integer userId = SecurityUtil.getCurrentUserId();
|
||||
order.setUpdatedBy(userId);
|
||||
order.setUpdateTime(new Date());
|
||||
|
||||
// 更新数据库
|
||||
int result = orderMapper.updateById(order);
|
||||
|
||||
if (result > 0) {
|
||||
logger.info("更新订单成功,订单ID:{}", order.getId());
|
||||
return AjaxResult.success("更新订单成功");
|
||||
} else {
|
||||
logger.error("更新订单失败");
|
||||
return AjaxResult.error("更新订单失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("更新订单异常:{}", e.getMessage(), e);
|
||||
return AjaxResult.error("更新订单失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除订单(逻辑删除)
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public AjaxResult deleteOrder(Integer id) {
|
||||
if (id == null) {
|
||||
logger.error("订单ID不能为空");
|
||||
return AjaxResult.error("订单ID不能为空");
|
||||
}
|
||||
|
||||
logger.info("开始删除订单,订单ID:{}", id);
|
||||
|
||||
try {
|
||||
// 查询订单是否存在
|
||||
Order order = orderMapper.selectById(id);
|
||||
if (order == null) {
|
||||
logger.error("订单不存在,ID:{}", id);
|
||||
return AjaxResult.error("订单不存在");
|
||||
}
|
||||
|
||||
// 逻辑删除(通过update方法设置is_delete=1)
|
||||
// MyBatis-Plus的@TableLogic会自动处理
|
||||
int result = orderMapper.deleteById(id);
|
||||
|
||||
if (result > 0) {
|
||||
logger.info("删除订单成功,订单ID:{}", id);
|
||||
return AjaxResult.success("删除订单成功");
|
||||
} else {
|
||||
logger.error("删除订单失败");
|
||||
return AjaxResult.error("删除订单失败");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("删除订单异常:{}", e.getMessage(), e);
|
||||
return AjaxResult.error("删除订单失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询订单详情
|
||||
*/
|
||||
@Override
|
||||
public AjaxResult getOrderDetail(Integer id) {
|
||||
if (id == null) {
|
||||
return AjaxResult.error("订单ID不能为空");
|
||||
}
|
||||
|
||||
logger.info("查询订单详情,订单ID:{}", id);
|
||||
|
||||
Order order = orderMapper.selectById(id);
|
||||
if (order == null) {
|
||||
logger.error("订单不存在,ID:{}", id);
|
||||
return AjaxResult.error("订单不存在");
|
||||
}
|
||||
|
||||
// 填充关联信息
|
||||
fillOrderInfo(order);
|
||||
|
||||
return AjaxResult.success(order);
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充订单关联信息(买方名称、卖方名称、创建人名称、结算方式描述)
|
||||
*/
|
||||
private void fillOrderInfo(Order order) {
|
||||
// 填充买方名称
|
||||
if (order.getBuyerId() != null && !order.getBuyerId().isEmpty()) {
|
||||
String buyerNames = Arrays.stream(order.getBuyerId().split(","))
|
||||
.map(buyerId -> {
|
||||
try {
|
||||
Map<String, Object> memberUser = memberMapper.selectMemberUserById(Integer.parseInt(buyerId.trim()));
|
||||
if (memberUser != null && memberUser.get("username") != null) {
|
||||
return (String) memberUser.get("username");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("查询买方信息失败,买方ID:{}", buyerId);
|
||||
}
|
||||
return "";
|
||||
})
|
||||
.filter(name -> !name.isEmpty())
|
||||
.collect(Collectors.joining(", "));
|
||||
order.setBuyerName(buyerNames);
|
||||
}
|
||||
|
||||
// 填充卖方名称
|
||||
if (order.getSellerId() != null && !order.getSellerId().isEmpty()) {
|
||||
String sellerNames = Arrays.stream(order.getSellerId().split(","))
|
||||
.map(sellerId -> {
|
||||
try {
|
||||
Map<String, Object> memberUser = memberMapper.selectMemberUserById(Integer.parseInt(sellerId.trim()));
|
||||
if (memberUser != null && memberUser.get("username") != null) {
|
||||
return (String) memberUser.get("username");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("查询卖方信息失败,卖方ID:{}", sellerId);
|
||||
}
|
||||
return "";
|
||||
})
|
||||
.filter(name -> !name.isEmpty())
|
||||
.collect(Collectors.joining(", "));
|
||||
order.setSellerName(sellerNames);
|
||||
}
|
||||
|
||||
// 填充创建人名称
|
||||
if (order.getCreatedBy() != null) {
|
||||
SysUser user = sysUserMapper.selectById(order.getCreatedBy());
|
||||
if (user != null) {
|
||||
order.setCreatedByName(user.getName());
|
||||
}
|
||||
}
|
||||
|
||||
// 填充结算方式描述
|
||||
if (order.getSettlementType() != null) {
|
||||
switch (order.getSettlementType()) {
|
||||
case 1:
|
||||
order.setSettlementTypeDesc("上车重量");
|
||||
break;
|
||||
case 2:
|
||||
order.setSettlementTypeDesc("下车重量");
|
||||
break;
|
||||
case 3:
|
||||
order.setSettlementTypeDesc("按肉价结算");
|
||||
break;
|
||||
default:
|
||||
order.setSettlementTypeDesc("未知");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
package com.aiotagro.cattletrade.business.service.impl;
|
||||
|
||||
import com.aiotagro.cattletrade.business.entity.Vehicle;
|
||||
import com.aiotagro.cattletrade.business.mapper.VehicleMapper;
|
||||
import com.aiotagro.cattletrade.business.service.IVehicleService;
|
||||
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.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 java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 车辆管理服务实现类
|
||||
*
|
||||
* @author System
|
||||
* @date 2025-01-20
|
||||
*/
|
||||
@Service
|
||||
public class VehicleServiceImpl extends ServiceImpl<VehicleMapper, Vehicle> implements IVehicleService {
|
||||
|
||||
@Autowired
|
||||
private VehicleMapper vehicleMapper;
|
||||
|
||||
/**
|
||||
* 分页查询车辆列表
|
||||
*/
|
||||
@Override
|
||||
public PageResultResponse<Vehicle> pageQuery(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 licensePlate = (String) params.get("licensePlate");
|
||||
|
||||
// 使用PageHelper进行分页
|
||||
Page<Vehicle> page = PageHelper.startPage(pageNum, pageSize);
|
||||
|
||||
// 构建查询条件
|
||||
LambdaQueryWrapper<Vehicle> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.like(licensePlate != null && !licensePlate.isEmpty(), Vehicle::getLicensePlate, licensePlate);
|
||||
queryWrapper.orderByDesc(Vehicle::getCreateTime);
|
||||
|
||||
// 执行查询
|
||||
List<Vehicle> list = vehicleMapper.selectList(queryWrapper);
|
||||
|
||||
// 构建分页结果(使用构造函数)
|
||||
return new PageResultResponse<>(page.getTotal(), list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增车辆
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public AjaxResult addVehicle(Vehicle vehicle) {
|
||||
// 验证车牌号是否已存在
|
||||
Vehicle existingVehicle = vehicleMapper.selectByLicensePlate(vehicle.getLicensePlate());
|
||||
if (existingVehicle != null) {
|
||||
return AjaxResult.error("车牌号已存在");
|
||||
}
|
||||
|
||||
// 设置创建人和创建时间
|
||||
Integer userId = SecurityUtil.getCurrentUserId();
|
||||
vehicle.setCreatedBy(userId);
|
||||
vehicle.setCreateTime(new Date());
|
||||
|
||||
// 插入数据库
|
||||
int result = vehicleMapper.insert(vehicle);
|
||||
|
||||
if (result > 0) {
|
||||
return AjaxResult.success("新增车辆成功");
|
||||
} else {
|
||||
return AjaxResult.error("新增车辆失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新车辆信息
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public AjaxResult updateVehicle(Vehicle vehicle) {
|
||||
if (vehicle.getId() == null) {
|
||||
return AjaxResult.error("车辆ID不能为空");
|
||||
}
|
||||
|
||||
// 验证车牌号唯一性(排除当前记录)
|
||||
Vehicle existingVehicle = vehicleMapper.selectByLicensePlate(vehicle.getLicensePlate());
|
||||
if (existingVehicle != null && !existingVehicle.getId().equals(vehicle.getId())) {
|
||||
return AjaxResult.error("车牌号已存在");
|
||||
}
|
||||
|
||||
// 设置更新人和更新时间
|
||||
Integer userId = SecurityUtil.getCurrentUserId();
|
||||
vehicle.setUpdatedBy(userId);
|
||||
vehicle.setUpdateTime(new Date());
|
||||
|
||||
// 更新数据库
|
||||
int result = vehicleMapper.updateById(vehicle);
|
||||
|
||||
if (result > 0) {
|
||||
return AjaxResult.success("更新车辆成功");
|
||||
} else {
|
||||
return AjaxResult.error("更新车辆失败");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除车辆(逻辑删除)
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public AjaxResult deleteVehicle(Integer id) {
|
||||
if (id == null) {
|
||||
return AjaxResult.error("车辆ID不能为空");
|
||||
}
|
||||
|
||||
// 查询车辆是否存在
|
||||
Vehicle vehicle = vehicleMapper.selectById(id);
|
||||
if (vehicle == null) {
|
||||
return AjaxResult.error("车辆不存在");
|
||||
}
|
||||
|
||||
// 逻辑删除
|
||||
vehicle.setIsDelete(1);
|
||||
int result = vehicleMapper.updateById(vehicle);
|
||||
|
||||
if (result > 0) {
|
||||
return AjaxResult.success("删除车辆成功");
|
||||
} else {
|
||||
return AjaxResult.error("删除车辆失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,18 @@ import lombok.Getter;
|
||||
@Getter
|
||||
public enum WarningStatusAdminEnum {
|
||||
/**
|
||||
* 牲畜类型
|
||||
* 预警类型枚举
|
||||
*/
|
||||
CATTLE(0, "盘点正常"),
|
||||
SHEEP(1, "距离正常"),
|
||||
PIG(2, "数量盘点预警"),
|
||||
DEER(3, "运输距离预警");
|
||||
NORMAL_COUNT(0, "盘点正常"),
|
||||
NORMAL_DISTANCE(1, "距离正常"),
|
||||
COUNT_WARNING(2, "数量盘点预警"),
|
||||
DISTANCE_WARNING(3, "运输距离预警"),
|
||||
STAGNATION_WARNING(4, "设备停留预警"),
|
||||
HIGH_TEMP_WARNING(5, "高温预警"),
|
||||
LOW_TEMP_WARNING(6, "低温预警"),
|
||||
POSITION_DEVIATION_WARNING(7, "位置偏离预警"),
|
||||
DELAY_WARNING(8, "延误预警"),
|
||||
EARLY_ARRIVAL_WARNING(9, "超前到达预警");
|
||||
|
||||
private final int value ;
|
||||
private final String description ;
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.aiotagro.cattletrade.job;
|
||||
|
||||
import com.aiotagro.cattletrade.business.service.IotDeviceSyncService;
|
||||
import com.aiotagro.cattletrade.business.service.IotDeviceLogSyncService;
|
||||
import com.aiotagro.cattletrade.business.service.DeviceWarningService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -24,6 +25,9 @@ public class IotDeviceSyncJob {
|
||||
|
||||
@Autowired
|
||||
private IotDeviceLogSyncService iotDeviceLogSyncService;
|
||||
|
||||
@Autowired
|
||||
private DeviceWarningService deviceWarningService;
|
||||
|
||||
/**
|
||||
* 每5分钟同步一次IoT设备数据
|
||||
@@ -40,9 +44,9 @@ public class IotDeviceSyncJob {
|
||||
}
|
||||
|
||||
/**
|
||||
* 每60分钟同步一次设备数据到日志表
|
||||
* 每5分钟同步一次设备数据到日志表
|
||||
*/
|
||||
@Scheduled(fixedRate = 60 * 60 * 1000) // 60分钟
|
||||
@Scheduled(fixedRate = 5 * 60 * 1000) // 5分钟
|
||||
public void syncDeviceDataToLogs() {
|
||||
try {
|
||||
logger.info("开始执行设备日志同步定时任务");
|
||||
@@ -51,6 +55,12 @@ public class IotDeviceSyncJob {
|
||||
|
||||
// 输出统计信息
|
||||
iotDeviceLogSyncService.logSyncStatistics();
|
||||
|
||||
// 执行预警检测
|
||||
logger.info("开始执行设备预警检测任务");
|
||||
deviceWarningService.checkDeviceWarnings();
|
||||
logger.info("设备预警检测任务执行完成");
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("设备日志同步定时任务执行失败", e);
|
||||
}
|
||||
|
||||
@@ -64,10 +64,11 @@
|
||||
wl.warning_time,
|
||||
wl.inventory_jbq_count,
|
||||
su.name as createByName
|
||||
FROM delivery d left join warning_log wl on d.id = wl.delivery_id
|
||||
FROM delivery d inner join warning_log wl on d.id = wl.delivery_id
|
||||
left join sys_user su on d.created_by = su.id
|
||||
<where>
|
||||
wl.warning_type in (2,3)
|
||||
wl.warning_type in (2,3,4,5,6,7,8,9)
|
||||
and wl.id in (select max(id) from warning_log where delivery_id = d.id group by warning_type)
|
||||
<if test="dto.deliveryNumber != null and '' != dto.deliveryNumber">
|
||||
and d.delivery_number like concat('%', #{dto.deliveryNumber}, '%')
|
||||
</if>
|
||||
|
||||
20
tradeCattle/create_order_table.sql
Normal file
20
tradeCattle/create_order_table.sql
Normal file
@@ -0,0 +1,20 @@
|
||||
-- 创建订单管理表
|
||||
-- 用于管理订单信息,包括买方、卖方、结算方式等
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `order` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`buyer_id` varchar(500) DEFAULT NULL COMMENT '买方ID(多个买家用逗号分隔)',
|
||||
`seller_id` varchar(500) DEFAULT NULL COMMENT '卖方ID(多个卖家用逗号分隔)',
|
||||
`settlement_type` int(11) NOT NULL COMMENT '结算方式:1-上车重量,2-下车重量,3-按肉价结算',
|
||||
`is_delete` tinyint(1) DEFAULT 0 COMMENT '逻辑删除标记(0-正常,1-已删除)',
|
||||
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`created_by` int(11) DEFAULT NULL COMMENT '创建人ID',
|
||||
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`updated_by` int(11) DEFAULT NULL COMMENT '更新人ID',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_is_delete` (`is_delete`),
|
||||
KEY `idx_created_by` (`created_by`),
|
||||
KEY `idx_create_time` (`create_time`),
|
||||
KEY `idx_settlement_type` (`settlement_type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单管理表';
|
||||
|
||||
23
tradeCattle/create_vehicle_table.sql
Normal file
23
tradeCattle/create_vehicle_table.sql
Normal file
@@ -0,0 +1,23 @@
|
||||
-- 创建车辆管理表
|
||||
-- 用于管理车辆的详细信息,包括车牌号、照片、行驶证和牧运通备案码等
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `vehicle` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`license_plate` varchar(20) NOT NULL COMMENT '车牌号',
|
||||
`car_front_photo` varchar(500) DEFAULT NULL COMMENT '车头照片URL',
|
||||
`car_rear_photo` varchar(500) DEFAULT NULL COMMENT '车尾照片URL',
|
||||
`driving_license_photo` varchar(500) DEFAULT NULL COMMENT '行驶证照片URL',
|
||||
`record_code` varchar(100) DEFAULT NULL COMMENT '牧运通备案码',
|
||||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||
`is_delete` tinyint(1) DEFAULT 0 COMMENT '逻辑删除(0-正常,1-已删除)',
|
||||
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`created_by` int(11) DEFAULT NULL COMMENT '创建人ID',
|
||||
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`updated_by` int(11) DEFAULT NULL COMMENT '更新人ID',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_license_plate` (`license_plate`),
|
||||
KEY `idx_is_delete` (`is_delete`),
|
||||
KEY `idx_created_by` (`created_by`),
|
||||
KEY `idx_create_time` (`create_time`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='车辆管理表';
|
||||
|
||||
45
tradeCattle/grant_all_permissions_to_super_admin.sql
Normal file
45
tradeCattle/grant_all_permissions_to_super_admin.sql
Normal file
@@ -0,0 +1,45 @@
|
||||
-- 为超级管理员(roleId=1)分配所有菜单权限
|
||||
-- 这将解决操作权限管理界面中超级管理员权限未全部打开的问题
|
||||
|
||||
-- 1. 查询当前超级管理员已有的权限
|
||||
SELECT rm.role_id, r.name as role_name, rm.menu_id, m.name as menu_name, m.authority
|
||||
FROM sys_role_menu rm
|
||||
LEFT JOIN sys_role r ON rm.role_id = r.id
|
||||
LEFT JOIN sys_menu m ON rm.menu_id = m.id
|
||||
WHERE rm.role_id = 1 AND m.is_delete = 0
|
||||
ORDER BY m.sort;
|
||||
|
||||
-- 2. 为超级管理员角色分配所有菜单权限
|
||||
-- 使用 INSERT ... ON DUPLICATE KEY UPDATE 避免重复插入
|
||||
INSERT INTO sys_role_menu (role_id, menu_id)
|
||||
SELECT 1, id FROM sys_menu WHERE is_delete = 0
|
||||
ON DUPLICATE KEY UPDATE role_id = role_id;
|
||||
|
||||
-- 3. 验证分配结果
|
||||
SELECT
|
||||
rm.role_id,
|
||||
r.name as role_name,
|
||||
COUNT(rm.menu_id) as menu_count
|
||||
FROM sys_role_menu rm
|
||||
LEFT JOIN sys_role r ON rm.role_id = r.id
|
||||
WHERE rm.role_id = 1
|
||||
GROUP BY rm.role_id, r.name;
|
||||
|
||||
-- 4. 查询总菜单数
|
||||
SELECT COUNT(*) as total_menus FROM sys_menu WHERE is_delete = 0;
|
||||
|
||||
-- 5. 查询超级管理员所有权限详情
|
||||
SELECT
|
||||
rm.role_id,
|
||||
r.name as role_name,
|
||||
m.id as menu_id,
|
||||
m.name as menu_name,
|
||||
m.type,
|
||||
m.authority,
|
||||
m.page_url
|
||||
FROM sys_role_menu rm
|
||||
LEFT JOIN sys_role r ON rm.role_id = r.id
|
||||
LEFT JOIN sys_menu m ON rm.menu_id = m.id
|
||||
WHERE rm.role_id = 1 AND m.is_delete = 0
|
||||
ORDER BY m.parent_id, m.sort;
|
||||
|
||||
18
tradeCattle/grant_super_admin_to_user.sql
Normal file
18
tradeCattle/grant_super_admin_to_user.sql
Normal file
@@ -0,0 +1,18 @@
|
||||
-- 授予手机号15900000000的用户超级管理员权限
|
||||
-- 修改sys_user表中的role_id为1(超级管理员角色ID)
|
||||
|
||||
UPDATE sys_user
|
||||
SET role_id = 1
|
||||
WHERE mobile = '15900000000' AND is_delete = 0;
|
||||
|
||||
-- 查询修改结果
|
||||
SELECT id, name, mobile, role_id, status, create_time
|
||||
FROM sys_user
|
||||
WHERE mobile = '15900000000' AND is_delete = 0;
|
||||
|
||||
-- 验证角色是否正确
|
||||
SELECT u.id, u.name, u.mobile, u.role_id, r.name as role_name, r.description
|
||||
FROM sys_user u
|
||||
LEFT JOIN sys_role r ON u.role_id = r.id
|
||||
WHERE u.mobile = '15900000000' AND u.is_delete = 0;
|
||||
|
||||
99
tradeCattle/insert_vehicle_menu_permissions.sql
Normal file
99
tradeCattle/insert_vehicle_menu_permissions.sql
Normal file
@@ -0,0 +1,99 @@
|
||||
-- 车辆管理模块权限配置SQL
|
||||
-- 在sys_menu表中添加车辆管理的菜单权限
|
||||
|
||||
-- 1. 插入车辆管理主菜单
|
||||
INSERT INTO `sys_menu` (
|
||||
`name`,
|
||||
`parent_id`,
|
||||
`sort`,
|
||||
`route_url`,
|
||||
`page_url`,
|
||||
`type`,
|
||||
`authority`,
|
||||
`create_time`,
|
||||
`update_time`
|
||||
) VALUES (
|
||||
'车辆管理',
|
||||
(SELECT id FROM (SELECT id FROM sys_menu WHERE name = '用户管理' AND parent_id = 0 LIMIT 1) AS t),
|
||||
3,
|
||||
'/vehicle',
|
||||
'/userManage/vehicle',
|
||||
1,
|
||||
'vehicle:query',
|
||||
NOW(),
|
||||
NOW()
|
||||
) ON DUPLICATE KEY UPDATE
|
||||
`name` = VALUES(`name`),
|
||||
`page_url` = VALUES(`page_url`);
|
||||
|
||||
-- 2. 获取刚插入的车辆管理菜单ID
|
||||
SET @vehicle_menu_id = LAST_INSERT_ID();
|
||||
SELECT @vehicle_menu_id := id FROM sys_menu WHERE page_url = '/userManage/vehicle' LIMIT 1;
|
||||
|
||||
-- 3. 插入新增车辆权限按钮
|
||||
INSERT INTO `sys_menu` (
|
||||
`name`,
|
||||
`parent_id`,
|
||||
`sort`,
|
||||
`type`,
|
||||
`authority`,
|
||||
`create_time`,
|
||||
`update_time`
|
||||
) VALUES (
|
||||
'新增车辆',
|
||||
@vehicle_menu_id,
|
||||
1,
|
||||
2,
|
||||
'vehicle:add',
|
||||
NOW(),
|
||||
NOW()
|
||||
) ON DUPLICATE KEY UPDATE
|
||||
`name` = VALUES(`name`),
|
||||
`authority` = VALUES(`authority`);
|
||||
|
||||
-- 4. 插入编辑车辆权限按钮
|
||||
INSERT INTO `sys_menu` (
|
||||
`name`,
|
||||
`parent_id`,
|
||||
`sort`,
|
||||
`type`,
|
||||
`authority`,
|
||||
`create_time`,
|
||||
`update_time`
|
||||
) VALUES (
|
||||
'编辑车辆',
|
||||
@vehicle_menu_id,
|
||||
2,
|
||||
2,
|
||||
'vehicle:edit',
|
||||
NOW(),
|
||||
NOW()
|
||||
) ON DUPLICATE KEY UPDATE
|
||||
`name` = VALUES(`name`),
|
||||
`authority` = VALUES(`authority`);
|
||||
|
||||
-- 5. 插入删除车辆权限按钮
|
||||
INSERT INTO `sys_menu` (
|
||||
`name`,
|
||||
`parent_id`,
|
||||
`sort`,
|
||||
`type`,
|
||||
`authority`,
|
||||
`create_time`,
|
||||
`update_time`
|
||||
) VALUES (
|
||||
'删除车辆',
|
||||
@vehicle_menu_id,
|
||||
3,
|
||||
2,
|
||||
'vehicle:delete',
|
||||
NOW(),
|
||||
NOW()
|
||||
) ON DUPLICATE KEY UPDATE
|
||||
`name` = VALUES(`name`),
|
||||
`authority` = VALUES(`authority`);
|
||||
|
||||
-- 6. 将车辆管理相关权限分配给超级管理员角色(role_id = 1)
|
||||
INSERT INTO `sys_role_menu` (`role_id`, `menu_id`)
|
||||
SELECT 1, `id` FROM `sys_menu` WHERE `authority` IN ('vehicle:query', 'vehicle:add', 'vehicle:edit', 'vehicle:delete')
|
||||
ON DUPLICATE KEY UPDATE `role_id` = `role_id`;
|
||||
Reference in New Issue
Block a user