Merge remote-tracking branch 'origin/dyf-app' into main_app权限适配

This commit is contained in:
2025-06-25 17:07:17 +08:00
31 changed files with 727 additions and 80 deletions

View File

@ -0,0 +1,93 @@
package com.fuyuanshen.modules.MiniProgram.controller;
import com.fuyuanshen.annotation.Log;
import com.fuyuanshen.annotation.rest.AnonymousPostMapping;
import com.fuyuanshen.modules.MiniProgram.service.MPService;
import com.fuyuanshen.modules.security.config.SecurityProperties;
import com.fuyuanshen.modules.security.security.TokenProvider;
import com.fuyuanshen.modules.security.service.OnlineUserService;
import com.fuyuanshen.modules.security.service.dto.AuthUserDto;
import com.fuyuanshen.modules.security.service.dto.AuthorityDto;
import com.fuyuanshen.modules.security.service.dto.JwtUserDto;
import com.fuyuanshen.modules.system.domain.User;
import com.fuyuanshen.modules.system.service.DeviceService;
import com.fuyuanshen.modules.utils.ResponseVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author: 默苍璃
* @date: 2025-06-2313:56
*/
@Slf4j
@RestController
@RequestMapping("/mp")
@RequiredArgsConstructor
@Api(tags = "小程序:相关接口")
public class MPController {
private final TokenProvider tokenProvider;
private final SecurityProperties properties;
private final OnlineUserService onlineUserService;
private final DeviceService deviceService;
private final MPService mpService;
@Log("小程序用户登录")
@ApiOperation("小程序登录授权")
@AnonymousPostMapping(value = "/login")
public ResponseEntity<Object> login(@RequestBody AuthUserDto authUser, HttpServletRequest request) throws Exception {
// 获取用户信息
User user = new User();
user.setUsername("MP");
user.setPassword("MP");
AuthorityDto authorityDto = new AuthorityDto();
authorityDto.setAuthority("MP");
List<AuthorityDto> authorityDtos = new ArrayList<>();
authorityDtos.add(authorityDto);
user.setPhone(authUser.getPhoneNumber());
JwtUserDto jwtUser = new JwtUserDto(null, user, null, authorityDtos);
Authentication authentication = new UsernamePasswordAuthenticationToken(jwtUser, null, authorityDtos);
SecurityContextHolder.getContext().setAuthentication(authentication);
// 生成令牌
String token = tokenProvider.createToken(jwtUser);
// 返回 token 与 用户信息
Map<String, Object> authInfo = new HashMap<String, Object>(2) {{
put("token", properties.getTokenStartWith() + token);
put("user", jwtUser);
}};
// 保存在线信息
onlineUserService.save(jwtUser, token, request);
// 返回登录信息
return ResponseEntity.ok(authInfo);
}
@GetMapping("/queryDevice")
@ApiOperation("是否存在设备MAC号")
public ResponseVO<Boolean> queryDevice(@ApiParam("设备mac值") String mac) {
return ResponseVO.success(mpService.queryDevice(mac));
}
}

View File

@ -0,0 +1,9 @@
package com.fuyuanshen.modules.MiniProgram.service;
/**
* @author: 默苍璃
* @date: 2025-06-2314:56
*/
public interface MPService {
Boolean queryDevice(String mac);
}

View File

@ -0,0 +1,43 @@
package com.fuyuanshen.modules.MiniProgram.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fuyuanshen.modules.MiniProgram.service.MPService;
import com.fuyuanshen.modules.system.domain.Device;
import com.fuyuanshen.modules.system.mapper.DeviceMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author: 默苍璃
* @date: 2025-06-2314:56
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class MPServiceImpl implements MPService {
private final DeviceMapper deviceMapper;
/**
* 查询设备MAC号
*
* @param mac
* @return
*/
@Override
public Boolean queryDevice(String mac) {
QueryWrapper<Device> wrapper = new QueryWrapper<>();
wrapper.eq("device_mac", mac);
List<Device> deviceList = deviceMapper.selectList(wrapper);
if (CollectionUtil.isNotEmpty(deviceList)) {
return true;
}
return false;
}
}

View File

@ -168,7 +168,6 @@ public class AuthController {
throw new BadRequestException("登录密码错误");
}
// 4. 加载用户详情
JwtUserDto jwtUser = userDetailsService.loadUserByAppUsername(appUser.getUsername());

View File

@ -30,6 +30,7 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.security.Key;

View File

@ -70,6 +70,7 @@ public class AppTokenProvider implements InitializingBean {
/**
* 创建Token 设置永不过期,
* Token 的时间有效性转到Redis 维护
*
* @param user /
* @return /
*/
@ -77,7 +78,7 @@ public class AppTokenProvider implements InitializingBean {
// 设置参数
Map<String, Object> claims = new HashMap<>(6);
// 设置用户ID
claims.put(AUTHORITIES_UID_KEY, user.getAppUser().getId());
claims.put(AUTHORITIES_UID_KEY, user.getAppUser().getId());
// if (user.getAppUser() != null){
// claims.put(AUTHORITIES_UID_KEY, user.getAppUser().getId());
// }else {
@ -94,6 +95,7 @@ public class AppTokenProvider implements InitializingBean {
/**
* APP创建Token 设置永不过期,
* Token 的时间有效性转到Redis 维护
*
* @param user /
* @return /
*/
@ -110,7 +112,7 @@ public class AppTokenProvider implements InitializingBean {
// }
// 设置UUID确保每次Token不一样
claims.put(AUTHORITIES_UUID_KEY, IdUtil.simpleUUID());
claims.put("userType","1");//0 系统登录 1 APP登录
claims.put("userType", "1");// 0 系统登录 1 APP登录
return jwtBuilder
.setClaims(claims)
.setSubject(user.getAppUser().getUsername())
@ -162,6 +164,7 @@ public class AppTokenProvider implements InitializingBean {
/**
* 获取登录用户RedisKey
*
* @param token /
* @return key
*/
@ -172,6 +175,7 @@ public class AppTokenProvider implements InitializingBean {
/**
* 获取会话编号
*
* @param token /
* @return /
*/

View File

@ -32,8 +32,8 @@ public class AuthUserDto {
@ApiModelProperty(value = "用户名")
private String username;
@ApiModelProperty(value = "手机号APP登录")
private String phoneNumber;
@ApiModelProperty(value = "手机号APP/小程序 登录)")
private Long phoneNumber;
@NotBlank
@ApiModelProperty(value = "密码")

View File

@ -0,0 +1,28 @@
package com.fuyuanshen.modules.system.constant;
/**
* 响应消息常量类
*
* @author: 默苍璃
* @date: 2025-06-2117:21
*/
public class ResponseMessageConstants {
/**
* 删除操作成功提示
*/
public static final String DELETE_SUCCESS = "删除成功!";
/**
* 新增操作成功提示
*/
public static final String SAVE_SUCCESS = "新增成功!";
/**
* 更新操作成功提示
*/
public static final String UPDATE_SUCCESS = "更新成功!";
// 可根据业务需求继续扩展其他常用提示信息
}

View File

@ -26,6 +26,10 @@ public class Device extends BaseEntity implements Serializable {
@ApiModelProperty(value = "ID")
private Long id;
@ApiModelProperty(value = "设备记录ID")
@TableField(exist = false)
private Long assignId;
@ApiModelProperty(value = "设备类型")
private Long deviceType;

View File

@ -26,7 +26,6 @@ public class APPDevice extends BaseEntity implements Serializable {
@ApiModelProperty(value = "ID")
private Long id;
@ApiModelProperty(value = "设备类型")
private Long deviceType;
@ -51,6 +50,9 @@ public class APPDevice extends BaseEntity implements Serializable {
@ApiModelProperty(value = "设备MAC")
private String deviceMac;
@ApiModelProperty(value = "设备IMEI")
private String deviceImei;
@ApiModelProperty(value = "设备SN")
private String deviceSn;
@ -90,6 +92,14 @@ public class APPDevice extends BaseEntity implements Serializable {
@ApiModelProperty(value = "绑定状态")
private Integer bindingStatus;
/**
* 绑定类型
* 0 APP
* 1 小程序
*/
@ApiModelProperty(value = "绑定类型")
private Integer bindingType;
public void copy(Device source) {
BeanUtil.copyProperties(source, this, CopyOptions.create().setIgnoreNullValue(true));

View File

@ -3,10 +3,13 @@ package com.fuyuanshen.modules.system.domain.app;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fuyuanshen.modules.system.domain.DeviceType;
import com.fuyuanshen.base.BaseEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import java.io.Serializable;
/**
* @Description: 设备类型
* @Author: WY
@ -14,11 +17,40 @@ import lombok.Data;
**/
@Data
@TableName("app_device_type")
public class APPDeviceType extends DeviceType {
public class APPDeviceType extends BaseEntity implements Serializable {
@TableId(value = "id", type = IdType.AUTO)
@ApiModelProperty(value = "ID", hidden = true)
private Long id;
@ApiModelProperty(value = "客户号")
private Long customerId;
@ApiModelProperty(value = "创建该类型的客户")
private Long ownerCustomerId;
/**
* 租户ID
*/
// @TableField(value = "tenant_id")
// @ApiModelProperty(hidden = true)
// private Long tenantId;
@NotBlank(message = "设备类型名称不能为空")
@ApiModelProperty(value = "类型名称", required = true)
private String typeName;
@ApiModelProperty(value = "是否支持蓝牙")
private Boolean isSupportBle;
@ApiModelProperty(value = "定位方式", example = "0:无;1:GPS;2:基站;3:wifi;4:北斗")
private String locateMode;
@ApiModelProperty(value = "联网方式", example = "0:无;1:4G;2:WIFI")
private String networkWay;
@ApiModelProperty(value = "通讯方式", example = "0:4G;1:蓝牙")
private String communicationMode;
}

View File

@ -46,9 +46,9 @@ public class DeviceExcelExportDTO {
@ColumnWidth(20)
private String deviceMac;
@ExcelProperty("设备SN")
@ExcelProperty("设备IMEI")
@ColumnWidth(20)
private String deviceSn;
private String deviceImei;
@ExcelProperty("经度")
private String longitude;

View File

@ -58,4 +58,7 @@ public class DeviceQueryCriteria {
@ApiModelProperty(value = "租户ID")
private Long tenantId;
@ApiModelProperty(value = "通讯方式", example = "0:4G;1:蓝牙")
private Integer communicationMode;
}

View File

@ -0,0 +1,45 @@
package com.fuyuanshen.modules.system.enums;
import com.fasterxml.jackson.annotation.JsonValue;
/**
* 通讯方式枚举
*
* @author: 默苍璃
* @date: 2025-06-2414:11
*/
public enum CommunicationModeEnum {
FOUR_G(0, "4G"),
BLUETOOTH(1, "蓝牙");
private final int value;
private final String label;
CommunicationModeEnum(int value, String label) {
this.value = value;
this.label = label;
}
@JsonValue
public int getValue() {
return value;
}
public String getLabel() {
return label;
}
/**
* 根据值获取标签
*/
public static String getLabelByValue(int value) {
for (CommunicationModeEnum mode : values()) {
if (mode.getValue() == value) {
return mode.getLabel();
}
}
return null;
}
}

View File

@ -3,6 +3,7 @@ package com.fuyuanshen.modules.system.listener.excel;
import com.fuyuanshen.modules.system.mapper.DeviceMapper;
import com.fuyuanshen.modules.system.mapper.DeviceTypeMapper;
import com.fuyuanshen.modules.system.mapper.UserMapper;
import com.fuyuanshen.modules.system.service.DeviceAssignmentsService;
import com.fuyuanshen.modules.system.service.DeviceService;
import lombok.*;
import org.springframework.web.multipart.MultipartFile;
@ -19,6 +20,7 @@ import org.springframework.web.multipart.MultipartFile;
public class DeviceImportParams {
private DeviceService deviceService;
private DeviceAssignmentsService deviceAssignmentsService;
private DeviceMapper deviceMapper;
private UserMapper userMapper;
private DeviceTypeMapper deviceTypeMapper;

View File

@ -7,9 +7,13 @@ import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fuyuanshen.modules.system.domain.DeviceAssignments;
import com.fuyuanshen.modules.system.domain.DeviceType;
import com.fuyuanshen.modules.system.domain.User;
import com.fuyuanshen.modules.system.domain.dto.DeviceQueryCriteria;
import com.fuyuanshen.modules.system.enums.DeviceActiveStatusEnum;
import com.fuyuanshen.modules.system.mapper.UserMapper;
import com.fuyuanshen.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import com.fuyuanshen.constants.DeviceConstants;
import com.fuyuanshen.modules.system.domain.Device;
@ -24,6 +28,7 @@ import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.nio.file.Files;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -149,6 +154,7 @@ public class UploadDeviceDataListener implements ReadListener<DeviceExcelImportD
private void processDataRowByRow() {
User currentUser = params.getUserMapper().findByUsername(SecurityUtils.getCurrentUsername());
for (Integer rowIndex : rowIndexList) {
Device device = rowDeviceMap.get(rowIndex);
DeviceExcelImportDTO originalDto = rowDtoMap.get(rowIndex);
@ -171,6 +177,20 @@ public class UploadDeviceDataListener implements ReadListener<DeviceExcelImportD
device.setDeviceType(deviceTypes.get(0).getId());
}
params.getDeviceService().save(device);
// 新增设备类型记录
DeviceAssignments assignments = new DeviceAssignments();
assignments.setDeviceId(device.getId());
assignments.setAssignedAt(LocalDateTime.now());
// 分配者
assignments.setAssignerId(currentUser.getId());
// 接收者
assignments.setAssigneeId(currentUser.getId());
assignments.setActive(DeviceActiveStatusEnum.ACTIVE.getCode());
String lever = currentUser.getId() + ":";
assignments.setLever(lever);
params.getDeviceAssignmentsService().save(assignments);
successCount++;
log.info("行 {} 数据插入成功", rowIndex);
} catch (Exception e) {

View File

@ -19,6 +19,15 @@ import java.util.List;
@Mapper
public interface APPDeviceMapper extends BaseMapper<APPDevice> {
/**
* APP用户设备列表
*
* @param page
* @param criteria
* @return
*/
IPage<APPDevice> appDeviceList(Page<APPDevice> page,@Param("criteria") DeviceQueryCriteria criteria);
/**
* 分页查询APP/小程序设备
@ -27,6 +36,7 @@ public interface APPDeviceMapper extends BaseMapper<APPDevice> {
* @param page
* @return
*/
IPage<APPDevice> queryAll(Page<APPDevice> page, @Param("criteria")DeviceQueryCriteria criteria );
IPage<APPDevice> queryAll(Page<APPDevice> page, @Param("criteria") DeviceQueryCriteria criteria);
}

View File

@ -0,0 +1,28 @@
package com.fuyuanshen.modules.system.mapper.app;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.fuyuanshen.modules.system.domain.app.APPDeviceType;
import com.fuyuanshen.modules.system.domain.dto.DeviceQueryCriteria;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* @author 97433
* @description 针对表【app_device_type(设备类型表)】的数据库操作Mapper
* @createDate 2025-06-24 11:16:18
* @Entity system.domain.AppDeviceType
*/
@Mapper
public interface AppDeviceTypeMapper extends BaseMapper<APPDeviceType> {
/**
* 查询设备类型列表
*
* @param criteria 查询条件
* @return 设备类型列表
*/
List<APPDeviceType> appTypeList(DeviceQueryCriteria criteria);
}

View File

@ -2,35 +2,35 @@ package com.fuyuanshen.modules.system.rest;
import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fuyuanshen.annotation.Log;
import com.fuyuanshen.exception.BadRequestException;
import com.fuyuanshen.modules.system.constant.ResponseMessageConstants;
import com.fuyuanshen.modules.system.constant.UserConstants;
import com.fuyuanshen.modules.system.domain.Device;
import com.fuyuanshen.modules.system.domain.User;
import com.fuyuanshen.modules.system.domain.dto.CustomerVo;
import com.fuyuanshen.modules.system.domain.dto.DeviceExcelImportDTO;
import com.fuyuanshen.modules.system.domain.dto.DeviceForm;
import com.fuyuanshen.modules.system.domain.dto.DeviceQueryCriteria;
import com.fuyuanshen.modules.system.listener.excel.DeviceImportParams;
import com.fuyuanshen.modules.system.listener.excel.UploadDeviceDataListener;
import com.fuyuanshen.modules.system.mapper.DeviceMapper;
import com.fuyuanshen.modules.system.mapper.DeviceTypeMapper;
import com.fuyuanshen.modules.system.mapper.UserMapper;
import com.fuyuanshen.modules.system.service.DeviceAssignmentsService;
import com.fuyuanshen.modules.system.service.DeviceService;
import com.fuyuanshen.modules.system.service.UserService;
import com.fuyuanshen.modules.system.service.impl.app.APPUserServiceImpl;
import com.fuyuanshen.modules.system.service.impl.DeviceExportService;
import com.fuyuanshen.modules.utils.ResponseVO;
import com.fuyuanshen.modules.utils.excel.ImportResult;
import com.fuyuanshen.utils.FileUtil;
import com.fuyuanshen.utils.PageResult;
import com.fuyuanshen.utils.SecurityUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import com.fuyuanshen.annotation.Log;
import com.fuyuanshen.domain.LocalStorage;
import com.fuyuanshen.exception.BadRequestException;
import com.fuyuanshen.modules.system.domain.Device;
import com.fuyuanshen.modules.system.domain.dto.CustomerVo;
import com.fuyuanshen.modules.system.domain.dto.DeviceExcelImportDTO;
import com.fuyuanshen.modules.system.domain.dto.DeviceForm;
import com.fuyuanshen.modules.system.domain.dto.DeviceQueryCriteria;
import com.fuyuanshen.modules.system.listener.excel.UploadDeviceDataListener;
import com.fuyuanshen.modules.system.service.DeviceService;
import com.fuyuanshen.modules.system.service.impl.DeviceExportService;
import com.fuyuanshen.modules.utils.ResponseVO;
import com.fuyuanshen.modules.utils.excel.ImportResult;
import com.fuyuanshen.utils.FileUtil;
import com.fuyuanshen.utils.PageResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
@ -50,7 +50,6 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.List;
import java.util.Map;
/**
* @Description:
@ -65,6 +64,7 @@ import java.util.Map;
public class DeviceController {
private final DeviceService deviceService;
private final DeviceAssignmentsService deviceAssignmentsService;
private final DeviceExportService exportService;
private final UserMapper userMapper;
private final DeviceMapper deviceMapper;
@ -158,13 +158,9 @@ public class DeviceController {
@ApiOperation("删除设备")
@DeleteMapping(value = "/delete")
public ResponseVO<Object> deleteDevice(@ApiParam(value = "传ID数组[]") @RequestBody List<Long> ids) {
try {
deviceService.deleteAll(ids);
} catch (Exception e) {
log.error("deleteDevice error: " + e.getMessage());
return ResponseVO.fail(e.getMessage());
}
return ResponseVO.success(null);
// deviceService.deleteAll(ids);
deviceService.deleteAssign(ids);
return ResponseVO.success(ResponseMessageConstants.DELETE_SUCCESS);
}
@ -176,7 +172,8 @@ public class DeviceController {
// 只能看到自己的创建的设备,以及被分配的设备。
if (onlineuser.getTenantId() != null && !onlineuser.getTenantId().equals(UserConstants.SUPER_ADMIN_ID)) {
criteria.setTenantId(onlineuser.getTenantId());
// criteria.setTenantId(onlineuser.getTenantId());
criteria.setCurrentOwnerId(onlineuser.getId());
}
exportService.export(deviceService.queryAll(criteria), response);
}
@ -210,7 +207,7 @@ public class DeviceController {
ImportResult result = new ImportResult();
try {
User currentUser = userMapper.findByUsername(SecurityUtils.getCurrentUsername());
DeviceImportParams params = DeviceImportParams.builder().ip(ip).deviceService(deviceService).tenantId(currentUser.getTenantId()).file(file).filePath(filePath).deviceMapper(deviceMapper).deviceTypeMapper(deviceTypeMapper).userId(currentUser.getId()).build();
DeviceImportParams params = DeviceImportParams.builder().ip(ip).deviceService(deviceService).tenantId(currentUser.getTenantId()).file(file).filePath(filePath).deviceMapper(deviceMapper).deviceAssignmentsService(deviceAssignmentsService).deviceTypeMapper(deviceTypeMapper).userId(currentUser.getId()).userMapper(userMapper).build();
// 创建监听器
UploadDeviceDataListener listener = new UploadDeviceDataListener(params);
// 读取Excel
@ -236,7 +233,6 @@ public class DeviceController {
try {
// 解码Base64字符串
byte[] data = Base64.getDecoder().decode(errorData);
return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"import_errors.xlsx\"").contentType(MediaType.APPLICATION_OCTET_STREAM).body(data);
} catch (Exception e) {
log.error("下载错误报告失败", e);

View File

@ -8,6 +8,7 @@ import com.fuyuanshen.modules.system.constant.UserConstants;
import com.fuyuanshen.modules.system.domain.Device;
import com.fuyuanshen.modules.system.domain.User;
import com.fuyuanshen.modules.system.domain.app.APPDevice;
import com.fuyuanshen.modules.system.domain.app.APPDeviceType;
import com.fuyuanshen.modules.system.domain.dto.CustomerVo;
import com.fuyuanshen.modules.system.domain.dto.DeviceExcelImportDTO;
import com.fuyuanshen.modules.system.domain.dto.DeviceForm;
@ -67,8 +68,39 @@ public class APPDeviceController {
private final APPDeviceService appDeviceService;
@PostMapping(value = "/list")
@ApiOperation("APP用户设备列表")
public ResponseVO<PageResult<APPDevice>> appDeviceList(@RequestBody DeviceQueryCriteria criteria) {
Page<APPDevice> page = new Page<>(criteria.getPage(), criteria.getSize());
PageResult<APPDevice> devices = null;
try {
devices = appDeviceService.appDeviceList(page, criteria);
} catch (Exception e) {
log.error("queryDevice error: " + e.getMessage());
return ResponseVO.fail("");
}
return ResponseVO.success(devices);
}
@PostMapping(value = "/typeList")
@ApiOperation("APP用户设备类型列表")
public ResponseVO<List<APPDeviceType>> appTypeList(@RequestBody DeviceQueryCriteria criteria) {
List<APPDeviceType> typeList = appDeviceService.appTypeList(criteria);
return ResponseVO.success(typeList);
}
@PostMapping(value = "/bind")
@ApiOperation("APP用户设备绑定")
public ResponseVO<String> appBindDevice(@RequestBody DeviceQueryCriteria criteria) {
appDeviceService.appBindDevice(criteria);
return ResponseVO.success("绑定成功!");
}
@GetMapping
@ApiOperation("查看APP用户设备绑定")
@ApiOperation("WEB端查看APP用户设备绑定")
public ResponseVO<PageResult<APPDevice>> queryAPPDevice(DeviceQueryCriteria criteria) {
Page<APPDevice> page = new Page<>(criteria.getPage(), criteria.getSize());
PageResult<APPDevice> devices = null;
@ -83,7 +115,7 @@ public class APPDeviceController {
@PostMapping(value = "/unbind")
@ApiOperation("APP用户设备解绑")
@ApiOperation("WEB端APP用户设备解绑")
public ResponseVO<String> unbindAPPDevice(@Validated @ModelAttribute APPUnbindDTO deviceForm) {
appDeviceService.unbindAPPDevice(deviceForm);
return ResponseVO.success("解绑成功!!!");

View File

@ -80,6 +80,13 @@ public interface DeviceService extends IService<Device> {
*/
void deleteAll(List<Long> ids);
/**
* 删除设备分配记录
*
* @param ids
*/
void deleteAssign(List<Long> ids);
/**
* 导出数据
*
@ -103,4 +110,5 @@ public interface DeviceService extends IService<Device> {
*/
void unbindDevice(DeviceForm deviceForm);
}

View File

@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.fuyuanshen.modules.system.domain.Device;
import com.fuyuanshen.modules.system.domain.app.APPDevice;
import com.fuyuanshen.modules.system.domain.app.APPDeviceType;
import com.fuyuanshen.modules.system.domain.dto.CustomerVo;
import com.fuyuanshen.modules.system.domain.dto.DeviceForm;
import com.fuyuanshen.modules.system.domain.dto.DeviceQueryCriteria;
@ -22,6 +23,29 @@ import java.util.List;
**/
public interface APPDeviceService extends IService<APPDevice> {
/**
* APP用户设备列表
*
* @param criteria
*/
PageResult<APPDevice> appDeviceList(Page<APPDevice> page, DeviceQueryCriteria criteria);
/**
* APP用户设备类型列表
*
* @param criteria
* @return
*/
List<APPDeviceType> appTypeList(DeviceQueryCriteria criteria);
/**
* APP/小程序用户设备绑定
*
* @param criteria
*/
void appBindDevice(DeviceQueryCriteria criteria);
/**
* 分页查询APP/小程序设备绑定
*
@ -38,4 +62,5 @@ public interface APPDeviceService extends IService<APPDevice> {
*/
void unbindAPPDevice(APPUnbindDTO deviceForm);
}

View File

@ -2,48 +2,35 @@ package com.fuyuanshen.modules.system.service.app;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fuyuanshen.constants.DeviceConstants;
import com.fuyuanshen.constants.ExceptionMessages;
import com.fuyuanshen.exception.BadRequestException;
import com.fuyuanshen.modules.security.service.UserCacheManager;
import com.fuyuanshen.modules.system.constant.UserConstants;
import com.fuyuanshen.modules.system.domain.Device;
import com.fuyuanshen.modules.system.domain.DeviceType;
import com.fuyuanshen.modules.system.domain.User;
import com.fuyuanshen.modules.system.domain.app.APPDevice;
import com.fuyuanshen.modules.system.domain.dto.CustomerVo;
import com.fuyuanshen.modules.system.domain.dto.DeviceForm;
import com.fuyuanshen.modules.system.domain.app.APPDeviceType;
import com.fuyuanshen.modules.system.domain.dto.DeviceQueryCriteria;
import com.fuyuanshen.modules.system.domain.dto.app.APPUnbindDTO;
import com.fuyuanshen.modules.system.enums.BindingStatusEnum;
import com.fuyuanshen.modules.system.enums.CommunicationModeEnum;
import com.fuyuanshen.modules.system.enums.UserType;
import com.fuyuanshen.modules.system.mapper.DeviceMapper;
import com.fuyuanshen.modules.system.mapper.DeviceTypeMapper;
import com.fuyuanshen.modules.system.mapper.UserMapper;
import com.fuyuanshen.modules.system.mapper.app.APPDeviceMapper;
import com.fuyuanshen.modules.system.service.DeviceService;
import com.fuyuanshen.modules.system.service.UserService;
import com.fuyuanshen.modules.system.service.impl.DeviceTypeServiceImpl;
import com.fuyuanshen.modules.utils.NanoId;
import com.fuyuanshen.utils.*;
import com.fuyuanshen.modules.system.mapper.app.AppDeviceTypeMapper;
import com.fuyuanshen.utils.PageResult;
import com.fuyuanshen.utils.SecurityUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.sql.Timestamp;
import java.util.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
/**
@ -58,6 +45,89 @@ public class APPDeviceServiceImpl extends ServiceImpl<APPDeviceMapper, APPDevice
private final APPDeviceMapper appDeviceMapper;
private final DeviceMapper deviceMapper;
private final DeviceTypeMapper deviceTypeMapper;
private final AppDeviceTypeMapper appDeviceTypeMapper;
/**
* APP用户设备列表
*
* @param criteria
*/
@Override
public PageResult<APPDevice> appDeviceList(Page<APPDevice> page, DeviceQueryCriteria criteria) {
IPage<APPDevice> devices = appDeviceMapper.appDeviceList(page, criteria);
return new PageResult<>(devices.getRecords(), devices.getTotal());
}
/**
* APP用户设备类型列表
*
* @param criteria
* @return
*/
@Override
public List<APPDeviceType> appTypeList(DeviceQueryCriteria criteria) {
return appDeviceTypeMapper.appTypeList(criteria);
}
/**
* APP/小程序用户设备绑定
*
* @param criteria
*/
@Override
@Transactional
public void appBindDevice(DeviceQueryCriteria criteria) {
List<Device> devices = new ArrayList<>();
if (criteria.getCommunicationMode().equals(CommunicationModeEnum.BLUETOOTH.getValue())) {
devices = deviceMapper.selectList(new QueryWrapper<Device>().eq("device_mac", criteria.getDeviceMac()));
if (CollectionUtil.isEmpty(devices)) {
throw new BadRequestException("请先将设备入库!!!");
}
List<APPDevice> appDevices = appDeviceMapper.selectList(new QueryWrapper<APPDevice>()
.eq("device_mac", criteria.getDeviceMac()).eq("binding_type", UserType.APP.getValue()));
if (CollectionUtil.isNotEmpty(appDevices)) {
throw new BadRequestException("该设备已绑定!!!");
}
}
if (criteria.getCommunicationMode().equals(CommunicationModeEnum.FOUR_G.getValue())) {
devices = deviceMapper.selectList(new QueryWrapper<Device>().eq("device_imei", criteria.getDeviceImei()));
if (CollectionUtil.isEmpty(devices)) {
throw new BadRequestException("请先将设备入库!!!");
}
List<APPDevice> appDevices = appDeviceMapper.selectList(new QueryWrapper<APPDevice>()
.eq("device_imei", criteria.getDeviceImei()).eq("binding_type", UserType.APP.getValue()));
if (CollectionUtil.isNotEmpty(appDevices)) {
throw new BadRequestException("该设备已绑定!!!");
}
}
Device device = devices.get(0);
APPDevice appDevice = new APPDevice();
BeanUtil.copyProperties(device, appDevice);
appDevice.setBindingType(UserType.APP.getValue());
appDevice.setBindingStatus(BindingStatusEnum.BOUND.getCode());
Long currentUserId = SecurityUtils.getCurrentUserId();
appDevice.setCustomerId(currentUserId);
appDevice.setCreateTime(new Timestamp(System.currentTimeMillis()));
// 设备类型名称
appDevice.setDeviceTypeName(device.getTypeName());
appDeviceMapper.insert(appDevice);
APPDeviceType appDeviceType = appDeviceTypeMapper.selectById(device.getDeviceType());
if (appDeviceType == null) {
DeviceType deviceType = deviceTypeMapper.selectById(device.getDeviceType());
APPDeviceType type = new APPDeviceType();
BeanUtil.copyProperties(deviceType, type);
appDeviceTypeMapper.insert(type);
}
}
/**
@ -83,11 +153,17 @@ public class APPDeviceServiceImpl extends ServiceImpl<APPDeviceMapper, APPDevice
@Transactional
public void unbindAPPDevice(APPUnbindDTO deviceForm) {
appDeviceMapper.delete(new QueryWrapper<APPDevice>().eq("device_mac", deviceForm.getDeviceMac()));
appDeviceMapper.delete(new QueryWrapper<APPDevice>().eq("device_mac", deviceForm.getDeviceMac()).eq("binding_type", UserType.APP.getValue()));
List<Device> devices = deviceMapper.selectList(new QueryWrapper<Device>().eq("device_mac", deviceForm.getDeviceMac()));
List<Long> ids = devices.stream()
.map(Device::getId)
.collect(Collectors.toList());
appDeviceTypeMapper.deleteBatchIds(ids);
Device device = new Device();
device.setId(deviceForm.getCustomerId());
device.setBindingStatus(BindingStatusEnum.UNBOUND.getCode());
deviceMapper.updateById(device);
}
}

View File

@ -0,0 +1,13 @@
package com.fuyuanshen.modules.system.service.app;
import com.baomidou.mybatisplus.extension.service.IService;
import com.fuyuanshen.modules.system.domain.app.APPDeviceType;
/**
* @author 97433
* @description 针对表【app_device_type(设备类型表)】的数据库操作Service
* @createDate 2025-06-24 11:16:18
*/
public interface AppDeviceTypeService extends IService<APPDeviceType> {
}

View File

@ -41,7 +41,8 @@ public class DeviceExportService {
dto.setCustomerName(device.getCustomerName());
dto.setDeviceName(device.getDeviceName());
dto.setDeviceMac(device.getDeviceMac());
dto.setDeviceSn(device.getDeviceSn());
// 设备IMEI
dto.setDeviceImei(device.getDeviceImei());
dto.setLongitude(device.getLongitude());
dto.setLatitude(device.getLatitude());
dto.setRemark(device.getRemark());

View File

@ -2,11 +2,9 @@ package com.fuyuanshen.modules.system.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fuyuanshen.constants.DeviceConstants;
@ -194,6 +192,8 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
// device.setId(snowflakeGenerator.next());
device.setCurrentOwnerId(currentUser.getId());
device.setOriginalOwnerId(currentUser.getId());
DeviceType deviceType = deviceTypeMapper.selectById(deviceForm.getDeviceType());
device.setTypeName(deviceType.getTypeName());
deviceMapper.insert(device);
@ -203,6 +203,7 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
assignments.setAssignedAt(LocalDateTime.now());
// 分配者
assignments.setAssignerId(currentUser.getId());
assignments.setAssignerName(currentUser.getUsername());
// 接收者
assignments.setAssigneeId(currentUser.getId());
assignments.setActive(DeviceActiveStatusEnum.ACTIVE.getCode());
@ -484,18 +485,17 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
@Transactional(rollbackFor = Exception.class)
public void deleteAll(List<Long> ids) {
SecurityUtils.getCurrentUserId();
// Step 1: 查询所有传入的设备(根据 ID
List<Device> allDevices = deviceMapper.selectBatchIds(ids);
// Step 2: 使用 Java Stream 过滤出 customer_id 不为 null 的设备
Set<Long> nonNullCustomerIds = allDevices.stream().filter(device -> device.getCustomerId() != null && device.getDeviceStatus() == 1).map(Device::getId).collect(Collectors.toSet());
// Step 3: 从原始 ids 中“去掉”这些非空 customer_id 的设备 ID
List<Long> remainingIds = ids.stream().filter(id -> !nonNullCustomerIds.contains(id)).collect(Collectors.toList());
if (CollectionUtil.isEmpty(remainingIds)) {
throw new BadRequestException("已分配的设备不允许删除!!!");
}
List<Device> devices = deviceMapper.selectBatchIds(remainingIds);
for (Device device : devices) {
String devicePic = device.getDevicePic();
@ -514,6 +514,58 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
deviceMapper.deleteBatchIds(ids);
}
/**
* 删除设备分配记录分配记录id
*
* @param ids
*/
public void deleteAssign1(List<Long> ids) {
Long currentUserId = SecurityUtils.getCurrentUserId();
// Step 1: 查询所有传入的设备(根据 ID
// List<DeviceAssignments> deviceAssignments = deviceAssignmentsMapper.selectBatchIds(ids);
QueryWrapper<DeviceAssignments> wrapper = new QueryWrapper<>();
// wrapper.eq("active", DeviceActiveStatusEnum.INACTIVE.getCode());
wrapper.in("device_id", ids);
wrapper.eq("assigner_id", currentUserId);
List<DeviceAssignments> deviceAssignments = deviceAssignmentsMapper.selectList(wrapper);
// Step 2: 使用 Java Stream 过滤出 customer_id 不为 null 的设备
Set<Long> nonNullCustomerIds = deviceAssignments.stream().filter(device -> !StringUtils.isNotEmpty(device.getAssigneeName())).map(DeviceAssignments::getId).collect(Collectors.toSet());
if (CollectionUtil.isEmpty(nonNullCustomerIds)) {
throw new BadRequestException("已分配的设备不允许删除!!!");
}
// QueryWrapper<DeviceAssignments> de = new QueryWrapper<>();
// wrapper.eq("active", DeviceActiveStatusEnum.INACTIVE.getCode());
// wrapper.in("device_id", ids);
// wrapper.eq("assignee_id", currentUserId);
// deviceAssignmentsMapper.delete(de);
deviceAssignmentsMapper.deleteBatchIds(nonNullCustomerIds);
}
/**
* 删除设备分配记录分配记录id
*
* @param ids
*/
@Override
public void deleteAssign(List<Long> ids) {
// Step 1: 查询所有传入的设备(根据 ID
List<DeviceAssignments> deviceAssignments = deviceAssignmentsMapper.selectBatchIds(ids);
// Step 2: 使用 Java Stream 过滤出 customer_id 不为 null 的设备
Set<Long> nonNullCustomerIds = deviceAssignments.stream()
.filter(device -> !StringUtils.isNotEmpty(device.getAssigneeName()))
.map(DeviceAssignments::getId).collect(Collectors.toSet());
if (CollectionUtil.isEmpty(nonNullCustomerIds)) {
throw new BadRequestException("已分配的设备不允许删除!!!");
}
deviceAssignmentsMapper.deleteBatchIds(ids);
}
@Override
public void download(List<Device> all, HttpServletResponse response) throws IOException {
List<Map<String, Object>> list = new ArrayList<>();

View File

@ -0,0 +1,18 @@
package com.fuyuanshen.modules.system.service.impl.app;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fuyuanshen.modules.system.domain.app.APPDeviceType;
import com.fuyuanshen.modules.system.mapper.app.AppDeviceTypeMapper;
import com.fuyuanshen.modules.system.service.app.AppDeviceTypeService;
import org.springframework.stereotype.Service;
/**
* @author 97433
* @description 针对表【app_device_type(设备类型表)】的数据库操作Service实现
* @createDate 2025-06-24 11:16:18
*/
@Service
public class AppDeviceTypeServiceImpl extends ServiceImpl<AppDeviceTypeMapper, APPDeviceType>
implements AppDeviceTypeService {
}

View File

@ -19,17 +19,20 @@
<result column="binding_status" property="bindingStatus"/>
</resultMap>
<!-- 分页查询APP/小程序设备 -->
<select id="queryAll" resultType="com.fuyuanshen.modules.system.domain.app.APPDevice">
<!-- APP用户设备列表 -->
<select id="appDeviceList" resultType="com.fuyuanshen.modules.system.domain.app.APPDevice">
select d.* from app_device as d
<where>
<!-- 时间范围等其他条件保持原样 -->
<if test="criteria.deviceName != null and criteria.deviceName.trim() != ''">
and d.device_name like concat('%', TRIM(#{criteria.deviceName}), '%')
</if>
<if test="criteria.deviceMac != null and criteria.deviceName.trim() != ''">
<if test="criteria.deviceMac != null and criteria.deviceMac.trim() != ''">
and d.device_mac = #{criteria.deviceMac}
</if>
<if test="criteria.deviceImei != null and criteria.deviceImei.trim() != ''">
and d.device_imei = #{criteria.deviceImei}
</if>
<if test="criteria.deviceSn != null">
and d.device_sn = #{criteria.deviceSn}
</if>
@ -42,13 +45,47 @@
<if test="criteria.createTime != null and criteria.createTime.size() != 0">
and d.create_time between #{criteria.createTime[0]} and #{criteria.createTime[1]}
</if>
<if test="criteria.tenantId != null">
AND tenant_id = #{criteria.tenantId}
</if>
and d.customer_id = #{criteria.customerId}
</where>
order by d.app_device_id desc
order by d.create_time desc
</select>
<!-- 分页查询APP/小程序设备 -->
<select id="queryAll" resultType="com.fuyuanshen.modules.system.domain.app.APPDevice">
select d.* from app_device as d
<where>
<!-- 时间范围等其他条件保持原样 -->
<if test="criteria.deviceName != null and criteria.deviceName.trim() != ''">
and d.device_name like concat('%', TRIM(#{criteria.deviceName}), '%')
</if>
<if test="criteria.deviceMac != null and criteria.deviceMac.trim() != ''">
and d.device_mac = #{criteria.deviceMac}
</if>
<if test="criteria.deviceImei != null and criteria.deviceImei.trim() != ''">
and d.device_imei = #{criteria.deviceImei}
</if>
<if test="criteria.deviceSn != null">
and d.device_sn = #{criteria.deviceSn}
</if>
<if test="criteria.deviceType != null">
and d.device_type = #{criteria.deviceType}
</if>
<if test="criteria.deviceStatus != null">
and d.device_status = #{criteria.deviceStatus}
</if>
<if test="criteria.createTime != null and criteria.createTime.size() != 0">
and d.create_time between #{criteria.createTime[0]} and #{criteria.createTime[1]}
</if>
<if test="criteria.tenantId != null">
AND tenant_id = #{criteria.tenantId}
</if>
and d.customer_id = #{criteria.customerId}
</where>
order by d.create_time desc
</select>
</mapper>

View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.fuyuanshen.modules.system.mapper.app.AppDeviceTypeMapper">
<resultMap id="BaseResultMap" type="com.fuyuanshen.modules.system.domain.app.APPDeviceType">
<id property="id" column="id"/>
<result property="typeName" column="type_name"/>
<result property="isSupportBle" column="is_support_ble"/>
<result property="locateMode" column="locate_mode"/>
<result property="networkWay" column="network_way"/>
<result property="createBy" column="create_by"/>
<result property="updateBy" column="update_by"/>
<result property="createTime" column="create_time"/>
<result property="updateTime" column="update_time"/>
<result property="customerId" column="customer_id"/>
<result property="communicationMode" column="communication_mode"/>
</resultMap>
<sql id="Base_Column_List">
id,type_name,is_support_ble,locate_mode,network_way,create_by,
update_by,create_time,update_time,customer_id,communication_mode
</sql>
<!-- 查询设备类型列表 -->
<select id="appTypeList" resultType="com.fuyuanshen.modules.system.domain.app.APPDeviceType">
select d.* from app_device_type as d
<where>
<!-- 时间范围等其他条件保持原样 -->
<if test="criteria.deviceName != null and criteria.deviceName.trim() != ''">
and d.device_name like concat('%', TRIM(#{criteria.deviceName}), '%')
</if>
<if test="criteria.deviceMac != null and criteria.deviceMac.trim() != ''">
and d.device_mac = #{criteria.deviceMac}
</if>
<if test="criteria.deviceImei != null and criteria.deviceImei.trim() != ''">
and d.device_imei = #{criteria.deviceImei}
</if>
<if test="criteria.deviceSn != null">
and d.device_sn = #{criteria.deviceSn}
</if>
<if test="criteria.deviceType != null">
and d.device_type = #{criteria.deviceType}
</if>
<if test="criteria.deviceStatus != null">
and d.device_status = #{criteria.deviceStatus}
</if>
<if test="criteria.createTime != null and criteria.createTime.size() != 0">
and d.create_time between #{criteria.createTime[0]} and #{criteria.createTime[1]}
</if>
<if test="criteria.tenantId != null">
AND tenant_id = #{criteria.tenantId}
</if>
and d.customer_id = #{criteria.customerId}
</where>
order by d.create_time desc
</select>
</mapper>

View File

@ -43,7 +43,7 @@
d.device_pic, d.device_mac, d.device_sn, d.update_by,d.device_imei,
d.update_time, d.device_type, d.remark, d.binding_status,t.type_name,
da.assignee_id AS customerId, da.assignee_name AS customerName, da.active AS deviceStatus,
da.assigned_at AS create_time , da.assigner_name AS create_by
da.assigned_at AS create_time , da.assigner_name AS create_by , da.id AS assignId
from device d
LEFT JOIN device_type t ON d.device_type = t.id
LEFT JOIN device_assignments da ON da.device_id = d.id
@ -85,12 +85,11 @@
<!-- AND tenant_id = #{criteria.tenantId} -->
<!-- </if> -->
</where>
order by d.id desc
ORDER BY create_time DESC
</select>
<select id="findAll1" resultType="com.fuyuanshen.modules.system.domain.Device">
select
SELECT
d.id, d.customer_id, d.customer_name, d.device_name,
d.device_pic, d.device_mac, d.device_sn, d.create_by, d.update_by,
d.create_time, d.update_time, d.device_type, d.remark, d.device_status, t.type_name

View File

@ -44,8 +44,8 @@
<!-- 查询所有设备类型 -->
<select id="findAll" resultMap="BaseResultMap">
SELECT dt.*
FROM device_type dt
SELECT DISTINCT dt.*
FROM device_type dt
JOIN device_type_grants dg ON dt.id = dg.device_type_id
<where>
<if test="criteria.typeName != null and criteria.typeName.trim() != ''">