xdd před 2 týdny
rodič
revize
d823269356

+ 25 - 0
fs-admin/src/main/java/com/fs/task/PrescribeTask.java

@@ -0,0 +1,25 @@
+package com.fs.task;
+
+import com.fs.common.annotation.QuartzRunnable;
+import com.fs.store.service.IFsPrescribeService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service("prescribeTask")
+public class PrescribeTask {
+
+    @Autowired
+    private IFsPrescribeService fsPrescribeService;
+
+
+    /**
+     * 生成处方和病历单图片
+     */
+    @QuartzRunnable(name="生成处方和病历单图片")
+    public void generatePrescribeImg(){
+        fsPrescribeService.generateDealImg();
+    }
+
+}

+ 48 - 0
fs-service-system/src/main/java/com/fs/store/dto/MedicalRecordDTO.java

@@ -0,0 +1,48 @@
+package com.fs.store.dto;
+
+import com.fs.store.domain.FsPrescribeDrug;
+import lombok.Data;
+import java.util.Date;
+import java.util.List;
+import java.util.Random;
+
+@Data
+public class MedicalRecordDTO {
+
+    // 头部信息
+    private Date visitDate;           // 就诊日期
+    private String outpatientNo;      // 门诊号
+    private String department;        // 科别
+    private String paymentType;       // 付款类型
+
+    // 患者基本信息
+    private String patientName;       // 姓名
+    private String gender;            // 性别
+    private Integer age;              // 年龄
+    private String height;            // 身高
+    private String weight;            // 体重
+    private String phone;             // 联系电话
+    private String address;           // 单位或地址
+
+    // 病情信息
+    private String chiefComplaint;    // 主诉
+    private String presentIllness;    // 现病史
+    private String pastHistory;       // 既往史
+    private String allergyHistory;    // 过敏史
+
+    // 检查信息
+    private String vitalSigns;        // 生命体征
+    private String auxiliaryExam;     // 辅助检查
+
+    // 诊疗信息
+    private String diagnosis;         // 诊断
+    private String medicalAdvice;     // 医嘱
+    private String healthEducation;   // 健康教育
+    private String treatmentPlan;     // 处理意见
+    private String prescription;      // 处方1
+
+    // 医生信息
+    private String doctorName;        // 医生签名
+
+    List<FsPrescribeDrug> drugList;
+}

+ 306 - 0
fs-service-system/src/main/java/com/fs/store/service/MedicalRecordService.java

@@ -0,0 +1,306 @@
+package com.fs.store.service;
+
+import com.fs.common.config.FSSysConfig;
+import com.fs.store.dto.MedicalRecordDTO;
+import com.fs.system.oss.CloudStorageService;
+import com.fs.system.oss.OSSFactory;
+import lombok.extern.slf4j.Slf4j;
+import net.coobird.thumbnailator.Thumbnails;
+import net.coobird.thumbnailator.resizers.configurations.Antialiasing;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.net.URL;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+@Service
+@Slf4j
+public class MedicalRecordService {
+    @Autowired
+    private FSSysConfig fsSysConfig;
+    /**
+     * 生成病历单图片并上传到OSS
+     * @param dto 病历单数据
+     * @return OSS图片URL
+     */
+    public String generateMedicalRecord(MedicalRecordDTO dto) {
+        try {
+            // 创建图片
+            BufferedImage image = createMedicalRecordImage(dto);
+
+            // 转换为字节流
+            ByteArrayOutputStream os = new ByteArrayOutputStream();
+            ImageIO.write(image, "png", os);
+
+            // 上传到OSS
+            InputStream inputStream = new ByteArrayInputStream(os.toByteArray());
+            CloudStorageService storage = OSSFactory.build();
+            String url = storage.uploadSuffix(inputStream, ".jpg");
+
+            log.info("病历单生成成功,URL: {}", url);
+            return url;
+
+        } catch (Exception e) {
+            log.error("生成病历单失败", e);
+            throw new RuntimeException("生成病历单失败", e);
+        }
+    }
+
+    /**
+     * 创建病历单图片
+     */
+    private BufferedImage createMedicalRecordImage(MedicalRecordDTO dto) {
+        // 创建A4大小的图片 (210mm x 297mm, 72dpi)
+        int width = 595;  // A4宽度
+        int height = 842; // A4高度
+
+        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+        Graphics2D g2d = image.createGraphics();
+
+        // 设置抗锯齿,提高文字清晰度
+        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+
+        // 填充白色背景
+        g2d.setColor(Color.WHITE);
+        g2d.fillRect(0, 0, width, height);
+
+        // 设置黑色画笔
+        g2d.setColor(Color.BLACK);
+
+        // 绘制标题
+        Font titleFont = new Font("黑体", Font.PLAIN,20);
+        g2d.setFont(titleFont);
+        drawCenteredString(g2d, "成都御君方互联网医院电子病历", width, 40);
+
+        // 设置内容字体
+        Font labelFont = new Font("黑体", Font.PLAIN, 12);
+        Font contentFont = new Font("黑体", Font.PLAIN, 12);
+
+        // 起始坐标
+        int leftMargin = 50;
+        int rightMargin = width - 50;
+        int yPos = 80;
+        int lineHeight = 25;
+        int columnWidth = (rightMargin - leftMargin) / 2;
+
+        // 绘制日期和基本信息行
+        g2d.setFont(labelFont);
+        g2d.drawString("就诊日期:", leftMargin, yPos);
+        g2d.setFont(contentFont);
+        g2d.drawString(formatDate(dto.getVisitDate()), leftMargin + 70, yPos);
+
+        g2d.setFont(labelFont);
+        g2d.drawString("科别:", leftMargin + columnWidth, yPos);
+        g2d.setFont(contentFont);
+        g2d.drawString(dto.getDepartment() != null ? dto.getDepartment() : "", leftMargin + columnWidth + 40, yPos);
+
+        yPos += lineHeight;
+
+        // 门诊号和付款类型
+        g2d.setFont(labelFont);
+        g2d.drawString("门诊号:", leftMargin, yPos);
+        g2d.setFont(contentFont);
+        g2d.drawString(dto.getOutpatientNo() != null ? dto.getOutpatientNo() : "", leftMargin + 55, yPos);
+
+        g2d.setFont(labelFont);
+        g2d.drawString("付款类型:", leftMargin + columnWidth, yPos);
+        g2d.setFont(contentFont);
+        g2d.drawString(dto.getPaymentType() != null ? dto.getPaymentType() : "", leftMargin + columnWidth + 65, yPos);
+
+        yPos += lineHeight+30;
+
+        // 患者基本信息
+        drawPatientInfo(g2d, dto, leftMargin, rightMargin, yPos, lineHeight, labelFont, contentFont);
+        yPos += lineHeight * 3;
+
+        // 分隔线
+        g2d.drawLine(leftMargin, yPos, rightMargin, yPos);
+        yPos += 30;
+
+        // 病情信息
+        yPos = drawSection(g2d, "主诉:", dto.getChiefComplaint(), leftMargin, rightMargin, yPos, labelFont, contentFont);
+        yPos = drawSection(g2d, "现病史:", dto.getPresentIllness(), leftMargin, rightMargin, yPos, labelFont, contentFont);
+        yPos = drawSection(g2d, "既往史:", dto.getPastHistory(), leftMargin, rightMargin, yPos, labelFont, contentFont);
+        yPos = drawSection(g2d, "过敏史:", dto.getAllergyHistory(), leftMargin, rightMargin, yPos, labelFont, contentFont);
+        yPos = drawSection(g2d, "生命体征:", dto.getVitalSigns(), leftMargin, rightMargin, yPos, labelFont, contentFont);
+        yPos = drawSection(g2d, "辅助检查:", dto.getAuxiliaryExam(), leftMargin, rightMargin, yPos, labelFont, contentFont);
+        yPos = drawSection(g2d, "诊断:", dto.getDiagnosis(), leftMargin, rightMargin, yPos, labelFont, contentFont);
+        yPos = drawSection(g2d, "医嘱:", dto.getMedicalAdvice(), leftMargin, rightMargin, yPos, labelFont, contentFont);
+        yPos = drawSection(g2d, "健康教育:", dto.getHealthEducation(), leftMargin, rightMargin, yPos, labelFont, contentFont);
+        yPos = drawSection(g2d, "处理意见:", dto.getTreatmentPlan(), leftMargin, rightMargin, yPos, labelFont, contentFont);
+        yPos = drawSection(g2d, "处方1:", dto.getPrescription(), leftMargin, rightMargin, yPos, labelFont, contentFont);
+
+        // 医生签名
+        yPos += 60;
+        g2d.setFont(labelFont);
+        g2d.drawString("医生签名:", rightMargin - 200, yPos);
+
+        try{
+            URL imageUrl = new URL(fsSysConfig.getDoctorSignImgUrl());
+            BufferedImage scaledImg = Thumbnails.of(imageUrl)
+                    .size(120, 55)
+                    .outputQuality(1.0)
+                    .antialiasing(Antialiasing.ON)
+                    .asBufferedImage();
+            g2d.drawImage(scaledImg, rightMargin - 150, yPos-25, null);
+
+        }catch (Exception e) {
+            e.printStackTrace();
+        }
+
+
+        // 底部日期
+        g2d.setFont(labelFont);
+        g2d.drawString("就诊日期:", leftMargin, yPos);
+        g2d.setFont(contentFont);
+        g2d.drawString(formatDate(dto.getVisitDate()), leftMargin + 70, yPos);
+
+        g2d.dispose();
+        return image;
+    }
+
+    /**
+     * 绘制患者基本信息
+     */
+    private void drawPatientInfo(Graphics2D g2d, MedicalRecordDTO dto, int leftMargin, int rightMargin,
+                                int yPos, int lineHeight, Font labelFont, Font contentFont) {
+        int columnWidth = (rightMargin - leftMargin) / 3;
+
+        // 第一行:姓名、性别、年龄
+        g2d.setFont(labelFont);
+        g2d.drawString("姓名:", leftMargin, yPos);
+        g2d.setFont(contentFont);
+        g2d.drawString(dto.getPatientName() != null ? dto.getPatientName() : "", leftMargin + 40, yPos);
+
+        g2d.setFont(labelFont);
+        g2d.drawString("性别:", leftMargin + columnWidth, yPos);
+        g2d.setFont(contentFont);
+        g2d.drawString(dto.getGender() != null ? dto.getGender() : "", leftMargin + columnWidth + 40, yPos);
+
+        g2d.setFont(labelFont);
+        g2d.drawString("年龄:", leftMargin + columnWidth * 2, yPos);
+        g2d.setFont(contentFont);
+        g2d.drawString(dto.getAge() != null ? dto.getAge() + "岁" : "", leftMargin + columnWidth * 2 + 40, yPos);
+
+        // 第二行:身高、体重、联系电话
+        yPos += lineHeight;
+        g2d.setFont(labelFont);
+        g2d.drawString("身高/体重:", leftMargin, yPos);
+        g2d.setFont(contentFont);
+        String heightWeight = (dto.getHeight() != null ? dto.getHeight() : "") + "/" +
+                            (dto.getWeight() != null ? dto.getWeight() : "");
+        g2d.drawString(heightWeight, leftMargin + 75, yPos);
+
+        g2d.setFont(labelFont);
+        g2d.drawString("联系电话:", leftMargin + columnWidth, yPos);
+        g2d.setFont(contentFont);
+        g2d.drawString(dto.getPhone() != null ? dto.getPhone() : "", leftMargin + columnWidth + 65, yPos);
+
+        // 第三行:单位或地址
+        yPos += lineHeight;
+        g2d.setFont(labelFont);
+        g2d.drawString("单位或地址:", leftMargin, yPos);
+        g2d.setFont(contentFont);
+        g2d.drawString(dto.getAddress() != null ? dto.getAddress() : "", leftMargin + 85, yPos);
+    }
+
+    /**
+     * 绘制文本段落(支持自动换行)
+     */
+    private int drawSection(Graphics2D g2d, String label, String content, int leftMargin, int rightMargin,
+                           int yPos, Font labelFont, Font contentFont) {
+        g2d.setFont(labelFont);
+        g2d.drawString(label, leftMargin, yPos);
+
+        if (content == null || content.isEmpty()) {
+            return yPos + 25;
+        }
+
+        g2d.setFont(contentFont);
+        FontMetrics fm = g2d.getFontMetrics();
+        int labelWidth = fm.stringWidth(label);
+        int contentX = leftMargin + labelWidth;
+        int maxWidth = rightMargin - contentX - 10;
+
+        // 自动换行处理
+        String[] lines = wrapText(content, fm, maxWidth);
+        for (int i = 0; i < lines.length; i++) {
+            if (i == 0) {
+                g2d.drawString(lines[i], contentX, yPos);
+            } else {
+                yPos += 20;
+                g2d.drawString(lines[i], leftMargin + 20, yPos);
+            }
+        }
+
+        return yPos + 25;
+    }
+
+    /**
+     * 文本自动换行
+     */
+    private String[] wrapText(String text, FontMetrics fm, int maxWidth) {
+        java.util.List<String> lines = new java.util.ArrayList<>();
+
+        // 先处理制表符,将 \t 替换为4个空格(可根据需要调整)
+        text = text.replace("\t", "    ");
+
+        // 按换行符分割,保留原有的换行
+        String[] paragraphs = text.split("\n", -1);
+
+        for (String paragraph : paragraphs) {
+            if (paragraph.isEmpty()) {
+                lines.add(""); // 保留空行
+                continue;
+            }
+
+            // 对每个段落进行宽度换行处理
+            StringBuilder line = new StringBuilder();
+            String[] chars = paragraph.split("");
+
+            for (String ch : chars) {
+                String testLine = line.toString() + ch;
+                if (fm.stringWidth(testLine) > maxWidth) {
+                    if (line.length() > 0) {
+                        lines.add(line.toString());
+                        line = new StringBuilder(ch);
+                    }
+                } else {
+                    line.append(ch);
+                }
+            }
+
+            if (line.length() > 0) {
+                lines.add(line.toString());
+            }
+        }
+
+        return lines.toArray(new String[0]);
+    }
+
+    /**
+     * 居中绘制文字
+     */
+    private void drawCenteredString(Graphics2D g2d, String text, int width, int y) {
+        FontMetrics fm = g2d.getFontMetrics();
+        int x = (width - fm.stringWidth(text)) / 2;
+        g2d.drawString(text, x, y);
+    }
+
+    /**
+     * 格式化日期
+     */
+    private String formatDate(Date date) {
+        if (date == null) {
+            return "";
+        }
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
+        return sdf.format(date);
+    }
+}