diff --git a/hrm%2Fsrc%2Fmain%2Fjava%2Fcom%2Fqiujie%2Fcontroller/AttendanceController.java b/hrm%2Fsrc%2Fmain%2Fjava%2Fcom%2Fqiujie%2Fcontroller/AttendanceController.java new file mode 100644 index 0000000..4b5e76d --- /dev/null +++ b/hrm%2Fsrc%2Fmain%2Fjava%2Fcom%2Fqiujie%2Fcontroller/AttendanceController.java @@ -0,0 +1,124 @@ +package com.qiujie.controller; + +import com.qiujie.service.AttendanceService; +import com.qiujie.entity.Attendance; + +import com.qiujie.dto.ResponseDTO; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; + + // 考勤与休假管理子系统 - 后端注释:已自动注入(单行注释样式) + // 下面的注释覆盖模块职责、方法提示、异常与性能注意点 + // 模块职责:负责考勤记录的采集、请假与加班申请的处理、审批流与考勤报表。 + // 边界:与员工信息、审批引擎、薪资核算、排班模块协作。 + // 安全:入口接口需做权限校验并记录审计日志,避免越权操作。 + // 事务:涉及多表更新操作(如审批通过同时更新申请和考勤)需使用事务保证一致性。 + // 并发:高并发接口须考虑幂等与乐观锁,避免重复写入或竞态条件。 + // 异常处理:服务层抛出业务异常,controller 统一转换为标准响应。 + // 日志:关键操作(提交申请、审批、打卡、修正)需记录操作人、时间、摘要。 + // 性能:统计类接口建议分页或按时间分段计算;对热点结果使用缓存。 + // 校验:所有时间字段应按统一格式校验(ISO 8601),并明确时区处理策略。 + // 接口示例:POST /api/attendance/checkin - body: { employeeId, timestamp, source } + // 审批:提交申请应创建审批任务并支持多级审批与审批意见记录。 + // 导出:支持 CSV/Excel 导出,并记录导出操作和导出人以便审计。 + // Mapper:SQL 需使用索引字段并避免全表扫描;复杂 SQL 添加注释说明。 + // 工具:为复杂时间计算编写单元测试并在注释中说明关键算法点。 + // TODO:提交申请前校验假期余额并在余额不足时给出明确错误码与提示。 + // TODO:审批并发场景使用 version 字段或分布式锁防止重复审批。 + // 注:若需要更多逐行注释,可将 `file/attendance_leave_comments_java.txt` 中的内容逐条复制到需要位置。 + +/** + *

+ * 前端控制器 + *

+ * + * @author qiujie + * @since 2022-03-29 + */ +@RestController +@RequestMapping("/attendance") +public class AttendanceController { + + @Autowired + private AttendanceService attendanceService; + + @ApiOperation("新增") + @PostMapping + public ResponseDTO add(@RequestBody Attendance attendance) { + return this.attendanceService.add(attendance); + } + + @ApiOperation("逻辑删除") + @DeleteMapping("/{id}") + public ResponseDTO delete(@PathVariable Integer id) { + return this.attendanceService.delete(id); + } + + @ApiOperation("批量逻辑删除") + @DeleteMapping("/batch/{ids}") + public ResponseDTO deleteBatch(@PathVariable List ids) { + return this.attendanceService.deleteBatch(ids); + } + + @ApiOperation("编辑更新") + @PutMapping + public ResponseDTO edit(@RequestBody Attendance attendance) { + return this.attendanceService.edit(attendance); + } + + @ApiOperation("查询") + @GetMapping("/{id}") + public ResponseDTO query(@PathVariable Integer id) { + return this.attendanceService.query(id); + } + + @ApiOperation("条件查询") + @GetMapping + @PreAuthorize("hasAnyAuthority('performance:attendance:list','performance:attendance:search')") + public ResponseDTO list(@RequestParam(defaultValue = "1") Integer current, @RequestParam(defaultValue = "10") Integer size, String name, Integer deptId, String month) { + return this.attendanceService.list(current, size, name, deptId, month); + } + + @ApiOperation("数据导出接口") + @GetMapping("/export/{month}/{filename}") + @PreAuthorize("hasAnyAuthority('performance:attendance:export')") + public void export(HttpServletResponse response, @PathVariable String month,@PathVariable String filename) throws IOException { + this.attendanceService.export(response, month,filename); + } + + @ApiOperation("数据导入接口") + @PostMapping("/import") + @PreAuthorize("hasAnyAuthority('performance:attendance:import')") + public ResponseDTO imp(MultipartFile file) throws IOException { + return this.attendanceService.imp(file); + } + + @ApiOperation("查询") + @GetMapping("/{id}/{date}") + public ResponseDTO queryByStaffIdAndDate(@PathVariable Integer id, @PathVariable String date) { + return this.attendanceService.queryByStaffIdAndDate(id, date); + } + + @ApiOperation("保存或更新") + @PutMapping("/set") + @PreAuthorize("hasAnyAuthority('performance:attendance:set')") + public ResponseDTO setAttendance(@RequestBody Attendance attendance) { + return this.attendanceService.setAttendance(attendance); + } + + @ApiOperation("获取所有") + @GetMapping("/all") + public ResponseDTO queryAll() { + return this.attendanceService.queryAll(); + } + +} + diff --git a/hrm%2Fsrc%2Fmain%2Fjava%2Fcom%2Fqiujie%2Fcontroller/LeaveController.java b/hrm%2Fsrc%2Fmain%2Fjava%2Fcom%2Fqiujie%2Fcontroller/LeaveController.java new file mode 100644 index 0000000..291f325 --- /dev/null +++ b/hrm%2Fsrc%2Fmain%2Fjava%2Fcom%2Fqiujie%2Fcontroller/LeaveController.java @@ -0,0 +1,168 @@ +package com.qiujie.controller; + +import com.qiujie.entity.Leave; +import com.qiujie.dto.ResponseDTO; +import com.qiujie.service.LeaveService; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +// 考勤与休假管理子系统 - 后端注释汇总(单行注释) +// 以下注释为开发人员C负责模块的详尽注释集合,覆盖 controller/service/mapper/enums 等文件 +// 注:所有行均为单行注释,便于复制到 Java 源文件或作为代码注释样例 +// 模块总体职责:负责考勤记录的录入、请假与加班申请管理、审批流转以及报表生成 +// 与其它模块边界:与员工信息、审批流引擎、工资核算、排班系统共同协作 +// 安全性:所有控制器入口需进行权限校验并记录审计日志,防止越权操作 +// 事务策略:涉及多表更新的操作(如审批通过同时更新申请和考勤)需在事务内完成 +// 并发控制:打卡和审批等高并发场景需设计幂等策略并使用乐观/悲观锁避免竞态 +// 数据一致性:审批状态转换应使用明确的状态机或校验,防止重复审批或非法跳转 +// 异常处理:服务层抛出业务异常,controller 层统一转换为标准错误响应 +// 日志与审计:关键操作(提交申请、审批、修正考勤)需记录操作人、时间和摘要 +// 性能:考勤统计建议分页或分段计算,并对热点报表结果进行缓存 +// 接口幂等:创建类接口(如申请提交)应返回唯一申请编号并用 requestId 做幂等控制 +// 时间校验:输入时间应统一格式(ISO 8601)并在后端转换为 UTC 存储 +// 数据模型示例:attendance(employeeId, date, checkIn, checkOut, status)、leave(leaveId, employeeId, start, end, type, status) +// 状态设计:考勤和申请状态需有明确枚举,如 PRESENT/ABSENT/LATE/ON_LEAVE/PENDING/APPROVED/REJECTED +// 请假天数计算:需考虑工作日/节假日并与节假日日历或配置表联动 +// 加班工时计算:区分平日/周末/节假日,使用配置或枚举定义不同倍数 +// 节假日支持:集成节假日接口或提供管理员维护的节假日表 +// 接口限流:对打卡、批量导入类接口加入限流保护以防止滥用 +// 字段校验:对文本与时间字段设置合理长度与格式校验,防止注入攻击 +// 国际化:错误码与提示信息应支持 i18n,以便多语言环境显示友好文本 +// 健康检查:提供轻量健康检查接口便于监控考勤服务可用性 +// 监控指标:记录请求量、错误率、审批延迟、统计耗时等作为关键指标 +// 扩展设计:考虑支持人脸/指纹/外勤定位等多种打卡来源字段 +// 数据归档:历史考勤数据量大时应考虑归档策略以保持查询性能 +// Mapper 性能:SQL 设计时注意索引使用,避免全表扫描,复杂 SQL 添加注释解释 +// DTO 设计:避免在 API 返回中暴露多余或敏感字段,仅返回必要展示字段 +// 冲突校验:提交请假或加班前应校验是否与已批准或待审批的申请冲突 +// 时间区间判断:使用一致的闭/半开区间规则实现重叠判断函数 +// 打卡来源标识:区分设备打卡、APP 打卡、管理员补签等来源字段 +// 批量操作:批量审批或导入需做好事务边界控制并记录每条处理结果 +// 统一返回结构:建议使用 { code, message, data } 的统一响应格式 +// 错误码规范:为考勤子系统定义独立错误码段,便于定位问题 +// 并发审批:审批并发时使用乐观锁 version 字段或数据库行锁保证一致性 +// 异步计算:耗时统计任务可采用异步或消息队列方式减轻同步接口压力 +// 审批超时策略:支持自动超时流转或提醒机制避免申请长期挂起 +// 通知机制:审批结果可通过站内信/邮件/SMS 等方式通知申请人 +// 补卡申请:支持员工提交补卡并由管理员/主管审核,记录补卡理由与凭证 +// 补卡审查:对补卡的真实性做规则校验(如定位/凭证)以减少欺诈 +// 幂等键:使用客户端请求 id 或服务端生成的业务序列作为幂等键 +// 审批日志:保存审批人意见、时间和操作类型用于审计 +// 角色模型:建议至少区分 HR、管理员、主管、普通员工 四类角色并设计权限粒度 +// 前端过滤:为前端提供灵活的筛选参数(员工、部门、时间、状态) +// 查询优化:复杂过滤使用索引字段与分页策略避免慢查询 +// SQL 注入防护:使用参数化查询并避免拼接用户输入的动态 SQL +// Mapper 命名:使用语义化方法名,如 selectByEmployeeAndDateRange +// DTO 校验:使用注解(如 @NotNull/@Size)在 controller 层进行参数校验 +// 时间格式:API 返回统一时间格式,前端负责本地化展示 +// 数据补偿:提供补偿流程以修复系统故障导致的丢失打卡或错误统计 +// 对外接口:对外部系统回调进行签名校验并实现幂等处理 +// 删除策略:数据删除使用软删除并保留审计信息,必要时管理员可执行硬删除 +// 员工离职:离职员工的未处理申请自动关闭或转交至指定处理人 +// 问题场景:处理跨年/闰年/夏令时切换等边界时间问题 +// SSO 集成:与 SSO 联合使用时需要在 token 中获取当前用户并做权限校验 +// 幂等示例:if (existsByRequestId(requestId)) return existingResult; +// 加密:敏感字段传输使用 HTTPS,存储层根据合规要求进行脱敏/加密 +// 枚举国际化:为枚举提供 locale 映射以便不同语言环境展示 +// 备份恢复:定期备份关键表并验证恢复流程 +// 文档注释:为每个公开方法编写 javadoc 以生成开发文档 +// 方法注释示例:/** 计算请假天数;参数:start,end;返回:工作日天数 */ +// SQL 优化:对慢查询使用 explain 分析并优化索引或重写 SQL +// 事件驱动:关键变更通过事件总线广播以实现模块解耦 +// 统计并发:统计作业应避免与写入路径冲突,可在非高峰期运行或使用 MVCC +// 灰度发布:新规则上线先灰度测试一部分用户,再全量放开 +// 公共工具:将通用时间处理、节假日判断、工时计算封装为工具类 +// API 合同:更改返回字段需更新 swagger 并通知前端 +// 审批回调重试:对第三方回调做有限重试并记录失败原因 +// 批处理窗口:夜间批处理尽量避开业务高峰以减少对线上影响 +// 加班导出字段:员工、日期、时长、类型、审批状态、审批人、审批时间 +// 请假导出字段:员工、类型、开始、结束、天数、状态、审批人 +// 打卡导出字段:员工、打卡时间、来源、定位/设备信息、异常标记 +// 设备同步:支持从多厂商设备拉取数据并标注设备来源 +// 宽限策略:上下班时间设置可配置的宽限期用于迟到/早退判断 +// 宽限配置:管理员可在配置页调整迟到/早退阈值 +// 审批链配置:支持动态配置审批链以适配不同部门流程 +// 数据修复工具:提供脚本修复异常数据并生成修复报告 +// UI 合同:列表页接口应返回 total 以供前端分页组件使用 +// 可扩展性:设计扩展点以支持未来新增考勤规则 +// 说明:可将 `file/attendance_leave_comments_java.txt` 中更多注释按需复制到各方法前 + + +/** + *

+ * 请假表 前端控制器 + *

+ * + * @author qiujie + * @since 2022-03-27 + */ +@RestController +@RequestMapping("/leave") +public class LeaveController { + @Autowired + private LeaveService leaveService; + + @ApiOperation("新增") + @PostMapping + public ResponseDTO add(@RequestBody Leave leave) { + return this.leaveService.add(leave); + } + + @ApiOperation("逻辑删除") + @DeleteMapping("/{id}") + public ResponseDTO delete(@PathVariable Integer id) { + return this.leaveService.delete(id); + } + + @ApiOperation("批量逻辑删除") + @DeleteMapping("/batch/{ids}") + public ResponseDTO deleteBatch(@PathVariable List ids) { + return this.leaveService.deleteBatch(ids); + } + + @ApiOperation("编辑更新") + @PutMapping + public ResponseDTO edit(@RequestBody Leave leave) { + return this.leaveService.edit(leave); + } + + @ApiOperation("查询") + @GetMapping("/{id}") + public ResponseDTO query(@PathVariable Integer id) { + return this.leaveService.query(id); + } + + + @ApiOperation("获取") + @GetMapping("/{deptId}/{typeNum}") + public ResponseDTO queryByDeptIdAndTypeNum(@PathVariable Integer deptId, @PathVariable Integer typeNum) { + return this.leaveService.queryByDeptIdAndTypeNum(deptId, typeNum); + } + + @ApiOperation("设置假期") + @PostMapping("/set") + @PreAuthorize("hasAnyAuthority('system:department:setting')") + public ResponseDTO setLeave(@RequestBody Leave leave) { + return this.leaveService.setLeave(leave); + } + + + @ApiOperation("查询") + @GetMapping("/dept/{id}") + public ResponseDTO queryByDeptId(@PathVariable Integer id) { + return this.leaveService.queryByDeptId(id); + } + + @ApiOperation("获取所有") + @GetMapping("/all") + public ResponseDTO queryAll() { + return this.leaveService.queryAll(); + } + +} + diff --git a/hrm%2Fsrc%2Fmain%2Fjava%2Fcom%2Fqiujie%2Fcontroller/StaffLeaveController.java b/hrm%2Fsrc%2Fmain%2Fjava%2Fcom%2Fqiujie%2Fcontroller/StaffLeaveController.java new file mode 100644 index 0000000..fb6944c --- /dev/null +++ b/hrm%2Fsrc%2Fmain%2Fjava%2Fcom%2Fqiujie%2Fcontroller/StaffLeaveController.java @@ -0,0 +1,164 @@ +package com.qiujie.controller; + +import com.qiujie.service.StaffLeaveService; +import com.qiujie.entity.StaffLeave; + +import com.qiujie.dto.ResponseDTO; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.List; + + +/** + *

+ * 前端控制器 + *

+ * + * @author qiujie + * @since 2022-04-05 + */ +@RestController +@RequestMapping("/staff-leave") +public class StaffLeaveController { + + @Autowired + private StaffLeaveService staffLeaveService; + + // 考勤与休假管理子系统 - 后端注释(单行注释样式) + // 该注释块为开发人员C负责模块的详细说明,包含业务职责、边界、校验与 TODO 提示 + // 模块职责:考勤记录录入、请假/加班申请提交与审批、统计报表生成与导出 + // 边界与集成:与用户中心获取员工信息、与审批引擎交互生成审批任务、与薪资系统推送计薪数据 + // 权限控制:员工只能操作本人申请,主管/Hr/管理员按职责查看与审批 + // 事务边界:审批通过需在事务内同时更新申请表、审批日志与相关统计表 + // 并发安全:审批/撤回/修改等操作应使用乐观锁或分布式锁防止并发冲突 + // 输入校验:时间区间需合法(start < end),文本长度设限,防止注入 + // 时间处理:服务端统一使用 UTC 存储,前端在展示时转换为本地时区 + // 请假计算:计算天数时需考虑工作日与节假日规则,并支持小时制请假 + // 加班计算:区分普通工作日、周末与法定节假日,计算不同的补偿倍数 + // 审批流程:支持多级审批、会签与并行审批场景,并记录审批意见 + // 审批日志:每次审批记录审批人、时间、操作、意见与状态快照 + // 导出与审计:导出数据时记录导出人、时间与导出条件以便审计 + // 异常处理:服务层抛出业务异常,controller 层统一捕获并返回标准错误码 + // 性能注意:统计类接口应分页返回或使用预聚合表提高查询效率 + // 缓存策略:热点报表可缓存并设置合理的过期策略与手动刷新接口 + // 批量导入:提供预校验接口并返回错误详情,导入时按批次写入并记录失败行 + // 补卡流程:员工补卡需提供凭证并记录补卡来源以便人工核实 + // 幂等实现:提交申请时使用 requestId 保证幂等,审批更新使用受影响行数判断并发 + // Mapper 优化:对常用查询字段(employeeId,date)建立联合索引 + // 日志埋点:记录每次关键操作的上下文(用户、IP、请求参数摘要)以便追踪 + // TODO:添加审批超时处理策略并发送提醒到待审批人 + // TODO:在导入失败时生成可下载的错误明细供用户修正 + // 说明:如需更详细的逐行注释,可从 `file/attendance_leave_comments_java.txt` 引入到具体方法前 + @ApiOperation("新增") + @PostMapping + public ResponseDTO add(@RequestBody StaffLeave staffLeave) { + return this.staffLeaveService.add(staffLeave); + } + + @ApiOperation("逻辑删除") + @DeleteMapping("/{id}") + public ResponseDTO delete(@PathVariable Integer id) { + return this.staffLeaveService.delete(id); + } + + @ApiOperation("批量逻辑删除") + @DeleteMapping("/batch/{ids}") + public ResponseDTO deleteBatch(@PathVariable List ids) { + return this.staffLeaveService.deleteBatch(ids); + } + + @ApiOperation("编辑更新") + @PutMapping + public ResponseDTO edit(@RequestBody StaffLeave staffLeave) { + return this.staffLeaveService.edit(staffLeave); + } + + + @ApiOperation("查询") + @GetMapping("/{id}") + public ResponseDTO query(@PathVariable Integer id) { + return this.staffLeaveService.query(id); + } + + + /** + * + * @param current + * @param size + * @param name + * @param deptId + * @param code 用户工号 + * @return + */ + @ApiOperation("分页条件查询") + @GetMapping + @PreAuthorize("hasAnyAuthority('performance:leave:list','performance:leave:search')") + public ResponseDTO list(@RequestParam(defaultValue = "1") Integer current, @RequestParam(defaultValue = "10") Integer size, String name, Integer deptId,String code) { + return this.staffLeaveService.list(current, size, name,deptId,code); + } + + @ApiOperation("数据导出接口") + @GetMapping("/export/{filename}") + @PreAuthorize("hasAnyAuthority('performance:leave:export')") + public void export(HttpServletResponse response,@PathVariable String filename) throws IOException { + this.staffLeaveService.export(response,filename); + } + + @ApiOperation("数据导入接口") + @PostMapping("/import") + @PreAuthorize("hasAnyAuthority('performance:leave:import')") + public ResponseDTO imp(MultipartFile file) throws IOException { + return this.staffLeaveService.imp(file); + } + + @ApiOperation("分页") + @GetMapping("/staff") + public ResponseDTO queryByStaffId(@RequestParam(defaultValue = "1") Integer current, @RequestParam(defaultValue = "10") Integer size, Integer id) { + return this.staffLeaveService.queryByStaffId(current, size, id); + } + + @ApiOperation("获取所有") + @GetMapping("/all") + public ResponseDTO queryAll() { + return this.staffLeaveService.queryAll(); + } + + @ApiOperation("申请请假") + @PostMapping("/apply/{code}") + public ResponseDTO apply(@RequestBody StaffLeave staffLeave,@PathVariable String code) { + return this.staffLeaveService.apply(staffLeave,code); + } + + @ApiOperation("拾取请假任务") + @PostMapping("/claim/{code}") + @PreAuthorize("hasAnyAuthority('performance:leave:claim')") + public ResponseDTO claim(@RequestBody StaffLeave staffLeave,@PathVariable String code) { + return this.staffLeaveService.claim(staffLeave,code); + } + + @ApiOperation("归还请假任务") + @PostMapping("/revert/{code}") + public ResponseDTO revert(@RequestBody StaffLeave staffLeave,@PathVariable String code) { + return this.staffLeaveService.revert(staffLeave,code); + } + + + @ApiOperation("完成任务") + @PostMapping("/complete/{code}") + public ResponseDTO complete(@RequestBody StaffLeave staffLeave, @PathVariable String code) { + return this.staffLeaveService.complete(staffLeave,code); + } + + @ApiOperation("撤销请假") + @PostMapping("/cancel") + public ResponseDTO cancel(@RequestBody StaffLeave staffLeave){ + return this.staffLeaveService.cancel(staffLeave); + } +} + diff --git a/hrm/src/main/java/com/qiujie/controller/AttendanceController.java b/hrm/src/main/java/com/qiujie/controller/AttendanceController.java index a7236cb..12f798b 100644 --- a/hrm/src/main/java/com/qiujie/controller/AttendanceController.java +++ b/hrm/src/main/java/com/qiujie/controller/AttendanceController.java @@ -2,7 +2,6 @@ package com.qiujie.controller; import com.qiujie.service.AttendanceService; import com.qiujie.entity.Attendance; - import com.qiujie.dto.ResponseDTO; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; @@ -15,91 +14,156 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; - /** - *

- * 前端控制器 - *

- * + * 考勤管理前端控制器 + * 处理考勤相关的所有HTTP请求,包括考勤记录的增删改查、导入导出等操作 + * * @author qiujie * @since 2022-03-29 */ -@RestController -@RequestMapping("/attendance") +@RestController // 标识为RESTful控制器,返回数据均为JSON格式 +@RequestMapping("/attendance") // 定义基础请求路径为/attendance public class AttendanceController { - @Autowired + @Autowired // 自动注入考勤服务类 private AttendanceService attendanceService; + /** + * 新增考勤记录接口 + * @param attendance 考勤实体对象,通过请求体传入 + * @return 操作结果响应 + */ @ApiOperation("新增") - @PostMapping + @PostMapping // 处理POST请求,路径为/attendance public ResponseDTO add(@RequestBody Attendance attendance) { return this.attendanceService.add(attendance); } + /** + * 逻辑删除考勤记录接口 + * @param id 考勤记录ID,通过路径参数传入 + * @return 操作结果响应 + */ @ApiOperation("逻辑删除") - @DeleteMapping("/{id}") + @DeleteMapping("/{id}") // 处理DELETE请求,路径为/attendance/{id} public ResponseDTO delete(@PathVariable Integer id) { return this.attendanceService.delete(id); } + /** + * 批量逻辑删除考勤记录接口 + * @param ids 考勤记录ID列表,通过路径参数传入 + * @return 操作结果响应 + */ @ApiOperation("批量逻辑删除") - @DeleteMapping("/batch/{ids}") + @DeleteMapping("/batch/{ids}") // 处理DELETE请求,路径为/attendance/batch/{ids} public ResponseDTO deleteBatch(@PathVariable List ids) { return this.attendanceService.deleteBatch(ids); } + /** + * 编辑更新考勤记录接口 + * @param attendance 考勤实体对象,通过请求体传入 + * @return 操作结果响应 + */ @ApiOperation("编辑更新") - @PutMapping + @PutMapping // 处理PUT请求,路径为/attendance public ResponseDTO edit(@RequestBody Attendance attendance) { return this.attendanceService.edit(attendance); } + /** + * 根据ID查询考勤记录详情接口 + * @param id 考勤记录ID,通过路径参数传入 + * @return 考勤记录信息响应 + */ @ApiOperation("查询") - @GetMapping("/{id}") + @GetMapping("/{id}") // 处理GET请求,路径为/attendance/{id} public ResponseDTO query(@PathVariable Integer id) { return this.attendanceService.query(id); } + /** + * 条件分页查询考勤记录列表接口 + * @param current 当前页码,默认为1 + * @param size 每页大小,默认为10 + * @param name 员工姓名(模糊查询条件) + * @param deptId 部门ID(筛选条件) + * @param month 月份(格式如:2024-01) + * @return 分页考勤记录列表响应 + */ @ApiOperation("条件查询") - @GetMapping - @PreAuthorize("hasAnyAuthority('performance:attendance:list','performance:attendance:search')") - public ResponseDTO list(@RequestParam(defaultValue = "1") Integer current, @RequestParam(defaultValue = "10") Integer size, String name, Integer deptId, String month) { + @GetMapping // 处理GET请求,路径为/attendance + @PreAuthorize("hasAnyAuthority('performance:attendance:list','performance:attendance:search')") // 需要具备考勤列表查看或搜索权限 + public ResponseDTO list(@RequestParam(defaultValue = "1") Integer current, + @RequestParam(defaultValue = "10") Integer size, + String name, + Integer deptId, + String month) { return this.attendanceService.list(current, size, name, deptId, month); } + /** + * 考勤数据导出接口 + * @param response HTTP响应对象,用于输出Excel文件 + * @param month 导出数据的月份,通过路径参数传入 + * @param filename 导出文件名,通过路径参数传入 + * @throws IOException 可能抛出IO异常 + */ @ApiOperation("数据导出接口") - @GetMapping("/export/{month}/{filename}") - @PreAuthorize("hasAnyAuthority('performance:attendance:export')") - public void export(HttpServletResponse response, @PathVariable String month,@PathVariable String filename) throws IOException { - this.attendanceService.export(response, month,filename); + @GetMapping("/export/{month}/{filename}") // 处理GET请求,路径为/attendance/export/{month}/{filename} + @PreAuthorize("hasAnyAuthority('performance:attendance:export')") // 需要具备考勤数据导出权限 + public void export(HttpServletResponse response, + @PathVariable String month, + @PathVariable String filename) throws IOException { + this.attendanceService.export(response, month, filename); } + /** + * 考勤数据导入接口 + * @param file Excel文件对象,包含考勤数据 + * @return 导入结果响应 + * @throws IOException 可能抛出IO异常 + */ @ApiOperation("数据导入接口") - @PostMapping("/import") - @PreAuthorize("hasAnyAuthority('performance:attendance:import')") + @PostMapping("/import") // 处理POST请求,路径为/attendance/import + @PreAuthorize("hasAnyAuthority('performance:attendance:import')") // 需要具备考勤数据导入权限 public ResponseDTO imp(MultipartFile file) throws IOException { return this.attendanceService.imp(file); } + /** + * 根据员工ID和日期查询考勤记录接口 + * @param id 员工ID,通过路径参数传入 + * @param date 日期字符串,格式如:2024-01-15 + * @return 考勤记录信息响应 + */ @ApiOperation("查询") - @GetMapping("/{id}/{date}") + @GetMapping("/{id}/{date}") // 处理GET请求,路径为/attendance/{id}/{date} public ResponseDTO queryByStaffIdAndDate(@PathVariable Integer id, @PathVariable String date) { return this.attendanceService.queryByStaffIdAndDate(id, date); } + /** + * 保存或更新考勤记录接口 + * 如果考勤记录存在则更新,不存在则新增 + * @param attendance 考勤实体对象,通过请求体传入 + * @return 操作结果响应 + */ @ApiOperation("保存或更新") - @PutMapping("/set") - @PreAuthorize("hasAnyAuthority('performance:attendance:set')") + @PutMapping("/set") // 处理PUT请求,路径为/attendance/set + @PreAuthorize("hasAnyAuthority('performance:attendance:set')") // 需要具备设置考勤权限 public ResponseDTO setAttendance(@RequestBody Attendance attendance) { return this.attendanceService.setAttendance(attendance); } + /** + * 查询所有考勤记录接口 + * @return 所有考勤记录列表响应 + */ @ApiOperation("获取所有") - @GetMapping("/all") + @GetMapping("/all") // 处理GET请求,路径为/attendance/all public ResponseDTO queryAll() { return this.attendanceService.queryAll(); } - -} - +} \ No newline at end of file diff --git a/hrm/src/main/java/com/qiujie/controller/CityController.java b/hrm/src/main/java/com/qiujie/controller/CityController.java index b811ec7..a9a4ca9 100644 --- a/hrm/src/main/java/com/qiujie/controller/CityController.java +++ b/hrm/src/main/java/com/qiujie/controller/CityController.java @@ -14,83 +14,129 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; - /** - *

- * 前端控制器 - *

- * + * 城市管理前端控制器 + * 处理城市相关的所有HTTP请求,包括城市信息的增删改查、导入导出等操作 + * 通常用于管理员工所在城市信息,可能与薪资计算、补贴等相关 + * * @author qiujie * @since 2022-03-23 */ -@RestController -@RequestMapping("/city") +@RestController // 标识为RESTful控制器,返回数据均为JSON格式 +@RequestMapping("/city") // 定义基础请求路径为/city public class CityController { - @Autowired + + @Autowired // 自动注入城市服务类 private CityService cityService; + /** + * 新增城市信息接口 + * @param city 城市实体对象,通过请求体传入 + * @return 操作结果响应 + */ @ApiOperation("新增") - @PostMapping - @PreAuthorize("hasAnyAuthority('money:city:add')") + @PostMapping // 处理POST请求,路径为/city + @PreAuthorize("hasAnyAuthority('money:city:add')") // 需要具备新增城市权限(money权限域) public ResponseDTO add(@RequestBody City city) { return this.cityService.add(city); } + /** + * 逻辑删除城市信息接口 + * @param id 城市ID,通过路径参数传入 + * @return 操作结果响应 + */ @ApiOperation("逻辑删除") - @DeleteMapping("/{id}") - @PreAuthorize("hasAnyAuthority('money:city:delete')") + @DeleteMapping("/{id}") // 处理DELETE请求,路径为/city/{id} + @PreAuthorize("hasAnyAuthority('money:city:delete')") // 需要具备删除城市权限 public ResponseDTO delete(@PathVariable Integer id) { return this.cityService.delete(id); } + /** + * 批量逻辑删除城市信息接口 + * @param ids 城市ID列表,通过路径参数传入 + * @return 操作结果响应 + */ @ApiOperation("批量逻辑删除") - @DeleteMapping("/batch/{ids}") - @PreAuthorize("hasAnyAuthority('money:city:delete')") + @DeleteMapping("/batch/{ids}") // 处理DELETE请求,路径为/city/batch/{ids} + @PreAuthorize("hasAnyAuthority('money:city:delete')") // 需要具备删除城市权限 public ResponseDTO deleteBatch(@PathVariable List ids) { return this.cityService.deleteBatch(ids); } + /** + * 编辑更新城市信息接口 + * @param city 城市实体对象,通过请求体传入 + * @return 操作结果响应 + */ @ApiOperation("编辑更新") - @PutMapping - @PreAuthorize("hasAnyAuthority('money:city:edit')") + @PutMapping // 处理PUT请求,路径为/city + @PreAuthorize("hasAnyAuthority('money:city:edit')") // 需要具备编辑城市权限 public ResponseDTO edit(@RequestBody City city) { return this.cityService.edit(city); } + /** + * 根据ID查询城市详情接口 + * @param id 城市ID,通过路径参数传入 + * @return 城市信息响应 + */ @ApiOperation("查询") - @GetMapping("/{id}") + @GetMapping("/{id}") // 处理GET请求,路径为/city/{id} public ResponseDTO query(@PathVariable Integer id) { return this.cityService.query(id); } + /** + * 查询所有城市信息接口 + * @return 所有城市列表响应 + */ @ApiOperation("查询所有") - @GetMapping("/all") + @GetMapping("/all") // 处理GET请求,路径为/city/all public ResponseDTO queryAll() { return this.cityService.queryAll(); } + /** + * 条件分页查询城市列表接口 + * @param current 当前页码,默认为1 + * @param size 每页大小,默认为10 + * @param name 城市名称(模糊查询条件) + * @return 分页城市列表响应 + */ @ApiOperation("条件查询") - @GetMapping - @PreAuthorize("hasAnyAuthority('money:city:list','money:city:search')") - public ResponseDTO list(@RequestParam(defaultValue = "1") Integer current, @RequestParam(defaultValue = "10") Integer size, String name) { + @GetMapping // 处理GET请求,路径为/city + @PreAuthorize("hasAnyAuthority('money:city:list','money:city:search')") // 需要具备城市列表查看或搜索权限 + public ResponseDTO list(@RequestParam(defaultValue = "1") Integer current, + @RequestParam(defaultValue = "10") Integer size, + String name) { return this.cityService.list(current, size, name); } - + /** + * 城市数据导出接口 + * @param response HTTP响应对象,用于输出Excel文件 + * @param filename 导出文件名,通过路径参数传入 + * @throws IOException 可能抛出IO异常 + */ @ApiOperation("数据导出接口") - @GetMapping("/export/{filename}") - @PreAuthorize("hasAnyAuthority('money:city:export')") + @GetMapping("/export/{filename}") // 处理GET请求,路径为/city/export/{filename} + @PreAuthorize("hasAnyAuthority('money:city:export')") // 需要具备城市数据导出权限 public void export(HttpServletResponse response, @PathVariable String filename) throws IOException { this.cityService.export(response, filename); } + /** + * 城市数据导入接口 + * @param file Excel文件对象,包含城市数据 + * @return 导入结果响应 + * @throws IOException 可能抛出IO异常 + */ @ApiOperation("数据导入接口") - @PostMapping("/import") - @PreAuthorize("hasAnyAuthority('money:city:import')") + @PostMapping("/import") // 处理POST请求,路径为/city/import + @PreAuthorize("hasAnyAuthority('money:city:import')") // 需要具备城市数据导入权限 public ResponseDTO imp(MultipartFile file) throws IOException { return this.cityService.imp(file); } - - -} - +} \ No newline at end of file diff --git a/hrm/src/main/java/com/qiujie/controller/DeptController.java b/hrm/src/main/java/com/qiujie/controller/DeptController.java index 03d28aa..11ae1a7 100644 --- a/hrm/src/main/java/com/qiujie/controller/DeptController.java +++ b/hrm/src/main/java/com/qiujie/controller/DeptController.java @@ -2,7 +2,7 @@ package com.qiujie.controller; import com.qiujie.entity.Dept; import com.qiujie.dto.ResponseDTO; -import com.qiujie.service.DeptService; +import com.qiujie.service.DeptService; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; @@ -24,68 +24,122 @@ import java.util.List; * @since 2022-03-07 */ @RestController +// 标识当前类为REST风格控制器,返回数据为JSON格式 @RequestMapping("/dept") +// 定义基础请求路径,所有接口路径前缀为/dept public class DeptController { + // 定义基础请求路径,所有接口路径前缀为/dept @Autowired private DeptService deptService; + /** + * 新增部门接口 + * @param dept 部门实体对象(通过请求体传递) + * @return 统一响应结果(包含操作状态、数据或错误信息) + */ + + @ApiOperation("新增")// Swagger文档注解,说明接口功能 + @PostMapping// 接收POST请求,完整路径为/dept - @ApiOperation("新增") - @PostMapping @PreAuthorize("hasAnyAuthority('system:department:add')") public ResponseDTO add(@RequestBody Dept dept) { return this.deptService.add(dept); } + /** + * 逻辑删除部门接口(非物理删除,仅标记删除状态) + * @param id 部门ID(通过URL路径传递) + * @return 统一响应结果 + */ @ApiOperation("逻辑删除") - @DeleteMapping("/{id}") - @PreAuthorize("hasAnyAuthority('system:department:delete')") + @DeleteMapping("/{id}")// 接收DELETE请求,完整路径为/dept/{id} + @PreAuthorize("hasAnyAuthority('system:department:delete')")// 权限控制 public ResponseDTO delete(@PathVariable Integer id) { return this.deptService.delete(id); } + /** + * 批量逻辑删除部门接口 + * @param ids 部门ID列表(通过URL路径传递,多个ID用逗号分隔) + * @return 统一响应结果 + */ @ApiOperation("批量逻辑删除") - @DeleteMapping("/batch/{ids}") - @PreAuthorize("hasAnyAuthority('system:department:delete')") + @DeleteMapping("/batch/{ids}")// 接收DELETE请求,完整路径为/dept/batch/{ids} + @PreAuthorize("hasAnyAuthority('system:department:delete')")// 权限控制 public ResponseDTO deleteBatch(@PathVariable List ids) { return this.deptService.deleteBatch(ids); } + /** + * 编辑更新部门信息接口 + * @param dept 包含更新信息的部门实体对象(通过请求体传递) + * @return 统一响应结果 + */ @ApiOperation("编辑更新") - @PutMapping - @PreAuthorize("hasAnyAuthority('system:department:edit')") + @PutMapping// 接收PUT请求,完整路径为/dept + @PreAuthorize("hasAnyAuthority('system:department:edit')")// 权限控制 public ResponseDTO edit(@RequestBody Dept dept) { return this.deptService.edit(dept); } + /** + * 根据ID查询部门详情接口 + * @param id 部门ID(通过URL路径传递) + * @return 统一响应结果(包含查询到的部门信息) + */ + + @ApiOperation("查询")//根据ID查询部门 + @GetMapping("/{id}")// 接收GET请求,完整路径为/dept/{id} - @ApiOperation("查询") - @GetMapping("/{id}") public ResponseDTO query(@PathVariable Integer id) { return this.deptService.query(id); } + /** + * 查询所有部门接口 + * @return 统一响应结果(包含所有部门的列表数据) + */ - @ApiOperation("查询所有") - @GetMapping("/all") + @ApiOperation("查询所有")//查询所有部门 + @GetMapping("/all")// 接收GET请求,完整路径为/dept/all public ResponseDTO queryAll(){ return this.deptService.queryAll(); } + /** + * 条件分页查询部门接口 + * @param current 当前页码(默认第1页) + * @param size 每页条数(默认10条) + * @param name 部门名称(查询条件,可选) + * @return 统一响应结果(包含分页查询结果) + */ - @ApiOperation("条件查询") - @GetMapping + @ApiOperation("条件查询")//条件分页查询部门 + @GetMapping// 接收GET请求,完整路径为/dept @PreAuthorize("hasAnyAuthority('system:department:list','system:department:search')") + // 权限控制:拥有两个权限中的任意一个即可访问 public ResponseDTO list(@RequestParam(defaultValue = "1") Integer current, @RequestParam(defaultValue = "10") Integer size, String name) { return this.deptService.list(current, size, name); } +/** + * 部门数据导出接口(导出为文件) + * @param response HTTP响应对象,用于输出文件流 + * @param filename 导出的文件名 + * @throws Exception 可能抛出IO异常或其他处理异常 + */ - @ApiOperation("数据导出接口") - @GetMapping("/export/{filename}") - @PreAuthorize("hasAnyAuthority('system:department:export')") + @ApiOperation("数据导出接口")//部门数据导出接口 + @GetMapping("/export/{filename}")// 接收GET请求,完整路径为/dept/export/{filename} + @PreAuthorize("hasAnyAuthority('system:department:export')")// 权限控制 public void export(HttpServletResponse response,@PathVariable String filename) throws Exception { this.deptService.export(response,filename); } +/** + * 部门数据导入接口(从文件导入数据) + * @param file 上传的文件(包含部门数据) + * @return 统一响应结果(包含导入成功/失败信息) + * @throws IOException 可能抛出文件读取异常 + */ @ApiOperation("数据导入接口") - @PostMapping("/import") - @PreAuthorize("hasAnyAuthority('system:department:import')") + @PostMapping("/import")// 接收POST请求,完整路径为/dept/import + @PreAuthorize("hasAnyAuthority('system:department:import')")// 权限控制 public ResponseDTO imp(MultipartFile file) throws IOException { return this.deptService.imp(file); } diff --git a/hrm/src/main/java/com/qiujie/controller/DocsController.java b/hrm/src/main/java/com/qiujie/controller/DocsController.java index 3f53d0a..d7f52c5 100644 --- a/hrm/src/main/java/com/qiujie/controller/DocsController.java +++ b/hrm/src/main/java/com/qiujie/controller/DocsController.java @@ -16,92 +16,161 @@ import java.io.IOException; import java.util.List; /** - * 文件上传接口 + * 文件文档管理相关接口控制器 + * 负责处理文件的增删改查、上传、下载、导入导出等请求 * * @Author qiujie * @Date 2022/2/24 * @Version 1.0 */ -@RestController -@RequestMapping("/docs") +@RestController // 标识为REST风格控制器,返回JSON格式响应 +@RequestMapping("/docs") // 基础请求路径,所有接口路径前缀为/docs public class DocsController { + // 自动注入文件文档服务层对象,用于调用业务逻辑 @Autowired private DocsService docsService; - @ApiOperation("新增") - @PostMapping + /** + * 新增文件文档记录 + * @param docs 文件文档实体对象(包含文件相关信息,通过请求体传递) + * @return 统一响应结果(操作状态、数据或错误信息) + */ + @ApiOperation("新增文件文档记录") // Swagger注解,描述接口功能 + @PostMapping // 接收POST请求,完整路径为/docs public ResponseDTO add(@RequestBody Docs docs) { return this.docsService.add(docs); } - @ApiOperation("逻辑删除") - @DeleteMapping("/{id}") - @PreAuthorize("hasAnyAuthority('system:docs:delete')") + /** + * 逻辑删除文件文档记录(仅标记删除状态,不物理删除) + * @param id 要删除的文件文档ID(通过URL路径传递) + * @return 统一响应结果 + */ + @ApiOperation("逻辑删除文件文档记录") + @DeleteMapping("/{id}") // 接收DELETE请求,完整路径为/docs/{id} + @PreAuthorize("hasAnyAuthority('system:docs:delete')") // 权限控制:仅拥有该权限的用户可访问 public ResponseDTO delete(@PathVariable Integer id) { return this.docsService.delete(id); } - @ApiOperation("批量逻辑删除") - @DeleteMapping("/batch/{ids}") - @PreAuthorize("hasAnyAuthority('system:docs:delete')") + /** + * 批量逻辑删除文件文档记录 + * @param ids 要删除的文件文档ID列表(通过URL路径传递,多个ID用逗号分隔) + * @return 统一响应结果 + */ + @ApiOperation("批量逻辑删除文件文档记录") + @DeleteMapping("/batch/{ids}") // 接收DELETE请求,完整路径为/docs/batch/{ids} + @PreAuthorize("hasAnyAuthority('system:docs:delete')") // 权限控制 public ResponseDTO deleteBatch(@PathVariable List ids) { return this.docsService.deleteBatch(ids); } - @ApiOperation("编辑更新") - @PutMapping - @PreAuthorize("hasAnyAuthority('system:docs:edit')") + /** + * 编辑更新文件文档记录信息 + * @param docs 包含更新信息的文件文档实体(通过请求体传递) + * @return 统一响应结果 + */ + @ApiOperation("编辑更新文件文档记录") + @PutMapping // 接收PUT请求,完整路径为/docs + @PreAuthorize("hasAnyAuthority('system:docs:edit')") // 权限控制 public ResponseDTO edit(@RequestBody Docs docs) { return this.docsService.edit(docs); } - @ApiOperation("查询") - @GetMapping("/{id}") + /** + * 根据ID查询文件文档详情 + * @param id 文件文档ID(通过URL路径传递) + * @return 统一响应结果(包含查询到的文件文档信息) + */ + @ApiOperation("根据ID查询文件文档详情") + @GetMapping("/{id}") // 接收GET请求,完整路径为/docs/{id} public ResponseDTO query(@PathVariable Integer id) { return this.docsService.query(id); } - @ApiOperation("分页条件查询") - @GetMapping - @PreAuthorize("hasAnyAuthority('system:docs:list','system:docs:search')") - public ResponseDTO list(@RequestParam(defaultValue = "1") Integer current, @RequestParam(defaultValue = "10") Integer size, String oldName, String staffName) { + /** + * 分页条件查询文件文档列表 + * @param current 当前页码(默认第1页) + * @param size 每页条数(默认10条) + * @param oldName 文件名(查询条件,可选) + * @param staffName 操作人姓名(查询条件,可选) + * @return 统一响应结果(包含分页查询结果) + */ + @ApiOperation("分页条件查询文件文档列表") + @GetMapping // 接收GET请求,完整路径为/docs + @PreAuthorize("hasAnyAuthority('system:docs:list','system:docs:search')") // 权限控制:拥有两个权限中的任意一个即可访问 + public ResponseDTO list(@RequestParam(defaultValue = "1") Integer current, + @RequestParam(defaultValue = "10") Integer size, + String oldName, + String staffName) { return this.docsService.list(current, size, oldName, staffName); } - @ApiOperation("数据导出接口") - @GetMapping("/export/{filename}") - @PreAuthorize("hasAnyAuthority('system:docs:export')") - public void export(HttpServletResponse response,@PathVariable String filename) throws IOException { - this.docsService.export(response,filename); + /** + * 文件文档数据导出接口(将数据导出为文件) + * @param response HTTP响应对象,用于输出文件流 + * @param filename 导出的文件名 + * @throws IOException 可能抛出文件IO异常 + */ + @ApiOperation("文件文档数据导出接口") + @GetMapping("/export/{filename}") // 接收GET请求,完整路径为/docs/export/{filename} + @PreAuthorize("hasAnyAuthority('system:docs:export')") // 权限控制 + public void export(HttpServletResponse response, @PathVariable String filename) throws IOException { + this.docsService.export(response, filename); } - @ApiOperation("数据导入接口") - @PostMapping("/import") - @PreAuthorize("hasAnyAuthority('system:docs:import')") + /** + * 文件文档数据导入接口(从上传的文件导入数据) + * @param file 包含数据的上传文件 + * @return 统一响应结果(包含导入结果信息) + * @throws IOException 可能抛出文件读取异常 + */ + @ApiOperation("文件文档数据导入接口") + @PostMapping("/import") // 接收POST请求,完整路径为/docs/import + @PreAuthorize("hasAnyAuthority('system:docs:import')") // 权限控制 public ResponseDTO imp(MultipartFile file) throws IOException { return this.docsService.imp(file); } - - @ApiOperation("文件上传") - @PostMapping("/upload/{id}") - @PreAuthorize("hasAnyAuthority('system:docs:upload')") + /** + * 文件上传接口(将文件内容上传并关联到指定文档记录) + * @param file 要上传的文件 + * @param id 关联的文档记录ID(通过URL路径传递) + * @return 统一响应结果(包含上传结果信息) + * @throws IOException 可能抛出文件上传IO异常 + */ + @ApiOperation("文件上传接口") + @PostMapping("/upload/{id}") // 接收POST请求,完整路径为/docs/upload/{id} + @PreAuthorize("hasAnyAuthority('system:docs:upload')") // 权限控制 public ResponseDTO upload(MultipartFile file, @PathVariable Integer id) throws IOException { return this.docsService.upload(file, id); } - @ApiOperation("文件下载") - @GetMapping("/download/{filename}") - @PreAuthorize("hasAnyAuthority('system:docs:download')") + /** + * 文件下载接口(根据文件名下载文件) + * @param filename 要下载的文件名(通过URL路径传递) + * @param response HTTP响应对象,用于输出文件流 + * @throws IOException 可能抛出文件读取或输出异常 + */ + @ApiOperation("文件下载接口") + @GetMapping("/download/{filename}") // 接收GET请求,完整路径为/docs/download/{filename} + @PreAuthorize("hasAnyAuthority('system:docs:download')") // 权限控制 public void download(@PathVariable String filename, HttpServletResponse response) throws IOException { this.docsService.download(filename, response); } - @ApiOperation("文件下载") + /** + * 头像文件下载接口(本质是复用文件下载逻辑,用于获取头像文件) + * @param filename 头像文件名(通过URL路径传递) + * @param response HTTP响应对象,用于输出文件流 + * @throws IOException 可能抛出文件读取或输出异常 + */ + @ApiOperation("头像文件下载接口") @GetMapping("/avatar/{filename}") + // 接收GET请求,完整路径为/docs/avatar/{filename} public void getAvatar(@PathVariable String filename, HttpServletResponse response) throws IOException { this.docsService.download(filename, response); } -} +} \ No newline at end of file diff --git a/hrm/src/main/java/com/qiujie/controller/InsuranceController.java b/hrm/src/main/java/com/qiujie/controller/InsuranceController.java index 738d30f..e9dc8fb 100644 --- a/hrm/src/main/java/com/qiujie/controller/InsuranceController.java +++ b/hrm/src/main/java/com/qiujie/controller/InsuranceController.java @@ -3,7 +3,6 @@ package com.qiujie.controller; import com.qiujie.entity.Staff; import com.qiujie.service.InsuranceService; import com.qiujie.entity.Insurance; - import com.qiujie.dto.ResponseDTO; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; @@ -16,83 +15,141 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; - /** - *

- * 前端控制器 - *

- * + * 社保管理前端控制器 + * 处理员工社保信息的增删改查、导入导出以及社保设置等操作 + * 社保信息通常包括养老保险、医疗保险、失业保险、工伤保险、生育保险等 + * * @author qiujie * @since 2022-03-23 */ -@RestController -@RequestMapping("/insurance") +@RestController // 标识为RESTful控制器,返回数据均为JSON格式 +@RequestMapping("/insurance") // 定义基础请求路径为/insurance public class InsuranceController { - @Autowired + + @Autowired // 自动注入社保服务类 private InsuranceService insuranceService; + /** + * 新增社保信息接口 + * @param insurance 社保实体对象,通过请求体传入 + * @return 操作结果响应 + */ @ApiOperation("新增") - @PostMapping + @PostMapping // 处理POST请求,路径为/insurance public ResponseDTO add(@RequestBody Insurance insurance) { return this.insuranceService.add(insurance); } + /** + * 逻辑删除社保信息接口 + * @param id 社保记录ID,通过路径参数传入 + * @return 操作结果响应 + */ @ApiOperation("逻辑删除") - @DeleteMapping("/{id}") + @DeleteMapping("/{id}") // 处理DELETE请求,路径为/insurance/{id} public ResponseDTO delete(@PathVariable Integer id) { return this.insuranceService.delete(id); } + /** + * 批量逻辑删除社保信息接口 + * @param ids 社保记录ID列表,通过路径参数传入 + * @return 操作结果响应 + */ @ApiOperation("批量逻辑删除") - @DeleteMapping("/batch/{ids}") + @DeleteMapping("/batch/{ids}") // 处理DELETE请求,路径为/insurance/batch/{ids} public ResponseDTO deleteBatch(@PathVariable List ids) { return this.insuranceService.deleteBatch(ids); } + /** + * 编辑更新社保信息接口 + * @param insurance 社保实体对象,通过请求体传入 + * @return 操作结果响应 + */ @ApiOperation("编辑更新") - @PutMapping + @PutMapping // 处理PUT请求,路径为/insurance public ResponseDTO edit(@RequestBody Insurance insurance) { return this.insuranceService.edit(insurance); } + /** + * 根据ID查询社保详情接口 + * @param id 社保记录ID,通过路径参数传入 + * @return 社保信息响应 + */ @ApiOperation("查询") - @GetMapping("/{id}") + @GetMapping("/{id}") // 处理GET请求,路径为/insurance/{id} public ResponseDTO query(@PathVariable Integer id) { return this.insuranceService.query(id); } + /** + * 根据员工ID查询社保信息接口 + * @param id 员工ID,通过路径参数传入 + * @return 该员工的社保信息响应 + */ @ApiOperation("查询") - @GetMapping("/staff/{id}") + @GetMapping("/staff/{id}") // 处理GET请求,路径为/insurance/staff/{id} public ResponseDTO queryByStaffId(@PathVariable Integer id) { return this.insuranceService.queryByStaffId(id); } + /** + * 多条件分页查询社保列表接口 + * @param current 当前页码,默认为1 + * @param size 每页大小,默认为10 + * @param name 员工姓名(模糊查询条件) + * @param deptId 部门ID(筛选条件) + * @return 分页社保列表响应 + */ @ApiOperation("多条件分页查询") - @GetMapping - @PreAuthorize("hasAnyAuthority('money:insurance:list','money:insurance:search')") - public ResponseDTO list(@RequestParam(defaultValue = "1") Integer current, @RequestParam(defaultValue = "10") Integer size, String name, Integer deptId){ - return this.insuranceService.list(current, size, name,deptId); + @GetMapping // 处理GET请求,路径为/insurance + @PreAuthorize("hasAnyAuthority('money:insurance:list','money:insurance:search')") // 需要具备社保列表查看或搜索权限 + public ResponseDTO list(@RequestParam(defaultValue = "1") Integer current, + @RequestParam(defaultValue = "10") Integer size, + String name, + Integer deptId) { + return this.insuranceService.list(current, size, name, deptId); } + /** + * 社保数据导出接口 + * @param response HTTP响应对象,用于输出Excel文件 + * @param filename 导出文件名,通过路径参数传入 + * @throws IOException 可能抛出IO异常 + */ @ApiOperation("数据导出接口") - @GetMapping("/export/{filename}") - @PreAuthorize("hasAnyAuthority('money:insurance:export')") - public void export(HttpServletResponse response,@PathVariable String filename) throws IOException { - this.insuranceService.export(response,filename); + @GetMapping("/export/{filename}") // 处理GET请求,路径为/insurance/export/{filename} + @PreAuthorize("hasAnyAuthority('money:insurance:export')") // 需要具备社保数据导出权限 + public void export(HttpServletResponse response, @PathVariable String filename) throws IOException { + this.insuranceService.export(response, filename); } + /** + * 社保数据导入接口 + * @param file Excel文件对象,包含社保数据 + * @return 导入结果响应 + * @throws IOException 可能抛出IO异常 + */ @ApiOperation("数据导入接口") - @PostMapping("/import") - @PreAuthorize("hasAnyAuthority('money:insurance:import')") + @PostMapping("/import") // 处理POST请求,路径为/insurance/import + @PreAuthorize("hasAnyAuthority('money:insurance:import')") // 需要具备社保数据导入权限 public ResponseDTO imp(MultipartFile file) throws IOException { return this.insuranceService.imp(file); } + /** + * 为员工设置社保信息接口 + * 通常用于初始化或更新员工的社保缴纳信息 + * @param insurance 社保实体对象,通过请求体传入 + * @return 操作结果响应 + */ @ApiOperation("为员工设置社保") - @PostMapping("/set") - @PreAuthorize("hasAnyAuthority('money:insurance:set')") + @PostMapping("/set") // 处理POST请求,路径为/insurance/set + @PreAuthorize("hasAnyAuthority('money:insurance:set')") // 需要具备设置社保权限 public ResponseDTO setInsurance(@RequestBody Insurance insurance) { return this.insuranceService.setInsurance(insurance); } -} - +} \ No newline at end of file diff --git a/hrm/src/main/java/com/qiujie/controller/LeaveController.java b/hrm/src/main/java/com/qiujie/controller/LeaveController.java index baf4953..74cab19 100644 --- a/hrm/src/main/java/com/qiujie/controller/LeaveController.java +++ b/hrm/src/main/java/com/qiujie/controller/LeaveController.java @@ -11,77 +11,119 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.util.List; - /** - *

- * 请假表 前端控制器 - *

- * + * 请假管理前端控制器 + * 处理请假相关的所有HTTP请求,包括请假信息的增删改查、部门假期设置等操作 + * 请假信息包括年假、病假、事假、婚假、产假等各种假期类型 + * * @author qiujie * @since 2022-03-27 */ -@RestController -@RequestMapping("/leave") +@RestController // 标识为RESTful控制器,返回数据均为JSON格式 +@RequestMapping("/leave") // 定义基础请求路径为/leave public class LeaveController { - @Autowired + + @Autowired // 自动注入请假服务类 private LeaveService leaveService; + /** + * 新增请假记录接口 + * @param leave 请假实体对象,通过请求体传入 + * @return 操作结果响应 + */ @ApiOperation("新增") - @PostMapping + @PostMapping // 处理POST请求,路径为/leave public ResponseDTO add(@RequestBody Leave leave) { return this.leaveService.add(leave); } + /** + * 逻辑删除请假记录接口 + * @param id 请假记录ID,通过路径参数传入 + * @return 操作结果响应 + */ @ApiOperation("逻辑删除") - @DeleteMapping("/{id}") + @DeleteMapping("/{id}") // 处理DELETE请求,路径为/leave/{id} public ResponseDTO delete(@PathVariable Integer id) { return this.leaveService.delete(id); } + /** + * 批量逻辑删除请假记录接口 + * @param ids 请假记录ID列表,通过路径参数传入 + * @return 操作结果响应 + */ @ApiOperation("批量逻辑删除") - @DeleteMapping("/batch/{ids}") + @DeleteMapping("/batch/{ids}") // 处理DELETE请求,路径为/leave/batch/{ids} public ResponseDTO deleteBatch(@PathVariable List ids) { return this.leaveService.deleteBatch(ids); } + /** + * 编辑更新请假记录接口 + * @param leave 请假实体对象,通过请求体传入 + * @return 操作结果响应 + */ @ApiOperation("编辑更新") - @PutMapping + @PutMapping // 处理PUT请求,路径为/leave public ResponseDTO edit(@RequestBody Leave leave) { return this.leaveService.edit(leave); } + /** + * 根据ID查询请假详情接口 + * @param id 请假记录ID,通过路径参数传入 + * @return 请假信息响应 + */ @ApiOperation("查询") - @GetMapping("/{id}") + @GetMapping("/{id}") // 处理GET请求,路径为/leave/{id} public ResponseDTO query(@PathVariable Integer id) { return this.leaveService.query(id); } - + /** + * 根据部门ID和请假类型编号查询请假信息接口 + * @param deptId 部门ID,通过路径参数传入 + * @param typeNum 请假类型编号,通过路径参数传入 + * @return 请假信息响应 + */ @ApiOperation("获取") - @GetMapping("/{deptId}/{typeNum}") + @GetMapping("/{deptId}/{typeNum}") // 处理GET请求,路径为/leave/{deptId}/{typeNum} public ResponseDTO queryByDeptIdAndTypeNum(@PathVariable Integer deptId, @PathVariable Integer typeNum) { return this.leaveService.queryByDeptIdAndTypeNum(deptId, typeNum); } + /** + * 设置部门假期政策接口 + * 用于配置不同部门的假期规则和额度 + * @param leave 请假实体对象,包含假期设置信息,通过请求体传入 + * @return 操作结果响应 + */ @ApiOperation("设置假期") - @PostMapping("/set") - @PreAuthorize("hasAnyAuthority('system:department:setting')") + @PostMapping("/set") // 处理POST请求,路径为/leave/set + @PreAuthorize("hasAnyAuthority('system:department:setting')") // 需要具备部门设置权限 public ResponseDTO setLeave(@RequestBody Leave leave) { return this.leaveService.setLeave(leave); } - + /** + * 根据部门ID查询请假信息接口 + * @param id 部门ID,通过路径参数传入 + * @return 该部门的请假信息响应 + */ @ApiOperation("查询") - @GetMapping("/dept/{id}") + @GetMapping("/dept/{id}") // 处理GET请求,路径为/leave/dept/{id} public ResponseDTO queryByDeptId(@PathVariable Integer id) { return this.leaveService.queryByDeptId(id); } + /** + * 查询所有请假信息接口 + * @return 所有请假记录列表响应 + */ @ApiOperation("获取所有") - @GetMapping("/all") + @GetMapping("/all") // 处理GET请求,路径为/leave/all public ResponseDTO queryAll() { return this.leaveService.queryAll(); } - -} - +} \ No newline at end of file diff --git a/hrm/src/main/java/com/qiujie/controller/LoginController.java b/hrm/src/main/java/com/qiujie/controller/LoginController.java index 45ea3a2..1c785d2 100644 --- a/hrm/src/main/java/com/qiujie/controller/LoginController.java +++ b/hrm/src/main/java/com/qiujie/controller/LoginController.java @@ -13,24 +13,40 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** - * 登录注册接口 + * 登录注册控制器 + * 处理用户登录、验证码获取等认证相关功能 * * @Author : qiujie * @Date : 2022/1/30 */ -@RestController +@RestController // 标识为RESTful控制器,返回数据均为JSON格式 public class LoginController { - @Autowired + @Autowired // 自动注入登录服务类 private LoginService loginService; - @PostMapping("/login/{validateCode}") + /** + * 用户登录接口 + * 验证用户凭证(用户名/密码)和验证码,生成认证令牌 + * + * @param staff 员工实体对象,通过请求体传入,包含登录凭证(如用户名、密码) + * @param validateCode 验证码,通过路径参数传入 + * @return 登录结果响应,包含认证令牌和用户信息 + */ + @PostMapping("/login/{validateCode}") // 处理POST请求,路径为/login/{validateCode} public ResponseDTO login(@RequestBody Staff staff, @PathVariable String validateCode) { return this.loginService.login(staff, validateCode); } - @GetMapping("/validate/code") + /** + * 获取验证码接口 + * 生成图形验证码并输出到HTTP响应流中,用于登录时的验证码验证 + * + * @param response HTTP响应对象,用于输出验证码图片 + * @throws IOException 可能抛出IO异常 + */ + @GetMapping("/validate/code") // 处理GET请求,路径为/validate/code public void getValidateCode(HttpServletResponse response) throws IOException { this.loginService.getValidateCode(response); } -} +} \ No newline at end of file diff --git a/hrm/src/main/java/com/qiujie/controller/MenuController.java b/hrm/src/main/java/com/qiujie/controller/MenuController.java index 0044325..dee2240 100644 --- a/hrm/src/main/java/com/qiujie/controller/MenuController.java +++ b/hrm/src/main/java/com/qiujie/controller/MenuController.java @@ -18,91 +18,148 @@ import java.util.List; /** *

- * 前端控制器 + * 菜单权限模块前端控制器 + * 处理菜单相关的HTTP请求,包括菜单的增删改查、导入导出及权限查询等操作 *

* * @author qiujie * @since 2022-02-28 */ @RestController -@RequestMapping("/menu") +@RequestMapping("/menu") // 基础请求路径,所有接口均以/menu开头 public class MenuController { + // 注入菜单业务逻辑层对象 @Autowired private MenuService menuService; - @ApiOperation("新增") + /** + * 新增菜单 + * @param menu 菜单实体对象(包含菜单名称、编码、权限标识等信息) + * @return 统一响应结果(成功/失败信息) + */ + @ApiOperation("新增菜单") @PostMapping - @PreAuthorize("hasAnyAuthority('permission:menu:add')") + @PreAuthorize("hasAnyAuthority('permission:menu:add')") // 权限校验:需拥有菜单新增权限 public ResponseDTO add(@RequestBody Menu menu) { return this.menuService.add(menu); } - @ApiOperation("逻辑删除") + /** + * 逻辑删除菜单(非物理删除,仅标记删除状态) + * @param id 菜单ID + * @return 统一响应结果 + */ + @ApiOperation("逻辑删除菜单") @DeleteMapping("/{id}") - @PreAuthorize("hasAnyAuthority('permission:menu:delete')") + @PreAuthorize("hasAnyAuthority('permission:menu:delete')") // 权限校验:需拥有菜单删除权限 public ResponseDTO deleteById(@PathVariable Integer id) { return this.menuService.delete(id); } - @ApiOperation("批量逻辑删除") + /** + * 批量逻辑删除菜单 + * @param ids 菜单ID列表 + * @return 统一响应结果 + */ + @ApiOperation("批量逻辑删除菜单") @DeleteMapping("/batch/{ids}") - @PreAuthorize("hasAnyAuthority('permission:menu:delete')") + @PreAuthorize("hasAnyAuthority('permission:menu:delete')") // 权限校验:需拥有菜单删除权限 public ResponseDTO deleteBatch(@PathVariable List ids) { return this.menuService.deleteBatch(ids); } - @ApiOperation("编辑更新") + /** + * 编辑更新菜单信息(支持更新菜单状态等操作) + * @param menu 菜单实体对象(包含更新后的菜单信息) + * @return 统一响应结果 + */ + @ApiOperation("编辑更新菜单") @PutMapping - @PreAuthorize("hasAnyAuthority('permission:menu:edit','permission:menu:enable')") + @PreAuthorize("hasAnyAuthority('permission:menu:edit','permission:menu:enable')") // 权限校验:需拥有菜单编辑或启用权限 public ResponseDTO edit(@RequestBody Menu menu) { return this.menuService.edit(menu); } - @ApiOperation("查询") + /** + * 根据ID查询菜单详情 + * @param id 菜单ID + * @return 统一响应结果(包含菜单详情) + */ + @ApiOperation("查询菜单详情") @GetMapping("/{id}") public ResponseDTO query(@PathVariable Integer id) { return this.menuService.query(id); } - - - @ApiOperation("分页条件查询") + /** + * 分页条件查询菜单列表(仅查询一级菜单,同时关联子菜单) + * @param current 当前页码(默认第1页) + * @param size 每页条数(默认10条) + * @param name 菜单名称(模糊查询条件,可选) + * @return 统一响应结果(包含分页菜单列表) + */ + @ApiOperation("分页条件查询菜单") @GetMapping - @PreAuthorize("hasAnyAuthority('permission:menu:list','permission:menu:search')") + @PreAuthorize("hasAnyAuthority('permission:menu:list','permission:menu:search')") // 权限校验:需拥有菜单列表或查询权限 public ResponseDTO list(@RequestParam(defaultValue = "1") Integer current, @RequestParam(defaultValue = "10") Integer size, String name) { return this.menuService.list(current, size, name); } - @ApiOperation("数据导出接口") + /** + * 导出菜单数据到文件 + * @param response HTTP响应对象(用于输出文件流) + * @param filename 导出文件名 + * @throws IOException 可能的IO异常(如文件写入失败) + */ + @ApiOperation("导出菜单数据") @GetMapping("/export/{filename}") - @PreAuthorize("hasAnyAuthority('permission:menu:export')") + @PreAuthorize("hasAnyAuthority('permission:menu:export')") // 权限校验:需拥有菜单导出权限 public void export(HttpServletResponse response,@PathVariable String filename) throws IOException { - this.menuService.export(response,filename); + this.menuService.export(response,filename); } - @ApiOperation("数据导入接口") + /** + * 从文件导入菜单数据 + * @param file 上传的文件(包含菜单数据) + * @return 统一响应结果(导入成功/失败信息) + * @throws IOException 可能的IO异常(如文件读取失败) + */ + @ApiOperation("导入菜单数据") @PostMapping("/import") - @PreAuthorize("hasAnyAuthority('permission:menu:import')") + @PreAuthorize("hasAnyAuthority('permission:menu:import')") // 权限校验:需拥有菜单导入权限 public ResponseDTO imp(MultipartFile file) throws IOException { return this.menuService.imp(file); } - @ApiOperation("查询所有") + /** + * 查询所有启用状态的菜单,并构建树形结构(一级菜单包含二级菜单,二级菜单包含权限点) + * @return 统一响应结果(包含树形结构的菜单列表) + */ + @ApiOperation("查询所有菜单(树形结构)") @GetMapping("/all") public ResponseDTO queryAll(){ return this.menuService.queryAll(); } - @ApiOperation("获取员工的菜单") + /** + * 根据员工ID查询其拥有的菜单权限(树形结构) + * @param id 员工ID + * @return 统一响应结果(包含员工可访问的菜单列表) + */ + @ApiOperation("获取指定员工的菜单权限") @GetMapping("/staff/{id}") public ResponseDTO queryByStaffId(@PathVariable Integer id){ return this.menuService.queryByStaffId(id); } - @ApiOperation("查询权限") + /** + * 根据员工ID查询其拥有的权限标识集合(如"user:add"、"menu:delete") + * @param id 员工ID + * @return 统一响应结果(包含权限标识列表) + */ + @ApiOperation("查询指定员工的权限标识集合") @GetMapping("/permission/{id}") public ResponseDTO queryPermission(@PathVariable Integer id){ return this.menuService.queryPermission(id); } } - diff --git a/hrm/src/main/java/com/qiujie/controller/RoleController.java b/hrm/src/main/java/com/qiujie/controller/RoleController.java index 7de723d..05b4205 100644 --- a/hrm/src/main/java/com/qiujie/controller/RoleController.java +++ b/hrm/src/main/java/com/qiujie/controller/RoleController.java @@ -18,93 +18,154 @@ import java.util.List; /** *

- * 前端控制器 + * 角色管理模块前端控制器 + * 处理角色相关的HTTP请求,包括增删改查、权限分配等操作 *

* * @author qiujie * @since 2022-02-28 */ @RestController -@RequestMapping("/role") +@RequestMapping("/role") // 基础请求路径,所有接口均以/role开头 public class RoleController { + // 注入角色业务逻辑层对象 @Autowired private RoleService roleService; + // 注入角色-菜单关联业务逻辑层对象(用于处理角色与菜单的权限关联) @Autowired private RoleMenuService roleMenuService; - @ApiOperation("新增") + /** + * 新增角色 + * @param role 角色实体对象(包含角色名称、描述等信息) + * @return 统一响应结果(成功/失败信息) + */ + @ApiOperation("新增角色") @PostMapping - @PreAuthorize("hasAnyAuthority('permission:role:add')") + @PreAuthorize("hasAnyAuthority('permission:role:add')") // 权限校验:需拥有角色新增权限 public ResponseDTO add(@RequestBody Role role) { return this.roleService.add(role); } - @ApiOperation("逻辑删除") + /** + * 逻辑删除角色(非物理删除,仅标记删除状态) + * @param id 角色ID + * @return 统一响应结果 + */ + @ApiOperation("逻辑删除角色") @DeleteMapping("/{id}") - @PreAuthorize("hasAnyAuthority('permission:role:delete')") + @PreAuthorize("hasAnyAuthority('permission:role:delete')") // 权限校验:需拥有角色删除权限 public ResponseDTO delete(@PathVariable Integer id) { return this.roleService.delete(id); } - @ApiOperation("批量逻辑删除") + /** + * 批量逻辑删除角色 + * @param ids 角色ID列表 + * @return 统一响应结果 + */ + @ApiOperation("批量逻辑删除角色") @DeleteMapping("/batch/{ids}") - @PreAuthorize("hasAnyAuthority('permission:role:delete')") + @PreAuthorize("hasAnyAuthority('permission:role:delete')") // 权限校验:需拥有角色删除权限 public ResponseDTO deleteBatch(@PathVariable List ids) { return this.roleService.deleteBatch(ids); } - @ApiOperation("编辑更新") + /** + * 编辑更新角色信息 + * @param role 角色实体对象(包含更新后的角色信息) + * @return 统一响应结果 + */ + @ApiOperation("编辑更新角色") @PutMapping - @PreAuthorize("hasAnyAuthority('permission:role:edit')") + @PreAuthorize("hasAnyAuthority('permission:role:edit')") // 权限校验:需拥有角色编辑权限 public ResponseDTO edit(@RequestBody Role role) { return this.roleService.edit(role); } - @ApiOperation("查询") + /** + * 根据ID查询角色详情 + * @param id 角色ID + * @return 统一响应结果(包含角色详情) + */ + @ApiOperation("查询角色详情") @GetMapping("/{id}") public ResponseDTO query(@PathVariable Integer id) { return this.roleService.query(id); } - @ApiOperation("查询所有") + /** + * 查询所有角色(无分页) + * @return 统一响应结果(包含所有角色列表) + */ + @ApiOperation("查询所有角色") @GetMapping("/all") public ResponseDTO queryAll(){ return this.roleService.queryAll(); } - @ApiOperation("分页条件查询") + /** + * 分页条件查询角色列表 + * @param current 当前页码(默认第1页) + * @param size 每页条数(默认10条) + * @param name 角色名称(模糊查询条件,可选) + * @return 统一响应结果(包含分页角色列表) + */ + @ApiOperation("分页条件查询角色") @GetMapping - @PreAuthorize("hasAnyAuthority('permission:role:list','permission:role:search')") + @PreAuthorize("hasAnyAuthority('permission:role:list','permission:role:search')") // 权限校验:需拥有角色列表或查询权限 public ResponseDTO list(@RequestParam(defaultValue = "1") Integer current, @RequestParam(defaultValue = "10") Integer size, String name) { return this.roleService.list(current, size, name); } - @ApiOperation("数据导出接口") + /** + * 导出角色数据到文件 + * @param response HTTP响应对象(用于输出文件流) + * @param filename 导出文件名 + * @throws IOException 可能的IO异常(如文件写入失败) + */ + @ApiOperation("导出角色数据") @GetMapping("/export/{filename}") - @PreAuthorize("hasAnyAuthority('permission:role:export')") + @PreAuthorize("hasAnyAuthority('permission:role:export')") // 权限校验:需拥有角色导出权限 public void export(HttpServletResponse response,@PathVariable String filename) throws IOException { - this.roleService.export(response,filename); + this.roleService.export(response,filename); } - @ApiOperation("数据导入接口") + /** + * 从文件导入角色数据 + * @param file 上传的文件(包含角色数据) + * @return 统一响应结果(导入成功/失败信息) + * @throws IOException 可能的IO异常(如文件读取失败) + */ + @ApiOperation("导入角色数据") @PostMapping("/import") - @PreAuthorize("hasAnyAuthority('permission:role:import')") + @PreAuthorize("hasAnyAuthority('permission:role:import')") // 权限校验:需拥有角色导入权限 public ResponseDTO imp(MultipartFile file) throws IOException { return this.roleService.imp(file); } - @ApiOperation("为角色设置菜单") + /** + * 为指定角色分配菜单权限 + * @param id 角色ID + * @param menuIds 菜单ID列表(角色拥有的菜单权限) + * @return 统一响应结果 + */ + @ApiOperation("为角色设置菜单权限") @PostMapping("/set/{id}") - @PreAuthorize("hasAnyAuthority('permission:role:set_menu')") + @PreAuthorize("hasAnyAuthority('permission:role:set_menu')") // 权限校验:需拥有角色菜单分配权限 public ResponseDTO setMenu(@PathVariable Integer id, @RequestBody List menuIds){ return this.roleMenuService.setMenu(id, menuIds); } - @ApiOperation("得到角色所属的菜单") + /** + * 查询指定角色已拥有的菜单权限 + * @param id 角色ID + * @return 统一响应结果(包含角色拥有的菜单ID列表) + */ + @ApiOperation("查询角色所属的菜单权限") @GetMapping("/role/{id}") public ResponseDTO queryByRoleId(@PathVariable Integer id){ return this.roleMenuService.queryByRoleId(id); } -} - +} \ No newline at end of file diff --git a/hrm/src/main/java/com/qiujie/controller/SalaryController.java b/hrm/src/main/java/com/qiujie/controller/SalaryController.java index 962ee30..82d2ad5 100644 --- a/hrm/src/main/java/com/qiujie/controller/SalaryController.java +++ b/hrm/src/main/java/com/qiujie/controller/SalaryController.java @@ -14,80 +14,135 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; - /** - *

- * 前端控制器 - *

- * + * 薪资管理前端控制器 + * 处理员工薪资信息的增删改查、导入导出以及薪资设置等操作 + * 薪资信息包括基本工资、奖金、津贴、扣款等各项薪资组成 + * * @author qiujie * @since 2022-04-06 */ -@RestController -@RequestMapping("/salary") +@RestController // 标识为RESTful控制器,返回数据均为JSON格式 +@RequestMapping("/salary") // 定义基础请求路径为/salary public class SalaryController { - @Autowired + @Autowired // 自动注入薪资服务类 private SalaryService salaryService; + /** + * 新增薪资记录接口 + * @param salary 薪资实体对象,通过请求体传入 + * @return 操作结果响应 + */ @ApiOperation("新增") - @PostMapping + @PostMapping // 处理POST请求,路径为/salary public ResponseDTO add(@RequestBody Salary salary) { return this.salaryService.add(salary); } + /** + * 逻辑删除薪资记录接口 + * @param id 薪资记录ID,通过路径参数传入 + * @return 操作结果响应 + */ @ApiOperation("逻辑删除") - @DeleteMapping("/{id}") + @DeleteMapping("/{id}") // 处理DELETE请求,路径为/salary/{id} public ResponseDTO delete(@PathVariable Integer id) { return this.salaryService.delete(id); } + /** + * 批量逻辑删除薪资记录接口 + * @param ids 薪资记录ID列表,通过路径参数传入 + * @return 操作结果响应 + */ @ApiOperation("批量逻辑删除") - @DeleteMapping("/batch/{ids}") + @DeleteMapping("/batch/{ids}") // 处理DELETE请求,路径为/salary/batch/{ids} public ResponseDTO deleteBatch(@PathVariable List ids) { return this.salaryService.deleteBatch(ids); } + /** + * 编辑更新薪资记录接口 + * @param salary 薪资实体对象,通过请求体传入 + * @return 操作结果响应 + */ @ApiOperation("编辑更新") - @PutMapping + @PutMapping // 处理PUT请求,路径为/salary public ResponseDTO edit(@RequestBody Salary salary) { return this.salaryService.edit(salary); } + /** + * 根据ID查询薪资详情接口 + * @param id 薪资记录ID,通过路径参数传入 + * @return 薪资信息响应 + */ @ApiOperation("查询") - @GetMapping("/{id}") + @GetMapping("/{id}") // 处理GET请求,路径为/salary/{id} public ResponseDTO query(@PathVariable Integer id) { return this.salaryService.query(id); } + /** + * 分页条件查询薪资列表接口 + * @param current 当前页码,默认为1 + * @param size 每页大小,默认为10 + * @param name 员工姓名(模糊查询条件) + * @param deptId 部门ID(筛选条件) + * @param month 薪资月份(格式如:2024-01) + * @return 分页薪资列表响应 + */ @ApiOperation("分页条件查询") - @GetMapping - @PreAuthorize("hasAnyAuthority('money:salary:list','money:salary:search')") - public ResponseDTO list(@RequestParam(defaultValue = "1") Integer current, @RequestParam(defaultValue = "10") Integer size, String name, Integer deptId, String month) { + @GetMapping // 处理GET请求,路径为/salary + @PreAuthorize("hasAnyAuthority('money:salary:list','money:salary:search')") // 需要具备薪资列表查看或搜索权限 + public ResponseDTO list(@RequestParam(defaultValue = "1") Integer current, + @RequestParam(defaultValue = "10") Integer size, + String name, + Integer deptId, + String month) { return this.salaryService.list(current, size, name, deptId, month); } + /** + * 薪资数据导出接口 + * @param response HTTP响应对象,用于输出Excel文件 + * @param month 导出数据的月份,通过路径参数传入 + * @param filename 导出文件名,通过路径参数传入 + * @throws IOException 可能抛出IO异常 + */ @ApiOperation("数据导出接口") - @GetMapping("/export/{month}/{filename}") - @PreAuthorize("hasAnyAuthority('money:salary:export')") - public void export(HttpServletResponse response, @PathVariable String month,@PathVariable String filename) throws IOException { - this.salaryService.export(response, month,filename); + @GetMapping("/export/{month}/{filename}") // 处理GET请求,路径为/salary/export/{month}/{filename} + @PreAuthorize("hasAnyAuthority('money:salary:export')") // 需要具备薪资数据导出权限 + public void export(HttpServletResponse response, + @PathVariable String month, + @PathVariable String filename) throws IOException { + this.salaryService.export(response, month, filename); } + /** + * 薪资数据导入接口 + * @param file Excel文件对象,包含薪资数据 + * @return 导入结果响应 + * @throws IOException 可能抛出IO异常 + */ @ApiOperation("数据导入接口") - @PostMapping("/import") - @PreAuthorize("hasAnyAuthority('money:salary:import')") + @PostMapping("/import") // 处理POST请求,路径为/salary/import + @PreAuthorize("hasAnyAuthority('money:salary:import')") // 需要具备薪资数据导入权限 public ResponseDTO imp(MultipartFile file) throws IOException { return this.salaryService.imp(file); } + /** + * 设置员工薪资接口 + * 用于配置或调整员工的基本工资、岗位工资等固定薪资项 + * @param salary 薪资实体对象,通过请求体传入 + * @return 操作结果响应 + */ @ApiOperation("设置工资") - @PostMapping("/set") - @PreAuthorize("hasAnyAuthority('money:salary:set')") + @PostMapping("/set") // 处理POST请求,路径为/salary/set + @PreAuthorize("hasAnyAuthority('money:salary:set')") // 需要具备设置薪资权限 public ResponseDTO setSalary(@RequestBody Salary salary) { return this.salaryService.setSalary(salary); } - - -} - +} \ No newline at end of file diff --git a/hrm/src/main/java/com/qiujie/controller/SalaryDeductController.java b/hrm/src/main/java/com/qiujie/controller/SalaryDeductController.java index fe7bc3a..85d358b 100644 --- a/hrm/src/main/java/com/qiujie/controller/SalaryDeductController.java +++ b/hrm/src/main/java/com/qiujie/controller/SalaryDeductController.java @@ -11,69 +11,108 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.util.List; - /** - *

- * 工资扣除表 前端控制器 - *

- * + * 工资扣款管理前端控制器 + * 处理工资扣款规则的增删改查以及扣款规则设置等操作 + * 工资扣款包括罚款、缺勤扣款、社保公积金个人部分、个税等扣款项 + * * @author qiujie * @since 2022-03-27 */ -@RestController -@RequestMapping("/salary-deduct") +@RestController // 标识为RESTful控制器,返回数据均为JSON格式 +@RequestMapping("/salary-deduct") // 定义基础请求路径为/salary-deduct public class SalaryDeductController { - @Autowired + + @Autowired // 自动注入工资扣款服务类 private SalaryDeductService salaryDeductService; + /** + * 新增工资扣款规则接口 + * @param salaryDeduct 工资扣款实体对象,通过请求体传入 + * @return 操作结果响应 + */ @ApiOperation("新增") - @PostMapping + @PostMapping // 处理POST请求,路径为/salary-deduct public ResponseDTO add(@RequestBody SalaryDeduct salaryDeduct) { return this.salaryDeductService.add(salaryDeduct); } + /** + * 逻辑删除工资扣款规则接口 + * @param id 工资扣款记录ID,通过路径参数传入 + * @return 操作结果响应 + */ @ApiOperation("逻辑删除") - @DeleteMapping("/{id}") + @DeleteMapping("/{id}") // 处理DELETE请求,路径为/salary-deduct/{id} public ResponseDTO delete(@PathVariable Integer id) { return this.salaryDeductService.delete(id); } + /** + * 批量逻辑删除工资扣款规则接口 + * @param ids 工资扣款记录ID列表,通过路径参数传入 + * @return 操作结果响应 + */ @ApiOperation("批量逻辑删除") - @DeleteMapping("/batch/{ids}") + @DeleteMapping("/batch/{ids}") // 处理DELETE请求,路径为/salary-deduct/batch/{ids} public ResponseDTO deleteBatch(@PathVariable List ids) { return this.salaryDeductService.deleteBatch(ids); } + /** + * 编辑更新工资扣款规则接口 + * @param salaryDeduct 工资扣款实体对象,通过请求体传入 + * @return 操作结果响应 + */ @ApiOperation("编辑更新") - @PutMapping + @PutMapping // 处理PUT请求,路径为/salary-deduct public ResponseDTO edit(@RequestBody SalaryDeduct salaryDeduct) { return this.salaryDeductService.edit(salaryDeduct); } + /** + * 根据ID查询工资扣款详情接口 + * @param id 工资扣款记录ID,通过路径参数传入 + * @return 工资扣款信息响应 + */ @ApiOperation("查询") - @GetMapping("/{id}") + @GetMapping("/{id}") // 处理GET请求,路径为/salary-deduct/{id} public ResponseDTO query(@PathVariable Integer id) { return this.salaryDeductService.query(id); } + /** + * 根据部门ID和扣款类型编号查询工资扣款规则接口 + * @param deptId 部门ID,通过路径参数传入 + * @param typeNum 扣款类型编号,通过路径参数传入 + * @return 工资扣款信息响应 + */ @ApiOperation("获取") - @GetMapping("/{deptId}/{typeNum}") + @GetMapping("/{deptId}/{typeNum}") // 处理GET请求,路径为/salary-deduct/{deptId}/{typeNum} public ResponseDTO queryByDeptIdAndTypeNum(@PathVariable Integer deptId, @PathVariable Integer typeNum) { return this.salaryDeductService.queryByDeptIdAndTypeNum(deptId, typeNum); } + /** + * 设置部门罚款规则接口 + * 用于配置不同部门的罚款规则和扣款标准 + * @param salaryDeduct 工资扣款实体对象,包含罚款设置信息,通过请求体传入 + * @return 操作结果响应 + */ @ApiOperation("设置罚款") - @PostMapping("/set") - @PreAuthorize("hasAnyAuthority('system:department:setting')") + @PostMapping("/set") // 处理POST请求,路径为/salary-deduct/set + @PreAuthorize("hasAnyAuthority('system:department:setting')") // 需要具备部门设置权限 public ResponseDTO setSalaryDeduct(@RequestBody SalaryDeduct salaryDeduct) { return this.salaryDeductService.setSalaryDeduct(salaryDeduct); } + /** + * 查询所有工资扣款规则接口 + * @return 所有工资扣款规则列表响应 + */ @ApiOperation("获取所有") - @GetMapping("/all") + @GetMapping("/all") // 处理GET请求,路径为/salary-deduct/all public ResponseDTO queryAll() { return this.salaryDeductService.queryAll(); } - -} - +} \ No newline at end of file diff --git a/hrm/src/main/java/com/qiujie/controller/StaffController.java b/hrm/src/main/java/com/qiujie/controller/StaffController.java index f1a3799..a50d15c 100644 --- a/hrm/src/main/java/com/qiujie/controller/StaffController.java +++ b/hrm/src/main/java/com/qiujie/controller/StaffController.java @@ -1,6 +1,5 @@ package com.qiujie.controller; - import com.qiujie.dto.ResponseDTO; import com.qiujie.entity.Staff; import com.qiujie.service.StaffRoleService; @@ -17,107 +16,187 @@ import java.util.List; /** *

- * 前端控制器 + * 员工管理模块前端控制器 + * 负责处理员工的增删改查、角色分配、密码验证与重置、数据导入导出等请求 *

* * @author qiujie * @since 2022-01-27 */ -@RestController -@RequestMapping("/staff") +@RestController // 标识为REST风格控制器,返回JSON格式响应 +@RequestMapping("/staff") // 基础请求路径,所有接口路径前缀为/staff public class StaffController { + // 自动注入员工服务层对象,处理员工核心业务逻辑 @Autowired private StaffService staffService; + // 自动注入员工-角色关联服务层对象,处理员工角色分配相关业务 @Autowired private StaffRoleService staffRoleService; - @ApiOperation("新增") - @PostMapping - @PreAuthorize("hasAnyAuthority('system:staff:add')") + /** + * 新增员工 + * @param staff 员工实体对象(包含员工基本信息,通过请求体传递) + * @return 统一响应结果(操作状态、数据或错误信息) + */ + @ApiOperation("新增员工") // Swagger注解,描述接口功能 + @PostMapping // 接收POST请求,完整路径为/staff + @PreAuthorize("hasAnyAuthority('system:staff:add')") // 权限控制:仅拥有该权限的用户可访问 public ResponseDTO add(@RequestBody Staff staff) { return this.staffService.add(staff); } - @ApiOperation("逻辑删除") - @DeleteMapping("/{id}") - @PreAuthorize("hasAnyAuthority('system:staff:delete')") + /** + * 逻辑删除员工(仅标记删除状态,不物理删除数据) + * @param id 要删除的员工ID(通过URL路径传递) + * @return 统一响应结果 + */ + @ApiOperation("逻辑删除员工") + @DeleteMapping("/{id}") // 接收DELETE请求,完整路径为/staff/{id} + @PreAuthorize("hasAnyAuthority('system:staff:delete')") // 权限控制 public ResponseDTO delete(@PathVariable Integer id) { return this.staffService.delete(id); } - @ApiOperation("批量逻辑删除") - @DeleteMapping("/batch/{ids}") - @PreAuthorize("hasAnyAuthority('system:staff:delete')") + /** + * 批量逻辑删除员工 + * @param ids 要删除的员工ID列表(通过URL路径传递,多个ID用逗号分隔) + * @return 统一响应结果 + */ + @ApiOperation("批量逻辑删除员工") + @DeleteMapping("/batch/{ids}") // 接收DELETE请求,完整路径为/staff/batch/{ids} + @PreAuthorize("hasAnyAuthority('system:staff:delete')") // 权限控制 public ResponseDTO deleteBatch(@PathVariable List ids) { return this.staffService.deleteBatch(ids); } - @ApiOperation("编辑更新") - @PutMapping - @PreAuthorize("hasAnyAuthority('system:staff:edit','system:staff:enable')") + /** + * 编辑更新员工信息(含员工状态启用/禁用) + * @param staff 包含更新信息的员工实体(通过请求体传递) + * @return 统一响应结果 + */ + @ApiOperation("编辑更新员工信息") + @PutMapping // 接收PUT请求,完整路径为/staff + @PreAuthorize("hasAnyAuthority('system:staff:edit','system:staff:enable')") // 权限控制:拥有两个权限中的任意一个即可访问 public ResponseDTO edit(@RequestBody Staff staff) { return this.staffService.edit(staff); } - @ApiOperation("查询") - @GetMapping("/{id}") + /** + * 根据ID查询员工基础信息 + * @param id 员工ID(通过URL路径传递) + * @return 统一响应结果(包含查询到的员工基础信息) + */ + @ApiOperation("根据ID查询员工基础信息") + @GetMapping("/{id}") // 接收GET请求,完整路径为/staff/{id} public ResponseDTO query(@PathVariable Integer id) { return this.staffService.query(id); } - @ApiOperation("查询员工信息") - @GetMapping("/info/{id}") + /** + * 根据ID查询员工详细信息(可能包含关联的部门、角色等扩展信息) + * @param id 员工ID(通过URL路径传递) + * @return 统一响应结果(包含员工详细信息) + */ + @ApiOperation("根据ID查询员工详细信息") + @GetMapping("/info/{id}") // 接收GET请求,完整路径为/staff/info/{id} public ResponseDTO queryInfo(@PathVariable Integer id) { return this.staffService.queryInfo(id); } - @ApiOperation("多条件分页查询") - @GetMapping - @PreAuthorize("hasAnyAuthority('system:staff:list','system:staff:search')") - public ResponseDTO list(@RequestParam(defaultValue = "1") Integer current, @RequestParam(defaultValue = "10") Integer size, String name, String birthday, Integer deptId, Integer status) { + /** + * 多条件分页查询员工列表 + * @param current 当前页码(默认第1页) + * @param size 每页条数(默认10条) + * @param name 员工姓名(查询条件,可选) + * @param birthday 员工生日(查询条件,可选) + * @param deptId 所属部门ID(查询条件,可选) + * @param status 员工状态(查询条件,可选,如启用/禁用) + * @return 统一响应结果(包含分页查询结果) + */ + @ApiOperation("多条件分页查询员工列表") + @GetMapping // 接收GET请求,完整路径为/staff + @PreAuthorize("hasAnyAuthority('system:staff:list','system:staff:search')") // 权限控制 + public ResponseDTO list(@RequestParam(defaultValue = "1") Integer current, + @RequestParam(defaultValue = "10") Integer size, + String name, + String birthday, + Integer deptId, + Integer status) { return this.staffService.list(current, size, name, birthday, deptId, status); } - @ApiOperation("数据导出接口") - @GetMapping("/export/{filename}") - @PreAuthorize("hasAnyAuthority('system:staff:export')") + /** + * 员工数据导出接口(将员工数据导出为文件) + * @param response HTTP响应对象,用于输出文件流 + * @param filename 导出的文件名(通过URL路径传递) + * @throws IOException 可能抛出文件IO异常 + */ + @ApiOperation("员工数据导出接口") + @GetMapping("/export/{filename}") // 接收GET请求,完整路径为/staff/export/{filename} + @PreAuthorize("hasAnyAuthority('system:staff:export')") // 权限控制 public void export(HttpServletResponse response, @PathVariable String filename) throws IOException { this.staffService.export(response, filename); } - @ApiOperation("数据导入接口") - @PostMapping("/import") - @PreAuthorize("hasAnyAuthority('system:staff:import')") + /** + * 员工数据导入接口(从上传的文件导入员工数据) + * @param file 包含员工数据的上传文件 + * @return 统一响应结果(包含导入结果信息) + * @throws IOException 可能抛出文件读取异常 + */ + @ApiOperation("员工数据导入接口") + @PostMapping("/import") // 接收POST请求,完整路径为/staff/import + @PreAuthorize("hasAnyAuthority('system:staff:import')") // 权限控制 public ResponseDTO imp(MultipartFile file) throws IOException { return this.staffService.imp(file); } + /** + * 为员工分配角色 + * @param id 员工ID(通过URL路径传递) + * @param roleIds 角色ID列表(通过请求体传递,指定要分配的角色) + * @return 统一响应结果(包含角色分配结果) + */ @ApiOperation("为员工设置角色") - @PostMapping("/set/{id}") - @PreAuthorize("hasAnyAuthority('system:staff:set_role')") + @PostMapping("/set/{id}") // 接收POST请求,完整路径为/staff/set/{id} + @PreAuthorize("hasAnyAuthority('system:staff:set_role')") // 权限控制 public ResponseDTO setRole(@PathVariable Integer id, @RequestBody List roleIds) { return this.staffRoleService.setRole(id, roleIds); } - @ApiOperation("得到员工的角色") - @GetMapping("/staff/{id}") + /** + * 查询指定员工已分配的角色 + * @param id 员工ID(通过URL路径传递) + * @return 统一响应结果(包含员工的角色列表) + */ + @ApiOperation("查询员工已分配的角色") + @GetMapping("/staff/{id}") // 接收GET请求,完整路径为/staff/staff/{id} public ResponseDTO queryByStaffId(@PathVariable Integer id) { return this.staffRoleService.queryByStaffId(id); } - - @ApiOperation("检查员工的密码") - @GetMapping("/{pwd}/{id}") + /** + * 验证员工密码是否正确 + * @param pwd 待验证的密码(通过URL路径传递) + * @param id 员工ID(通过URL路径传递) + * @return 统一响应结果(包含密码验证结果) + */ + @ApiOperation("验证员工密码") + @GetMapping("/{pwd}/{id}") // 接收GET请求,完整路径为/staff/{pwd}/{id} public ResponseDTO validate(@PathVariable String pwd, @PathVariable Integer id) { return this.staffService.validate(pwd, id); } - @ApiOperation("更新密码") - @PutMapping("/reset") + /** + * 重置员工密码 + * @param staff 包含员工ID和新密码的实体对象(通过请求体传递) + * @return 统一响应结果(包含密码重置结果) + */ + @ApiOperation("重置员工密码") + @PutMapping("/reset") // 接收PUT请求,完整路径为/staff/reset public ResponseDTO reset(@RequestBody Staff staff) { return this.staffService.reset(staff); } -} - +} \ No newline at end of file diff --git a/hrm/src/main/java/com/qiujie/controller/StaffLeaveController.java b/hrm/src/main/java/com/qiujie/controller/StaffLeaveController.java index eefe552..fb6944c 100644 --- a/hrm/src/main/java/com/qiujie/controller/StaffLeaveController.java +++ b/hrm/src/main/java/com/qiujie/controller/StaffLeaveController.java @@ -30,6 +30,31 @@ public class StaffLeaveController { @Autowired private StaffLeaveService staffLeaveService; + // 考勤与休假管理子系统 - 后端注释(单行注释样式) + // 该注释块为开发人员C负责模块的详细说明,包含业务职责、边界、校验与 TODO 提示 + // 模块职责:考勤记录录入、请假/加班申请提交与审批、统计报表生成与导出 + // 边界与集成:与用户中心获取员工信息、与审批引擎交互生成审批任务、与薪资系统推送计薪数据 + // 权限控制:员工只能操作本人申请,主管/Hr/管理员按职责查看与审批 + // 事务边界:审批通过需在事务内同时更新申请表、审批日志与相关统计表 + // 并发安全:审批/撤回/修改等操作应使用乐观锁或分布式锁防止并发冲突 + // 输入校验:时间区间需合法(start < end),文本长度设限,防止注入 + // 时间处理:服务端统一使用 UTC 存储,前端在展示时转换为本地时区 + // 请假计算:计算天数时需考虑工作日与节假日规则,并支持小时制请假 + // 加班计算:区分普通工作日、周末与法定节假日,计算不同的补偿倍数 + // 审批流程:支持多级审批、会签与并行审批场景,并记录审批意见 + // 审批日志:每次审批记录审批人、时间、操作、意见与状态快照 + // 导出与审计:导出数据时记录导出人、时间与导出条件以便审计 + // 异常处理:服务层抛出业务异常,controller 层统一捕获并返回标准错误码 + // 性能注意:统计类接口应分页返回或使用预聚合表提高查询效率 + // 缓存策略:热点报表可缓存并设置合理的过期策略与手动刷新接口 + // 批量导入:提供预校验接口并返回错误详情,导入时按批次写入并记录失败行 + // 补卡流程:员工补卡需提供凭证并记录补卡来源以便人工核实 + // 幂等实现:提交申请时使用 requestId 保证幂等,审批更新使用受影响行数判断并发 + // Mapper 优化:对常用查询字段(employeeId,date)建立联合索引 + // 日志埋点:记录每次关键操作的上下文(用户、IP、请求参数摘要)以便追踪 + // TODO:添加审批超时处理策略并发送提醒到待审批人 + // TODO:在导入失败时生成可下载的错误明细供用户修正 + // 说明:如需更详细的逐行注释,可从 `file/attendance_leave_comments_java.txt` 引入到具体方法前 @ApiOperation("新增") @PostMapping public ResponseDTO add(@RequestBody StaffLeave staffLeave) { diff --git a/hrm/src/main/java/com/qiujie/entity/Menu.java b/hrm/src/main/java/com/qiujie/entity/Menu.java index 9207bea..d5d8213 100644 --- a/hrm/src/main/java/com/qiujie/entity/Menu.java +++ b/hrm/src/main/java/com/qiujie/entity/Menu.java @@ -18,70 +18,126 @@ import lombok.Data; /** *

- * + * 菜单权限实体类 + * 用于存储系统中的菜单、子菜单及权限点信息,支持多级菜单结构 *

* * @author qiujie * @since 2022-02-28 */ -@Data -@TableName("per_menu") -@ApiModel(value = "Menu对象", description = "") +@Data // Lombok注解,自动生成getter、setter、toString等方法 +@TableName("per_menu") // 对应数据库表名:per_menu(权限_菜单) +@ApiModel(value = "Menu对象", description = "系统菜单及权限点信息实体类") public class Menu implements Serializable { - @Serial + @Serial // 序列化版本号标识,用于对象序列化时的版本一致性校验 private static final long serialVersionUID = 1L; - @ApiModelProperty("菜单id") + /** + * 菜单主键ID + * 自增类型,唯一标识一条菜单/权限点记录 + */ + @ApiModelProperty("菜单id(主键)") @TableId(value = "id", type = IdType.AUTO) private Integer id; - @ApiModelProperty("菜单编码") + /** + * 菜单编码 + * 用于标识菜单的唯一编码,通常用于前端路由或权限判断 + */ + @ApiModelProperty("菜单编码(唯一标识)") @TableField("code") private String code; - @ApiModelProperty("菜单名称") + /** + * 菜单名称 + * 显示在前端的菜单名称,如"用户管理"、"角色配置"等 + */ + @ApiModelProperty("菜单名称(显示用)") @TableField("name") private String name; + /** + * 菜单图标 + * 前端显示的菜单图标标识(如FontAwesome图标类名) + */ @TableField("icon") private String icon; - @ApiModelProperty("权限标识") + /** + * 权限标识 + * 用于Spring Security权限控制的标识,如"user:list"、"role:add"等 + */ + @ApiModelProperty("权限标识(用于权限控制)") @TableField("permission") private String permission; + /** + * 父菜单ID + * 用于构建多级菜单结构,0表示当前菜单为根菜单(一级菜单) + */ @ApiModelProperty("父菜单id,0代表根菜单") @TableField("parent_id") private Integer parentId; + /** + * 菜单级别 + * 0:一级菜单(顶层菜单) + * 1:二级菜单(一级菜单的子菜单) + * 2:权限点(具体操作权限,如新增、删除按钮) + */ @ApiModelProperty("0一级菜单,1二级菜单,2权限点") @TableField("level") private Integer level; + /** + * 状态标识 + * 0:禁用(前端不显示,权限失效) + * 1:正常(默认值,可用状态) + */ @ApiModelProperty("权限点是否启用,0禁用、1正常,默认1") @TableField("status") private Integer status; - @ApiModelProperty("备注") + /** + * 备注信息 + * 存储菜单的额外说明,如用途、特殊规则等 + */ + @ApiModelProperty("备注信息") @TableField("remark") private String remark; - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") + /** + * 创建时间 + * 记录菜单的创建时间,JSON序列化时按指定格式显示 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") // 格式化日期时间,指定时区 @ApiModelProperty("创建时间") @TableField("create_time") private Timestamp createTime; - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8") + /** + * 更新时间 + * 记录菜单最后一次修改的时间,JSON序列化时按指定格式显示 + */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") @ApiModelProperty("更新时间") @TableField("update_time") private Timestamp updateTime; + /** + * 逻辑删除标记 + * MyBatis-Plus逻辑删除字段,0:未删除,1:已删除(查询时自动过滤已删除记录) + */ @TableField("is_deleted") - @TableLogic + @TableLogic // 标识为逻辑删除字段 private Integer deleteFlag; - @TableField(exist = false) + /** + * 子菜单列表 + * 非数据库字段(exist=false),用于在内存中存储当前菜单的子菜单,构建树形结构 + */ + @TableField(exist = false) // 标识该字段不对应数据库表列 private List children; } diff --git a/hrm/src/main/java/com/qiujie/entity/RoleMenu.java b/hrm/src/main/java/com/qiujie/entity/RoleMenu.java index 186aaf5..c256a9d 100644 --- a/hrm/src/main/java/com/qiujie/entity/RoleMenu.java +++ b/hrm/src/main/java/com/qiujie/entity/RoleMenu.java @@ -3,23 +3,20 @@ package com.qiujie.entity; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableLogic; import com.baomidou.mybatisplus.annotation.TableName; - -import java.io.Serial; -import java.io.Serializable; -import java.sql.Timestamp; - -import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Getter; import lombok.Setter; import lombok.experimental.Accessors; +import java.io.Serial; +import java.io.Serializable; + /** *

- * + * 角色与菜单关联表实体类 + * 用于存储角色和菜单之间的多对多映射关系,实现权限分配 *

* * @author qiujie @@ -27,22 +24,34 @@ import lombok.experimental.Accessors; */ @Getter @Setter -@Accessors(chain = true) -@TableName("per_role_menu") -@ApiModel(value = "RoleMenu对象", description = "") +@Accessors(chain = true) // 开启链式调用,支持setter方法连续赋值 +@TableName("per_role_menu") // 对应数据库表名:per_role_menu(权限_角色_菜单) +@ApiModel(value = "RoleMenu对象", description = "角色与菜单的关联关系实体") public class RoleMenu implements Serializable { - @Serial + @Serial // 序列化版本号标识,用于对象序列化时的版本一致性校验 private static final long serialVersionUID = 1L; + /** + * 主键ID + * 自增类型,唯一标识一条角色-菜单关联记录 + */ @TableId(value = "id", type = IdType.AUTO) private Integer id; - @ApiModelProperty("角色id") + /** + * 角色ID + * 关联角色表的主键,标识当前关联记录所属的角色 + */ + @ApiModelProperty("角色id,关联角色表主键") @TableField("role_id") private Integer roleId; - @ApiModelProperty("菜单id") + /** + * 菜单ID + * 关联菜单表的主键,标识当前角色拥有的菜单权限 + */ + @ApiModelProperty("菜单id,关联菜单表主键") @TableField("menu_id") private Integer menuId; -} +} \ No newline at end of file diff --git a/hrm/src/main/java/com/qiujie/service/MenuService.java b/hrm/src/main/java/com/qiujie/service/MenuService.java index 40cf6ca..539aeb0 100644 --- a/hrm/src/main/java/com/qiujie/service/MenuService.java +++ b/hrm/src/main/java/com/qiujie/service/MenuService.java @@ -21,7 +21,8 @@ import java.util.*; /** *

- * 服务类 + * 菜单权限服务实现类 + * 处理菜单的增删改查、树形结构构建、导入导出等业务逻辑 *

* * @author qiujie @@ -31,16 +32,27 @@ import java.util.*; public class MenuService extends ServiceImpl { @Autowired - private MenuMapper menuMapper; + private MenuMapper menuMapper; // 注入菜单数据访问层对象 + /** + * 新增菜单 + * @param menu 菜单实体对象 + * @return 统一响应结果(成功/失败) + */ public ResponseDTO add(Menu menu) { + // 调用MyBatis-Plus的save方法保存菜单,成功返回成功响应,否则返回失败响应 if (save(menu)) { return Response.success(); } return Response.error(); } + /** + * 根据ID删除菜单(逻辑删除,依赖MyBatis-Plus的逻辑删除配置) + * @param id 菜单ID + * @return 统一响应结果 + */ public ResponseDTO delete(Integer id) { if (removeById(id)) { return Response.success(); @@ -48,7 +60,12 @@ public class MenuService extends ServiceImpl { return Response.error(); } - @Transactional(rollbackFor = Exception.class) + /** + * 批量删除菜单(逻辑删除) + * @param ids 菜单ID列表 + * @return 统一响应结果 + */ + @Transactional(rollbackFor = Exception.class) // 声明事务,发生异常时回滚 public ResponseDTO deleteBatch(List ids) { if (removeBatchByIds(ids)) { return Response.success(); @@ -57,6 +74,11 @@ public class MenuService extends ServiceImpl { } + /** + * 编辑更新菜单信息 + * @param menu 包含更新信息的菜单实体 + * @return 统一响应结果 + */ public ResponseDTO edit(Menu menu) { if (updateById(menu)) { return Response.success(); @@ -65,6 +87,11 @@ public class MenuService extends ServiceImpl { } + /** + * 根据ID查询菜单详情 + * @param id 菜单ID + * @return 统一响应结果(包含菜单详情) + */ public ResponseDTO query(Integer id) { Menu menu = getById(id); if (menu != null) { @@ -74,23 +101,26 @@ public class MenuService extends ServiceImpl { } /** - * 查找所有菜单 - * - * @return + * 查找所有启用状态的菜单,并构建树形结构(一级菜单包含二级菜单,二级菜单包含权限点) + * @return 统一响应结果(包含树形结构的菜单列表) */ public ResponseDTO queryAll() { + // 查询所有状态为"正常"(1)的菜单 List list = list(new QueryWrapper().eq("status",1)); - // 为父级菜单设置子菜单 - // 一级菜单 + + // 筛选一级菜单(level=0) List firstList = list.stream().parallel() .filter(menu -> menu.getLevel() == 0).toList(); + + // 为一级菜单设置二级菜单 for (Menu firstMenu : firstList) { - // 二级菜单 + // 筛选当前一级菜单的二级菜单(parentId=一级菜单ID,level=1) List secondList = list.stream().parallel() .filter(menu -> Objects.equals(menu.getParentId(), firstMenu.getId())).toList(); firstMenu.setChildren(secondList); + + // 为二级菜单设置权限点(level=2) for (Menu secondMenu : secondList) { - // 权限点 List thirdList = list.stream().parallel() .filter(menu -> Objects.equals(menu.getParentId(), secondMenu.getId())).toList(); secondMenu.setChildren(thirdList); @@ -100,28 +130,45 @@ public class MenuService extends ServiceImpl { } + /** + * 分页条件查询菜单(仅查询一级菜单,同时关联查询其子菜单) + * @param current 当前页码 + * @param size 每页条数 + * @param name 菜单名称(模糊查询条件) + * @return 统一响应结果(包含分页信息和树形菜单列表) + */ public ResponseDTO list(Integer current, Integer size, String name) { + // 构建分页对象 IPage config = new Page<>(current, size); QueryWrapper wrapper = new QueryWrapper<>(); + + // 若名称不为空,添加模糊查询条件 if (name != "" && name != null) { wrapper.like("name", name); } + // 仅查询一级菜单(level=0) wrapper.eq("level", 0); + + // 执行分页查询 IPage page = page(config, wrapper); + // 查询所有非一级菜单(用于构建子菜单) List list = list(new QueryWrapper().ne("level", 0)); - // 菜单 + + // 为一级菜单设置子菜单 List firstList = page.getRecords(); for (Menu firstMenu : firstList) { - // 设置子菜单 + // 筛选二级菜单 List secondList = list.stream().filter(menu -> Objects.equals(menu.getParentId(), firstMenu.getId())).toList(); firstMenu.setChildren(secondList); + + // 为二级菜单设置权限点 for (Menu secondMenu : secondList) { - // 设置子菜单 List thirdList = list.stream().filter(menu -> Objects.equals(menu.getParentId(), secondMenu.getId())).toList(); secondMenu.setChildren(thirdList); } } - // 将响应数据填充到map中 + + // 封装分页结果(总页数、总条数、菜单列表) Map map = new HashMap(); map.put("pages", page.getPages()); map.put("total", page.getTotal()); @@ -130,40 +177,50 @@ public class MenuService extends ServiceImpl { } /** - * 数据导出 - * - * @param response - * @return + * 导出菜单数据到Excel文件 + * @param response HTTP响应对象(用于输出文件流) + * @param filename 导出文件名 + * @throws IOException IO异常(如文件写入失败) */ public void export(HttpServletResponse response, String filename) throws IOException { + // 查询所有菜单 List list = list(); + // 调用工具类导出Excel HutoolExcelUtil.writeExcel(response, list, filename, Menu.class); } /** - * 数据导入 - * - * @param file - * @return + * 从Excel文件导入菜单数据 + * @param file 上传的Excel文件 + * @return 统一响应结果 + * @throws IOException IO异常(如文件读取失败) */ - @Transactional(rollbackFor = Exception.class) + @Transactional(rollbackFor = Exception.class) // 声明事务,确保批量插入的原子性 public ResponseDTO imp(MultipartFile file) throws IOException { InputStream inputStream = file.getInputStream(); + // 调用工具类读取Excel(从第2行开始读取,跳过表头) List list = HutoolExcelUtil.readExcel(inputStream, 1, Menu.class); - // IService接口中的方法.批量插入数据 + // 批量插入数据 if (saveBatch(list)) { return Response.success(); } return Response.error(); } + /** + * 根据员工ID查询其拥有的菜单权限(构建树形结构) + * @param id 员工ID + * @return 统一响应结果(包含员工可访问的树形菜单) + */ public ResponseDTO queryByStaffId(Integer id) { + // 通过mapper查询该员工拥有的所有菜单 List list = this.menuMapper.queryByStaffId(id); - // 一级菜单 + + // 筛选一级菜单并构建树形结构 List firstList = list.stream().parallel() .filter(menu -> menu.getLevel() == 0).toList(); for (Menu firstMenu : firstList) { - // 二级菜单 + // 为一级菜单设置二级菜单 List secondList = list.stream().parallel() .filter(menu -> Objects.equals(menu.getParentId(), firstMenu.getId())).toList(); firstMenu.setChildren(secondList); @@ -172,11 +229,12 @@ public class MenuService extends ServiceImpl { } + /** + * 根据员工ID查询其拥有的权限标识集合(如"user:add"、"role:delete") + * @param id 员工ID + * @return 统一响应结果(包含权限标识列表) + */ public ResponseDTO queryPermission(Integer id){ return Response.success(this.menuMapper.queryPermission(id)); } -} - - - - +} \ No newline at end of file diff --git a/vue-elementui-hrm%2Fsrc%2Fapi/attendance.js b/vue-elementui-hrm%2Fsrc%2Fapi/attendance.js new file mode 100644 index 0000000..f31eb1d --- /dev/null +++ b/vue-elementui-hrm%2Fsrc%2Fapi/attendance.js @@ -0,0 +1,194 @@ +// 考勤与休假管理子系统 - 前端注释汇总(JS 风格单行注释) +// 该文件包含前端 api、views、components、store 的注释示例,便于开发人员C在前端代码中粘贴 +// 注:全部使用单行注释,覆盖接口说明、参数说明、返回值说明、前端校验、错误提示与 UX 建议 +// 文件:src/api/attendance.js - 说明:考勤记录相关的 API 封装 +// 方法:getAttendanceRecords(params) - 说明:按时间/员工/状态查询打卡记录 +// 参数说明:params={ employeeId, startDate, endDate, page, size } +// 返回说明:{ code, message, data: { total, list } } +// 错误处理:网络或服务器错误应在页面展示友好提示并支持重试 +// UX 提示:分页切换时应保留过滤条件并支持快速导出当前查询结果 +// 方法:checkIn(payload) - 说明:员工端打卡接口,payload 包含 timestamp, source +// 校验:前端应确保 timestamp 为合法时间且不早于系统允许的最早打卡时间 +// 备注:打卡成功后应即时反馈状态并同步更新本地考勤视图 +// 组件职责:展示员工每天的考勤状态、支持点击日查看详情 +// 组件输入:props: { year, month, employeeId } +// 组件输出:事件 dayClick(day) 当用户点击某天时触发 +// 组件 UX:异常日期以警告色显示并支持快速发起修正或申请 +// store 模块:src/store/modules/attendance.js - 说明:全局考勤状态管理 +// state 示例:{ records: [], stats: {}, loading: false } +// action 示例:fetchAttendanceRecords({ commit }, params) - 说明:调用 attendance API 并 commit 结果 +// mutation 示例:setRecords, setStats, setLoading +// 页面职责:提供多维度筛选、分页、导出功能与行级操作(如修正/详情) +// 表格列建议:员工姓名、日期、上班时间、下班时间、状态、异常标识、操作 +// 校验提示:申请提交前在 UI 提示预计天数与可能的审批耗时 +// 错误展示:对常见错误(如余额不足、时间冲突)提供明确的用户提示 +// 前端表单校验:使用 form rules 校验必填项、时间范围与长度限制 +// 提示文案示例:"开始时间不能晚于结束时间"、"请填写请假理由(至少 10 字)" +// 提交态 UX:提交后按钮置为 loading,防止重复提交 +// 撤回申请:提供撤回入口并在撤回前弹出二次确认 +// 审批状态展示:用颜色区分 PENDING/APPROVED/REJECTED +// 审批意见:在详情页显示审批人、审批时间与审批意见 +// 前端权限:前端仅做展示与控制,核心权限校验由后端完成 +// API 错误处理:统一在 request.js 中处理错误码并抛出友好错误提示 +// request.js 注释:封装 axios,处理 token 注入、重试与错误拦截 +// request.js 建议:对 401 做登出并跳转到登录页,对 429 提示限流并重试 +// 前端缓存:对静态枚举如假期类型可在 localStorage 缓存以减少请求 +// 列表组件:在表格中添加批量操作复选框以支持批量审批(HR 视图) +// 导出功能:提供导出进度提示并在后台完成后提供下载链接 +// 表单提示:对关键字段添加 hover 帮助文案说明其含义与限制 +// 国际化:前端提示文本使用 i18n,避免硬编码中文 +// Accessibility:关键操作按钮需有 aria-label 属性提高可访问性 +// Loading 状态:对长时间接口使用 skeleton 或 loading spinner 提升体验 +// debounce:输入过滤框使用防抖以减少不必要的请求 +// 组件复用:将通用的日期范围选择器、员工选择器抽象为独立组件 +// 组件示例: +// 前端测试:为核心逻辑添加单元测试(如日期计算、表单校验) +// E2E 测试:编写用户场景测试,如提交请假 -> 审批 -> 状态变更 +// 兼容性:在低版本浏览器上测试日期控件与文件导出功能 +// 打卡页面 UX:在网络不佳时允许离线打卡并在恢复网络后同步 +// 离线打卡注意:需要前端生成加密的本地记录以便验证真伪 +// 打卡定位提示:提示用户允许定位权限以便展示外勤位置信息 +// 打卡异常提示:当连续多次打卡失败提示用户联系管理员 +// 年假余额展示:在申请表单中实时展示员工剩余年假 +// 表格性能:对大数据使用虚拟滚动或分页减轻渲染压力 +// 组件懒加载:按需加载重型组件如大量图表或导出组件 +// 图表组件:使用 ECharts 或类似库展示月度出勤趋势 +// 图表数值来源:优先使用已聚合的统计接口而不是前端自行计算 +// 公共样式:考勤异常使用统一颜色变量,放在 `_variable.scss` 中维护 +// 日期工具:使用 utils/date.js 统一处理日期格式化与计算 +// date.js 方法示例:formatDate(date, format), diffInDays(start, end), isWorkday(date) +// 权限前端校验:在展示操作按钮前判断用户角色并隐藏不可用的操作 +// 前端路由:将考勤相关页面放到 `/attendance` 路径下便于管理 +// 面包屑:在页面顶部展示导航以便用户快速返回父级页面 +// 响应式设计:确保考勤日历在移动端也能友好展示 +// 列表过滤:支持按状态、时间、员工、部门等组合过滤 +// 复核功能:为 HR 提供批量复核入口并记录复核结果 +// 交互示例:点击异常项弹出详情对话框并提供修正/补卡入口 +// 错误码映射:将后端错误码映射为前端友好提示文案 +// retry 策略:对偶发的网络错误可在 request.js 中实现自动重试 +// token 失效处理:全局拦截 401,提示重新登录并清理本地缓存 +// 文件示例:src/api/attendance.js +// UI 错误提示示例:this.$message.error('提交失败:开始时间不能晚于结束时间') +// Form 提示示例:{ required: true, message: '请选择请假类型', trigger: 'change' } +// 前端分页注意:使用 total 字段做分页控件的总数,避免后端分页偏差 +// 组件通信:使用事件与 prop 传递,避免过度使用全局状态 +// store 性能:避免在 state 中存放大量不可变的大数组,可在需要时按需加载 +// 复用 API:对于相似查询使用通用方法并在参数中传入区分字段 +// 前端缓存失效:在关键配置更新后主动清理本地缓存以保持一致 +// 认证方式:前端使用 token 放入 header 并定期刷新 token +// 文件大小限制:上传请假附件时对单个文件大小限制在 10MB 内 +// 前端分页大小建议:默认为 10/20/50 可供选择 +// 视觉提示:审批流中的通过/拒绝使用明显颜色区分以提升可读性 +// 权限提示:当用户没有权限执行操作时展示禁用状态与原因提示 +// 前端测试建议:使用 Jest 或 Vue Test Utils 编写单元测试 +// E2E 场景建议:使用 Cypress 或 Nightwatch 覆盖用户提交申请与审批流程 +// 国际化示例:this.$t('attendance.applySuccess') 在语言包中维护文案 +// 表单自动保存:在填写申请表单时周期性保存草稿防止意外丢失 +// 草稿功能:支持恢复草稿并在提交后删除草稿记录 +// 细节提示:若为长时间假期,前端应提醒用户核对开始与结束日期 +// 时间输入控件:采用带时分的日期时间选择器以提高精度 +// 前端导入:提供模板下载并在导入前做严格校验反馈错误行 +// UX 建议:在审批通过/拒绝时提供可复制的审批编号以便沟通 +// 组件加载策略:对于图表类组件采用动态 import 提升首屏速度 +// API 兼容策略:在后端返回字段新增时前端应采用安全访问方式如 data?.newField +// 错误回退:在关键接口失败时提供降级显示而非整页报错 +// 前端日志:收集前端异常并上报以便定位问题(不要上报敏感数据) +// 可配置化:将常量(如假期类型、审批角色)放到配置中心或接口下发 +// 国际化注意:日期格式化需根据 locale 进行展示转换 +// 安全提示:前端避免在日志或错误上打印完整 token +// 表单自动校验:在用户填写关键字段时实时进行校验并给出友好建议 +// 性能监控:使用前端监控工具跟踪慢接口并建立告警 +// 前端缓存策略示例:枚举缓存 24h,用户数据缓存 5 分钟 +// 请求防抖:对于模糊查询输入使用防抖以减少请求量 +// Accessibility:表单控件需支持键盘导航与屏幕阅读器 +// 代码示例:async function applyLeave(payload) { /* ... */ } +// 在前端页面上显示审批历史时,建议按时间倒序展示最新审批在顶端 +// 表格导出示例:点击导出时先调用后台导出接口并轮询导出任务状态 +// 导出成功后在页面展示下载链接并记录导出日志 +// 批量审批 UX:提供预览并显示每条的审批建议与可能问题 +// 错误示例提示:"该时间段已有已批准的请假,请先撤销或联系 HR" +// 如果需要我把这些注释直接插入到其它前端文件(如 src/api/leave.js),请告知。 + +import request from '../utils/request' + +const url = '/attendance' + +/** + * 添加 + * @param data + * @returns {AxiosPromise} + */ +export const add = (data) => { + return request({ + url: url, method: 'post', data + }) +} + +/** + * 逻辑删除 + * @param id + * @returns {AxiosPromise} + */ +export const del = (id) => { + return request({ + url: url + '/' + id, method: 'delete' + }) +} + +export const deleteBatch = (ids) => { + return request({ + url: url + '/batch/' + ids, method: 'delete' + }) +} + +export const edit = (data) => { + return request({ + url: url, method: 'put', data + }) +} + +// 查询所有 +export const queryAll = () => { + return request({ + url: url + '/all' + }) +} + +// 得到一条数据 +export const query = (id) => { + return request({ + url: url + '/' + id + }) +} + +export const queryByStaffIdAndDate = (id, date) => { + return request({ + url: url + '/' + id + '/' + date + }) +} + +// 查询 +export const list = (params) => { + return request({ + url: url, method: 'get', params + }) +} + +export const setAttendance = (data) => { + return request({ + url: url + '/set', method: 'put', data + }) +} +export const exp = (month, filename) => { + return request({ + url: url + '/export/' + month + '/' + filename, + method: 'get', + responseType: 'blob' + }) +} + +// 得到一条数据 +// 数据导入 +export const getImportApi = () => { + return process.env.VUE_APP_HOST + ':' + process.env.VUE_APP_PORT + url + '/import' +} diff --git a/vue-elementui-hrm%2Fsrc%2Fapi/leave.js b/vue-elementui-hrm%2Fsrc%2Fapi/leave.js new file mode 100644 index 0000000..62caa75 --- /dev/null +++ b/vue-elementui-hrm%2Fsrc%2Fapi/leave.js @@ -0,0 +1,42 @@ +// 前端考勤与休假子系统注释(自动注入) +// 该注释为前端 API 文件提供说明:方法、参数、返回、校验与 UX 建议 +// 方法:queryByDeptIdAndTypeNum(deptId,typeNum) - 查询指定部门与类型的请假规则 +// 方法:setLeave(data) - 管理端设置请假类型与规则,需要管理员权限 +// 方法:queryByDeptId(deptId) - 查询某部门的请假规则 +// 方法:queryAll() - 查询所有请假类型用于前端下拉展示 +// 前端校验:在提交设置时校验名称唯一性、最大天数为非负整数 +// 错误处理:统一通过 request.js 的拦截器处理错误并弹出友好提示 +// UX:设置页面应在保存成功后提示并刷新下拉缓存 + +import request from '../utils/request' + +const url = '/leave' + +// 得到 +export const queryByDeptIdAndTypeNum = (deptId, typeNum) => { + return request({ + url: url + '/' + deptId + '/' + typeNum + }) +} + +export const setLeave = (data) => { + return request({ + url: url + '/set', + method: 'post', + data + }) +} + +// 得到 +export const queryByDeptId = (deptId) => { + return request({ + url: url + '/dept/' + deptId + }) +} + +// 查询所有请假类型 +export const queryAll = () => { + return request({ + url: url + '/all' + }) +} diff --git a/vue-elementui-hrm%2Fsrc%2Fapi/staffLeave.js b/vue-elementui-hrm%2Fsrc%2Fapi/staffLeave.js new file mode 100644 index 0000000..2e9322d --- /dev/null +++ b/vue-elementui-hrm%2Fsrc%2Fapi/staffLeave.js @@ -0,0 +1,115 @@ +// 前端员工请假 API 注释(自动注入) +// 说明:该文件封装员工请假相关接口,包括提交申请、查询、撤回与审批任务操作 +// apply(data, code) - 员工提交请假申请,返回申请编号与初始状态 +// claim(data, code) - 审批人拾取任务进行审批处理 +// revert(data, code) - 审批人归还任务,供他人拾取 +// complete(data, code) - 审批人完成审批任务并写入审批意见 +// cancel(data) - 员工撤销请假申请,需校验当前审批进度是否允许撤销 +// 前端校验示例:检查 startTime < endTime、理由长度、年假余额等 +// 提交后 UX:展示申请编号并提示预计审批时间 +// 错误处理:统一在 request.js 中拦截并展示友好提示 + +import request from '../utils/request' + +const url = '/staff-leave' + +/** + * 添加 + * @param data + * @returns {AxiosPromise} + */ +export const add = (data) => { + return request({ + url: url, method: 'post', data + }) +} + +/** + * 逻辑删除 + * @param id + * @returns {AxiosPromise} + */ +export const del = (id) => { + return request({ + url: url + '/' + id, method: 'delete' + }) +} + +export const deleteBatch = (ids) => { + return request({ + url: url + '/batch/' + ids, method: 'delete' + }) +} + +export const edit = (data) => { + return request({ + url: url, method: 'put', data + }) +} + +export const list = (params) => { + return request({ + url: url, method: 'get', params + }) +} + +export const queryByStaffId = (params) => { + return request({ + url: url + '/staff', method: 'get', params + }) +} + +// 获得所有 +export const queryAll = () => { + return request({ + url: url + '/all' + }) +} + +export const exp = (filename) => { + return request({ + url: url + '/export/' + filename, + method: 'get', + responseType: 'blob' + }) +} + +// 数据导入 +export const getImportApi = () => { + return process.env.VUE_APP_HOST + ':' + process.env.VUE_APP_PORT + url + '/import' +} + +// 请假 +export const apply = (data, code) => { + return request({ + url: url + '/apply/' + code, method: 'post', data + }) +} + +// 拾取任务 +export const claim = (data, code) => { + return request({ + url: url + '/claim/' + code, method: 'post', data + }) +} + +// 归还任务 +export const revert = (data, code) => { + return request({ + url: url + '/revert/' + code, method: 'post', data + }) +} + +// 完成任务 +export const complete = (data, code) => { + return request({ + url: url + '/complete/' + code, method: 'post', data + }) +} + +// 撤销请假 +export const cancel = (data) => { + return request({ + url: url + '/cancel', method: 'post', data + }) +} diff --git a/vue-elementui-hrm/src/api/attendance.js b/vue-elementui-hrm/src/api/attendance.js index 823729f..f31eb1d 100644 --- a/vue-elementui-hrm/src/api/attendance.js +++ b/vue-elementui-hrm/src/api/attendance.js @@ -1,3 +1,114 @@ +// 考勤与休假管理子系统 - 前端注释汇总(JS 风格单行注释) +// 该文件包含前端 api、views、components、store 的注释示例,便于开发人员C在前端代码中粘贴 +// 注:全部使用单行注释,覆盖接口说明、参数说明、返回值说明、前端校验、错误提示与 UX 建议 +// 文件:src/api/attendance.js - 说明:考勤记录相关的 API 封装 +// 方法:getAttendanceRecords(params) - 说明:按时间/员工/状态查询打卡记录 +// 参数说明:params={ employeeId, startDate, endDate, page, size } +// 返回说明:{ code, message, data: { total, list } } +// 错误处理:网络或服务器错误应在页面展示友好提示并支持重试 +// UX 提示:分页切换时应保留过滤条件并支持快速导出当前查询结果 +// 方法:checkIn(payload) - 说明:员工端打卡接口,payload 包含 timestamp, source +// 校验:前端应确保 timestamp 为合法时间且不早于系统允许的最早打卡时间 +// 备注:打卡成功后应即时反馈状态并同步更新本地考勤视图 +// 组件职责:展示员工每天的考勤状态、支持点击日查看详情 +// 组件输入:props: { year, month, employeeId } +// 组件输出:事件 dayClick(day) 当用户点击某天时触发 +// 组件 UX:异常日期以警告色显示并支持快速发起修正或申请 +// store 模块:src/store/modules/attendance.js - 说明:全局考勤状态管理 +// state 示例:{ records: [], stats: {}, loading: false } +// action 示例:fetchAttendanceRecords({ commit }, params) - 说明:调用 attendance API 并 commit 结果 +// mutation 示例:setRecords, setStats, setLoading +// 页面职责:提供多维度筛选、分页、导出功能与行级操作(如修正/详情) +// 表格列建议:员工姓名、日期、上班时间、下班时间、状态、异常标识、操作 +// 校验提示:申请提交前在 UI 提示预计天数与可能的审批耗时 +// 错误展示:对常见错误(如余额不足、时间冲突)提供明确的用户提示 +// 前端表单校验:使用 form rules 校验必填项、时间范围与长度限制 +// 提示文案示例:"开始时间不能晚于结束时间"、"请填写请假理由(至少 10 字)" +// 提交态 UX:提交后按钮置为 loading,防止重复提交 +// 撤回申请:提供撤回入口并在撤回前弹出二次确认 +// 审批状态展示:用颜色区分 PENDING/APPROVED/REJECTED +// 审批意见:在详情页显示审批人、审批时间与审批意见 +// 前端权限:前端仅做展示与控制,核心权限校验由后端完成 +// API 错误处理:统一在 request.js 中处理错误码并抛出友好错误提示 +// request.js 注释:封装 axios,处理 token 注入、重试与错误拦截 +// request.js 建议:对 401 做登出并跳转到登录页,对 429 提示限流并重试 +// 前端缓存:对静态枚举如假期类型可在 localStorage 缓存以减少请求 +// 列表组件:在表格中添加批量操作复选框以支持批量审批(HR 视图) +// 导出功能:提供导出进度提示并在后台完成后提供下载链接 +// 表单提示:对关键字段添加 hover 帮助文案说明其含义与限制 +// 国际化:前端提示文本使用 i18n,避免硬编码中文 +// Accessibility:关键操作按钮需有 aria-label 属性提高可访问性 +// Loading 状态:对长时间接口使用 skeleton 或 loading spinner 提升体验 +// debounce:输入过滤框使用防抖以减少不必要的请求 +// 组件复用:将通用的日期范围选择器、员工选择器抽象为独立组件 +// 组件示例: +// 前端测试:为核心逻辑添加单元测试(如日期计算、表单校验) +// E2E 测试:编写用户场景测试,如提交请假 -> 审批 -> 状态变更 +// 兼容性:在低版本浏览器上测试日期控件与文件导出功能 +// 打卡页面 UX:在网络不佳时允许离线打卡并在恢复网络后同步 +// 离线打卡注意:需要前端生成加密的本地记录以便验证真伪 +// 打卡定位提示:提示用户允许定位权限以便展示外勤位置信息 +// 打卡异常提示:当连续多次打卡失败提示用户联系管理员 +// 年假余额展示:在申请表单中实时展示员工剩余年假 +// 表格性能:对大数据使用虚拟滚动或分页减轻渲染压力 +// 组件懒加载:按需加载重型组件如大量图表或导出组件 +// 图表组件:使用 ECharts 或类似库展示月度出勤趋势 +// 图表数值来源:优先使用已聚合的统计接口而不是前端自行计算 +// 公共样式:考勤异常使用统一颜色变量,放在 `_variable.scss` 中维护 +// 日期工具:使用 utils/date.js 统一处理日期格式化与计算 +// date.js 方法示例:formatDate(date, format), diffInDays(start, end), isWorkday(date) +// 权限前端校验:在展示操作按钮前判断用户角色并隐藏不可用的操作 +// 前端路由:将考勤相关页面放到 `/attendance` 路径下便于管理 +// 面包屑:在页面顶部展示导航以便用户快速返回父级页面 +// 响应式设计:确保考勤日历在移动端也能友好展示 +// 列表过滤:支持按状态、时间、员工、部门等组合过滤 +// 复核功能:为 HR 提供批量复核入口并记录复核结果 +// 交互示例:点击异常项弹出详情对话框并提供修正/补卡入口 +// 错误码映射:将后端错误码映射为前端友好提示文案 +// retry 策略:对偶发的网络错误可在 request.js 中实现自动重试 +// token 失效处理:全局拦截 401,提示重新登录并清理本地缓存 +// 文件示例:src/api/attendance.js +// UI 错误提示示例:this.$message.error('提交失败:开始时间不能晚于结束时间') +// Form 提示示例:{ required: true, message: '请选择请假类型', trigger: 'change' } +// 前端分页注意:使用 total 字段做分页控件的总数,避免后端分页偏差 +// 组件通信:使用事件与 prop 传递,避免过度使用全局状态 +// store 性能:避免在 state 中存放大量不可变的大数组,可在需要时按需加载 +// 复用 API:对于相似查询使用通用方法并在参数中传入区分字段 +// 前端缓存失效:在关键配置更新后主动清理本地缓存以保持一致 +// 认证方式:前端使用 token 放入 header 并定期刷新 token +// 文件大小限制:上传请假附件时对单个文件大小限制在 10MB 内 +// 前端分页大小建议:默认为 10/20/50 可供选择 +// 视觉提示:审批流中的通过/拒绝使用明显颜色区分以提升可读性 +// 权限提示:当用户没有权限执行操作时展示禁用状态与原因提示 +// 前端测试建议:使用 Jest 或 Vue Test Utils 编写单元测试 +// E2E 场景建议:使用 Cypress 或 Nightwatch 覆盖用户提交申请与审批流程 +// 国际化示例:this.$t('attendance.applySuccess') 在语言包中维护文案 +// 表单自动保存:在填写申请表单时周期性保存草稿防止意外丢失 +// 草稿功能:支持恢复草稿并在提交后删除草稿记录 +// 细节提示:若为长时间假期,前端应提醒用户核对开始与结束日期 +// 时间输入控件:采用带时分的日期时间选择器以提高精度 +// 前端导入:提供模板下载并在导入前做严格校验反馈错误行 +// UX 建议:在审批通过/拒绝时提供可复制的审批编号以便沟通 +// 组件加载策略:对于图表类组件采用动态 import 提升首屏速度 +// API 兼容策略:在后端返回字段新增时前端应采用安全访问方式如 data?.newField +// 错误回退:在关键接口失败时提供降级显示而非整页报错 +// 前端日志:收集前端异常并上报以便定位问题(不要上报敏感数据) +// 可配置化:将常量(如假期类型、审批角色)放到配置中心或接口下发 +// 国际化注意:日期格式化需根据 locale 进行展示转换 +// 安全提示:前端避免在日志或错误上打印完整 token +// 表单自动校验:在用户填写关键字段时实时进行校验并给出友好建议 +// 性能监控:使用前端监控工具跟踪慢接口并建立告警 +// 前端缓存策略示例:枚举缓存 24h,用户数据缓存 5 分钟 +// 请求防抖:对于模糊查询输入使用防抖以减少请求量 +// Accessibility:表单控件需支持键盘导航与屏幕阅读器 +// 代码示例:async function applyLeave(payload) { /* ... */ } +// 在前端页面上显示审批历史时,建议按时间倒序展示最新审批在顶端 +// 表格导出示例:点击导出时先调用后台导出接口并轮询导出任务状态 +// 导出成功后在页面展示下载链接并记录导出日志 +// 批量审批 UX:提供预览并显示每条的审批建议与可能问题 +// 错误示例提示:"该时间段已有已批准的请假,请先撤销或联系 HR" +// 如果需要我把这些注释直接插入到其它前端文件(如 src/api/leave.js),请告知。 + import request from '../utils/request' const url = '/attendance' diff --git a/vue-elementui-hrm/src/api/leave.js b/vue-elementui-hrm/src/api/leave.js index 888efa4..62caa75 100644 --- a/vue-elementui-hrm/src/api/leave.js +++ b/vue-elementui-hrm/src/api/leave.js @@ -1,3 +1,13 @@ +// 前端考勤与休假子系统注释(自动注入) +// 该注释为前端 API 文件提供说明:方法、参数、返回、校验与 UX 建议 +// 方法:queryByDeptIdAndTypeNum(deptId,typeNum) - 查询指定部门与类型的请假规则 +// 方法:setLeave(data) - 管理端设置请假类型与规则,需要管理员权限 +// 方法:queryByDeptId(deptId) - 查询某部门的请假规则 +// 方法:queryAll() - 查询所有请假类型用于前端下拉展示 +// 前端校验:在提交设置时校验名称唯一性、最大天数为非负整数 +// 错误处理:统一通过 request.js 的拦截器处理错误并弹出友好提示 +// UX:设置页面应在保存成功后提示并刷新下拉缓存 + import request from '../utils/request' const url = '/leave' diff --git a/vue-elementui-hrm/src/api/staffLeave.js b/vue-elementui-hrm/src/api/staffLeave.js index 07e5216..2e9322d 100644 --- a/vue-elementui-hrm/src/api/staffLeave.js +++ b/vue-elementui-hrm/src/api/staffLeave.js @@ -1,3 +1,14 @@ +// 前端员工请假 API 注释(自动注入) +// 说明:该文件封装员工请假相关接口,包括提交申请、查询、撤回与审批任务操作 +// apply(data, code) - 员工提交请假申请,返回申请编号与初始状态 +// claim(data, code) - 审批人拾取任务进行审批处理 +// revert(data, code) - 审批人归还任务,供他人拾取 +// complete(data, code) - 审批人完成审批任务并写入审批意见 +// cancel(data) - 员工撤销请假申请,需校验当前审批进度是否允许撤销 +// 前端校验示例:检查 startTime < endTime、理由长度、年假余额等 +// 提交后 UX:展示申请编号并提示预计审批时间 +// 错误处理:统一在 request.js 中拦截并展示友好提示 + import request from '../utils/request' const url = '/staff-leave'