feat(bi): 新增工单及派工相关业务指标统计接口
- 增加工单处理状态统计功能,返回未完成数、完成数及平均处理时长 - 实现责任人绩效统计,支持按处理数量或平均时长排序分页返回 - 新增出差天数统计,区分国内外出差并返回人员出差详情 - 增加计划达成率统计,按人员汇总完成情况及计划总数 - 实现人员派工统计,支持分页查询并返回进行中状态及未完成数量 - 添加BIDispatchQuery查询参数,支持按部门、用户名及状态筛选 - 扩展GongfuDispatchService支持BIDispatchQuery的业务数据查询 - ApiResult新增分页数据封装success方法支持分页参数返回 feat(common): 新增HEIC图片格式转换PNG工具及支持 - 新增ImageUtil工具类,通过ImageMagick命令行将HEIC格式图片转换为PNG格式 - 文件上传模块(Admin及CFS)支持HEIC图片自动转换为PNG再上传 - 调整文件格式后缀统一为小写,处理HEIC上传时文件类型自动换为.png - 移除对commons-imaging和imageio-heif依赖,改用外部ImageMagick工具实现转换 - 增加readme.md说明服务器需安装ImageMagick以及HEIC支持相关环境依赖和源码编译步骤 fix(dispatch): 修正派工相关编码及消息通知中派工单编号字段 - 派工单编码统一使用code字段替代原no字段用于消息通知及文件关联 - 去除DispatchAddRequest中deviceNo的@NotBlank注解,添加手动校验规则 - 优化DispatchController,新增机台编号非空校验逻辑 - 修复部分代码重复设置CurrentHandle现象,确保责任人数据准确传递 refactor(common): 细节优化及代码规范调整 - DateTimeUtil新增日期差计算及字符串解析方法 - DeviceVO添加客户名称属性,设备查询接口支持按设备名称模糊搜索 - API请求与返回VO新增及规范化,实现各统计视图对应VO结构 - 优化分页查询基础类PageBaseQuery格式及默认值设置 - 文件上传相关异常处理及流关闭逻辑完善,统一代码风格及格式 - GongfuTicketServiceImpl修正责任人ID设置,确保工单处理流程数据一致性
This commit is contained in:
parent
73e4f4d0ee
commit
fe9b485b66
|
|
@ -141,17 +141,6 @@
|
|||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!--处理heic图片文件-->
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-imaging</artifactId>
|
||||
<version>1.0.0-alpha6</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.gotson.nightmonkeys</groupId>
|
||||
<artifactId>imageio-heif</artifactId>
|
||||
<version>1.1.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import com.nflg.mobilebroken.common.pojo.vo.FileUploadVO;
|
|||
import com.nflg.mobilebroken.common.pojo.vo.FileVO;
|
||||
import com.nflg.mobilebroken.common.util.AdminUserUtil;
|
||||
import com.nflg.mobilebroken.common.util.DateTimeUtil;
|
||||
import com.nflg.mobilebroken.common.util.ImageUtil;
|
||||
import com.nflg.mobilebroken.common.util.VUtils;
|
||||
import com.nflg.mobilebroken.repository.entity.FileUploadRecord;
|
||||
import com.nflg.mobilebroken.repository.service.IFileUploadRecordService;
|
||||
|
|
@ -22,7 +23,6 @@ import com.nflg.mobilebroken.starter.service.FileUploadService;
|
|||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import org.apache.commons.imaging.Imaging;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
|
|
@ -32,13 +32,14 @@ import org.springframework.web.bind.annotation.*;
|
|||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.*;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.LocalDateTime;
|
||||
|
|
@ -89,7 +90,7 @@ public class FileController extends ControllerBase {
|
|||
InputStream is;
|
||||
if (fileType.equals(".heic")) {
|
||||
is = convertHeic(file);
|
||||
fileType = ".jpg";
|
||||
fileType = ".png";
|
||||
} else {
|
||||
is = file.getInputStream();
|
||||
}
|
||||
|
|
@ -103,11 +104,7 @@ public class FileController extends ControllerBase {
|
|||
}
|
||||
|
||||
private InputStream convertHeic(MultipartFile file) throws IOException {
|
||||
BufferedImage image = Imaging.getBufferedImage(file.getBytes());
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
ImageIO.write(image, "PNG", outputStream);
|
||||
byte[] imageBytes = outputStream.toByteArray();
|
||||
return new ByteArrayInputStream(imageBytes);
|
||||
return new ByteArrayInputStream(ImageUtil.heicToPng(file.getBytes()));
|
||||
}
|
||||
|
||||
private String buildFilePath(String fileType) {
|
||||
|
|
@ -136,7 +133,7 @@ public class FileController extends ControllerBase {
|
|||
InputStream is;
|
||||
if (fileType.equals(".heic")) {
|
||||
is = convertHeic(file);
|
||||
fileType = ".jpg";
|
||||
fileType = ".png";
|
||||
} else {
|
||||
is = file.getInputStream();
|
||||
}
|
||||
|
|
@ -169,7 +166,7 @@ public class FileController extends ControllerBase {
|
|||
}
|
||||
|
||||
private String getFileType(String fileName) {
|
||||
return "." + FilenameUtils.getExtension(fileName);
|
||||
return "." + FilenameUtils.getExtension(fileName).toLowerCase();
|
||||
}
|
||||
|
||||
private FileUploadRecord buildFileUploadRecord(Byte source, Long sourceId, String fileName, String fileType, String url) {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import com.nflg.mobilebroken.common.exception.NflgException;
|
|||
import com.nflg.mobilebroken.common.pojo.ApiResult;
|
||||
import com.nflg.mobilebroken.common.pojo.vo.FileUploadVO;
|
||||
import com.nflg.mobilebroken.common.util.AppUserUtil;
|
||||
import com.nflg.mobilebroken.common.util.ImageUtil;
|
||||
import com.nflg.mobilebroken.common.util.SaTokenAppUtil;
|
||||
import com.nflg.mobilebroken.repository.entity.FileUploadRecord;
|
||||
import com.nflg.mobilebroken.repository.service.IFileUploadRecordService;
|
||||
|
|
@ -23,6 +24,9 @@ import javax.annotation.Resource;
|
|||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -59,7 +63,14 @@ public class FileController extends ControllerBase {
|
|||
try {
|
||||
String fileName = file.getOriginalFilename();
|
||||
String fileType = getFileType(fileName);
|
||||
String url = fileUploadService.upload(buildFilePath(fileType), file);
|
||||
InputStream is;
|
||||
if (fileType.equals(".heic")) {
|
||||
is = convertHeic(file);
|
||||
fileType = ".png";
|
||||
} else {
|
||||
is = file.getInputStream();
|
||||
}
|
||||
String url = fileUploadService.upload(buildFilePath(fileType), is);
|
||||
FileUploadRecord record = buildFileUploadRecord(source, sourceId, fileName, fileType, url);
|
||||
fileUploadRecordService.save(record);
|
||||
return ApiResult.success(new FileUploadVO(record.getId(), fileName, url, file.getSize()));
|
||||
|
|
@ -68,6 +79,10 @@ public class FileController extends ControllerBase {
|
|||
}
|
||||
}
|
||||
|
||||
private InputStream convertHeic(MultipartFile file) throws IOException {
|
||||
return new ByteArrayInputStream(ImageUtil.heicToPng(file.getBytes()));
|
||||
}
|
||||
|
||||
private String buildFilePath(String fileType) {
|
||||
if (SaTokenAppUtil.isLogin()) {
|
||||
return StrUtil.format("cfs/{}/{}/{}/{}{}", LocalDateTime.now().format(FORMATTER)
|
||||
|
|
@ -94,7 +109,14 @@ public class FileController extends ControllerBase {
|
|||
for (MultipartFile file : files) {
|
||||
String fileName = file.getOriginalFilename();
|
||||
String fileType = getFileType(fileName);
|
||||
String url = fileUploadService.upload(buildFilePath(fileType), file);
|
||||
InputStream is;
|
||||
if (fileType.equals(".heic")) {
|
||||
is = convertHeic(file);
|
||||
fileType = ".png";
|
||||
} else {
|
||||
is = file.getInputStream();
|
||||
}
|
||||
String url = fileUploadService.upload(buildFilePath(fileType), is);
|
||||
FileUploadRecord record = buildFileUploadRecord(source, sourceId, fileName, fileType, url);
|
||||
fileUploadRecordService.save(record);
|
||||
list.add(new FileUploadVO(record.getId(), fileName, url, file.getSize()));
|
||||
|
|
@ -123,7 +145,7 @@ public class FileController extends ControllerBase {
|
|||
}
|
||||
|
||||
private String getFileType(String fileName) {
|
||||
return "." + FilenameUtils.getExtension(fileName);
|
||||
return "." + FilenameUtils.getExtension(fileName).toLowerCase();
|
||||
}
|
||||
|
||||
private FileUploadRecord buildFileUploadRecord(Byte source, Long sourceId, String fileName, String fileType, String url) {
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ public class ApiResult<T> implements Serializable {
|
|||
return vo;
|
||||
}
|
||||
|
||||
|
||||
public static <T> ApiResult<T> error(int state,String msg,T value) {
|
||||
ApiResult<T> vo = new ApiResult<>();
|
||||
vo.result = value;
|
||||
|
|
@ -101,4 +100,17 @@ public class ApiResult<T> implements Serializable {
|
|||
public static <T> ApiResult<T> error(int msgCode, String msg) {
|
||||
return error(msgCode, msg, msg);
|
||||
}
|
||||
|
||||
public static <T> ApiResult<PageData<T>> success(Collection<T> datas, int pageIndex, int pageSize) {
|
||||
ApiResult<PageData<T>> vo = new ApiResult<>();
|
||||
PageData<T> pageData = new PageData<>();
|
||||
pageData.setPage(pageIndex);
|
||||
pageData.setPageSize(pageSize);
|
||||
pageData.setTotal(datas.size());
|
||||
pageData.setItems(datas);
|
||||
vo.setCode(STATE.Success.getState());
|
||||
vo.setType(STATE.Success.getType());
|
||||
vo.setResult(pageData);
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
package com.nflg.mobilebroken.common.pojo.query;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class BIDispatchQuery extends BIBaseQuery {
|
||||
|
||||
/**
|
||||
* 部门id
|
||||
*/
|
||||
private Long deptId;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
@JsonIgnore
|
||||
private List<Integer> states = List.of(2);
|
||||
|
||||
private Integer page = 1;
|
||||
|
||||
private Integer pageSize = 20;
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.nflg.mobilebroken.common.pojo.query;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class HandlePerformanceQuery extends BIBaseQuery {
|
||||
|
||||
/**
|
||||
* 排序方式,0:处理数量;1:平均处理时长
|
||||
*/
|
||||
private Integer sortType = 0;
|
||||
|
||||
private Integer page = 1;
|
||||
|
||||
private Integer pageSize = 20;
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ import lombok.Data;
|
|||
@Data
|
||||
public class PageBaseQuery {
|
||||
|
||||
private Integer page=1;
|
||||
private Integer page = 1;
|
||||
|
||||
private Integer pageSize=20;
|
||||
private Integer pageSize = 20;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ public class DispatchAddRequest {
|
|||
/**
|
||||
* 设备编号
|
||||
*/
|
||||
@NotBlank
|
||||
private String deviceNo;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -26,4 +26,7 @@ public class SearchDeviceRequest extends PageRequest {
|
|||
|
||||
//客户名称
|
||||
private String customerName;
|
||||
|
||||
//设备名称
|
||||
private String deviceName;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
package com.nflg.mobilebroken.common.pojo.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class DaysOnBusinessTripVO {
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 处理人
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 国内出差天数
|
||||
*/
|
||||
private int daysForInternal;
|
||||
|
||||
/**
|
||||
* 国外出差天数
|
||||
*/
|
||||
private int daysForForeign;
|
||||
|
||||
/**
|
||||
* 总出差天数
|
||||
*/
|
||||
private int totalDays;
|
||||
|
||||
public int getTotalDays() {
|
||||
return daysForInternal + daysForForeign;
|
||||
}
|
||||
}
|
||||
|
|
@ -26,4 +26,7 @@ public class DeviceVO {
|
|||
|
||||
// 销售日期
|
||||
private LocalDate shipmentDate;
|
||||
|
||||
// 客户名称
|
||||
private String customerName;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,74 @@
|
|||
package com.nflg.mobilebroken.common.pojo.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Accessors(chain = true)
|
||||
public class HandlePerformanceVO {
|
||||
|
||||
/**
|
||||
* 处理人
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 工单数量
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
private Integer total = 0;
|
||||
|
||||
/**
|
||||
* 工单完成率
|
||||
*/
|
||||
private String completionRate;
|
||||
|
||||
public String getCompletionRate() {
|
||||
if (total == 0) {
|
||||
return "0";
|
||||
}
|
||||
double rate = (double) completes * 100 / total;
|
||||
return String.format("%.2f", rate).replaceAll("\\.?0+$", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 工单处理平均时长,单位:小时
|
||||
*/
|
||||
private String averageProcessingTime;
|
||||
|
||||
public String getAverageProcessingTime() {
|
||||
if (completes == 0) {
|
||||
return "0";
|
||||
}
|
||||
double rate = (double) processingTime / completes / 60.0;
|
||||
return String.format("%.2f", rate).replaceAll("\\.?0+$", "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@JsonIgnore
|
||||
private Integer userId;
|
||||
|
||||
/**
|
||||
* 已完成工单数量
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@JsonIgnore
|
||||
private int completes = 0;
|
||||
|
||||
/**
|
||||
* 工单处理时长,单位:分钟
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@JsonIgnore
|
||||
private long processingTime = 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package com.nflg.mobilebroken.common.pojo.vo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class PlanAchievementRateVO {
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 处理人
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 计划完成率
|
||||
*/
|
||||
private int planAchievementRate;
|
||||
|
||||
public int getPlanAchievementRate() {
|
||||
if (total == 0) {
|
||||
return 0;
|
||||
}
|
||||
return completes * 100 / total;
|
||||
}
|
||||
|
||||
/**
|
||||
* 总工单数量
|
||||
*/
|
||||
@JsonIgnore
|
||||
private int total;
|
||||
|
||||
/**
|
||||
* 已完成工单数量
|
||||
*/
|
||||
@JsonIgnore
|
||||
private int completes;
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.nflg.mobilebroken.common.pojo.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class StateStatisticsVO {
|
||||
|
||||
/**
|
||||
* 未完成工单数量
|
||||
*/
|
||||
private int unaccomplished;
|
||||
|
||||
/**
|
||||
* 已完成工单数量
|
||||
*/
|
||||
private int completes;
|
||||
|
||||
/**
|
||||
* 总工单数量
|
||||
*/
|
||||
private int total;
|
||||
|
||||
public int getTotal() {
|
||||
return unaccomplished + completes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 工单处理平均时长,单位:小时
|
||||
*/
|
||||
private Double averageProcessingTime;
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.nflg.mobilebroken.common.pojo.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class UserStatisticsVO {
|
||||
|
||||
/**
|
||||
* 用户id
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 处理人
|
||||
*/
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 产品线
|
||||
*/
|
||||
private String productLine;
|
||||
|
||||
/**
|
||||
* 当前是否在派工中
|
||||
*/
|
||||
private boolean inProgress;
|
||||
|
||||
/**
|
||||
* 最近一次派工时间
|
||||
*/
|
||||
private String recentDispatchTime;
|
||||
|
||||
/**
|
||||
* 未完成工单数量
|
||||
*/
|
||||
private int unfinishedNum;
|
||||
}
|
||||
|
|
@ -7,35 +7,36 @@ import java.time.LocalDateTime;
|
|||
import java.time.ZoneId;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Objects;
|
||||
|
||||
public class DateTimeUtil {
|
||||
|
||||
private static final DateTimeFormatter FORMATTER=DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN);
|
||||
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN);
|
||||
|
||||
public static String format(LocalDateTime dateTime){
|
||||
if (Objects.isNull(dateTime)){
|
||||
public static String format(LocalDateTime dateTime) {
|
||||
if (Objects.isNull(dateTime)) {
|
||||
return "";
|
||||
}
|
||||
return dateTime.format(FORMATTER);
|
||||
}
|
||||
|
||||
public static String format(LocalDateTime dateTime,String pattern){
|
||||
if (Objects.isNull(dateTime)){
|
||||
public static String format(LocalDateTime dateTime, String pattern) {
|
||||
if (Objects.isNull(dateTime)) {
|
||||
return "";
|
||||
}
|
||||
return dateTime.format(DateTimeFormatter.ofPattern(pattern));
|
||||
}
|
||||
|
||||
public static String format(LocalDate date,String pattern){
|
||||
if (Objects.isNull(date)){
|
||||
public static String format(LocalDate date, String pattern) {
|
||||
if (Objects.isNull(date)) {
|
||||
return "";
|
||||
}
|
||||
return date.format(DateTimeFormatter.ofPattern(pattern));
|
||||
}
|
||||
|
||||
public static LocalDate asSystemDate(LocalDate date){
|
||||
if (Objects.isNull(date)){
|
||||
public static LocalDate asSystemDate(LocalDate date) {
|
||||
if (Objects.isNull(date)) {
|
||||
return null;
|
||||
}
|
||||
return date.atStartOfDay(ZoneOffset.UTC)
|
||||
|
|
@ -43,12 +44,20 @@ public class DateTimeUtil {
|
|||
.toLocalDate();
|
||||
}
|
||||
|
||||
public static LocalDateTime asSystemDateTime(LocalDateTime datetime){
|
||||
if (Objects.isNull(datetime)){
|
||||
public static LocalDateTime asSystemDateTime(LocalDateTime datetime) {
|
||||
if (Objects.isNull(datetime)) {
|
||||
return null;
|
||||
}
|
||||
return datetime.atZone(ZoneOffset.UTC)
|
||||
.withZoneSameInstant(ZoneId.systemDefault())
|
||||
.toLocalDateTime();
|
||||
}
|
||||
|
||||
public static LocalDate parse(String dateStr) {
|
||||
return LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN));
|
||||
}
|
||||
|
||||
public static int between(LocalDate date1, LocalDate date2) {
|
||||
return (int) ChronoUnit.DAYS.between(date1, date2) + 1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
package com.nflg.mobilebroken.common.util;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class ImageUtil {
|
||||
|
||||
public static byte[] heicToPng(byte[] heicBytes) throws IOException {
|
||||
ProcessBuilder pb = new ProcessBuilder("magick", "-", "png:-");
|
||||
Process process = pb.start();
|
||||
try (OutputStream stdin = process.getOutputStream();
|
||||
InputStream stdout = process.getInputStream();
|
||||
InputStream stderr = process.getErrorStream()) {
|
||||
// 4. 在单独的线程中读取标准错误,防止缓冲区填满导致死锁
|
||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
Future<String> stderrFuture = executor.submit(() -> readStreamAsString(stderr));
|
||||
executor.shutdown(); // 不再接受新任务
|
||||
// 5. 将HEIC字节数组写入到进程的标准输入
|
||||
stdin.write(heicBytes);
|
||||
stdin.flush(); // 确保数据被写入
|
||||
stdin.close(); // 关闭输入流,表示输入结束
|
||||
// 6. 从进程的标准输出读取转换后的PNG数据
|
||||
ByteArrayOutputStream pngBuffer = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[8192]; // 8KB 缓冲区
|
||||
int bytesRead;
|
||||
while ((bytesRead = stdout.read(buffer)) != -1) {
|
||||
pngBuffer.write(buffer, 0, bytesRead);
|
||||
}
|
||||
// 7. 等待进程执行完成
|
||||
int exitCode = process.waitFor();
|
||||
// 8. 检查退出码,如果不为0,说明转换失败
|
||||
if (exitCode != 0) {
|
||||
// 获取错误信息
|
||||
String errorOutput = stderrFuture.get(5, TimeUnit.SECONDS);
|
||||
throw new IOException("ImageMagick conversion failed with exit code " + exitCode + ".\nError: " + errorOutput);
|
||||
}
|
||||
|
||||
return pngBuffer.toByteArray();
|
||||
} catch (Exception e) {
|
||||
// 确保进程被销毁
|
||||
process.destroyForcibly();
|
||||
throw new IOException("HEIC转换失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String readStreamAsString(InputStream inputStream) throws IOException {
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
stringBuilder.append(line).append(System.lineSeparator());
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,21 @@
|
|||
package com.nflg.mobilebroken.gongfu.controller;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||
import com.nflg.mobilebroken.common.constant.TicketState;
|
||||
import com.nflg.mobilebroken.common.pojo.ApiResult;
|
||||
import com.nflg.mobilebroken.common.pojo.PageData;
|
||||
import com.nflg.mobilebroken.common.pojo.query.BIBaseQuery;
|
||||
import com.nflg.mobilebroken.common.pojo.query.BIDispatchQuery;
|
||||
import com.nflg.mobilebroken.common.pojo.query.EquipmentFailureRankingSearchQuery;
|
||||
import com.nflg.mobilebroken.common.pojo.vo.EquipmentFailureRankingVO;
|
||||
import com.nflg.mobilebroken.common.pojo.query.HandlePerformanceQuery;
|
||||
import com.nflg.mobilebroken.common.pojo.vo.*;
|
||||
import com.nflg.mobilebroken.common.util.DateTimeUtil;
|
||||
import com.nflg.mobilebroken.repository.entity.AdminUser;
|
||||
import com.nflg.mobilebroken.repository.entity.GongfuDispatch;
|
||||
import com.nflg.mobilebroken.repository.entity.GongfuTicket;
|
||||
import com.nflg.mobilebroken.repository.service.IAdminUserService;
|
||||
import com.nflg.mobilebroken.repository.service.IGongfuDispatchService;
|
||||
import com.nflg.mobilebroken.repository.service.IGongfuTicketService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
|
|
@ -15,7 +25,11 @@ import org.springframework.web.bind.annotation.RestController;
|
|||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
|
|
@ -29,6 +43,12 @@ public class BiController extends ControllerBase {
|
|||
@Resource
|
||||
private IGongfuTicketService ticketService;
|
||||
|
||||
@Resource
|
||||
private IAdminUserService adminUserService;
|
||||
|
||||
@Resource
|
||||
private IGongfuDispatchService dispatchService;
|
||||
|
||||
/**
|
||||
* 设备故障排名
|
||||
*/
|
||||
|
|
@ -37,16 +57,184 @@ public class BiController extends ControllerBase {
|
|||
return ApiResult.success(ticketService.getEquipmentFailureRanking(qo));
|
||||
}
|
||||
|
||||
public ApiResult getStateStatistics(@Valid @RequestBody BIBaseQuery qo) {
|
||||
List<GongfuTicket> datas = ticketService.lambdaQuery()
|
||||
/**
|
||||
* 工单处理状态
|
||||
*/
|
||||
@PostMapping("ticket/getStateStatistics")
|
||||
public ApiResult<StateStatisticsVO> getStateStatistics(@Valid @RequestBody BIBaseQuery qo) {
|
||||
long unaccomplished = ticketService.lambdaQuery()
|
||||
.ne(GongfuTicket::getState, TicketState.Revoked.getState())
|
||||
.lt(GongfuTicket::getState, TicketState.ProcessingCompleted.getState())
|
||||
.ge(GongfuTicket::getCreateTime, qo.getStartDate())
|
||||
.lt(GongfuTicket::getCreateTime, qo.getEndDate())
|
||||
.count();
|
||||
List<GongfuTicket> completes = ticketService.lambdaQuery()
|
||||
.select(GongfuTicket::getCreateTime, GongfuTicket::getSolveTime)
|
||||
.ne(GongfuTicket::getState, TicketState.Revoked.getState())
|
||||
.in(GongfuTicket::getState, List.of(TicketState.ProcessingCompleted.getState(), TicketState.Closed.getState()))
|
||||
.ge(GongfuTicket::getCreateTime, qo.getStartDate())
|
||||
.lt(GongfuTicket::getCreateTime, qo.getEndDate())
|
||||
.list();
|
||||
List<GongfuTicket> completes = datas.stream()
|
||||
.filter(it -> it.getState() >= TicketState.ProcessingCompleted.getState())
|
||||
.collect(Collectors.toList());
|
||||
StateStatisticsVO vo = new StateStatisticsVO()
|
||||
.setUnaccomplished((int) unaccomplished)
|
||||
.setCompletes(completes.size())
|
||||
.setAverageProcessingTime(completes.stream()
|
||||
.map(t -> LocalDateTimeUtil.between(t.getCreateTime(), t.getSolveTime(), ChronoUnit.MINUTES) / 60.0)
|
||||
.mapToDouble(Double::doubleValue)
|
||||
.average()
|
||||
.orElse(0)
|
||||
);
|
||||
return ApiResult.success(vo);
|
||||
}
|
||||
|
||||
return ApiResult.success();
|
||||
/**
|
||||
* 责任人绩效
|
||||
*/
|
||||
@PostMapping("ticket/getHandlePerformance")
|
||||
public ApiResult<PageData<HandlePerformanceVO>> getHandlePerformance(@Valid @RequestBody HandlePerformanceQuery qo) {
|
||||
List<GongfuTicket> tickets = ticketService.lambdaQuery()
|
||||
.select(GongfuTicket::getCurrentHandle, GongfuTicket::getState, GongfuTicket::getCreateTime, GongfuTicket::getSolveTime)
|
||||
.notIn(GongfuTicket::getState, List.of(TicketState.Revoked.getState(), TicketState.PendingProcessing.getState()))
|
||||
.ge(GongfuTicket::getCreateTime, qo.getStartDate())
|
||||
.lt(GongfuTicket::getCreateTime, qo.getEndDate())
|
||||
.list();
|
||||
if (CollectionUtil.isEmpty(tickets)) {
|
||||
return ApiResult.success(new PageData<>());
|
||||
}
|
||||
List<AdminUser> users = adminUserService.lambdaQuery()
|
||||
.in(AdminUser::getId, tickets.stream().map(GongfuTicket::getCurrentHandle).collect(Collectors.toSet()))
|
||||
.list();
|
||||
List<HandlePerformanceVO> vos = new ArrayList<>();
|
||||
tickets.forEach(ticket -> {
|
||||
HandlePerformanceVO vo = vos.stream()
|
||||
.filter(v -> Objects.equals(v.getUserId(), ticket.getCurrentHandle()))
|
||||
.findFirst()
|
||||
.orElseGet(() -> {
|
||||
HandlePerformanceVO v = new HandlePerformanceVO()
|
||||
.setUserId(ticket.getCurrentHandle())
|
||||
.setUserName(users.stream()
|
||||
.filter(user -> Objects.equals(user.getId(), ticket.getCurrentHandle()))
|
||||
.findFirst()
|
||||
.orElse(new AdminUser().setUserName("无效用户"))
|
||||
.getUserName()
|
||||
);
|
||||
vos.add(v);
|
||||
return v;
|
||||
});
|
||||
vo.setTotal(vo.getTotal() + 1);
|
||||
if (Objects.equals(TicketState.ProcessingCompleted.getState(), ticket.getState())
|
||||
|| Objects.equals(TicketState.Closed.getState(), ticket.getState())) {
|
||||
vo.setCompletes(vo.getCompletes() + 1);
|
||||
vo.setProcessingTime(vo.getProcessingTime() + LocalDateTimeUtil.between(ticket.getCreateTime(), ticket.getSolveTime(), ChronoUnit.MINUTES));
|
||||
}
|
||||
});
|
||||
if (qo.getSortType() == 0) {
|
||||
vos.sort(Comparator.comparingInt(HandlePerformanceVO::getTotal).reversed());
|
||||
} else if (qo.getSortType() == 1) {
|
||||
vos.sort(Comparator.comparing(HandlePerformanceVO::getAverageProcessingTime));
|
||||
}
|
||||
return ApiResult.success(vos, qo.getPage(), qo.getPageSize());
|
||||
}
|
||||
|
||||
/**
|
||||
* 出差天数
|
||||
*/
|
||||
@PostMapping("dispatch/getDaysOnBusinessTrip")
|
||||
public ApiResult<List<DaysOnBusinessTripVO>> getDaysOnBusinessTrip(@Valid @RequestBody BIDispatchQuery qo) {
|
||||
List<GongfuDispatch> dispatches = dispatchService.getForBI(qo);
|
||||
return ApiResult.success(dispatches.stream()
|
||||
.collect(Collectors.groupingBy(GongfuDispatch::getHandlerUserId))
|
||||
.values()
|
||||
.stream()
|
||||
.map(ds -> new DaysOnBusinessTripVO()
|
||||
.setUserId(ds.get(0).getHandlerUserId())
|
||||
.setUserName(ds.get(0).getHandlerUserName())
|
||||
.setDaysForInternal(ds.stream()
|
||||
.filter(d -> Objects.equals(d.getCategory(), 0))
|
||||
.map(d -> DateTimeUtil.between(DateTimeUtil.parse(d.getPlanStartDate()), DateTimeUtil.parse(d.getPlanEndDate())))
|
||||
.mapToInt(Integer::intValue)
|
||||
.sum()
|
||||
)
|
||||
.setDaysForForeign(ds.stream()
|
||||
.filter(d -> Objects.equals(d.getCategory(), 1))
|
||||
.map(d -> DateTimeUtil.between(DateTimeUtil.parse(d.getPlanStartDate()), DateTimeUtil.parse(d.getPlanEndDate())))
|
||||
.mapToInt(Integer::intValue)
|
||||
.sum()
|
||||
))
|
||||
.sorted(Comparator.comparingInt(DaysOnBusinessTripVO::getTotalDays).reversed())
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计划达成率
|
||||
*/
|
||||
@PostMapping("dispatch/getPlanAchievementRate")
|
||||
public ApiResult<List<PlanAchievementRateVO>> getPlanAchievementRate(@Valid @RequestBody BIDispatchQuery qo) {
|
||||
qo.setStates(List.of(1, 2));
|
||||
List<GongfuDispatch> dispatches = dispatchService.getForBI(qo);
|
||||
return ApiResult.success(dispatches.stream()
|
||||
.collect(Collectors.groupingBy(GongfuDispatch::getHandlerUserId))
|
||||
.values()
|
||||
.stream()
|
||||
.map(ds -> new PlanAchievementRateVO()
|
||||
.setUserId(ds.get(0).getHandlerUserId())
|
||||
.setUserName(ds.get(0).getHandlerUserName())
|
||||
.setTotal(ds.size())
|
||||
.setCompletes(Math.toIntExact(ds.stream()
|
||||
.filter(d -> Objects.equals(d.getState(), 2))
|
||||
.count()
|
||||
)
|
||||
)
|
||||
)
|
||||
.sorted(Comparator.comparingInt(PlanAchievementRateVO::getPlanAchievementRate).reversed())
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 人员派工统计
|
||||
*/
|
||||
@PostMapping("dispatch/getUserStatistics")
|
||||
public ApiResult<PageData<UserStatisticsVO>> getUserStatistics(@Valid @RequestBody BIDispatchQuery qo) {
|
||||
qo.setStates(List.of(1));
|
||||
List<GongfuDispatch> dispatches = dispatchService.getForBI(qo);
|
||||
if (CollectionUtil.isEmpty(dispatches)) {
|
||||
return ApiResult.success(new PageData<>());
|
||||
}
|
||||
List<AdminUser> users = adminUserService.lambdaQuery()
|
||||
.in(AdminUser::getId, dispatches.stream().map(GongfuDispatch::getHandlerUserId).collect(Collectors.toSet()))
|
||||
.list();
|
||||
List<UserStatisticsVO> vos = dispatches.stream()
|
||||
.collect(Collectors.groupingBy(GongfuDispatch::getHandlerUserId))
|
||||
.values()
|
||||
.stream()
|
||||
.map(ds -> new UserStatisticsVO()
|
||||
.setUserId(ds.get(0).getHandlerUserId())
|
||||
.setUserName(ds.get(0).getHandlerUserName())
|
||||
.setProductLine(
|
||||
users.stream()
|
||||
.filter(user -> Objects.equals(user.getId(), Math.toIntExact(ds.get(0).getHandlerUserId())))
|
||||
.findFirst()
|
||||
.orElse(new AdminUser().setUserName("无效用户"))
|
||||
.getProductLine()
|
||||
)
|
||||
.setInProgress(ds.stream().anyMatch(d -> Objects.equals(d.getState(), 1)))
|
||||
.setRecentDispatchTime(
|
||||
ds.stream()
|
||||
.filter(d -> Objects.equals(d.getState(), 1))
|
||||
.max(Comparator.comparing(GongfuDispatch::getPlanStartDate))
|
||||
.map(GongfuDispatch::getPlanStartDate)
|
||||
.orElse("")
|
||||
)
|
||||
.setUnfinishedNum(
|
||||
Math.toIntExact(ds.stream()
|
||||
.filter(d -> Objects.equals(d.getState(), 1))
|
||||
.count())
|
||||
)
|
||||
)
|
||||
.sorted(Comparator.comparingInt(UserStatisticsVO::getUnfinishedNum).reversed())
|
||||
.collect(Collectors.toList());
|
||||
return ApiResult.success(vos, qo.getPage(), qo.getPageSize());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.nflg.mobilebroken.gongfu.controller;
|
|||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.nflg.mobilebroken.common.constant.MessageSubType;
|
||||
import com.nflg.mobilebroken.common.constant.MessageType;
|
||||
|
|
@ -67,6 +68,8 @@ public class DispatchController extends ControllerBase {
|
|||
*/
|
||||
@PostMapping("/add")
|
||||
public ApiResult<Void> add(@Valid @RequestBody DispatchAddRequest request) {
|
||||
VUtils.trueThrowBusinessError(!Objects.equals(request.getType(), 4) && StrUtil.isBlank(request.getDeviceNo()))
|
||||
.throwMessage("机台编号需必填");
|
||||
GongfuDispatch dispatch = new GongfuDispatch()
|
||||
.setTitle(request.getTitle())
|
||||
.setType(request.getType())
|
||||
|
|
@ -180,7 +183,7 @@ public class DispatchController extends ControllerBase {
|
|||
.map(it -> new GongfuFile()
|
||||
.setType(0)
|
||||
.setSourceId(dispatch.getId())
|
||||
.setNo(dispatch.getNo())
|
||||
.setNo(dispatch.getCode())
|
||||
.setFileName(it.getFileName())
|
||||
.setFileUrl(it.getUrl())
|
||||
.setFileSuffix(FilenameUtils.getExtension(it.getFileName()))
|
||||
|
|
|
|||
|
|
@ -1474,6 +1474,7 @@ public class TicketController extends ControllerBase {
|
|||
images = fileUploadRecordService.lambdaQuery()
|
||||
.eq(FileUploadRecord::getSource, (byte) 0)
|
||||
.eq(FileUploadRecord::getSourceId, id)
|
||||
.in(FileUploadRecord::getFileType, List.of(".jpg", ".png", ".heic", ".jpeg", ".webp"))
|
||||
.list();
|
||||
if (CollectionUtil.isEmpty(images)) {
|
||||
return ApiResult.success(Collections.emptyList());
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ public class DispatchApplyforEvent extends ApplicationEvent implements Applicati
|
|||
GongfuDispatch dispatch = dispatchService.getById(applyfor.getTicketId());
|
||||
adminMessageService.add(
|
||||
new AdminMessage()
|
||||
.setNo(dispatch.getNo())
|
||||
.setNo(dispatch.getCode())
|
||||
.setTitle(dispatch.getTitle())
|
||||
.setUserId(dispatch.getCreateById())
|
||||
.setSourceId(applyfor.getId())
|
||||
|
|
|
|||
|
|
@ -3,10 +3,13 @@ package com.nflg.mobilebroken.repository.mapper;
|
|||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.nflg.mobilebroken.common.pojo.query.BIDispatchQuery;
|
||||
import com.nflg.mobilebroken.common.pojo.request.DispatchSearchRequest;
|
||||
import com.nflg.mobilebroken.common.pojo.vo.DispatchVO;
|
||||
import com.nflg.mobilebroken.repository.entity.GongfuDispatch;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 派工单 Mapper 接口
|
||||
|
|
@ -19,4 +22,6 @@ public interface GongfuDispatchMapper extends BaseMapper<GongfuDispatch> {
|
|||
IPage<DispatchVO> search(DispatchSearchRequest request, Page<?> objectPage);
|
||||
|
||||
DispatchVO getInfo(Long id);
|
||||
|
||||
List<GongfuDispatch> getForBI(BIDispatchQuery qo);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,13 @@ package com.nflg.mobilebroken.repository.service;
|
|||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.nflg.mobilebroken.common.pojo.query.BIDispatchQuery;
|
||||
import com.nflg.mobilebroken.common.pojo.request.DispatchSearchRequest;
|
||||
import com.nflg.mobilebroken.common.pojo.vo.DispatchVO;
|
||||
import com.nflg.mobilebroken.repository.entity.GongfuDispatch;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 派工单 服务类
|
||||
|
|
@ -20,4 +23,6 @@ public interface IGongfuDispatchService extends IService<GongfuDispatch> {
|
|||
DispatchVO getInfo(Long id);
|
||||
|
||||
String getMaxCode();
|
||||
|
||||
List<GongfuDispatch> getForBI(BIDispatchQuery qo);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.nflg.mobilebroken.repository.service.impl;
|
|||
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.nflg.mobilebroken.common.pojo.query.BIDispatchQuery;
|
||||
import com.nflg.mobilebroken.common.pojo.request.DispatchSearchRequest;
|
||||
import com.nflg.mobilebroken.common.pojo.vo.DispatchVO;
|
||||
import com.nflg.mobilebroken.repository.entity.GongfuDispatch;
|
||||
|
|
@ -10,6 +11,7 @@ import com.nflg.mobilebroken.repository.mapper.GongfuDispatchMapper;
|
|||
import com.nflg.mobilebroken.repository.service.IGongfuDispatchService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
|
|
@ -41,4 +43,9 @@ public class GongfuDispatchServiceImpl extends ServiceImpl<GongfuDispatchMapper,
|
|||
return dispatch.getCode();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GongfuDispatch> getForBI(BIDispatchQuery qo) {
|
||||
return baseMapper.getForBI(qo);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ public class GongfuTicketServiceImpl extends ServiceImpl<GongfuTicketMapper, Gon
|
|||
ticket.setCurrentHandle(request.getHandlerUserId());
|
||||
ticket.setHandle(String.valueOf(request.getHandlerUserId()));
|
||||
ticket.setHandleName(request.getHandlerUserName());
|
||||
ticket.setCurrentHandle(request.getHandlerUserId());
|
||||
ticket.setUrgency(request.getUrgency());
|
||||
ticket.setState(TicketState.Processing.getState());
|
||||
}
|
||||
|
|
@ -222,7 +223,7 @@ public class GongfuTicketServiceImpl extends ServiceImpl<GongfuTicketMapper, Gon
|
|||
ticket.setHandle(StrUtil.join(",", request.getUserIds()));
|
||||
ticket.setHandleName(StrUtil.join(",", adminUserService.getSimples(request.getUserIds()).stream().map(AdminUserSimpleVO::getUserName).collect(Collectors.toList())));
|
||||
// ticket.setCqm(AdminUserUtil.getUserId());
|
||||
ticket.setCurrentHandle(AdminUserUtil.getUserId());
|
||||
ticket.setCurrentHandle(request.getUserIds().get(0));
|
||||
ticket.setUpdateTime(LocalDateTime.now());
|
||||
updateById(ticket);
|
||||
return ticket;
|
||||
|
|
|
|||
|
|
@ -60,8 +60,8 @@
|
|||
</update>
|
||||
|
||||
<select id="searchDevice" resultType="com.nflg.mobilebroken.common.pojo.vo.DeviceVO">
|
||||
SELECT d.device_no AS 'deviceNo',d.device_name AS 'deviceName',d.model_no AS 'modelNo'
|
||||
,d.device_type AS 'deviceType',d.shipment_date AS 'shipmentDate',IFNULL(dit2.value,di2.value) AS 'warrantyState'
|
||||
SELECT d.device_no,d.device_name,d.model_no,d.device_type,d.shipment_date,d.customer_name
|
||||
,IFNULL(dit2.value,di2.value) AS 'warrantyState'
|
||||
FROM v_all_device d
|
||||
INNER JOIN t_base_customer c ON d.agent_code=c.agency_company_code
|
||||
INNER JOIN dictionary_item di ON di.id=d.device_state
|
||||
|
|
@ -92,6 +92,9 @@
|
|||
<if test="request.key!=null and request.key!=''">
|
||||
and (d.device_no LIKE concat('%', #{request.key}, '%') or d.model_no LIKE concat('%', #{request.key}, '%'))
|
||||
</if>
|
||||
<if test="request.deviceName!=null and request.deviceName!=''">
|
||||
and d.device_name LIKE concat('%', #{request.deviceName}, '%')
|
||||
</if>
|
||||
</select>
|
||||
<!--定时任务-质保未开始-->
|
||||
<update id="taskWarrantyStateNotStarted">
|
||||
|
|
|
|||
|
|
@ -53,4 +53,26 @@
|
|||
left join v_dispatch_applyfor af on da.id=af.ticket_id
|
||||
where da.id = #{id}
|
||||
</select>
|
||||
|
||||
<select id="getForBI" resultType="com.nflg.mobilebroken.repository.entity.GongfuDispatch">
|
||||
SELECT gd.*
|
||||
FROM gongfu_dispatch gd
|
||||
LEFT JOIN admin_user au ON gd.handler_user_id = au.id
|
||||
WHERE gd.handler_user_type=1 and gd.state in
|
||||
<foreach collection="states" close=")" open="(" item="state" separator=",">
|
||||
#{state}
|
||||
</foreach>
|
||||
<if test="deptId!=null">
|
||||
and au.department_id=#{deptId}
|
||||
</if>
|
||||
<if test="startDate!=null">
|
||||
and gd.plan_start_date >= #{startDate}
|
||||
</if>
|
||||
<if test="endDate!=null">
|
||||
and gd.plan_end_date <= #{endDate}
|
||||
</if>
|
||||
<if test="userName!=null and userName!=''">
|
||||
and au.user_name LIKE CONCAT('%',#{userName},'%')
|
||||
</if>
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
## 服务器需要安装的软件
|
||||
|
||||
- ImageMagick
|
||||
|
||||
> 用于将苹果的HEIC图片格式转换为PNG图片格式,必须源码编译,否则不支持HEIC格式
|
||||
|
||||
```bash
|
||||
yum install -y epel-release
|
||||
rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
|
||||
yum install -y yum-utils
|
||||
yum-config-manager --enable remi
|
||||
wget https://download1.rpmfusion.org/free/el/rpmfusion-free-release-7.noarch.rpm
|
||||
wget https://download1.rpmfusion.org/nonfree/el/rpmfusion-nonfree-release-7.noarch.rpm
|
||||
rpm -Uvh rpmfusion-free-release-7.noarch.rpm rpmfusion-nonfree-release-7.noarch.rpm
|
||||
yum clean all
|
||||
yum install -y libde265 libx265
|
||||
yum install -y libheif-devel
|
||||
yum install -y libtool-ltdl-devel
|
||||
# 源码编译安装ImageMagick
|
||||
yum groupinstall -y "Development Tools"
|
||||
yum install -y libjpeg-turbo-devel libpng-devel freetype-devel libtiff-devel giflib-devel
|
||||
yum install -y libheif-devel libde265-devel x265-devel
|
||||
wget https://github.com/ImageMagick/ImageMagick/archive/refs/tags/7.1.2-11.tar.gz
|
||||
tar xf 7.1.2-11.tar.gz
|
||||
cd ImageMagick-7.1.2-11/
|
||||
./configure --with-heif=yes --with-modules --enable-hdri
|
||||
make -j$(nproc)
|
||||
make install
|
||||
which magick
|
||||
ln -s /usr/local/bin/magick /usr/bin/magick
|
||||
magick -version
|
||||
magick -list format | grep HEIC
|
||||
```
|
||||
Loading…
Reference in New Issue