package com.talentcard.server.business.talent; import java.util.Map; import java.time.LocalDate; import com.talentcard.server.business.PageResult; import com.talentcard.server.business.admin.StatusUpdateRequest; import com.talentcard.server.common.ApiResponse; import jakarta.validation.Valid; import org.springframework.http.HttpStatus; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PatchMapping; 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.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import org.springframework.format.annotation.DateTimeFormat; @RestController @RequestMapping("/api/talents") public class TalentController { private final TalentService talentService; public TalentController(TalentService talentService) { this.talentService = talentService; } @PostMapping @ResponseStatus(HttpStatus.CREATED) public ApiResponse> create(@Valid @RequestBody TalentCreateRequest request) { return ApiResponse.success(talentService.create(request)); } @GetMapping public ApiResponse>> page( @RequestParam(required = false) String keyword, @RequestParam(required = false) String mobile, @RequestParam(required = false) String cardNo, @RequestParam(required = false) String level, @RequestParam(required = false) Integer status, @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate registerStart, @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate registerEnd, @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int size ) { return ApiResponse.success(talentService.page(keyword, mobile, cardNo, level, status, registerStart, registerEnd, page, size)); } @GetMapping(value = "/export", produces = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") public ResponseEntity export( @RequestParam(required = false) String keyword, @RequestParam(required = false) String mobile, @RequestParam(required = false) String cardNo, @RequestParam(required = false) String level, @RequestParam(required = false) Integer status, @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate registerStart, @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate registerEnd ) { return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=talents.xlsx") .contentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) .body(talentService.exportExcel(keyword, mobile, cardNo, level, status, registerStart, registerEnd)); } @GetMapping(value = "/import-template", produces = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") public ResponseEntity importTemplate() { return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=talent-import-template.xlsx") .contentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) .body(talentService.importTemplate()); } @GetMapping("/advisors") public ApiResponse>> advisors() { return ApiResponse.success(talentService.availableAdvisors()); } @GetMapping("/service-staff") public ApiResponse>> serviceStaff() { return ApiResponse.success(talentService.availableServiceStaff()); } @PostMapping(value = "/import", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ApiResponse> importExcel(@RequestParam("file") MultipartFile file) throws java.io.IOException { if (file.isEmpty() || file.getOriginalFilename() == null || !file.getOriginalFilename().toLowerCase().endsWith(".xlsx")) { throw new com.talentcard.server.common.BusinessException( com.talentcard.server.common.ErrorCode.BAD_REQUEST, "请选择有效的 .xlsx 文件"); } return ApiResponse.success(talentService.importExcel(file.getInputStream())); } @GetMapping("/{id}") public ApiResponse> detail(@PathVariable Long id) { return ApiResponse.success(talentService.detail(id)); } @PatchMapping("/{id}/mobile") public ApiResponse> updateMobile( @PathVariable Long id, @Valid @RequestBody TalentMobileUpdateRequest request ) { return ApiResponse.success(talentService.updateMobile(id, request.mobile())); } @PatchMapping("/{id}/certification") public ApiResponse> updateCertification( @PathVariable Long id, @Valid @RequestBody TalentCertificationUpdateRequest request ) { return ApiResponse.success(talentService.updateCertification(id, request)); } @PatchMapping("/{id}/card-level") public ApiResponse> updateCardLevel( @PathVariable Long id, @Valid @RequestBody TalentLevelUpdateRequest request ) { return ApiResponse.success(talentService.updateCardLevel(id, request.talentLevel())); } /** * 游客升级为持卡人:补录认证信息 + 选等级 + 发卡。详情页里「升级人才」按钮走这条。 */ @PostMapping("/{id}/upgrade") public ApiResponse> upgrade( @PathVariable Long id, @Valid @RequestBody TalentUpgradeRequest request ) { return ApiResponse.success(talentService.upgrade(id, request)); } @PatchMapping("/{id}/advisor") public ApiResponse> updateAdvisor( @PathVariable Long id, @RequestBody TalentAdvisorUpdateRequest request ) { return ApiResponse.success(talentService.updateAdvisor(id, request.advisorId())); } @PatchMapping("/{id}/service-staff") public ApiResponse> updateServiceStaff( @PathVariable Long id, @RequestBody TalentAdvisorUpdateRequest request ) { return ApiResponse.success(talentService.updateServiceStaff(id, request.advisorId())); } @PatchMapping("/{id}/status") public ApiResponse> updateStatus( @PathVariable Long id, @Valid @RequestBody StatusUpdateRequest request ) { return ApiResponse.success(talentService.updateStatus(id, request.status())); } @GetMapping("/{id}/cards") public ApiResponse>> cards( @PathVariable Long id, @RequestParam(defaultValue = "1") int page, @RequestParam(defaultValue = "10") int size ) { return ApiResponse.success(talentService.cards(id, page, size)); } }