1
0

Merge remote-tracking branch 'upstream/main'

# Conflicts:
#	fys-modules/fys-app/src/main/resources/mapper/app/AppBusinessFileMapper.xml
This commit is contained in:
2025-07-17 17:03:25 +08:00
15 changed files with 380 additions and 120 deletions

View File

@ -14,12 +14,10 @@ import com.fuyuanshen.common.core.constant.SystemConstants;
import com.fuyuanshen.common.core.domain.model.AppLoginUser; import com.fuyuanshen.common.core.domain.model.AppLoginUser;
import com.fuyuanshen.common.core.domain.model.SmsLoginBody; import com.fuyuanshen.common.core.domain.model.SmsLoginBody;
import com.fuyuanshen.common.core.enums.LoginType; import com.fuyuanshen.common.core.enums.LoginType;
import com.fuyuanshen.common.core.enums.UserType;
import com.fuyuanshen.common.core.exception.user.CaptchaExpireException; import com.fuyuanshen.common.core.exception.user.CaptchaExpireException;
import com.fuyuanshen.common.core.exception.user.UserException; import com.fuyuanshen.common.core.exception.user.UserException;
import com.fuyuanshen.common.core.utils.MessageUtils; import com.fuyuanshen.common.core.utils.*;
import com.fuyuanshen.common.core.utils.ServletUtils;
import com.fuyuanshen.common.core.utils.StringUtils;
import com.fuyuanshen.common.core.utils.ValidatorUtils;
import com.fuyuanshen.common.json.utils.JsonUtils; import com.fuyuanshen.common.json.utils.JsonUtils;
import com.fuyuanshen.common.redis.utils.RedisUtils; import com.fuyuanshen.common.redis.utils.RedisUtils;
import com.fuyuanshen.common.satoken.utils.AppLoginHelper; import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
@ -60,9 +58,9 @@ public class AppSmsAuthStrategy implements IAuthStrategy {
AppUserVo user = loadUserByPhonenumber(phonenumber); AppUserVo user = loadUserByPhonenumber(phonenumber);
if (ObjectUtil.isNull(user)) { if (ObjectUtil.isNull(user)) {
//新增Appuser //新增Appuser
addAppUser(tenantId, phonenumber); AppUser appUser = addAppUser(tenantId, phonenumber);
MapstructUtils.convert(appUser, user);
user = appUserMapper.selectVoOne(new LambdaQueryWrapper<AppUser>().eq(AppUser::getPhonenumber, phonenumber)); // user = appUserMapper.selectVoOne(new LambdaQueryWrapper<AppUser>().eq(AppUser::getPhonenumber, phonenumber));
// loginService.recordLogininfor(tenantId, phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.not.exists", phonenumber)); // loginService.recordLogininfor(tenantId, phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.not.exists", phonenumber));
// throw new UserException("user.not.exists", phonenumber); // throw new UserException("user.not.exists", phonenumber);
} }
@ -89,7 +87,7 @@ public class AppSmsAuthStrategy implements IAuthStrategy {
return loginVo; return loginVo;
} }
private void addAppUser(String tenantId, String phonenumber) { private AppUser addAppUser(String tenantId, String phonenumber) {
AppUser appUser = new AppUser(); AppUser appUser = new AppUser();
appUser.setPhonenumber(phonenumber); appUser.setPhonenumber(phonenumber);
appUser.setUserName(phonenumber); appUser.setUserName(phonenumber);
@ -98,6 +96,7 @@ public class AppSmsAuthStrategy implements IAuthStrategy {
appUser.setLoginIp(ServletUtils.getClientIP()); appUser.setLoginIp(ServletUtils.getClientIP());
appUser.setTenantId(tenantId); appUser.setTenantId(tenantId);
appUserMapper.insert(appUser); appUserMapper.insert(appUser);
return appUser;
} }
@ -114,7 +113,9 @@ public class AppSmsAuthStrategy implements IAuthStrategy {
} }
private AppUserVo loadUserByPhonenumber(String phonenumber) { private AppUserVo loadUserByPhonenumber(String phonenumber) {
AppUserVo user = appUserMapper.selectVoOne(new LambdaQueryWrapper<AppUser>().eq(AppUser::getPhonenumber, phonenumber)); AppUserVo user = appUserMapper.selectVoOne(new LambdaQueryWrapper<AppUser>()
.eq(AppUser::getPhonenumber, phonenumber)
.eq(AppUser::getUserType, UserType.APP_USER.getUserType()));
if (ObjectUtil.isNull(user)) { if (ObjectUtil.isNull(user)) {
log.info("登录用户:{} 不存在.", phonenumber); log.info("登录用户:{} 不存在.", phonenumber);
// throw new UserException("user.not.exists", phonenumber); // throw new UserException("user.not.exists", phonenumber);
@ -126,5 +127,4 @@ public class AppSmsAuthStrategy implements IAuthStrategy {
} }
return user; return user;
} }
} }

View File

@ -37,7 +37,7 @@ public enum BusinessType {
EXPORT, EXPORT,
/** /**
* 导入 *
*/ */
IMPORT, IMPORT,

View File

@ -17,8 +17,8 @@ public class TestSMSController {
public void testSend() { public void testSend() {
// 在创建完SmsBlend实例后再未手动调用注销的情况下框架会持有该实例可以直接通过指定configId来获取想要的配置如果你想使用 // 在创建完SmsBlend实例后再未手动调用注销的情况下框架会持有该实例可以直接通过指定configId来获取想要的配置如果你想使用
// 负载均衡形式获取实例只要使用getSmsBlend的无参重载方法即可如果你仅有一个配置也可以使用该方法 // 负载均衡形式获取实例只要使用getSmsBlend的无参重载方法即可如果你仅有一个配置也可以使用该方法
SmsBlend smsBlend = SmsFactory.getSmsBlend("alibaba"); SmsBlend smsBlend = SmsFactory.getSmsBlend("config1");
SmsResponse smsResponse = smsBlend.sendMessage("18656573389", "123"); SmsResponse smsResponse = smsBlend.sendMessage("18656573389", "1234");
} }
} }

View File

@ -2,6 +2,7 @@ package com.fuyuanshen.app.controller;
import java.util.List; import java.util.List;
import com.fuyuanshen.common.core.enums.UserType;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*; import jakarta.validation.constraints.*;
@ -36,12 +37,14 @@ public class AppUserController extends BaseController {
private final IAppUserService appUserService; private final IAppUserService appUserService;
/** /**
* 查询APP用户信息列表 * 查询APP用户信息列表
*/ */
// @SaCheckPermission("app:user:list") // @SaCheckPermission("app:user:list")
@GetMapping("/list") @GetMapping("/list")
public TableDataInfo<AppUserVo> list(AppUserBo bo, PageQuery pageQuery) { public TableDataInfo<AppUserVo> list(AppUserBo bo, PageQuery pageQuery) {
bo.setUserType(UserType.APP_USER.getUserType());
return appUserService.queryPageList(bo, pageQuery); return appUserService.queryPageList(bo, pageQuery);
} }

View File

@ -1,6 +1,9 @@
package com.fuyuanshen.app.domain.vo; package com.fuyuanshen.app.domain.vo;
import java.util.Date; import java.util.Date;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.fuyuanshen.app.domain.AppUser; import com.fuyuanshen.app.domain.AppUser;
import cn.idev.excel.annotation.ExcelIgnoreUnannotated; import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
@ -120,4 +123,10 @@ public class AppUserVo implements Serializable {
* 部门ID * 部门ID
*/ */
private Long deptId; private Long deptId;
/**
* 创建时间
*/
private Date createTime;
} }

View File

@ -5,8 +5,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<mapper namespace="com.fuyuanshen.app.mapper.AppBusinessFileMapper"> <mapper namespace="com.fuyuanshen.app.mapper.AppBusinessFileMapper">
<select id="queryAppFileList" resultType="com.fuyuanshen.app.domain.vo.AppFileVo"> <select id="queryAppFileList" resultType="com.fuyuanshen.app.domain.vo.AppFileVo">
select a.id,a.business_id,a.file_id,b.file_name,b.url fileUrl,a.file_type from app_business_file a left join sys_oss b on a.file_id = b.oss_id select a.id,a.business_id,a.file_id,b.file_name,b.url fileUrl from app_business_file a left join sys_oss b on a.file_id = b.oss_id
where where 1=1
<if test="createBy != null"> <if test="createBy != null">
a.create_by = #{createBy} a.create_by = #{createBy}
</if> </if>
@ -19,6 +19,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="fileType != null"> <if test="fileType != null">
and a.file_type = #{fileType} and a.file_type = #{fileType}
</if> </if>
<if test="createBy != null">
and a.create_by = #{createBy}
</if>
order by a.create_time desc order by a.create_time desc
</select> </select>
</mapper> </mapper>

View File

@ -3,6 +3,7 @@ package com.fuyuanshen.customer.controller;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.crypto.digest.BCrypt; import cn.hutool.crypto.digest.BCrypt;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fuyuanshen.common.core.domain.R;
import com.fuyuanshen.common.core.domain.ResponseVO; import com.fuyuanshen.common.core.domain.ResponseVO;
import com.fuyuanshen.common.core.utils.StringUtils; import com.fuyuanshen.common.core.utils.StringUtils;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
@ -51,43 +52,43 @@ public class CustomerController {
@GetMapping(value = "/allCustomer") @GetMapping(value = "/allCustomer")
@Operation(summary = "查询所有客户") @Operation(summary = "查询所有客户")
public ResponseVO<List<Customer>> queryAllCustomer(UserQueryCriteria criteria) { public R<List<Customer>> queryAllCustomer(UserQueryCriteria criteria) {
List<Customer> customers = customerService.queryAllCustomers(criteria); List<Customer> customers = customerService.queryAllCustomers(criteria);
return ResponseVO.success(customers); return R.ok(customers);
} }
// @Log("新增客户") // @Log("新增客户")
@Operation(summary = "新增客户") @Operation(summary = "新增客户")
@PostMapping(value = "/addCustomer") @PostMapping(value = "/addCustomer")
public ResponseVO<Object> addCustomer(@Validated @RequestBody Customer customer) throws BadRequestException { public R<Void> addCustomer(@Validated @RequestBody Customer customer) throws BadRequestException {
if (StringUtils.isBlank(customer.getPassword())) { if (StringUtils.isBlank(customer.getPassword())) {
throw new BadRequestException("账号密码不能为空"); throw new BadRequestException("账号密码不能为空");
} }
customer.setPassword(BCrypt.hashpw(customer.getPassword())); customer.setPassword(BCrypt.hashpw(customer.getPassword()));
customerService.addCustomer(customer); customerService.addCustomer(customer);
return ResponseVO.success("新增客户成功!!!"); return R.ok();
} }
// @Log("修改客户") // @Log("修改客户")
@Operation(summary = "修改客户") @Operation(summary = "修改客户")
@PutMapping(value = "updateCustomer") @PutMapping(value = "updateCustomer")
public ResponseVO<Object> updateCustomer(@RequestBody Customer resources) throws Exception { public R<Void> updateCustomer(@RequestBody Customer resources) throws Exception {
customerService.updateCustomer(resources); customerService.updateCustomer(resources);
return ResponseVO.success(null); return R.ok();
} }
// @Log("删除客户") // @Log("删除客户")
@Operation(summary = "删除客户") @Operation(summary = "删除客户")
@DeleteMapping(value = "/deleteCustomer") @DeleteMapping(value = "/deleteCustomer")
public ResponseVO<Object> deleteCustomer(@RequestBody Set<Long> ids) throws BadRequestException { public R<Void> deleteCustomer(@RequestBody Set<Long> ids) throws BadRequestException {
if (CollectionUtil.isEmpty(ids)) { if (CollectionUtil.isEmpty(ids)) {
throw new BadRequestException("请选择要删除的客户"); throw new BadRequestException("请选择要删除的客户");
} }
customerService.delete(ids); customerService.delete(ids);
return ResponseVO.success(null); return R.ok();
} }

View File

@ -6,17 +6,17 @@ import com.fuyuanshen.common.core.validate.EditGroup;
import com.fuyuanshen.common.idempotent.annotation.RepeatSubmit; import com.fuyuanshen.common.idempotent.annotation.RepeatSubmit;
import com.fuyuanshen.common.log.annotation.Log; import com.fuyuanshen.common.log.annotation.Log;
import com.fuyuanshen.common.log.enums.BusinessType; import com.fuyuanshen.common.log.enums.BusinessType;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.common.web.core.BaseController; import com.fuyuanshen.common.web.core.BaseController;
import com.fuyuanshen.equipment.domain.bo.UserAppBo; import com.fuyuanshen.equipment.domain.bo.UserAppBo;
import com.fuyuanshen.equipment.domain.query.DeviceQueryCriteria;
import com.fuyuanshen.equipment.service.AppUserService; import com.fuyuanshen.equipment.service.AppUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/** /**
* @Description: * @Description:

View File

@ -4,11 +4,13 @@ package com.fuyuanshen.equipment.controller;
import com.alibaba.excel.EasyExcel; import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fuyuanshen.common.core.constant.ResponseMessageConstants; import com.fuyuanshen.common.core.constant.ResponseMessageConstants;
import com.fuyuanshen.common.core.domain.R;
import com.fuyuanshen.common.core.domain.ResponseVO; import com.fuyuanshen.common.core.domain.ResponseVO;
import com.fuyuanshen.common.core.domain.model.LoginUser; import com.fuyuanshen.common.core.domain.model.LoginUser;
import com.fuyuanshen.common.core.utils.file.FileUtil; import com.fuyuanshen.common.core.utils.file.FileUtil;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.common.satoken.utils.LoginHelper; import com.fuyuanshen.common.satoken.utils.LoginHelper;
import com.fuyuanshen.common.web.core.BaseController;
import com.fuyuanshen.customer.mapper.CustomerMapper; import com.fuyuanshen.customer.mapper.CustomerMapper;
import com.fuyuanshen.equipment.domain.Device; import com.fuyuanshen.equipment.domain.Device;
import com.fuyuanshen.equipment.domain.dto.DeviceExcelImportDTO; import com.fuyuanshen.equipment.domain.dto.DeviceExcelImportDTO;
@ -49,7 +51,7 @@ import java.util.List;
@RestController @RestController
@RequiredArgsConstructor @RequiredArgsConstructor
@RequestMapping("/api/device") @RequestMapping("/api/device")
public class DeviceController { public class DeviceController extends BaseController {
private final ISysOssService ossService; private final ISysOssService ossService;
private final DeviceService deviceService; private final DeviceService deviceService;
@ -72,106 +74,106 @@ public class DeviceController {
// @Log("新增设备") // @Log("新增设备")
@Operation(summary = "新增设备") @Operation(summary = "新增设备")
@PostMapping(value = "/add") @PostMapping(value = "/add")
public ResponseVO<Object> addDevice(@Validated @ModelAttribute DeviceForm deviceForm) { public R<Void> addDevice(@Validated @ModelAttribute DeviceForm deviceForm) {
try { try {
deviceService.addDevice(deviceForm); deviceService.addDevice(deviceForm);
} catch (Exception e) { } catch (Exception e) {
log.error("addDevice error: " + e.getMessage()); log.error("addDevice error: " + e.getMessage());
return ResponseVO.fail(e.getMessage()); return R.fail(e.getMessage());
} }
return ResponseVO.success(null); return R.ok();
} }
// @Log("修改设备") // @Log("修改设备")
@Operation(summary = "修改设备") @Operation(summary = "修改设备")
@PutMapping(value = "/update") @PutMapping(value = "/update")
public ResponseVO<Object> updateDevice(@Validated @ModelAttribute DeviceForm deviceForm) { public R<Void> updateDevice(@Validated @ModelAttribute DeviceForm deviceForm) {
try { try {
deviceService.update(deviceForm); deviceService.update(deviceForm);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
log.error("updateDevice error: " + e.getMessage()); log.error("updateDevice error: " + e.getMessage());
return ResponseVO.fail("出错了"); return R.fail(e.getMessage());
} }
return ResponseVO.success(null); return R.ok();
} }
@Operation(summary = "设备详情") @Operation(summary = "设备详情")
@GetMapping(value = "/detail/{id}") @GetMapping(value = "/detail/{id}")
public ResponseVO<Object> getDevice(@PathVariable Long id) { public R<Device> getDevice(@PathVariable Long id) {
Device device = deviceService.getById(id); Device device = deviceService.getById(id);
return ResponseVO.success(device); return R.ok(device);
} }
// @Log("删除设备") // @Log("删除设备")
@Operation(summary = "删除设备") @Operation(summary = "删除设备")
@DeleteMapping(value = "/delete") @DeleteMapping(value = "/delete")
public ResponseVO<Object> deleteDevice(@Parameter(name = "传ID数组[]") @RequestBody List<Long> ids) { public R<Void> deleteDevice(@Parameter(name = "传ID数组[]") @RequestBody List<Long> ids) {
deviceService.deleteAll(ids); deviceService.deleteAll(ids);
return ResponseVO.success(ResponseMessageConstants.DELETE_SUCCESS); return R.ok();
} }
@Operation(summary = "设备定位") @Operation(summary = "设备定位")
@GetMapping(value = "/locateDevice") @GetMapping(value = "/locateDevice")
public ResponseVO<Object> locateDevice(DeviceQueryCriteria criteria) throws IOException { public R<List<Device>> locateDevice(DeviceQueryCriteria criteria) throws IOException {
List<Device> devices = deviceService.queryAllDevices(criteria); List<Device> devices = deviceService.queryAllDevices(criteria);
return ResponseVO.success(devices); return R.ok(devices);
} }
// @Log("分配客户") // @Log("分配客户")
@Operation(summary = "分配客户") @Operation(summary = "分配客户")
@PutMapping(value = "/assignCustomer") @PutMapping(value = "/assignCustomer")
public ResponseVO<Object> assignCustomer(@Validated @RequestBody CustomerVo customerVo) { public R<Void> assignCustomer(@Validated @RequestBody CustomerVo customerVo) {
deviceService.assignCustomer(customerVo); deviceService.assignCustomer(customerVo);
return ResponseVO.success(null); return R.ok();
} }
// @Log("撤回设备") // @Log("撤回设备")
@Operation(summary = "撤回分配设备") @Operation(summary = "撤回分配设备")
@PostMapping(value = "/withdraw") @PostMapping(value = "/withdraw")
public ResponseVO<Object> withdrawDevice(@RequestBody List<Long> ids) { public R<Void> withdrawDevice(@RequestBody List<Long> ids) {
try { try {
deviceService.withdrawDevice(ids); deviceService.withdrawDevice(ids);
} catch (Exception e) { } catch (Exception e) {
log.error("updateDevice error: " + e.getMessage()); log.error("updateDevice error: " + e.getMessage());
return ResponseVO.fail("出错了"); return R.fail(e.getMessage());
} }
return ResponseVO.success(null); return R.ok();
} }
/** /**
* @param deviceForm * @param id
* @return * @return
* @ModelAttribute 主要用于将请求参数绑定到 Java 对象上,它会从 HTTP 请求的查询参数Query Parameters * @ModelAttribute 主要用于将请求参数绑定到 Java 对象上,它会从 HTTP 请求的查询参数Query Parameters
* 或表单数据Form Data中提取值并自动填充到指定的对象属性中。 * 或表单数据Form Data中提取值并自动填充到指定的对象属性中。
*/ */
// @Log("解绑设备") // @Log("解绑设备")
@Operation(summary = "解绑设备") @Operation(summary = "WEB端解绑设备")
@PostMapping(value = "/unbind") @GetMapping(value = "/unbind")
public ResponseVO<Object> unbindDevice(@Validated @ModelAttribute DeviceForm deviceForm) { public R<Void> unbindDevice(@Validated Long id) {
deviceService.unbindDevice(deviceForm); return toAjax(deviceService.webUnBindDevice(id));
return ResponseVO.success("解绑成功!!!");
} }
@Operation(summary = "导出数据设备") @Operation(summary = "导出数据设备")
@GetMapping(value = "/download") @GetMapping(value = "/download")
public void exportDevice(HttpServletResponse response, DeviceQueryCriteria criteria) throws IOException { public R<Void> exportDevice(HttpServletResponse response, DeviceQueryCriteria criteria) throws IOException {
List<Device> devices = deviceService.queryAll(criteria); List<Device> devices = deviceService.queryAll(criteria);
exportService.export(devices, response); exportService.export(devices, response);
return R.ok();
} }
@Operation(summary = "导入设备数据") @Operation(summary = "导入设备数据")
@PostMapping(value = "/import", consumes = "multipart/form-data") @PostMapping(value = "/import", consumes = "multipart/form-data")
public ResponseVO<ImportResult> importData(@Parameter(name = "文件", required = true) @RequestPart("file") MultipartFile file) throws BadRequestException { public R<ImportResult> importData(@Parameter(name = "文件", required = true) @RequestPart("file") MultipartFile file) throws BadRequestException {
String suffix = FileUtil.getExtensionName(file.getOriginalFilename()); String suffix = FileUtil.getExtensionName(file.getOriginalFilename());
if (!("xlsx".equalsIgnoreCase(suffix))) { if (!("xlsx".equalsIgnoreCase(suffix))) {
@ -195,13 +197,13 @@ public class DeviceController {
// 设置响应消息 // 设置响应消息
String message = String.format("成功导入 %d 条数据,失败 %d 条", result.getSuccessCount(), result.getFailureCount()); String message = String.format("成功导入 %d 条数据,失败 %d 条", result.getSuccessCount(), result.getFailureCount());
// 返回带有正确泛型的响应 // 返回带有正确泛型的响应
return ResponseVO.<ImportResult>success(message, result); return R.ok(message, result);
} catch (Exception e) { } catch (Exception e) {
log.error("导入设备数据出错: {}", e.getMessage(), e); log.error("导入设备数据出错: {}", e.getMessage(), e);
// 在异常情况下,设置默认结果 // 在异常情况下,设置默认结果
String errorMessage = String.format("导入失败: %s。成功 %d 条,失败 %d 条", e.getMessage(), result.getSuccessCount(), result.getFailureCount()); String errorMessage = String.format("导入失败: %s。成功 %d 条,失败 %d 条", e.getMessage(), result.getSuccessCount(), result.getFailureCount());
// 使用新方法确保类型正确 // 使用新方法确保类型正确
return ResponseVO.<ImportResult>fail(errorMessage, result); return R.fail(errorMessage, result);
} }
} }

View File

@ -1,6 +1,7 @@
package com.fuyuanshen.equipment.controller; package com.fuyuanshen.equipment.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fuyuanshen.common.core.domain.R;
import com.fuyuanshen.common.core.domain.ResponseVO; import com.fuyuanshen.common.core.domain.ResponseVO;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.equipment.domain.DeviceType; import com.fuyuanshen.equipment.domain.DeviceType;
@ -40,43 +41,45 @@ public class DeviceTypeController {
@GetMapping(value = "/all") @GetMapping(value = "/all")
@Operation(summary = "查询所有设备类型") @Operation(summary = "查询所有设备类型")
public ResponseVO<Object> queryDeviceTypes() { public R<List<DeviceType>> queryDeviceTypes() {
List<DeviceType> deviceTypes = deviceTypeService.queryDeviceTypes(); List<DeviceType> deviceTypes = deviceTypeService.queryDeviceTypes();
return ResponseVO.success(deviceTypes); return R.ok(deviceTypes);
} }
// @Log("新增设备类型") // @Log("新增设备类型")
@Operation(summary = "新增设备类型") @Operation(summary = "新增设备类型")
@PostMapping(value = "/add") @PostMapping(value = "/add")
public ResponseVO<Object> createDeviceType(@Validated @RequestBody DeviceType resources) { public R<Void> createDeviceType(@Validated @RequestBody DeviceType resources) {
deviceTypeService.create(resources); deviceTypeService.create(resources);
return ResponseVO.success(null); return R.ok();
} }
// @Log("修改设备类型") // @Log("修改设备类型")
@Operation(summary = "修改设备类型") @Operation(summary = "修改设备类型")
@PutMapping(value = "/update") @PutMapping(value = "/update")
public ResponseVO<Object> updateDeviceType(@Validated @RequestBody DeviceTypeForm resources) { public R<Void> updateDeviceType(@Validated @RequestBody DeviceTypeForm resources) {
deviceTypeService.update(resources); deviceTypeService.update(resources);
return ResponseVO.success(null); return R.ok();
} }
// @Log("删除设备类型") // @Log("删除设备类型")
@Operation(summary = "删除设备类型") @Operation(summary = "删除设备类型")
@DeleteMapping(value = "/delete") @DeleteMapping(value = "/delete")
public ResponseVO<Object> deleteDeviceType(@Parameter(name = "传ID数组[]") @RequestBody List<Long> ids) { public R<Void> deleteDeviceType(@Parameter(name = "传ID数组[]") @RequestBody List<Long> ids) {
deviceTypeService.deleteAll(ids); deviceTypeService.deleteAll(ids);
return ResponseVO.success("删除成功!!!"); return R.ok();
} }
@GetMapping(value = "/communicationMode") @GetMapping(value = "/communicationMode")
@Operation(summary = "获取设备类型通讯方式") @Operation(summary = "获取设备类型通讯方式")
public ResponseVO<DeviceType> getCommunicationMode(@Parameter(name = "设备类型ID", required = true) Long id) { public R<DeviceType> getCommunicationMode(@Parameter(name = "设备类型ID", required = true) Long id) {
return ResponseVO.success(deviceTypeService.getCommunicationMode(id)); DeviceType communicationMode = deviceTypeService.getCommunicationMode(id);
return R.ok(communicationMode);
} }
} }

View File

@ -9,6 +9,8 @@ import com.fuyuanshen.common.tenant.core.TenantEntity;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import java.util.Date;
/** /**
* @Description: 设备表 * @Description: 设备表
* @Author: WY * @Author: WY
@ -114,4 +116,6 @@ public class Device extends TenantEntity {
private String createByName; private String createByName;
private Long bindingUserId; private Long bindingUserId;
private Date bindingTime;
} }

View File

@ -98,4 +98,12 @@ public interface DeviceService extends IService<Device> {
* @return * @return
*/ */
Boolean queryDevice(String mac); Boolean queryDevice(String mac);
/**
* WEB端解绑设备
*
* @param id
* @return
*/
int webUnBindDevice(Long id);
} }

View File

@ -10,6 +10,8 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fuyuanshen.common.core.domain.model.LoginUser; import com.fuyuanshen.common.core.domain.model.LoginUser;
import com.fuyuanshen.common.core.exception.BadRequestException;
import com.fuyuanshen.common.core.utils.StringUtils;
import com.fuyuanshen.common.mybatis.core.page.PageQuery; import com.fuyuanshen.common.mybatis.core.page.PageQuery;
import com.fuyuanshen.common.mybatis.core.page.TableDataInfo; import com.fuyuanshen.common.mybatis.core.page.TableDataInfo;
import com.fuyuanshen.common.satoken.utils.AppLoginHelper; import com.fuyuanshen.common.satoken.utils.AppLoginHelper;
@ -54,6 +56,7 @@ import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Objects;
/** /**
* @Description: * @Description:
@ -272,20 +275,23 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
public void deleteAll(List<Long> ids) { public void deleteAll(List<Long> ids) {
List<Long> invalidIds = new ArrayList<>(); List<Long> invalidIds = new ArrayList<>();
for (Long id : ids) {
DeviceAssignments deviceAssignment = deviceAssignmentsMapper.selectById(id);
Device deviceType = deviceMapper.selectById(deviceAssignment.getDeviceId());
if (StringUtils.isNotEmpty(deviceAssignment.getAssigneeName())) {
throw new BadRequestException(deviceType.getDeviceName() + ":设备已分配,请先解绑设备!!!");
}
// 接收者
if (Objects.equals(deviceAssignment.getAssigneeId(), deviceType.getOriginalOwnerId())) {
invalidIds.add(deviceAssignment.getDeviceId());
}
}
deviceAssignmentsMapper.deleteByIds(ids); deviceAssignmentsMapper.deleteByIds(ids);
// deviceMapper.deleteByIds(invalidIds);
// for (Long id : ids) {
//
// Device deviceType = deviceMapper.selectById(id);
// if (deviceType == null || !Objects.equals(deviceType.getCurrentOwnerId(), LoginHelper.getUserId())) {
// invalidIds.add(id);
// }
// }
// if (!invalidIds.isEmpty()) {
// throw new RuntimeException("以下设备无法删除ID 不存在或无权限): " + invalidIds);
// }
//
// deviceMapper.deleteByIds(ids);
} }
@ -527,8 +533,9 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
UpdateWrapper<Device> deviceUpdateWrapper = new UpdateWrapper<>(); UpdateWrapper<Device> deviceUpdateWrapper = new UpdateWrapper<>();
deviceUpdateWrapper.eq("id", device.getId()) deviceUpdateWrapper.eq("id", device.getId())
.set("binding_status", BindingStatusEnum.BOUND.getCode()) .set("binding_status", BindingStatusEnum.BOUND.getCode())
.set("binding_user_id", userId); .set("binding_user_id", userId)
; .set("binding_time", new Date());
return baseMapper.update(null, deviceUpdateWrapper); return baseMapper.update(null, deviceUpdateWrapper);
} else if (mode == CommunicationModeEnum.BLUETOOTH.getValue()) { } else if (mode == CommunicationModeEnum.BLUETOOTH.getValue()) {
@ -546,7 +553,8 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
UpdateWrapper<Device> deviceUpdateWrapper = new UpdateWrapper<>(); UpdateWrapper<Device> deviceUpdateWrapper = new UpdateWrapper<>();
deviceUpdateWrapper.eq("id", device.getId()) deviceUpdateWrapper.eq("id", device.getId())
.set("binding_status", BindingStatusEnum.BOUND.getCode()) .set("binding_status", BindingStatusEnum.BOUND.getCode())
.set("binding_user_id", userId); .set("binding_user_id", userId)
.set("binding_time", new Date());
return baseMapper.update(null, deviceUpdateWrapper); return baseMapper.update(null, deviceUpdateWrapper);
} else { } else {
throw new RuntimeException("通讯方式错误"); throw new RuntimeException("通讯方式错误");
@ -565,11 +573,27 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
UpdateWrapper<Device> deviceUpdateWrapper = new UpdateWrapper<>(); UpdateWrapper<Device> deviceUpdateWrapper = new UpdateWrapper<>();
deviceUpdateWrapper.eq("id", device.getId()) deviceUpdateWrapper.eq("id", device.getId())
.set("binding_status", BindingStatusEnum.UNBOUND.getCode()) .set("binding_status", BindingStatusEnum.UNBOUND.getCode())
.set("binding_user_id", null); .set("binding_user_id", null)
.set("binding_time", null);
return baseMapper.update(null, deviceUpdateWrapper); return baseMapper.update(null, deviceUpdateWrapper);
} }
/**
* WEB端解绑设备
*
* @param id
* @return
*/
@Override
public int webUnBindDevice(Long id) {
DeviceAssignments deviceAssignment = deviceAssignmentsMapper.selectById(id);
if (deviceAssignment == null) {
throw new RuntimeException("请先将设备入库!!!");
}
return unBindDevice(deviceAssignment.getDeviceId());
}
/** /**
* 查询设备MAC号 * 查询设备MAC号

View File

@ -0,0 +1,239 @@
package com.fuyuanshen.equipment.utils.c;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* 可靠点阵生成工具 - 终极版
*
* @author: 默苍璃
* @date: 2025-07-15
*/
public class ReliableTextToBitmap {
public static void main(String[] args) throws IOException {
String unit = "繁體繁體繁體";
String department = "A研B发C";
String name = "12李34四56";
byte[] unitBytes = textToBitmapBytes(unit);
byte[] deptBytes = textToBitmapBytes(department);
byte[] nameBytes = textToBitmapBytes(name);
generateCFile(unitBytes, deptBytes, nameBytes, "display_data.c");
// 生成预览图片
generatePreviewImage(unitBytes, "unit_image.png");
generatePreviewImage(deptBytes, "department_image.png");
generatePreviewImage(nameBytes, "name_image.png");
}
// 专门生成预览图片的方法
private static void generatePreviewImage(byte[] data, String filename) {
try {
BufferedImage image = convertByteArrayToImage(data, 12);
ImageIO.write(image, "PNG", new File(filename));
System.out.println("成功生成预览图片: " + filename);
} catch (IOException e) {
System.err.println("图片生成失败: " + e.getMessage());
}
}
/**
* 可靠的字节数组转图像方法
*/
public static BufferedImage convertByteArrayToImage(byte[] data, int height) {
if (data == null || data.length == 0) {
return new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
}
// 计算宽度
int width = (data.length * 8) / height;
// 创建RGB图像
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 设置白色背景
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
image.setRGB(x, y, Color.WHITE.getRGB());
}
}
// 直接设置像素点
int bitIndex = 0;
for (int i = 0; i < data.length; i++) {
int value = data[i] & 0xFF;
for (int bit = 7; bit >= 0; bit--) { // 高位在前
boolean isBlack = ((value >> bit) & 1) == 1;
if (isBlack) {
int x = bitIndex % width;
int y = bitIndex / width;
if (y < height) { // 确保不越界
image.setRGB(x, y, Color.BLACK.getRGB());
}
}
bitIndex++;
}
}
return image;
}
/**
* 可靠的点阵生成方法
*/
public static byte[] textToBitmapBytes(String text) {
if (text == null || text.isEmpty()) {
return new byte[0];
}
// 1. 创建画布 - 使用RGB类型避免问题
Font font = new Font("宋体", Font.PLAIN, 12);
BufferedImage image = createTextImage(text, font);
// 2. 直接提取点阵数据
return extractBitmapData(image);
}
/**
* 创建文本图像 - 最可靠的方法
*/
private static BufferedImage createTextImage(String text, Font font) {
// 创建临时图像获取字体度量
BufferedImage tempImage = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);
Graphics2D tempG = tempImage.createGraphics();
tempG.setFont(font);
FontMetrics metrics = tempG.getFontMetrics();
// 计算文本宽度
int totalWidth = metrics.stringWidth(text);
// 宽度对齐到8的倍数
int width = (int) Math.ceil(totalWidth / 8.0) * 8;
int height = 12;
// 创建RGB图像
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = image.createGraphics();
// 设置白色背景
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);
// 设置黑色文本
g.setColor(Color.BLACK);
g.setFont(font);
// 关闭抗锯齿 - 确保清晰度
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
// 绘制文本 - 精确居中
int y = (height - metrics.getHeight()) / 2 + metrics.getAscent();
g.drawString(text, 0, y);
g.dispose();
tempG.dispose();
return image;
}
/**
* 提取点阵数据 - 简单可靠的方法
*/
private static byte[] extractBitmapData(BufferedImage image) {
int width = image.getWidth();
int height = image.getHeight();
List<Byte> byteList = new ArrayList<>();
int currentByte = 0;
int bitCount = 0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
// 获取像素颜色
Color color = new Color(image.getRGB(x, y));
// 简单阈值判断 - 灰度小于128为黑色
int gray = (color.getRed() + color.getGreen() + color.getBlue()) / 3;
boolean isBlack = gray < 128;
// 高位优先打包
currentByte = (currentByte << 1) | (isBlack ? 1 : 0);
bitCount++;
if (bitCount == 8) {
byteList.add((byte) currentByte);
currentByte = 0;
bitCount = 0;
}
}
}
// 处理最后不满8位的部分
if (bitCount > 0) {
currentByte <<= (8 - bitCount);
byteList.add((byte) currentByte);
}
return byteListToArray(byteList);
}
private static byte[] byteListToArray(List<Byte> byteList) {
byte[] result = new byte[byteList.size()];
for (int i = 0; i < byteList.size(); i++) {
result[i] = byteList.get(i);
}
return result;
}
public static void generateCFile(byte[] unit, byte[] department, byte[] name, String filename) throws IOException {
try (FileWriter writer = new FileWriter(filename)) {
writer.write("/**\n");
writer.write(" * 点阵显示数据 - 可靠生成\n");
writer.write(" * 宽度计算公式: width = (数组长度 * 8) / 12\n");
writer.write(" */\n\n");
writer.write("#include <stdint.h>\n\n");
// 单位数据
writer.write(String.format("// 单位: %d 字节, 宽度: %d 像素\n",
unit.length, (unit.length * 8) / 12));
writer.write("const uint8_t unit[] = {\n ");
writeByteArray(writer, unit);
writer.write("\n};\n\n");
// 部门数据
writer.write(String.format("// 部门: %d 字节, 宽度: %d 像素\n",
department.length, (department.length * 8) / 12));
writer.write("const uint8_t department[] = {\n ");
writeByteArray(writer, department);
writer.write("\n};\n\n");
// 姓名数据
writer.write(String.format("// 姓名: %d 字节, 宽度: %d 像素\n",
name.length, (name.length * 8) / 12));
writer.write("const uint8_t name[] = {\n ");
writeByteArray(writer, name);
writer.write("\n};\n");
}
}
private static void writeByteArray(FileWriter writer, byte[] data) throws IOException {
for (int i = 0; i < data.length; i++) {
int value = data[i] & 0xFF;
writer.write(String.format("0x%02X", value));
if (i < data.length - 1) {
writer.write(", ");
if ((i + 1) % 12 == 0) writer.write("\n ");
}
}
}
}

View File

@ -36,48 +36,12 @@
d.device_imei, d.longitude, d.latitude, d.tenant_id d.device_imei, d.longitude, d.latitude, d.tenant_id
</sql> </sql>
<!-- 分页查询设备 -->
<select id="findAll1" resultType="com.fuyuanshen.equipment.domain.Device">
select d.* , t.type_name
FROM device d
LEFT JOIN device_type t ON d.device_type = t.id
<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 d.device_mac = #{criteria.deviceMac}
</if>
<if test="criteria.deviceImei != null">
and d.device_imei = #{criteria.deviceImei}
</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.currentOwnerId != null">
and d.current_owner_id = #{criteria.currentOwnerId}
</if>
<if test="criteria.params.beginTime != null and criteria.params.endTime != null">
and d.create_time between #{criteria.params.beginTime} and #{criteria.params.endTime}
</if>
<if test="criteria.tenantId != null">
AND tenant_id = #{criteria.tenantId}
</if>
</where>
order by d.create_time desc
</select>
<!-- 分页查询设备 --> <!-- 分页查询设备 -->
<select id="findAll" resultType="com.fuyuanshen.equipment.domain.Device"> <select id="findAll" resultType="com.fuyuanshen.equipment.domain.Device">
select select
da.id AS id,d.device_name,d.bluetooth_name, da.id AS id,d.device_name,d.bluetooth_name,
d.device_pic, d.device_mac, d.device_sn, d.update_by,d.device_imei, d.device_pic, d.device_mac, d.device_sn, d.update_by,d.device_imei,
d.update_time, dg.id AS device_type, d.remark, d.binding_status,d.type_name AS typeName, d.update_time, dg.id AS device_type, d.remark, d.binding_status,t.type_name AS typeName,
da.assignee_id AS customerId, da.assignee_name AS customerName, da.active AS deviceStatus, da.assignee_id AS customerId, da.assignee_name AS customerName, da.active AS deviceStatus,
da.create_time AS create_time , da.assigner_name AS createByName , da.id AS assignId da.create_time AS create_time , da.assigner_name AS createByName , da.id AS assignId
from device d from device d
@ -166,7 +130,7 @@
<!-- 查询APP绑定设备列表 --> <!-- 查询APP绑定设备列表 -->
<select id="queryAppBindDeviceList" resultType="com.fuyuanshen.equipment.domain.vo.AppDeviceVo"> <select id="queryAppBindDeviceList" resultType="com.fuyuanshen.equipment.domain.vo.AppDeviceVo">
select d.id, d.device_name, d.device_name, select d.id, d.device_name, d.device_name,
d.device_name, d.device_name,
d.device_mac, d.device_mac,
d.device_sn, d.device_sn,