| @@ -16,8 +16,8 @@ public class WebConfig implements WebMvcConfigurer { | |||
| registry.addMapping("/**") | |||
| .allowedHeaders("*") | |||
| .allowedOrigins("*") | |||
| .exposedHeaders("filename") | |||
| .allowedMethods("GET", "POST", "PUT", "DELETE", "HEAD"); | |||
| .exposedHeaders("filename", "Content-Disposition") | |||
| .allowedMethods("GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS"); | |||
| } | |||
| @@ -0,0 +1,86 @@ | |||
| package com.ffii.fpsms.modules.master.service | |||
| import com.ffii.core.utils.PdfUtils | |||
| import com.ffii.core.utils.QrCodeUtil | |||
| import com.ffii.fpsms.modules.master.entity.WarehouseRepository | |||
| import com.ffii.fpsms.modules.master.web.ExportWarehouseQrCodeRequest | |||
| import net.sf.jasperreports.engine.JasperCompileManager | |||
| import net.sf.jasperreports.engine.JasperPrint | |||
| 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 WarehouseQrCodeService( | |||
| private val warehouseRepository: WarehouseRepository | |||
| ) { | |||
| fun exportWarehouseQrCode(request: ExportWarehouseQrCodeRequest): Map<String, Any> { | |||
| val QRCODE_HANDLE_PDF = "qrCodeHandle/warehouse_QrHandle.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 warehouses = warehouseRepository.findAllById(request.warehouseIds) | |||
| if (warehouses.isEmpty()) { | |||
| throw IllegalArgumentException("No warehouses found for the provided warehouse IDs: ${request.warehouseIds}") | |||
| } | |||
| val fields = mutableListOf<MutableMap<String, Any>>() | |||
| for (warehouse in warehouses) { | |||
| val field = mutableMapOf<String, Any>() | |||
| val code = warehouse.code ?: "" | |||
| if (code.isBlank()) { | |||
| continue | |||
| } | |||
| val qrContentMap = mapOf("warehouseCode" to code) | |||
| val qrCodeContent = Json.encodeToString(qrContentMap) | |||
| val qrCodeImage = QrCodeUtil.generateQRCodeImage(qrCodeContent) | |||
| field["username"] = "" | |||
| field["staffNo"] = "" | |||
| field["code"] = code | |||
| field["equipmentCode"] = "" | |||
| field["qrCode"] = qrCodeImage | |||
| fields.add(field) | |||
| } | |||
| if (fields.isEmpty()) { | |||
| throw IllegalArgumentException("No valid warehouses found for the provided warehouse IDs: ${request.warehouseIds}") | |||
| } | |||
| val params: MutableMap<String, Any> = mutableMapOf() | |||
| 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" | |||
| 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 | |||
| val firstWarehouse = warehouses.firstOrNull() | |||
| return mapOf( | |||
| "report" to PdfUtils.fillReport(qrCodeHandleReport, fields, params), | |||
| "fileName" to (firstWarehouse?.code ?: "warehouse_qrcode") | |||
| ) | |||
| } | |||
| } | |||
| @@ -0,0 +1,5 @@ | |||
| package com.ffii.fpsms.modules.master.web | |||
| data class ExportWarehouseQrCodeRequest( | |||
| val warehouseIds: List<Long> | |||
| ) | |||
| @@ -3,7 +3,9 @@ package com.ffii.fpsms.modules.master.web | |||
| import com.ffii.fpsms.modules.master.entity.Warehouse | |||
| import com.ffii.fpsms.modules.master.entity.projections.WarehouseCombo | |||
| import com.ffii.fpsms.modules.master.service.WarehouseService | |||
| import com.ffii.fpsms.modules.master.service.WarehouseQrCodeService | |||
| import jakarta.servlet.http.HttpServletRequest | |||
| import jakarta.servlet.http.HttpServletResponse | |||
| import org.apache.poi.ss.usermodel.Workbook | |||
| import org.apache.poi.xssf.usermodel.XSSFWorkbook | |||
| import org.springframework.http.ResponseEntity | |||
| @@ -17,12 +19,18 @@ 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.RestController | |||
| import org.springframework.web.bind.annotation.RequestMethod | |||
| import org.springframework.web.bind.annotation.CrossOrigin | |||
| import org.springframework.web.multipart.MultipartHttpServletRequest | |||
| import net.sf.jasperreports.engine.JasperExportManager | |||
| import net.sf.jasperreports.engine.JasperPrint | |||
| import java.io.OutputStream | |||
| @RestController | |||
| @RequestMapping("/warehouse") | |||
| class WarehouseController( | |||
| private val warehouseService: WarehouseService | |||
| private val warehouseService: WarehouseService, | |||
| private val warehouseQrCodeService: WarehouseQrCodeService | |||
| ) { | |||
| @GetMapping | |||
| fun getWarehouses(): List<Warehouse> { | |||
| @@ -72,4 +80,21 @@ class WarehouseController( | |||
| return ResponseEntity.ok(warehouseService.importNewExcel(workbook)) | |||
| } | |||
| @PostMapping("/export-qrcode") | |||
| @CrossOrigin(origins = ["*"], allowedHeaders = ["*"]) | |||
| fun exportQrCode(@Valid @RequestBody request: ExportWarehouseQrCodeRequest, response: HttpServletResponse) { | |||
| response.setHeader("Access-Control-Allow-Origin", "*") | |||
| response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") | |||
| response.setHeader("Access-Control-Allow-Headers", "*") | |||
| response.characterEncoding = "utf-8" | |||
| response.contentType = "application/pdf" | |||
| val out: OutputStream = response.outputStream | |||
| val pdf = warehouseQrCodeService.exportWarehouseQrCode(request) | |||
| val jasperPrint = pdf["report"] as JasperPrint | |||
| val fileName = pdf["fileName"] as String | |||
| response.addHeader("Content-Disposition", "attachment; filename=\"${fileName}_qrcode.pdf\"") | |||
| out.write(JasperExportManager.exportReportToPdf(jasperPrint)) | |||
| out.flush() | |||
| } | |||
| } | |||
| @@ -0,0 +1,43 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="qrCodeHandle" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="80" bottomMargin="20" uuid="c2f7cd27-3725-47ce-ac85-d8a38dc906fa"> | |||
| <property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/> | |||
| <property name="com.jaspersoft.studio.unit." value="pixel"/> | |||
| <property name="com.jaspersoft.studio.unit.pageHeight" value="pixel"/> | |||
| <property name="com.jaspersoft.studio.unit.pageWidth" value="pixel"/> | |||
| <property name="com.jaspersoft.studio.unit.topMargin" value="pixel"/> | |||
| <property name="com.jaspersoft.studio.unit.bottomMargin" value="pixel"/> | |||
| <property name="com.jaspersoft.studio.unit.leftMargin" value="pixel"/> | |||
| <property name="com.jaspersoft.studio.unit.rightMargin" value="pixel"/> | |||
| <property name="com.jaspersoft.studio.unit.columnWidth" value="pixel"/> | |||
| <property name="com.jaspersoft.studio.unit.columnSpacing" value="pixel"/> | |||
| <queryString> | |||
| <![CDATA[]]> | |||
| </queryString> | |||
| <field name="username" class="java.lang.String"/> | |||
| <field name="staffNo" class="java.lang.String"/> | |||
| <field name="qrCode" class="java.awt.Image"/> | |||
| <field name="code" class="java.lang.String"/> | |||
| <field name="equipmentCode" class="java.lang.String"/> | |||
| <background> | |||
| <band splitType="Stretch"/> | |||
| </background> | |||
| <detail> | |||
| <band height="670" splitType="Stretch"> | |||
| <textField isStretchWithOverflow="true" isBlankWhenNull="false"> | |||
| <reportElement stretchType="RelativeToTallestObject" x="37" y="0" width="480" height="120" uuid="e3faf8de-84ba-423f-b6cf-84ba21598686"> | |||
| <property name="com.jaspersoft.studio.unit.x" value="px"/> | |||
| <property name="com.jaspersoft.studio.unit.width" value="px"/> | |||
| <property name="com.jaspersoft.studio.unit.height" value="px"/> | |||
| </reportElement> | |||
| <textElement textAlignment="Center" verticalAlignment="Middle"> | |||
| <font size="34" isBold="true" fontName="微軟正黑體" pdfEncoding="Identity-H" isPdfEmbedded="true"/> | |||
| </textElement> | |||
| <textFieldExpression><![CDATA[$F{code}]]></textFieldExpression> | |||
| </textField> | |||
| <image> | |||
| <reportElement x="27" y="120" width="500" height="500" uuid="b1a8ee23-9f0f-4014-9996-e0025222dcd2"/> | |||
| <imageExpression><![CDATA[$F{qrCode}]]></imageExpression> | |||
| </image> | |||
| </band> | |||
| </detail> | |||
| </jasperReport> | |||