Compare commits

...

5 Commits

Author SHA1 Message Date
171eeabea1 Merge branch 'dyf-device' 2025-07-17 09:24:10 +08:00
cc776300ec 删除设备 逻辑修改 2025-07-17 09:23:11 +08:00
04df7e3ec7 可靠点阵生成工具 - 终极版 2025-07-16 08:46:21 +08:00
7be94fe1d2 产品参数bug修改 2025-07-15 15:59:32 +08:00
6f24759361 发送指令显示工具 2025-07-15 15:58:12 +08:00
5 changed files with 269 additions and 21 deletions

View File

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

View File

@ -6,15 +6,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<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 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="businessId != null"> <if test="businessId != null">
and a.business_id = #{businessId} and a.business_id = #{businessId}
</if> </if>
<if test="fileId != null"> <if test="fileId != null">
and a.file_id = #{fileId} and a.file_id = #{fileId}
</if> </if>
<if test="fileType != null">
and a.file_type = #{fileType}
</if>
<if test="createBy != null"> <if test="createBy != null">
a.create_by = #{createBy} and a.create_by = #{createBy}
</if> </if>
order by a.create_time desc order by a.create_time desc
</select> </select>

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

@ -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;
@ -42,6 +44,7 @@ import com.fuyuanshen.system.domain.vo.SysOssVo;
import com.fuyuanshen.system.service.ISysOssService; import com.fuyuanshen.system.service.ISysOssService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@ -54,6 +57,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 +276,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);
} }
@ -573,7 +580,6 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
} }
/** /**
* 查询设备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 ");
}
}
}
}