src/main/java/com/ruoyi/collaborativeApproval/service/MeetingService.java
@@ -14,6 +14,7 @@ import com.ruoyi.collaborativeApproval.vo.SearchMeetingDraftVo; import com.ruoyi.collaborativeApproval.vo.SearchMeetingRoomVo; import com.ruoyi.collaborativeApproval.vo.SearchMeetingUseVo; import com.ruoyi.approve.pojo.ApproveProcess; import com.ruoyi.framework.web.domain.R; @@ -71,4 +72,10 @@ List<MeetingSimpleDto> getMeetSummaryItems(); /** * 即将开始的会议提醒:已发布、开始前1小时内、且当前登录用户为参会人。 * 返回结构复用 ApproveProcess,直接并入首页待办事项。 */ List<ApproveProcess> getUpcomingMeetingReminders(); } src/main/java/com/ruoyi/collaborativeApproval/service/impl/MeetingServiceImpl.java
@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.github.xiaoymin.knife4j.core.util.StrUtil; import com.ruoyi.approve.pojo.ApproveProcess; import com.ruoyi.collaborativeApproval.dto.MeetSummaryDto; import com.ruoyi.collaborativeApproval.dto.MeetUseDto; import com.ruoyi.collaborativeApproval.dto.MeetingItem; @@ -27,7 +28,9 @@ import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.framework.web.domain.R; import com.ruoyi.project.system.domain.SysPost; import com.ruoyi.project.system.domain.SysUser; import com.ruoyi.project.system.mapper.SysPostMapper; import com.ruoyi.project.system.mapper.SysUserMapper; import com.ruoyi.project.system.service.ISysNoticeService; import com.ruoyi.staff.mapper.StaffOnJobMapper; @@ -54,6 +57,7 @@ private final MeetingMinutesMapper meetingMinutesMapper; private final SysUserMapper userMapper; private final SysPostMapper sysPostMapper; private final ISysNoticeService sysNoticeService; @@ -324,6 +328,114 @@ public List<MeetingSimpleDto> getMeetSummaryItems() { return meetApplicationMapper.getMeetSummaryItems(); } @Override public List<ApproveProcess> getUpcomingMeetingReminders() { List<ApproveProcess> reminders = new ArrayList<>(); LocalDateTime now = LocalDateTime.now(); List<MeetApplication> meetings = meetApplicationMapper.selectList( Wrappers.<MeetApplication>lambdaQuery() .eq(MeetApplication::getPublishStatus, 1) .gt(MeetApplication::getStartTime, now) .le(MeetApplication::getStartTime, now.plusHours(1)) .orderByAsc(MeetApplication::getStartTime)); if (meetings == null || meetings.isEmpty()) { return reminders; } Long currentUserId = SecurityUtils.getLoginUser().getUserId(); Map<Integer, SysPost> postCache = new HashMap<>(); for (MeetApplication meeting : meetings) { if (meeting.getStartTime() == null) { continue; } List<Long> staffIds = parseParticipantStaffIds(meeting.getParticipants()); if (staffIds.isEmpty()) { continue; } List<StaffOnJob> staffs = staffOnJobMapper.selectBatchIds(staffIds); Map<Long, StaffOnJob> staffMap = (staffs == null) ? new HashMap<>() : staffs.stream().collect(Collectors.toMap(StaffOnJob::getId, s -> s, (a, b) -> a)); boolean isParticipant = false; List<String> participantNames = new ArrayList<>(); for (Long staffId : staffIds) { StaffOnJob staff = staffMap.get(staffId); if (staff == null) { continue; } String display = staff.getStaffName() == null ? "" : staff.getStaffName(); if (staff.getSysPostId() != null) { SysPost post = postCache.get(staff.getSysPostId()); if (post == null) { post = sysPostMapper.selectPostById(staff.getSysPostId().longValue()); if (post != null) { postCache.put(staff.getSysPostId(), post); } } if (post != null && post.getPostName() != null && !post.getPostName().isEmpty()) { display = display + " (" + post.getPostName() + ")"; } } if (!display.isEmpty()) { participantNames.add(display); } if (!isParticipant && staff.getStaffNo() != null) { SysUser user = userMapper.selectOne( Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUserName, staff.getStaffNo())); if (user != null && currentUserId.equals(user.getUserId())) { isParticipant = true; } } } if (!isParticipant) { continue; } String roomName = "会议"; if (meeting.getRoomId() != null) { MeetingRoom room = meetingRoomMapper.selectById(meeting.getRoomId()); if (room != null && room.getName() != null && !room.getName().isEmpty()) { roomName = room.getName(); } } ApproveProcess ap = new ApproveProcess(); ap.setId(100000000L + meeting.getId()); ap.setApproveId("会议提醒"); ap.setApproveDeptName(roomName); String reason = "会议《" + meeting.getTitle() + "》将于 " + meeting.getStartTime().format(DateTimeFormatter.ofPattern("HH:mm")) + " 开始"; if (!participantNames.isEmpty()) { reason += ";参会人员:" + String.join("、", participantNames); } ap.setApproveReason(reason); ap.setApproveUserName(meeting.getApplicant()); ap.setApproveTime(java.sql.Timestamp.valueOf(meeting.getStartTime())); ap.setApproveTypeName("会议提醒"); reminders.add(ap); } return reminders; } private List<Long> parseParticipantStaffIds(String participants) { List<Long> ids = new ArrayList<>(); if (participants == null || participants.trim().isEmpty()) { return ids; } String cleanStr = participants.replaceAll("^\\[|\\]$", "").trim(); if (cleanStr.isEmpty()) { return ids; } for (String s : cleanStr.split(",")) { String val = s.trim(); if (val.isEmpty()) { continue; } try { ids.add(Long.valueOf(val)); } catch (NumberFormatException ignored) { } } return ids; } } src/main/java/com/ruoyi/customervisits/pojo/CustomerVisits.java
@@ -5,8 +5,10 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.format.annotation.DateTimeFormat; import java.math.BigDecimal; @@ -20,6 +22,8 @@ @TableName("customer_visits") @Data @Builder @NoArgsConstructor @AllArgsConstructor @Schema public class CustomerVisits { src/main/java/com/ruoyi/device/service/impl/DeviceAreaServiceImpl.java
@@ -17,6 +17,7 @@ import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -51,8 +52,9 @@ .collect(Collectors.toMap(DeviceArea::getId, a -> a)); // 递归汇总每个节点的设备数量(含所有子级) Map<Long, Long> countMap = directCountMap.entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); // 必须从空 map 开始:每个区域的自身直挂数只在 accumulate 中累加一次, // 否则会与“初始即含自身直挂数”叠加,导致每个区域自身设备数被计两次(双倍) Map<Long, Long> countMap = new HashMap<>(); for (DeviceArea area : all) { accumulate(area.getId(), directCountMap.getOrDefault(area.getId(), 0L), countMap, areaMap); } src/main/java/com/ruoyi/device/service/impl/DeviceRepairServiceImpl.java
@@ -64,7 +64,13 @@ @Override @Transactional(rollbackFor = Exception.class) public AjaxResult saveDeviceRepair(DeviceRepairDto deviceRepairDto) { if (deviceRepairDto.getDeviceLedgerId() == null) { return AjaxResult.error("请选择设备"); } DeviceLedger byId = deviceLedgerService.getById(deviceRepairDto.getDeviceLedgerId()); if (byId == null) { return AjaxResult.error("所选设备不存在"); } deviceRepairDto.setDeviceName(byId.getDeviceName()); deviceRepairDto.setDeviceModel(byId.getDeviceModel()); if (deviceRepairDto.getStatus() == null) { src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
@@ -31,6 +31,7 @@ import com.ruoyi.basic.pojo.SupplierManage; import com.ruoyi.collaborativeApproval.mapper.NoticeMapper; import com.ruoyi.collaborativeApproval.pojo.Notice; import com.ruoyi.collaborativeApproval.service.MeetingService; import com.ruoyi.common.enums.ApproveTypeEnum; import com.ruoyi.common.enums.TypeEnums; import com.ruoyi.common.utils.SecurityUtils; @@ -116,6 +117,8 @@ private final ProductMapper productMapper; private final StaffOnJobMapper staffOnJobMapper; private final MeetingService meetingService; private final CustomerMapper customerMapper; @@ -446,6 +449,16 @@ } } // 会议提醒:已发布、开始前1小时内、当前用户为参会人(失败不影响待办其它数据) try { List<ApproveProcess> meetingReminders = meetingService.getUpcomingMeetingReminders(); if (!CollectionUtils.isEmpty(meetingReminders)) { approveProcesses.addAll(meetingReminders); } } catch (Exception e) { log.warn("加载会议提醒失败: {}", e.getMessage()); } return approveProcesses; } src/main/java/com/ruoyi/measuringinstrumentledger/controller/MeasuringInstrumentLedgerController.java
@@ -109,6 +109,12 @@ return update ? AjaxResult.success("检定成功") : AjaxResult.error("检定失败"); } @GetMapping("/options") @Operation(summary = "计量器具台账-下拉列表") public AjaxResult options() { return AjaxResult.success(measuringInstrumentLedgerService.listOptions()); } @PostMapping("/downloadTemplate") @Operation(summary = "下载计量器具台账导入模板") public void downloadTemplate(HttpServletResponse response) { src/main/java/com/ruoyi/measuringinstrumentledger/mapper/MeasuringInstrumentLedgerMapper.java
@@ -27,4 +27,12 @@ List<MeasuringInstrumentLedger> listPage(@Param("req") MeasuringInstrumentLedger measuringInstrumentLedger); List<String> selectExistingCodes(@Param("tenantId") Long tenantId, @Param("codes") Collection<String> codes); /** * 下拉:当前租户全部计量器具(用于校准/检定选择,豁免数据范围过滤) * * @param tenantId 租户ID * @return 计量器具列表 */ List<MeasuringInstrumentLedger> listOptions(@Param("tenantId") Long tenantId); } src/main/java/com/ruoyi/measuringinstrumentledger/service/MeasuringInstrumentLedgerService.java
@@ -10,6 +10,7 @@ import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; /** * @author :yys @@ -47,4 +48,11 @@ * @return */ boolean add(MeasuringInstrumentLedger measuringInstrumentLedger) throws IOException; /** * 下拉:当前租户全部计量器具(用于校准/检定选择) * * @return 计量器具列表 */ List<MeasuringInstrumentLedger> listOptions(); } src/main/java/com/ruoyi/measuringinstrumentledger/service/impl/MeasuringInstrumentLedgerServiceImpl.java
@@ -76,7 +76,8 @@ if(measuringInstrumentLedger == null) { return false; } SysUser sysUser = sysUserMapper.selectUserById(measuringInstrumentLedger.getUserId()); Long nameUserId = measuringInstrumentLedger.getUserId() != null ? measuringInstrumentLedger.getUserId() : req.getUserId(); SysUser sysUser = nameUserId == null ? null : sysUserMapper.selectUserById(nameUserId); measuringInstrumentLedger.setValid(req.getValid()); measuringInstrumentLedger.setMostDate(req.getRecordDate()); measuringInstrumentLedger.setNextDate(new Date(req.getRecordDate().getTime() + 1000L * 60 * 60 * 24 * req.getValid())); @@ -87,7 +88,7 @@ measuringInstrumentLedgerRecord.setEntryDate(req.getEntryDate()); measuringInstrumentLedgerRecord.setValid(req.getValid()); measuringInstrumentLedgerRecord.setUserId(req.getUserId()); measuringInstrumentLedgerRecord.setUserName(sysUser.getUserName()); measuringInstrumentLedgerRecord.setUserName(sysUser == null ? null : sysUser.getUserName()); measuringInstrumentLedgerRecordMapper.insert(measuringInstrumentLedgerRecord); // 台账绑定一次 // if(!CollectionUtils.isEmpty(req.getTempFileIds())){ @@ -200,4 +201,10 @@ return true; } @Override public List<MeasuringInstrumentLedger> listOptions() { Long tenantId = SecurityUtils.getLoginUser().getTenantId(); return measuringInstrumentLedgerMapper.listOptions(tenantId); } } src/main/java/com/ruoyi/project/system/controller/SysDeptController.java
@@ -131,4 +131,15 @@ deptService.checkDeptDataScope(deptId); return toAjax(deptService.deleteDeptById(deptId)); } /** * 修改部门排序(批量) */ @PreAuthorize("@ss.hasPermi('system:dept:edit')") @Log(title = "部门管理", businessType = BusinessType.UPDATE) @PutMapping("/sort") public AjaxResult updateSort(@RequestBody List<SysDept> depts) { return toAjax(deptService.updateDeptSort(depts)); } } src/main/java/com/ruoyi/project/system/mapper/SysDeptMapper.java
@@ -110,7 +110,15 @@ * @param depts 子元素 * @return 结果 */ public int updateDeptChildren(@Param("depts") List<SysDept> depts); public int updateDeptChildren(@Param("depts") List<SysDept> depts); /** * 批量修改部门排序 * * @param depts 部门列表(deptId + orderNum) * @return 结果 */ public int updateDeptSort(@Param("depts") List<SysDept> depts); /** * 删除部门管理信息 src/main/java/com/ruoyi/project/system/service/ISysDeptService.java
@@ -128,4 +128,12 @@ * @return */ Long maxLevelDeptId(Long deptId); /** * 批量修改部门排序 * * @param depts 部门列表(deptId + orderNum) * @return 结果 */ public int updateDeptSort(List<SysDept> depts); } src/main/java/com/ruoyi/project/system/service/impl/SysDeptServiceImpl.java
@@ -249,6 +249,22 @@ } /** * 批量修改部门排序 * * @param depts 部门列表(deptId + orderNum) * @return 结果 */ @Override public int updateDeptSort(List<SysDept> depts) { if (depts == null || depts.isEmpty()) { return 0; } return deptMapper.updateDeptSort(depts); } /** * 修改该部门的父级部门状态 * * @param dept 当前部门 src/main/java/com/ruoyi/purchase/dto/ProcurementBusinessSummaryDto.java
@@ -93,4 +93,14 @@ */ @Excel(name = "退货金额") private BigDecimal returnAmount; /** * 排序字段(白名单:entryDate) */ private String orderByColumn; /** * 排序方向:asc / desc */ private String isAsc; } src/main/resources/mapper/measuringinstrumentledger/MeasuringInstrumentLedgerMapper.xml
@@ -74,4 +74,12 @@ #{code} </foreach> </select> <!-- 下拉选择:当前租户全部计量器具。SQL 带 /*data_scope*/ 标记,仅此查询豁免数据范围过滤 --> <select id="listOptions" resultType="com.ruoyi.measuringinstrumentledger.pojo.MeasuringInstrumentLedger"> SELECT /*data_scope*/ id, code, name, model, unit, most_date, valid, record_date FROM measuring_instrument_ledger WHERE tenant_id = #{tenantId} ORDER BY create_time DESC </select> </mapper> src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
@@ -241,7 +241,19 @@ AND slp.product_category = #{req.productCategory} </if> GROUP BY slp.product_category, slp.specification_model, sl.supplier_name ORDER BY slp.product_category <!-- 排序:支持按录入日期(聚合列)排序,白名单防止注入;默认按产品大类 --> <choose> <when test="req.orderByColumn == 'entryDate'"> ORDER BY MAX(sl.entry_date) <choose> <when test="req.isAsc == 'asc'">ASC</when> <otherwise>DESC</otherwise> </choose> </when> <otherwise> ORDER BY slp.product_category ASC </otherwise> </choose> </select> <select id="selectProductBomStructure" resultType="com.ruoyi.sales.dto.LossProductModelDto"> select src/main/resources/mapper/stock/StockInventoryMapper.xml
@@ -222,7 +222,7 @@ unit, product_name, product_id order by combined.create_time desc order by create_time desc </select> <select id="listStockInventoryExportData" resultType="com.ruoyi.stock.execl.StockInventoryExportData"> src/main/resources/mapper/system/SysDeptMapper.xml
@@ -155,6 +155,19 @@ </foreach> </update> <update id="updateDeptSort" parameterType="java.util.List"> update sys_dept set order_num = <foreach collection="depts" item="item" index="index" separator=" " open="case dept_id" close="end"> when #{item.deptId} then #{item.orderNum} </foreach> where dept_id in <foreach collection="depts" item="item" index="index" separator="," open="(" close=")"> #{item.deptId} </foreach> </update> <update id="updateDeptStatusNormal" parameterType="Long"> update sys_dept set status = '0' where dept_id in <foreach collection="array" item="deptId" open="(" separator="," close=")">