yuan
2026-07-13 bb078cde6d9641ec84ee3c52b544153845795c0e
Merge remote-tracking branch 'origin/dev_New_pro' into dev_pro_山西长治
已添加1个文件
已修改10个文件
211 ■■■■ 文件已修改
src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/controller/PersonalAttendanceLocationConfigController.java 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/controller/PersonalShiftController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/init/DataInitializer.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/mapper/PersonalShiftMapper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/pojo/PersonalAttendanceLocationConfig.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/service/PersonalAttendanceLocationConfigService.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/service/impl/PersonalAttendanceLocationConfigServiceImpl.java 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/service/impl/PersonalAttendanceRecordsServiceImpl.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/staff/PersonalAttendanceRecordsMapper.xml 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/staff/PersonalShiftMapper.xml 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/impl/CustomerServiceImpl.java
@@ -310,18 +310,26 @@
    @Override
    public List<Map<String, Object>> customerList(Customer customer) {
        LambdaQueryWrapper<Customer> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.select(Customer::getId, Customer::getCustomerName, Customer::getTaxpayerIdentificationNumber);
        LoginUser loginUser = SecurityUtils.getLoginUser();
        Long loginUserId = loginUser.getUserId();
        CustomerDto query = new CustomerDto();
        if (customer != null) {
            BeanUtils.copyProperties(customer, query);
        }
        // èŽ·å–åŽŸå§‹æŸ¥è¯¢ç»“æžœ
        List<Map<String, Object>> result = customerMapper.selectMaps(queryWrapper);
        // å¤ç”¨å®¢æˆ·åˆ—表的可见性规则,避免把别人的私海客户暴露给当前账号
        List<CustomerVo> visibleCustomers = customerMapper.list(query, loginUserId);
        if (CollectionUtils.isEmpty(visibleCustomers)) {
            return Collections.emptyList();
        }
        // å°†ä¸‹åˆ’线命名转换为驼峰命名
        return result.stream().map(map -> map.entrySet().stream()
                .collect(Collectors.toMap(
                        entry -> underlineToCamel(entry.getKey()),
                        Map.Entry::getValue))
        ).collect(Collectors.toList());
        return visibleCustomers.stream().map(item -> {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("id", item.getId());
            map.put("customerName", item.getCustomerName());
            map.put("taxpayerIdentificationNumber", item.getTaxpayerIdentificationNumber());
            return map;
        }).collect(Collectors.toList());
    }
    // åˆ†é…å…¬æµ·å®¢æˆ·ç»™ç§æµ·
src/main/java/com/ruoyi/staff/controller/PersonalAttendanceLocationConfigController.java
@@ -1,6 +1,8 @@
package com.ruoyi.staff.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.staff.pojo.PersonalAttendanceLocationConfig;
@@ -31,8 +33,10 @@
    @Operation(summary = "新增/修改人员打卡规则配置")
    @PostMapping("/add")
    public R add(@RequestBody PersonalAttendanceLocationConfig personalAttendanceLocationConfig){
        if (personalAttendanceLocationConfig.getId() != null
                && !personalAttendanceLocationConfigService.canEdit(personalAttendanceLocationConfig.getId())) {
            return R.fail("该班次配置已被排班并产生打卡记录,不能编辑");
        }
        // ç­æ¬¡éœ€è¦ä¸èƒ½å¤Ÿé‡å¤
        if (personalAttendanceLocationConfig.getId() == null && personalAttendanceLocationConfigService.lambdaQuery().eq(PersonalAttendanceLocationConfig::getShift, personalAttendanceLocationConfig.getShift()).one() != null) {
            return R.fail("班次不能重复");
@@ -42,15 +46,35 @@
    @Operation(summary = "分页查询人员打卡规则配置")
    @GetMapping("/listPage")
    public R listPage(Page page){
    public R listPage(Page page, PersonalAttendanceLocationConfig query){
        page.addOrder(OrderItem.desc("id"));
        return R.ok(personalAttendanceLocationConfigService.page(page));
        LambdaQueryWrapper<PersonalAttendanceLocationConfig> wrapper = new LambdaQueryWrapper<PersonalAttendanceLocationConfig>()
                .ne(PersonalAttendanceLocationConfig::getId, 999);
        if (query.getSysDeptId() != null) {
            wrapper.eq(PersonalAttendanceLocationConfig::getSysDeptId, query.getSysDeptId());
        }
        if (query.getShift() != null && !query.getShift().isEmpty()) {
            wrapper.eq(PersonalAttendanceLocationConfig::getShift, query.getShift());
        }
        IPage<PersonalAttendanceLocationConfig> result = personalAttendanceLocationConfigService.page(page, wrapper);
        result.getRecords().forEach(item -> {
            boolean locked = personalAttendanceLocationConfigService.hasAttendanceUsage(item.getId());
            item.setUsageLocked(locked);
            item.setCanEdit(!locked);
            item.setCanDelete(!locked);
        });
        return R.ok(result);
    }
    @Operation(summary = "删除人员打卡规则配置")
    @DeleteMapping("/del")
    public R del(@RequestBody List<Integer> ids) {
        for (Integer id : ids) {
            if (!personalAttendanceLocationConfigService.canDelete(id)) {
                return R.fail("存在已排班且已有打卡记录的班次配置,不能删除");
            }
        }
        return R.ok(personalAttendanceLocationConfigService.removeBatchByIds(ids));
    }
src/main/java/com/ruoyi/staff/controller/PersonalShiftController.java
@@ -60,7 +60,7 @@
    }
    @Operation(summary = "班次状态修改")
    @PostMapping("update")
    @PostMapping("/update")
    public R performanceShiftUpdate(@RequestBody PersonalShift personalShift) {
        personalShiftService.performanceShiftUpdate(personalShift);
        return R.ok();
src/main/java/com/ruoyi/staff/init/DataInitializer.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,33 @@
package com.ruoyi.staff.init;
import com.ruoyi.staff.mapper.PersonalAttendanceLocationConfigMapper;
import com.ruoyi.staff.pojo.PersonalAttendanceLocationConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@Slf4j
@Component
@RequiredArgsConstructor
public class DataInitializer implements ApplicationRunner {
    private final PersonalAttendanceLocationConfigMapper configMapper;
    @Override
    public void run(ApplicationArguments args) {
        initLeaveConfig();
    }
    private void initLeaveConfig() {
        PersonalAttendanceLocationConfig config = configMapper.selectById(999);
        if (config == null) {
            config = new PersonalAttendanceLocationConfig();
            config.setId(999);
            config.setShift("请假");
            configMapper.insert(config);
            log.info("已初始化请假班次配置(id=999)");
        }
    }
}
src/main/java/com/ruoyi/staff/mapper/PersonalShiftMapper.java
@@ -31,4 +31,6 @@
    List<Map<String, Object>> performanceShiftYearList(@Param("time") String time, @Param("userName") String userName, @Param("sysDeptId") Integer sysDeptId);
    List<PerformanceShiftMapDto> performanceShiftList(@Param("time") String time, @Param("userName") String userName, @Param("sysDeptId") Integer sysDeptId);
    boolean existsAttendanceUsedByConfig(@Param("configId") Integer configId);
}
src/main/java/com/ruoyi/staff/pojo/PersonalAttendanceLocationConfig.java
@@ -61,6 +61,28 @@
    @Schema(description = "班次")
    private String shift;
    /**
     * æ˜¯å¦å·²è¢«æŽ’班且已有打卡记录使用
     */
    @Schema(description = "是否已被排班且已有打卡记录使用")
    @TableField(exist = false)
    private Boolean usageLocked;
    /**
     * æ˜¯å¦å¯ç¼–辑
     */
    @Schema(description = "是否可编辑")
    @TableField(exist = false)
    private Boolean canEdit;
    /**
     * æ˜¯å¦å¯åˆ é™¤
     */
    @Schema(description = "是否可删除")
    @TableField(exist = false)
    private Boolean canDelete;
    @Schema(description = "创建用户")
    @TableField(fill = FieldFill.INSERT)
    private Integer createUser;
src/main/java/com/ruoyi/staff/service/PersonalAttendanceLocationConfigService.java
@@ -13,4 +13,19 @@
 */
public interface PersonalAttendanceLocationConfigService extends IService<PersonalAttendanceLocationConfig> {
    /**
     * åˆ¤æ–­ç­æ¬¡é…ç½®æ˜¯å¦å·²è¢«æŽ’班且已有打卡记录使用。
     */
    boolean hasAttendanceUsage(Integer configId);
    /**
     * åˆ¤æ–­ç­æ¬¡é…ç½®æ˜¯å¦å…è®¸ç¼–辑。
     */
    boolean canEdit(Integer configId);
    /**
     * åˆ¤æ–­ç­æ¬¡é…ç½®æ˜¯å¦å…è®¸åˆ é™¤ã€‚
     */
    boolean canDelete(Integer configId);
}
src/main/java/com/ruoyi/staff/service/impl/PersonalAttendanceLocationConfigServiceImpl.java
@@ -1,15 +1,12 @@
package com.ruoyi.staff.service.impl;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.staff.pojo.PersonalAttendanceLocationConfig;
import com.ruoyi.staff.mapper.PersonalAttendanceLocationConfigMapper;
import com.ruoyi.staff.service.PersonalAttendanceLocationConfigService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import com.ruoyi.staff.mapper.PersonalAttendanceLocationConfigMapper;
import com.ruoyi.staff.mapper.PersonalShiftMapper;
import com.ruoyi.staff.pojo.PersonalAttendanceLocationConfig;
import com.ruoyi.staff.service.PersonalAttendanceLocationConfigService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
/**
 * <p>
@@ -20,6 +17,26 @@
 * @since 2026-02-11 09:41:34
 */
@Service
@RequiredArgsConstructor
public class PersonalAttendanceLocationConfigServiceImpl extends ServiceImpl<PersonalAttendanceLocationConfigMapper, PersonalAttendanceLocationConfig> implements PersonalAttendanceLocationConfigService {
    private final PersonalShiftMapper personalShiftMapper;
    @Override
    public boolean hasAttendanceUsage(Integer configId) {
        if (configId == null) {
            return false;
        }
        return personalShiftMapper.existsAttendanceUsedByConfig(configId);
    }
    @Override
    public boolean canEdit(Integer configId) {
        return !hasAttendanceUsage(configId);
    }
    @Override
    public boolean canDelete(Integer configId) {
        return !hasAttendanceUsage(configId);
    }
}
src/main/java/com/ruoyi/staff/service/impl/PersonalAttendanceRecordsServiceImpl.java
@@ -72,7 +72,8 @@
        List<PersonalShift> personalShifts = personalShiftMapper.selectList(Wrappers.<PersonalShift>lambdaQuery()
                .eq(PersonalShift::getStaffOnJobId, staffOnJob.getId())
                .eq(PersonalShift::getWorkTime, currentDate.atStartOfDay())
                .isNotNull(PersonalShift::getPersonalAttendanceLocationConfigId));
                .isNotNull(PersonalShift::getPersonalAttendanceLocationConfigId)
                .ne(PersonalShift::getPersonalAttendanceLocationConfigId, 999));
        if (CollectionUtil.isEmpty(personalShifts)){
            throw new BaseException("当前用户当天没有排班数据");
        }
@@ -230,12 +231,15 @@
        List<PersonalShift> personalShifts = personalShiftMapper.selectList(Wrappers.<PersonalShift>lambdaQuery()
                .eq(PersonalShift::getStaffOnJobId, staffOnJob.getId())
                .eq(PersonalShift::getWorkTime, currentDate.atStartOfDay())
                .isNotNull(PersonalShift::getPersonalAttendanceLocationConfigId));
                .isNotNull(PersonalShift::getPersonalAttendanceLocationConfigId)
                .ne(PersonalShift::getPersonalAttendanceLocationConfigId, 999));
        if (CollectionUtil.isNotEmpty(personalShifts)){
            PersonalAttendanceLocationConfig personalAttendanceLocationConfig = personalAttendanceLocationConfigMapper.selectById(personalShifts.get(0).getPersonalAttendanceLocationConfigId());
            resultDto.setStartAt(personalAttendanceLocationConfig.getStartAt());
            resultDto.setEndAt(personalAttendanceLocationConfig.getEndAt());
            resultDto.setShift(personalAttendanceLocationConfig.getShift());
            if (personalAttendanceLocationConfig != null) {
                resultDto.setStartAt(personalAttendanceLocationConfig.getStartAt());
                resultDto.setEndAt(personalAttendanceLocationConfig.getEndAt());
                resultDto.setShift(personalAttendanceLocationConfig.getShift());
            }
        }
        return resultDto;
    }
src/main/resources/mapper/staff/PersonalAttendanceRecordsMapper.xml
@@ -42,7 +42,7 @@
        order by personal_attendance_records.id desc
    </select>
    <!-- æŸ¥è¯¢æŒ‡å®šæ—¥æœŸæ²¡æœ‰è€ƒå‹¤è®°å½•的在职员工(在指定时间之前入职的) -->
    <!-- æŸ¥è¯¢æŒ‡å®šæ—¥æœŸæœ‰æŽ’班(非请假)但没有考勤记录的在职员工,没排班视为休息不标记缺勤 -->
    <select id="selectStaffWithoutAttendanceRecordBeforeTime" resultType="com.ruoyi.staff.pojo.StaffOnJob">
        SELECT soj.*
        FROM staff_on_job soj
@@ -50,8 +50,11 @@
        AND soj.create_time &lt; #{entryDeadline}
        AND EXISTS (
        SELECT 1
        FROM personal_attendance_location_config palc
        WHERE palc.sys_dept_id = soj.sys_dept_id
        FROM personal_shift ps
        WHERE ps.staff_on_job_id = soj.id
        AND DATE(ps.work_time) = #{date}
        AND ps.personal_attendance_location_config_id IS NOT NULL
        AND ps.personal_attendance_location_config_id != 999
        )
        AND NOT EXISTS (
        SELECT 1
src/main/resources/mapper/staff/PersonalShiftMapper.xml
@@ -18,6 +18,7 @@
        u.id user_id
        FROM personal_shift s
        LEFT JOIN staff_on_job u ON u.id = s.staff_on_job_id
        LEFT JOIN staff_leave sl ON sl.staff_on_job_id = u.id
        LEFT JOIN personal_attendance_location_config palc ON palc.id = s.personal_attendance_location_config_id
        <where>
            u.id IS NOT NULL
@@ -26,6 +27,7 @@
            </if>
            <if test="time != null and time != ''">
                and DATE_FORMAT(s.work_time, '%Y-%m') = DATE_FORMAT(#{time}, '%Y-%m')
                AND (u.staff_state = 1 OR (u.staff_state = 0 AND sl.leave_date IS NOT NULL AND sl.leave_date >= DATE_FORMAT(#{time}, '%Y-%m-01')))
            </if>
            <if test="userName != null and userName != ''">
                and u.staff_name like concat('%', #{userName}, '%')
@@ -44,10 +46,12 @@
        GROUP_CONCAT(DATE_FORMAT(s.work_time, '%c'), ':', IFNULL(palc.shift, '') order by s.work_time SEPARATOR ';') month_str
        FROM personal_shift s
        LEFT JOIN staff_on_job u ON u.id = s.staff_on_job_id
         LEFT JOIN personal_attendance_location_config palc ON palc.id = s.personal_attendance_location_config_id
        LEFT JOIN staff_leave sl ON sl.staff_on_job_id = u.id
        LEFT JOIN personal_attendance_location_config palc ON palc.id = s.personal_attendance_location_config_id
         <where>
            <if test="time != null and time != ''">
                and DATE_FORMAT(s.work_time, '%Y') = DATE_FORMAT(#{time}, '%Y' )
                AND (u.staff_state = 1 OR (u.staff_state = 0 AND sl.leave_date IS NOT NULL AND sl.leave_date >= DATE_FORMAT(#{time}, '%Y-01-01')))
            </if>
            <if test="userName != null and userName != ''">
                and u.staff_name like concat('%', #{userName}, '%')
@@ -67,10 +71,12 @@
        GROUP_CONCAT(DATE_FORMAT(s.work_time, '%c'), ':', IFNULL(palc.shift, '') order by s.work_time SEPARATOR ';') month_str
        FROM personal_shift s
        LEFT JOIN staff_on_job u ON u.id = s.staff_on_job_id
        LEFT JOIN staff_leave sl ON sl.staff_on_job_id = u.id
        LEFT JOIN personal_attendance_location_config palc ON palc.id = s.personal_attendance_location_config_id
       <where>
        <if test="time != null and time != ''">
            and DATE_FORMAT(s.work_time, '%Y') = DATE_FORMAT(#{time}, '%Y' )
            AND (u.staff_state = 1 OR (u.staff_state = 0 AND sl.leave_date IS NOT NULL AND sl.leave_date >= DATE_FORMAT(#{time}, '%Y-01-01')))
        </if>
        <if test="userName != null and userName != ''">
            and u.staff_name like concat('%', #{userName}, '%')
@@ -88,10 +94,12 @@
        GROUP_CONCAT(s.work_time, ':', IFNULL(palc.shift, ''), ':', s.id order by s.work_time SEPARATOR ';') AS shift_time, u.id user_id
        FROM personal_shift s
        LEFT JOIN staff_on_job u ON u.id = s.staff_on_job_id
        LEFT JOIN staff_leave sl ON sl.staff_on_job_id = u.id
        LEFT JOIN personal_attendance_location_config palc ON palc.id = s.personal_attendance_location_config_id
        <where>
            <if test="time != null and time != ''">
                and DATE_FORMAT(s.work_time, '%Y-%m') = DATE_FORMAT(#{time}, '%Y-%m' )
                AND (u.staff_state = 1 OR (u.staff_state = 0 AND sl.leave_date IS NOT NULL AND sl.leave_date >= DATE_FORMAT(#{time}, '%Y-%m-01')))
            </if>
            <if test="userName != null and userName != ''">
                and u.staff_name like concat('%', #{userName}, '%')
@@ -104,4 +112,15 @@
        order by s.create_time
    </select>
    <select id="existsAttendanceUsedByConfig" resultType="boolean">
        SELECT EXISTS (
            SELECT 1
            FROM personal_shift ps
            INNER JOIN personal_attendance_records par
                ON par.staff_on_job_id = ps.staff_on_job_id
               AND par.date = DATE(ps.work_time)
            WHERE ps.personal_attendance_location_config_id = #{configId}
        )
    </select>
</mapper>