| @@ -16,8 +16,8 @@ public class WebConfig implements WebMvcConfigurer { | |||||
| registry.addMapping("/**") | registry.addMapping("/**") | ||||
| .allowedHeaders("*") | .allowedHeaders("*") | ||||
| .allowedOrigins("*") | .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.Warehouse | ||||
| import com.ffii.fpsms.modules.master.entity.projections.WarehouseCombo | import com.ffii.fpsms.modules.master.entity.projections.WarehouseCombo | ||||
| import com.ffii.fpsms.modules.master.service.WarehouseService | 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.HttpServletRequest | ||||
| import jakarta.servlet.http.HttpServletResponse | |||||
| import org.apache.poi.ss.usermodel.Workbook | import org.apache.poi.ss.usermodel.Workbook | ||||
| import org.apache.poi.xssf.usermodel.XSSFWorkbook | import org.apache.poi.xssf.usermodel.XSSFWorkbook | ||||
| import org.springframework.http.ResponseEntity | 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.RequestBody | ||||
| import org.springframework.web.bind.annotation.RequestMapping | import org.springframework.web.bind.annotation.RequestMapping | ||||
| import org.springframework.web.bind.annotation.RestController | 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 org.springframework.web.multipart.MultipartHttpServletRequest | ||||
| import net.sf.jasperreports.engine.JasperExportManager | |||||
| import net.sf.jasperreports.engine.JasperPrint | |||||
| import java.io.OutputStream | |||||
| @RestController | @RestController | ||||
| @RequestMapping("/warehouse") | @RequestMapping("/warehouse") | ||||
| class WarehouseController( | class WarehouseController( | ||||
| private val warehouseService: WarehouseService | |||||
| private val warehouseService: WarehouseService, | |||||
| private val warehouseQrCodeService: WarehouseQrCodeService | |||||
| ) { | ) { | ||||
| @GetMapping | @GetMapping | ||||
| fun getWarehouses(): List<Warehouse> { | fun getWarehouses(): List<Warehouse> { | ||||
| @@ -72,4 +80,21 @@ class WarehouseController( | |||||
| return ResponseEntity.ok(warehouseService.importNewExcel(workbook)) | 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> | |||||