1.任务 创建删除查询导入等功能

This commit is contained in:
zhaowenyuan 2024-06-20 09:25:50 +08:00
parent a28491d716
commit f9d0c564b9
24 changed files with 1127 additions and 86 deletions

View File

@ -161,6 +161,8 @@ public class DataScopeAspect {
}
private Map<String, Object> getSqlParam(final JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
if (null == args || args.length == 0) return new HashMap<>();
Object params = joinPoint.getArgs()[0];
Map<String, Object> sqlParam;
if (StringUtils.isNotNull(params) && params instanceof BaseEntity) {
@ -170,7 +172,7 @@ public class DataScopeAspect {
CommonParam commonParam = (CommonParam) params;
sqlParam = commonParam.getSqlParam();
}else {
return null;
return new HashMap<>();
}
return sqlParam;
}

View File

@ -0,0 +1,51 @@
package com.chushang.common.excel.convert;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
/**
* 大数值转换
* Excel 数值长度位15位 大于15位的数值转换位字符串
*
* @author Lion Li
*/
@Slf4j
public class ExcelBigNumberConvert implements Converter<Long> {
@Override
public Class<Long> supportJavaTypeKey() {
return Long.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
@Override
public Long convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
return Convert.toLong(cellData.getData());
}
@Override
public WriteCellData<Object> convertToExcelData(Long object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
if (ObjectUtil.isNotNull(object)) {
String str = Convert.toStr(object);
if (str.length() > 15) {
return new WriteCellData<>(str);
}
}
WriteCellData<Object> cellData = new WriteCellData<>(new BigDecimal(object));
cellData.setType(CellDataTypeEnum.NUMBER);
return cellData;
}
}

View File

@ -0,0 +1,74 @@
package com.chushang.common.excel.convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import lombok.extern.slf4j.Slf4j;
import java.time.LocalDateTime;
/**
* <h1>日期格式化</h1>
*
* @author 单傲
* @version 1.0
* @Date 2023-04-19 17:57
**/
@Slf4j
public class LocalDateTimeConvert implements Converter<LocalDateTime> {
@Override
public Class<LocalDateTime> supportJavaTypeKey() {
return LocalDateTime.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return null;
}
/**
* <h2>转换为java对象</h2>
*
* @param cellData Excel 单元格数据
* @param contentProperty 内容属性
* @param globalConfiguration 全局配置
* @return java对象
* @author 单傲
* @date 2023/4/19 18:09
*/
@Override
public LocalDateTime convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
if (cellData.getStringValue() == null) {
return null;
}
return LocalDateTimeUtil.parse(cellData.getStringValue(), DatePattern.NORM_DATE_PATTERN);
}
/**
* <h2>转换单元格数据</h2>
*
* @param value Java 数据
* @param contentProperty 内容属性
* @param globalConfiguration 全局配置
* @return excel中的数据
* @author 单傲
* @date 2023/4/19 18:11
*/
@Override
public WriteCellData<String> convertToExcelData(LocalDateTime value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
if (ObjectUtil.isEmpty(value)) {
return new WriteCellData<>();
}
return new WriteCellData<>(LocalDateTimeUtil.format(value, DatePattern.CHINESE_DATE_PATTERN));
}
}

View File

@ -0,0 +1,59 @@
package com.chushang.common.excel.convert;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
public class StringConvert implements Converter<String> {
@Override
public Class<String> supportJavaTypeKey() {
return String.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
/**
* <h2>转换为java对象</h2>
*
* @param cellData Excel 单元格数据
* @param contentProperty 内容属性
* @param globalConfiguration 全局配置
* @return java对象
* @author 单傲
* @date 2023/4/19 18:09
*/
@Override
public String convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
if (cellData.getStringValue() == null) {
return null;
}
return cellData.getStringValue();
}
/**
* <h2>转换单元格数据</h2>
*
* @param value Java 数据
* @param contentProperty 内容属性
* @param globalConfiguration 全局配置
* @return excel中的数据
* @author 单傲
* @date 2023/4/19 18:11
*/
@Override
public WriteCellData<String> convertToExcelData(String value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
if (StrUtil.isEmpty(value)) {
return new WriteCellData<>();
}
return new WriteCellData<>(value);
}
}

View File

@ -4,10 +4,15 @@ import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import org.apache.poi.ss.formula.functions.T;
import java.util.ArrayList;
import java.util.List;
/**
* 用于读取
* @param <T>
*/
@Getter
@EqualsAndHashCode(callSuper = true)
public class DataListener<T> extends AnalysisEventListener<T> {
@ -27,4 +32,4 @@ public class DataListener<T> extends AnalysisEventListener<T> {
}
}
}

View File

@ -0,0 +1,130 @@
package com.chushang.common.excel.listener;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.read.listener.PageReadListener;
import com.alibaba.excel.util.ConverterUtils;
import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
* <h1>Excel 导入监听</h1>
*
* <p>
* 对分页监听的增强
* </p>
*
* @author 单傲
* @version 1.0
* @Date 2023-04-18 16:29
**/
@Slf4j
public class DefaultExcelListener<T> extends PageReadListener<T> {
private final Boolean isValidate;
public DefaultExcelListener(Consumer<List<T>> consumer, boolean isValidate) {
super(consumer);
this.isValidate = isValidate;
PageReadListener.BATCH_COUNT = 30000;
}
/**
* <h2>异常处理</h2>
*
* @param exception 异常
* @param context Excel 上下文
* @author 单傲
* @date 2023/4/18 16:32
*/
@Override
public void onException(Exception exception, AnalysisContext context) throws Exception {
String errMsg;
if (exception instanceof ExcelDataConvertException convert) {
Integer index = convert.getColumnIndex();
errMsg = StrUtil.format("【{}】行,【{}】列的数据解析异常", convert.getRowIndex() + 1, index + 1);
} else if (exception instanceof ConstraintViolationException violation) {
Set<ConstraintViolation<?>> violations = Optional
.ofNullable(violation.getConstraintViolations()).orElse(CollUtil.newHashSet());
String collect = violations.stream().map(ConstraintViolation::getMessage)
.filter(Objects::nonNull).collect(Collectors.joining(", "));
errMsg = StrUtil.format("【{}】行输入有误:【{}】", context.readRowHolder()
.getRowIndex() + 1, collect);
} else {
errMsg = exception.getMessage();
}
log.error("#DefaultExcelListener.onException# {}", errMsg, exception);
Assert.isTrue(false, errMsg);
}
/**
* <h2>处理解析的数据</h2>
*
* @param t 解析到的数据
* @param analysisContext 分析上下文
* @author 单傲
* @date 2023/4/19 16:43
*/
@Override
public void invoke(T t, AnalysisContext analysisContext) {
log.info("解析到一条数据【{}】", JSON.toJSONString(t));
//去掉Unicode特殊字符
// UnicodeUtils.removeUnicodeSpecialCharacters(t.getClass(), t);
// 处理数据校验
if (isValidate) {
Set<ConstraintViolation<T>> validate = SpringUtil.getBean(Validator.class)
.validate(t);
if (CollUtil.isNotEmpty(validate)) {
throw new ConstraintViolationException("参数校验异常", validate);
}
}
super.invoke(t, analysisContext);
}
/**
* <h2>解析头数据</h2>
*
* @param headMap 头数据
* @param context 分析上下文
* @author 单傲
* @date 2023/4/19 16:43
*/
@Override
public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
log.info("解析到表头数据: 【{}】", JSON.toJSONString(ConverterUtils.convertToStringMap(headMap, context)));
}
/**
* <h2>解析完成后调用</h2>
*
* @param analysisContext 分析上下文
* @author 单傲
* @date 2023/4/19 16:43
*/
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
super.doAfterAllAnalysed(analysisContext);
log.info("#DefaultExcelListener.onException# :文件处理完成");
}
}

View File

@ -69,4 +69,4 @@ public class ImportListener<T> extends AnalysisEventListener<T> {
list.clear();
}
}
}

View File

@ -6,6 +6,7 @@ import com.alibaba.excel.read.listener.ReadListener;
import com.chushang.common.core.exception.ResultException;
import com.chushang.common.core.util.StringUtils;
import com.chushang.common.excel.listener.DataListener;
import com.chushang.common.excel.listener.DefaultExcelListener;
import com.chushang.common.excel.listener.ImportListener;
import com.chushang.common.excel.service.ExcelImporter;
import lombok.SneakyThrows;
@ -19,6 +20,7 @@ import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.function.Consumer;
/**
* by zhaowenyuan create 2021/12/27 10:49
@ -57,6 +59,43 @@ public class ExcelUtils {
}
/**
* 使用校验监听器 异步导入 同步返回
*
* @param is 输入流
* @param clazz 对象类型
* @param isValidate 是否 Validator 检验 默认为是
* @param consumer 消费者
* @param sheetNo 表号
* @param sheetName 表名称
*/
public static <T> void importExcel(InputStream is, Class<T> clazz, boolean isValidate, Consumer<List<T>> consumer, Integer sheetNo, String sheetName) {
DefaultExcelListener<T> listener = new DefaultExcelListener<>(consumer, isValidate);
EasyExcel.read(is, clazz, listener).sheet(sheetNo, sheetName).doRead();
}
/**
* 使用校验监听器 异步导入 同步返回
*
* @param is 输入流
* @param clazz 对象类型
* @param consumer 消费者
*/
public static <T> void importExcel(InputStream is, Class<T> clazz, Consumer<List<T>> consumer) {
importExcel(is, clazz, Boolean.TRUE, consumer, null, null);
}
/**
* 读取并导入数据
*
* @param excel excel文件
* @param consumer 导入逻辑类
* @param clazz 泛型
*/
public static <T> void importExcel(MultipartFile excel, Class<T> clazz, Consumer<List<T>> consumer) throws IOException {
importExcel(excel.getInputStream(), clazz, consumer);
}
/**
* 读取excel的所有sheet数据
*

View File

@ -4,6 +4,9 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;
import static com.chushang.common.mybatis.annotation.Condition.ConditionType.*;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@ -11,9 +14,14 @@ public @interface Condition {
String name();
ConditionType type() default ConditionType.eq;
ConditionType[] type() default {eq};
enum ConditionType {
ge,
le,
gt,
lt,
isNull,
eq,
like,
in,

View File

@ -4,6 +4,7 @@ import com.chushang.common.core.exception.utils.AssertUtil;
import com.chushang.common.core.text.Convert;
import com.chushang.common.core.util.ServletUtils;
import com.chushang.common.core.util.StringUtils;
import com.chushang.common.mybatis.annotation.Condition;
import lombok.Data;
import java.io.Serial;
@ -49,6 +50,7 @@ public class CommonParam implements Serializable {
/**
* 内部使用 sql 查询, 仅用于 角色权限所需查询, 前端不能传递
*/
@Condition(name = "dept_id", type = Condition.ConditionType.dataScope)
private Map<String, Object> sqlParam;
public Map<String, Object> getSqlParam()

View File

@ -23,6 +23,10 @@ import java.util.List;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class WrapperUtils {
public static <T> LambdaQueryWrapper<T> builder(String... columns) {
return builder(null, null, columns);
}
public static <T> LambdaQueryWrapper<T> builder(Object query, CommonParam commonParam, String... columns) {
QueryWrapper<T> queryWrapper = new QueryWrapper<>();
if (null != columns) {
@ -52,64 +56,85 @@ public class WrapperUtils {
}
String name = condition.name();
String[] split = name.split(",");
switch (condition.type()) {
case eq:
queryWrapper = queryWrapper.eq(ObjectUtil.isNotEmpty(value), name, value);
break;
case like:
queryWrapper = queryWrapper.like(ObjectUtil.isNotEmpty(value), name, value);
break;
case in:
if (value instanceof Collection<?>) {
queryWrapper = queryWrapper.in(ObjectUtil.isNotEmpty(value), name, (Collection) value);
} else {
throw new MybatisConditionException("in 条件必须为集合");
Condition.ConditionType[] type = condition.type();
if (null != type){
for (Condition.ConditionType conditionType : type) {
switch (conditionType) {
case ge:
queryWrapper = queryWrapper.ge(ObjectUtil.isNotEmpty(value), name, value);
break;
case le:
queryWrapper = queryWrapper.le(ObjectUtil.isNotEmpty(value), name, value);
break;
case gt:
queryWrapper = queryWrapper.gt(ObjectUtil.isNotEmpty(value), name, value);
break;
case lt:
queryWrapper = queryWrapper.lt(ObjectUtil.isNotEmpty(value), name, value);
break;
case isNull:
queryWrapper = queryWrapper.isNull(name);
break;
case eq:
queryWrapper = queryWrapper.eq(ObjectUtil.isNotEmpty(value), name, value);
break;
case like:
queryWrapper = queryWrapper.like(ObjectUtil.isNotEmpty(value), name, value);
break;
case in:
if (value instanceof Collection<?>) {
queryWrapper = queryWrapper.in(ObjectUtil.isNotEmpty(value), name, (Collection) value);
} else {
throw new MybatisConditionException("in 条件必须为集合");
}
break;
case between:
if (value instanceof Collection<?>) {
List<?> list = Convert.toList(value);
if (CollUtil.size(list) == 2) {
queryWrapper = queryWrapper.between(name, list.get(0), list.get(1));
}
} else {
throw new MybatisConditionException("between 条件必须为集合");
}
break;
case likeLeft:
queryWrapper = queryWrapper.likeLeft(ObjectUtil.isNotEmpty(value), name, value);
break;
case dataScope:
if (value instanceof HashMap sqlParam) {
// dataScope 拼接部门Ids
Object dataScope = sqlParam.get("dataScopeIds");
if (ObjectUtil.isNotEmpty(dataScope) && dataScope instanceof Collection<?> deptIds) {
queryWrapper = queryWrapper.in(CollectionUtil.isNotEmpty(deptIds), name, deptIds);
}
}
break;
case or_eq:
queryWrapper.and(q -> {
for (String key : split) {
q.or().eq(ObjectUtil.isNotEmpty(value), key, value);
}
});
break;
case or_like:
queryWrapper.and(q -> {
for (String key : split) {
q.or().like(ObjectUtil.isNotEmpty(value), key, value);
}
});
break;
case or_likeLeft:
queryWrapper.and(q -> {
for (String key : split) {
q.or().likeLeft(ObjectUtil.isNotEmpty(value), key, value);
}
});
break;
}
break;
case between:
if (value instanceof Collection<?>) {
List<?> list = Convert.toList(value);
if (CollUtil.size(list) == 2) {
queryWrapper = queryWrapper.between(name, list.get(0), list.get(1));
}
} else {
throw new MybatisConditionException("between 条件必须为集合");
}
break;
case likeLeft:
queryWrapper = queryWrapper.likeLeft(ObjectUtil.isNotEmpty(value), name, value);
break;
case dataScope:
if (value instanceof HashMap sqlParam) {
// dataScope 拼接部门Ids
Object dataScope = sqlParam.get("dataScopeIds");
if (ObjectUtil.isNotEmpty(dataScope) && dataScope instanceof Collection<?> deptIds) {
queryWrapper = queryWrapper.in(CollectionUtil.isNotEmpty(deptIds), name, deptIds);
}
}
break;
case or_eq:
queryWrapper.and(q -> {
for (String key : split) {
q.or().eq(ObjectUtil.isNotEmpty(value), key, value);
}
});
break;
case or_like:
queryWrapper.and(q -> {
for (String key : split) {
q.or().like(ObjectUtil.isNotEmpty(value), key, value);
}
});
break;
case or_likeLeft:
queryWrapper.and(q -> {
for (String key : split) {
q.or().likeLeft(ObjectUtil.isNotEmpty(value), key, value);
}
});
break;
}
}
}
return queryWrapper.lambda();
}

View File

@ -13,5 +13,9 @@
<groupId>com.chushang</groupId>
<artifactId>task-feign</artifactId>
</dependency>
<dependency>
<groupId>com.chushang</groupId>
<artifactId>chushang-common-excel</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,15 @@
package com.chushang.inspection.project.entity.dto;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import java.io.Serializable;
import java.util.List;
@Data
public class Delete implements Serializable {
/** id列表 */
@NotEmpty(message = "id不能为空")
List<Long> ids;
}

View File

@ -0,0 +1,104 @@
package com.chushang.inspection.project.entity.dto;
import com.chushang.common.core.validator.Create;
import com.chushang.common.core.validator.Update;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Range;
import javax.validation.constraints.*;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TaskDTO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 上级ID
*/
@Builder.Default
private Long parentId = 0L;
/**
* 任务名称
*/
@NotBlank(message = "任务名称不能为空", groups = Create.class)
@Size(max = 255, message = "任务名称不能超过255个字符", groups = {Create.class, Update.class})
private String name;
/**
* 联系人
*/
@Size(max = 32, message = "联系人不能超过32个字符", groups = {Create.class, Update.class})
private String contact;
/**
* 联系电话
*/
@Size(max = 11, message = "联系电话不能超过11个字符", groups = {Create.class, Update.class})
private String phone;
/**
* 项目开始时间
*/
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime startTime;
/**
* 项目结束时间
*/
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private LocalDateTime endTime;
/**
* 负责的部门 -- 为空时 取当前用户部门id
*/
@NotEmpty(message = "必须指定负责的部门", groups = {Create.class})
private Long deptId;
/**
* 状态
*/
@Range(min = 0, max = 1, message = "是否启用格式不正确", groups = {Create.class, Update.class})
private Integer enabled;
/**
* 是否有电子巡检单(默认0 没有)
*/
@Range(min = 0, max = 1, message = "是否有电子巡检单格式不正确", groups = {Create.class, Update.class})
private Integer isInspection;
/**
* 派单方式
*/
@Range(min = 0, max = 10, message = "派单方式格式不正确", groups = {Create.class, Update.class})
private Integer dispatchMethod;
/**
* 审核方式
*/
@Range(min = 1, max = 3, message = "审核方式格式不正确", groups = {Create.class, Update.class})
private Integer reviewMethod;
/**
* 是否重复派单
*/
@Range(min = 0, max = 1, message = "是否重复派单格式不正确", groups = {Create.class, Update.class})
private Integer isRepeat;
/**
* 银行编号
*/
@Size(max = 63, message = "编号不能超过63个字符", groups = {Create.class, Update.class})
private String number;
}

View File

@ -0,0 +1,47 @@
package com.chushang.inspection.project.entity.dto;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.io.Serializable;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TaskExcelDTO implements Serializable {
@ExcelProperty("一分")
@NotBlank(message = "名称不能为空")
@Size(max = 64, message = "名称不能超过64个字符")
private String firstBank;
@ExcelProperty("二分")
@Size(max = 64, message = "名称不能超过64个字符")
private String secondBank;
@ExcelProperty("一支")
@Size(max = 64, message = "名称不能超过64个字符")
private String firstSubBank;
@ExcelProperty("二支")
@Size(max = 64, message = "名称不能超过64个字符")
private String secondSubBank;
@ExcelProperty("联系人")
@Size(max = 32, message = "联系人不能超过32个字符")
private String contact;
@ExcelProperty("联系电话")
@Size(max = 11, message = "联系电话不能超过11个字符")
private String phone;
// @ExcelProperty("编号")
// @Size(max = 63, message = "编号不能超过63个字符")
// private String number;
}

View File

@ -1,7 +1,10 @@
package com.chushang.inspection.project.entity.dto;
import com.baomidou.mybatisplus.annotation.TableField;
import com.chushang.common.mybatis.annotation.Condition;
import com.chushang.common.mybatis.page.CommonParam;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.validator.constraints.Range;
import javax.validation.constraints.Size;
@ -13,8 +16,9 @@ import java.util.List;
* @auther: zhao
* @date: 2024/6/18 16:04
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class TaskQuery {
public class TaskQuery extends CommonParam {
/** 任务名称或联系人 */
@Size(max = 32, message = "任务名称或联系人长度不能超过32位")
@ -26,11 +30,17 @@ public class TaskQuery {
private List<LocalDateTime> createTime;
/** 上级任务id */
@Condition(name = "parent_id", type = Condition.ConditionType.eq)
private Long pid;
/** 是否查询未开启的状态1 不是 0是 */
@Range(max = 1, message = "状态输入错误")
@Condition(name = "enabled", type = Condition.ConditionType.eq)
private Integer enabled;
/**
* 结束时间
*/
@TableField(value = "end_time")
private LocalDateTime endTime;
}

View File

@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.chushang.common.mybatis.annotation.Condition;
import com.chushang.common.mybatis.base.BaseEntity;
import java.time.LocalDateTime;

View File

@ -0,0 +1,35 @@
package com.chushang.inspection.project.entity.vo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ConfigVO implements Serializable {
/**
* 是否有电子巡检单(默认0 没有)
*/
private Integer isInspection;
/**
* 派单方式
*/
private Integer dispatchMethod;
/**
* 审核方式
*/
private Integer reviewMethod;
/**
* 是否重复派单
*/
private Integer isRepeat;
}

View File

@ -13,7 +13,7 @@ import java.util.List;
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class TaskVO extends TreeNode<Long> {
public class TaskVO extends TreeNode<TaskVO> {
/**
* 任务名称
@ -79,5 +79,9 @@ public class TaskVO extends TreeNode<Long> {
* 银行编号
*/
private String number;
/**
* 所属部门
*/
private Long deptId;
}

View File

@ -1,15 +1,26 @@
package com.chushang.inspection.project.controller;
import com.chushang.common.core.validator.Create;
import com.chushang.common.core.validator.Update;
import com.chushang.common.core.web.AjaxResult;
import com.chushang.common.log.annotation.SysLog;
import com.chushang.common.log.enums.BusinessType;
import com.chushang.common.mybatis.page.CommonParam;
import com.chushang.inspection.project.entity.dto.Delete;
import com.chushang.inspection.project.entity.dto.TaskDTO;
import com.chushang.inspection.project.entity.dto.TaskExcelDTO;
import com.chushang.inspection.project.entity.dto.TaskQuery;
import com.chushang.inspection.project.entity.vo.ConfigVO;
import com.chushang.inspection.project.entity.vo.TaskVO;
import com.chushang.inspection.project.service.PollingTaskService;
import com.chushang.security.utils.SecurityUtils;
import com.chushang.security.annotation.RequiresPermissions;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.util.List;
/**
* @auther: zhao
@ -24,16 +35,117 @@ public class PollTaskController {
PollingTaskService pollingTaskService;
/**
* 查询任务列表
*/
@GetMapping("/list")
@RequiresPermissions("store:task:list")
public AjaxResult findList(TaskQuery taskQuery) {
return AjaxResult.success(pollingTaskService.findList(taskQuery));
}
/**
* 查询顶级任务列表
*/
@GetMapping("/list/top")
// @RequiresPermissions("store:task:top")
public AjaxResult findTopList(TaskQuery taskQuery) {
// Long userId = SecurityUtils.getUserId();
Long userId = 1L;
return AjaxResult.success(pollingTaskService.findTopList(taskQuery, userId));
@RequiresPermissions("store:task:top")
public AjaxResult findTopList(){
return AjaxResult.success(pollingTaskService.findTopList(CommonParam.buildPageRequest()));
}
/**
* 查询顶级任务配置
*/
@GetMapping("/config/{taskId}")
@RequiresPermissions("store:task:config")
public ConfigVO findTaskConfig(@PathVariable Long taskId) {
return pollingTaskService.findTaskConfig(taskId);
}
/**
* 获取详细信息
*
* @param taskId 任务id
* @return 详情
*/
@GetMapping("/info/{taskId}")
@RequiresPermissions("store:task:info")
public TaskVO getTaskById(@PathVariable Long taskId) {
return pollingTaskService.getTaskById(taskId);
}
/**
* 新增任务
*
* @param task 任务信息
*/
@PostMapping("/save")
@RequiresPermissions("store:task:save")
@SysLog( value = "任务", businessType = BusinessType.INSERT)
public AjaxResult save(@RequestBody @Validated(Create.class) TaskDTO task) {
Long taskId = pollingTaskService.saveTask(task);
return AjaxResult.success(taskId);
}
/**
* 修改
*
* @param task 任务信息
*/
@PostMapping("/{taskId}")
@RequiresPermissions("store:task:update")
@SysLog(value = "任务", businessType = BusinessType.UPDATE)
public AjaxResult update(@RequestBody @Validated(Update.class) TaskDTO task,
@PathVariable Long taskId)
{
return AjaxResult.success(pollingTaskService.updateTask(task, taskId));
}
/**
* 删除任务
*
* @param taskId 删除的id
*/
@DeleteMapping("/del/{taskId}")
@RequiresPermissions("store:task:delete")
@SysLog(value = "任务", businessType = BusinessType.DELETE)
public AjaxResult delete(@PathVariable Long taskId) {
pollingTaskService.removeById(taskId);
return AjaxResult.success();
}
/**
* 批量删除任务
*
* @param delete 删除的id 集合
*/
@PostMapping("/del/batch")
@RequiresPermissions("store:task:delete")
@SysLog(value = "批量任务", businessType = BusinessType.DELETE)
public AjaxResult delete(@RequestBody Delete delete) {
List<Long> ids = delete.getIds();
pollingTaskService.removeBatchByIds(ids);
return AjaxResult.success();
}
/**
* 导入任务 读取
*/
@PostMapping("/import/read")
@RequiresPermissions("store:task:import")
public AjaxResult importRead(@RequestParam("file") MultipartFile file) {
return AjaxResult.success(pollingTaskService.importRead(file));
}
/**
* 导入任务 保存
*/
@SysLog(value = "任务", businessType = BusinessType.IMPORT)
@PostMapping("/import/{parentId}")
@RequiresPermissions("store:task:save")
public AjaxResult importSave(@RequestBody List<TaskExcelDTO> taskExcel, @PathVariable Long parentId) {
pollingTaskService.importSave(taskExcel, parentId);
return AjaxResult.success();
}
}

View File

@ -1,5 +1,7 @@
package com.chushang.inspection.project.mapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.chushang.inspection.project.entity.po.PollingTask;
@ -8,4 +10,12 @@ import com.chushang.inspection.project.entity.po.PollingTask;
* @date: 2024/6/18 15:39
*/
public interface PollingTaskMapper extends BaseMapper<PollingTask> {
default Integer childMaxIndex(String index, int level){
QueryWrapper<PollingTask> taskSql = new QueryWrapper<>();
taskSql.select("max(search_index) AS search_index").lambda()
.likeLeft(PollingTask::getSearchNum,index)
.eq(PollingTask::getLevel, level);
PollingTask pollingTask = selectOne(taskSql);
return pollingTask.getSearchIndex();
}
}

View File

@ -1,8 +1,14 @@
package com.chushang.inspection.project.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.chushang.common.mybatis.page.CommonParam;
import com.chushang.inspection.project.entity.dto.TaskDTO;
import com.chushang.inspection.project.entity.dto.TaskExcelDTO;
import com.chushang.inspection.project.entity.dto.TaskQuery;
import com.chushang.inspection.project.entity.po.PollingTask;
import com.chushang.inspection.project.entity.vo.ConfigVO;
import com.chushang.inspection.project.entity.vo.TaskVO;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@ -13,5 +19,20 @@ import java.util.List;
public interface PollingTaskService extends IService<PollingTask>{
List<PollingTask> findTopList(TaskQuery taskQuery, Long userId);
List<TaskVO> findList(TaskQuery taskQuery);
List<TaskVO> findTopList(CommonParam commonParam);
ConfigVO findTaskConfig(Long taskId);
TaskVO getTaskById(Long taskId);
Long saveTask(TaskDTO task);
Long updateTask(TaskDTO task, Long taskId);
List<TaskExcelDTO> importRead(MultipartFile file);
void importSave(List<TaskExcelDTO> taskExcel, Long parentId);
}

View File

@ -155,15 +155,16 @@ public class WrkProjectService extends ServiceImpl<WrkProjectMapper, WrkProject>
updateState(contract.getProjectId(), projectEffect ? 1 : 0 );
Integer auditStatus = contract.getAuditStatus();
// 新增合同的审核记录
WrkAudit audit = new WrkAudit();
audit.setThirdType(1);
audit.setDeptId(deptId);
audit.setAuditStatus(auditStatus);
audit.setThirdId(projectContract.getContractId());
audit.setRemark(contract.getRemark());
auditService.save(audit);
if (null != auditStatus && (1 == auditStatus || 2 == auditStatus)){
// 新增合同的审核记录
WrkAudit audit = new WrkAudit();
audit.setThirdType(1);
audit.setDeptId(deptId);
audit.setAuditStatus(auditStatus);
audit.setThirdId(projectContract.getContractId());
audit.setRemark(contract.getRemark());
auditService.save(audit);
}
return projectContract.getContractId();
}

View File

@ -1,18 +1,51 @@
package com.chushang.inspection.project.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.chushang.common.core.constant.SecurityConstants;
import com.chushang.common.core.util.SpringUtils;
import com.chushang.common.core.util.TreeUtils;
import com.chushang.common.core.web.Result;
import com.chushang.common.excel.utils.ExcelUtils;
import com.chushang.common.mybatis.enums.Operator;
import com.chushang.common.mybatis.page.CommonParam;
import com.chushang.common.mybatis.utils.WrapperUtils;
import com.chushang.datascope.annotation.DataScope;
import com.chushang.inspection.project.entity.dto.TaskDTO;
import com.chushang.inspection.project.entity.dto.TaskExcelDTO;
import com.chushang.inspection.project.entity.dto.TaskQuery;
import com.chushang.inspection.project.entity.vo.ConfigVO;
import com.chushang.inspection.project.entity.vo.TaskVO;
import com.chushang.inspection.project.service.PollingTaskService;
import com.chushang.security.utils.SecurityUtils;
import com.chushang.task.entity.dto.CreateTaskDTO;
import com.chushang.task.enums.ServiceEnum;
import com.chushang.task.enums.TaskTypeEnum;
import com.chushang.task.feign.RemoteTaskService;
import com.google.common.collect.Maps;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chushang.inspection.project.mapper.PollingTaskMapper;
import com.chushang.inspection.project.entity.po.PollingTask;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @auther: zhao
@ -21,12 +54,261 @@ import java.util.List;
@Slf4j
@Service
public class PollingTaskServiceImpl extends ServiceImpl<PollingTaskMapper, PollingTask> implements PollingTaskService {
/**
* 通过远程调用的方式进行入库
*/
@Resource
RemoteTaskService remoteTaskService;
@Override
public List<PollingTask> findTopList(TaskQuery taskQuery, Long userId)
@DataScope
public List<TaskVO> findList(TaskQuery taskQuery)
{
LambdaQueryWrapper<PollingTask> taskSql = WrapperUtils.builder(taskQuery, CommonParam.buildPageRequest());
list(taskSql);
return List.of();
Long pid = taskQuery.getPid();
String searchNum = null;
if (null != pid){
PollingTask topTask = getOne(new LambdaQueryWrapper<PollingTask>().eq(PollingTask::getId, pid));
if (ObjectUtil.isNotEmpty(topTask)){
searchNum = topTask.getSearchNum();
}
}
taskSql.likeLeft(PollingTask::getSearchNum, searchNum);
List<TaskVO> taskVOS = listObjs(taskSql, p -> convert(((PollingTask) p)));
return TreeUtils.build(taskVOS);
}
@Override
@DataScope
public List<TaskVO> findTopList(CommonParam commonParam) {
LambdaQueryWrapper<PollingTask> searchNumSql = WrapperUtils.builder(commonParam, commonParam);
searchNumSql.select(PollingTask::getSearchNum)
.eq(PollingTask::getEnabled, 1)
.and(w -> w.isNull(PollingTask::getEndTime)
.or().ge(PollingTask::getEndTime, LocalDateTime.now()));
List<String> searchNums = listObjs(searchNumSql, p -> ((PollingTask) p).getSearchNum());
if (CollectionUtil.isNotEmpty(searchNums)){
return new ArrayList<>();
}
searchNums = searchNums.stream().map(s -> s.split("-")[0] + '-').distinct().collect(Collectors.toList());
LambdaQueryWrapper<PollingTask> topSql = WrapperUtils.builder(commonParam, commonParam);
topSql.in(CollectionUtil.isNotEmpty(searchNums), PollingTask::getSearchNum, searchNums);
return listObjs(topSql, p->convert(((PollingTask)p)));
}
@Override
public ConfigVO findTaskConfig(Long taskId)
{
PollingTask task = getById(taskId);
Assert.notNull(task, "此任务不存在");
if (task.getParentId() == 0) {
return BeanUtil.copyProperties(task, ConfigVO.class);
}
String searchNum = task.getSearchNum().split("-")[0] + "-";
CommonParam commonParam = CommonParam.buildPageRequest();
LambdaQueryWrapper<PollingTask> taskSql = WrapperUtils.builder(commonParam, commonParam);
taskSql.eq(PollingTask::getSearchNum, searchNum).last(Operator.LIMIT_ONE.getCharacter());
task = getOne(taskSql);
Assert.notNull(task, "此任务不存在");
return BeanUtil.copyProperties(task, ConfigVO.class);
}
@Override
public TaskVO getTaskById(Long taskId) {
PollingTask task = getById(taskId);
Assert.notNull(task, "此任务不存在");
return convert(task);
}
@Override
@Transactional
public Long saveTask(TaskDTO task) {
PollingTask pollingTask = BeanUtil.copyProperties(task, PollingTask.class);
processIndexes(pollingTask);
save(pollingTask);
return pollingTask.getId();
}
@Override
@Transactional
public Long updateTask(TaskDTO task, Long taskId) {
PollingTask currentTask = getById(taskId);
Assert.notNull(currentTask, "修改的任务不存在");
PollingTask pollingTask = BeanUtil.copyProperties(task, PollingTask.class);
if (!Objects.equals(pollingTask.getParentId(), currentTask.getParentId())) {
processIndexes(currentTask);
LambdaQueryWrapper<PollingTask> taskSql = WrapperUtils.builder();
taskSql.likeLeft(PollingTask::getSearchNum, currentTask.getSearchNum());
// 修改下级机构
List<PollingTask> tasks = list(taskSql);
if (CollUtil.isNotEmpty(tasks)) {
for (PollingTask updateTask : tasks) {
String replace = StrUtil.replace(updateTask.getSearchNum(), currentTask.getSearchNum(), pollingTask.getSearchNum());
updateTask.setSearchNum(replace);
updateTask.setLevel(replace.split("-").length);
updateById(updateTask);
}
}
}
if (pollingTask.getParentId() != 0) {
// 只有顶级可以修改设置
pollingTask.setIsInspection(null);
pollingTask.setDispatchMethod(null);
pollingTask.setReviewMethod(null);
pollingTask.setIsRepeat(null);
}
else {
Assert.notNull(pollingTask.getIsInspection(), "必须指定是否开通巡检单");
Assert.notNull(pollingTask.getDispatchMethod(), "必须指定巡检方式");
Assert.notNull(pollingTask.getReviewMethod(), "必须指定审核方式");
Assert.notNull(pollingTask.getIsRepeat(), "必须指定是否重复派单");
}
if (task.getEnabled() != null && !task.getEnabled().equals(1)) {
// 同时禁用下级
String searchNum = pollingTask.getSearchNum();
LambdaUpdateWrapper<PollingTask> updateSql = new LambdaUpdateWrapper<>();
updateSql.eq(PollingTask::getSearchNum, searchNum)
.set(PollingTask::getEnabled, false);
update(updateSql);
}
pollingTask.setId(currentTask.getId());
updateById(pollingTask);
return currentTask.getId();
}
@SneakyThrows
@Override
public List<TaskExcelDTO> importRead(MultipartFile file) {
// try (InputStream inputStream = file.getInputStream()) {
return ExcelUtils.read(file, TaskExcelDTO.class);
// ExcelUtil.importExcel(inputStream, TaskExcelDTO.class, bulkShipping(pid));
// } catch (IOException e) {
// log.error("导入失败", e);
// Assert.isTrue(false, "导入失败");
// }
}
/**
* 读取保存
*/
@Override
public void importSave(List<TaskExcelDTO> taskExcel, Long parentId)
{
Map<String, Object> paramMap = new HashMap<>();
paramMap.put("data", taskExcel);
paramMap.put("parentId", parentId);
Long deptId = SecurityUtils.getDeptId();
String username = SecurityUtils.getUsername();
// 交给后台任务
remoteTaskService.createTask(
CreateTaskDTO.builder()
.params(JSON.toJSONString(paramMap))
.taskName("任务导入")
.applicationName(ServiceEnum.INSPECTION)
.methodName("importTask")
.className(this.getClass().getName())
.deptId(deptId)
.taskType(TaskTypeEnum.UPLOAD)
.createBy(username)
.build(), SecurityConstants.INNER
);
}
@Transactional
public Result<Boolean> importTask(String params)
{
JSONObject jsonObject = JSON.parseObject(params);
// 数据导入
List<TaskExcelDTO> tasks = jsonObject.getList("data", TaskExcelDTO.class);
// 数据集合
// 父类任务ID
Long parentId = jsonObject.getLong("parentId");
Map<String, Long> map = Maps.newHashMap();
// 一分
create(parentId == null ? 0 : parentId, tasks.stream().map(TaskExcelDTO::getFirstBank).distinct().collect(Collectors.toList()), map);
// 二分
extracted(tasks, map, TaskExcelDTO::getFirstBank, TaskExcelDTO::getSecondBank);
// 一支
extracted(tasks, map, TaskExcelDTO::getSecondBank, TaskExcelDTO::getFirstSubBank);
// 二支
extracted(tasks, map, TaskExcelDTO::getFirstSubBank, TaskExcelDTO::getSecondSubBank);
return Result.ok();
}
private void extracted(List<TaskExcelDTO> tasks, Map<String, Long> map, Function<TaskExcelDTO, String> groupingBy, Function<TaskExcelDTO, String> mapping) {
Map<String, Set<String>> secondBanks;
secondBanks = tasks.stream().filter(f -> StrUtil.isNotEmpty(groupingBy.apply(f)) && StrUtil.isNotEmpty(mapping.apply(f)))
.distinct().collect(Collectors.groupingBy(groupingBy,
Collectors.mapping(mapping, Collectors.toSet())));
if (CollUtil.isEmpty(secondBanks)) {
return;
}
secondBanks.forEach((k, v) -> create(map.get(k), new ArrayList<>(v), map));
}
private void create(Long pid, List<String> names, Map<String, Long> map) {
Assert.notNull(pid, "【{}】还未指定上级id", names);
names.forEach(name -> {
LambdaQueryWrapper<PollingTask> taskSql = WrapperUtils.builder();
taskSql.eq(PollingTask::getName, name).eq(PollingTask::getParentId, pid);
List<PollingTask> queryList = list(taskSql);
// 先通过名称和pid查询是否存在 存在直接返回id 不存在新增
if(CollUtil.isEmpty(queryList)){
map.put(name, saveTask(TaskDTO.builder().name(name).parentId(pid)
.enabled(1).build()));
}else{
map.put(name,queryList.get(0).getId());
}
}
);
}
private void processIndexes(PollingTask task) {
if (task.getParentId() != 0)
{
LambdaQueryWrapper<PollingTask> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(PollingTask::getParentId, task.getParentId()).last(Operator.LIMIT_ONE.getCharacter());
PollingTask superiorTask = getOne(queryWrapper);
// 获取上级
Assert.notNull(superiorTask, "上级任务不存在");
// 如果上级id存在
String index = superiorTask.getSearchNum();
int level = superiorTask.getLevel() + 1;
Integer max = getBaseMapper().childMaxIndex(index, level);
max = max != null ? max + 1 : 1;
task.setSearchNum(index + max + "-");
task.setSearchIndex(max);
task.setLevel(level);
// 只有顶级可以修改设置
task.setIsInspection(null);
task.setDispatchMethod(null);
task.setReviewMethod(null);
task.setIsRepeat(null);
}
else
{
// 顶级
Integer max = getBaseMapper().childMaxIndex(null, 1);
max = max == null ? 1 : max + 1;
task.setSearchNum(max + "-");
task.setSearchIndex(max);
task.setLevel(1);
}
}
private TaskVO convert(PollingTask task){
TaskVO taskVO = new TaskVO();
BeanUtil.copyProperties(task,taskVO);
return taskVO;
}
}