xiaoyi
2026-10-28 22dd2136e694e3f871591e7fcaac7b19d05e09bd
fix 审查考勤问题
已删除1个文件
已修改6个文件
110 ■■■■■ 文件已修改
sql/mysql/hrm_attendance_location_20261024.sql 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sql/mysql/hrm_attendance_supplement.sql 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/HrmAttendanceRecordController.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceClockRespVO.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/attendance/HrmAttendanceSummaryDO.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-qcreport/pom.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-server/src/main/resources/application-chdl.yaml 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sql/mysql/hrm_attendance_location_20261024.sql
@@ -52,12 +52,27 @@
DROP PROCEDURE xgdl_hrm_attendance_add_column_20261024;
-- å¯¹é½è€ƒå‹¤è§„则与打卡按钮权限码,确保 Web å’Œ APP æ™®é€šè§’色可以授权使用。
UPDATE `system_menu` SET `permission` = 'hrm:attendance-rule:query' WHERE `id` = 60131;
UPDATE `system_menu` SET `permission` = 'hrm:attendance-rule:create' WHERE `id` = 60132;
UPDATE `system_menu` SET `permission` = 'hrm:attendance-rule:update' WHERE `id` = 60133;
UPDATE `system_menu` SET `permission` = 'hrm:attendance-rule:delete' WHERE `id` = 60134;
UPDATE `system_menu` SET `permission` = 'hrm:attendance-rule:export' WHERE `id` = 60135;
-- å¯¹é½è€ƒå‹¤è§„则按钮权限码到 Controller å®žé™…使用的 hrm:attendance-rule:*。
-- 60131~60135 æ˜¯ hrm_attendance_supplement.sql åˆ›å»ºçš„æ—¢æœ‰æŒ‰é’®è¡Œï¼Œè¿™é‡Œåªæ”¹æƒé™æ ‡è¯†ï¼Œä¿ç•™èœå• ID ä¸Žæ—¢æœ‰è§’色授权。
UPDATE `system_menu` SET `permission` = 'hrm:attendance-rule:query'  WHERE `id` = 60131 AND `deleted` = b'0';
UPDATE `system_menu` SET `permission` = 'hrm:attendance-rule:create' WHERE `id` = 60132 AND `deleted` = b'0';
UPDATE `system_menu` SET `permission` = 'hrm:attendance-rule:update' WHERE `id` = 60133 AND `deleted` = b'0';
UPDATE `system_menu` SET `permission` = 'hrm:attendance-rule:delete' WHERE `id` = 60134 AND `deleted` = b'0';
UPDATE `system_menu` SET `permission` = 'hrm:attendance-rule:export' WHERE `id` = 60135 AND `deleted` = b'0';
-- menu_permission_consistency_patch.sql å¯èƒ½å·²ä¸ºåŒæ ·çš„æƒé™æ ‡è¯†æ’入过新菜单行,
-- è‹¥å…ˆæ‰§è¡Œè¿‡è¯¥è¡¥ä¸ï¼Œä¸Šé¢ 5 æ¡ UPDATE ä¼šé€ æˆâ€œä¸€ä¸ªæƒé™å¯¹åº”多个菜单”的重复按钮,这里清理掉非 60131~60135 çš„重复行。
UPDATE `system_menu` dup
JOIN `system_menu` canonical
  ON canonical.`permission` = dup.`permission`
 AND canonical.`id` IN (60131, 60132, 60133, 60134, 60135)
 AND canonical.`deleted` = b'0'
SET dup.`deleted` = b'1', dup.`updater` = '1', dup.`update_time` = NOW()
WHERE dup.`id` NOT IN (60131, 60132, 60133, 60134, 60135)
  AND dup.`deleted` = b'0'
  AND dup.`permission` IN ('hrm:attendance-rule:query', 'hrm:attendance-rule:create',
                            'hrm:attendance-rule:update', 'hrm:attendance-rule:delete',
                            'hrm:attendance-rule:export');
INSERT INTO `system_menu`
(`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`,
sql/mysql/hrm_attendance_supplement.sql
@@ -53,19 +53,19 @@
VALUES (6013, '考勤规则', '', 2, 0, 6010, 'rule', 'ep:setting', 'hrm/attendance/rule/index', 'HrmAttendanceRule', 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
VALUES (60131, '考勤规则查询', 'hrm:attendance:query', 3, 1, 6013, '', '', '', NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0');
VALUES (60131, '考勤规则查询', 'hrm:attendance-rule:query', 3, 1, 6013, '', '', '', NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
VALUES (60132, '考勤规则新增', 'hrm:attendance:create', 3, 2, 6013, '', '', '', NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0');
VALUES (60132, '考勤规则新增', 'hrm:attendance-rule:create', 3, 2, 6013, '', '', '', NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
VALUES (60133, '考勤规则修改', 'hrm:attendance:update', 3, 3, 6013, '', '', '', NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0');
VALUES (60133, '考勤规则修改', 'hrm:attendance-rule:update', 3, 3, 6013, '', '', '', NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
VALUES (60134, '考勤规则删除', 'hrm:attendance:delete', 3, 4, 6013, '', '', '', NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0');
VALUES (60134, '考勤规则删除', 'hrm:attendance-rule:delete', 3, 4, 6013, '', '', '', NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0');
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
VALUES (60135, '考勤规则导出', 'hrm:attendance:export', 3, 5, 6013, '', '', '', NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0');
VALUES (60135, '考勤规则导出', 'hrm:attendance-rule:export', 3, 5, 6013, '', '', '', NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0');
-- 3.2 èŠ‚å‡æ—¥é…ç½®èœå•
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
@@ -101,7 +101,7 @@
-- 3.4 æ‰“卡权限
INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)
VALUES (60114, '打卡', 'hrm:attendance:clock', 3, 4, 6011, '', '', '', NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0');
VALUES (60114, '定位打卡', 'hrm:attendance-record:clock', 3, 4, 6011, '', '', '', NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0');
-- =============================================
-- 4. è§’色菜单关联
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/HrmAttendanceRecordController.java
@@ -9,7 +9,6 @@
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.util.OperateLogUtils;
import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceClockReqVO;
import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceClockRespVO;
import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceMyStatusRespVO;
import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceRecordImportExcelVO;
import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceRecordImportReqVO;
@@ -67,9 +66,8 @@
    @PostMapping("/clock-in")
    @Operation(summary = "上班打卡")
    @PreAuthorize("@ss.hasPermission('hrm:attendance-record:clock')")
    @ApiAccessLog(requestEnable = false)
    public CommonResult<HrmAttendanceClockRespVO> clockIn(
    public CommonResult<HrmAttendanceRecordRespVO> clockIn(
            @Valid @RequestBody(required = false) HrmAttendanceClockReqVO reqVO,
            @RequestParam(value = "location", required = false) String legacyLocation) {
        Long loginUserId = getLoginUserId();
@@ -80,14 +78,13 @@
        }
        HrmAttendanceClockResult result = attendanceRecordService.clockIn(
                employee.getId(), LocalDateTime.now(), reqVO, legacyLocation);
        return success(buildClockResultVO(result, employee));
        return success(buildClockRespVO(result.record(), employee));
    }
    @PostMapping("/clock-out")
    @Operation(summary = "下班打卡")
    @PreAuthorize("@ss.hasPermission('hrm:attendance-record:clock')")
    @ApiAccessLog(requestEnable = false)
    public CommonResult<HrmAttendanceClockRespVO> clockOut(
    public CommonResult<HrmAttendanceRecordRespVO> clockOut(
            @Valid @RequestBody(required = false) HrmAttendanceClockReqVO reqVO,
            @RequestParam(value = "location", required = false) String legacyLocation) {
        Long loginUserId = getLoginUserId();
@@ -98,13 +95,12 @@
        }
        HrmAttendanceClockResult result = attendanceRecordService.clockOut(
                employee.getId(), LocalDateTime.now(), reqVO, legacyLocation);
        return success(buildClockResultVO(result, employee));
        return success(buildClockRespVO(result.record(), employee));
    }
    @GetMapping("/my-status")
    @Operation(summary = "获得当前登录人的考勤状态")
    @Parameter(name = "date", description = "考勤日期,格式 yyyy-MM-dd,默认服务器当天", example = "2026-10-17")
    @PreAuthorize("@ss.hasPermission('hrm:attendance-record:clock')")
    public CommonResult<HrmAttendanceMyStatusRespVO> getMyStatus(
            @RequestParam(value = "date", required = false)
            @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) LocalDate date) {
@@ -124,19 +120,6 @@
            if (dept != null) {
                respVO.setDeptName(dept.getName());
            }
        }
        return respVO;
    }
    private HrmAttendanceClockRespVO buildClockResultVO(HrmAttendanceClockResult result,
                                                         HrmEmployeeDO employee) {
        HrmAttendanceClockRespVO respVO = new HrmAttendanceClockRespVO();
        respVO.setRecord(buildClockRespVO(result.record(), employee));
        respVO.setLocationName(result.rule().getLocationName());
        if (Boolean.TRUE.equals(result.rule().getLocationRequired())) {
            respVO.setDistanceMeters(result.distanceMeters());
            respVO.setRadiusMeters(result.rule().getRadiusMeters());
            respVO.setWithinRange(true);
        }
        return respVO;
    }
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/controller/admin/attendance/vo/HrmAttendanceClockRespVO.java
ÎļþÒÑɾ³ý
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/dal/dataobject/attendance/HrmAttendanceSummaryDO.java
@@ -2,6 +2,7 @@
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
@@ -43,7 +44,12 @@
    /**
     * å¹´æœˆï¼Œæ ¼å¼ï¼šyyyy-MM
     *
     * YEAR_MONTH åœ¨ MySQL 8 ä¸­æ˜¯ä¿ç•™å…³é”®å­—(日期单位),
     * ä¸åŠ åå¼•å·ä¼šå¯¼è‡´ MyBatis-Plus ç”Ÿæˆçš„ SQL æŠ¥ 1064 è¯­æ³•错误,
     * å› æ­¤è¿™é‡Œæ˜¾å¼æŒ‡å®šå¸¦åå¼•号的列名。
     */
    @TableField("`year_month`")
    private String yearMonth;
    /**
yudao-module-qcreport/pom.xml
@@ -60,7 +60,11 @@
            <artifactId>yudao-spring-boot-starter-excel</artifactId>
        </dependency>
        <!-- PDF å‡ºä»¶ï¼šæœåŠ¡ç«¯è°ƒç”¨ Chromium æŠŠæŠ¥å‘Š HTML æ‰“印成 PDF -->
        <!-- PDF å‡ºä»¶ï¼šæœåŠ¡ç«¯è°ƒç”¨ Chromium æŠŠæŠ¥å‘Š HTML æ‰“印成 PDF。
             å¿…须保持默认 compile ä½œç”¨åŸŸï¼šPdfRenderService / BrowserManager çš„æ–¹æ³•签名直接引用
             Playwright ç±»åž‹ï¼ŒSpring åˆ›å»º bean æ—¶å†…省方法签名会强制加载这些类。
             ä¸€æ—¦ provided æ‰“不进 jar,启动即报 NoClassDefFoundError(与 pdf.enabled æ— å…³ï¼‰ã€‚
             ä»£ä»·ï¼šplaywright å¸¦å…¥ driver-bundle çº¦ 194MB,jar çº¦ 490MB。 -->
        <dependency>
            <groupId>com.microsoft.playwright</groupId>
            <artifactId>playwright</artifactId>
yudao-server/src/main/resources/application-chdl.yaml
@@ -65,15 +65,15 @@
      primary: master
      datasource:
        master:
          url: jdbc:mysql://172.17.0.1:10000/mom-chdl?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X è¿žæŽ¥çš„示例
          url: jdbc:mysql://172.17.0.1:9000/mom-chdl?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X è¿žæŽ¥çš„示例
          username: root
          password: xd@123456..
          password: changhui@123456..
  # Redis é…ç½®ã€‚Redisson é»˜è®¤çš„配置足够使用,一般不需要进行调优
  data:
    redis:
      host: 172.17.0.1 # åœ°å€
      port: 9999 # ç«¯å£
      port: 6379 # ç«¯å£ï¼ˆå®¿ä¸»æœº 6379 -> å®¹å™¨ 6379)
      database: 5 # æ•°æ®åº“索引
#      password: dev # å¯†ç ï¼Œå»ºè®®ç”Ÿäº§çŽ¯å¢ƒå¼€å¯
@@ -190,7 +190,7 @@
  storage: # æ–‡ä»¶ä¸Šä¼ é…ç½®
    path: /data/javaWork/mom/file # æ–‡ä»¶å­˜å‚¨æ ¹ç›®å½•
    url-prefix: /admin-api/system/storage-blob # URL路径前缀
    domain: http://36.213.150.237:9003 # åŸŸåå‰ç¼€ï¼ˆæŒ‰å®žé™…域名配置),前端配置好像不太对现在是直连后端,所有要后端端口
    domain: http://101.245.92.159:9006 # åŸŸåå‰ç¼€ï¼ˆæŒ‰å®žé™…域名配置),前端配置好像不太对现在是直连后端,所有要后端端口
    expired: 120 # token过期时间(分钟)
    use-limit: 10 # token使用次数上限
    jwt-secret: abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG # JWT密钥
@@ -208,7 +208,7 @@
      #   2) ä¸­æ–‡å­—体:报告正文是中文,缺 CJK å­—体会打成方框,需装 fonts-wqy-zenhei / Noto Sans CJK
      #   3) ä»¥ root è¿è¡Œï¼šChromium ä¸åŠ  --no-sandbox ä¼šç›´æŽ¥æ‹’绝启动;容器 /dev/shm é»˜è®¤ä»… 64M,
      #      è¿˜éœ€ --disable-dev-shm-usage,否则渲染大报告时会随机崩
      enabled: true # å…³æŽ‰åŽå¯¼å‡ºæŽ¥å£ä¼šæ˜Žç¡®æŠ¥ã€Œæœªå¯ç”¨ã€ï¼Œè€Œä¸æ˜¯æŠ› 500
      enabled: false # å…³æŽ‰åŽå¯¼å‡ºæŽ¥å£ä¼šæ˜Žç¡®æŠ¥ã€Œæœªå¯ç”¨ã€ï¼Œè€Œä¸æ˜¯æŠ› 500。长辉镜像暂未内置 Chromium,先关闭
      channel: '' # ç•™ç©ºï¼šæ”¹ç”±ä¸‹é¢çš„ executable-path æŒ‡å®šé•œåƒå†…çš„ chromium
      executable-path: /usr/local/bin/chromium # é•œåƒå†… chromium çš„固定位置,由 Dockerfile å»ºè½¯é“¾ä¿è¯
      concurrency: 2 # åŒæ—¶è¿›è¡Œçš„ PDF æ¸²æŸ“上限,Chromium å¾ˆåƒå†…存,不要放开
@@ -230,8 +230,8 @@
      max-xlsx-rows: 300 # Excel å•表最多读取的行数
  database-backup: # æ•°æ®åº“备份配置
    host: 172.17.0.1 # å¤‡ä»½ç›®æ ‡ MySQL ä¸»æœºï¼Œç•™ç©ºè‡ªåŠ¨ä»Žæ•°æ®æº JDBC URL è§£æž
    port: 9002 # å¤‡ä»½ç›®æ ‡ MySQL ç«¯å£ï¼Œç•™ç©ºè‡ªåŠ¨ä»Žæ•°æ®æº JDBC URL è§£æž
    port: 9000 # å¤‡ä»½ç›®æ ‡ MySQL ç«¯å£ï¼Œç•™ç©ºè‡ªåŠ¨ä»Žæ•°æ®æº JDBC URL è§£æž
    database: mom-chdl # å¤‡ä»½ç›®æ ‡æ•°æ®åº“,留空自动从数据源 JDBC URL è§£æž
    username: root # å¤‡ä»½è´¦å·ï¼Œç•™ç©ºä½¿ç”¨æ•°æ®æºè´¦å·
    password: 'xd@123456..' # å¤‡ä»½å¯†ç ï¼Œç•™ç©ºä½¿ç”¨æ•°æ®æºå¯†ç 
    password: 'changhui@123456..' # å¤‡ä»½å¯†ç ï¼Œç•™ç©ºä½¿ç”¨æ•°æ®æºå¯†ç 
    command: # mysqldump å‘½ä»¤ï¼Œç•™ç©ºè‡ªåŠ¨æ£€æµ‹éƒ¨ç½²çŽ¯å¢ƒï¼ˆæœ¬æœº mysqldump æˆ– Docker MySQL å®¹å™¨ï¼‰ï¼›å¯æ‰‹åŠ¨æŒ‡å®šï¼Œå¦‚ï¼šdocker exec mysql8 mysqldump