WorkRecordPanel.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. package com.mes.ui;
  2. import org.slf4j.Logger;
  3. import org.slf4j.LoggerFactory;
  4. import com.mes.util.JdbcUtils;
  5. import javax.swing.*;
  6. import javax.swing.table.DefaultTableCellRenderer;
  7. import javax.swing.table.DefaultTableModel;
  8. import javax.swing.table.TableColumn;
  9. import java.awt.*;
  10. import java.awt.event.ComponentAdapter;
  11. import java.awt.event.ComponentEvent;
  12. import java.util.HashSet;
  13. import java.util.List;
  14. import java.util.Set;
  15. /**
  16. * 工作记录面板组件
  17. * 支持分页查询和展示工作记录数据
  18. */
  19. public class WorkRecordPanel extends JPanel {
  20. private static final Logger log = LoggerFactory.getLogger(WorkRecordPanel.class);
  21. // 表格列名
  22. private static final String[] COLUMN_NAMES = {"工件码", "工位号", "工位结果", "作业人员", "日期", "状态"};
  23. // 分页配置
  24. private static final int PAGE_SIZE = 20;
  25. // 查询条件
  26. private String oprno; // 工位号(null或空则查全部)
  27. private String lineSn; // 产线编号
  28. private boolean isAllStation; // 是否是"所有工位"模式
  29. // 分页状态
  30. private int pageNo = 1;
  31. private long totalCount = 0;
  32. private int totalPages = 0;
  33. // UI组件
  34. private JTable table;
  35. private DefaultTableModel tableModel;
  36. private JLabel pageLabel;
  37. private JButton btnPrevious;
  38. private JButton btnNext;
  39. private JButton btnRefresh;
  40. private JButton btnSearch;
  41. private JLabel statusLabel;
  42. private JTextField snSearchField; // 工件码搜索框
  43. private JTextField oprnoSearchField; // 工位号搜索框(仅"所有工位"模式)
  44. private JLabel snLabel;
  45. private JLabel oprnoLabel;
  46. /**
  47. * 构造函数
  48. * @param oprno 工位号(如OP010A查询该工位,null或空则查所有工位)
  49. * @param lineSn 产线编号
  50. */
  51. public WorkRecordPanel(String oprno, String lineSn) {
  52. this.oprno = oprno;
  53. this.lineSn = lineSn;
  54. this.isAllStation = (oprno == null || oprno.isEmpty());
  55. initUI();
  56. }
  57. /**
  58. * 初始化UI
  59. */
  60. private void initUI() {
  61. setLayout(null);
  62. setBackground(Color.WHITE);
  63. // 顶部控制区
  64. JPanel topPanel = new JPanel();
  65. topPanel.setLayout(null);
  66. topPanel.setBounds(0, 0, 1200, 50);
  67. topPanel.setBackground(new Color(248, 248, 248));
  68. add(topPanel);
  69. int xPos = 10;
  70. // 状态标签
  71. String displayOprno = isAllStation ? "所有工位" : oprno;
  72. statusLabel = new JLabel("工位:" + displayOprno);
  73. statusLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13));
  74. statusLabel.setBounds(xPos, 10, 160, 30);
  75. topPanel.add(statusLabel);
  76. xPos += 165;
  77. // 工件码搜索
  78. snLabel = new JLabel("工件码:");
  79. snLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13));
  80. snLabel.setBounds(xPos, 10, 50, 30);
  81. topPanel.add(snLabel);
  82. xPos += 52;
  83. snSearchField = new JTextField();
  84. snSearchField.setFont(new Font("微软雅黑", Font.PLAIN, 13));
  85. snSearchField.setBounds(xPos, 10, 200, 30);
  86. snSearchField.addActionListener(e -> doSearch()); // 回车搜索
  87. topPanel.add(snSearchField);
  88. xPos += 210;
  89. // 工位号搜索(仅"所有工位"模式显示)
  90. if (isAllStation) {
  91. oprnoLabel = new JLabel("工位:");
  92. oprnoLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13));
  93. oprnoLabel.setBounds(xPos, 10, 40, 30);
  94. topPanel.add(oprnoLabel);
  95. xPos += 42;
  96. oprnoSearchField = new JTextField();
  97. oprnoSearchField.setFont(new Font("微软雅黑", Font.PLAIN, 13));
  98. oprnoSearchField.setBounds(xPos, 10, 100, 30);
  99. oprnoSearchField.addActionListener(e -> doSearch()); // 回车搜索
  100. topPanel.add(oprnoSearchField);
  101. xPos += 110;
  102. }
  103. // 查询按钮
  104. btnSearch = new JButton("查询");
  105. btnSearch.setFont(new Font("微软雅黑", Font.PLAIN, 13));
  106. btnSearch.setBounds(xPos, 10, 70, 30);
  107. btnSearch.addActionListener(e -> doSearch());
  108. topPanel.add(btnSearch);
  109. xPos += 80;
  110. // 刷新按钮
  111. btnRefresh = new JButton("刷新");
  112. btnRefresh.setFont(new Font("微软雅黑", Font.PLAIN, 13));
  113. btnRefresh.setBounds(xPos, 10, 70, 30);
  114. btnRefresh.addActionListener(e -> {
  115. clearSearchFields();
  116. refreshData();
  117. });
  118. topPanel.add(btnRefresh);
  119. xPos += 80;
  120. // 上一页按钮
  121. btnPrevious = new JButton("上一页");
  122. btnPrevious.setFont(new Font("微软雅黑", Font.PLAIN, 13));
  123. btnPrevious.setBounds(xPos, 10, 80, 30);
  124. btnPrevious.addActionListener(e -> {
  125. if (pageNo > 1) {
  126. pageNo--;
  127. loadData();
  128. }
  129. });
  130. topPanel.add(btnPrevious);
  131. xPos += 85;
  132. // 页码显示
  133. pageLabel = new JLabel("0/0");
  134. pageLabel.setFont(new Font("微软雅黑", Font.PLAIN, 13));
  135. pageLabel.setHorizontalAlignment(SwingConstants.CENTER);
  136. pageLabel.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1));
  137. pageLabel.setBounds(xPos, 10, 70, 30);
  138. topPanel.add(pageLabel);
  139. xPos += 75;
  140. // 下一页按钮
  141. btnNext = new JButton("下一页");
  142. btnNext.setFont(new Font("微软雅黑", Font.PLAIN, 13));
  143. btnNext.setBounds(xPos, 10, 80, 30);
  144. btnNext.addActionListener(e -> {
  145. if (pageNo < totalPages) {
  146. pageNo++;
  147. loadData();
  148. }
  149. });
  150. topPanel.add(btnNext);
  151. // 表格面板
  152. JPanel tablePanel = new JPanel();
  153. tablePanel.setBounds(0, 50, 1200, 518);
  154. tablePanel.setLayout(new GridLayout(1, 1, 0, 0));
  155. add(tablePanel);
  156. // 创建表格模型
  157. tableModel = new DefaultTableModel(COLUMN_NAMES, 0) {
  158. @Override
  159. public boolean isCellEditable(int row, int column) {
  160. return false;
  161. }
  162. };
  163. // 创建表格
  164. table = new JTable(tableModel);
  165. table.setRowHeight(32);
  166. table.setFont(new Font("微软雅黑", Font.PLAIN, 13));
  167. table.getTableHeader().setFont(new Font("微软雅黑", Font.BOLD, 14));
  168. table.getTableHeader().setReorderingAllowed(false);
  169. // 设置列宽
  170. setColumnWidths();
  171. // 设置居中渲染器
  172. DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
  173. centerRenderer.setHorizontalAlignment(JLabel.CENTER);
  174. for (int i = 0; i < table.getColumnCount(); i++) {
  175. table.getColumnModel().getColumn(i).setCellRenderer(centerRenderer);
  176. }
  177. // 添加滚动面板
  178. JScrollPane scrollPane = new JScrollPane(table);
  179. tablePanel.add(scrollPane);
  180. // 添加组件大小变化监听器
  181. addComponentListener(new ComponentAdapter() {
  182. @Override
  183. public void componentResized(ComponentEvent e) {
  184. int w = getWidth();
  185. int h = getHeight();
  186. // 调整顶部面板宽度
  187. topPanel.setBounds(0, 0, w, 50);
  188. // 调整表格面板
  189. if (h > 50) {
  190. tablePanel.setBounds(0, 50, w, h - 50);
  191. }
  192. topPanel.revalidate();
  193. tablePanel.revalidate();
  194. }
  195. });
  196. }
  197. /**
  198. * 设置列宽
  199. */
  200. private void setColumnWidths() {
  201. TableColumn column;
  202. // 工件码
  203. column = table.getColumnModel().getColumn(0);
  204. column.setPreferredWidth(260);
  205. // 工位号
  206. column = table.getColumnModel().getColumn(1);
  207. column.setPreferredWidth(90);
  208. // 工位结果
  209. column = table.getColumnModel().getColumn(2);
  210. column.setPreferredWidth(70);
  211. // 作业人员
  212. column = table.getColumnModel().getColumn(3);
  213. column.setPreferredWidth(100);
  214. // 日期
  215. column = table.getColumnModel().getColumn(4);
  216. column.setPreferredWidth(150);
  217. // 状态
  218. column = table.getColumnModel().getColumn(5);
  219. column.setPreferredWidth(80);
  220. }
  221. /**
  222. * 清空搜索框
  223. */
  224. private void clearSearchFields() {
  225. snSearchField.setText("");
  226. if (oprnoSearchField != null) {
  227. oprnoSearchField.setText("");
  228. }
  229. }
  230. /**
  231. * 执行搜索
  232. */
  233. private void doSearch() {
  234. pageNo = 1;
  235. loadData();
  236. }
  237. /**
  238. * 刷新数据(重置到第一页)
  239. */
  240. public void refreshData() {
  241. pageNo = 1;
  242. loadData();
  243. }
  244. /**
  245. * 加载数据
  246. */
  247. public void loadData() {
  248. // 获取搜索条件
  249. String searchSn = snSearchField.getText().trim();
  250. String searchOprno = oprno; // 默认使用构造函数传入的工位号
  251. // 如果是"所有工位"模式,检查是否有工位号搜索条件
  252. if (isAllStation && oprnoSearchField != null) {
  253. String inputOprno = oprnoSearchField.getText().trim();
  254. if (!inputOprno.isEmpty()) {
  255. searchOprno = inputOprno;
  256. }
  257. }
  258. final String finalSearchOprno = searchOprno;
  259. final String finalSearchSn = searchSn;
  260. // 在后台线程中执行数据加载
  261. SwingWorker<WorkRecordResp, Void> worker = new SwingWorker<WorkRecordResp, Void>() {
  262. @Override
  263. protected WorkRecordResp doInBackground() throws Exception {
  264. // 更新状态
  265. SwingUtilities.invokeLater(() -> {
  266. statusLabel.setText("正在加载...");
  267. setButtonsEnabled(false);
  268. });
  269. // 调用接口查询数据
  270. return DataUtil.getWorkRecordList(finalSearchOprno, finalSearchSn, pageNo, PAGE_SIZE);
  271. }
  272. @Override
  273. protected void done() {
  274. try {
  275. WorkRecordResp resp = get();
  276. updateUI(resp, finalSearchOprno);
  277. } catch (Exception e) {
  278. log.error("加载工作记录失败: {}", e.getMessage());
  279. updateUIError("加载失败: " + e.getMessage());
  280. }
  281. }
  282. };
  283. worker.execute();
  284. }
  285. /**
  286. * 设置按钮启用状态
  287. */
  288. private void setButtonsEnabled(boolean enabled) {
  289. btnSearch.setEnabled(enabled);
  290. btnRefresh.setEnabled(enabled);
  291. btnPrevious.setEnabled(enabled && pageNo > 1);
  292. btnNext.setEnabled(enabled && pageNo < totalPages);
  293. }
  294. /**
  295. * 更新UI显示数据
  296. */
  297. private void updateUI(WorkRecordResp resp, String queryOprno) {
  298. // 清空表格
  299. tableModel.setRowCount(0);
  300. if (resp == null || !resp.isResult()) {
  301. String msg = resp != null ? resp.getMessage() : "请求失败";
  302. // 服务端失败时仍展示本地提交记录
  303. fillLocalSubmitRows(queryOprno);
  304. updateUIError(msg);
  305. return;
  306. }
  307. // 更新分页信息
  308. totalCount = resp.getCount();
  309. totalPages = (int) Math.ceil((double) totalCount / PAGE_SIZE);
  310. if (totalPages == 0) totalPages = 1;
  311. // 更新页码显示
  312. pageLabel.setText(pageNo + "/" + totalPages);
  313. // 更新按钮状态
  314. setButtonsEnabled(true);
  315. // 更新状态标签
  316. String oprnoDisplay;
  317. if (isAllStation) {
  318. oprnoDisplay = (queryOprno == null || queryOprno.isEmpty()) ? "所有工位" : queryOprno;
  319. } else {
  320. oprnoDisplay = oprno;
  321. }
  322. statusLabel.setText("工位:" + oprnoDisplay + " 共" + totalCount + "条");
  323. // 填充表格数据:本地未提交置顶,服务端记录标记为已提交
  324. Set<String> pendingKeys = new HashSet<>();
  325. if (pageNo == 1) {
  326. pendingKeys.addAll(fillLocalSubmitRows(queryOprno));
  327. }
  328. List<WorkRecordData> list = resp.getList();
  329. if (list != null && !list.isEmpty()) {
  330. for (WorkRecordData data : list) {
  331. String key = data.getSn() + "|" + data.getOprno();
  332. if (pendingKeys.contains(key)) {
  333. continue;
  334. }
  335. String state = data.getSubmitState();
  336. if (state == null || state.isEmpty()) {
  337. state = "已提交";
  338. }
  339. Object[] row = {
  340. data.getSn(),
  341. data.getOprno(),
  342. data.getContent(),
  343. data.getUpdateBy(),
  344. data.getUpdateDate(),
  345. state
  346. };
  347. tableModel.addRow(row);
  348. }
  349. }
  350. // 刷新表格
  351. table.repaint();
  352. }
  353. /** 填充本地未提交记录;返回未提交的 sn|oprno 集合 */
  354. private Set<String> fillLocalSubmitRows(String queryOprno) {
  355. Set<String> pendingKeys = new HashSet<>();
  356. String localOprno = isAllStation
  357. ? (queryOprno == null || queryOprno.isEmpty() ? null : queryOprno)
  358. : oprno;
  359. String snFilter = snSearchField != null ? snSearchField.getText().trim() : "";
  360. List<String[]> localRows = JdbcUtils.getSubmitRecordRows(localOprno, snFilter, 50);
  361. for (String[] row : localRows) {
  362. if ("未提交".equals(row[5])) {
  363. pendingKeys.add(row[0] + "|" + row[1]);
  364. tableModel.addRow(new Object[]{row[0], row[1], row[2], row[3], row[4], row[5]});
  365. }
  366. }
  367. return pendingKeys;
  368. }
  369. /**
  370. * 更新UI显示错误信息
  371. */
  372. private void updateUIError(String message) {
  373. statusLabel.setText("错误: " + message + "(已显示本地提交记录)");
  374. pageLabel.setText(pageNo + "/" + Math.max(totalPages, 1));
  375. setButtonsEnabled(true);
  376. btnPrevious.setEnabled(pageNo > 1);
  377. btnNext.setEnabled(false);
  378. // 不在这里清空表格,保留 fillLocalSubmitRows 已填充的本地记录
  379. table.repaint();
  380. }
  381. /**
  382. * 获取当前工位号
  383. */
  384. public String getOprno() {
  385. return oprno;
  386. }
  387. }