From 736e077dce47799f8c30b205646cd34a004c85b1 Mon Sep 17 00:00:00 2001 From: username <1532322479@qq.com> Date: Wed, 9 Apr 2025 12:32:09 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=9B=BE=E5=BA=93=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/bs/cm/vo/CmAttachVO.java | 90 ++ .../controller/CtGalleryImagesController.java | 83 +- .../com/bs/ct/domain/CtGalleryImages.java | 7 + .../main/java/com/bs/ct/utils/UUIDUtils.java | 29 + .../controller/common/CommonController.java | 229 ++++- .../com/bs/web/controller/utils/FileUtil.java | 800 ++++++++++++++++++ bs-ui/src/views/task/template/index.vue | 25 +- 7 files changed, 1244 insertions(+), 19 deletions(-) create mode 100644 bs-admin/src/main/java/com/bs/cm/vo/CmAttachVO.java create mode 100644 bs-admin/src/main/java/com/bs/ct/utils/UUIDUtils.java create mode 100644 bs-admin/src/main/java/com/bs/web/controller/utils/FileUtil.java diff --git a/bs-admin/src/main/java/com/bs/cm/vo/CmAttachVO.java b/bs-admin/src/main/java/com/bs/cm/vo/CmAttachVO.java new file mode 100644 index 0000000..9084a9e --- /dev/null +++ b/bs-admin/src/main/java/com/bs/cm/vo/CmAttachVO.java @@ -0,0 +1,90 @@ +package com.bs.cm.vo; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.bs.common.annotation.Excel; +import com.bs.common.core.domain.BaseEntity; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * 附近信息对象 cm_attach + * + * @author bs + * @date 2025-03-04 + */ +@Data +public class CmAttachVO extends BaseEntity{ + + /** 用户id */ + @TableId(value = "id",type = IdType.AUTO) + @ApiModelProperty(value = "用户id") + private Long id; + + /** 文件组id */ + + @Excel(name = "文件组id") + @ApiModelProperty(value = "文件组id") + private String fileId; + + /** 文件排序 */ + + @Excel(name = "文件排序") + @ApiModelProperty(value = "文件排序") + private Long fileSort; + + /** 文件名称(编译后) */ + + @Excel(name = "文件名称", readConverterExp = "编=译后") + @ApiModelProperty(value = "文件名称(编译后)") + private String attachName; + + /** 文件类型 */ + + @Excel(name = "文件类型") + @ApiModelProperty(value = "文件类型") + private String attachFileType; + + /** 文件编码类型 */ + + @Excel(name = "文件编码类型") + @ApiModelProperty(value = "文件编码类型") + private String attachContentType; + + /** 文件大小 */ + + @Excel(name = "文件大小") + @ApiModelProperty(value = "文件大小") + private Long attachFileSize; + + /** 文件路径 */ + + @Excel(name = "文件路径") + @ApiModelProperty(value = "文件路径") + private String attachFileUrl; + + /** 文件名(原始) */ + + @Excel(name = "文件名", readConverterExp = "原=始") + @ApiModelProperty(value = "文件名(原始)") + private String oldName; + + /** 文件版本号 */ + + @Excel(name = "文件版本号") + @ApiModelProperty(value = "文件版本号") + private String versionNo; + + /** 备注 */ + + @Excel(name = "备注") + @ApiModelProperty(value = "备注") + private String remark; + + private String angle; + + +} diff --git a/bs-admin/src/main/java/com/bs/ct/controller/CtGalleryImagesController.java b/bs-admin/src/main/java/com/bs/ct/controller/CtGalleryImagesController.java index fc3c2cc..41cf0be 100644 --- a/bs-admin/src/main/java/com/bs/ct/controller/CtGalleryImagesController.java +++ b/bs-admin/src/main/java/com/bs/ct/controller/CtGalleryImagesController.java @@ -1,8 +1,18 @@ package com.bs.ct.controller; +import java.math.BigDecimal; +import java.util.Date; import java.util.List; +import java.util.Random; import javax.servlet.http.HttpServletResponse; +import com.bs.cm.domain.CmAttach; +import com.bs.cm.service.ICmAttachService; +import com.bs.common.config.BsConfig; +import com.bs.common.utils.file.FileUploadUtils; +import com.bs.common.utils.file.FileUtils; +import com.bs.ct.domain.CtTaskFeedback; +import com.bs.framework.config.ServerConfig; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.security.access.prepost.PreAuthorize; @@ -25,6 +35,8 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import cn.hutool.core.lang.Validator; import com.bs.ct.domain.CtGalleryImages; import com.bs.ct.service.ICtGalleryImagesService; +import org.springframework.web.multipart.MultipartFile; + import javax.annotation.Resource; /** @@ -39,7 +51,10 @@ import javax.annotation.Resource; public class CtGalleryImagesController extends BaseController { @Resource private ICtGalleryImagesService ctGalleryImagesService; - + @Autowired + private ServerConfig serverConfig; + @Autowired + private ICmAttachService cmAttachService; /** * 分页查询图库图片列表 */ @@ -50,9 +65,17 @@ public class CtGalleryImagesController extends BaseController { LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(); condition(queryWrapper,ctGalleryImages); List list = ctGalleryImagesService.list(queryWrapper); + setFile(list); return getDataTable(list); } + private void setFile(List list) { + for (CtGalleryImages ctGalleryImages : list) { + List cmAttachList = cmAttachService.list(new LambdaQueryWrapper().eq(CmAttach::getFileId,ctGalleryImages.getFileId())); + ctGalleryImages.setFile(cmAttachList); + } + } + /** * 查询图库图片列表 */ @@ -65,6 +88,64 @@ public class CtGalleryImagesController extends BaseController { return success(list); } + /** + * 通用上传请求(单个) + */ + @PostMapping("/upload") + public AjaxResult uploadFile(MultipartFile file, String fileId, Long cataId, String imageTitle, Date photoTime,Date uploadTime, + String isOpen,String keyWords,String remarks + ) throws Exception + { + try + { + Long newId = System.currentTimeMillis() + new Random().nextInt(1000); + CtGalleryImages ctGalleryImages = new CtGalleryImages(); + ctGalleryImages.setCataId(cataId); + ctGalleryImages.setImageTitle(imageTitle); + ctGalleryImages.setPhotoTime(photoTime); + ctGalleryImages.setUploadTime(uploadTime); + ctGalleryImages.setIsOpen(isOpen); + ctGalleryImages.setKeyWords(keyWords); + ctGalleryImages.setRemarks(remarks); + ctGalleryImages.setFileId(newId); + // 上传文件路径 + String filePath = BsConfig.getUploadPath(); + // 上传并返回新文件名称 + String fileName = FileUploadUtils.upload(filePath, file); + String url = serverConfig.getUrl() + fileName; + String newFileName = FileUtils.getName(fileName); + String originalFilename = file.getOriginalFilename(); + CmAttach cmAttach = new CmAttach(); + cmAttach.setFileId(String.valueOf(newId)); + cmAttach.setFileSort(1L); + cmAttach.setAttachName(newFileName); + cmAttach.setAttachContentType(file.getContentType()); + cmAttach.setAttachFileSize(file.getSize()); + cmAttach.setAttachFileUrl(fileName); + cmAttach.setOldName(originalFilename); + cmAttach.setVersionNo("1"); + cmAttach.setRemark(""); + boolean save = cmAttachService.save(cmAttach); + if (save) { + Long id = cmAttach.getId(); + AjaxResult ajax = AjaxResult.success(); + ajax.put("cmAttach", cmAttach); + ctGalleryImages.setImageName(originalFilename); + ctGalleryImages.setImagePath(fileName); + ctGalleryImages.setImageSize(BigDecimal.valueOf(file.getSize())); + ctGalleryImages.setFileId(newId); + boolean saveImage = ctGalleryImagesService.save(ctGalleryImages); + return ajax; + } + return null; + } + catch (Exception e) + { + return AjaxResult.error(e.getMessage()); + } + } + + /** * 导出图库图片列表 */ diff --git a/bs-admin/src/main/java/com/bs/ct/domain/CtGalleryImages.java b/bs-admin/src/main/java/com/bs/ct/domain/CtGalleryImages.java index 34613df..da4a6a7 100644 --- a/bs-admin/src/main/java/com/bs/ct/domain/CtGalleryImages.java +++ b/bs-admin/src/main/java/com/bs/ct/domain/CtGalleryImages.java @@ -2,6 +2,9 @@ package com.bs.ct.domain; import java.math.BigDecimal; import java.util.Date; +import java.util.List; + +import com.bs.cm.domain.CmAttach; import com.fasterxml.jackson.annotation.JsonFormat; import com.bs.common.annotation.Excel; import com.bs.common.core.domain.BaseEntity; @@ -100,7 +103,11 @@ public class CtGalleryImages extends BaseEntity{ @ApiModelProperty(value = "备注") private String remarks; + /** 附件id */ + @ApiModelProperty(value = "附件") + @TableField(exist = false) + private List file; } diff --git a/bs-admin/src/main/java/com/bs/ct/utils/UUIDUtils.java b/bs-admin/src/main/java/com/bs/ct/utils/UUIDUtils.java new file mode 100644 index 0000000..57c400c --- /dev/null +++ b/bs-admin/src/main/java/com/bs/ct/utils/UUIDUtils.java @@ -0,0 +1,29 @@ + +package com.bs.ct.utils; + +import java.util.UUID; + + +public final class UUIDUtils { + + + private UUIDUtils() { + + } + + + public static String generatorUUID() { + UUID uuid = UUID.randomUUID(); + return uuid.toString().replaceAll("-", ""); + } + + /** + * 获得20个长度的十六进制的UUID + * @return UUID + */ + public static String generator20UUID(){ + UUID id=UUID.randomUUID(); + String[] idd=id.toString().split("-"); + return idd[0]+idd[1]+idd[2]+idd[3]; + } +} diff --git a/bs-admin/src/main/java/com/bs/web/controller/common/CommonController.java b/bs-admin/src/main/java/com/bs/web/controller/common/CommonController.java index 94536d7..33cbffb 100644 --- a/bs-admin/src/main/java/com/bs/web/controller/common/CommonController.java +++ b/bs-admin/src/main/java/com/bs/web/controller/common/CommonController.java @@ -1,21 +1,40 @@ package com.bs.web.controller.common; -import java.util.ArrayList; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.*; import java.util.List; +import javax.annotation.Resource; +import javax.imageio.IIOImage; +import javax.imageio.ImageIO; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.stream.ImageOutputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import cn.hutool.core.lang.Validator; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.bs.BsApplication; import com.bs.cm.domain.CmAttach; import com.bs.cm.service.ICmAttachService; +import com.bs.cm.vo.CmAttachVO; +import com.bs.common.exception.ServiceException; +import com.bs.ct.domain.CtGalleryImages; +import com.bs.ct.service.ICtGalleryImagesService; +import com.bs.ct.utils.UUIDUtils; +import io.swagger.annotations.ApiOperation; import org.aspectj.util.FileUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import com.bs.common.config.BsConfig; import com.bs.common.constant.Constants; @@ -25,6 +44,8 @@ import com.bs.common.utils.file.FileUploadUtils; import com.bs.common.utils.file.FileUtils; import com.bs.framework.config.ServerConfig; +import static cn.hutool.core.img.ImgUtil.getWriter; + /** * 通用请求处理 * @@ -35,14 +56,141 @@ import com.bs.framework.config.ServerConfig; public class CommonController { private static final Logger log = LoggerFactory.getLogger(CommonController.class); - + @Value("${bs.profile}") + private String profile; @Autowired private ServerConfig serverConfig; @Autowired private ICmAttachService cmAttachService; - + @Resource + private ICtGalleryImagesService ctGalleryImagesService; + public static final String SEPARATOR = "/"; +// public static final String SUFFIX = RESOURCE_PREFIX; private static final String FILE_DELIMETER = ","; + public static void clockwise90(File file, File outputFile, String formatName) { + try { + // 原图片 + BufferedImage image = ImageIO.read(file); + int width = image.getWidth(); + int height = image.getHeight(); + + // 新生成的图片 + BufferedImage imageNew = new BufferedImage(height, width, image.getType()); + // 把原图顺时针旋转后,像素存入新图片。 + // 算法实现方式: + // 把原图片的最后一行,转变为新图片的第1列. + // 把原图片的倒数第2行,转变为新图片的第2列. + // ...... + // 以此类推,进行变换。代码中行数列数从0开始计算。 + int maxY = height - 1; + for (int y = maxY; y >= 0; y--) { + for (int x = 0; x < width; x++) { + int rgb = image.getRGB(x, y); + imageNew.setRGB(maxY - y, x, rgb); + } + } + // 把图片输出到硬盘上。 + ImageIO.write(imageNew, formatName, outputFile); + // 检查输出文件的父目录是否存在,如果不存在则创建 + File parentDir = outputFile.getParentFile(); + if (parentDir != null &&!parentDir.exists()) { + if (!parentDir.mkdirs()) { + System.err.println("无法创建输出文件的父目录: " + parentDir.getAbsolutePath()); + return; + } + } + // 把图片输出到硬盘上。 + if (!ImageIO.write(imageNew, formatName, outputFile)) { + System.err.println("无法保存图片到: " + outputFile.getAbsolutePath()); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static ImageWriter getWriter(BufferedImage im, String formatName) { + Iterator writers = ImageIO.getImageWritersByFormatName(formatName); + if (writers.hasNext()) { + return writers.next(); + } + return null; + } + + public static BufferedImage rotateImage90DegreesClockwise(BufferedImage originalImage) { + int width = originalImage.getWidth(); + int height = originalImage.getHeight(); + BufferedImage rotatedImage = new BufferedImage(height, width, originalImage.getType()); + Graphics2D g2d = rotatedImage.createGraphics(); + g2d.rotate(Math.toRadians(90), height / 2.0, width / 2.0); + g2d.translate((height - width) / 2, (width - height) / 2); + g2d.drawImage(originalImage, 0, 0, null); + g2d.dispose(); + + return rotatedImage; + } + + public static void clockwise180(File file, File outputFile, String formatName) { + try { + // 原图片 + BufferedImage image = ImageIO.read(file); + int width = image.getWidth(); + int height = image.getHeight(); + // 新生成的图片 + BufferedImage imageNew = new BufferedImage(width, height, image.getType()); + + // 把原图片顺时针旋转180度后,像素存入新图片。 + // 算法实现方式: + // 原图片第1行转变为新图片倒数第1行。并且旧行中像素的顺序,在新行倒转了过来。 + // 原图片第2行转变为新图片倒数第2行。并且旧行中像素的顺序,在新行倒转了过来。 + // ...... + // 以此类推,进行变换。代码中行数列数从0开始计算。 + int maxX = width - 1; + int maxY = height - 1; + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + int rgb = image.getRGB(x, y); + imageNew.setRGB(maxX - x, maxY - y, rgb); + } + } + + // 把图片输出到硬盘上。 + ImageIO.write(imageNew, formatName, outputFile); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void anticlockwise90(File file, File outputFile, String formatName) { + try { + // 原图片 + BufferedImage image = ImageIO.read(file); + int width = image.getWidth(); + int height = image.getHeight(); + + // 新生成的图片 + BufferedImage imageNew = new BufferedImage(height, width, image.getType()); + + // 把原图逆时针旋转后,像素存入新图片。 + // 算法实现方式: + // 把原图片第1行,转变为新图片第1列。并且旧行中第1个像素是新列中最后1个像素. + // 把原图片第2行,转变为新图片第2列。并且旧行中第1个像素是新列中最后1个像素. + // ...... + // 以此类推,进行变换。代码中行数列数从0开始计算。 + int maxX = width - 1; + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + int rgb = image.getRGB(x, y); + imageNew.setRGB(y, maxX - x, rgb); + } + } + + // 把图片输出到硬盘上。 + ImageIO.write(imageNew, formatName, outputFile); + } catch (IOException e) { + e.printStackTrace(); + } + } /** * 通用下载请求 @@ -76,6 +224,67 @@ public class CommonController } } + @ApiOperation("下载文件") + @GetMapping("/file/download/{attachId}") + public void download(@PathVariable String attachId, HttpServletRequest request, HttpServletResponse response) { + if (org.apache.commons.lang3.StringUtils.isBlank(attachId) || "null".equals(attachId)) { + throw new ServiceException("附件ID不能为空"); + } + try { + Map param = new HashMap<>(); + param.put("attachId", attachId); + //CmAttach cmAttach = cmAttachMapper.selectByAttachId(param); + CmAttach vwAttach = cmAttachService.getById(attachId); + String attachFileurl = vwAttach.getAttachFileUrl(); + if (Validator.isNotEmpty(attachFileurl) && attachFileurl.contains(Constants.RESOURCE_PREFIX)) { + attachFileurl = attachFileurl.replace("/profile", ""); + } + File file = new File(profile + attachFileurl); + boolean exists = file.exists(); + response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); + com.bs.web.controller.utils.FileUtil.downloadFile(request, response, file, false); + } catch (Exception e) { + throw new ServiceException("下载失败:" + e.getMessage()); + } + } + + @ApiOperation("修改附件") + @PutMapping("/editFile") + public AjaxResult edit(@RequestBody CmAttachVO attachVo) throws Exception { + Long id = attachVo.getId(); + String attachFileUrl = attachVo.getAttachFileUrl(); + String attachUrl = attachVo.getAttachFileUrl().replace("/profile", ""); + String filePath = profile + attachUrl; + String formatName = FileUtils.getName(filePath); + String fileName = UUIDUtils.generatorUUID() + formatName; + String newAttachUrl = attachUrl.substring(0, attachUrl.lastIndexOf(SEPARATOR)) + SEPARATOR + fileName; + String outFilePath = profile + newAttachUrl; + File inputFile = new File(filePath); + File outputFile = new File(outFilePath); + formatName = "jpeg"; + if ("90".equals(attachVo.getAngle())) { + // 旋转90度 + //BufferedImage rotated90Image = rotateImage(inputImage, 90); + clockwise90(inputFile, outputFile, formatName); + } else if ("180".equals(attachVo.getAngle())) { + // 旋转180度 + clockwise180(inputFile, outputFile, formatName); + } else if ("270".equals(attachVo.getAngle())) { + anticlockwise90(inputFile, outputFile, formatName); + } + List list = cmAttachService.list(new LambdaQueryWrapper() + .eq(CmAttach::getFileId, attachVo.getFileId())); + if (null != list && list.size() > 0) { + for (CmAttach cmAttach : list) { + cmAttach.setOldName(attachVo.getOldName()); + String attachUrlNew = newAttachUrl.replace("/uploadPath", "/profile"); + cmAttach.setAttachFileUrl(attachUrlNew); + } + cmAttachService.updateBatchById(list); + } + return AjaxResult.success(); + } + /** * 通用上传请求(单个) */ @@ -105,13 +314,7 @@ public class CommonController if (save) { Long id = cmAttach.getId(); AjaxResult ajax = AjaxResult.success(); -// ajax.put("attachFileUrl", url); -// ajax.put("id", id); -// ajax.put("fileName", fileName); -// ajax.put("newFileName", newFileName); -// ajax.put("originalFilename", originalFilename); ajax.put("cmAttach", cmAttach); - return ajax; } return null; diff --git a/bs-admin/src/main/java/com/bs/web/controller/utils/FileUtil.java b/bs-admin/src/main/java/com/bs/web/controller/utils/FileUtil.java new file mode 100644 index 0000000..e0965d0 --- /dev/null +++ b/bs-admin/src/main/java/com/bs/web/controller/utils/FileUtil.java @@ -0,0 +1,800 @@ +package com.bs.web.controller.utils; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.IdUtil; +import cn.hutool.poi.excel.BigExcelWriter; +import cn.hutool.poi.excel.ExcelUtil; +import com.bs.common.constant.Constants; +import com.bs.common.exception.ServiceException; +import com.bs.ct.utils.UUIDUtils; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.util.IOUtils; +import org.apache.poi.xssf.streaming.SXSSFSheet; +import org.springframework.core.io.ClassPathResource; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.awt.image.BufferedImage; +import java.io.*; +import java.net.URLEncoder; +import java.security.MessageDigest; +import java.security.SecureRandom; +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * File工具类,扩展 hutool 工具包 + */ +@Slf4j +public class FileUtil extends cn.hutool.core.io.FileUtil { + + /** + * 定义GB的计算常量 + */ + private static final int GB = 1024 * 1024 * 1024; + /** + * 定义MB的计算常量 + */ + private static final int MB = 1024 * 1024; + /** + * 定义KB的计算常量 + */ + private static final int KB = 1024; + + /** + * 格式化小数 + */ + private static final DecimalFormat DF = new DecimalFormat("0.00"); + /** + * 系统临时目录 + *
+ * windows 包含路径分割符,但Linux 不包含, + * 在windows \\==\ 前提下, + * 为安全起见 同意拼装 路径分割符, + *
+     *       java.io.tmpdir
+     *       windows : C:\Users/xxx\AppData\Local\Temp\
+     *       linux: /temp
+     * 
+ */ + public static final String SYS_TEM_DIR = System.getProperty("java.io.tmpdir") + File.separator; + + private static final int FILE_READ_BTYE = 1024; + + /** + * MultipartFile转File + */ + public static File toFile(MultipartFile multipartFile) { + // 获取文件名 + String fileName = multipartFile.getOriginalFilename(); + // 获取文件后缀 + String prefix = "." + getExtensionName(fileName); + File file = null; + try { + // 用uuid作为文件名,防止生成的临时文件重复 + file = File.createTempFile(IdUtil.simpleUUID(), prefix); + // MultipartFile to File + multipartFile.transferTo(file); + } catch (IOException e) { + e.printStackTrace(); + } + return file; + } + + /** + * 获取文件扩展名,不带 . + */ + public static String getExtensionName(String filename) { + if ((filename != null) && (filename.length() > 0)) { + int dot = filename.lastIndexOf('.'); + if ((dot > -1) && (dot < (filename.length() - 1))) { + return filename.substring(dot + 1); + } + } + return filename; + } + + public static String getExtensionNameBase64(String filename) { + if (filename.contains("data:image/png;base64")) { + return "png"; + }else if(filename.contains("data:image/jpg;base64")){ + return "jpg"; + }else if(filename.contains("data:image/jpeg;base64")){ + return "jpeg"; + } + return "bmp"; + } + /** + * Java文件操作 获取不带扩展名的文件名 + */ + public static String getFileNameNoEx(String filename) { + if ((filename != null) && (filename.length() > 0)) { + int dot = filename.lastIndexOf('.'); + if ((dot > -1) && (dot < (filename.length()))) { + return filename.substring(0, dot); + } + } + return filename; + } + + /** + * 文件大小转换 + */ + public static String getSize(long size) { + String resultSize; + if (size / GB >= 1) { + //如果当前Byte的值大于等于1GB + resultSize = DF.format(size / (float) GB) + "GB "; + } else if (size / MB >= 1) { + //如果当前Byte的值大于等于1MB + resultSize = DF.format(size / (float) MB) + "MB "; + } else if (size / KB >= 1) { + //如果当前Byte的值大于等于1KB + resultSize = DF.format(size / (float) KB) + "KB "; + } else { + resultSize = size + "B "; + } + return resultSize; + } + + + /** + * 将文件名解析成文件的上传路径 + */ + public static File upload(MultipartFile file, String filePath) { + //String name = getFileNameNoEx(file.getOriginalFilename()); + String suffix = getExtensionName(file.getOriginalFilename()); + StringBuffer nowStr = fileRename(); + try { + String fileName = nowStr + "." + suffix; + String path = filePath + fileName; + // getCanonicalFile 可解析正确各种路径 + File dest = new File(path).getCanonicalFile(); + // 检测是否存在目录 + if (!dest.getParentFile().exists()) { + dest.getParentFile().mkdirs(); + } + // 文件写入 + file.transferTo(dest); + return dest; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static String fileToBase64(File file) throws Exception { + FileInputStream inputFile = new FileInputStream(file); + String base64; + byte[] buffer = new byte[(int) file.length()]; + inputFile.read(buffer); + inputFile.close(); + base64 = Base64.encode(buffer); + return base64.replaceAll("[\\s*\t\n\r]", ""); + } + + + public static String getFileType(String type) { + String documents = "txt doc pdf ppt pps xlsx xls docx"; + String music = "mp3 wav wma mpa ram ra aac aif m4a"; + String video = "avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg"; + String image = "bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg"; + if (image.contains(type)) { + return "pic"; + } else if (documents.contains(type)) { + return "txt"; + } else if (music.contains(type)) { + return "music"; + } else if (video.contains(type)) { + return "vedio"; + } else { + return "other"; + } + } + + + public static void checkSize(long maxSize, long size) { + // 1M + int len = 1024 * 1024; + if (size > (maxSize * len)) { + throw new ServiceException("文件超出规定大小"); + + } + } + + /** + * 判断两个文件是否相同 + */ + public static boolean check(File file1, File file2) { + String img1Md5 = getMd5(file1); + String img2Md5 = getMd5(file2); + return img1Md5.equals(img2Md5); + } + + /** + * 判断两个文件是否相同 + */ + public static boolean check(String file1Md5, String file2Md5) { + return file1Md5.equals(file2Md5); + } + + private static byte[] getByte(File file) { + // 得到文件长度 + byte[] b = new byte[(int) file.length()]; + try { + InputStream in = new FileInputStream(file); + try { + in.read(b); + } catch (IOException e) { + e.printStackTrace(); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + return null; + } + return b; + } + + private static String getMd5(byte[] bytes) { + // 16进制字符 + char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + try { + MessageDigest mdTemp = MessageDigest.getInstance("MD5"); + mdTemp.update(bytes); + byte[] md = mdTemp.digest(); + int j = md.length; + char[] str = new char[j * 2]; + int k = 0; + // 移位 输出字符串 + for (byte byte0 : md) { + str[k++] = hexDigits[byte0 >>> 4 & 0xf]; + str[k++] = hexDigits[byte0 & 0xf]; + } + return new String(str); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + /** + * 下载文件 + * + * @param request / + * @param response / + * @param file / + */ + public static void downloadFile(HttpServletRequest request, HttpServletResponse response, File file, boolean deleteOnExit) { + response.setCharacterEncoding(request.getCharacterEncoding()); + response.setContentType("application/octet-stream"); + FileInputStream fis = null; + try { + fis = new FileInputStream(file); + response.setHeader("Content-Disposition", "attachment; filename=" + file.getName()); + IOUtils.copy(fis, response.getOutputStream()); + response.flushBuffer(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (fis != null) { + try { + fis.close(); + if (deleteOnExit) { + file.deleteOnExit(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + public static String getMd5(File file) { + return getMd5(getByte(file)); + } + + /** + * 读取json文件,返回json串 + * + * @param fileName + * @return + */ + public static String readJsonFile(String fileName) { + String jsonStr = ""; + try { + File jsonFile = new File(fileName); + FileReader fileReader = new FileReader(jsonFile); + + Reader reader = new InputStreamReader(new FileInputStream(jsonFile), "utf-8"); + int ch = 0; + StringBuffer sb = new StringBuffer(); + while ((ch = reader.read()) != -1) { + sb.append((char) ch); + } + fileReader.close(); + reader.close(); + jsonStr = sb.toString(); + return jsonStr; + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + public static BufferedImage inputImage(MultipartFile file) { + BufferedImage srcImage = null; + try { + FileInputStream in = (FileInputStream) file.getInputStream(); + srcImage = javax.imageio.ImageIO.read(in); + } catch (IOException e) { + System.out.println("读取图片文件出错!" + e.getMessage()); + } + return srcImage; + } + + /** + * 自动调节精度(经验数值) + * + * @param size 源图片大小 + * @return 图片压缩质量比 + */ + public static float getAccuracy(long size) { + float accuracy; + if (size < 400) { + accuracy = 0.85f; + } else if (size < 900) { + accuracy = 0.75f; + } else if (size < 2047) { + accuracy = 0.6f; + } else if (size < 3275) { + accuracy = 0.44f; + } else { + accuracy = 0.4f; + } + return accuracy; + } + + /** + * 上传文件重命名 + * + * @return 新的文件名 + */ + public static StringBuffer fileRename() { + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS"); + String time = sdf.format(new Date()); + StringBuffer buf = new StringBuffer(time); + SecureRandom r = new SecureRandom(); + //循环取得三个不大于10的随机整数 + for (int x = 0; x < 3; x++) { + buf.append(r.nextInt(10)); + } + return buf; + } + + /** + * 对中文字符进行UTF-8编码 + * + * @param source 要转义的字符串 + * @return + * @throws UnsupportedEncodingException + */ + public static String transformStyle(String source) throws UnsupportedEncodingException { + char[] arr = source.toCharArray(); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < arr.length; i++) { + char temp = arr[i]; + if (isChinese(temp)) { + sb.append(URLEncoder.encode("" + temp, Constants.UTF8)); + continue; + } + sb.append(arr[i]); + } + return sb.toString(); + } + + /** + * 判断是不是中文字符 + * + * @param c + * @return + */ + public static boolean isChinese(char c) { + + Character.UnicodeBlock ub = Character.UnicodeBlock.of(c); + + if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS + + || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS + + || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A + + || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION + + || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION + + || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) { + + return true; + + } + + return false; + + } + + + /** + * 上传文件重命名Mos系统 + * + * @return 新的文件名 + */ + public static String fileRenameMos(String prefix, String suffix) { + // 生成唯一的文件名[带前缀以及后缀] + String fileName = (prefix == null ? "" + : prefix.trim()) + UUIDUtils.generatorUUID() + (suffix == null ? "" + : suffix.trim()); + return fileName; + } + + /** + * 上传文件Mos系统 + */ + public static File uploadMos(MultipartFile file, String path) { + try { + // getCanonicalFile 可解析正确各种路径 + File dest = new File(path).getCanonicalFile(); + // 检测是否存在目录 + if (!dest.getParentFile().exists()) { + dest.getParentFile().mkdirs(); + } + // 文件写入 + file.transferTo(dest); + return dest; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public static File uploadMosBase64(String imageStr, String path) { + try { + // getCanonicalFile 可解析正确各种路径 + File dest = new File(path).getCanonicalFile(); + // 检测是否存在目录 + if (!dest.getParentFile().exists()) { + dest.getParentFile().mkdirs(); + } + byte[] bytes=Base64.decode(imageStr); //imageStr.getBytes(); + FileOutputStream fos = new FileOutputStream(dest); + try{ + // 文件写入 + fos.write(bytes,0,bytes.length); + fos.flush(); + }catch (IOException e){ + e.printStackTrace(); + }finally { + fos.close(); + } + return dest; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + /** + * 读取文件,返回文件字符串. + * + * @param in 文件输入流 + * @param encoding 文件编码 + * @return String + */ + public static String readFile(InputStream in, String encoding) { + if (in == null) { + return null; + } + + StringBuffer sb = new StringBuffer(); + InputStreamReader reader = null; + try { + reader = new InputStreamReader(in, encoding); + int tmp = -1; + char temp; + while ((tmp = reader.read()) != -1) { + temp = (char) tmp; + sb.append(temp); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (in != null) { + try { + in.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + return sb.toString(); + } + + /** + * 将inputStream写入文件并关闭inputStream. + * + * @param is 文件输入流 + * @param filePath 文件路径 + * @param append true为追加,false为覆盖 + * @return 是否成功 + */ + public static boolean writeFile(InputStream is, String filePath, + boolean append) { + FileOutputStream fos = null; + try { + if (makeDir(filePath) && is != null) { + fos = new FileOutputStream(filePath, append); + byte[] buffer = new byte[FILE_READ_BTYE * FILE_READ_BTYE]; + // int bytesum = 0; + int byteread = 0; + while ((byteread = is.read(buffer)) != -1) { + // bytesum+=byteread; + fos.write(buffer, 0, byteread); + fos.flush(); + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (is != null) { + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return true; + } + + /** + * 将字符串写入到文件. + * + * @param str 字符串 + * @param filePath 文件路径 + * @param encoding 编码 + * @param append 是否累加 + * @return 是否成功 + */ + public static boolean writeFile(String str, String filePath, + String encoding, boolean append) { + FileOutputStream fos = null; + Writer out = null; + boolean isSucc = false; + try { + if (makeDir(filePath)) { + fos = new FileOutputStream(new File(filePath), append); + out = new OutputStreamWriter(fos, encoding); + out.write(str); + + out.flush(); + out.close(); + + fos.flush(); + fos.close(); + } else { + isSucc = false; + } + isSucc = true; + } catch (IOException e) { + e.printStackTrace(); + isSucc = false; + } finally { + if (fos != null) { + try { + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (out != null) { + try { + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return isSucc; + } + + + + /** + * 根据文件创建目录. + * + * @param file 文件 + * @return 是否成功 + */ + public static boolean makeDir(File file) { + if (!file.exists()) { + makeDir(file.getAbsolutePath()); + } + return true; + } + + /** + * 根据文件名创建目录 + * + * @param fileName + * @return + */ + public static boolean makeDir(String fileName) { + int index = 0; + int index1 = fileName.lastIndexOf("/"); + int index2 = fileName.lastIndexOf("\\"); + if (index1 > index2) { + index = index1; + } else { + index = index2; + } + fileName = fileName.substring(0, index); + File file = new File(fileName); + file.setWritable(true, false); + if (!file.exists()) { + if (!file.mkdirs()) { + return false; + } + } + return true; + } + + /** + * 删除单个文件 。 + * + * @param sPath 被删除文件的文件名 + * @return 单个文件删除成功返回true,否则返回false + */ + public static boolean deleteFile(String sPath) { + Boolean flag = false; + File file = new File(sPath); + // 路径为文件且不为空则进行删除 + if (file.isFile() && file.exists()) { + file.delete(); + flag = true; + } + return flag; + } + + /** + * 删除单个文件 。 + * + * @param file 被删除文件 + * @return 单个文件删除成功返回true,否则返回false + */ + public static boolean deleteFile(File file) { + Boolean flag = false; + // 路径为文件且不为空则进行删除 + if (file.isFile() && file.exists()) { + file.delete(); + flag = true; + } + return flag; + } + + /** + * 删除文件夹。 + * + * @param sPath 文件夹路径 + * @param flags true删除文件夹,false只删除文件夹下的文件 + * @return 是否删除成功 + */ + public static boolean deleteDirectory(String sPath, Boolean flags) { + // 如果sPath不以文件分隔符结尾,自动添加文件分隔符 + if (!sPath.endsWith(File.separator)) { + sPath = sPath + File.separator; + } + File dirFile = new File(sPath); + // 如果dir对应的文件不存在,或者不是一个目录,则退出 + if (!dirFile.exists() || !dirFile.isDirectory()) { + return false; + } + Boolean flag = true; + // 删除文件夹下的所有文件(包括子目录) + File[] files = dirFile.listFiles(); + for (int i = 0; i < files.length; i++) { + // 删除子文件 + if (files[i].isFile()) { + flag = deleteFile(files[i].getAbsolutePath()); + if (!flag) { + break; + } + } else { + // 删除子目录 + flag = deleteDirectory(files[i].getAbsolutePath(), true); + if (!flag) { + break; + } + } + } + if (!flag) { + return false; + } + if (flags) { + // 删除当前目录 + return dirFile.delete(); + } + return true; + } + + + + /** + * inputStream 转 File + */ + static File inputStreamToFile(InputStream ins, String name) throws Exception { + File file = new File(SYS_TEM_DIR + name); + if (file.exists()) { + return file; + } + OutputStream os = new FileOutputStream(file); + int bytesRead; + int len = 8192; + byte[] buffer = new byte[len]; + while ((bytesRead = ins.read(buffer, 0, len)) != -1) { + os.write(buffer, 0, bytesRead); + } + os.close(); + ins.close(); + return file; + } + + /** + * 导出excel + */ + public static void downloadExcel(List> list, HttpServletResponse response) throws IOException { + String tempPath = SYS_TEM_DIR + IdUtil.fastSimpleUUID() + ".xlsx"; + File file = new File(tempPath); + BigExcelWriter writer = ExcelUtil.getBigWriter(file); + // 一次性写出内容,使用默认样式,强制输出标题 + writer.write(list, true); + SXSSFSheet sheet = (SXSSFSheet) writer.getSheet(); + //上面需要强转SXSSFSheet 不然没有trackAllColumnsForAutoSizing方法 + sheet.trackAllColumnsForAutoSizing(); + //列宽自适应 + writer.autoSizeColumnAll(); + //response为HttpServletResponse对象 + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"); + //test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码 + response.setHeader("Content-Disposition", "attachment;filename=file.xlsx"); + ServletOutputStream out = response.getOutputStream(); + // 终止后删除临时文件 + file.deleteOnExit(); + writer.flush(out, true); + //此处记得关闭输出Servlet流 + IoUtil.close(out); + } + + + + + +} diff --git a/bs-ui/src/views/task/template/index.vue b/bs-ui/src/views/task/template/index.vue index 3383538..b8384eb 100644 --- a/bs-ui/src/views/task/template/index.vue +++ b/bs-ui/src/views/task/template/index.vue @@ -245,11 +245,13 @@ import {pageListTemplate, getTemplate, delTemplate, addTemplate, updateTemplate} from "@/api/task/template"; import { listTag } from "@/api/system/tag"; import TagTable from './components/TagSelector' +import Editor from '@/components/Editor' // 假设存在该组件用于任务要求编辑,需确保引入正确 export default { name: "Template", components: { - TagTable + TagTable, + Editor }, dicts: ['task_type'], // 添加字典声明 data() { @@ -296,7 +298,8 @@ export default { taskTitle: null, taskContent: null, remarks: null, - tagIds: [] + tagIds: [], + tags: [] }, // 表单校验 rules: { @@ -360,7 +363,8 @@ export default { taskTitle: null, taskContent: null, remarks: null, - tagIds: [] + tagIds: [], + tags: [] }; this.resetForm("form"); }, @@ -420,13 +424,23 @@ export default { this.$refs["form"].validate(valid => { if (valid) { if (this.form.id!= null) { - updateTemplate(this.form).then(response => { + const tagIds = this.form.tags.map(tag => tag.id); + const updatedForm = { + ...this.form, + tagIds: tagIds + }; + updateTemplate(updatedForm).then(response => { this.$modal.msgSuccess("修改成功"); this.open = false; this.getList(); }); } else { - addTemplate(this.form).then(response => { + const tagIds = this.form.tags.map(tag => tag.id); + const newForm = { + ...this.form, + tagIds: tagIds + }; + addTemplate(newForm).then(response => { this.$modal.msgSuccess("新增成功"); this.open = false; this.getList(); @@ -457,6 +471,7 @@ export default { }; +