CoordinateAdjustTool.java 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. package com.mes.print;
  2. import com.mes.print.model.FlowCardData;
  3. import com.mes.print.template.FlowCardRenderer;
  4. import javax.swing.*;
  5. import java.awt.*;
  6. import java.awt.image.BufferedImage;
  7. /**
  8. * 流转卡坐标调整工具
  9. * 可视化调整二维码和文字位置(支持项目号、钢印码、客户码)
  10. */
  11. public class CoordinateAdjustTool extends JFrame {
  12. // 当前坐标(初始值从 FlowCardRenderer 获取)
  13. private float qrX = 194.5f;
  14. private float qrY = 65.4f - 16.0f; // 已上移
  15. private float qrW = 35.7f;
  16. private float qrH = 34.6f;
  17. private float projTextX = 291.5f;
  18. private float projTextY = 75.0f - 16.0f; // 项目号
  19. private float steelTextX = 291.5f;
  20. private float steelTextY = 85.5f - 16.0f; // 钢印码
  21. private float snTextX = 291.5f;
  22. private float snTextY = 96.4f - 16.0f; // 客户码
  23. private JLabel previewLabel;
  24. private FlowCardData testData;
  25. // 拖拽相关
  26. private boolean draggingQr = false;
  27. private Point dragStart = null;
  28. public CoordinateAdjustTool() {
  29. setTitle("流转卡坐标调整工具 - OP170");
  30. setSize(1200, 900);
  31. setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  32. setLayout(new BorderLayout(10, 10));
  33. // 测试数据
  34. testData = new FlowCardData();
  35. testData.setSn("+KB60IS3031T729002101");
  36. testData.setSteelSn("T09260729002");
  37. // 左侧:预览区域
  38. previewLabel = new JLabel();
  39. previewLabel.setHorizontalAlignment(JLabel.CENTER);
  40. // 添加鼠标拖拽监听
  41. previewLabel.addMouseListener(new java.awt.event.MouseAdapter() {
  42. @Override
  43. public void mousePressed(java.awt.event.MouseEvent e) {
  44. handleMousePressed(e);
  45. }
  46. @Override
  47. public void mouseReleased(java.awt.event.MouseEvent e) {
  48. draggingQr = false;
  49. dragStart = null;
  50. }
  51. });
  52. previewLabel.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
  53. @Override
  54. public void mouseDragged(java.awt.event.MouseEvent e) {
  55. handleMouseDragged(e);
  56. }
  57. });
  58. JScrollPane scrollPane = new JScrollPane(previewLabel);
  59. add(scrollPane, BorderLayout.CENTER);
  60. // 右侧:控制面板
  61. JPanel controlPanel = new JPanel();
  62. controlPanel.setLayout(new BoxLayout(controlPanel, BoxLayout.Y_AXIS));
  63. controlPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
  64. // 输入框区域
  65. controlPanel.add(createLabel("=== 测试数据 ==="));
  66. JTextField snField = new JTextField(testData.getSn(), 20);
  67. JTextField steelSnField = new JTextField(testData.getSteelSn(), 15);
  68. JPanel inputPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
  69. inputPanel.add(new JLabel("客户码:"));
  70. inputPanel.add(snField);
  71. controlPanel.add(inputPanel);
  72. JPanel inputPanel2 = new JPanel(new FlowLayout(FlowLayout.LEFT));
  73. inputPanel2.add(new JLabel("钢印码:"));
  74. inputPanel2.add(steelSnField);
  75. controlPanel.add(inputPanel2);
  76. // 项目号显示
  77. JLabel projLabel = new JLabel("项目号: " + testData.getProdCode());
  78. projLabel.setFont(new Font("Microsoft YaHei UI", Font.BOLD, 12));
  79. projLabel.setForeground(new Color(0, 100, 0));
  80. controlPanel.add(projLabel);
  81. JButton updateBtn = new JButton("更新预览");
  82. updateBtn.addActionListener(e -> {
  83. testData.setSn(snField.getText());
  84. testData.setSteelSn(steelSnField.getText());
  85. projLabel.setText("项目号: " + testData.getProdCode());
  86. updatePreview();
  87. });
  88. controlPanel.add(updateBtn);
  89. controlPanel.add(Box.createVerticalStrut(20));
  90. // 二维码坐标控制
  91. controlPanel.add(createLabel("=== 二维码位置 ==="));
  92. JTextField qrXField = new JTextField(String.format("%.1f", qrX), 8);
  93. JTextField qrYField = new JTextField(String.format("%.1f", qrY), 8);
  94. controlPanel.add(createCoordinatePanel("X", qrXField, qrX, 100f, 300f, v -> {
  95. qrX = v;
  96. qrXField.setText(String.format("%.1f", v));
  97. updatePreview();
  98. }));
  99. controlPanel.add(createCoordinatePanel("Y", qrYField, qrY, 30f, 150f, v -> {
  100. qrY = v;
  101. qrYField.setText(String.format("%.1f", v));
  102. updatePreview();
  103. }));
  104. controlPanel.add(Box.createVerticalStrut(20));
  105. // 项目号坐标控制
  106. controlPanel.add(createLabel("=== 项目号位置 ==="));
  107. JTextField projXField = new JTextField(String.format("%.1f", projTextX), 8);
  108. JTextField projYField = new JTextField(String.format("%.1f", projTextY), 8);
  109. controlPanel.add(createCoordinatePanel("X", projXField, projTextX, 200f, 400f, v -> {
  110. projTextX = v;
  111. projXField.setText(String.format("%.1f", v));
  112. updatePreview();
  113. }));
  114. controlPanel.add(createCoordinatePanel("Y", projYField, projTextY, 50f, 150f, v -> {
  115. projTextY = v;
  116. projYField.setText(String.format("%.1f", v));
  117. updatePreview();
  118. }));
  119. controlPanel.add(Box.createVerticalStrut(20));
  120. // 钢印码坐标控制
  121. controlPanel.add(createLabel("=== 钢印码位置 ==="));
  122. JTextField steelXField = new JTextField(String.format("%.1f", steelTextX), 8);
  123. JTextField steelYField = new JTextField(String.format("%.1f", steelTextY), 8);
  124. controlPanel.add(createCoordinatePanel("X", steelXField, steelTextX, 200f, 400f, v -> {
  125. steelTextX = v;
  126. steelXField.setText(String.format("%.1f", v));
  127. updatePreview();
  128. }));
  129. controlPanel.add(createCoordinatePanel("Y", steelYField, steelTextY, 50f, 150f, v -> {
  130. steelTextY = v;
  131. steelYField.setText(String.format("%.1f", v));
  132. updatePreview();
  133. }));
  134. controlPanel.add(Box.createVerticalStrut(20));
  135. // 客户码坐标控制
  136. controlPanel.add(createLabel("=== 客户码位置 ==="));
  137. JTextField snXField = new JTextField(String.format("%.1f", snTextX), 8);
  138. JTextField snYField = new JTextField(String.format("%.1f", snTextY), 8);
  139. controlPanel.add(createCoordinatePanel("X", snXField, snTextX, 200f, 400f, v -> {
  140. snTextX = v;
  141. snXField.setText(String.format("%.1f", v));
  142. updatePreview();
  143. }));
  144. controlPanel.add(createCoordinatePanel("Y", snYField, snTextY, 50f, 150f, v -> {
  145. snTextY = v;
  146. snYField.setText(String.format("%.1f", v));
  147. updatePreview();
  148. }));
  149. controlPanel.add(Box.createVerticalStrut(20));
  150. // 按钮
  151. JButton exportBtn = new JButton("生成代码");
  152. exportBtn.setFont(new Font("Microsoft YaHei UI", Font.BOLD, 14));
  153. exportBtn.addActionListener(e -> exportCode());
  154. controlPanel.add(exportBtn);
  155. JButton previewPdfBtn = new JButton("预览 PDF");
  156. previewPdfBtn.setFont(new Font("Microsoft YaHei UI", Font.BOLD, 14));
  157. previewPdfBtn.addActionListener(e -> previewPdf());
  158. controlPanel.add(previewPdfBtn);
  159. add(controlPanel, BorderLayout.EAST);
  160. // 初始预览
  161. updatePreview();
  162. }
  163. private void handleMousePressed(java.awt.event.MouseEvent e) {
  164. if (previewLabel.getIcon() == null) return;
  165. ImageIcon icon = (ImageIcon) previewLabel.getIcon();
  166. int imgW = icon.getIconWidth();
  167. int imgH = icon.getIconHeight();
  168. int labelW = previewLabel.getWidth();
  169. int labelH = previewLabel.getHeight();
  170. int offsetX = (labelW - imgW) / 2;
  171. int offsetY = (labelH - imgH) / 2;
  172. int clickX = e.getX() - offsetX;
  173. int clickY = e.getY() - offsetY;
  174. if (clickX < 0 || clickX >= imgW || clickY < 0 || clickY >= imgH) return;
  175. double scale = 300.0 / 72.0;
  176. int qrImgX = (int) (qrX * scale);
  177. int qrImgY = (int) (qrY * scale);
  178. int qrImgW = (int) (qrW * scale);
  179. int qrImgH = (int) (qrH * scale);
  180. if (clickX >= qrImgX && clickX <= qrImgX + qrImgW &&
  181. clickY >= qrImgY && clickY <= qrImgY + qrImgH) {
  182. draggingQr = true;
  183. dragStart = new Point(clickX, clickY);
  184. }
  185. }
  186. private void handleMouseDragged(java.awt.event.MouseEvent e) {
  187. if (!draggingQr || dragStart == null) return;
  188. if (previewLabel.getIcon() == null) return;
  189. ImageIcon icon = (ImageIcon) previewLabel.getIcon();
  190. int imgW = icon.getIconWidth();
  191. int imgH = icon.getIconHeight();
  192. int labelW = previewLabel.getWidth();
  193. int labelH = previewLabel.getHeight();
  194. int offsetX = (labelW - imgW) / 2;
  195. int offsetY = (labelH - imgH) / 2;
  196. int currentX = e.getX() - offsetX;
  197. int currentY = e.getY() - offsetY;
  198. int deltaX = currentX - dragStart.x;
  199. int deltaY = currentY - dragStart.y;
  200. double scale = 300.0 / 72.0;
  201. float pdfDeltaX = (float) (deltaX / scale);
  202. float pdfDeltaY = (float) (deltaY / scale);
  203. qrX += pdfDeltaX;
  204. qrY += pdfDeltaY;
  205. dragStart = new Point(currentX, currentY);
  206. updatePreview();
  207. }
  208. private JLabel createLabel(String text) {
  209. JLabel label = new JLabel(text);
  210. label.setFont(new Font("Microsoft YaHei UI", Font.BOLD, 14));
  211. return label;
  212. }
  213. private JPanel createCoordinatePanel(String label, JTextField field, float initValue, float min, float max, ValueChangeListener listener) {
  214. JPanel panel = new JPanel(new BorderLayout(5, 5));
  215. JLabel nameLabel = new JLabel(label);
  216. nameLabel.setFont(new Font("Microsoft YaHei UI", Font.PLAIN, 12));
  217. JLabel valueLabel = new JLabel(String.format("%.1f", initValue));
  218. valueLabel.setFont(new Font("Consolas", Font.PLAIN, 12));
  219. valueLabel.setPreferredSize(new Dimension(50, 20));
  220. JSlider slider = new JSlider(JSlider.HORIZONTAL, (int)(min * 10), (int)(max * 10), (int)(initValue * 10));
  221. slider.addChangeListener(e -> {
  222. float value = slider.getValue() / 10.0f;
  223. valueLabel.setText(String.format("%.1f", value));
  224. listener.onValueChange(value);
  225. });
  226. field.addActionListener(e -> {
  227. try {
  228. float value = Float.parseFloat(field.getText());
  229. slider.setValue((int)(value * 10));
  230. listener.onValueChange(value);
  231. } catch (NumberFormatException ex) {
  232. field.setText(String.format("%.1f", initValue));
  233. }
  234. });
  235. JPanel topPanel = new JPanel(new BorderLayout());
  236. topPanel.add(nameLabel, BorderLayout.WEST);
  237. topPanel.add(field, BorderLayout.CENTER);
  238. topPanel.add(valueLabel, BorderLayout.EAST);
  239. panel.add(topPanel, BorderLayout.NORTH);
  240. panel.add(slider, BorderLayout.CENTER);
  241. return panel;
  242. }
  243. private void updatePreview() {
  244. try {
  245. BufferedImage preview = createPreviewImage();
  246. ImageIcon icon = new ImageIcon(preview);
  247. previewLabel.setIcon(icon);
  248. } catch (Exception e) {
  249. e.printStackTrace();
  250. JOptionPane.showMessageDialog(this, "预览失败: " + e.getMessage());
  251. }
  252. }
  253. private BufferedImage createPreviewImage() throws Exception {
  254. BufferedImage templateBg = FlowCardRenderer.getTemplateImage();
  255. BufferedImage img = new BufferedImage(templateBg.getWidth(), templateBg.getHeight(), BufferedImage.TYPE_INT_RGB);
  256. Graphics2D g2 = img.createGraphics();
  257. g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
  258. g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
  259. g2.drawImage(templateBg, 0, 0, null);
  260. double scale = 300.0 / 72.0;
  261. // 绘制二维码
  262. try {
  263. BufferedImage qrCode = FlowCardRenderer.generateQrCode(testData.getSn(), 600);
  264. int imgQrX = (int)(qrX * scale);
  265. int imgQrY = (int)(qrY * scale);
  266. int imgQrW = (int)(qrW * scale);
  267. int imgQrH = (int)(qrH * scale);
  268. g2.drawImage(qrCode, imgQrX, imgQrY, imgQrW, imgQrH, null);
  269. } catch (Exception e) {
  270. e.printStackTrace();
  271. }
  272. g2.setColor(Color.BLACK);
  273. g2.setFont(new Font("SimSun", Font.BOLD, (int)(8 * scale)));
  274. // 绘制项目号(蓝色)
  275. String projCode = testData.getProdCode();
  276. if (projCode != null && !projCode.isEmpty()) {
  277. int imgProjX = (int)(projTextX * scale);
  278. int imgProjY = (int)(projTextY * scale);
  279. g2.setColor(new Color(0, 0, 200));
  280. g2.drawString(projCode, imgProjX, imgProjY);
  281. // 蓝色十字标记
  282. g2.setStroke(new BasicStroke(2));
  283. g2.drawLine(imgProjX - 20, imgProjY, imgProjX + 20, imgProjY);
  284. g2.drawLine(imgProjX, imgProjY - 20, imgProjX, imgProjY + 20);
  285. }
  286. // 绘制钢印码(红色)
  287. int imgSteelX = (int)(steelTextX * scale);
  288. int imgSteelY = (int)(steelTextY * scale);
  289. if (testData.getSteelSn() != null) {
  290. g2.setColor(Color.BLACK);
  291. g2.drawString(testData.getSteelSn(), imgSteelX, imgSteelY);
  292. }
  293. g2.setColor(Color.RED);
  294. g2.setStroke(new BasicStroke(2));
  295. g2.drawLine(imgSteelX - 20, imgSteelY, imgSteelX + 20, imgSteelY);
  296. g2.drawLine(imgSteelX, imgSteelY - 20, imgSteelX, imgSteelY + 20);
  297. // 绘制客户码(绿色)
  298. int imgSnX = (int)(snTextX * scale);
  299. int imgSnY = (int)(snTextY * scale);
  300. if (testData.getSn() != null) {
  301. g2.setColor(Color.BLACK);
  302. g2.drawString(testData.getSn(), imgSnX, imgSnY);
  303. }
  304. g2.setColor(Color.GREEN.darker());
  305. g2.setStroke(new BasicStroke(2));
  306. g2.drawLine(imgSnX - 20, imgSnY, imgSnX + 20, imgSnY);
  307. g2.drawLine(imgSnX, imgSnY - 20, imgSnX, imgSnY + 20);
  308. // 显示当前坐标
  309. g2.setColor(Color.BLACK);
  310. g2.setFont(new Font("Consolas", Font.BOLD, 24));
  311. g2.drawString(String.format("QR: (%.1f, %.1f)", qrX, qrY), 20, 50);
  312. g2.drawString(String.format("项目: (%.1f, %.1f)", projTextX, projTextY), 20, 90);
  313. g2.drawString(String.format("钢印: (%.1f, %.1f)", steelTextX, steelTextY), 20, 130);
  314. g2.drawString(String.format("客户: (%.1f, %.1f)", snTextX, snTextY), 20, 170);
  315. g2.dispose();
  316. return img;
  317. }
  318. private void exportCode() {
  319. String code = String.format(
  320. "// 坐标配置(复制到 FlowCardRenderer.java 中)\n" +
  321. "private static final float QR_X = %.1ff;\n" +
  322. "private static final float QR_Y = %.1ff;\n" +
  323. "private static final float QR_W = %.1ff;\n" +
  324. "private static final float QR_H = %.1ff;\n\n" +
  325. "private static final float PROJ_TEXT_X = %.1ff;\n" +
  326. "private static final float PROJ_TEXT_Y = %.1ff;\n" +
  327. "private static final float STEEL_TEXT_X = %.1ff;\n" +
  328. "private static final float STEEL_TEXT_Y = %.1ff;\n" +
  329. "private static final float SN_TEXT_X = %.1ff;\n" +
  330. "private static final float SN_TEXT_Y = %.1ff;\n",
  331. qrX, qrY, qrW, qrH,
  332. projTextX, projTextY, steelTextX, steelTextY, snTextX, snTextY
  333. );
  334. JTextArea textArea = new JTextArea(code, 15, 50);
  335. textArea.setFont(new Font("Consolas", Font.PLAIN, 12));
  336. textArea.setEditable(false);
  337. JOptionPane.showMessageDialog(this, new JScrollPane(textArea), "生成的代码", JOptionPane.INFORMATION_MESSAGE);
  338. }
  339. private void previewPdf() {
  340. try {
  341. FlowCardRenderer.preview(testData);
  342. JOptionPane.showMessageDialog(this, "PDF 预览已打开");
  343. } catch (Exception e) {
  344. JOptionPane.showMessageDialog(this, "预览失败: " + e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE);
  345. }
  346. }
  347. interface ValueChangeListener {
  348. void onValueChange(float value);
  349. }
  350. public static void main(String[] args) {
  351. SwingUtilities.invokeLater(() -> {
  352. CoordinateAdjustTool tool = new CoordinateAdjustTool();
  353. tool.setVisible(true);
  354. });
  355. }
  356. }