[add] 添加安全、质量知识库,分包工器具,分包工器具记录,

This commit is contained in:
lcj
2025-06-26 19:49:24 +08:00
parent 51bd7ed5d8
commit 48fb86cf84
80 changed files with 3395 additions and 436 deletions

View File

@ -232,9 +232,11 @@ springdoc:
packages-to-scan: org.dromara.progress
- group: 10.其他模块
packages-to-scan: org.dromara.other
- group: 11.代码生成模块
- group: 11.分包模块
packages-to-scan: org.dromara.contractor
- group: 12.代码生成模块
packages-to-scan: org.dromara.generator
- group: 12.工作流模块
- group: 13.工作流模块
packages-to-scan: org.dromara.workflow
# 防止XSS攻击

View File

@ -1,7 +1,10 @@
package org.dromara.test;
import cn.hutool.core.io.FileUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.dromara.facility.service.IFacPhotovoltaicPanelPartsService;
import org.dromara.project.service.IBusProjectService;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@ -12,12 +15,16 @@ import java.util.List;
* @author lcj
* @date 2025/5/30 9:48
*/
@Slf4j
@SpringBootTest
public class DemoTest {
@Resource
private IFacPhotovoltaicPanelPartsService photovoltaicPanelPartsService;
@Resource
private IBusProjectService projectService;
@Test
void test() {
Boolean result = photovoltaicPanelPartsService
@ -29,4 +36,22 @@ public class DemoTest {
List.of("G01.01.01", "G01.08.06")
);
}
@Test
void testProjectSync() {
projectService.insertProjectSyncThing(1897160897167638529L)
.thenAccept(result -> log.info("项目异步执行数据同步成功"))
.exceptionally(ex -> {
log.error("项目异步执行数据同步失败", ex);
return null;
});
;
}
@Test
void testMethod() {
String originalFilename = "test";
String suffix = FileUtil.getSuffix(originalFilename);
System.out.println(suffix);
}
}

View File

@ -1,4 +1,4 @@
package org.dromara.safety.domain.enums;
package org.dromara.common.enums;
import lombok.Getter;
@ -7,7 +7,7 @@ import lombok.Getter;
* @date 2025/4/14 14:03
*/
@Getter
public enum HseDocumentStatusEnum {
public enum DocumentStatusEnum {
NORMAL("正常", "0"),
DELETE("删除", "1");
@ -16,7 +16,7 @@ public enum HseDocumentStatusEnum {
private final String value;
HseDocumentStatusEnum(String text, String value) {
DocumentStatusEnum(String text, String value) {
this.text = text;
this.value = value;
}

View File

@ -1,4 +1,4 @@
package org.dromara.safety.domain.enums;
package org.dromara.common.enums;
import lombok.Getter;
@ -7,17 +7,17 @@ import lombok.Getter;
* @date 2025/4/14 10:42
*/
@Getter
public enum HseDocumentTypeEnum {
public enum DocumentTypeEnum {
FILE("文件", "1"),
FOLDER("文件", "2"),
FOLDER("文件", "1"),
FILE("文件", "2"),
PICTURE("图片", "3");
private final String text;
private final String value;
HseDocumentTypeEnum(String text, String value) {
DocumentTypeEnum(String text, String value) {
this.text = text;
this.value = value;
}

View File

@ -1,4 +1,4 @@
package org.dromara.utils;
package org.dromara.common.utils;
import java.math.BigDecimal;
import java.math.RoundingMode;

View File

@ -1,4 +1,4 @@
package org.dromara.utils;
package org.dromara.common.utils;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.XWPFDocument;

View File

@ -1,4 +1,4 @@
package org.dromara.utils;
package org.dromara.common.utils;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;

View File

@ -1,4 +1,4 @@
package org.dromara.utils;
package org.dromara.common.utils;
import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.SecureUtil;

View File

@ -1,8 +1,8 @@
package org.dromara.utils;
package org.dromara.common.utils;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.constant.GeoJsonConstant;
import org.dromara.common.constant.GeoJsonConstant;
import org.dromara.facility.domain.dto.geojson.FacFeatureByPlane;
import org.dromara.facility.domain.dto.geojson.FacFeatureByPoint;
import org.dromara.facility.domain.dto.geojson.FacGeometry;

View File

@ -1,4 +1,4 @@
package org.dromara.utils;
package org.dromara.common.utils;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

View File

@ -0,0 +1,106 @@
package org.dromara.contractor.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import org.dromara.common.core.domain.R;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.contractor.domain.dto.contractortoolentry.SubContractorToolRecordCreateReq;
import org.dromara.contractor.domain.dto.contractortoolentry.SubContractorToolRecordQueryReq;
import org.dromara.contractor.domain.dto.contractortoolentry.SubContractorToolRecordUpdateReq;
import org.dromara.contractor.domain.vo.contractortoolentry.SubContractorToolRecordVo;
import org.dromara.contractor.service.ISubContractorToolRecordService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 分包方工器具记录
*
* @author lcj
* @date 2025-06-26
*/
@Validated
@RestController
@RequestMapping("/contractor/contractorToolRecord")
public class SubContractorToolRecordController extends BaseController {
@Resource
private ISubContractorToolRecordService contractorToolRecordService;
/**
* 查询分包方工器具记录列表
*/
@SaCheckPermission("contractor:contractorToolRecord:list")
@GetMapping("/list")
public TableDataInfo<SubContractorToolRecordVo> list(SubContractorToolRecordQueryReq req, PageQuery pageQuery) {
return contractorToolRecordService.queryPageList(req, pageQuery);
}
/**
* 导出分包方工器具记录列表
*/
@SaCheckPermission("contractor:contractorToolRecord:export")
@Log(title = "分包方工器具记录", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(SubContractorToolRecordQueryReq req, HttpServletResponse response) {
List<SubContractorToolRecordVo> list = contractorToolRecordService.queryList(req);
ExcelUtil.exportExcel(list, "分包方工器具记录", SubContractorToolRecordVo.class, response);
}
/**
* 获取分包方工器具记录详细信息
*
* @param id 主键
*/
@SaCheckPermission("contractor:contractorToolRecord:query")
@GetMapping("/{id}")
public R<SubContractorToolRecordVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(contractorToolRecordService.queryById(id));
}
/**
* 新增分包方工器具记录
*/
@SaCheckPermission("contractor:contractorToolRecord:add")
@Log(title = "分包方工器具记录", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Long> add(@RequestBody SubContractorToolRecordCreateReq req) {
return R.ok(contractorToolRecordService.insertByBo(req));
}
/**
* 修改分包方工器具记录
*/
@SaCheckPermission("contractor:contractorToolRecord:edit")
@Log(title = "分包方工器具记录", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@RequestBody SubContractorToolRecordUpdateReq req) {
return toAjax(contractorToolRecordService.updateByBo(req));
}
/**
* 删除分包方工器具记录
*
* @param ids 主键串
*/
@SaCheckPermission("contractor:contractorToolRecord:remove")
@Log(title = "分包方工器具记录", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(contractorToolRecordService.deleteWithValidByIds(List.of(ids), true));
}
}

View File

@ -0,0 +1,87 @@
package org.dromara.contractor.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
import java.util.Date;
/**
* 分包方工器具记录对象 sub_contractor_tool_record
*
* @author lcj
* @date 2025-06-26
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sub_contractor_tool_record")
public class SubContractorToolRecord extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@TableId(value = "id")
private Long id;
/**
* 项目id
*/
private Long projectId;
/**
* 分包方id
*/
private Long contractorId;
/**
* 分包方工器具id
*/
private Long contractorToolId;
/**
* 记录类型(1进场 2出场)
*/
private String recordType;
/**
* 进场工器具数量
*/
private String toolNumber;
/**
* 检测编号
*/
private String checkNum;
/**
* 检测部门
*/
private String checkDept;
/**
* 检测时间
*/
private Date checkTime;
/**
* 合格证
*/
private String certificate;
/**
* 备注
*/
private String remark;
/**
* 进场时间
*/
private Date entryTime;
}

View File

@ -0,0 +1,63 @@
package org.dromara.contractor.domain.dto.contractortoolentry;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* @author lcj
* @date 2025/6/26 17:52
*/
@Data
public class SubContractorToolRecordCreateReq implements Serializable {
@Serial
private static final long serialVersionUID = 8161480499208093948L;
/**
* 分包方工器具id
*/
private Long contractorToolId;
/**
* 记录类型(1进场 2出场)
*/
private String recordType;
/**
* 进场工器具数量
*/
private String toolNumber;
/**
* 检测编号
*/
private String checkNum;
/**
* 检测部门
*/
private String checkDept;
/**
* 检测时间
*/
private Date checkTime;
/**
* 合格证
*/
private String certificate;
/**
* 备注
*/
private String remark;
/**
* 进场时间
*/
private Date entryTime;
}

View File

@ -0,0 +1,43 @@
package org.dromara.contractor.domain.dto.contractortoolentry;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/6/26 17:52
*/
@Data
public class SubContractorToolRecordQueryReq implements Serializable {
@Serial
private static final long serialVersionUID = -5521479525294608178L;
/**
* 项目id
*/
private Long projectId;
/**
* 分包方id
*/
private Long contractorId;
/**
* 分包方工器具id
*/
private Long contractorToolId;
/**
* 检测编号
*/
private String checkNum;
/**
* 检测部门
*/
private String checkDept;
}

View File

@ -0,0 +1,59 @@
package org.dromara.contractor.domain.dto.contractortoolentry;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* @author lcj
* @date 2025/6/26 17:52
*/
@Data
public class SubContractorToolRecordUpdateReq implements Serializable {
@Serial
private static final long serialVersionUID = 5280254073638207854L;
/**
* 主键id
*/
private Long id;
/**
* 进场工器具数量
*/
private String toolNumber;
/**
* 检测编号
*/
private String checkNum;
/**
* 检测部门
*/
private String checkDept;
/**
* 检测时间
*/
private Date checkTime;
/**
* 合格证
*/
private String certificate;
/**
* 备注
*/
private String remark;
/**
* 进场时间
*/
private Date entryTime;
}

View File

@ -0,0 +1,110 @@
package org.dromara.contractor.domain.vo.contractortoolentry;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.contractor.domain.SubContractorToolRecord;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 分包方工器具记录视图对象 sub_contractor_tool_entry
*
* @author lcj
* @date 2025-06-26
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = SubContractorToolRecord.class)
public class SubContractorToolRecordVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@ExcelProperty(value = "主键id")
private Long id;
/**
* 项目id
*/
@ExcelProperty(value = "项目id")
private Long projectId;
/**
* 分包方id
*/
@ExcelProperty(value = "分包方id")
private Long contractorId;
/**
* 分包方名称
*/
private String contractorName;
/**
* 分包方工器具id
*/
@ExcelProperty(value = "分包方工器具id")
private Long contractorToolId;
/**
* 分包方工器具名称
*/
private String contractorToolName;
/**
* 记录类型(1进场 2出场)
*/
@ExcelProperty(value = "记录类型(1进场 2出场)")
private String recordType;
/**
* 进场工器具数量
*/
@ExcelProperty(value = "进场工器具数量")
private String toolNumber;
/**
* 检测编号
*/
@ExcelProperty(value = "检测编号")
private String checkNum;
/**
* 检测部门
*/
@ExcelProperty(value = "检测部门")
private String checkDept;
/**
* 检测时间
*/
@ExcelProperty(value = "检测时间")
private Date checkTime;
/**
* 合格证
*/
@ExcelProperty(value = "合格证")
private String certificate;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 进场时间
*/
@ExcelProperty(value = "进场时间")
private Date entryTime;
}

View File

@ -0,0 +1,15 @@
package org.dromara.contractor.mapper;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import org.dromara.contractor.domain.SubContractorToolRecord;
import org.dromara.contractor.domain.vo.contractortoolentry.SubContractorToolRecordVo;
/**
* 分包方工器具记录Mapper接口
*
* @author lcj
* @date 2025-06-26
*/
public interface SubContractorToolRecordMapper extends BaseMapperPlus<SubContractorToolRecord, SubContractorToolRecordVo> {
}

View File

@ -0,0 +1,98 @@
package org.dromara.contractor.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.contractor.domain.SubContractorToolRecord;
import org.dromara.contractor.domain.dto.contractortoolentry.SubContractorToolRecordCreateReq;
import org.dromara.contractor.domain.dto.contractortoolentry.SubContractorToolRecordQueryReq;
import org.dromara.contractor.domain.dto.contractortoolentry.SubContractorToolRecordUpdateReq;
import org.dromara.contractor.domain.vo.contractortoolentry.SubContractorToolRecordVo;
import java.util.Collection;
import java.util.List;
/**
* 分包方工器具记录Service接口
*
* @author lcj
* @date 2025-06-26
*/
public interface ISubContractorToolRecordService extends IService<SubContractorToolRecord> {
/**
* 查询分包方工器具记录
*
* @param id 主键
* @return 分包方工器具记录
*/
SubContractorToolRecordVo queryById(Long id);
/**
* 分页查询分包方工器具记录列表
*
* @param req 查询条件
* @param pageQuery 分页参数
* @return 分包方工器具记录分页列表
*/
TableDataInfo<SubContractorToolRecordVo> queryPageList(SubContractorToolRecordQueryReq req, PageQuery pageQuery);
/**
* 查询符合条件的分包方工器具记录列表
*
* @param req 查询条件
* @return 分包方工器具记录列表
*/
List<SubContractorToolRecordVo> queryList(SubContractorToolRecordQueryReq req);
/**
* 新增分包方工器具记录
*
* @param req 分包方工器具记录
* @return 新增分包方工器具记录主键id
*/
Long insertByBo(SubContractorToolRecordCreateReq req);
/**
* 修改分包方工器具记录
*
* @param req 分包方工器具记录
* @return 是否修改成功
*/
Boolean updateByBo(SubContractorToolRecordUpdateReq req);
/**
* 校验并批量删除分包方工器具记录信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 获取分包方工器具记录视图对象
*
* @param contractorToolEntry 分包方工器具记录对象
* @return 分包方工器具记录视图对象
*/
SubContractorToolRecordVo getVo(SubContractorToolRecord contractorToolEntry);
/**
* 获取分包方工器具记录查询条件封装
*
* @param req 分包方工器具记录查询条件
* @return 分包方工器具记录查询条件封装
*/
LambdaQueryWrapper<SubContractorToolRecord> buildQueryWrapper(SubContractorToolRecordQueryReq req);
/**
* 获取分包方工器具记录分页对象视图
*
* @param contractorToolEntryPage 分包方工器具记录分页对象
* @return 分包方工器具记录分页对象视图
*/
Page<SubContractorToolRecordVo> getVoPage(Page<SubContractorToolRecord> contractorToolEntryPage);
}

View File

@ -0,0 +1,250 @@
package org.dromara.contractor.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.ObjectUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.contractor.domain.SubContractorToolRecord;
import org.dromara.contractor.domain.dto.contractortoolentry.SubContractorToolRecordCreateReq;
import org.dromara.contractor.domain.dto.contractortoolentry.SubContractorToolRecordQueryReq;
import org.dromara.contractor.domain.dto.contractortoolentry.SubContractorToolRecordUpdateReq;
import org.dromara.contractor.domain.vo.contractortoolentry.SubContractorToolRecordVo;
import org.dromara.contractor.mapper.SubContractorToolRecordMapper;
import org.dromara.contractor.service.ISubContractorToolRecordService;
import org.dromara.project.domain.BusContractor;
import org.dromara.project.domain.BusContractorTool;
import org.dromara.project.service.IBusContractorService;
import org.dromara.project.service.IBusContractorToolService;
import org.dromara.project.service.IBusProjectService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 分包方工器具记录Service业务层处理
*
* @author lcj
* @date 2025-06-26
*/
@Service
public class SubContractorToolRecordServiceImpl extends ServiceImpl<SubContractorToolRecordMapper, SubContractorToolRecord>
implements ISubContractorToolRecordService {
@Resource
private IBusProjectService projectService;
@Resource
private IBusContractorService contractorService;
@Resource
private IBusContractorToolService contractorToolService;
/**
* 查询分包方工器具记录
*
* @param id 主键
* @return 分包方工器具记录
*/
@Override
public SubContractorToolRecordVo queryById(Long id) {
SubContractorToolRecord entity = this.getById(id);
if (entity == null) {
throw new ServiceException("分包方工器具记录信息不存在", HttpStatus.NOT_FOUND);
}
return this.getVo(entity);
}
/**
* 分页查询分包方工器具记录列表
*
* @param req 查询条件
* @param pageQuery 分页参数
* @return 分包方工器具记录分页列表
*/
@Override
public TableDataInfo<SubContractorToolRecordVo> queryPageList(SubContractorToolRecordQueryReq req, PageQuery pageQuery) {
Page<SubContractorToolRecord> result = this.page(pageQuery.build(), this.buildQueryWrapper(req));
return TableDataInfo.build(this.getVoPage(result));
}
/**
* 查询符合条件的分包方工器具记录列表
*
* @param req 查询条件
* @return 分包方工器具记录列表
*/
@Override
public List<SubContractorToolRecordVo> queryList(SubContractorToolRecordQueryReq req) {
LambdaQueryWrapper<SubContractorToolRecord> lqw = buildQueryWrapper(req);
return this.list(lqw).stream().map(this::getVo).toList();
}
/**
* 新增分包方工器具记录
*
* @param req 分包方工器具记录
* @return 新增分包方工器具记录主键id
*/
@Override
public Long insertByBo(SubContractorToolRecordCreateReq req) {
SubContractorToolRecord entry = new SubContractorToolRecord();
BeanUtils.copyProperties(req, entry);
Long contractorToolId = req.getContractorToolId();
if (contractorToolId == null) {
throw new ServiceException("工器具id不能为空", HttpStatus.BAD_REQUEST);
}
BusContractorTool contractorTool = contractorToolService.getById(contractorToolId);
if (contractorTool == null) {
throw new ServiceException("分包方工器具不存在", HttpStatus.NOT_FOUND);
}
// 填充默认值
entry.setProjectId(contractorTool.getProjectId());
entry.setContractorId(contractorTool.getContractorId());
boolean save = this.save(entry);
if (!save) {
throw new ServiceException("分包方工器具记录失败", HttpStatus.ERROR);
}
return entry.getId();
}
/**
* 修改分包方工器具记录
*
* @param req 分包方工器具记录
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(SubContractorToolRecordUpdateReq req) {
SubContractorToolRecord entry = new SubContractorToolRecord();
BeanUtils.copyProperties(req, entry);
SubContractorToolRecord contractorToolEntry = this.getById(entry.getId());
if (contractorToolEntry == null) {
throw new ServiceException("修改分包方工器具记录失败,数据不存在", HttpStatus.NOT_FOUND);
}
boolean result = this.updateById(entry);
if (!result) {
throw new ServiceException("修改分包方工器具记录失败", HttpStatus.ERROR);
}
return true;
}
/**
* 校验并批量删除分包方工器具记录信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
Long userId = LoginHelper.getUserId();
List<SubContractorToolRecord> list = this.listByIds(ids);
if (isValid) {
List<Long> projectIdList = list.stream().map(SubContractorToolRecord::getProjectId).toList();
projectService.validAuth(projectIdList, userId);
}
return this.removeBatchByIds(ids);
}
/**
* 获取分包方工器具记录视图对象
*
* @param contractorToolEntry 分包方工器具记录对象
* @return 分包方工器具记录视图对象
*/
@Override
public SubContractorToolRecordVo getVo(SubContractorToolRecord contractorToolEntry) {
SubContractorToolRecordVo vo = new SubContractorToolRecordVo();
if (contractorToolEntry == null) {
throw new ServiceException("数据不存在");
}
BeanUtils.copyProperties(contractorToolEntry, vo);
BusContractorTool contractorTool = contractorToolService.getById(vo.getContractorToolId());
if (contractorTool != null) {
vo.setContractorToolName(contractorTool.getToolName());
}
BusContractor contractor = contractorService.getById(vo.getContractorId());
if (contractor != null) {
vo.setContractorName(contractor.getName());
}
return vo;
}
/**
* 获取分包方工器具记录查询条件封装
*
* @param req 分包方工器具记录查询条件
* @return 分包方工器具记录查询条件封装
*/
@Override
public LambdaQueryWrapper<SubContractorToolRecord> buildQueryWrapper(SubContractorToolRecordQueryReq req) {
LambdaQueryWrapper<SubContractorToolRecord> lqw = new LambdaQueryWrapper<>();
if (req == null) {
return lqw;
}
Long projectId = req.getProjectId();
Long contractorId = req.getContractorId();
Long contractorToolId = req.getContractorToolId();
String checkNum = req.getCheckNum();
String checkDept = req.getCheckDept();
lqw.eq(ObjectUtils.isNotEmpty(projectId), SubContractorToolRecord::getProjectId, projectId);
lqw.eq(ObjectUtils.isNotEmpty(contractorId), SubContractorToolRecord::getContractorId, contractorId);
lqw.eq(ObjectUtils.isNotEmpty(contractorToolId), SubContractorToolRecord::getContractorToolId, contractorToolId);
lqw.like(StringUtils.isNotBlank(checkNum), SubContractorToolRecord::getCheckNum, checkNum);
lqw.like(StringUtils.isNotBlank(checkDept), SubContractorToolRecord::getCheckDept, checkDept);
return lqw;
}
/**
* 获取分包方工器具记录分页对象视图
*
* @param contractorToolEntryPage 分包方工器具记录分页对象
* @return 分包方工器具记录分页对象视图
*/
@Override
public Page<SubContractorToolRecordVo> getVoPage(Page<SubContractorToolRecord> contractorToolEntryPage) {
List<SubContractorToolRecord> contractorToolEntryList = contractorToolEntryPage.getRecords();
Page<SubContractorToolRecordVo> contractorToolEntryVoPage = new Page<>(
contractorToolEntryPage.getCurrent(),
contractorToolEntryPage.getSize(),
contractorToolEntryPage.getTotal());
if (CollUtil.isEmpty(contractorToolEntryList)) {
return contractorToolEntryVoPage;
}
Set<Long> contractorIdList = contractorToolEntryList.stream().map(SubContractorToolRecord::getContractorId).collect(Collectors.toSet());
Map<Long, BusContractor> contractorMap = contractorService.listByIds(contractorIdList)
.stream().collect(Collectors.toMap(BusContractor::getId, v -> v));
Set<Long> contractorToolIdList = contractorToolEntryList.stream().map(SubContractorToolRecord::getContractorToolId).collect(Collectors.toSet());
Map<Long, BusContractorTool> contractorToolMap = contractorToolService.listByIds(contractorToolIdList)
.stream().collect(Collectors.toMap(BusContractorTool::getId, v -> v));
List<SubContractorToolRecordVo> contractorToolEntryVoList = contractorToolEntryList.stream().map(entity -> {
SubContractorToolRecordVo vo = new SubContractorToolRecordVo();
BeanUtils.copyProperties(entity, vo);
if (contractorToolMap.containsKey(entity.getContractorToolId())) {
vo.setContractorToolName(contractorToolMap.get(entity.getContractorToolId()).getToolName());
}
if (contractorMap.containsKey(entity.getContractorId())) {
vo.setContractorName(contractorMap.get(entity.getContractorId()).getName());
}
return vo;
}).toList();
contractorToolEntryVoPage.setRecords(contractorToolEntryVoList);
return contractorToolEntryVoPage;
}
}

View File

@ -4,7 +4,7 @@ import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import lombok.Data;
import org.dromara.facility.domain.enums.FacCoordinateTypeEnum;
import org.dromara.utils.JsonDimensionUtil;
import org.dromara.common.utils.JsonDimensionUtil;
import java.io.Serial;
import java.io.Serializable;

View File

@ -30,7 +30,7 @@ import org.dromara.progress.constant.PgsProgressCategoryConstant;
import org.dromara.progress.domain.PgsProgressCategory;
import org.dromara.progress.service.IPgsProgressCategoryService;
import org.dromara.project.service.IBusProjectService;
import org.dromara.utils.JSTUtil;
import org.dromara.common.utils.JSTUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -146,8 +146,7 @@ public class FacBoxTransformerServiceImpl extends ServiceImpl<FacBoxTransformerM
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByGeoJson(FacBoxTransformerCreateByGeoJsonReq geoJson) {
// Long projectId = geoJson.getProjectId();
Long projectId = 1930896467736707073L;
Long projectId = geoJson.getProjectId();
if (projectService.getById(projectId) == null) {
throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND);
}

View File

@ -30,7 +30,7 @@ import org.dromara.progress.constant.PgsProgressCategoryConstant;
import org.dromara.progress.domain.PgsProgressCategory;
import org.dromara.progress.service.IPgsProgressCategoryService;
import org.dromara.project.service.IBusProjectService;
import org.dromara.utils.JSTUtil;
import org.dromara.common.utils.JSTUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -146,8 +146,7 @@ public class FacInverterServiceImpl extends ServiceImpl<FacInverterMapper, FacIn
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByGeoJson(FacInverterCreateByGeoJsonReq geoJson) {
// Long projectId = geoJson.getProjectId();
Long projectId = 1930896467736707073L;
Long projectId = geoJson.getProjectId();
if (projectService.getById(projectId) == null) {
throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND);
}

View File

@ -27,7 +27,7 @@ import org.dromara.facility.service.*;
import org.dromara.progress.service.IPgsProgressCategoryService;
import org.dromara.project.domain.BusProject;
import org.dromara.project.service.IBusProjectService;
import org.dromara.utils.JSTUtil;
import org.dromara.common.utils.JSTUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
@ -260,8 +260,7 @@ public class FacMatrixServiceImpl extends ServiceImpl<FacMatrixMapper, FacMatrix
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByGeoJson(FacMatrixCreateByGeoJsonReq geoJson) {
// Long projectId = geoJson.getProjectId();
Long projectId = 1930896467736707073L;
Long projectId = geoJson.getProjectId();
// 判断 redis key 是否存在,存在则返回
List<String> operationRedisKey = FacRedisKeyConstant.getInOperationRedisKeyList(projectId);
List<Object> list = redisTemplate.opsForValue().multiGet(operationRedisKey);

View File

@ -28,7 +28,7 @@ import org.dromara.progress.constant.PgsProgressCategoryConstant;
import org.dromara.progress.domain.PgsProgressCategory;
import org.dromara.progress.service.IPgsProgressCategoryService;
import org.dromara.project.service.IBusProjectService;
import org.dromara.utils.JSTUtil;
import org.dromara.common.utils.JSTUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.dao.DataAccessException;
@ -89,8 +89,7 @@ public class FacPhotovoltaicPanelPartsServiceImpl implements IFacPhotovoltaicPan
*/
@Override
public Boolean insertPartsByGeoJson(FacPhotovoltaicPanelPartsCreateByGeoJsonReq geoJson) {
// Long projectId = geoJson.getProjectId();
Long projectId = 1930896467736707073L;
Long projectId = geoJson.getProjectId();
// 判断 redis key 是否存在,存在则返回
List<String> operationRedisKey = FacRedisKeyConstant.getInOperationRedisKeyList(projectId);
List<Object> list = redisTemplate.opsForValue().multiGet(operationRedisKey);

View File

@ -37,7 +37,7 @@ import org.dromara.progress.constant.PgsProgressCategoryConstant;
import org.dromara.progress.domain.PgsProgressCategory;
import org.dromara.progress.service.IPgsProgressCategoryService;
import org.dromara.project.service.IBusProjectService;
import org.dromara.utils.JSTUtil;
import org.dromara.common.utils.JSTUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.dao.DataAccessException;
@ -170,8 +170,7 @@ public class FacPhotovoltaicPanelServiceImpl extends ServiceImpl<FacPhotovoltaic
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertByGeoJson(FacPhotovoltaicPanelCreateByGeoJsonReq geoJson) {
// Long projectId = geoJson.getProjectId();
Long projectId = 1930896467736707073L;
Long projectId = geoJson.getProjectId();
// 判断 redis key 是否存在,存在则返回
List<String> operationRedisKey = FacRedisKeyConstant.getInOperationRedisKeyList(projectId);
List<Object> list = redisTemplate.opsForValue().multiGet(operationRedisKey);

View File

@ -26,7 +26,7 @@ import java.util.stream.Collectors;
* @date 2025/6/18 15:59
*/
@Slf4j
@Component
//@Component
public class IncSyncYs7DeviceCapturePicData {
@Resource
@ -44,8 +44,7 @@ public class IncSyncYs7DeviceCapturePicData {
private final ExecutorService executorService = Executors.newFixedThreadPool(5);
// 每 30 分钟执行一次
// todo 修改为 30 分钟
@Scheduled(cron = "0 0 7-19 * * ?")
@Scheduled(cron = "0 */30 7-19 * * ?")
public void run() {
// 查询所有在线的摄像头设备,仅获取必要字段
List<OthYs7Device> deviceList = ys7DeviceService.lambdaQuery()

View File

@ -15,7 +15,7 @@ import java.util.List;
* @date 2025/6/17 9:33
*/
@Slf4j
@Component
//@Component
public class IncSyncYs7DeviceData {
@Resource
@ -24,9 +24,8 @@ public class IncSyncYs7DeviceData {
@Resource
private IOthYs7DeviceService ys7DeviceService;
// 每 5 分钟执行一次
// todo 修改为 5 分钟
@Scheduled(cron = "0 */10 * * * ?")
// 每 1 分钟执行一次
@Scheduled(cron = "0 */1 * * * ?")
public void run() {
log.info("定时同步摄像头设备数据");
List<Ys7QueryDeviceResponseVo> ys7QueryDeviceList = ys7Manager.queryAllDeviceList();

View File

@ -35,8 +35,8 @@ import org.dromara.progress.service.IPgsProgressPlanDetailService;
import org.dromara.progress.service.IPgsProgressPlanService;
import org.dromara.project.domain.BusProject;
import org.dromara.project.service.IBusProjectService;
import org.dromara.utils.BigDecimalUtil;
import org.dromara.utils.JsonDimensionUtil;
import org.dromara.common.utils.BigDecimalUtil;
import org.dromara.common.utils.JsonDimensionUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

View File

@ -38,7 +38,7 @@ import org.dromara.progress.mapper.PgsProgressPlanDetailMapper;
import org.dromara.progress.service.IPgsProgressCategoryService;
import org.dromara.progress.service.IPgsProgressPlanDetailService;
import org.dromara.progress.service.IPgsProgressPlanService;
import org.dromara.utils.PageConvertUtil;
import org.dromara.common.utils.PageConvertUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

View File

@ -0,0 +1,108 @@
package org.dromara.project.controller;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.project.domain.dto.contractortool.BusContractorToolCreateReq;
import org.dromara.project.domain.dto.contractortool.BusContractorToolQueryReq;
import org.dromara.project.domain.dto.contractortool.BusContractorToolUpdateReq;
import org.dromara.project.domain.vo.contractortool.BusContractorToolVo;
import org.dromara.project.service.IBusContractorToolService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 分包方工器具
*
* @author lcj
* @date 2025-06-26
*/
@Validated
@RestController
@RequestMapping("/project/contractorTool")
public class BusContractorToolController extends BaseController {
@Resource
private IBusContractorToolService busContractorToolService;
/**
* 查询分包方工器具列表
*/
@SaCheckPermission("project:contractorTool:list")
@GetMapping("/list")
public TableDataInfo<BusContractorToolVo> list(BusContractorToolQueryReq req, PageQuery pageQuery) {
return busContractorToolService.queryPageList(req, pageQuery);
}
/**
* 导出分包方工器具列表
*/
@SaCheckPermission("project:contractorTool:export")
@Log(title = "分包方工器具", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(BusContractorToolQueryReq req, HttpServletResponse response) {
List<BusContractorToolVo> list = busContractorToolService.queryList(req);
ExcelUtil.exportExcel(list, "分包方工器具", BusContractorToolVo.class, response);
}
/**
* 获取分包方工器具详细信息
*
* @param id 主键
*/
@SaCheckPermission("project:contractorTool:query")
@GetMapping("/{id}")
public R<BusContractorToolVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(busContractorToolService.queryById(id));
}
/**
* 新增分包方工器具
*/
@SaCheckPermission("project:contractorTool:add")
@Log(title = "分包方工器具", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Long> add(@Validated(AddGroup.class) @RequestBody BusContractorToolCreateReq req) {
return R.ok(busContractorToolService.insertByBo(req));
}
/**
* 修改分包方工器具
*/
@SaCheckPermission("project:contractorTool:edit")
@Log(title = "分包方工器具", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody BusContractorToolUpdateReq req) {
return toAjax(busContractorToolService.updateByBo(req));
}
/**
* 删除分包方工器具
*
* @param ids 主键串
*/
@SaCheckPermission("project:contractorTool:remove")
@Log(title = "分包方工器具", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(busContractorToolService.deleteWithValidByIds(List.of(ids), true));
}
}

View File

@ -35,6 +35,11 @@ public class BusContractor extends BaseEntity {
*/
private Long projectId;
/**
* 部门id
*/
private Long deptId;
/**
* 公司名称
*/

View File

@ -0,0 +1,84 @@
package org.dromara.project.domain;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.io.Serial;
import java.util.Date;
/**
* 分包方工器具对象 bus_contractor_tool
*
* @author lcj
* @date 2025-06-26
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("bus_contractor_tool")
public class BusContractorTool extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@TableId(value = "id")
private Long id;
/**
* 项目id
*/
private Long projectId;
/**
* 分包方id
*/
private Long contractorId;
/**
* 工具名称
*/
private String toolName;
/**
* 工具类型
*/
private String toolType;
/**
* 工具型号
*/
private String toolModel;
/**
* 工具数量
*/
private String toolNumber;
/**
* 文件
*/
private String file;
/**
* 备注
*/
private String remark;
/**
* 删除时间
*/
private Date deletedAt;
/**
* 是否删除0正常 1删除
*/
@TableLogic
private Long isDelete;
}

View File

@ -0,0 +1,58 @@
package org.dromara.project.domain.dto.contractortool;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/6/26 15:26
*/
@Data
public class BusContractorToolCreateReq implements Serializable {
@Serial
private static final long serialVersionUID = -148571725751082526L;
/**
* 项目id
*/
private Long projectId;
/**
* 分包方id
*/
private Long contractorId;
/**
* 工具名称
*/
private String toolName;
/**
* 工具类型
*/
private String toolType;
/**
* 工具型号
*/
private String toolModel;
/**
* 工具数量
*/
private String toolNumber;
/**
* 文件
*/
private String file;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,43 @@
package org.dromara.project.domain.dto.contractortool;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/6/26 15:26
*/
@Data
public class BusContractorToolQueryReq implements Serializable {
@Serial
private static final long serialVersionUID = -654101391027815665L;
/**
* 项目id
*/
private Long projectId;
/**
* 分包方id
*/
private Long contractorId;
/**
* 工具名称
*/
private String toolName;
/**
* 工具类型
*/
private String toolType;
/**
* 工具型号
*/
private String toolModel;
}

View File

@ -0,0 +1,63 @@
package org.dromara.project.domain.dto.contractortool;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/6/26 15:26
*/
@Data
public class BusContractorToolUpdateReq implements Serializable {
@Serial
private static final long serialVersionUID = 6147452720586538283L;
/**
* 主键id
*/
private Long id;
/**
* 项目id
*/
private Long projectId;
/**
* 分包方id
*/
private Long contractorId;
/**
* 工具名称
*/
private String toolName;
/**
* 工具类型
*/
private String toolType;
/**
* 工具型号
*/
private String toolModel;
/**
* 工具数量
*/
private String toolNumber;
/**
* 文件
*/
private String file;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,90 @@
package org.dromara.project.domain.vo.contractortool;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import org.dromara.project.domain.BusContractorTool;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* 分包方工器具视图对象 bus_contractor_tool
*
* @author lcj
* @date 2025-06-26
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = BusContractorTool.class)
public class BusContractorToolVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键id
*/
@ExcelProperty(value = "主键id")
private Long id;
/**
* 项目id
*/
@ExcelProperty(value = "项目id")
private Long projectId;
/**
* 分包方id
*/
@ExcelProperty(value = "分包方id")
private Long contractorId;
/**
* 分包方名称
*/
private String contractorName;
/**
* 工具名称
*/
@ExcelProperty(value = "工具名称")
private String toolName;
/**
* 工具类型
*/
@ExcelProperty(value = "工具类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "contractor_tool_type")
private String toolType;
/**
* 工具型号
*/
@ExcelProperty(value = "工具型号")
private String toolModel;
/**
* 工具数量
*/
@ExcelProperty(value = "工具数量")
private String toolNumber;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 创建时间
*/
@ExcelProperty(value = "创建时间")
private Date createTime;
}

View File

@ -0,0 +1,15 @@
package org.dromara.project.mapper;
import org.dromara.project.domain.BusContractorTool;
import org.dromara.project.domain.vo.contractortool.BusContractorToolVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
/**
* 分包方工器具Mapper接口
*
* @author lcj
* @date 2025-06-26
*/
public interface BusContractorToolMapper extends BaseMapperPlus<BusContractorTool, BusContractorToolVo> {
}

View File

@ -0,0 +1,98 @@
package org.dromara.project.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.project.domain.BusContractorTool;
import org.dromara.project.domain.dto.contractortool.BusContractorToolCreateReq;
import org.dromara.project.domain.dto.contractortool.BusContractorToolQueryReq;
import org.dromara.project.domain.dto.contractortool.BusContractorToolUpdateReq;
import org.dromara.project.domain.vo.contractortool.BusContractorToolVo;
import java.util.Collection;
import java.util.List;
/**
* 分包方工器具Service接口
*
* @author lcj
* @date 2025-06-26
*/
public interface IBusContractorToolService extends IService<BusContractorTool> {
/**
* 查询分包方工器具
*
* @param id 主键
* @return 分包方工器具
*/
BusContractorToolVo queryById(Long id);
/**
* 分页查询分包方工器具列表
*
* @param req 查询条件
* @param pageQuery 分页参数
* @return 分包方工器具分页列表
*/
TableDataInfo<BusContractorToolVo> queryPageList(BusContractorToolQueryReq req, PageQuery pageQuery);
/**
* 查询符合条件的分包方工器具列表
*
* @param req 查询条件
* @return 分包方工器具列表
*/
List<BusContractorToolVo> queryList(BusContractorToolQueryReq req);
/**
* 新增分包方工器具
*
* @param req 分包方工器具
* @return 新增分包工器具主键id
*/
Long insertByBo(BusContractorToolCreateReq req);
/**
* 修改分包方工器具
*
* @param req 分包方工器具
* @return 是否修改成功
*/
Boolean updateByBo(BusContractorToolUpdateReq req);
/**
* 校验并批量删除分包方工器具信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 获取分包方工器具视图对象
*
* @param contractorTool 分包方工器具对象
* @return 分包方工器具视图对象
*/
BusContractorToolVo getVo(BusContractorTool contractorTool);
/**
* 获取分包方工器具查询条件封装
*
* @param req 分包方工器具查询条件
* @return 分包方工器具查询条件封装
*/
LambdaQueryWrapper<BusContractorTool> buildQueryWrapper(BusContractorToolQueryReq req);
/**
* 获取分包方工器具分页对象视图
*
* @param contractorPage 分包方工器具分页对象
* @return 分包方工器具分页对象视图
*/
Page<BusContractorToolVo> getVoPage(Page<BusContractorTool> contractorPage);
}

View File

@ -25,7 +25,7 @@ import org.dromara.project.service.IBusConstructionBlacklistService;
import org.dromara.project.service.IBusConstructionUserService;
import org.dromara.project.service.IBusProjectService;
import org.dromara.project.service.IBusProjectTeamMemberService;
import org.dromara.utils.IdCardEncryptorUtil;
import org.dromara.common.utils.IdCardEncryptorUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

View File

@ -33,7 +33,7 @@ import org.dromara.project.service.*;
import org.dromara.system.domain.vo.SysOssVo;
import org.dromara.system.service.ISysDictTypeService;
import org.dromara.system.service.ISysOssService;
import org.dromara.utils.IdCardEncryptorUtil;
import org.dromara.common.utils.IdCardEncryptorUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

View File

@ -18,6 +18,7 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.project.domain.BusConstructionUser;
import org.dromara.project.domain.BusContractor;
import org.dromara.project.domain.BusProject;
import org.dromara.project.domain.dto.contractor.BusContractorCreateReq;
import org.dromara.project.domain.dto.contractor.BusContractorQueryReq;
import org.dromara.project.domain.dto.contractor.BusContractorUpdateReq;
@ -26,6 +27,9 @@ import org.dromara.project.mapper.BusContractorMapper;
import org.dromara.project.service.IBusConstructionUserService;
import org.dromara.project.service.IBusContractorService;
import org.dromara.project.service.IBusProjectService;
import org.dromara.system.domain.bo.SysDeptBo;
import org.dromara.system.service.ISysDeptService;
import org.dromara.system.service.ISysPostService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -51,6 +55,12 @@ public class BusContractorServiceImpl extends ServiceImpl<BusContractorMapper, B
@Resource
private IBusProjectService projectService;
@Resource
private ISysDeptService deptService;
@Resource
private ISysPostService postService;
/**
* 查询分包单位
*
@ -100,6 +110,7 @@ public class BusContractorServiceImpl extends ServiceImpl<BusContractorMapper, B
* @return 新增id
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Long insertByBo(BusContractorCreateReq req) {
// 将实体类和 DTO 进行转换
BusContractor contractor = new BusContractor();
@ -110,10 +121,36 @@ public class BusContractorServiceImpl extends ServiceImpl<BusContractorMapper, B
contractor.setFiles(fileMapStr);
// 数据校验
validEntityBeforeSave(contractor, true);
Long count = this.lambdaQuery().eq(BusContractor::getName, req.getName()).count();
String name = req.getName();
Long count = this.lambdaQuery().eq(BusContractor::getName, name).count();
if (count > 0) {
throw new ServiceException("分包单位名称重复", HttpStatus.BAD_REQUEST);
}
Long projectId = req.getProjectId();
BusProject project = projectService.getById(projectId);
if (project == null) {
throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND);
}
// 创建部门
Long deptId = project.getDeptId();
SysDeptBo createBo = new SysDeptBo();
createBo.setParentId(deptId);
createBo.setDeptName(name);
if (!deptService.checkDeptNameUnique(createBo)) {
throw new ServiceException("新增项目部门'" + createBo.getDeptName() + "'失败,项目名称已存在");
}
// 新增部门
int dept = deptService.insertDept(createBo);
if (dept <= 0) {
throw new ServiceException("新增项目部门'" + createBo.getDeptName() + "'失败");
}
Long newDeptId = deptService.selectIdByDeptName(createBo.getDeptName());
contractor.setDeptId(newDeptId);
// 新增岗位
Boolean result = postService.insertPostByDeptId(newDeptId);
if (!result) {
throw new ServiceException("对应岗位类型保存失败");
}
// 操作数据库
boolean save = this.save(contractor);
if (!save) {

View File

@ -0,0 +1,246 @@
package org.dromara.project.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.ObjectUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.project.domain.BusContractor;
import org.dromara.project.domain.BusContractorTool;
import org.dromara.project.domain.dto.contractortool.BusContractorToolCreateReq;
import org.dromara.project.domain.dto.contractortool.BusContractorToolQueryReq;
import org.dromara.project.domain.dto.contractortool.BusContractorToolUpdateReq;
import org.dromara.project.domain.vo.contractortool.BusContractorToolVo;
import org.dromara.project.mapper.BusContractorToolMapper;
import org.dromara.project.service.IBusContractorService;
import org.dromara.project.service.IBusContractorToolService;
import org.dromara.project.service.IBusProjectService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* 分包方工器具Service业务层处理
*
* @author lcj
* @date 2025-06-26
*/
@Service
public class BusContractorToolServiceImpl extends ServiceImpl<BusContractorToolMapper, BusContractorTool>
implements IBusContractorToolService {
@Resource
private IBusProjectService projectService;
@Resource
private IBusContractorService contractorService;
/**
* 查询分包方工器具
*
* @param id 主键
* @return 分包方工器具
*/
@Override
public BusContractorToolVo queryById(Long id) {
BusContractorTool contractorTool = this.getById(id);
if (contractorTool == null) {
throw new ServiceException("分包方工器具信息不存在", HttpStatus.NOT_FOUND);
}
return this.getVo(contractorTool);
}
/**
* 分页查询分包方工器具列表
*
* @param req 查询条件
* @param pageQuery 分页参数
* @return 分包方工器具分页列表
*/
@Override
public TableDataInfo<BusContractorToolVo> queryPageList(BusContractorToolQueryReq req, PageQuery pageQuery) {
Page<BusContractorTool> result = this.page(pageQuery.build(), this.buildQueryWrapper(req));
return TableDataInfo.build(this.getVoPage(result));
}
/**
* 查询符合条件的分包方工器具列表
*
* @param req 查询条件
* @return 分包方工器具列表
*/
@Override
public List<BusContractorToolVo> queryList(BusContractorToolQueryReq req) {
LambdaQueryWrapper<BusContractorTool> lqw = this.buildQueryWrapper(req);
return this.list(lqw).stream().map(this::getVo).toList();
}
/**
* 新增分包方工器具
*
* @param req 分包方工器具
* @return 新增分包工器具主键id
*/
@Override
public Long insertByBo(BusContractorToolCreateReq req) {
BusContractorTool contractorTool = new BusContractorTool();
BeanUtils.copyProperties(req, contractorTool);
validEntityBeforeSave(contractorTool, true);
boolean result = this.save(contractorTool);
if (!result) {
throw new ServiceException("分包方工器具新增失败", HttpStatus.ERROR);
}
return contractorTool.getId();
}
/**
* 修改分包方工器具
*
* @param req 分包方工器具
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(BusContractorToolUpdateReq req) {
Long id = req.getId();
BusContractorTool oldContractorTool = this.getById(id);
if (oldContractorTool == null) {
throw new ServiceException("修改分包方工器具失败,数据不存在", HttpStatus.NOT_FOUND);
}
BusContractorTool contractorTool = new BusContractorTool();
BeanUtils.copyProperties(req, contractorTool);
validEntityBeforeSave(contractorTool, false);
boolean result = this.updateById(contractorTool);
if (!result) {
throw new ServiceException("修改分包方工器具失败", HttpStatus.ERROR);
}
return true;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(BusContractorTool entity, Boolean create) {
Long projectId = entity.getProjectId();
Long contractorId = entity.getContractorId();
if (create) {
if (projectId == null) {
throw new ServiceException("项目 id 不能为空", HttpStatus.BAD_REQUEST);
}
if (contractorId == null) {
throw new ServiceException("合同方 id 不能为空", HttpStatus.BAD_REQUEST);
}
}
if (projectId != null && projectService.getById(projectId) == null) {
throw new ServiceException("对应项目不存在", HttpStatus.NOT_FOUND);
}
if (contractorId != null && contractorService.getById(contractorId) == null) {
throw new ServiceException("对应分包方不存在", HttpStatus.NOT_FOUND);
}
}
/**
* 校验并批量删除分包方工器具信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @return 是否删除成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
Long userId = LoginHelper.getUserId();
List<BusContractorTool> contractorToolList = this.listByIds(ids);
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
List<Long> projectIdList = contractorToolList.stream().map(BusContractorTool::getProjectId).distinct().toList();
projectService.validAuth(projectIdList, userId);
}
return this.removeBatchByIds(ids);
}
/**
* 获取分包方工器具视图对象
*
* @param contractorTool 分包方工器具对象
* @return 分包方工器具视图对象
*/
@Override
public BusContractorToolVo getVo(BusContractorTool contractorTool) {
BusContractorToolVo contractorToolVo = new BusContractorToolVo();
if (contractorTool == null) {
return contractorToolVo;
}
BeanUtils.copyProperties(contractorTool, contractorToolVo);
Long contractorId = contractorTool.getContractorId();
BusContractor contractor = contractorService.getById(contractorId);
contractorToolVo.setContractorName(contractor.getName());
return contractorToolVo;
}
/**
* 获取分包方工器具查询条件封装
*
* @param req 分包方工器具查询条件
* @return 分包方工器具查询条件封装
*/
@Override
public LambdaQueryWrapper<BusContractorTool> buildQueryWrapper(BusContractorToolQueryReq req) {
LambdaQueryWrapper<BusContractorTool> lqw = new LambdaQueryWrapper<>();
Long projectId = req.getProjectId();
Long contractorId = req.getContractorId();
String toolName = req.getToolName();
String toolType = req.getToolType();
String toolModel = req.getToolModel();
lqw.eq(ObjectUtils.isNotEmpty(projectId), BusContractorTool::getProjectId, projectId);
lqw.eq(ObjectUtils.isNotEmpty(contractorId), BusContractorTool::getContractorId, contractorId);
lqw.eq(StringUtils.isNotBlank(toolType), BusContractorTool::getToolType, toolType);
lqw.like(StringUtils.isNotBlank(toolName), BusContractorTool::getToolName, toolName);
lqw.like(StringUtils.isNotBlank(toolModel), BusContractorTool::getToolModel, toolModel);
return lqw;
}
/**
* 获取分包方工器具分页对象视图
*
* @param contractorPage 分包方工器具分页对象
* @return 分包方工器具分页对象视图
*/
@Override
public Page<BusContractorToolVo> getVoPage(Page<BusContractorTool> contractorPage) {
List<BusContractorTool> contractorToolList = contractorPage.getRecords();
Page<BusContractorToolVo> contractorToolVoPage = new Page<>(
contractorPage.getCurrent(),
contractorPage.getSize(),
contractorPage.getTotal());
if (CollUtil.isEmpty(contractorToolList)) {
return contractorToolVoPage;
}
Set<Long> contractorIdList = contractorToolList.stream().map(BusContractorTool::getContractorId).collect(Collectors.toSet());
Map<Long, BusContractor> contractorMap = contractorService.listByIds(contractorIdList)
.stream().collect(Collectors.toMap(BusContractor::getId, v -> v));
List<BusContractorToolVo> contractorToolVoList = contractorToolList.stream().map(contractorTool -> {
BusContractorToolVo contractorToolVo = new BusContractorToolVo();
BeanUtils.copyProperties(contractorTool, contractorToolVo);
Long contractorId = contractorTool.getContractorId();
if (contractorMap.containsKey(contractorId)) {
contractorToolVo.setContractorName(contractorMap.get(contractorId).getName());
}
return contractorToolVo;
}).toList();
contractorToolVoPage.setRecords(contractorToolVoList);
return contractorToolVoPage;
}
}

View File

@ -20,7 +20,7 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.sse.dto.SseMessageDto;
import org.dromara.common.sse.utils.SseMessageUtils;
import org.dromara.constant.DesignMapFileConstant;
import org.dromara.common.constant.DesignMapFileConstant;
import org.dromara.project.domain.BusProject;
import org.dromara.project.domain.BusProjectFile;
import org.dromara.project.domain.dto.projectfile.BusProjectFileQueryReq;
@ -30,7 +30,7 @@ import org.dromara.project.domain.vo.projectfile.BusProjectFileVo;
import org.dromara.project.mapper.BusProjectFileMapper;
import org.dromara.project.service.IBusProjectFileService;
import org.dromara.project.service.IBusProjectService;
import org.dromara.utils.Dxf2JsonUtil;
import org.dromara.common.utils.Dxf2JsonUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

View File

@ -52,6 +52,7 @@ import org.dromara.safety.service.IHseKnowledgeDocumentService;
import org.dromara.system.domain.bo.SysDeptBo;
import org.dromara.system.domain.vo.SysDeptVo;
import org.dromara.system.service.ISysDeptService;
import org.dromara.system.service.ISysPostService;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
@ -101,6 +102,9 @@ public class BusProjectServiceImpl extends ServiceImpl<BusProjectMapper, BusProj
@Resource
private ISysDeptService deptService;
@Resource
private ISysPostService postService;
@Lazy
@Resource
private IHseKnowledgeDocumentService hseKnowledgeDocumentService;
@ -353,9 +357,7 @@ public class BusProjectServiceImpl extends ServiceImpl<BusProjectMapper, BusProj
}
// 异步执行数据同步
self.insertProjectSyncThing(projectId)
.thenAccept(result -> {
log.info("项目[{}-{}]异步执行数据同步成功", req.getProjectName(), projectId);
})
.thenAccept(result -> log.info("项目[{}-{}]异步执行数据同步成功", req.getProjectName(), projectId))
.exceptionally(ex -> {
log.error("项目[{}-{}]异步执行数据同步失败", req.getProjectName(), projectId, ex);
return null;
@ -422,7 +424,19 @@ public class BusProjectServiceImpl extends ServiceImpl<BusProjectMapper, BusProj
return CompletableFuture.completedFuture(false);
}
// 安全、质量知识库文件夹模版
Boolean saveHseKnowledgeDocument = hseKnowledgeDocumentService.insertFolderByTemplate(id);
if (!saveHseKnowledgeDocument) {
log.error("同步数据失败,项目[{}]新增安全知识库文件夹模版失败", id);
}
Boolean saveQltKnowledgeDocument = qltKnowledgeDocumentService.insertFolderByTemplate(id);
if (!saveQltKnowledgeDocument) {
log.error("同步数据失败,项目[{}]新增质量知识库文件夹模版失败", id);
}
// 新增岗位
Boolean postR = postService.insertPostByDeptId(project.getDeptId());
if (!postR) {
throw new ServiceException("对应岗位类型保存失败");
}
return CompletableFuture.completedFuture(true);
}

View File

@ -0,0 +1,41 @@
package org.dromara.quality.constant;
import java.util.List;
/**
* @author lcj
* @date 2025/6/26 11:02
*/
public interface QltKnowledgeDocumentConstant {
/**
* 顶级目录前缀
*/
String TOP_FOLDER_PREFIX = "doc/safety/knowledge/";
/**
* 顶级目录名称
*/
String TOP_FOLDER_NAME = "知识库";
/**
* 二级目录名称
*/
List<String> SECOND_LEVEL_FOLDER_NAME = List.of("指导手册", "交底记录", "强条");
/**
* 图片后缀列表
*/
List<String> PICTURE_SUFFIX_LIST = List.of("jpeg", "jpg", "png", "webp");
/**
* 获取顶级目录前缀
*
* @param projectId 项目id
* @return 顶级目录前缀
*/
static String getTopFolderPrefix(Long projectId) {
return String.format("%s%s/", TOP_FOLDER_PREFIX, projectId);
}
}

View File

@ -1,24 +1,28 @@
package org.dromara.quality.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import cn.hutool.core.lang.tree.Tree;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import org.dromara.common.core.domain.R;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentCreateFileReq;
import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentFileQueryReq;
import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentQueryReq;
import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentUpdateFileReq;
import org.dromara.quality.domain.vo.knowledgedocument.QltKnowledgeDocumentVo;
import org.dromara.quality.domain.bo.QltKnowledgeDocumentBo;
import org.dromara.quality.service.IQltKnowledgeDocumentService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* 质量知识库
@ -27,32 +31,39 @@ import org.dromara.quality.service.IQltKnowledgeDocumentService;
* @date 2025-06-25
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/quality/knowledgeDocument")
public class QltKnowledgeDocumentController extends BaseController {
private final IQltKnowledgeDocumentService qltKnowledgeDocumentService;
@Resource
private IQltKnowledgeDocumentService qltKnowledgeDocumentService;
/**
* 查询质量知识库列表
* 查询质量知识库文件列表
*/
@SaCheckPermission("quality:knowledgeDocument:list")
@GetMapping("/list")
public R<List<QltKnowledgeDocumentVo>> list(QltKnowledgeDocumentBo bo) {
List<QltKnowledgeDocumentVo> list = qltKnowledgeDocumentService.queryList(bo);
@SaCheckPermission("safety:knowledgeDocument:list")
@GetMapping("/file/list")
public TableDataInfo<QltKnowledgeDocumentVo> queryFilePageList(QltKnowledgeDocumentFileQueryReq req, PageQuery pageQuery) {
return qltKnowledgeDocumentService.queryFileListByFolderId(req, pageQuery);
}
/**
* 查询质量知识库文件树列表
*/
@SaCheckPermission("safety:knowledgeDocument:list")
@GetMapping("/folder/tree/list")
public R<List<Tree<Long>>> queryFolderTreeList(QltKnowledgeDocumentQueryReq req) {
List<Tree<Long>> list = qltKnowledgeDocumentService.queryFolderTreeList(req);
return R.ok(list);
}
/**
* 导出质量知识库列表
* 查询质量知识库回收站文件列表
*/
@SaCheckPermission("quality:knowledgeDocument:export")
@Log(title = "质量知识库", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(QltKnowledgeDocumentBo bo, HttpServletResponse response) {
List<QltKnowledgeDocumentVo> list = qltKnowledgeDocumentService.queryList(bo);
ExcelUtil.exportExcel(list, "质量知识库", QltKnowledgeDocumentVo.class, response);
@SaCheckPermission("safety:knowledgeDocument:list")
@GetMapping("/recycleBin/list")
public TableDataInfo<QltKnowledgeDocumentVo> queryRecycleBinPageList(QltKnowledgeDocumentQueryReq req, PageQuery pageQuery) {
return qltKnowledgeDocumentService.queryRecycleBinPageList(req, pageQuery);
}
/**
@ -60,45 +71,56 @@ public class QltKnowledgeDocumentController extends BaseController {
*
* @param id 主键
*/
@SaCheckPermission("quality:knowledgeDocument:query")
@SaCheckPermission("safety:knowledgeDocument:query")
@GetMapping("/{id}")
public R<QltKnowledgeDocumentVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
@PathVariable Long id) {
return R.ok(qltKnowledgeDocumentService.queryById(id));
}
/**
* 新增质量知识库
* 新增质量知识库文件
*/
@SaCheckPermission("quality:knowledgeDocument:add")
@SaCheckPermission("safety:knowledgeDocument:add")
@Log(title = "质量知识库", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody QltKnowledgeDocumentBo bo) {
return toAjax(qltKnowledgeDocumentService.insertByBo(bo));
@PostMapping("/file")
public R<Void> add(@RequestPart("file") MultipartFile file, QltKnowledgeDocumentCreateFileReq req) {
return toAjax(qltKnowledgeDocumentService.insertFile(file, req));
}
/**
* 修改质量知识库
*/
@SaCheckPermission("quality:knowledgeDocument:edit")
@SaCheckPermission("safety:knowledgeDocument:edit")
@Log(title = "质量知识库", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody QltKnowledgeDocumentBo bo) {
return toAjax(qltKnowledgeDocumentService.updateByBo(bo));
@PutMapping("/file")
public R<Void> edit(@RequestBody QltKnowledgeDocumentUpdateFileReq req) {
return toAjax(qltKnowledgeDocumentService.updateFile(req));
}
/**
* 删除质量知识库
* 删除质量知识库文件
*
* @param ids 主键
* @param id 主键
*/
@SaCheckPermission("quality:knowledgeDocument:remove")
@SaCheckPermission("safety:knowledgeDocument:remove")
@Log(title = "质量知识库", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(qltKnowledgeDocumentService.deleteWithValidByIds(List.of(ids), true));
@DeleteMapping("/file/{id}")
public R<Void> remove(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return toAjax(qltKnowledgeDocumentService.deleteFileById(id));
}
/**
* 根据主键id批量恢复
*/
@SaCheckPermission("safety:knowledgeDocument:recovery")
@Log(title = "质量知识库", businessType = BusinessType.UPDATE)
@PostMapping("/recovery/{ids}")
public R<Void> recoveryBatchById(@NotNull(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(qltKnowledgeDocumentService.recoveryBatchById(List.of(ids)));
}
}

View File

@ -0,0 +1,33 @@
package org.dromara.quality.domain.dto.knowledgedocument;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/6/26 18:43
*/
@Data
public class QltKnowledgeDocumentCreateFileReq implements Serializable {
@Serial
private static final long serialVersionUID = 2209500240715662744L;
/**
* 项目id
*/
private Long projectId;
/**
* 父级0代表顶级
*/
private Long pid;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,27 @@
package org.dromara.quality.domain.dto.knowledgedocument;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/6/26 18:44
*/
@Data
public class QltKnowledgeDocumentFileQueryReq implements Serializable {
@Serial
private static final long serialVersionUID = 3877587395295861071L;
/**
* 文件夹id
*/
private Long folderId;
/**
* 文件名
*/
private String fileName;
}

View File

@ -0,0 +1,27 @@
package org.dromara.quality.domain.dto.knowledgedocument;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/6/26 11:31
*/
@Data
public class QltKnowledgeDocumentQueryReq implements Serializable {
@Serial
private static final long serialVersionUID = -2232852522603216190L;
/**
* 项目id
*/
private Long projectId;
/**
* 文件名
*/
private String fileName;
}

View File

@ -0,0 +1,37 @@
package org.dromara.quality.domain.dto.knowledgedocument;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/6/26 18:44
*/
@Data
public class QltKnowledgeDocumentUpdateFileReq implements Serializable {
@Serial
private static final long serialVersionUID = -2002756179428078203L;
/**
* 主键id
*/
private Long id;
/**
* 父级0代表顶级
*/
private Long pid;
/**
* 文件名称
*/
private String fileName;
/**
* 备注
*/
private String remark;
}

View File

@ -1,7 +1,17 @@
package org.dromara.quality.service;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.quality.domain.QltKnowledgeDocument;
import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentCreateFileReq;
import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentFileQueryReq;
import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentQueryReq;
import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentUpdateFileReq;
import org.dromara.quality.domain.vo.knowledgedocument.QltKnowledgeDocumentVo;
import org.dromara.quality.domain.bo.QltKnowledgeDocumentBo;
import org.springframework.web.multipart.MultipartFile;
import java.util.Collection;
import java.util.List;
@ -12,7 +22,7 @@ import java.util.List;
* @author lcj
* @date 2025-06-25
*/
public interface IQltKnowledgeDocumentService {
public interface IQltKnowledgeDocumentService extends IService<QltKnowledgeDocument> {
/**
* 查询质量知识库
@ -22,37 +32,94 @@ public interface IQltKnowledgeDocumentService {
*/
QltKnowledgeDocumentVo queryById(Long id);
/**
* 查询符合条件的质量知识库列表
* 查询质量知识库文件夹树列表
*
* @param bo 查询条件
* @return 质量知识库列表
* @param req 查询参数
* @return 质量知识库文件夹树列表
*/
List<QltKnowledgeDocumentVo> queryList(QltKnowledgeDocumentBo bo);
List<Tree<Long>> queryFolderTreeList(QltKnowledgeDocumentQueryReq req);
/**
* 新增质量知识库
* 查询文件夹下的质量知识库文件列表
*
* @param bo 质量知识库
* @param req 查询参数
* @param pageQuery 分页参数
* @return 质量知识库文件列表
*/
TableDataInfo<QltKnowledgeDocumentVo> queryFileListByFolderId(QltKnowledgeDocumentFileQueryReq req, PageQuery pageQuery);
/**
* 查询回收站中的文件
*
* @param req 查询参数
* @param pageQuery 分页参数
* @return 回收站中的文件
*/
TableDataInfo<QltKnowledgeDocumentVo> queryRecycleBinPageList(QltKnowledgeDocumentQueryReq req, PageQuery pageQuery);
/**
* 新增质量知识库文件
*
* @param file 文件
* @param req 质量知识库
* @return 是否新增成功
*/
Boolean insertByBo(QltKnowledgeDocumentBo bo);
Boolean insertFile(MultipartFile file, QltKnowledgeDocumentCreateFileReq req);
/**
* 修改质量知识库
* 新增质量知识库文件夹
*
* @param bo 质量知识库
* @param projectId 项目id
* @return 是否新增成功
*/
Boolean insertFolderByTemplate(Long projectId);
/**
* 修改质量知识库文件
*
* @param req 质量知识库
* @return 是否修改成功
*/
Boolean updateByBo(QltKnowledgeDocumentBo bo);
Boolean updateFile(QltKnowledgeDocumentUpdateFileReq req);
/**
* 校验并批量删除质量知识库信息
* 删除质量知识库文件信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @param id 待删除文件的主键
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
Boolean deleteFileById(Long id);
/**
* 批量恢复质量会议纪要信息
*
* @param ids 待删除的主键集合
* @return 是否删除成功
*/
Boolean recoveryBatchById(Collection<Long> ids);
/**
* 构建前端所需要下拉树结构
*
* @param documentList 文档列表
* @return 下拉树结构列表
*/
List<Tree<Long>> buildTreeSelect(List<QltKnowledgeDocument> documentList);
/**
* 构建文档封装对象
*
* @param document 文档
* @return 文档封装对象
*/
QltKnowledgeDocumentVo getVo(QltKnowledgeDocument document);
/**
* 获取文档对象视图
*
* @param documentPage 文档对象
* @return 文档对象视图
*/
Page<QltKnowledgeDocumentVo> getVoPage(Page<QltKnowledgeDocument> documentPage);
}

View File

@ -1,20 +1,40 @@
package org.dromara.quality.service.impl;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.dromara.quality.domain.bo.QltKnowledgeDocumentBo;
import org.dromara.quality.domain.vo.knowledgedocument.QltKnowledgeDocumentVo;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.*;
import org.dromara.common.enums.DocumentStatusEnum;
import org.dromara.common.enums.DocumentTypeEnum;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.project.service.IBusProjectService;
import org.dromara.quality.constant.QltKnowledgeDocumentConstant;
import org.dromara.quality.domain.QltKnowledgeDocument;
import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentCreateFileReq;
import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentFileQueryReq;
import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentQueryReq;
import org.dromara.quality.domain.dto.knowledgedocument.QltKnowledgeDocumentUpdateFileReq;
import org.dromara.quality.domain.vo.knowledgedocument.QltKnowledgeDocumentVo;
import org.dromara.quality.mapper.QltKnowledgeDocumentMapper;
import org.dromara.quality.service.IQltKnowledgeDocumentService;
import org.dromara.system.domain.vo.SysOssUploadVo;
import org.dromara.system.service.ISysOssService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.*;
import java.util.stream.Collectors;
/**
* 质量知识库Service业务层处理
@ -22,11 +42,15 @@ import java.util.Collection;
* @author lcj
* @date 2025-06-25
*/
@RequiredArgsConstructor
@Service
public class QltKnowledgeDocumentServiceImpl implements IQltKnowledgeDocumentService {
public class QltKnowledgeDocumentServiceImpl extends ServiceImpl<QltKnowledgeDocumentMapper, QltKnowledgeDocument>
implements IQltKnowledgeDocumentService {
private final QltKnowledgeDocumentMapper baseMapper;
@Resource
private IBusProjectService projectService;
@Resource
private ISysOssService ossService;
/**
* 查询质量知识库
@ -35,88 +59,365 @@ public class QltKnowledgeDocumentServiceImpl implements IQltKnowledgeDocumentSer
* @return 质量知识库
*/
@Override
public QltKnowledgeDocumentVo queryById(Long id){
return baseMapper.selectVoById(id);
public QltKnowledgeDocumentVo queryById(Long id) {
QltKnowledgeDocument entity = this.getById(id);
if (entity == null) {
throw new ServiceException("质量知识库文件或文件夹不存在", HttpStatus.NOT_FOUND);
}
return this.getVo(entity);
}
/**
* 查询符合条件的质量知识库列表
* 查询质量知识库文件夹树列表
*
* @param bo 查询条件
* @return 质量知识库列表
* @param req 查询参数
* @return 质量知识库文件夹树列表
*/
@Override
public List<QltKnowledgeDocumentVo> queryList(QltKnowledgeDocumentBo bo) {
LambdaQueryWrapper<QltKnowledgeDocument> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<QltKnowledgeDocument> buildQueryWrapper(QltKnowledgeDocumentBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<QltKnowledgeDocument> lqw = Wrappers.lambdaQuery();
lqw.orderByAsc(QltKnowledgeDocument::getId);
lqw.eq(bo.getProjectId() != null, QltKnowledgeDocument::getProjectId, bo.getProjectId());
lqw.eq(bo.getPid() != null, QltKnowledgeDocument::getPid, bo.getPid());
lqw.like(StringUtils.isNotBlank(bo.getFileName()), QltKnowledgeDocument::getFileName, bo.getFileName());
lqw.eq(StringUtils.isNotBlank(bo.getFilePath()), QltKnowledgeDocument::getFilePath, bo.getFilePath());
lqw.eq(StringUtils.isNotBlank(bo.getFileUrl()), QltKnowledgeDocument::getFileUrl, bo.getFileUrl());
lqw.eq(StringUtils.isNotBlank(bo.getFileType()), QltKnowledgeDocument::getFileType, bo.getFileType());
lqw.eq(StringUtils.isNotBlank(bo.getFileSuffix()), QltKnowledgeDocument::getFileSuffix, bo.getFileSuffix());
lqw.eq(StringUtils.isNotBlank(bo.getFileStatus()), QltKnowledgeDocument::getFileStatus, bo.getFileStatus());
lqw.like(StringUtils.isNotBlank(bo.getOriginalName()), QltKnowledgeDocument::getOriginalName, bo.getOriginalName());
return lqw;
public List<Tree<Long>> queryFolderTreeList(QltKnowledgeDocumentQueryReq req) {
Long projectId = req.getProjectId();
List<QltKnowledgeDocument> folderList = this.lambdaQuery()
.eq(QltKnowledgeDocument::getProjectId, projectId)
.eq(QltKnowledgeDocument::getFileType, DocumentTypeEnum.FOLDER.getValue())
.eq(QltKnowledgeDocument::getFileStatus, DocumentStatusEnum.NORMAL.getValue())
.list();
return this.buildTreeSelect(folderList);
}
/**
* 新增质量知识库
* 查询文件夹下的质量知识库文件列表
*
* @param bo 质量知识库
* @param req 查询参数
* @param pageQuery 分页参数
* @return 质量知识库文件列表
*/
@Override
public TableDataInfo<QltKnowledgeDocumentVo> queryFileListByFolderId(QltKnowledgeDocumentFileQueryReq req, PageQuery pageQuery) {
QltKnowledgeDocument folder = this.getById(req.getFolderId());
if (folder == null) {
throw new ServiceException("文件夹不存在", HttpStatus.NOT_FOUND);
}
if (!DocumentTypeEnum.FOLDER.getValue().equals(folder.getFileType())) {
throw new ServiceException("所选目录不是文件夹", HttpStatus.BAD_REQUEST);
}
LambdaQueryWrapper<QltKnowledgeDocument> lqw = new LambdaQueryWrapper<>();
lqw.eq(QltKnowledgeDocument::getPid, folder.getId());
lqw.eq(QltKnowledgeDocument::getProjectId, folder.getProjectId());
lqw.ne(QltKnowledgeDocument::getFileType, DocumentTypeEnum.FOLDER.getValue());
lqw.eq(QltKnowledgeDocument::getFileStatus, DocumentStatusEnum.NORMAL.getValue());
lqw.like(StringUtils.isNotBlank(req.getFileName()), QltKnowledgeDocument::getFileName, req.getFileName());
Page<QltKnowledgeDocument> documentPage = this.page(pageQuery.build(), lqw);
return TableDataInfo.build(this.getVoPage(documentPage));
}
/**
* 查询回收站中的文件
*
* @param req 查询参数
* @param pageQuery 分页参数
* @return 回收站中的文件
*/
@Override
public TableDataInfo<QltKnowledgeDocumentVo> queryRecycleBinPageList(QltKnowledgeDocumentQueryReq req, PageQuery pageQuery) {
Long projectId = req.getProjectId();
if (projectService.getById(projectId) == null) {
throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND);
}
LambdaQueryWrapper<QltKnowledgeDocument> lqw = new LambdaQueryWrapper<>();
lqw.eq(QltKnowledgeDocument::getProjectId, projectId);
lqw.eq(QltKnowledgeDocument::getFileStatus, DocumentStatusEnum.DELETE.getValue());
lqw.like(StringUtils.isNotBlank(req.getFileName()), QltKnowledgeDocument::getFileName, req.getFileName());
lqw.orderByDesc(QltKnowledgeDocument::getDeletedAt);
Page<QltKnowledgeDocument> result = this.page(pageQuery.build(), lqw);
return TableDataInfo.build(this.getVoPage(result));
}
/**
* 新增质量知识库文件
*
* @param file 文件
* @param req 质量知识库
* @return 是否新增成功
*/
@Override
public Boolean insertByBo(QltKnowledgeDocumentBo bo) {
QltKnowledgeDocument add = MapstructUtils.convert(bo, QltKnowledgeDocument.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
public Boolean insertFile(MultipartFile file, QltKnowledgeDocumentCreateFileReq req) {
// 数据校验
if (ObjectUtils.isEmpty(file)) {
throw new ServiceException("文件不能为空", HttpStatus.BAD_REQUEST);
}
return flag;
Long projectId = req.getProjectId();
if (projectService.getById(projectId) == null) {
throw new ServiceException("项目不存在", HttpStatus.BAD_REQUEST);
}
// 拼接文件名
String originalFilename = file.getOriginalFilename();
String suffix = FileUtil.getSuffix(originalFilename);
if (StringUtils.isBlank(suffix)) {
throw new ServiceException("文件格式错误", HttpStatus.BAD_REQUEST);
}
String date = DateUtils.getDate();
String uuid = IdUtil.fastSimpleUUID();
String fileName = String.format("%s_%s.%s", date, uuid, suffix);
// 拼接文件路径
Long pid = req.getPid();
if (pid == null || pid == 0) {
throw new ServiceException("不能在根目录上传文件", HttpStatus.BAD_REQUEST);
}
QltKnowledgeDocument pQltKnowledgeDocument = this.getById(pid);
// 校验父级目录
validParentFolder(pQltKnowledgeDocument, projectId);
String filePath = pQltKnowledgeDocument.getFilePath() + "/" + fileName;
// 上传文件
SysOssUploadVo ossUploadVo = ossService.uploadWithNoSave(file, filePath);
// 保存文件信息
QltKnowledgeDocument knowledgeDocument = new QltKnowledgeDocument();
knowledgeDocument.setFilePath(filePath);
knowledgeDocument.setFileUrl(ossUploadVo.getUrl());
knowledgeDocument.setFileSuffix(suffix);
if (QltKnowledgeDocumentConstant.PICTURE_SUFFIX_LIST.contains(suffix)) {
knowledgeDocument.setFileType(DocumentTypeEnum.PICTURE.getValue());
} else {
knowledgeDocument.setFileType(DocumentTypeEnum.FILE.getValue());
}
knowledgeDocument.setFileName(originalFilename);
knowledgeDocument.setOriginalName(originalFilename);
knowledgeDocument.setProjectId(projectId);
knowledgeDocument.setPid(pid);
boolean save = this.save(knowledgeDocument);
if (!save) {
throw new ServiceException("新增文件失败,数据库异常", HttpStatus.ERROR);
}
return true;
}
/**
* 修改质量知识库
* 新增质量知识库文件夹
*
* @param bo 质量知识库
* @param projectId 项目id
* @return 是否新增成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertFolderByTemplate(Long projectId) {
// 创建顶级目录
String prefix = QltKnowledgeDocumentConstant.getTopFolderPrefix(projectId);
String topPath = prefix + QltKnowledgeDocumentConstant.TOP_FOLDER_NAME;
QltKnowledgeDocument topFolder = new QltKnowledgeDocument();
topFolder.setProjectId(projectId);
topFolder.setPid(0L);
topFolder.setFileName(QltKnowledgeDocumentConstant.TOP_FOLDER_NAME);
topFolder.setFilePath(topPath);
topFolder.setFileType(DocumentTypeEnum.FOLDER.getValue());
boolean save = this.save(topFolder);
if (!save) {
throw new ServiceException("新增顶级目录失败,数据库异常", HttpStatus.ERROR);
}
// 创建二级目录
Long pid = topFolder.getId();
List<QltKnowledgeDocument> documents = QltKnowledgeDocumentConstant.SECOND_LEVEL_FOLDER_NAME.stream().map(name -> {
QltKnowledgeDocument folder = new QltKnowledgeDocument();
String path = topPath + "/" + name;
folder.setProjectId(projectId);
folder.setPid(pid);
folder.setFileName(name);
folder.setFilePath(path);
folder.setFileType(DocumentTypeEnum.FOLDER.getValue());
return folder;
}).toList();
return this.saveBatch(documents);
}
/**
* 修改质量知识库文件
*
* @param req 质量知识库
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(QltKnowledgeDocumentBo bo) {
QltKnowledgeDocument update = MapstructUtils.convert(bo, QltKnowledgeDocument.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
public Boolean updateFile(QltKnowledgeDocumentUpdateFileReq req) {
Long id = req.getId();
QltKnowledgeDocument oldDocument = this.getById(id);
if (oldDocument == null) {
throw new ServiceException("修改质量知识库文件失败,数据不存在", HttpStatus.NOT_FOUND);
}
QltKnowledgeDocument document = new QltKnowledgeDocument();
BeanUtils.copyProperties(req, document);
boolean result = this.updateById(document);
if (!result) {
throw new ServiceException("修改质量知识库文件失败", HttpStatus.ERROR);
}
return true;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(QltKnowledgeDocument entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 校验并批量删除质量知识库信息
* 删除质量知识库文件信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @param id 待删除文件的主键
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
public Boolean deleteFileById(Long id) {
QltKnowledgeDocument document = this.getById(id);
if (document == null) {
throw new ServiceException("文件不存在", HttpStatus.ERROR);
}
return baseMapper.deleteByIds(ids) > 0;
if (!document.getFileStatus().equals(DocumentStatusEnum.NORMAL.getValue())) {
throw new ServiceException("文件已删除", HttpStatus.ERROR);
}
if (document.getFileType().equals(DocumentTypeEnum.FOLDER.getValue())) {
throw new ServiceException("文件夹不能删除", HttpStatus.ERROR);
}
QltKnowledgeDocument deleteDocument = new QltKnowledgeDocument();
deleteDocument.setId(document.getId());
deleteDocument.setDeletedAt(new Date());
deleteDocument.setFileStatus(DocumentStatusEnum.DELETE.getValue());
return this.updateById(deleteDocument);
}
/**
* 批量恢复质量会议纪要信息
*
* @param ids 待删除的主键集合
* @return 是否删除成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean recoveryBatchById(Collection<Long> ids) {
List<Long> allParentIdsRecursively = getAllParentIdsRecursively(ids);
// 需要更新状态的文件集合
allParentIdsRecursively.addAll(ids);
List<QltKnowledgeDocument> updateList = allParentIdsRecursively.stream().map(id -> {
QltKnowledgeDocument documentSafetyMeeting = new QltKnowledgeDocument();
documentSafetyMeeting.setId(id);
documentSafetyMeeting.setFileStatus(DocumentStatusEnum.NORMAL.getValue());
return documentSafetyMeeting;
}).toList();
boolean result = this.updateBatchById(updateList);
if (!result) {
throw new ServiceException("恢复文件失败,数据库异常", HttpStatus.ERROR);
}
return true;
}
/**
* 构建前端所需要下拉树结构
*
* @param documentList 文档列表
* @return 下拉树结构列表
*/
@Override
public List<Tree<Long>> buildTreeSelect(List<QltKnowledgeDocument> documentList) {
if (CollUtil.isEmpty(documentList)) {
return CollUtil.newArrayList();
}
// 获取当前列表中每一个节点的parentId然后在列表中查找是否有id与其parentId对应若无对应则表明此时节点列表中该节点在当前列表中属于顶级节点
List<Tree<Long>> treeList = CollUtil.newArrayList();
for (QltKnowledgeDocument d : documentList) {
Long parentId = d.getPid();
QltKnowledgeDocument document = StreamUtils.findFirst(documentList, it -> Objects.equals(it.getId(), parentId));
if (ObjectUtil.isNull(document)) {
List<Tree<Long>> trees = TreeBuildUtils.build(documentList, parentId, (knowledgeDocument, tree) ->
tree.setId(knowledgeDocument.getId())
.setParentId(knowledgeDocument.getPid())
.setName(knowledgeDocument.getFileName()));
Tree<Long> tree = StreamUtils.findFirst(trees, it -> Objects.equals(it.getId(), d.getId()));
treeList.add(tree);
}
}
return treeList;
}
/**
* 构建文档封装对象
*
* @param document 文档
* @return 文档封装对象
*/
@Override
public QltKnowledgeDocumentVo getVo(QltKnowledgeDocument document) {
QltKnowledgeDocumentVo vo = new QltKnowledgeDocumentVo();
if (document == null) {
return vo;
}
BeanUtils.copyProperties(document, vo);
return vo;
}
/**
* 获取文档对象视图
*
* @param documentPage 文档对象
* @return 文档对象视图
*/
@Override
public Page<QltKnowledgeDocumentVo> getVoPage(Page<QltKnowledgeDocument> documentPage) {
List<QltKnowledgeDocument> documentList = documentPage.getRecords();
Page<QltKnowledgeDocumentVo> documentVoPage = new Page<>(
documentPage.getCurrent(),
documentPage.getSize(),
documentPage.getTotal());
if (CollUtil.isEmpty(documentList)) {
return documentVoPage;
}
List<QltKnowledgeDocumentVo> documentVoList = documentList.stream().map(entity -> {
QltKnowledgeDocumentVo documentVo = new QltKnowledgeDocumentVo();
BeanUtils.copyProperties(entity, documentVo);
return documentVo;
}).toList();
documentVoPage.setRecords(documentVoList);
return documentVoPage;
}
/**
* 校验父级目录是否存在
*
* @param knowledgeDocument 父级目录
* @param projectId 当前项目id
*/
private void validParentFolder(QltKnowledgeDocument knowledgeDocument, Long projectId) {
// 判断父级目录是否存在
if (knowledgeDocument == null) {
throw new ServiceException("父级目录不存在", HttpStatus.NOT_FOUND);
}
// 判断父级目录是否是文件夹
if (!DocumentTypeEnum.FOLDER.getValue().equals(knowledgeDocument.getFileType())) {
throw new ServiceException("父级目录不是文件夹", HttpStatus.BAD_REQUEST);
}
// 判断是否为同一个项目
if (!knowledgeDocument.getProjectId().equals(projectId)) {
throw new ServiceException("父级目录不属于当前项目", HttpStatus.BAD_REQUEST);
}
}
/**
* 递归查询所有父级 id
*
* @param ids id 列表
* @return 父级 id 列表
*/
private List<Long> getAllParentIdsRecursively(Collection<Long> ids) {
// 使用 list() 方法批量查询当前 id 列表对应的实体数据
List<QltKnowledgeDocument> fileList = this.lambdaQuery()
.in(QltKnowledgeDocument::getId, ids)
.eq(QltKnowledgeDocument::getFileStatus, DocumentStatusEnum.DELETE.getValue())
.list();
// 通过 stream 流过滤出非 0 的父 id并去重
List<Long> parentIdList = fileList.stream()
.map(QltKnowledgeDocument::getPid)
.filter(pid -> pid != 0)
.distinct()
.collect(Collectors.toList());
// 如果父 id 列表为空,说明递归终止,返回空列表
if (parentIdList.isEmpty()) {
return new ArrayList<>();
}
// 递归查询父 id 列表对应的上级父 id
List<Long> higherParentIds = getAllParentIdsRecursively(parentIdList);
// 将当前层的父 id 和上级递归得到的父 id 合并
List<Long> allParentIds = new ArrayList<>();
allParentIds.addAll(parentIdList);
allParentIds.addAll(higherParentIds);
// 返回合并后去重的结果
return allParentIds.stream().distinct().collect(Collectors.toList());
}
}

View File

@ -35,7 +35,7 @@ import org.dromara.system.domain.vo.SysOssVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.service.ISysOssService;
import org.dromara.system.service.ISysUserService;
import org.dromara.utils.DocumentUtil;
import org.dromara.common.utils.DocumentUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;

View File

@ -45,7 +45,7 @@ import org.dromara.system.service.ISysDictDataService;
import org.dromara.system.service.ISysDictTypeService;
import org.dromara.system.service.ISysOssService;
import org.dromara.system.service.ISysUserService;
import org.dromara.utils.DocumentUtil;
import org.dromara.common.utils.DocumentUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;

View File

@ -0,0 +1,42 @@
package org.dromara.safety.constant;
import java.util.List;
/**
* @author lcj
* @date 2025/6/26 10:29
*/
public interface HseKnowledgeDocumentConstant {
/**
* 顶级目录前缀
*/
String TOP_FOLDER_PREFIX = "doc/safety/knowledge/";
/**
* 顶级目录名称
*/
String TOP_FOLDER_NAME = "知识库";
/**
* 二级目录名称
*/
List<String> SECOND_LEVEL_FOLDER_NAME = List.of("指导手册", "交底记录", "强条");
/**
* 图片后缀列表
*/
List<String> PICTURE_SUFFIX_LIST = List.of("jpeg", "jpg", "png", "webp");
/**
* 获取顶级目录前缀
*
* @param projectId 项目id
* @return 顶级目录前缀
*/
static String getTopFolderPrefix(Long projectId) {
return String.format("%s%s/", TOP_FOLDER_PREFIX, projectId);
}
}

View File

@ -1,24 +1,27 @@
package org.dromara.safety.controller;
import java.util.List;
import lombok.RequiredArgsConstructor;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import cn.hutool.core.lang.tree.Tree;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotNull;
import org.dromara.common.core.domain.R;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.web.core.BaseController;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.web.core.BaseController;
import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentCreateFileReq;
import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentFileQueryReq;
import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentQueryReq;
import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentUpdateFileReq;
import org.dromara.safety.domain.vo.knowledgedocument.HseKnowledgeDocumentVo;
import org.dromara.safety.domain.bo.HseKnowledgeDocumentBo;
import org.dromara.safety.service.IHseKnowledgeDocumentService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* 安全知识库
@ -27,32 +30,39 @@ import org.dromara.safety.service.IHseKnowledgeDocumentService;
* @date 2025-06-25
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/safety/knowledgeDocument")
public class HseKnowledgeDocumentController extends BaseController {
private final IHseKnowledgeDocumentService hseKnowledgeDocumentService;
@Resource
private IHseKnowledgeDocumentService hseKnowledgeDocumentService;
/**
* 查询安全知识库列表
* 查询安全知识库文件列表
*/
@SaCheckPermission("safety:knowledgeDocument:list")
@GetMapping("/list")
public R<List<HseKnowledgeDocumentVo>> list(HseKnowledgeDocumentBo bo) {
List<HseKnowledgeDocumentVo> list = hseKnowledgeDocumentService.queryList(bo);
@GetMapping("/file/list")
public TableDataInfo<HseKnowledgeDocumentVo> queryFilePageList(HseKnowledgeDocumentFileQueryReq req, PageQuery pageQuery) {
return hseKnowledgeDocumentService.queryFileListByFolderId(req, pageQuery);
}
/**
* 查询安全知识库文件树列表
*/
@SaCheckPermission("safety:knowledgeDocument:list")
@GetMapping("/folder/tree/list")
public R<List<Tree<Long>>> queryFolderTreeList(HseKnowledgeDocumentQueryReq req) {
List<Tree<Long>> list = hseKnowledgeDocumentService.queryFolderTreeList(req);
return R.ok(list);
}
/**
* 导出安全知识库列表
* 查询安全知识库回收站文件列表
*/
@SaCheckPermission("safety:knowledgeDocument:export")
@Log(title = "安全知识库", businessType = BusinessType.EXPORT)
@PostMapping("/export")
public void export(HseKnowledgeDocumentBo bo, HttpServletResponse response) {
List<HseKnowledgeDocumentVo> list = hseKnowledgeDocumentService.queryList(bo);
ExcelUtil.exportExcel(list, "安全知识库", HseKnowledgeDocumentVo.class, response);
@SaCheckPermission("safety:knowledgeDocument:list")
@GetMapping("/recycleBin/list")
public TableDataInfo<HseKnowledgeDocumentVo> queryRecycleBinPageList(HseKnowledgeDocumentQueryReq req, PageQuery pageQuery) {
return hseKnowledgeDocumentService.queryRecycleBinPageList(req, pageQuery);
}
/**
@ -63,19 +73,19 @@ public class HseKnowledgeDocumentController extends BaseController {
@SaCheckPermission("safety:knowledgeDocument:query")
@GetMapping("/{id}")
public R<HseKnowledgeDocumentVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
@PathVariable Long id) {
return R.ok(hseKnowledgeDocumentService.queryById(id));
}
/**
* 新增安全知识库
* 新增安全知识库文件
*/
@SaCheckPermission("safety:knowledgeDocument:add")
@Log(title = "安全知识库", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<Void> add(@Validated(AddGroup.class) @RequestBody HseKnowledgeDocumentBo bo) {
return toAjax(hseKnowledgeDocumentService.insertByBo(bo));
@PostMapping("/file")
public R<Void> add(@RequestPart("file") MultipartFile file, HseKnowledgeDocumentCreateFileReq req) {
return toAjax(hseKnowledgeDocumentService.insertFile(file, req));
}
/**
@ -84,21 +94,32 @@ public class HseKnowledgeDocumentController extends BaseController {
@SaCheckPermission("safety:knowledgeDocument:edit")
@Log(title = "安全知识库", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<Void> edit(@Validated(EditGroup.class) @RequestBody HseKnowledgeDocumentBo bo) {
return toAjax(hseKnowledgeDocumentService.updateByBo(bo));
@PutMapping("/file")
public R<Void> edit(@RequestBody HseKnowledgeDocumentUpdateFileReq req) {
return toAjax(hseKnowledgeDocumentService.updateFile(req));
}
/**
* 删除安全知识库
* 删除安全知识库文件
*
* @param ids 主键
* @param id 主键
*/
@SaCheckPermission("safety:knowledgeDocument:remove")
@Log(title = "安全知识库", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(hseKnowledgeDocumentService.deleteWithValidByIds(List.of(ids), true));
@DeleteMapping("/file/{id}")
public R<Void> remove(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return toAjax(hseKnowledgeDocumentService.deleteFileById(id));
}
/**
* 根据主键id批量恢复
*/
@SaCheckPermission("safety:knowledgeDocument:recovery")
@Log(title = "安全知识库", businessType = BusinessType.UPDATE)
@PostMapping("/recovery/{ids}")
public R<Void> recoveryBatchById(@NotNull(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(hseKnowledgeDocumentService.recoveryBatchById(List.of(ids)));
}
}

View File

@ -1,87 +0,0 @@
package org.dromara.safety.domain.bo;
import org.dromara.safety.domain.HseKnowledgeDocument;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
/**
* 安全知识库业务对象 hse_knowledge_document
*
* @author lcj
* @date 2025-06-25
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = HseKnowledgeDocument.class, reverseConvertGenerate = false)
public class HseKnowledgeDocumentBo extends BaseEntity {
/**
* 主键id
*/
@NotNull(message = "主键id不能为空", groups = { EditGroup.class })
private Long id;
/**
* 项目id
*/
@NotNull(message = "项目id不能为空", groups = { AddGroup.class, EditGroup.class })
private Long projectId;
/**
* 父级0代表顶级
*/
@NotNull(message = "父级0代表顶级不能为空", groups = { AddGroup.class, EditGroup.class })
private Long pid;
/**
* 文件名称
*/
@NotBlank(message = "文件名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String fileName;
/**
* 文件路径
*/
private String filePath;
/**
* 文件访问路径
*/
private String fileUrl;
/**
* 文件类型1文件夹 2文件 3图片
*/
@NotBlank(message = "文件类型1文件夹 2文件 3图片不能为空", groups = { AddGroup.class, EditGroup.class })
private String fileType;
/**
* 文件后缀
*/
private String fileSuffix;
/**
* 状态0正常 1删除
*/
@NotBlank(message = "状态0正常 1删除不能为空", groups = { AddGroup.class, EditGroup.class })
private String fileStatus;
/**
* 原文件名
*/
private String originalName;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,33 @@
package org.dromara.safety.domain.dto.knowledgedocument;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/6/26 11:39
*/
@Data
public class HseKnowledgeDocumentCreateFileReq implements Serializable {
@Serial
private static final long serialVersionUID = 4262046408641303686L;
/**
* 项目id
*/
private Long projectId;
/**
* 父级0代表顶级
*/
private Long pid;
/**
* 备注
*/
private String remark;
}

View File

@ -0,0 +1,21 @@
package org.dromara.safety.domain.dto.knowledgedocument;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/6/26 14:43
*/
@Data
public class HseKnowledgeDocumentFileQueryReq implements Serializable {
@Serial
private static final long serialVersionUID = -2641241219631684277L;
private Long folderId;
private String fileName;
}

View File

@ -0,0 +1,27 @@
package org.dromara.safety.domain.dto.knowledgedocument;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/6/26 11:16
*/
@Data
public class HseKnowledgeDocumentQueryReq implements Serializable {
@Serial
private static final long serialVersionUID = 1678465205213645248L;
/**
* 项目id
*/
private Long projectId;
/**
* 文件名
*/
private String fileName;
}

View File

@ -0,0 +1,38 @@
package org.dromara.safety.domain.dto.knowledgedocument;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* @author lcj
* @date 2025/6/26 11:43
*/
@Data
public class HseKnowledgeDocumentUpdateFileReq implements Serializable {
@Serial
private static final long serialVersionUID = -7715282474964511324L;
/**
* 主键id
*/
private Long id;
/**
* 父级0代表顶级
*/
private Long pid;
/**
* 文件名称
*/
private String fileName;
/**
* 备注
*/
private String remark;
}

View File

@ -52,7 +52,7 @@ public class HseDocumentSafetyMeetingRecycleBinVo implements Serializable {
private String fileSuffix;
/**
* 文件类型1文件-2文件夹-3图片
* 文件类型1文件2文件 3图片
*/
private String fileType;

View File

@ -57,7 +57,7 @@ public class HseDocumentSafetyMeetingVo implements Serializable {
private String fileSuffix;
/**
* 文件类型1文件-2文件夹-3图片
* 文件类型1文件2文件 3图片
*/
private String fileType;

View File

@ -1,15 +1,12 @@
package org.dromara.safety.domain.vo.knowledgedocument;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.common.excel.annotation.ExcelDictFormat;
import org.dromara.common.excel.convert.ExcelDictConvert;
import org.dromara.safety.domain.HseKnowledgeDocument;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
@ -19,7 +16,6 @@ import java.io.Serializable;
* @date 2025-06-25
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = HseKnowledgeDocument.class)
public class HseKnowledgeDocumentVo implements Serializable {
@ -29,70 +25,61 @@ public class HseKnowledgeDocumentVo implements Serializable {
/**
* 主键id
*/
@ExcelProperty(value = "主键id")
private Long id;
/**
* 项目id
*/
@ExcelProperty(value = "项目id")
private Long projectId;
/**
* 父级0代表顶级
*/
@ExcelProperty(value = "父级", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "0=代表顶级")
private Long pid;
/**
* 文件名称
*/
@ExcelProperty(value = "文件名称")
private String fileName;
/**
* 文件路径
*/
@ExcelProperty(value = "文件路径")
private String filePath;
/**
* 文件访问路径
*/
@ExcelProperty(value = "文件访问路径")
private String fileUrl;
/**
* 文件类型1文件夹 2文件 3图片
*/
@ExcelProperty(value = "文件类型", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "1=文件夹,2=文件,3=图片")
private String fileType;
/**
* 文件后缀
*/
@ExcelProperty(value = "文件后缀")
private String fileSuffix;
/**
* 状态0正常 1删除
*/
@ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(readConverterExp = "0=正常,1=删除")
private String fileStatus;
/**
* 原文件名
*/
@ExcelProperty(value = "原文件名")
private String originalName;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 创建时间
*/
private Date createTime;
}

View File

@ -1,7 +1,17 @@
package org.dromara.safety.service;
import cn.hutool.core.lang.tree.Tree;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.safety.domain.HseKnowledgeDocument;
import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentCreateFileReq;
import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentFileQueryReq;
import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentQueryReq;
import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentUpdateFileReq;
import org.dromara.safety.domain.vo.knowledgedocument.HseKnowledgeDocumentVo;
import org.dromara.safety.domain.bo.HseKnowledgeDocumentBo;
import org.springframework.web.multipart.MultipartFile;
import java.util.Collection;
import java.util.List;
@ -12,7 +22,7 @@ import java.util.List;
* @author lcj
* @date 2025-06-25
*/
public interface IHseKnowledgeDocumentService {
public interface IHseKnowledgeDocumentService extends IService<HseKnowledgeDocument> {
/**
* 查询安全知识库
@ -22,37 +32,94 @@ public interface IHseKnowledgeDocumentService {
*/
HseKnowledgeDocumentVo queryById(Long id);
/**
* 查询符合条件的安全知识库列表
* 查询安全知识库文件夹树列表
*
* @param bo 查询条件
* @return 安全知识库列表
* @param req 查询参数
* @return 安全知识库文件夹树列表
*/
List<HseKnowledgeDocumentVo> queryList(HseKnowledgeDocumentBo bo);
List<Tree<Long>> queryFolderTreeList(HseKnowledgeDocumentQueryReq req);
/**
* 新增安全知识库
* 查询文件夹下的安全知识库文件列表
*
* @param bo 安全知识库
* @param req 查询参数
* @param pageQuery 分页参数
* @return 安全知识库文件列表
*/
TableDataInfo<HseKnowledgeDocumentVo> queryFileListByFolderId(HseKnowledgeDocumentFileQueryReq req, PageQuery pageQuery);
/**
* 查询回收站中的文件
*
* @param req 查询参数
* @param pageQuery 分页参数
* @return 回收站中的文件
*/
TableDataInfo<HseKnowledgeDocumentVo> queryRecycleBinPageList(HseKnowledgeDocumentQueryReq req, PageQuery pageQuery);
/**
* 新增安全知识库文件
*
* @param file 文件
* @param req 安全知识库
* @return 是否新增成功
*/
Boolean insertByBo(HseKnowledgeDocumentBo bo);
Boolean insertFile(MultipartFile file, HseKnowledgeDocumentCreateFileReq req);
/**
* 修改安全知识库
* 新增安全知识库文件夹
*
* @param bo 安全知识库
* @param projectId 项目id
* @return 是否新增成功
*/
Boolean insertFolderByTemplate(Long projectId);
/**
* 修改安全知识库文件
*
* @param req 安全知识库
* @return 是否修改成功
*/
Boolean updateByBo(HseKnowledgeDocumentBo bo);
Boolean updateFile(HseKnowledgeDocumentUpdateFileReq req);
/**
* 校验并批量删除安全知识库信息
* 删除安全知识库文件信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @param id 待删除文件的主键
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
Boolean deleteFileById(Long id);
/**
* 批量恢复安全会议纪要信息
*
* @param ids 待删除的主键集合
* @return 是否删除成功
*/
Boolean recoveryBatchById(Collection<Long> ids);
/**
* 构建前端所需要下拉树结构
*
* @param documentList 文档列表
* @return 下拉树结构列表
*/
List<Tree<Long>> buildTreeSelect(List<HseKnowledgeDocument> documentList);
/**
* 构建文档封装对象
*
* @param document 文档
* @return 文档封装对象
*/
HseKnowledgeDocumentVo getVo(HseKnowledgeDocument document);
/**
* 获取文档对象视图
*
* @param documentPage 文档对象
* @return 文档对象视图
*/
Page<HseKnowledgeDocumentVo> getVoPage(Page<HseKnowledgeDocument> documentPage);
}

View File

@ -19,11 +19,11 @@ import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.project.service.IBusProjectService;
import org.dromara.safety.constant.HseDocumentSafetyMeetingConstant;
import org.dromara.safety.domain.HseDocumentSafetyMeeting;
import org.dromara.safety.domain.enums.HseDocumentStatusEnum;
import org.dromara.safety.domain.enums.HseDocumentTypeEnum;
import org.dromara.safety.domain.dto.documentsafetymeeting.HseDocumentSafetyMeetingCreateFileReq;
import org.dromara.safety.domain.dto.documentsafetymeeting.HseDocumentSafetyMeetingCreateFolderReq;
import org.dromara.safety.domain.dto.documentsafetymeeting.HseDocumentSafetyMeetingQueryReq;
import org.dromara.common.enums.DocumentStatusEnum;
import org.dromara.common.enums.DocumentTypeEnum;
import org.dromara.safety.domain.vo.documentsafetymeeting.HseDocumentSafetyMeetingRecycleBinVo;
import org.dromara.safety.domain.vo.documentsafetymeeting.HseDocumentSafetyMeetingVo;
import org.dromara.safety.mapper.HseDocumentSafetyMeetingMapper;
@ -84,7 +84,7 @@ public class HseDocumentSafetyMeetingServiceImpl extends ServiceImpl<HseDocument
public List<HseDocumentSafetyMeetingVo> queryList(HseDocumentSafetyMeetingQueryReq req) {
LambdaQueryWrapper<HseDocumentSafetyMeeting> lqw = buildQueryWrapper(req);
// 排除已经删除的文件
lqw.eq(HseDocumentSafetyMeeting::getFileStatus, HseDocumentStatusEnum.NORMAL.getValue());
lqw.eq(HseDocumentSafetyMeeting::getFileStatus, DocumentStatusEnum.NORMAL.getValue());
List<HseDocumentSafetyMeeting> result = this.list(lqw);
return result.stream().map(this::getVo).toList();
}
@ -99,7 +99,7 @@ public class HseDocumentSafetyMeetingServiceImpl extends ServiceImpl<HseDocument
@Override
public TableDataInfo<HseDocumentSafetyMeetingRecycleBinVo> queryRecycleBinPageList(HseDocumentSafetyMeetingQueryReq req, PageQuery pageQuery) {
LambdaQueryWrapper<HseDocumentSafetyMeeting> lqw = this.buildQueryWrapper(req);
lqw.eq(HseDocumentSafetyMeeting::getFileStatus, HseDocumentStatusEnum.DELETE.getValue());
lqw.eq(HseDocumentSafetyMeeting::getFileStatus, DocumentStatusEnum.DELETE.getValue());
Page<HseDocumentSafetyMeeting> result = this.page(pageQuery.build(), lqw);
List<HseDocumentSafetyMeeting> documentSafetyMeetingList = result.getRecords();
// 添加分页信息
@ -148,7 +148,7 @@ public class HseDocumentSafetyMeetingServiceImpl extends ServiceImpl<HseDocument
}
// 填充默认值
documentSafetyMeeting.setFilePath(filePath);
documentSafetyMeeting.setFileType(HseDocumentTypeEnum.FOLDER.getValue());
documentSafetyMeeting.setFileType(DocumentTypeEnum.FOLDER.getValue());
boolean save = this.save(documentSafetyMeeting);
if (!save) {
throw new ServiceException("新增目录失败,数据库异常", HttpStatus.ERROR);
@ -198,9 +198,9 @@ public class HseDocumentSafetyMeetingServiceImpl extends ServiceImpl<HseDocument
documentSafetyMeeting.setFileSuffix(suffix);
// 判断文件类型
if (HseDocumentSafetyMeetingConstant.PICTURE_SUFFIX_LIST.contains(suffix)) {
documentSafetyMeeting.setFileType(HseDocumentTypeEnum.PICTURE.getValue());
documentSafetyMeeting.setFileType(DocumentTypeEnum.PICTURE.getValue());
} else {
documentSafetyMeeting.setFileType(HseDocumentTypeEnum.FILE.getValue());
documentSafetyMeeting.setFileType(DocumentTypeEnum.FILE.getValue());
}
documentSafetyMeeting.setFileName(ossUploadVo.getFileName());
documentSafetyMeeting.setOriginalName(originalFilename);
@ -229,7 +229,7 @@ public class HseDocumentSafetyMeetingServiceImpl extends ServiceImpl<HseDocument
List<HseDocumentSafetyMeeting> updateList = allParentIdsRecursively.stream().map(id -> {
HseDocumentSafetyMeeting documentSafetyMeeting = new HseDocumentSafetyMeeting();
documentSafetyMeeting.setId(id);
documentSafetyMeeting.setFileStatus(HseDocumentStatusEnum.NORMAL.getValue());
documentSafetyMeeting.setFileStatus(DocumentStatusEnum.NORMAL.getValue());
return documentSafetyMeeting;
}).toList();
boolean result = this.updateBatchById(updateList);
@ -243,7 +243,7 @@ public class HseDocumentSafetyMeetingServiceImpl extends ServiceImpl<HseDocument
// 使用 list() 方法批量查询当前 id 列表对应的实体数据
List<HseDocumentSafetyMeeting> fileList = this.lambdaQuery()
.in(HseDocumentSafetyMeeting::getId, ids)
.eq(HseDocumentSafetyMeeting::getFileStatus, HseDocumentStatusEnum.DELETE.getValue())
.eq(HseDocumentSafetyMeeting::getFileStatus, DocumentStatusEnum.DELETE.getValue())
.list();
// 通过 stream 流过滤出非 0 的父 id并去重
List<Long> parentIdList = fileList.stream()
@ -278,7 +278,7 @@ public class HseDocumentSafetyMeetingServiceImpl extends ServiceImpl<HseDocument
throw new ServiceException("父级目录不存在", HttpStatus.NOT_FOUND);
}
// 判断父级目录是否是文件夹
if (HseDocumentTypeEnum.FILE.getValue().equals(pDocumentSafetyMeeting.getFileType())) {
if (DocumentTypeEnum.FILE.getValue().equals(pDocumentSafetyMeeting.getFileType())) {
throw new ServiceException("父级目录不是文件夹", HttpStatus.BAD_REQUEST);
}
// 判断是否为同一个项目
@ -306,7 +306,7 @@ public class HseDocumentSafetyMeetingServiceImpl extends ServiceImpl<HseDocument
HseDocumentSafetyMeeting documentSafetyMeeting = new HseDocumentSafetyMeeting();
documentSafetyMeeting.setId(id);
documentSafetyMeeting.setDeletedAt(new Date());
documentSafetyMeeting.setFileStatus(HseDocumentStatusEnum.DELETE.getValue());
documentSafetyMeeting.setFileStatus(DocumentStatusEnum.DELETE.getValue());
return documentSafetyMeeting;
}).toList();
// 批量修改
@ -421,7 +421,7 @@ public class HseDocumentSafetyMeetingServiceImpl extends ServiceImpl<HseDocument
idList.add(id);
// 查询当前记录(判断是否为文件夹)
HseDocumentSafetyMeeting record = this.getById(id);
if (record != null && HseDocumentTypeEnum.FOLDER.getValue().equals(record.getFileType())) {
if (record != null && DocumentTypeEnum.FOLDER.getValue().equals(record.getFileType())) {
// 如果是文件夹,递归查询子节点
getChildIds(id, idList);
}
@ -439,13 +439,13 @@ public class HseDocumentSafetyMeetingServiceImpl extends ServiceImpl<HseDocument
// 条件查询查询pid为parentId的记录
List<HseDocumentSafetyMeeting> childList = this.lambdaQuery()
.eq(HseDocumentSafetyMeeting::getPid, parentId)
.eq(HseDocumentSafetyMeeting::getFileStatus, HseDocumentStatusEnum.NORMAL.getValue())
.eq(HseDocumentSafetyMeeting::getFileStatus, DocumentStatusEnum.NORMAL.getValue())
.list();
// 遍历所有子记录
for (HseDocumentSafetyMeeting child : childList) {
ids.add(child.getId());
// 如果子节点是文件夹,继续递归
if (HseDocumentTypeEnum.FOLDER.getValue().equals(child.getFileType())) {
if (DocumentTypeEnum.FOLDER.getValue().equals(child.getFileType())) {
getChildIds(child.getId(), ids);
}
}

View File

@ -1,20 +1,40 @@
package org.dromara.safety.service.impl;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.dromara.safety.domain.bo.HseKnowledgeDocumentBo;
import org.dromara.safety.domain.vo.knowledgedocument.HseKnowledgeDocumentVo;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.dromara.common.core.constant.HttpStatus;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.*;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.project.service.IBusProjectService;
import org.dromara.safety.constant.HseKnowledgeDocumentConstant;
import org.dromara.safety.domain.HseKnowledgeDocument;
import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentCreateFileReq;
import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentFileQueryReq;
import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentQueryReq;
import org.dromara.safety.domain.dto.knowledgedocument.HseKnowledgeDocumentUpdateFileReq;
import org.dromara.common.enums.DocumentStatusEnum;
import org.dromara.common.enums.DocumentTypeEnum;
import org.dromara.safety.domain.vo.knowledgedocument.HseKnowledgeDocumentVo;
import org.dromara.safety.mapper.HseKnowledgeDocumentMapper;
import org.dromara.safety.service.IHseKnowledgeDocumentService;
import org.dromara.system.domain.vo.SysOssUploadVo;
import org.dromara.system.service.ISysOssService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.*;
import java.util.stream.Collectors;
/**
* 安全知识库Service业务层处理
@ -22,11 +42,15 @@ import java.util.Collection;
* @author lcj
* @date 2025-06-25
*/
@RequiredArgsConstructor
@Service
public class HseKnowledgeDocumentServiceImpl implements IHseKnowledgeDocumentService {
public class HseKnowledgeDocumentServiceImpl extends ServiceImpl<HseKnowledgeDocumentMapper, HseKnowledgeDocument>
implements IHseKnowledgeDocumentService {
private final HseKnowledgeDocumentMapper baseMapper;
@Resource
private IBusProjectService projectService;
@Resource
private ISysOssService ossService;
/**
* 查询安全知识库
@ -35,88 +59,364 @@ public class HseKnowledgeDocumentServiceImpl implements IHseKnowledgeDocumentSer
* @return 安全知识库
*/
@Override
public HseKnowledgeDocumentVo queryById(Long id){
return baseMapper.selectVoById(id);
public HseKnowledgeDocumentVo queryById(Long id) {
HseKnowledgeDocument entity = this.getById(id);
if (entity == null) {
throw new ServiceException("安全知识库文件或文件夹不存在", HttpStatus.NOT_FOUND);
}
return this.getVo(entity);
}
/**
* 查询符合条件的安全知识库列表
* 查询安全知识库列表
*
* @param bo 查询条件
* @param req 查询参数
* @return 安全知识库列表
*/
@Override
public List<HseKnowledgeDocumentVo> queryList(HseKnowledgeDocumentBo bo) {
LambdaQueryWrapper<HseKnowledgeDocument> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<HseKnowledgeDocument> buildQueryWrapper(HseKnowledgeDocumentBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<HseKnowledgeDocument> lqw = Wrappers.lambdaQuery();
lqw.orderByAsc(HseKnowledgeDocument::getId);
lqw.eq(bo.getProjectId() != null, HseKnowledgeDocument::getProjectId, bo.getProjectId());
lqw.eq(bo.getPid() != null, HseKnowledgeDocument::getPid, bo.getPid());
lqw.like(StringUtils.isNotBlank(bo.getFileName()), HseKnowledgeDocument::getFileName, bo.getFileName());
lqw.eq(StringUtils.isNotBlank(bo.getFilePath()), HseKnowledgeDocument::getFilePath, bo.getFilePath());
lqw.eq(StringUtils.isNotBlank(bo.getFileUrl()), HseKnowledgeDocument::getFileUrl, bo.getFileUrl());
lqw.eq(StringUtils.isNotBlank(bo.getFileType()), HseKnowledgeDocument::getFileType, bo.getFileType());
lqw.eq(StringUtils.isNotBlank(bo.getFileSuffix()), HseKnowledgeDocument::getFileSuffix, bo.getFileSuffix());
lqw.eq(StringUtils.isNotBlank(bo.getFileStatus()), HseKnowledgeDocument::getFileStatus, bo.getFileStatus());
lqw.like(StringUtils.isNotBlank(bo.getOriginalName()), HseKnowledgeDocument::getOriginalName, bo.getOriginalName());
return lqw;
public List<Tree<Long>> queryFolderTreeList(HseKnowledgeDocumentQueryReq req) {
Long projectId = req.getProjectId();
List<HseKnowledgeDocument> folderList = this.lambdaQuery()
.eq(HseKnowledgeDocument::getProjectId, projectId)
.eq(HseKnowledgeDocument::getFileType, DocumentTypeEnum.FOLDER.getValue())
.eq(HseKnowledgeDocument::getFileStatus, DocumentStatusEnum.NORMAL.getValue())
.list();
return this.buildTreeSelect(folderList);
}
/**
* 新增安全知识库
* 查询文件夹下的安全知识库文件列表
*
* @param bo 安全知识库
* @param req 查询参数
* @param pageQuery 分页参数
* @return 安全知识库文件列表
*/
@Override
public TableDataInfo<HseKnowledgeDocumentVo> queryFileListByFolderId(HseKnowledgeDocumentFileQueryReq req, PageQuery pageQuery) {
HseKnowledgeDocument folder = this.getById(req.getFolderId());
if (folder == null) {
throw new ServiceException("文件夹不存在", HttpStatus.NOT_FOUND);
}
if (!DocumentTypeEnum.FOLDER.getValue().equals(folder.getFileType())) {
throw new ServiceException("所选目录不是文件夹", HttpStatus.BAD_REQUEST);
}
LambdaQueryWrapper<HseKnowledgeDocument> lqw = new LambdaQueryWrapper<>();
lqw.eq(HseKnowledgeDocument::getPid, folder.getId());
lqw.eq(HseKnowledgeDocument::getProjectId, folder.getProjectId());
lqw.ne(HseKnowledgeDocument::getFileType, DocumentTypeEnum.FOLDER.getValue());
lqw.eq(HseKnowledgeDocument::getFileStatus, DocumentStatusEnum.NORMAL.getValue());
lqw.like(StringUtils.isNotBlank(req.getFileName()), HseKnowledgeDocument::getFileName, req.getFileName());
Page<HseKnowledgeDocument> documentPage = this.page(pageQuery.build(), lqw);
return TableDataInfo.build(this.getVoPage(documentPage));
}
/**
* 查询回收站中的文件
*
* @param req 查询参数
* @param pageQuery 分页参数
* @return 回收站中的文件
*/
@Override
public TableDataInfo<HseKnowledgeDocumentVo> queryRecycleBinPageList(HseKnowledgeDocumentQueryReq req, PageQuery pageQuery) {
Long projectId = req.getProjectId();
if (projectService.getById(projectId) == null) {
throw new ServiceException("项目不存在", HttpStatus.NOT_FOUND);
}
LambdaQueryWrapper<HseKnowledgeDocument> lqw = new LambdaQueryWrapper<>();
lqw.eq(HseKnowledgeDocument::getProjectId, projectId);
lqw.eq(HseKnowledgeDocument::getFileStatus, DocumentStatusEnum.DELETE.getValue());
lqw.like(StringUtils.isNotBlank(req.getFileName()), HseKnowledgeDocument::getFileName, req.getFileName());
lqw.orderByDesc(HseKnowledgeDocument::getDeletedAt);
Page<HseKnowledgeDocument> result = this.page(pageQuery.build(), lqw);
return TableDataInfo.build(this.getVoPage(result));
}
/**
* 新增安全知识库文件
*
* @param req 安全知识库
* @return 是否新增成功
*/
@Override
public Boolean insertByBo(HseKnowledgeDocumentBo bo) {
HseKnowledgeDocument add = MapstructUtils.convert(bo, HseKnowledgeDocument.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
public Boolean insertFile(MultipartFile file, HseKnowledgeDocumentCreateFileReq req) {
// 数据校验
if (ObjectUtils.isEmpty(file)) {
throw new ServiceException("文件不能为空", HttpStatus.BAD_REQUEST);
}
return flag;
Long projectId = req.getProjectId();
if (projectService.getById(projectId) == null) {
throw new ServiceException("项目不存在", HttpStatus.BAD_REQUEST);
}
// 拼接文件名
String originalFilename = file.getOriginalFilename();
String suffix = FileUtil.getSuffix(originalFilename);
if (StringUtils.isBlank(suffix)) {
throw new ServiceException("文件格式错误", HttpStatus.BAD_REQUEST);
}
String uuid = IdUtil.fastSimpleUUID();
String date = DateUtils.getDate();
String fileName = String.format("%s_%s.%s", date, uuid, suffix);
// 拼接文件路径
Long pid = req.getPid();
if (pid == null || pid == 0) {
throw new ServiceException("不能在根目录上传文件", HttpStatus.BAD_REQUEST);
}
HseKnowledgeDocument pHseKnowledgeDocument = this.getById(pid);
// 校验父级目录
validParentFolder(pHseKnowledgeDocument, projectId);
String filePath = pHseKnowledgeDocument.getFilePath() + "/" + fileName;
// 上传文件
SysOssUploadVo ossUploadVo = ossService.uploadWithNoSave(file, filePath);
// 保存文件信息
HseKnowledgeDocument knowledgeDocument = new HseKnowledgeDocument();
knowledgeDocument.setFilePath(filePath);
knowledgeDocument.setFileUrl(ossUploadVo.getUrl());
knowledgeDocument.setFileSuffix(suffix);
if (HseKnowledgeDocumentConstant.PICTURE_SUFFIX_LIST.contains(suffix)) {
knowledgeDocument.setFileType(DocumentTypeEnum.PICTURE.getValue());
} else {
knowledgeDocument.setFileType(DocumentTypeEnum.FILE.getValue());
}
knowledgeDocument.setFileName(originalFilename);
knowledgeDocument.setOriginalName(originalFilename);
knowledgeDocument.setProjectId(projectId);
knowledgeDocument.setPid(pid);
boolean save = this.save(knowledgeDocument);
if (!save) {
throw new ServiceException("新增文件失败,数据库异常", HttpStatus.ERROR);
}
return true;
}
/**
* 修改安全知识库
* 新增安全知识库文件夹
*
* @param bo 安全知识库
* @param projectId 项目id
* @return 是否新增成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean insertFolderByTemplate(Long projectId) {
// 创建顶级目录
String prefix = HseKnowledgeDocumentConstant.getTopFolderPrefix(projectId);
String topPath = prefix + HseKnowledgeDocumentConstant.TOP_FOLDER_NAME;
HseKnowledgeDocument topFolder = new HseKnowledgeDocument();
topFolder.setProjectId(projectId);
topFolder.setPid(0L);
topFolder.setFileName(HseKnowledgeDocumentConstant.TOP_FOLDER_NAME);
topFolder.setFilePath(topPath);
topFolder.setFileType(DocumentTypeEnum.FOLDER.getValue());
boolean save = this.save(topFolder);
if (!save) {
throw new ServiceException("新增顶级目录失败,数据库异常", HttpStatus.ERROR);
}
// 创建二级目录
Long pid = topFolder.getId();
List<HseKnowledgeDocument> documents = HseKnowledgeDocumentConstant.SECOND_LEVEL_FOLDER_NAME.stream().map(name -> {
HseKnowledgeDocument folder = new HseKnowledgeDocument();
String path = topPath + "/" + name;
folder.setProjectId(projectId);
folder.setPid(pid);
folder.setFileName(name);
folder.setFilePath(path);
folder.setFileType(DocumentTypeEnum.FOLDER.getValue());
return folder;
}).toList();
return this.saveBatch(documents);
}
/**
* 修改安全知识库文件
*
* @param req 安全知识库
* @return 是否修改成功
*/
@Override
public Boolean updateByBo(HseKnowledgeDocumentBo bo) {
HseKnowledgeDocument update = MapstructUtils.convert(bo, HseKnowledgeDocument.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
public Boolean updateFile(HseKnowledgeDocumentUpdateFileReq req) {
Long id = req.getId();
HseKnowledgeDocument oldDocument = this.getById(id);
if (oldDocument == null) {
throw new ServiceException("修改安全知识库文件失败,数据不存在", HttpStatus.NOT_FOUND);
}
HseKnowledgeDocument document = new HseKnowledgeDocument();
BeanUtils.copyProperties(req, document);
boolean result = this.updateById(document);
if (!result) {
throw new ServiceException("修改安全知识库文件失败", HttpStatus.ERROR);
}
return true;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(HseKnowledgeDocument entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 校验并批量删除安全知识库信息
* 删除安全知识库文件信息
*
* @param ids 待删除的主键集合
* @param isValid 是否进行有效性校验
* @param id 待删除文件的主键
* @return 是否删除成功
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
public Boolean deleteFileById(Long id) {
HseKnowledgeDocument document = this.getById(id);
if (document == null) {
throw new ServiceException("文件不存在", HttpStatus.ERROR);
}
return baseMapper.deleteByIds(ids) > 0;
if (!document.getFileStatus().equals(DocumentStatusEnum.NORMAL.getValue())) {
throw new ServiceException("文件已删除", HttpStatus.ERROR);
}
if (document.getFileType().equals(DocumentTypeEnum.FOLDER.getValue())) {
throw new ServiceException("文件夹不能删除", HttpStatus.ERROR);
}
HseKnowledgeDocument deleteDocument = new HseKnowledgeDocument();
deleteDocument.setId(document.getId());
deleteDocument.setDeletedAt(new Date());
deleteDocument.setFileStatus(DocumentStatusEnum.DELETE.getValue());
return this.updateById(deleteDocument);
}
/**
* 批量恢复安全会议纪要信息
*
* @param ids 待删除的主键集合
* @return 是否删除成功
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean recoveryBatchById(Collection<Long> ids) {
List<Long> allParentIdsRecursively = getAllParentIdsRecursively(ids);
// 需要更新状态的文件集合
allParentIdsRecursively.addAll(ids);
List<HseKnowledgeDocument> updateList = allParentIdsRecursively.stream().map(id -> {
HseKnowledgeDocument documentSafetyMeeting = new HseKnowledgeDocument();
documentSafetyMeeting.setId(id);
documentSafetyMeeting.setFileStatus(DocumentStatusEnum.NORMAL.getValue());
return documentSafetyMeeting;
}).toList();
boolean result = this.updateBatchById(updateList);
if (!result) {
throw new ServiceException("恢复文件失败,数据库异常", HttpStatus.ERROR);
}
return true;
}
/**
* 构建前端所需要下拉树结构
*
* @param documentList 文档列表
* @return 下拉树结构列表
*/
@Override
public List<Tree<Long>> buildTreeSelect(List<HseKnowledgeDocument> documentList) {
if (CollUtil.isEmpty(documentList)) {
return CollUtil.newArrayList();
}
// 获取当前列表中每一个节点的parentId然后在列表中查找是否有id与其parentId对应若无对应则表明此时节点列表中该节点在当前列表中属于顶级节点
List<Tree<Long>> treeList = CollUtil.newArrayList();
for (HseKnowledgeDocument d : documentList) {
Long parentId = d.getPid();
HseKnowledgeDocument document = StreamUtils.findFirst(documentList, it -> Objects.equals(it.getId(), parentId));
if (ObjectUtil.isNull(document)) {
List<Tree<Long>> trees = TreeBuildUtils.build(documentList, parentId, (knowledgeDocument, tree) ->
tree.setId(knowledgeDocument.getId())
.setParentId(knowledgeDocument.getPid())
.setName(knowledgeDocument.getFileName()));
Tree<Long> tree = StreamUtils.findFirst(trees, it -> Objects.equals(it.getId(), d.getId()));
treeList.add(tree);
}
}
return treeList;
}
/**
* 构建文档封装对象
*
* @param document 文档
* @return 文档封装对象
*/
@Override
public HseKnowledgeDocumentVo getVo(HseKnowledgeDocument document) {
HseKnowledgeDocumentVo vo = new HseKnowledgeDocumentVo();
if (document == null) {
return vo;
}
BeanUtils.copyProperties(document, vo);
return vo;
}
/**
* 获取文档对象视图
*
* @param documentPage 文档对象
* @return 文档对象视图
*/
@Override
public Page<HseKnowledgeDocumentVo> getVoPage(Page<HseKnowledgeDocument> documentPage) {
List<HseKnowledgeDocument> documentList = documentPage.getRecords();
Page<HseKnowledgeDocumentVo> documentVoPage = new Page<>(
documentPage.getCurrent(),
documentPage.getSize(),
documentPage.getTotal());
if (CollUtil.isEmpty(documentList)) {
return documentVoPage;
}
List<HseKnowledgeDocumentVo> documentVoList = documentList.stream().map(entity -> {
HseKnowledgeDocumentVo documentVo = new HseKnowledgeDocumentVo();
BeanUtils.copyProperties(entity, documentVo);
return documentVo;
}).toList();
documentVoPage.setRecords(documentVoList);
return documentVoPage;
}
/**
* 校验父级目录是否存在
*
* @param knowledgeDocument 父级目录
* @param projectId 当前项目id
*/
private void validParentFolder(HseKnowledgeDocument knowledgeDocument, Long projectId) {
// 判断父级目录是否存在
if (knowledgeDocument == null) {
throw new ServiceException("父级目录不存在", HttpStatus.NOT_FOUND);
}
// 判断父级目录是否是文件夹
if (!DocumentTypeEnum.FOLDER.getValue().equals(knowledgeDocument.getFileType())) {
throw new ServiceException("父级目录不是文件夹", HttpStatus.BAD_REQUEST);
}
// 判断是否为同一个项目
if (!knowledgeDocument.getProjectId().equals(projectId)) {
throw new ServiceException("父级目录不属于当前项目", HttpStatus.BAD_REQUEST);
}
}
/**
* 递归查询所有父级 id
*
* @param ids id 列表
* @return 父级 id 列表
*/
private List<Long> getAllParentIdsRecursively(Collection<Long> ids) {
// 使用 list() 方法批量查询当前 id 列表对应的实体数据
List<HseKnowledgeDocument> fileList = this.lambdaQuery()
.in(HseKnowledgeDocument::getId, ids)
.eq(HseKnowledgeDocument::getFileStatus, DocumentStatusEnum.DELETE.getValue())
.list();
// 通过 stream 流过滤出非 0 的父 id并去重
List<Long> parentIdList = fileList.stream()
.map(HseKnowledgeDocument::getPid)
.filter(pid -> pid != 0)
.distinct()
.collect(Collectors.toList());
// 如果父 id 列表为空,说明递归终止,返回空列表
if (parentIdList.isEmpty()) {
return new ArrayList<>();
}
// 递归查询父 id 列表对应的上级父 id
List<Long> higherParentIds = getAllParentIdsRecursively(parentIdList);
// 将当前层的父 id 和上级递归得到的父 id 合并
List<Long> allParentIds = new ArrayList<>();
allParentIds.addAll(parentIdList);
allParentIds.addAll(higherParentIds);
// 返回合并后去重的结果
return allParentIds.stream().distinct().collect(Collectors.toList());
}
}

View File

@ -46,7 +46,7 @@ import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.service.ISysDictDataService;
import org.dromara.system.service.ISysOssService;
import org.dromara.system.service.ISysUserService;
import org.dromara.utils.DocumentUtil;
import org.dromara.common.utils.DocumentUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;

View File

@ -0,0 +1,43 @@
package org.dromara.system.domain.enums;
import lombok.Getter;
import java.util.Arrays;
import java.util.List;
/**
* @author lcj
* @date 2025/6/26 9:39
*/
@Getter
public enum SysPostManagerEnum {
MAJOR("major", "专业负责人"),
CONSTRUCTION("construction", "施工员"),
QUALITY("quality", "质检员"),
SAFETY("safety", "安全员"),
MEASURE("measure", "测量员"),
DATA("data", "资料员"),
TEST("test", "试验员"),
MATERIALS("materials", "材料员"),
SUPERVISOR("supervisor", "监理员");
private final String code;
private final String name;
SysPostManagerEnum(String code, String name) {
this.code = code;
this.name = name;
}
/**
* 获取全部枚举
*
* @return 全部枚举
*/
public static List<SysPostManagerEnum> toList() {
return Arrays.asList(values());
}
}

View File

@ -120,6 +120,22 @@ public interface ISysPostService {
*/
int insertPost(SysPostBo bo);
/**
* 批量新增岗位信息
*
* @param bo 岗位信息
* @return 结果
*/
Boolean insertPost(List<SysPostBo> bo);
/**
* 通过部门id批量新增默认岗位信息
*
* @param deptId 部门id
* @return 结果
*/
Boolean insertPostByDeptId(Long deptId);
/**
* 修改保存岗位信息
*

View File

@ -18,6 +18,7 @@ import org.dromara.system.domain.SysDept;
import org.dromara.system.domain.SysPost;
import org.dromara.system.domain.SysUserPost;
import org.dromara.system.domain.bo.SysPostBo;
import org.dromara.system.domain.enums.SysPostManagerEnum;
import org.dromara.system.domain.vo.SysPostVo;
import org.dromara.system.mapper.SysDeptMapper;
import org.dromara.system.mapper.SysPostMapper;
@ -27,6 +28,7 @@ import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 岗位信息 服务层处理
@ -234,6 +236,39 @@ public class SysPostServiceImpl implements ISysPostService, PostService {
return baseMapper.insert(post);
}
/**
* 批量新增岗位信息
*
* @param bo 岗位信息
* @return 结果
*/
@Override
public Boolean insertPost(List<SysPostBo> bo) {
List<SysPost> postList = bo.stream().map(b -> MapstructUtils.convert(b, SysPost.class)).toList();
return baseMapper.insertBatch(postList);
}
/**
* 通过部门id批量新增默认岗位信息
*
* @param deptId 部门id
* @return 结果
*/
@Override
public Boolean insertPostByDeptId(Long deptId) {
List<SysPostManagerEnum> managerEnumList = SysPostManagerEnum.toList();
AtomicInteger counter = new AtomicInteger(1);
List<SysPostBo> postBoList = managerEnumList.stream().map(managerEnum -> {
SysPostBo postBo = new SysPostBo();
postBo.setDeptId(deptId);
postBo.setPostName(managerEnum.getName());
postBo.setPostCode(managerEnum.getCode());
postBo.setPostSort(counter.getAndIncrement());
return postBo;
}).toList();
return insertPost(postBoList);
}
/**
* 修改保存岗位信息
*

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.contractor.mapper.SubContractorToolRecordMapper">
</mapper>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.project.mapper.BusContractorToolMapper">
</mapper>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.quality.mapper.QltKnowledgeDocumentMapper">
</mapper>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="org.dromara.safety.mapper.HseKnowledgeDocumentMapper">
</mapper>

View File

@ -797,3 +797,43 @@ values(1937825131464245254, '质量知识库删除', 1937825131464245250, '4',
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1937825131464245255, '质量知识库导出', 1937825131464245250, '5', '#', '', 1, 0, 'F', '0', '0', 'quality:knowledgeDocument:export', '#', 103, 1, sysdate(), null, null, '');
-- 菜单 SQL
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1938134870333067266, '分包方工器具', '1937684147828957185', '1', 'contractorTool', 'project/contractorTool/index', 1, 0, 'C', '0', '0', 'project:contractorTool:list', '#', 103, 1, sysdate(), null, null, '分包方工器具菜单');
-- 按钮 SQL
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1938134870333067267, '分包方工器具查询', 1938134870333067266, '1', '#', '', 1, 0, 'F', '0', '0', 'project:contractorTool:query', '#', 103, 1, sysdate(), null, null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1938134870333067268, '分包方工器具新增', 1938134870333067266, '2', '#', '', 1, 0, 'F', '0', '0', 'project:contractorTool:add', '#', 103, 1, sysdate(), null, null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1938134870333067269, '分包方工器具修改', 1938134870333067266, '3', '#', '', 1, 0, 'F', '0', '0', 'project:contractorTool:edit', '#', 103, 1, sysdate(), null, null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1938134870333067270, '分包方工器具删除', 1938134870333067266, '4', '#', '', 1, 0, 'F', '0', '0', 'project:contractorTool:remove', '#', 103, 1, sysdate(), null, null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1938134870333067271, '分包方工器具导出', 1938134870333067266, '5', '#', '', 1, 0, 'F', '0', '0', 'project:contractorTool:export', '#', 103, 1, sysdate(), null, null, '');
-- 菜单 SQL
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1938171656673443841, '分包方工器具进场', '1938134870333067266', '1', 'contractorToolEntry', 'contractor/contractorToolEntry/index', 1, 0, 'C', '0', '0', 'contractor:contractorToolEntry:list', '#', 103, 1, sysdate(), null, null, '分包方工器具进场菜单');
-- 按钮 SQL
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1938171656673443842, '分包方工器具进场查询', 1938171656673443841, '1', '#', '', 1, 0, 'F', '0', '0', 'contractor:contractorToolEntry:query', '#', 103, 1, sysdate(), null, null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1938171656673443843, '分包方工器具进场新增', 1938171656673443841, '2', '#', '', 1, 0, 'F', '0', '0', 'contractor:contractorToolEntry:add', '#', 103, 1, sysdate(), null, null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1938171656673443844, '分包方工器具进场修改', 1938171656673443841, '3', '#', '', 1, 0, 'F', '0', '0', 'contractor:contractorToolEntry:edit', '#', 103, 1, sysdate(), null, null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1938171656673443845, '分包方工器具进场删除', 1938171656673443841, '4', '#', '', 1, 0, 'F', '0', '0', 'contractor:contractorToolEntry:remove', '#', 103, 1, sysdate(), null, null, '');
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
values(1938171656673443846, '分包方工器具进场导出', 1938171656673443841, '5', '#', '', 1, 0, 'F', '0', '0', 'contractor:contractorToolEntry:export', '#', 103, 1, sysdate(), null, null, '');

View File

@ -1241,3 +1241,98 @@ CREATE TABLE `qlt_knowledge_document`
primary key (`id`) using btree,
index `idx_project_id` (`project_id` asc) using btree comment '项目id'
) comment '质量知识库' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `bus_contractor_tool`;
CREATE TABLE `bus_contractor_tool`
(
`id` bigint not null auto_increment comment '主键id',
`project_id` bigint not null comment '项目id',
`contractor_id` bigint not null comment '分包方id',
`tool_name` varchar(255) null comment '工具名称',
`tool_type` char(2) null comment '工具类型',
`tool_model` varchar(255) null comment '工具型号',
`tool_number` varchar(255) default 0 not null comment '工具数量',
`file` varchar(512) null comment '文件',
`remark` varchar(512) null comment '备注',
`create_by` varchar(64) null comment '创建者',
`update_by` varchar(64) null comment '更新者',
`create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间',
`update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间',
`deleted_at` datetime null comment '删除时间',
`is_delete` tinyint(4) default 0 not null comment '是否删除0正常 1删除',
primary key (`id`) using btree,
index `idx_project_id` (`project_id` asc) using btree comment '项目id',
index `idx_contractor_id` (`contractor_id` asc) using btree comment '分包方id'
) comment = '分包方工器具' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `sub_contractor_tool_record`;
CREATE TABLE `sub_contractor_tool_record`
(
`id` bigint not null auto_increment comment '主键id',
`project_id` bigint not null comment '项目id',
`contractor_id` bigint not null comment '分包方id',
`contractor_tool_id` bigint not null comment '分包方工器具id',
`record_type` char(1) not null comment '记录类型(1进场 2出场)',
`tool_number` varchar(255) null comment '进场工器具数量',
`check_num` varchar(255) null comment '检测编号',
`check_dept` varchar(255) null comment '检测部门',
`check_time` datetime null comment '检测时间',
`certificate` varchar(512) null comment '合格证',
`remark` varchar(512) null comment '备注',
`create_by` varchar(64) null comment '创建者',
`update_by` varchar(64) null comment '更新者',
`entry_time` datetime null comment '进场时间',
`create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间',
`update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间',
primary key (`id`) using btree,
index `idx_project_id` (`project_id` asc) using btree comment '项目id',
index `idx_contractor_id` (`contractor_id` asc) using btree comment '分包方id',
index `idx_contractor_tool_id` (`contractor_tool_id` asc) using btree comment '分包方工器具id'
) comment = '分包方工器具记录' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `sub_contractor_material`;
CREATE TABLE `sub_contractor_material`
(
`id` bigint not null auto_increment comment '主键id',
`project_id` bigint not null comment '项目id',
`contractor_id` bigint not null comment '分包方id',
`material_name` varchar(255) null comment '物料名称',
`material_type` char(2) null comment '物料类型',
`material_model` varchar(255) null comment '物料型号',
`material_number` varchar(255) default 0 not null comment '物料数量',
`file` varchar(512) null comment '文件',
`remark` varchar(512) null comment '备注',
`create_by` varchar(64) null comment '创建者',
`update_by` varchar(64) null comment '更新者',
`create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间',
`update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间',
`deleted_at` datetime null comment '删除时间',
`is_delete` tinyint(4) default 0 not null comment '是否删除0正常 1删除',
primary key (`id`) using btree,
index `idx_project_id` (`project_id` asc) using btree comment '项目id',
index `idx_contractor_id` (`contractor_id` asc) using btree comment '分包方id'
) comment = '分包方物料' collate = utf8mb4_unicode_ci;
DROP TABLE IF EXISTS `sub_contractor_material_record`;
CREATE TABLE `sub_contractor_material_record`
(
`id` bigint not null auto_increment comment '主键id',
`project_id` bigint not null comment '项目id',
`contractor_id` bigint not null comment '分包方id',
`material_id` bigint not null comment '物料id',
`record_type` char(1) not null comment '记录类型(1到货计划 2使用情况)',
`record_time` datetime not null comment '记录时间',
`material_number` varchar(255) null comment '数量',
`material_unit` varchar(50) null comment '单位',
`used_position` varchar(255) null comment '使用位置或构件部位(使用情况)',
`file` varchar(512) null comment '相关附件',
`remark` varchar(512) null comment '备注',
`create_by` varchar(64) null comment '创建者',
`update_by` varchar(64) null comment '更新者',
`create_time` datetime default CURRENT_TIMESTAMP null comment '创建时间',
`update_time` datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP comment '更新时间',
primary key (`id`) using btree,
index `idx_project_id` (`project_id` asc) using btree comment '项目id',
index `idx_contractor_id` (`contractor_id` asc) using btree comment '分包方id',
index `idx_material_id` (`material_id` asc) using btree comment '物料id'
) comment = '分包方物料记录' collate = utf8mb4_unicode_ci;