diff --git a/src/main/java/com/ffii/fpsms/modules/user/req/UpdateUserReq.java b/src/main/java/com/ffii/fpsms/modules/user/req/UpdateUserReq.java index efe0c63..f7bc5ff 100644 --- a/src/main/java/com/ffii/fpsms/modules/user/req/UpdateUserReq.java +++ b/src/main/java/com/ffii/fpsms/modules/user/req/UpdateUserReq.java @@ -22,6 +22,7 @@ public class UpdateUserReq { private LocalDate expiryDate; private String locale; private String remarks; + private String staffNo; // @NotNull @@ -126,4 +127,12 @@ public class UpdateUserReq { this.remarks = remarks; } + public String getStaffNo() { // Add getter + return staffNo; + } + + public void setStaffNo(String staffNo) { // Add setter + this.staffNo = staffNo; + } + } diff --git a/src/main/java/com/ffii/fpsms/modules/user/service/UserQrCodeService.kt b/src/main/java/com/ffii/fpsms/modules/user/service/UserQrCodeService.kt new file mode 100644 index 0000000..12f66a5 --- /dev/null +++ b/src/main/java/com/ffii/fpsms/modules/user/service/UserQrCodeService.kt @@ -0,0 +1,76 @@ +package com.ffii.fpsms.modules.user.service + +import com.ffii.core.utils.PdfUtils +import com.ffii.core.utils.QrCodeUtil +import com.ffii.fpsms.modules.user.entity.UserRepository +import com.ffii.fpsms.modules.user.web.ExportUserQrCodeRequest +import net.sf.jasperreports.engine.JasperCompileManager +import net.sf.jasperreports.engine.JasperPrint +import net.sf.jasperreports.engine.export.JRPdfExporter +import net.sf.jasperreports.export.SimpleExporterInput +import net.sf.jasperreports.export.SimpleOutputStreamExporterOutput +import org.springframework.core.io.ClassPathResource +import org.springframework.stereotype.Service +import java.io.FileNotFoundException +import java.awt.GraphicsEnvironment +import kotlinx.serialization.json.Json +import kotlinx.serialization.encodeToString + +@Service +class UserQrCodeService( + private val userRepository: UserRepository +) { + + fun exportUserQrCode(request: ExportUserQrCodeRequest): Map { + val QRCODE_HANDLE_PDF = "qrCodeHandle/qrCodeHandle.jrxml" + val resource = ClassPathResource(QRCODE_HANDLE_PDF) + if (!resource.exists()) { + throw FileNotFoundException("Report file not found: $QRCODE_HANDLE_PDF") + } + + val inputStream = resource.inputStream + val qrCodeHandleReport = JasperCompileManager.compileReport(inputStream) + + val users = userRepository.findAllById(request.userIds) + val fields = mutableListOf>() + + for (user in users) { + val field = mutableMapOf() + + val staffNo = user.staffNo ?: "" + val username = user.username ?: "N/A" + + val qrContentMap = mapOf("staffNo" to staffNo) + val qrCodeContent = Json.encodeToString(qrContentMap) + + val qrCodeImage = QrCodeUtil.generateQRCodeImage(qrCodeContent) + + field["username"] = username + field["staffNo"] = staffNo.ifEmpty { "N/A" } + field["qrCode"] = qrCodeImage + + fields.add(field) + } + + val params: MutableMap = mutableMapOf() + + // Configure for Chinese character support + // Try to find a Chinese-supporting font + val availableFonts = GraphicsEnvironment.getLocalGraphicsEnvironment().availableFontFamilyNames + val chineseFont = availableFonts.find { + it.contains("SimSun", ignoreCase = true) || + it.contains("Microsoft YaHei", ignoreCase = true) || + it.contains("STSong", ignoreCase = true) || + it.contains("SimHei", ignoreCase = true) + } ?: "Arial Unicode MS" // Fallback + + params["net.sf.jasperreports.default.pdf.encoding"] = "Identity-H" + params["net.sf.jasperreports.default.pdf.embedded"] = true + params["net.sf.jasperreports.default.pdf.font.name"] = chineseFont + + return mapOf( + "report" to PdfUtils.fillReport(qrCodeHandleReport, fields, params), + "fileName" to (users.firstOrNull()?.username ?: "user_qrcode") + ) + } +} \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/user/service/UserService.java b/src/main/java/com/ffii/fpsms/modules/user/service/UserService.java index 2a124c9..d7df17c 100644 --- a/src/main/java/com/ffii/fpsms/modules/user/service/UserService.java +++ b/src/main/java/com/ffii/fpsms/modules/user/service/UserService.java @@ -111,7 +111,8 @@ public class UserService extends AbstractBaseEntityService +) \ No newline at end of file diff --git a/src/main/java/com/ffii/fpsms/modules/user/web/UserController.java b/src/main/java/com/ffii/fpsms/modules/user/web/UserController.java index 88137d4..9d8164e 100644 --- a/src/main/java/com/ffii/fpsms/modules/user/web/UserController.java +++ b/src/main/java/com/ffii/fpsms/modules/user/web/UserController.java @@ -42,6 +42,14 @@ import com.ffii.fpsms.modules.user.req.UpdateUserReq; import com.ffii.fpsms.modules.user.service.UserService; import com.ffii.fpsms.modules.user.service.res.LoadUserRes; +import com.ffii.fpsms.modules.user.web.ExportUserQrCodeRequest; +import com.ffii.fpsms.modules.user.service.UserQrCodeService; +import jakarta.servlet.http.HttpServletResponse; +import net.sf.jasperreports.engine.JasperExportManager; +import net.sf.jasperreports.engine.JasperPrint; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; @@ -53,14 +61,17 @@ public class UserController{ private UserService userService; private PasswordEncoder passwordEncoder; private SettingsService settingsService; + private UserQrCodeService userQrCodeService; public UserController( UserService userService, PasswordEncoder passwordEncoder, - SettingsService settingsService) { + SettingsService settingsService, + UserQrCodeService userQrCodeService) { this.userService = userService; this.passwordEncoder = passwordEncoder; this.settingsService = settingsService; + this.userQrCodeService = userQrCodeService; } // @Operation(summary = "list user", responses = { @ApiResponse(responseCode = "200"), @@ -229,6 +240,20 @@ public class UserController{ return new PasswordRule(settingsService); } + @PostMapping("/export-qrcode") + public void exportQrCode(@Valid @RequestBody ExportUserQrCodeRequest request, HttpServletResponse response) + throws Exception { + response.setCharacterEncoding("utf-8"); + response.setContentType("application/pdf"); + OutputStream out = response.getOutputStream(); + Map pdf = userQrCodeService.exportUserQrCode(request); + JasperPrint jasperPrint = (JasperPrint) pdf.get("report"); + String fileName = (String) pdf.get("fileName"); + response.addHeader("Content-Disposition", "attachment; filename=\"" + fileName + "_qrcode.pdf\""); + out.write(JasperExportManager.exportReportToPdf(jasperPrint)); + out.flush(); + } + public static class AdminChangePwdReq { private Long id; @NotBlank diff --git a/src/main/resources/qrCodeHandle/qrCodeHandle.jrxml b/src/main/resources/qrCodeHandle/qrCodeHandle.jrxml new file mode 100644 index 0000000..b56bc08 --- /dev/null +++ b/src/main/resources/qrCodeHandle/qrCodeHandle.jrxml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file