package com.mydreamjob.salarycalculator; import com.mydreamjob.common.api.ApiResponse; import com.mydreamjob.common.api.PageResponse; import com.mydreamjob.common.exception.BusinessException; import com.mydreamjob.common.exception.ErrorCode; import com.mydreamjob.salarycalculator.dto.SalaryCalculationRequest; import com.mydreamjob.salarycalculator.dto.SalaryCalculationResponse; import com.mydreamjob.salarycalculator.dto.SalaryHistoryDetailResponse; import com.mydreamjob.salarycalculator.dto.SalaryHistorySummaryResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletRequest; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @Tag(name = "薪资计算器", description = "城市政策、到手工资估算与历史记录") @RestController @RequestMapping("/salary-calculator") @RequiredArgsConstructor public class SalaryCalculationController { private final SalaryCalculationService calculationService; private final SalaryHistoryService historyService; @Operation(summary = "计算并保存到手工资", description = "仅 STUDENT;未发布政策返回 404/10601,幂等重放不可绕过发布门禁;本人历史查询不受影响") @PostMapping("/calculations") public ResponseEntity> calculate( @Valid @RequestBody SalaryCalculationRequest body, HttpServletRequest request) { Long userId = resolveUserId(); return ResponseEntity.ok(ApiResponse.ok( calculationService.calculateAndSave(userId, body), getRequestId(request))); } @Operation(summary = "查询本人薪资历史", description = "仅 STUDENT;按创建时间倒序分页") @GetMapping("/calculations") public ResponseEntity>> list( @RequestParam(defaultValue = "0") int page, @RequestParam(defaultValue = "20") int size, HttpServletRequest request) { Long userId = resolveUserId(); return ResponseEntity.ok(ApiResponse.ok( historyService.list(userId, page, size), getRequestId(request))); } @Operation(summary = "查询本人薪资历史详情", description = "仅 STUDENT;返回完整快照") @GetMapping("/calculations/{id}") public ResponseEntity> get( @PathVariable Long id, HttpServletRequest request) { Long userId = resolveUserId(); return ResponseEntity.ok(ApiResponse.ok( historyService.get(userId, id), getRequestId(request))); } @Operation(summary = "删除本人薪资历史", description = "仅 STUDENT;物理删除") @DeleteMapping("/calculations/{id}") public ResponseEntity> delete( @PathVariable Long id, HttpServletRequest request) { Long userId = resolveUserId(); historyService.delete(userId, id); return ResponseEntity.ok(ApiResponse.ok(null, getRequestId(request))); } private Long resolveUserId() { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth == null || !auth.isAuthenticated() || "anonymousUser".equals(String.valueOf(auth.getPrincipal()))) { throw new BusinessException(ErrorCode.UNAUTHORIZED); } try { return Long.valueOf(auth.getName()); } catch (NumberFormatException ex) { throw new BusinessException(ErrorCode.UNAUTHORIZED); } } private String getRequestId(HttpServletRequest request) { return request.getHeader("X-Request-Id"); } }