This commit is contained in:
zt
2025-09-23 20:25:40 +08:00
parent 278004788b
commit 4d6c7fe2c0
19 changed files with 734 additions and 100 deletions

View File

@ -0,0 +1,60 @@
package org.dromara.contractor.controller.app;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
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.SubUserSalaryDetail;
import org.dromara.contractor.domain.dto.usersalarydetail.SubUserSalaryDetailQueryReq;
import org.dromara.contractor.domain.dto.usersalaryperiod.SubConstructionUserSalaryDto;
import org.dromara.contractor.domain.vo.usersalarydetail.SubUserSalaryDetailVo;
import org.dromara.contractor.domain.vo.usersalaryperiod.SubConstructionUserSalaryVo;
import org.dromara.contractor.service.ISubUserSalaryDetailService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* app工资
*
* @author lilemy
* @date 2025-09-04
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/app/contractor/userSalaryDetail")
public class SubUserSalaryDetailAppController extends BaseController {
private final ISubUserSalaryDetailService subUserSalaryDetailService;
/**
* 工资分页
*/
@GetMapping("/salaryPageList")
public TableDataInfo<SubConstructionUserSalaryVo> salaryPageList( SubConstructionUserSalaryDto dto, PageQuery pageQuery) {
return subUserSalaryDetailService.salaryPageList(dto, pageQuery);
}
/**
* 工资详情
*/
@GetMapping("/detailList")
public R<List<SubUserSalaryDetail>> detailList( SubConstructionUserSalaryDto dto) {
return R.ok(subUserSalaryDetailService.detailList(dto));
}
}

View File

@ -100,4 +100,29 @@ public class SubConstructionUserSalaryVo implements Serializable {
*/
private String createTime;
private Long createBy;
/**
* 创建人
*/
@Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "createBy")
private String createByName;
/**
* 发放时间
*/
private Long tim;
/**
* 班组id
*/
private Long teamId;
/**
* 班组名
*/
private String teamName;
}

View File

@ -56,6 +56,7 @@ import org.dromara.project.service.IBusAttendanceService;
import org.dromara.project.service.IBusProjectService;
import org.dromara.project.service.IBusProjectTeamService;
import org.dromara.project.service.IBusWorkWageService;
import org.dromara.project.service.impl.BusProjectTeamServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
@ -64,10 +65,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import software.amazon.awssdk.utils.CollectionUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
@ -277,14 +275,13 @@ public class SubUserSalaryDetailServiceImpl extends ServiceImpl<SubUserSalaryDet
@Override
public TableDataInfo<SubConstructionUserSalaryVo> salaryPageList(SubConstructionUserSalaryDto dto, PageQuery pageQuery) {
String time = dto.getTime();
YearMonth parse = YearMonth.parse(time, DateTimeFormatter.ofPattern("yyyy-MM"));
LocalDate start = parse.atDay(1);
LocalDate end = parse.atEndOfMonth();
QueryWrapper<SubUserSalaryDetail> queryWrapper = new QueryWrapper<>();
queryWrapper.select("user_id", "SUM(work_hour) as workHour", "SUM(total_salary) as totalSalary","max(create_time) as createTime")
queryWrapper.select("user_id","max(team_id) as teamId","max(create_by) as createBy", "SUM(work_hour) as workHour", "SUM(total_salary) as totalSalary","max(create_time) as createTime")
.eq("project_id", dto.getProjectId())
.between("report_date", start, end)
.eq(dto.getTeamId()!=null,"team_id", dto.getTeamId())
@ -295,15 +292,24 @@ public class SubUserSalaryDetailServiceImpl extends ServiceImpl<SubUserSalaryDet
Page<SubUserSalaryDetail> result = this.page(pageQuery.build(), queryWrapper);
List<SubUserSalaryDetail> records = result.getRecords();
List<Long> userIds = records.stream().map(SubUserSalaryDetail::getUserId).toList();
Map<Long, SubConstructionUser> collect = new HashMap<>();
if(CollectionUtil.isNotEmpty(userIds)){
List<SubConstructionUser> subConstructionUsers = constructionUserService.list(Wrappers.lambdaQuery(SubConstructionUser.class)
.in(SubConstructionUser::getSysUserId, userIds));
collect = subConstructionUsers.stream().collect(Collectors.toMap(SubConstructionUser::getSysUserId, vo -> vo));
}
Set<Long> teamIds = records.stream().map(SubUserSalaryDetail::getTeamId).collect(Collectors.toSet());
Map<Long, BusProjectTeam> teamMap = new HashMap<>();
if(CollectionUtil.isNotEmpty(teamIds)){
List<BusProjectTeam> busProjectTeams = projectTeamService.listByIds(teamIds);
teamMap = busProjectTeams.stream().collect(Collectors.toMap(BusProjectTeam::getId, vo -> vo));
}
ArrayList<SubConstructionUserSalaryVo> vos = new ArrayList<>();
for (SubUserSalaryDetail detail : records) {
SubConstructionUserSalaryVo vo = new SubConstructionUserSalaryVo();
vo.setCreateBy(detail.getCreateBy());
vo.setId(detail.getId());
vo.setTime(dto.getTime());
vo.setTotalSalary(detail.getTotalSalary());
@ -311,6 +317,7 @@ public class SubUserSalaryDetailServiceImpl extends ServiceImpl<SubUserSalaryDet
vo.setWorkDay(detail.getWorkHour());
vo.setProjectId(dto.getProjectId());
vo.setUserId(detail.getUserId());
vo.setTeamId(detail.getTeamId());
SubConstructionUser constructionUser = collect.get(detail.getUserId());
if(constructionUser != null){
if(constructionUser.getSfzNumber() != null){
@ -319,6 +326,11 @@ public class SubUserSalaryDetailServiceImpl extends ServiceImpl<SubUserSalaryDet
vo.setUserName(constructionUser.getUserName());
vo.setYhkNumber(constructionUser.getYhkNumber());
vo.setYhkOpeningBank(constructionUser.getYhkOpeningBank());
}
BusProjectTeam projectTeam = teamMap.get(detail.getTeamId());
if(projectTeam != null){
vo.setTeamName(projectTeam.getTeamName());
}
vos.add(vo);
}
@ -328,18 +340,20 @@ public class SubUserSalaryDetailServiceImpl extends ServiceImpl<SubUserSalaryDet
@Override
public void export(HttpServletResponse response, SubConstructionUserSalaryDto dto) throws IOException {
// 1. 查询项目和人员数据
// 1. 查询项目信息并校验
BusProject project = projectService.getById(dto.getProjectId());
if (project == null) {
throw new ServiceException("项目不存在");
}
// 2. 解析年月和查询薪资明细
// 2. 解析时间参数
YearMonth yearMonth = YearMonth.parse(dto.getTime(), DateTimeFormatter.ofPattern("yyyy-MM"));
LocalDate start = yearMonth.atDay(1);
LocalDate end = yearMonth.atEndOfMonth();
// 3. 查询薪资明细数据
QueryWrapper<SubUserSalaryDetail> queryWrapper = new QueryWrapper<>();
queryWrapper.select("user_id", "SUM(work_hour) as workHour", "SUM(total_salary) as totalSalary","max(create_time) as createTime")
queryWrapper.select("user_id", "SUM(work_hour) as workHour", "SUM(total_salary) as totalSalary")
.eq("project_id", dto.getProjectId())
.between("report_date", start, end)
.eq(dto.getUserId() != null, "user_id", dto.getUserId())
@ -348,137 +362,140 @@ public class SubUserSalaryDetailServiceImpl extends ServiceImpl<SubUserSalaryDet
.groupBy("user_id");
List<SubUserSalaryDetail> salaryDetailsList = baseMapper.selectList(queryWrapper);
if (salaryDetailsList.isEmpty()) {
throw new ServiceException("暂无数据");
}
Map<Long, SubUserSalaryDetail> map = salaryDetailsList.stream().collect(Collectors.toMap(SubUserSalaryDetail::getUserId, vo -> vo));
List<Long> userIds = salaryDetailsList.stream().map(SubUserSalaryDetail::getUserId).toList();
// 4. 构建薪资数据映射
Map<Long, SubUserSalaryDetail> salaryMap = salaryDetailsList.stream()
.collect(Collectors.toMap(SubUserSalaryDetail::getUserId, vo -> vo));
// 5. 批量查询用户信息(只查必要字段)
Set<Long> userIds = salaryMap.keySet();
List<SubConstructionUser> userList = constructionUserService.lambdaQuery()
.select(SubConstructionUser::getSysUserId, SubConstructionUser::getTeamId, SubConstructionUser::getUserName
, SubConstructionUser::getYhkNumber, SubConstructionUser::getYhkOpeningBank)
.in(SubConstructionUser::getSysUserId, userIds)
.list();
// 3. 设置响应头(下载文件配置
// 6. 预处理班组信息解决null键问题
// 使用-1L作为临时键替代null避免groupingBy出现null键错误
Map<Long, List<SubConstructionUser>> teamUsersMap = userList.stream()
.collect(Collectors.groupingBy(user -> {
Long teamId = user.getTeamId();
return teamId != null ? teamId : -1L; // 关键修复null键映射为-1
}));
// 提取实际班组ID排除-1并计算数量
List<Long> teamIds = teamUsersMap.keySet().stream()
.filter(id -> !id.equals(-1L))
.collect(Collectors.toList());
int actualTeamCount = teamIds.size();
// 动态计算初始容量避免HashMap扩容
Map<Long, String> teamNameMap = new HashMap<>((int) Math.ceil(actualTeamCount * 1.5));
// 批量查询班组名称
if (!teamIds.isEmpty()) {
List<BusProjectTeam> teams = projectTeamService.lambdaQuery()
.select(BusProjectTeam::getId, BusProjectTeam::getTeamName)
.in(BusProjectTeam::getId, teamIds)
.list();
teams.forEach(team -> teamNameMap.put(team.getId(), team.getTeamName()));
}
// 7. 检查班组数量阈值
int maxSheetThreshold = 100; // 根据实际情况调整
if (actualTeamCount > maxSheetThreshold) {
log.warn("班组数量过多({}个可能导致Excel文件过大或导出缓慢", actualTeamCount);
// 若需严格限制,可在此处抛出异常
// throw new ServiceException("班组数量超过限制,最多支持" + maxSheetThreshold + "个");
}
// 8. 设置响应头
setResponseHeader(response, yearMonth.getYear(), yearMonth.getMonthValue());
// 5. 读取模板文件到字节数组(复用模板
// 9. 读取模板文件(缓冲流优化
byte[] templateBytes;
try (InputStream templateStream = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("excelTemplate/salary_template.xlsx")) {
.getResourceAsStream("excelTemplate/salary_template.xlsx");
BufferedInputStream bis = new BufferedInputStream(templateStream);
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
if (templateStream == null) {
throw new ServiceException("模板文件不存在路径excelTemplate/salary_template.xlsx");
}
templateBytes = IOUtils.toByteArray(templateStream);
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = bis.read(buffer)) != -1) {
baos.write(buffer, 0, bytesRead);
}
templateBytes = baos.toByteArray();
}
// 6. POI 处理多 sheet核心:克隆模板 + 命名
// 存储 <sheet名称, sheet对象> 映射,方便后续 EasyExcel 匹配
Map<String, Sheet> sheetMap = new LinkedHashMap<>();
// 10. POI处理多Sheet核心逻辑
try (Workbook workbook = WorkbookFactory.create(new ByteArrayInputStream(templateBytes));
ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
// 校验模板是否有有效 sheet
if (workbook.getNumberOfSheets() == 0) {
throw new ServiceException("模板文件中无任何sheet页请检查模板");
}
// 6.1 预处理班组信息获取班组ID + 班组名称映射)
List<Long> teamIds = userList.stream()
.map(SubConstructionUser::getTeamId)
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());
Map<Long, String> teamNameMap = new HashMap<>();
if (!teamIds.isEmpty()) {
List<BusProjectTeam> teams = projectTeamService.lambdaQuery()
.in(BusProjectTeam::getId, teamIds)
.list();
teamNameMap = teams.stream()
.collect(Collectors.toMap(
BusProjectTeam::getId,
BusProjectTeam::getTeamName,
(oldVal, newVal) -> newVal // 避免重复ID冲突
));
}
int originalSheetIndex = 0;
// 6.2 克隆模板:为每个班组生成 sheet(关键修正)
// 10.1 为每个班组创建sheet
for (Long teamId : teamIds) {
// ① 克隆原始模板 sheet返回克隆后的 Sheet 对象)
Sheet newSheet = workbook.cloneSheet(0);
// ② 生成班组名称(避免空名称)
Sheet newSheet = workbook.cloneSheet(originalSheetIndex);
String teamName = teamNameMap.getOrDefault(teamId, "未知班组_" + teamId);
// ③ 给新 sheet 命名(通过 sheet 对象获取索引)
int newSheetIndex = workbook.getSheetIndex(newSheet);
workbook.setSheetName(newSheetIndex, teamName);
// ④ 存入映射,方便后续填充
sheetMap.put(teamName, newSheet);
}
// 6.3 克隆模板:处理无班组数据(如果需要
boolean needNoTeamSheet = dto.getTeamId() == null;
// 10.2 处理无班组数据(使用-1对应的用户列表
boolean needNoTeamSheet = dto.getTeamId() == null && teamUsersMap.containsKey(-1L);
if (needNoTeamSheet) {
Sheet noTeamSheet = workbook.cloneSheet(0);
String noTeamName = "无班组";
Sheet noTeamSheet = workbook.cloneSheet(originalSheetIndex);
int noTeamSheetIndex = workbook.getSheetIndex(noTeamSheet);
workbook.setSheetName(noTeamSheetIndex, noTeamName);
sheetMap.put(noTeamName, noTeamSheet);
workbook.setSheetName(noTeamSheetIndex, "无班组");
}
// 6.4 删除原始模板 sheet(避免最终文件保留空模板)
workbook.removeSheetAt(0);
// 10.3 移除原始模板sheet
workbook.removeSheetAt(originalSheetIndex);
// 6.5 将 POI 处理后的 workbook 写入字节数组,供 EasyExcel 使用
// 10.4 写入并关闭workbook
workbook.write(bos);
workbook.close();
byte[] workbookBytes = bos.toByteArray();
// 7. EasyExcel 填充数据(按 sheet 映射顺序填充)
// 11. EasyExcel填充数据
try (InputStream workbookStream = new ByteArrayInputStream(workbookBytes);
ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
.withTemplate(workbookStream)
.build()) {
// 7.1 填充“班组”sheet 数据
for (Map.Entry<String, Sheet> entry : sheetMap.entrySet()) {
String sheetName = entry.getKey();
// 跳过“无班组”sheet后续单独处理
if ("无班组".equals(sheetName)) {
continue;
}
// 根据 sheet 名称反查班组ID用于过滤数据
Long teamId = teamNameMap.entrySet().stream()
.filter(e -> sheetName.equals(e.getValue()))
.map(Map.Entry::getKey)
.findFirst()
.orElse(null);
// 创建 EasyExcel 的 WriteSheet通过名称匹配 sheet
WriteSheet writeSheet = EasyExcel.writerSheet(sheetName).build();
FillConfig fillConfig = FillConfig.builder()
.forceNewRow(true) // 强制新增行,不覆盖模板内容
.build();
// 填充列表数据和汇总数据
excelWriter.fill(getTeamData(userList, map, teamId), fillConfig, writeSheet);
excelWriter.fill(getTeamSummary(project, teamNameMap.get(teamId), yearMonth), writeSheet);
}
// 7.2 填充“无班组”sheet 数据
if (needNoTeamSheet) {
WriteSheet noTeamSheet = EasyExcel.writerSheet("无班组").build();
FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build();
excelWriter.fill(getTeamData(userList, map, null), fillConfig, noTeamSheet);
// 11.1 填充各班组数据
for (Long teamId : teamIds) {
String teamName = teamNameMap.getOrDefault(teamId, "未知班组_" + teamId);
WriteSheet writeSheet = EasyExcel.writerSheet(teamName).build();
// 使用提前分组好的数据
excelWriter.fill(getTeamData(teamUsersMap.get(teamId), salaryMap, teamId), fillConfig, writeSheet);
excelWriter.fill(getTeamSummary(project, teamName, yearMonth), writeSheet);
}
// 11.2 填充无班组数据
if (needNoTeamSheet) {
WriteSheet noTeamSheet = EasyExcel.writerSheet("无班组").build();
excelWriter.fill(getTeamData(teamUsersMap.get(-1L), salaryMap, null), fillConfig, noTeamSheet);
excelWriter.fill(getTeamSummary(project, null, yearMonth), noTeamSheet);
}
}
}
}
/**
* 设置响应头信息
*/
@ -497,15 +514,15 @@ public class SubUserSalaryDetailServiceImpl extends ServiceImpl<SubUserSalaryDet
private List<SubConstructionUserSalaryVo> getTeamData(List<SubConstructionUser> rows,
Map<Long, SubUserSalaryDetail> map,Long teamId){
List<SubConstructionUser> list1 ;
if(teamId == null){
list1 = rows.stream().filter(row -> row.getTeamId() == null && Arrays.asList("1","2").contains(row.getExitStatus())).toList();
}else {
list1 = rows.stream().filter(row -> teamId.equals(row.getTeamId())).toList();
}
// List<SubConstructionUser> list1 ;
// if(teamId == null){
// list1 = rows.stream().filter(row -> row.getTeamId() == null && Arrays.asList("1","2").contains(row.getExitStatus())).toList();
// }else {
// list1 = rows.stream().filter(row -> teamId.equals(row.getTeamId())).toList();
// }
ArrayList<SubConstructionUserSalaryVo> vos = new ArrayList<>();
int i =1;
for (SubConstructionUser row : list1) {
for (SubConstructionUser row : rows) {
SubConstructionUserSalaryVo vo = new SubConstructionUserSalaryVo();
BeanUtil.copyProperties(row,vo);
vo.setOrder(i);

View File

@ -0,0 +1,70 @@
package org.dromara.cory.controller.app;
import cn.dev33.satoken.annotation.SaCheckPermission;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
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.cory.domain.bo.BusContactnoticeBo;
import org.dromara.cory.domain.dto.BusContactnoticeAppDto;
import org.dromara.cory.domain.vo.BusContactnoticeVo;
import org.dromara.cory.service.IBusContactnoticeService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* APP联系单
*
* @author Lion Li
* @date 2025-07-03
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/app/cory/contactnotice")
public class BusContactnoticeAppController extends BaseController {
private final IBusContactnoticeService busContactnoticeService;
/**
* 查询联系单列表
*/
@GetMapping("/list")
public TableDataInfo<BusContactnoticeVo> list(BusContactnoticeAppDto dto, PageQuery pageQuery) {
return busContactnoticeService.queryAppPageList(dto, pageQuery);
}
/**
* 获取联系单详细信息
*
* @param id 主键
*/
@GetMapping("/{id}")
public R<BusContactnoticeVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(busContactnoticeService.queryById(id));
}
/**
* 新增联系单
*/
@Log(title = "联系单", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<BusContactnoticeVo> add(@Validated(AddGroup.class) @RequestBody BusContactnoticeBo bo) {
return R.ok(busContactnoticeService.insertByBo(bo));
}
}

View File

@ -0,0 +1,39 @@
package org.dromara.cory.domain.dto;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.core.validate.QueryGroup;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.cory.domain.BusContactnotice;
import java.util.List;
/**
* 联系单业务对象 bus_contactnotice
*
* @author Lion Li
* @date 2025-07-03
*/
@Data
public class BusContactnoticeAppDto extends BaseEntity {
/**
* 项目ID
*/
private Long projectId;
/**
* 模板类型
*/
private Long type;
/**
* 查询参数
*/
private String queryParam;
}

View File

@ -3,6 +3,7 @@ package org.dromara.cory.service;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.cory.domain.bo.BusContactnoticeBo;
import org.dromara.cory.domain.dto.BusContactnoticeAppDto;
import org.dromara.cory.domain.vo.BusContactnoticeVo;
import java.util.Collection;
@ -65,4 +66,9 @@ public interface IBusContactnoticeService {
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* app列表
*/
TableDataInfo<BusContactnoticeVo> queryAppPageList(BusContactnoticeAppDto dto, PageQuery pageQuery);
}

View File

@ -1,7 +1,9 @@
package org.dromara.cory.service.impl;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.stream.StreamUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -19,12 +21,14 @@ import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.cory.domain.BusContactnotice;
import org.dromara.cory.domain.bo.BusContactnoticeBo;
import org.dromara.cory.domain.dto.BusContactnoticeAppDto;
import org.dromara.cory.domain.vo.BusContactnoticeVo;
import org.dromara.cory.mapper.BusContactnoticeMapper;
import org.dromara.cory.service.IBusContactnoticeService;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import java.util.Collection;
import java.util.Collections;
@ -158,6 +162,28 @@ public class BusContactnoticeServiceImpl implements IBusContactnoticeService {
return baseMapper.deleteByIds(ids) > 0;
}
@Override
public TableDataInfo<BusContactnoticeVo> queryAppPageList(BusContactnoticeAppDto dto, PageQuery pageQuery) {
LambdaQueryWrapper<BusContactnotice> lqw = Wrappers.lambdaQuery();
lqw.eq(BusContactnotice::getProjectId, dto.getProjectId());
lqw.eq(BusContactnotice::getType, dto.getType());
// 处理查询参数(避免空值)
String queryParam = dto.getQueryParam();
if (StrUtil.isNotBlank(queryParam)) {
// 使用JSON函数+参数绑定避免SQL注入
lqw.and(wrapper -> wrapper
// 对volumeNumber进行模糊查询
.apply("detail->>'$.volumeNumber' LIKE CONCAT('%', {0}, '%')", queryParam)
// 或对volumeName进行模糊查询
.or()
.apply("detail->>'$.volumeName' LIKE CONCAT('%', {0}, '%')", queryParam)
);
}
Page<BusContactnoticeVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等)
* 正常使用只需#processEvent.flowCode=='leave1'

View File

@ -0,0 +1,143 @@
package org.dromara.design.controller.app;
import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
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.enums.BusinessStatusEnum;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
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.design.domain.DesVolumeFile;
import org.dromara.design.domain.dto.designchange.DesDesignChangeCreateReq;
import org.dromara.design.domain.dto.designchange.DesDesignChangeQueryReq;
import org.dromara.design.domain.dto.designchange.DesDesignChangeUpdateReq;
import org.dromara.design.domain.vo.designchange.DesDesignChangeVo;
import org.dromara.design.domain.vo.volumecatalog.DesVolumeCatalogVo;
import org.dromara.design.service.IDesDesignChangeService;
import org.dromara.design.service.IDesVolumeCatalogService;
import org.dromara.design.service.IDesVolumeFileService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 设计变更管理
*
* @author lilemy
* @date 2025-07-03
*/
@Validated
@RestController
@RequestMapping("/app/design/designChange")
public class DesDesignChangeAppController extends BaseController {
@Resource
private IDesDesignChangeService desDesignChangeService;
@Resource
private IDesVolumeCatalogService desVolumeCatalogService;
@Resource
private IDesVolumeFileService desVolumeFileService;
/**
* 查询设计变更管理列表
*/
@SaCheckPermission("design:designChange:list")
@GetMapping("/list")
public TableDataInfo<DesDesignChangeVo> list(DesDesignChangeQueryReq req, PageQuery pageQuery) {
return desDesignChangeService.queryPageList(req, pageQuery);
}
/**
* 根据主键导出设计变更单
*/
@SaCheckPermission("design:designChange:exportWord")
@Log(title = "设计变更管理", businessType = BusinessType.EXPORT)
@PostMapping("/export/word")
public void exportWordById(@NotNull(message = "主键不能为空") Long id,
HttpServletResponse response) {
desDesignChangeService.exportWordById(id, response);
}
/**
* 获取设计变更管理详细信息
*
* @param id 主键
*/
@SaCheckPermission("design:designChange:query")
@GetMapping("/{id}")
public R<DesDesignChangeVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable Long id) {
return R.ok(desDesignChangeService.queryById(id));
}
/**
* 新增设计变更管理
*/
@SaCheckPermission("design:designChange:add")
@Log(title = "设计变更管理", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping()
public R<DesDesignChangeVo> add(@Validated(AddGroup.class) @RequestBody DesDesignChangeCreateReq req) {
return R.ok(desDesignChangeService.insertByBo(req));
}
/**
* 修改设计变更管理
*/
@SaCheckPermission("design:designChange:edit")
@Log(title = "设计变更管理", businessType = BusinessType.UPDATE)
@RepeatSubmit()
@PutMapping()
public R<DesDesignChangeVo> edit(@Validated(EditGroup.class) @RequestBody DesDesignChangeUpdateReq req) {
return R.ok(desDesignChangeService.updateByBo(req));
}
/**
* 删除设计变更管理
*
* @param ids 主键串
*/
@SaCheckPermission("design:designChange:remove")
@Log(title = "设计变更管理", businessType = BusinessType.DELETE)
@DeleteMapping("/{ids}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable Long[] ids) {
return toAjax(desDesignChangeService.deleteByIds(List.of(ids)));
}
/**
* 查询选择卷册目录
*/
@SaCheckPermission("design:designChange:catalogList")
@GetMapping("/catalogList/{projectId}")
public R<List<DesVolumeCatalogVo>> catalogList(@PathVariable("projectId") Long projectId) {
return R.ok(desVolumeCatalogService.catalogList(projectId));
}
/**
* 查询选择目录下的蓝图
*/
@SaCheckPermission("design:designChange:blueprint")
@GetMapping("/blueprint/{volumeCatalogId}")
public R<List<DesVolumeFile>> blueprint(@PathVariable("volumeCatalogId") Long volumeCatalogId) {
List<DesVolumeFile> list = desVolumeFileService.list(Wrappers.lambdaQuery(DesVolumeFile.class)
.eq(DesVolumeFile::getVolumeCatalogId, volumeCatalogId)
.eq(DesVolumeFile::getType, DesVolumeFile.BLUEPRINT)
.eq(DesVolumeFile::getAuditStatus, BusinessStatusEnum.FINISH.getStatus()));
return R.ok(list);
}
}

View File

@ -0,0 +1,51 @@
package org.dromara.design.controller.app;
import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaIgnore;
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.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.design.domain.bo.DesVolumeFileBo;
import org.dromara.design.domain.dto.volumefile.DesVolumeFileAppPageDto;
import org.dromara.design.domain.dto.volumefile.DesVolumeFileCreateReq;
import org.dromara.design.domain.vo.volumefile.DesVolumeFileAppVo;
import org.dromara.design.domain.vo.volumefile.DesVolumeFileCodeVo;
import org.dromara.design.domain.vo.volumefile.DesVolumeFileJoinVo;
import org.dromara.design.domain.vo.volumefile.DesVolumeFileVo;
import org.dromara.design.service.IDesVolumeFileService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* App图纸
*
* @author lilemy
* @date 2025-07-30
*/
@Validated
@RestController
@RequestMapping("/app/design/volumeFile")
public class DesVolumeFileAppController extends BaseController {
@Resource
private IDesVolumeFileService desVolumeFileService;
/**
* app图纸管理分页查询
*/
@GetMapping("/list")
public TableDataInfo<DesVolumeFileAppVo> list(DesVolumeFileAppPageDto dto, PageQuery pageQuery) {
return desVolumeFileService.queryAppPageList(dto, pageQuery);
}
}

View File

@ -0,0 +1,36 @@
package org.dromara.design.domain.dto.volumefile;
import io.github.linpeilie.annotations.AutoMapper;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;
import org.dromara.common.mybatis.core.domain.BaseEntity;
import org.dromara.design.domain.DesVolumeFile;
/**
* 卷册文件业务对象 des_volume_file
*
* @author lilemy
* @date 2025-08-19
*/
@Data
public class DesVolumeFileAppPageDto {
/**
* 项目ID
*/
private Long projectId;
/**
* 图纸类型(1-过程3-蓝图4-作废)
*/
private String type;
/**
* 查询参数
*/
private String queryParam;
}

View File

@ -0,0 +1,108 @@
package org.dromara.design.domain.vo.volumefile;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import org.dromara.common.translation.annotation.Translation;
import org.dromara.common.translation.constant.TransConstant;
import org.dromara.design.domain.DesVolumeFile;
import java.io.Serial;
import java.io.Serializable;
/**
* 卷册文件视图对象 des_volume_file
*
* @author lilemy
* @date 2025-07-30
*/
@Data
public class DesVolumeFileAppVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
private Long id;
/**
* 卷册目录ID
*/
private Long volumeCatalogId;
/**
* 卷册号
*/
private String volumeNumber;
/**
* 设计子项
*/
private String designSubitem;
/**
* 文件ID
*/
private Long fileId;
/**
* 文件名
*/
private String fileName;
/**
* 状态1正常 2变更
*/
private String status;
/**
* 专业
*/
private String specialty;
/**
* 专业
*/
@Translation(type = TransConstant.DICT_TYPE_TO_LABEL, mapper = "specialty",other = "des_user_major")
private String specialtyName;
/**
* 图纸类型(1-过程3-蓝图4-作废)
*/
private String type;
/**
* 版本号
*/
private String version;
/**
* 审核状态
*/
private String auditStatus;
/**
* 负责人
*/
private String principal;
/**
* 负责人
*/
@Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "principal")
private String principalName;
/**
* 路径
*/
private String url;
/**
* 资料名称
*/
private String documentName;
}

View File

@ -62,7 +62,7 @@ public class DesVolumeFileVo implements Serializable {
private String remark;
/**
* 图纸类型(1-过程,2-变更,3-蓝图4-作废)
* 图纸类型(1-过程3-蓝图4-作废)
*/
private String type;

View File

@ -5,6 +5,8 @@ import org.apache.ibatis.annotations.Param;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.design.domain.DesVolumeFile;
import org.dromara.design.domain.bo.DesVolumeFileBo;
import org.dromara.design.domain.dto.volumefile.DesVolumeFileAppPageDto;
import org.dromara.design.domain.vo.volumefile.DesVolumeFileAppVo;
import org.dromara.design.domain.vo.volumefile.DesVolumeFileJoinVo;
import org.dromara.design.domain.vo.volumefile.DesVolumeFileVo;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
@ -20,4 +22,7 @@ public interface DesVolumeFileMapper extends BaseMapperPlus<DesVolumeFile, DesVo
Page<DesVolumeFileJoinVo> queryJoinPageList(@Param("page")Page<DesVolumeFileJoinVo> page, @Param("bo")DesVolumeFileBo bo);
Page<DesVolumeFileAppVo> queryAppPageList(@Param("page")Page<DesVolumeFileJoinVo> page, @Param("dto") DesVolumeFileAppPageDto dto);
}

View File

@ -6,7 +6,9 @@ import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.design.domain.DesVolumeFile;
import org.dromara.design.domain.bo.DesVolumeFileBo;
import org.dromara.design.domain.dto.volumefile.DesVolumeFileAppPageDto;
import org.dromara.design.domain.dto.volumefile.DesVolumeFileCreateReq;
import org.dromara.design.domain.vo.volumefile.DesVolumeFileAppVo;
import org.dromara.design.domain.vo.volumefile.DesVolumeFileCodeVo;
import org.dromara.design.domain.vo.volumefile.DesVolumeFileJoinVo;
import org.dromara.design.domain.vo.volumefile.DesVolumeFileVo;
@ -93,4 +95,9 @@ public interface IDesVolumeFileService extends IService<DesVolumeFile> {
* 二维码获取卷册文件详细信息
*/
DesVolumeFileCodeVo getCodeInfo(Long id);
/**
* app分页查询
*/
TableDataInfo<DesVolumeFileAppVo> queryAppPageList(DesVolumeFileAppPageDto dto, PageQuery pageQuery);
}

View File

@ -27,8 +27,10 @@ import org.dromara.common.sse.utils.SseMessageUtils;
import org.dromara.design.domain.DesVolumeCatalog;
import org.dromara.design.domain.DesVolumeFile;
import org.dromara.design.domain.bo.DesVolumeFileBo;
import org.dromara.design.domain.dto.volumefile.DesVolumeFileAppPageDto;
import org.dromara.design.domain.dto.volumefile.DesVolumeFileCreateReq;
import org.dromara.design.domain.vo.BusDrawingreviewReceiptsVo;
import org.dromara.design.domain.vo.volumefile.DesVolumeFileAppVo;
import org.dromara.design.domain.vo.volumefile.DesVolumeFileCodeVo;
import org.dromara.design.domain.vo.volumefile.DesVolumeFileJoinVo;
import org.dromara.design.domain.vo.volumefile.DesVolumeFileVo;
@ -469,6 +471,12 @@ public class DesVolumeFileServiceImpl extends ServiceImpl<DesVolumeFileMapper, D
}
@Override
public TableDataInfo<DesVolumeFileAppVo> queryAppPageList(DesVolumeFileAppPageDto dto, PageQuery pageQuery) {
Page<DesVolumeFileAppVo> result = baseMapper.queryAppPageList(pageQuery.build(), dto);
return TableDataInfo.build(result);
}
/**
* 总体流程监听(例如: 草稿,撤销,退回,作废,终止,已完成,单任务完成等)
* 正常使用只需#processEvent.flowCode=='leave1'

View File

@ -50,7 +50,7 @@ public class BusAttendanceController extends BaseController {
/**
* 查询施工人员月份考勤列表
*/
@SaCheckPermission("project:attendance:list")
// @SaCheckPermission("project:attendance:list")
@GetMapping("/list/month/byUserId")
public R<List<BusAttendanceMonthByUserIdVo>> listAttendanceMonthListByUserId(BusAttendanceMonthByUserIdReq req) {
return R.ok(busAttendanceService.listAttendanceMonthListByUserId(req));

View File

@ -7,11 +7,13 @@ import lombok.Data;
import org.dromara.common.translation.annotation.Translation;
import org.dromara.common.translation.constant.TransConstant;
import org.dromara.quality.domain.QltQualityConstructionLog;
import org.dromara.system.domain.vo.SysOssVo;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDate;
import java.util.Date;
import java.util.List;
/**
@ -76,8 +78,7 @@ public class QltQualityConstructionLogVo implements Serializable {
/**
* 附件列表
*/
@Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "file")
private String fileList;
private List<SysOssVo> fileList;
/**
* 创建者

View File

@ -196,6 +196,13 @@ public class QltQualityConstructionLogServiceImpl extends ServiceImpl<QltQuality
if (qualityConstructionLog == null) {
return qualityConstructionLogVo;
}
// 关联附件信息
String file = qualityConstructionLog.getFile();
if (StringUtils.isNotBlank(file)) {
List<Long> ossIdList = Arrays.stream(file.split(",")).map(Long::parseLong).toList();
List<SysOssVo> ossVoList = ossService.listByIds(ossIdList);
qualityConstructionLogVo.setFileList(ossVoList);
}
BeanUtils.copyProperties(qualityConstructionLog, qualityConstructionLogVo);
return qualityConstructionLogVo;
}

View File

@ -17,4 +17,29 @@
</if>
</select>
<select id="queryAppPageList" resultType="org.dromara.design.domain.vo.volumefile.DesVolumeFileAppVo">
select f.id,
f.volume_catalog_id,
f.type,
f.status,
f.audit_status,
f.version,
f.file_id,
c.design_subitem,
c.specialty,
c.principal,
c.document_name,
c.volume_number,
o.url
from des_volume_file f
left join des_volume_catalog c on f.volume_catalog_id = c.design
left join sys_oss o on f.file_id = o.oss_id
where c.project_id = #{dto.projectId}
and f.type = #{dto.type}
<if test="dto.queryParam != null and dto.queryParam != '' ">
and (c.document_name like concat('%',#{dto.queryParam},'%') or c.volume_number like concat('%',#{dto.queryParam},'%'))
</if>
</select>
</mapper>