diff --git a/yudao-module-farm/pom.xml b/yudao-module-farm/pom.xml
index f0136113..2dfa7f88 100644
--- a/yudao-module-farm/pom.xml
+++ b/yudao-module-farm/pom.xml
@@ -80,6 +80,13 @@
yudao-spring-boot-starter-mq
+
+
+ org.eclipse.paho
+ org.eclipse.paho.client.mqttv3
+ 1.2.5
+
+
cn.iocoder.boot
@@ -134,14 +141,10 @@
spring-websocket
-
-
-
-
-
-
-
-
+
+ org.springframework.boot
+ spring-boot-starter-data-mongodb
+
diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/config/FarmMongoConfiguration.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/config/FarmMongoConfiguration.java
new file mode 100644
index 00000000..b57e0dc7
--- /dev/null
+++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/config/FarmMongoConfiguration.java
@@ -0,0 +1,15 @@
+package cn.iocoder.yudao.module.farm.config;
+
+import cn.iocoder.yudao.module.farm.dal.mongo.telemetry.DeviceTelemetryRepository;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
+
+/**
+ * Enable Mongo repositories for the farm module.
+ */
+@Configuration
+@EnableMongoRepositories(basePackageClasses = DeviceTelemetryRepository.class)
+public class FarmMongoConfiguration {
+}
+
+
diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/config/MqttAutoConfiguration.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/config/MqttAutoConfiguration.java
new file mode 100644
index 00000000..9195c575
--- /dev/null
+++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/config/MqttAutoConfiguration.java
@@ -0,0 +1,48 @@
+package cn.iocoder.yudao.module.farm.config;
+
+import org.eclipse.paho.client.mqttv3.MqttClient;
+import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+import cn.iocoder.yudao.module.farm.service.mqtt.MqttClientManager;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@EnableConfigurationProperties(MqttProperties.class)
+@ConditionalOnProperty(prefix = "mqtt", name = "broker")
+public class MqttAutoConfiguration {
+
+ @Bean
+ public MqttClient mqttClient(MqttProperties props) throws MqttException {
+ MqttConnectOptions options = new MqttConnectOptions();
+ options.setCleanSession(props.isCleanSession());
+ options.setKeepAliveInterval(props.getKeepAlive());
+ if (props.getUsername() != null && !props.getUsername().isEmpty()) {
+ options.setUserName(props.getUsername());
+ options.setPassword(props.getPassword() != null ? props.getPassword().toCharArray() : new char[0]);
+ }
+ MqttClient client = new MqttClient(props.getBroker(), props.getClientId(), new MemoryPersistence());
+ client.connect(options);
+ return client;
+ }
+
+ @Bean
+ @ConditionalOnProperty(prefix = "mqtt", name = "connections")
+ public java.util.Map multipleMqttClients(MqttProperties props, MqttClientManager manager) throws MqttException {
+ java.util.Map map = new java.util.HashMap<>();
+ if (props.getConnections() != null) {
+ for (MqttConnectionProperties c : props.getConnections()) {
+ MqttClient cli = manager.createAndConnect(
+ c.getName(), c.getBroker(), c.getClientId(), c.getUsername(), c.getPassword(), c.isCleanSession(), c.getKeepAlive()
+ );
+ map.put(c.getName(), cli);
+ }
+ }
+ return map;
+ }
+}
+
+
diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/config/MqttConnectionProperties.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/config/MqttConnectionProperties.java
new file mode 100644
index 00000000..528c53f0
--- /dev/null
+++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/config/MqttConnectionProperties.java
@@ -0,0 +1,97 @@
+package cn.iocoder.yudao.module.farm.config;
+
+public class MqttConnectionProperties {
+
+ private String name;
+ private String broker;
+ private String deviceId;
+ private String clientId;
+ private String username;
+ private String password;
+ private boolean cleanSession = true;
+ private int keepAlive = 30;
+ private int qos = 1;
+ private boolean reconnect = true;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getBroker() {
+ return broker;
+ }
+
+ public void setBroker(String broker) {
+ this.broker = broker;
+ }
+
+ public String getDeviceId() {
+ return deviceId;
+ }
+
+ public void setDeviceId(String deviceId) {
+ this.deviceId = deviceId;
+ }
+
+ public String getClientId() {
+ return clientId;
+ }
+
+ public void setClientId(String clientId) {
+ this.clientId = clientId;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public boolean isCleanSession() {
+ return cleanSession;
+ }
+
+ public void setCleanSession(boolean cleanSession) {
+ this.cleanSession = cleanSession;
+ }
+
+ public int getKeepAlive() {
+ return keepAlive;
+ }
+
+ public void setKeepAlive(int keepAlive) {
+ this.keepAlive = keepAlive;
+ }
+
+ public int getQos() {
+ return qos;
+ }
+
+ public void setQos(int qos) {
+ this.qos = qos;
+ }
+
+ public boolean isReconnect() {
+ return reconnect;
+ }
+
+ public void setReconnect(boolean reconnect) {
+ this.reconnect = reconnect;
+ }
+}
+
+
diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/config/MqttProperties.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/config/MqttProperties.java
new file mode 100644
index 00000000..6f176418
--- /dev/null
+++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/config/MqttProperties.java
@@ -0,0 +1,92 @@
+package cn.iocoder.yudao.module.farm.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@ConfigurationProperties(prefix = "mqtt")
+public class MqttProperties {
+
+ private String broker;
+ private String clientId;
+ private String username;
+ private String password;
+ private boolean cleanSession = true;
+ private int keepAlive = 30;
+ private int qos = 1;
+ private boolean reconnect = true;
+
+ private java.util.List connections;
+
+ public String getBroker() {
+ return broker;
+ }
+
+ public void setBroker(String broker) {
+ this.broker = broker;
+ }
+
+ public String getClientId() {
+ return clientId;
+ }
+
+ public void setClientId(String clientId) {
+ this.clientId = clientId;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public boolean isCleanSession() {
+ return cleanSession;
+ }
+
+ public void setCleanSession(boolean cleanSession) {
+ this.cleanSession = cleanSession;
+ }
+
+ public int getKeepAlive() {
+ return keepAlive;
+ }
+
+ public void setKeepAlive(int keepAlive) {
+ this.keepAlive = keepAlive;
+ }
+
+ public int getQos() {
+ return qos;
+ }
+
+ public void setQos(int qos) {
+ this.qos = qos;
+ }
+
+ public boolean isReconnect() {
+ return reconnect;
+ }
+
+ public void setReconnect(boolean reconnect) {
+ this.reconnect = reconnect;
+ }
+
+ public java.util.List getConnections() {
+ return connections;
+ }
+
+ public void setConnections(java.util.List connections) {
+ this.connections = connections;
+ }
+}
+
+
diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/dict/DictController.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/dict/DictController.java
index 8053c83e..5ff6ec2b 100644
--- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/dict/DictController.java
+++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/dict/DictController.java
@@ -307,12 +307,9 @@ public class DictController {
@Operation(summary = "字典数据维护-下拉框列表-二级物种类别")
@GetMapping("/list/two-library")
- public CommonResult> getTwoLibraryList() {
+ public CommonResult> getTwoLibraryList() {
try {
- // 获取物种类别字典数据
- List dictList = sysDictService.getByTypeCode(CommonConstants.DICT_TYPE_CODE_3);
- // 使用工具类构建二级树结构
- List twoList = TreeStructureUtil.buildTwoLevelTree(dictList);
+ List twoList = speciesLibraryService.getSpeciesTwoLevelTree();
return success(twoList);
} catch (Exception e) {
log.error("获取二级物种类别列表失败", e);
diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/personnelmanagement/PersonnelManagementController.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/personnelmanagement/PersonnelManagementController.java
index 5b4ba08b..a1d07510 100644
--- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/personnelmanagement/PersonnelManagementController.java
+++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/personnelmanagement/PersonnelManagementController.java
@@ -24,6 +24,7 @@ import java.io.IOException;
import java.util.List;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
@Tag(name = "管理后台 - 人员管理")
@@ -38,7 +39,12 @@ public class PersonnelManagementController {
@PostMapping("/create")
@Operation(summary = "创建人员管理")
public CommonResult createPersonnelManagement(@Valid @RequestBody PersonnelManagementSaveReqVO createReqVO) {
- return success(personnelManagementService.createPersonnelManagement(createReqVO));
+ String management = personnelManagementService.createPersonnelManagement(createReqVO);
+ if (management.length() > 0) {
+ return success(management);
+ } else {
+ return error(501,"手机号重复!");
+ }
}
@PutMapping("/reset")
diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/plotinfo/PlotInfoController.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/plotinfo/PlotInfoController.java
index 10bbc378..595a4f42 100644
--- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/plotinfo/PlotInfoController.java
+++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/plotinfo/PlotInfoController.java
@@ -8,7 +8,9 @@ import jakarta.validation.Valid;
import jakarta.validation.Valid;
import jakarta.validation.Valid;
import jakarta.servlet.http.HttpServletResponse;
+
import java.util.List;
+
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import jakarta.annotation.Resource;
@@ -24,6 +26,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
@@ -44,14 +47,12 @@ public class PlotInfoController {
@PostMapping("/create")
@Operation(summary = "创建地块")
-
public CommonResult createPlotInfo(@Valid @RequestBody PlotInfoSaveReqVO createReqVO) {
return success(plotInfoService.createPlotInfo(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新地块")
-
public CommonResult updatePlotInfo(@Valid @RequestBody PlotInfoSaveReqVO updateReqVO) {
plotInfoService.updatePlotInfo(updateReqVO);
return success(true);
@@ -60,7 +61,6 @@ public class PlotInfoController {
@DeleteMapping("/delete")
@Operation(summary = "删除地块")
@Parameter(name = "id", description = "编号", required = true)
-
public CommonResult deletePlotInfo(@RequestParam("id") String id) {
plotInfoService.deletePlotInfo(id);
return success(true);
@@ -69,7 +69,6 @@ public class PlotInfoController {
@DeleteMapping("/delete-list")
@Parameter(name = "ids", description = "编号", required = true)
@Operation(summary = "批量删除地块")
-
public CommonResult deletePlotInfoList(@RequestParam("ids") List ids) {
plotInfoService.deletePlotInfoListByIds(ids);
return success(true);
@@ -78,7 +77,6 @@ public class PlotInfoController {
@GetMapping("/get")
@Operation(summary = "获得地块")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
-
public CommonResult getPlotInfo(@RequestParam("id") String id) {
PlotInfoDO plotInfo = plotInfoService.getPlotInfo(id);
return success(BeanUtils.toBean(plotInfo, PlotInfoRespVO.class));
@@ -86,7 +84,6 @@ public class PlotInfoController {
@GetMapping("/page")
@Operation(summary = "获得地块分页")
-
public CommonResult> getPlotInfoPage(@Valid PlotInfoPageReqVO pageReqVO) {
PageResult pageResult = plotInfoService.getPlotInfoPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, PlotInfoRespVO.class));
@@ -94,15 +91,14 @@ public class PlotInfoController {
@GetMapping("/export-excel")
@Operation(summary = "导出地块 Excel")
-
@ApiAccessLog(operateType = EXPORT)
public void exportPlotInfoExcel(@Valid PlotInfoPageReqVO pageReqVO,
- HttpServletResponse response) throws IOException {
+ HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List list = plotInfoService.getPlotInfoPage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "地块.xls", "数据", PlotInfoRespVO.class,
- BeanUtils.toBean(list, PlotInfoRespVO.class));
+ BeanUtils.toBean(list, PlotInfoRespVO.class));
}
}
\ No newline at end of file
diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/mqtt/MqttConnectionDO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/mqtt/MqttConnectionDO.java
new file mode 100644
index 00000000..cf907fe0
--- /dev/null
+++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/mqtt/MqttConnectionDO.java
@@ -0,0 +1,47 @@
+package cn.iocoder.yudao.module.farm.dal.dataobject.mqtt;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+@TableName("farm_mqtt_connection")
+@KeySequence("farm_mqtt_connection_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class MqttConnectionDO extends BaseDO {
+
+ @TableId
+ private Long id;
+
+ private String tenantId;
+
+ private String name;
+
+ private String deviceId;
+
+ private String broker;
+
+ private String clientId;
+
+ private String username;
+
+ private String password;
+
+ private Boolean cleanSession;
+
+ private Integer keepAlive;
+
+ private Integer qos;
+
+ private Boolean reconnect;
+
+ private Boolean status;
+}
+
+
diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/personnelmanagement/SystemUserRoleDO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/personnelmanagement/SystemUserRoleDO.java
new file mode 100644
index 00000000..70800305
--- /dev/null
+++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/personnelmanagement/SystemUserRoleDO.java
@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.farm.dal.dataobject.personnelmanagement;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+@TableName("system_user_role")
+@KeySequence("system_user_role_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class SystemUserRoleDO extends BaseDO {
+ /**
+ * 自增主键
+ */
+ @TableId
+ private Long id;
+ /**
+ * 用户 ID
+ */
+ private Long userId;
+ /**
+ * 角色 ID
+ */
+ private Long roleId;
+}
diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/mongo/telemetry/DeviceTelemetryDoc.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/mongo/telemetry/DeviceTelemetryDoc.java
new file mode 100644
index 00000000..30b1bc47
--- /dev/null
+++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/mongo/telemetry/DeviceTelemetryDoc.java
@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.module.farm.dal.mongo.telemetry;
+
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Document(collection = "farm_device_telemetry")
+public class DeviceTelemetryDoc {
+
+ @Id
+ private String id;
+ private String tenantId;
+ private String deviceId;
+ private Long ts;
+ private String payloadJson;
+
+ public String getId() { return id; }
+ public void setId(String id) { this.id = id; }
+ public String getTenantId() { return tenantId; }
+ public void setTenantId(String tenantId) { this.tenantId = tenantId; }
+ public String getDeviceId() { return deviceId; }
+ public void setDeviceId(String deviceId) { this.deviceId = deviceId; }
+ public Long getTs() { return ts; }
+ public void setTs(Long ts) { this.ts = ts; }
+ public String getPayloadJson() { return payloadJson; }
+ public void setPayloadJson(String payloadJson) { this.payloadJson = payloadJson; }
+}
+
+
diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/mongo/telemetry/DeviceTelemetryRepository.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/mongo/telemetry/DeviceTelemetryRepository.java
new file mode 100644
index 00000000..e7e3f102
--- /dev/null
+++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/mongo/telemetry/DeviceTelemetryRepository.java
@@ -0,0 +1,11 @@
+package cn.iocoder.yudao.module.farm.dal.mongo.telemetry;
+
+import org.springframework.data.mongodb.repository.MongoRepository;
+
+import java.util.List;
+
+public interface DeviceTelemetryRepository extends MongoRepository {
+ List findTop100ByTenantIdAndDeviceIdOrderByTsDesc(String tenantId, String deviceId);
+}
+
+
diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/mysql/mqtt/MqttConnectionMapper.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/mysql/mqtt/MqttConnectionMapper.java
new file mode 100644
index 00000000..cea5038d
--- /dev/null
+++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/mysql/mqtt/MqttConnectionMapper.java
@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.farm.dal.mysql.mqtt;
+
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.yudao.module.farm.dal.dataobject.mqtt.MqttConnectionDO;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface MqttConnectionMapper extends BaseMapperX {
+
+ default MqttConnectionDO selectByDeviceIdAndTenant(String deviceId, String tenantId) {
+ return selectOne(new LambdaQueryWrapperX()
+ .eqIfPresent(MqttConnectionDO::getDeviceId, deviceId)
+ .eqIfPresent(MqttConnectionDO::getTenantId, tenantId)
+ .eq(MqttConnectionDO::getStatus, true)
+ );
+ }
+}
+
+
diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/mysql/personnelmanagement/SystemUserRoleMapper.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/mysql/personnelmanagement/SystemUserRoleMapper.java
new file mode 100644
index 00000000..15fc1aea
--- /dev/null
+++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/mysql/personnelmanagement/SystemUserRoleMapper.java
@@ -0,0 +1,9 @@
+package cn.iocoder.yudao.module.farm.dal.mysql.personnelmanagement;
+
+import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.yudao.module.farm.dal.dataobject.personnelmanagement.SystemUserRoleDO;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface SystemUserRoleMapper extends BaseMapperX {
+}
diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/mqtt/DeviceMqttService.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/mqtt/DeviceMqttService.java
new file mode 100644
index 00000000..74d55f56
--- /dev/null
+++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/mqtt/DeviceMqttService.java
@@ -0,0 +1,83 @@
+package cn.iocoder.yudao.module.farm.service.mqtt;
+
+import cn.iocoder.yudao.module.farm.dal.dataobject.deviceinfo.DeviceInfoDO;
+import cn.iocoder.yudao.module.farm.dal.mysql.deviceinfo.DeviceInfoMapper;
+import org.eclipse.paho.client.mqttv3.IMqttMessageListener;
+import org.eclipse.paho.client.mqttv3.MqttClient;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.springframework.stereotype.Service;
+
+import jakarta.annotation.Resource;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.nio.charset.StandardCharsets;
+import cn.iocoder.yudao.module.farm.service.telemetry.DeviceTelemetryService;
+
+@Service
+public class DeviceMqttService {
+
+ @Resource
+ private DeviceInfoMapper deviceInfoMapper;
+ @Resource
+ private MqttConnectionService mqttConnectionService;
+ @Resource
+ private DeviceTelemetryService deviceTelemetryService;
+
+ private final Set subscribed = ConcurrentHashMap.newKeySet();
+
+ // 上报主题
+ private String telemetryTopic(String deviceUniqueId) {
+ return "farm/" + deviceUniqueId + "/telemetry";
+ }
+
+ // 下发指令
+ private String commandTopic(String deviceUniqueId) {
+ return "farm/" + deviceUniqueId + "/cmd";
+ }
+
+ public void publishTelemetry(String deviceUniqueId, String jsonPayload) throws MqttException {
+ MqttClient client = mqttConnectionService.getClientByDeviceId(deviceUniqueId);
+ if (client == null) return;
+ client.publish(telemetryTopic(deviceUniqueId), jsonPayload.getBytes(StandardCharsets.UTF_8), 1, false);
+ }
+
+ public void sendCommand(String deviceUniqueId, String jsonCommand) throws MqttException {
+ MqttClient client = mqttConnectionService.getClientByDeviceId(deviceUniqueId);
+ if (client == null) return;
+ client.publish(commandTopic(deviceUniqueId), jsonCommand.getBytes(StandardCharsets.UTF_8), 1, false);
+ }
+
+ public void subscribeTelemetry(String deviceUniqueId, IMqttMessageListener listener) throws MqttException {
+ MqttClient client = mqttConnectionService.getClientByDeviceId(deviceUniqueId);
+ if (client == null) return;
+ String topic = telemetryTopic(deviceUniqueId);
+ String key = client.getClientId() + "|" + topic;
+ if (subscribed.add(key)) {
+ client.subscribe(topic, 1, listener);
+ }
+ }
+
+ public void subscribeCommands(String deviceUniqueId, IMqttMessageListener listener) throws MqttException {
+ MqttClient client = mqttConnectionService.getClientByDeviceId(deviceUniqueId);
+ if (client == null) return;
+ String topic = commandTopic(deviceUniqueId);
+ String key = client.getClientId() + "|" + topic;
+ if (subscribed.add(key)) {
+ client.subscribe(topic, 1, listener);
+ }
+ }
+
+ // 订阅并自动入库
+ public void subscribeTelemetryAndPersist(String deviceUniqueId) throws MqttException {
+ this.subscribeTelemetry(deviceUniqueId, (topic, message) -> {
+ String payload = new String(message.getPayload(), StandardCharsets.UTF_8);
+ deviceTelemetryService.saveTelemetry(deviceUniqueId, payload);
+ });
+ }
+
+ public DeviceInfoDO getDevice(String deviceUniqueId) {
+ return deviceInfoMapper.selectOne(DeviceInfoDO::getDeviceUniqueId, deviceUniqueId);
+ }
+}
+
+
diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/mqtt/MqttClientManager.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/mqtt/MqttClientManager.java
new file mode 100644
index 00000000..62e65cd4
--- /dev/null
+++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/mqtt/MqttClientManager.java
@@ -0,0 +1,50 @@
+package cn.iocoder.yudao.module.farm.service.mqtt;
+
+import org.eclipse.paho.client.mqttv3.MqttClient;
+import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Service
+public class MqttClientManager {
+
+ private final Map clients = new ConcurrentHashMap<>();
+
+ public MqttClient createAndConnect(String name,
+ String broker,
+ String clientId,
+ String username,
+ String password,
+ boolean cleanSession,
+ int keepAlive) throws MqttException {
+ MqttClient client = new MqttClient(broker, clientId, new MemoryPersistence());
+ MqttConnectOptions options = new MqttConnectOptions();
+ options.setCleanSession(cleanSession);
+ options.setKeepAliveInterval(keepAlive);
+ if (username != null && !username.isEmpty()) {
+ options.setUserName(username);
+ options.setPassword(password != null ? password.toCharArray() : new char[0]);
+ }
+ client.connect(options);
+ clients.put(name, client);
+ return client;
+ }
+
+ public MqttClient get(String name) {
+ return clients.get(name);
+ }
+
+ public void disconnectAndRemove(String name) {
+ MqttClient c = clients.remove(name);
+ if (c != null) {
+ try { c.disconnect(); } catch (Exception ignored) {}
+ try { c.close(); } catch (Exception ignored) {}
+ }
+ }
+}
+
+
diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/mqtt/MqttClientService.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/mqtt/MqttClientService.java
new file mode 100644
index 00000000..3d3aada0
--- /dev/null
+++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/mqtt/MqttClientService.java
@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.farm.service.mqtt;
+
+import org.eclipse.paho.client.mqttv3.IMqttMessageListener;
+import org.eclipse.paho.client.mqttv3.MqttClient;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.springframework.stereotype.Service;
+
+import jakarta.annotation.Resource;
+import java.nio.charset.StandardCharsets;
+
+@Service
+public class MqttClientService {
+
+ @Resource
+ private MqttConnectionService mqttConnectionService;
+
+ public void publish(String deviceId, String topic, String payload, int qos, boolean retained) throws MqttException {
+ MqttClient client = mqttConnectionService.getClientByDeviceId(deviceId);
+ if (client == null) return;
+ client.publish(topic, payload.getBytes(StandardCharsets.UTF_8), qos, retained);
+ }
+
+ public void subscribe(String deviceId, String topicFilter, int qos, IMqttMessageListener listener) throws MqttException {
+ MqttClient client = mqttConnectionService.getClientByDeviceId(deviceId);
+ if (client == null) return;
+ client.subscribe(topicFilter, qos, listener);
+ }
+}
+
+
diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/mqtt/MqttConnectionService.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/mqtt/MqttConnectionService.java
new file mode 100644
index 00000000..8b80a79b
--- /dev/null
+++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/mqtt/MqttConnectionService.java
@@ -0,0 +1,102 @@
+package cn.iocoder.yudao.module.farm.service.mqtt;
+
+import cn.iocoder.yudao.module.farm.dal.dataobject.mqtt.MqttConnectionDO;
+import cn.iocoder.yudao.module.farm.dal.mysql.mqtt.MqttConnectionMapper;
+import org.eclipse.paho.client.mqttv3.IMqttMessageListener;
+import org.eclipse.paho.client.mqttv3.MqttClient;
+import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.springframework.stereotype.Service;
+
+import jakarta.annotation.PreDestroy;
+import jakarta.annotation.Resource;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
+
+@Service
+public class MqttConnectionService {
+
+ @Resource
+ private MqttConnectionMapper connectionMapper;
+
+ private final Map cache = new ConcurrentHashMap<>();
+
+ public MqttClient getClientByDeviceId(String deviceId) throws MqttException {
+ String tenantId = String.valueOf(getLoginUser().getTenantId());
+ return this.getClientByDeviceId(deviceId, tenantId);
+ }
+
+ public MqttClient getClientByDeviceId(String deviceId, String tenantId) throws MqttException {
+ String key = tenantId + ":" + deviceId;
+ MqttClient existing = cache.get(key);
+ if (existing != null) {
+ if (!existing.isConnected()) {
+ try { existing.reconnect(); } catch (Exception ignored) {}
+ }
+ if (existing.isConnected()) return existing;
+ }
+
+ MqttConnectionDO cfg = connectionMapper.selectByDeviceIdAndTenant(deviceId, tenantId);
+ if (cfg == null) {
+ return null;
+ }
+
+ MqttClient client = new MqttClient(cfg.getBroker(), cfg.getClientId(), new MemoryPersistence());
+ MqttConnectOptions options = new MqttConnectOptions();
+ options.setCleanSession(Boolean.TRUE.equals(cfg.getCleanSession()));
+ options.setAutomaticReconnect(Boolean.TRUE.equals(cfg.getReconnect()));
+ if (cfg.getKeepAlive() != null) options.setKeepAliveInterval(cfg.getKeepAlive());
+ if (cfg.getUsername() != null && !cfg.getUsername().isEmpty()) {
+ options.setUserName(cfg.getUsername());
+ options.setPassword(cfg.getPassword() != null ? cfg.getPassword().toCharArray() : new char[0]);
+ }
+ try {
+ String lwtTopic = "farm/" + deviceId + "/lwt";
+ MqttMessage lwt = new MqttMessage("offline".getBytes(StandardCharsets.UTF_8));
+ lwt.setQos(cfg.getQos() != null ? cfg.getQos() : 1);
+ lwt.setRetained(true);
+ options.setWill(lwtTopic, lwt.getPayload(), lwt.getQos(), lwt.isRetained());
+ } catch (Exception ignored) {}
+ client.connect(options);
+ cache.put(key, client);
+ return client;
+ }
+
+ public void publish(String deviceId, String topic, String payload, int qos, boolean retained) throws MqttException {
+ MqttClient c = getClientByDeviceId(deviceId);
+ if (c == null) return;
+ c.publish(topic, payload.getBytes(StandardCharsets.UTF_8), qos, retained);
+ }
+
+ public void subscribe(String deviceId, String topicFilter, int qos, IMqttMessageListener listener) throws MqttException {
+ MqttClient c = getClientByDeviceId(deviceId);
+ if (c == null) return;
+ c.subscribe(topicFilter, qos, listener);
+ }
+
+ public void reload(String deviceId) {
+ String tenantId = String.valueOf(getLoginUser().getTenantId());
+ String key = tenantId + ":" + deviceId;
+ MqttClient old = cache.remove(key);
+ if (old != null) {
+ try { old.disconnect(); } catch (Exception ignored) {}
+ try { old.close(); } catch (Exception ignored) {}
+ }
+ }
+
+ @PreDestroy
+ public void shutdown() {
+ for (Map.Entry e : cache.entrySet()) {
+ try { e.getValue().disconnect(); } catch (Exception ignored) {}
+ try { e.getValue().close(); } catch (Exception ignored) {}
+ }
+ cache.clear();
+ }
+}
+
+
diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/personnelmanagement/PersonnelManagementServiceImpl.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/personnelmanagement/PersonnelManagementServiceImpl.java
index b3599467..652fb2d7 100644
--- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/personnelmanagement/PersonnelManagementServiceImpl.java
+++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/personnelmanagement/PersonnelManagementServiceImpl.java
@@ -9,8 +9,10 @@ import cn.iocoder.yudao.module.farm.controller.admin.personnelmanagement.vo.Pers
import cn.iocoder.yudao.module.farm.controller.admin.personnelmanagement.vo.PersonnelManagementSaveReqVO;
import cn.iocoder.yudao.module.farm.dal.dataobject.personnelmanagement.PersonnelManagementDO;
import cn.iocoder.yudao.module.farm.dal.dataobject.personnelmanagement.SystemUserDO;
+import cn.iocoder.yudao.module.farm.dal.dataobject.personnelmanagement.SystemUserRoleDO;
import cn.iocoder.yudao.module.farm.dal.mysql.personnelmanagement.PersonnelManagementMapper;
import cn.iocoder.yudao.module.farm.dal.mysql.personnelmanagement.SystemUserMapper;
+import cn.iocoder.yudao.module.farm.dal.mysql.personnelmanagement.SystemUserRoleMapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import jakarta.annotation.Resource;
import org.springframework.security.crypto.password.PasswordEncoder;
@@ -38,15 +40,21 @@ public class PersonnelManagementServiceImpl implements PersonnelManagementServic
private SystemUserMapper userMapper;
@Resource
private PasswordEncoder passwordEncoder;
+ @Resource
+ private SystemUserRoleMapper systemUserRoleMapper;
@Override
public String createPersonnelManagement(PersonnelManagementSaveReqVO createReqVO) {
LoginUser user = getLoginUser();
+
// 插入
PersonnelManagementDO personnelManagement = BeanUtils.toBean(createReqVO, PersonnelManagementDO.class);
personnelManagement.setId(IdUtil.fastUUID());
personnelManagement.setTenantId(String.valueOf(user.getTenantId()));
-
+ SystemUserDO userDO = userMapper.selectByPhone(personnelManagement.getPhone());
+ if (userDO != null) {
+ return "";
+ }
// 处理图片集合转换
handleImageConversion(personnelManagement, createReqVO);
@@ -59,7 +67,14 @@ public class PersonnelManagementServiceImpl implements PersonnelManagementServic
adminUserDO.setStatus(CommonStatusEnum.ENABLE.getStatus()); // 默认开启
String substring = personnelManagement.getPhone().substring(personnelManagement.getPhone().length() - 6);
adminUserDO.setPassword(encodePassword(substring)); // 加密密码
- userMapper.insert(adminUserDO);
+ userMapper.insert(adminUserDO);// 系统用户同步新增
+ // 用户角色关联
+ for (String s : personnelManagement.getRole().split(",")) {
+ SystemUserRoleDO userRoleDO = new SystemUserRoleDO();
+ userRoleDO.setUserId(adminUserDO.getId());
+ userRoleDO.setRoleId(Long.valueOf(s));
+ systemUserRoleMapper.insert(userRoleDO);
+ }
personnelManagementMapper.insert(personnelManagement);
// 返回
return personnelManagement.getId();
@@ -69,12 +84,25 @@ public class PersonnelManagementServiceImpl implements PersonnelManagementServic
public void updatePersonnelManagement(PersonnelManagementSaveReqVO updateReqVO) {
// 校验存在
validatePersonnelManagementExists(updateReqVO.getId());
+ PersonnelManagementDO managementDO = personnelManagementMapper.selectById(updateReqVO.getId());
+
+
// 更新
PersonnelManagementDO updateObj = BeanUtils.toBean(updateReqVO, PersonnelManagementDO.class);
-
+ SystemUserDO userDO = userMapper.selectByPhone(managementDO.getPhone());
+ if (updateReqVO.getPhone() != null) userDO.setUsername(updateReqVO.getPhone());
+ if (updateReqVO.getName() != null) userDO.setNickname(updateReqVO.getName());
+ if (updateReqVO.getPhone() != null) userDO.setMobile(updateReqVO.getPhone());
+ if (updateReqVO.getPicture() != null) userDO.setAvatar(updateReqVO.getPicture());
// 处理图片集合转换
handleImageConversion(updateObj, updateReqVO);
-
+ for (String s : managementDO.getRole().split(",")) {
+ SystemUserRoleDO userRoleDO = new SystemUserRoleDO();
+ userRoleDO.setUserId(userDO.getId());
+ userRoleDO.setRoleId(Long.valueOf(s));
+ systemUserRoleMapper.insert(userRoleDO);
+ }
+ userMapper.updateById(userDO);
personnelManagementMapper.updateById(updateObj);
}
@@ -82,6 +110,10 @@ public class PersonnelManagementServiceImpl implements PersonnelManagementServic
public void deletePersonnelManagement(String id) {
// 校验存在
validatePersonnelManagementExists(id);
+ PersonnelManagementDO managementDO = personnelManagementMapper.selectById(id);
+ SystemUserDO userDO = userMapper.selectByPhone(managementDO.getPhone());
+ userMapper.deleteById(userDO.getId());
+ systemUserRoleMapper.delete(SystemUserRoleDO::getUserId, userDO.getId());
// 删除
personnelManagementMapper.deleteById(id);
}
diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/specieslibrary/SpeciesLibraryService.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/specieslibrary/SpeciesLibraryService.java
index 4d54dae7..4a55f58c 100644
--- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/specieslibrary/SpeciesLibraryService.java
+++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/specieslibrary/SpeciesLibraryService.java
@@ -69,11 +69,11 @@ public interface SpeciesLibraryService {
*/
Map getSpeciesLibraryForLifeCycMap();
- /**
- * 基于 speciesName1 -> speciesName2 -> cultivarName 构建三级树
- */
+
List getSpeciesThreeLevelTree();
+
+ List getSpeciesTwoLevelTree();
/**
* 物种与模型
* @return
diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/specieslibrary/SpeciesLibraryServiceImpl.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/specieslibrary/SpeciesLibraryServiceImpl.java
index cbf1d7c8..db550083 100644
--- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/specieslibrary/SpeciesLibraryServiceImpl.java
+++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/specieslibrary/SpeciesLibraryServiceImpl.java
@@ -305,6 +305,67 @@ public class SpeciesLibraryServiceImpl implements SpeciesLibraryService {
return result;
}
+ @Override
+ public List getSpeciesTwoLevelTree() {
+ List dictTree = twoDictService.getTwoDictTree();
+ if (dictTree == null || dictTree.isEmpty()) {
+ return new ArrayList<>();
+ }
+
+ // 1级:parentId == null 的节点
+ List level1Nodes = dictTree.stream()
+ .filter(n -> n != null && n.getParentId() == null)
+ .sorted(java.util.Comparator.comparing(TwoDictTreeRespVO::getName, java.util.Comparator.nullsLast(String::compareTo)))
+ .collect(Collectors.toList());
+
+ // 收集所有二级分类ID,一次性查询物种,避免 N+1
+ List level2Ids = dictTree.stream()
+ .filter(n -> n != null && n.getParentId() != null) // 非根即二级(在当前两级分类中)
+ .map(TwoDictTreeRespVO::getId)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+
+ // 批量查询所有二级分类下的物种,避免 N+1 查询
+ Map> categoryToSpeciesMap;
+ if (level2Ids.isEmpty()) {
+ categoryToSpeciesMap = java.util.Collections.emptyMap();
+ } else {
+ // 构建查询条件:查询所有二级分类下的物种
+ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
+ queryWrapper.in(SpeciesLibraryDO::getCategory, level2Ids.stream().map(String::valueOf).collect(Collectors.toList()));
+ queryWrapper.eq(SpeciesLibraryDO::getTenantId, String.valueOf(getLoginUser().getTenantId()));
+
+ List allSpecies = speciesLibraryMapper.selectList(queryWrapper);
+
+ // 按分类ID分组
+ categoryToSpeciesMap = allSpecies.stream()
+ .collect(Collectors.groupingBy(SpeciesLibraryDO::getCategory));
+ }
+
+ List result = new ArrayList<>();
+ for (TwoDictTreeRespVO lvl1 : level1Nodes) {
+ SpeciesThreeLevelTreeRespVO lvl1Vo = new SpeciesThreeLevelTreeRespVO();
+ lvl1Vo.setName(lvl1.getName());
+ lvl1Vo.setId(lvl1.getId().toString());
+ List lvl2Vos = new ArrayList<>();
+
+ if (lvl1.getChildren() != null && !lvl1.getChildren().isEmpty()) {
+ // 二级按名称排序
+ List lvl2Children = new ArrayList<>(lvl1.getChildren());
+ lvl2Children.sort(java.util.Comparator.comparing(TwoDictTreeRespVO::getName, java.util.Comparator.nullsLast(String::compareTo)));
+ for (TwoDictTreeRespVO lvl2 : lvl2Children) {
+ SpeciesThreeLevelTreeRespVO lvl2Vo = new SpeciesThreeLevelTreeRespVO();
+ lvl2Vo.setName(lvl2.getName());
+ lvl2Vo.setId(lvl2.getId().toString());
+ lvl2Vos.add(lvl2Vo);
+ }
+ }
+ lvl1Vo.setChildren(lvl2Vos);
+ result.add(lvl1Vo);
+ }
+ return result;
+ }
+
private String splitSpeciesName(String speciesName, int index) {
if (speciesName == null) {
return "";
diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/telemetry/DeviceTelemetryService.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/telemetry/DeviceTelemetryService.java
new file mode 100644
index 00000000..fdd310cf
--- /dev/null
+++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/telemetry/DeviceTelemetryService.java
@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.farm.service.telemetry;
+
+import cn.iocoder.yudao.module.farm.dal.dataobject.deviceinfo.DeviceInfoDO;
+import cn.iocoder.yudao.module.farm.dal.mongo.telemetry.DeviceTelemetryDoc;
+import cn.iocoder.yudao.module.farm.dal.mongo.telemetry.DeviceTelemetryRepository;
+import cn.iocoder.yudao.module.farm.dal.mysql.deviceinfo.DeviceInfoMapper;
+import org.springframework.stereotype.Service;
+
+import jakarta.annotation.Resource;
+
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser;
+
+@Service
+public class DeviceTelemetryService {
+
+ @Resource
+ private DeviceTelemetryRepository telemetryRepository;
+ @Resource
+ private DeviceInfoMapper deviceInfoMapper;
+
+ public void saveTelemetry(String deviceUniqueId, String payloadJson) {
+ String tenantId = String.valueOf(getLoginUser().getTenantId());
+
+ DeviceTelemetryDoc doc = new DeviceTelemetryDoc();
+ doc.setTenantId(tenantId);
+ doc.setDeviceId(deviceUniqueId);
+ doc.setTs(System.currentTimeMillis());
+ doc.setPayloadJson(payloadJson);
+ telemetryRepository.save(doc);
+
+ DeviceInfoDO device = deviceInfoMapper.selectOne(DeviceInfoDO::getDeviceUniqueId, deviceUniqueId);
+ if (device != null) {
+ device.setDataImage(payloadJson);
+ deviceInfoMapper.updateById(device);
+ }
+ }
+}
+
+
diff --git a/yudao-module-farm/src/main/resources/mapper/personnelmanagement/SystemUserRoleMapper.xml b/yudao-module-farm/src/main/resources/mapper/personnelmanagement/SystemUserRoleMapper.xml
new file mode 100644
index 00000000..15a4d650
--- /dev/null
+++ b/yudao-module-farm/src/main/resources/mapper/personnelmanagement/SystemUserRoleMapper.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/PersonnelMapper.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/PersonnelMapper.java
index e593e51c..65f728d7 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/PersonnelMapper.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/user/PersonnelMapper.java
@@ -7,4 +7,7 @@ import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface PersonnelMapper extends BaseMapperX {
+ default PersonnelDO selectByPhone(String mobile) {
+ return selectOne(PersonnelDO::getPhone, mobile);
+ }
}
diff --git a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java
index 638d3f6b..7299790c 100644
--- a/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java
+++ b/yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java
@@ -176,6 +176,27 @@ public class AdminUserServiceImpl implements AdminUserService {
// 2.1 更新用户
AdminUserDO updateObj = BeanUtils.toBean(updateReqVO, AdminUserDO.class);
userMapper.updateById(updateObj);
+ AdminUserDO adminUserDO = userMapper.selectById(updateObj.getId());
+ PersonnelDO userDo = personnelMapper.selectByPhone(adminUserDO.getMobile());
+ if (updateObj.getNickname() != null) userDo.setName(updateObj.getNickname());
+ if (updateObj.getMobile() != null) userDo.setPhone(updateObj.getMobile());
+ if (updateObj.getDeptId() != null) userDo.setDepartment(updateObj.getDeptId().toString());
+ if (updateObj.getTenantId() != null) userDo.setTenantId(updateObj.getTenantId().toString());
+ if (updateObj.getAvatar() != null) userDo.setPicture(updateObj.getAvatar());
+ userDo.setAccountStatus(0);
+ List userPostDOS = convertList(updateObj.getPostIds(),
+ postId -> new UserPostDO().setUserId(updateObj.getId()).setPostId(postId));
+ String roles = "";
+ for (UserPostDO up : userPostDOS) {
+ if (roles.length() > 0) {
+ roles += "," + up.getPostId();
+ } else {
+ roles = up.getPostId().toString();
+ }
+ }
+ userDo.setRole(roles);
+ personnelMapper.updateById(userDo);
+
// 2.2 更新岗位
updateUserPost(updateReqVO, updateObj);
@@ -262,7 +283,8 @@ public class AdminUserServiceImpl implements AdminUserService {
public void deleteUser(Long id) {
// 1. 校验用户存在
AdminUserDO user = validateUserExists(id);
-
+ AdminUserDO adminUserDO = userMapper.selectById(id);
+ personnelMapper.delete(PersonnelDO::getPhone, adminUserDO.getMobile());
// 2.1 删除用户
userMapper.deleteById(id);
// 2.2 删除用户关联数据
diff --git a/yudao-server/src/main/resources/application-dev.yaml b/yudao-server/src/main/resources/application-dev.yaml
index 131d3937..4a2e2a15 100644
--- a/yudao-server/src/main/resources/application-dev.yaml
+++ b/yudao-server/src/main/resources/application-dev.yaml
@@ -122,6 +122,7 @@ lock4j:
acquire-timeout: 3000 # 获取分布式锁超时时间,默认为 3000 毫秒
expire: 30000 # 分布式锁的超时时间,默认为 30 毫秒
+
--- #################### 监控相关配置 ####################
# Actuator 监控端点的配置项
diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml
index 3c0b3c88..765b0521 100644
--- a/yudao-server/src/main/resources/application.yaml
+++ b/yudao-server/src/main/resources/application.yaml
@@ -108,7 +108,7 @@ aj:
cache-number: 1000 # local 缓存的阈值,达到这个值,清除缓存
timing-clear: 180 # local定时清除过期缓存(单位秒),设置为0代表不执行
type: blockPuzzle # 验证码类型 default 三种都实例化。blockPuzzle 滑块拼图、clickWord 文字点选、pictureWord 文本输入
- water-mark: 芋道源码 # 右下角水印文字(我的水印),可使用 https://tool.chinaz.com/tools/unicode.aspx 中文转 Unicode,Linux 可能需要转 unicode
+ water-mark: 江西云戈 # 右下角水印文字(我的水印),可使用 https://tool.chinaz.com/tools/unicode.aspx 中文转 Unicode,Linux 可能需要转 unicode
interference-options: 0 # 滑动干扰项(0/1/2)
req-frequency-limit-enable: false # 接口请求次数一分钟限制是否开启 true|false
req-get-lock-limit: 5 # 验证失败 5 次,get接口锁定