diff --git a/.idea/libraries/junit_4_12.xml b/.idea/libraries/junit_4_12.xml index 3e0b5d8..fdd6e34 100644 --- a/.idea/libraries/junit_4_12.xml +++ b/.idea/libraries/junit_4_12.xml @@ -1,9 +1,8 @@ - - + - - + + diff --git a/db/dbuml.db3 b/db/dbuml.db3 index a4b4bc7..c8e1aab 100644 Binary files a/db/dbuml.db3 and b/db/dbuml.db3 differ diff --git a/src/DML.java b/src/DML.java index 24b15a0..b0a0c25 100644 --- a/src/DML.java +++ b/src/DML.java @@ -69,7 +69,7 @@ public class DML { try (Connection conn = DriverManager.getConnection(URL); Statement stmt = conn.createStatement()) { - String sql = "DELETE FROM operation_logs"; + String sql = "DELETE FROM warehouse"; int result = stmt.executeUpdate(sql); System.out.println("已清空数据表,删除了 " + result + " 条记录"); @@ -93,4 +93,96 @@ public class DML { e.printStackTrace(); } } //删除指定数据表 + + @Test + public void showCurrentStock() { + try (Connection conn = DriverManager.getConnection(URL); + Statement stmt = conn.createStatement()) { + + // 查询每个商品的当前库存(入库减去出库) + String sql = "SELECT goods_id, SUM(quantity) as current_stock " + + "FROM warehouse " + + "GROUP BY goods_id"; + ResultSet rs = stmt.executeQuery(sql); + + // 打印表头 + System.out.println("===================== 当前库存状态 ====================="); + System.out.printf("%-20s %-15s%n", "货物名称", "当前库存"); + System.out.println("==================================================="); + + // 打印数据 + while (rs.next()) { + System.out.printf("%-20s %-15d%n", + rs.getString("goods_id"), + rs.getInt("current_stock") + ); + } + System.out.println("==================================================="); + + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @Test + public void showAllTransactions() { + try (Connection conn = DriverManager.getConnection(URL); + Statement stmt = conn.createStatement()) { + + // 查询所有出入库记录 + String sql = "SELECT *, " + + "CASE WHEN quantity > 0 THEN '入库' ELSE '出库' END as type " + + "FROM warehouse " + + "ORDER BY inbound_time DESC"; + ResultSet rs = stmt.executeQuery(sql); + + // 打印表头 + System.out.println("===================== 出入库记录 ====================="); + System.out.printf("%-15s %-15s %-8s %-8s %-15s %-25s%n", + "单号", "货物名称", "数量", "类型", "供应商", "时间"); + System.out.println("==================================================="); + + // 打印数据 + while (rs.next()) { + System.out.printf("%-15s %-15s %-8d %-8s %-15s %-25s%n", + rs.getString("id"), + rs.getString("goods_id"), + Math.abs(rs.getInt("quantity")), + rs.getString("type"), + rs.getString("supplier"), + rs.getString("inbound_time") + ); + } + System.out.println("==================================================="); + + } catch (SQLException e) { + e.printStackTrace(); + } + } + + @Test + public void deleteOutboundRecord() { + try (Connection conn = DriverManager.getConnection(URL); + Statement stmt = conn.createStatement()) { + + // 删除出库记录的SQL语句 + String sql = "DELETE FROM warehouse WHERE id = ?"; + + try (PreparedStatement pstmt = conn.prepareStatement(sql)) { + // 这里可以设置要删除的记录ID + pstmt.setString(1, "要删除的记录ID"); + int result = pstmt.executeUpdate(); + + if (result > 0) { + System.out.println("出库记录删除成功"); + } else { + System.out.println("未找到要删除的记录"); + } + } + + } catch (SQLException e) { + e.printStackTrace(); + System.out.println("删除出库记录失败:" + e.getMessage()); + } + } } \ No newline at end of file diff --git a/src/model/OutboundRecord.java b/src/model/OutboundRecord.java index dde4c6e..30bf39d 100644 --- a/src/model/OutboundRecord.java +++ b/src/model/OutboundRecord.java @@ -1,3 +1,4 @@ + package model; import java.time.LocalDateTime; @@ -6,35 +7,76 @@ public class OutboundRecord { private String id; private String goodsId; private int quantity; - private String supplier; - private LocalDateTime inboundTime; + private String customer; + private LocalDateTime outboundTime; private String operator; private String remark; - public OutboundRecord(String id, String goodsId, int quantity, String supplier, - LocalDateTime inboundTime, String operator, String remark) { + public OutboundRecord(String id, String goodsId, int quantity, String customer, + LocalDateTime outboundTime, String operator, String remark) { this.id = id; this.goodsId = goodsId; this.quantity = quantity; - this.supplier = supplier; - this.inboundTime = inboundTime; + this.customer = customer; + this.outboundTime = outboundTime; this.operator = operator; this.remark = remark; } // Getters and Setters - public String getId() { return id; } - public void setId(String id) { this.id = id; } - public String getGoodsId() { return goodsId; } - public void setGoodsId(String goodsId) { this.goodsId = goodsId; } - public int getQuantity() { return quantity; } - public void setQuantity(int quantity) { this.quantity = quantity; } - public String getSupplier() { return supplier; } - public void setSupplier(String supplier) { this.supplier = supplier; } - public LocalDateTime getInboundTime() { return inboundTime; } - public void setInboundTime(LocalDateTime inboundTime) { this.inboundTime = inboundTime; } - public String getOperator() { return operator; } - public void setOperator(String operator) { this.operator = operator; } - public String getRemark() { return remark; } - public void setRemark(String remark) { this.remark = remark; } -} \ No newline at end of file + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getGoodsId() { + return goodsId; + } + + public void setGoodsId(String goodsId) { + this.goodsId = goodsId; + } + + public int getQuantity() { + return quantity; + } + + public void setQuantity(int quantity) { + this.quantity = quantity; + } + + public String getCustomer() { + return customer; + } + + public void setCustomer(String customer) { + this.customer = customer; + } + + public LocalDateTime getOutboundTime() { + return outboundTime; + } + + public void setOutboundTime(LocalDateTime outboundTime) { + this.outboundTime = outboundTime; + } + + public String getOperator() { + return operator; + } + + public void setOperator(String operator) { + this.operator = operator; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } +} \ No newline at end of file diff --git a/src/view/GoodsManagementView.java b/src/view/GoodsManagementView.java index 63c97c2..0a1a56e 100644 --- a/src/view/GoodsManagementView.java +++ b/src/view/GoodsManagementView.java @@ -11,7 +11,6 @@ import model.Goods; import java.sql.Connection; import java.sql.DriverManager; -import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Statement; import java.time.LocalDateTime; @@ -146,16 +145,19 @@ public class GoodsManagementView extends BorderPane { String url = "jdbc:sqlite:db/dbuml.db3"; List goodsList = new ArrayList<>(); try (Connection conn = DriverManager.getConnection(url)) { - String sql = "SELECT * FROM warehouse ORDER BY inbound_time DESC"; + String sql = "SELECT id, goods_id as name, quantity, " + + "supplier, inbound_time, operator, remark " + + "FROM warehouse " + + "ORDER BY id"; // 不再使用GROUP BY,直接显示所有记录 try (Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) { while (rs.next()) { Goods goods = new Goods( - rs.getString("id"), - rs.getString("goods_id"), - rs.getInt("quantity"), - rs.getString("remark") + rs.getString("id"), + rs.getString("name"), + rs.getInt("quantity"), + rs.getString("remark") ); goods.setInboundTime(LocalDateTime.parse(rs.getString("inbound_time"))); goods.setOperator(rs.getString("operator")); @@ -196,41 +198,33 @@ public class GoodsManagementView extends BorderPane { return; } - // 检查是否存在该记录 - String url = "jdbc:sqlite:db/dbuml.db3"; - try (Connection conn = DriverManager.getConnection(url)) { - String checkSql = "SELECT * FROM warehouse WHERE id = ?"; - try (PreparedStatement pstmt = conn.prepareStatement(checkSql)) { - pstmt.setString(1, id); - ResultSet rs = pstmt.executeQuery(); - - if (rs.next()) { - // 记录存在,执行更新操作 - String updateSql = "UPDATE warehouse SET goods_id = ?, quantity = ?, " + - "supplier = ?, remark = ? WHERE id = ?"; - try (PreparedStatement updateStmt = conn.prepareStatement(updateSql)) { - updateStmt.setString(1, name); - updateStmt.setInt(2, quantity); - updateStmt.setString(3, supplier); - updateStmt.setString(4, remark); - updateStmt.setString(5, id); - - updateStmt.executeUpdate(); - showAlert("成功", "货物信息已更新!"); - } - } else { - showAlert("错误", "未找到指定ID的货物记录!"); - return; - } - } + // 查找货物对象 + Goods existingGoods = DataManager.getInstance().getGoods(id); + if (existingGoods == null) { + // 插入新货物 + Goods newGoods = new Goods(String.format("NO%014d", System.currentTimeMillis()), + name, quantity, remark); + newGoods.setInboundTime(LocalDateTime.now()); + newGoods.setOperator("当前用户"); + newGoods.setSupplier(supplier); + DataManager.getInstance().addGoodsToDatabase(newGoods); + } else { + // 更新现有货物 + existingGoods.setName(name); + existingGoods.setQuantity(quantity); + existingGoods.setSupplier(supplier); + existingGoods.setRemark(remark); + DataManager.getInstance().updateGoodsInDatabase(existingGoods); } - // 更新表格显示 + // 更新表格 loadGoodsData(); // 清空输入 handleClear(); + showAlert("成功", "货物信息已更新!"); + } catch (Exception e) { showAlert("错误", "保存失败:" + e.getMessage()); e.printStackTrace(); diff --git a/src/view/InboundView.java b/src/view/InboundView.java index 08b6731..e485037 100644 --- a/src/view/InboundView.java +++ b/src/view/InboundView.java @@ -182,14 +182,15 @@ public class InboundView extends BorderPane { } // 创建入库记录 - String id = "IN" + System.currentTimeMillis(); + String id = String.format("NO%014d", System.currentTimeMillis()); LocalDateTime now = LocalDateTime.now(); // 修改数据库连接为相对路径 String url = "jdbc:sqlite:db/dbuml.db3"; try (Connection conn = DriverManager.getConnection(url)) { - String sql = "INSERT INTO warehouse (id, goods_id, quantity, supplier, inbound_time, operator, remark, type) " + - "VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; + String sql = "INSERT INTO warehouse (id, goods_id, quantity, supplier, inbound_time, operator, remark) " + + "VALUES (?, ?, ?, ?, ?, ?, ?)"; + try (PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setString(1, id); pstmt.setString(2, goodsName); @@ -198,8 +199,7 @@ public class InboundView extends BorderPane { pstmt.setString(5, now.toString()); pstmt.setString(6, "当前用户"); pstmt.setString(7, remark); - pstmt.setString(8, "IN"); // 设置类型为入库 - + pstmt.executeUpdate(); } } @@ -256,7 +256,7 @@ public class InboundView extends BorderPane { private void loadInboundRecords() { String url = "jdbc:sqlite:db/dbuml.db3"; try (Connection conn = DriverManager.getConnection(url)) { - String sql = "SELECT * FROM warehouse WHERE type = 'IN' ORDER BY inbound_time DESC"; + String sql = "SELECT * FROM warehouse ORDER BY inbound_time DESC"; try (Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) { diff --git a/src/view/OutboundView.java b/src/view/OutboundView.java index b734174..3d84a9e 100644 --- a/src/view/OutboundView.java +++ b/src/view/OutboundView.java @@ -11,8 +11,6 @@ import model.OutboundRecord; import model.DataManager; import model.Goods; import javafx.collections.FXCollections; -import model.InboundRecord; - import java.util.List; import java.util.stream.Collectors; import java.sql.*; @@ -20,7 +18,7 @@ import java.sql.*; public class OutboundView extends BorderPane { private TextField goodsField; - private TextField supplierField; + private TextField customerField; private TextField quantityField; private TextField remarkField; private TableView tableView; @@ -49,20 +47,21 @@ public class OutboundView extends BorderPane { VBox topArea = new VBox(10); topArea.setPadding(new Insets(10)); - // 第一行:基本信息 + // 基本信息 GridPane basicInfo = new GridPane(); basicInfo.setHgap(10); basicInfo.setVgap(10); + // 第一行:货物名称和供应商 Label goodsLabel = new Label("货物名称:"); goodsField = new TextField(); goodsField.setPromptText("请输入货物名称"); Label supplierLabel = new Label("供应商:"); - supplierField = new TextField(); - supplierField.setPromptText("请输入供应商"); + customerField = new TextField(); + customerField.setPromptText("请输入供应商"); - basicInfo.addRow(0, goodsLabel, goodsField, supplierLabel, supplierField); + basicInfo.addRow(0, goodsLabel, goodsField, supplierLabel, customerField); // 第二行:数量和备注 Label quantityLabel = new Label("数量:"); @@ -92,7 +91,7 @@ public class OutboundView extends BorderPane { buttonBox.setAlignment(Pos.CENTER_RIGHT); buttonBox.setPadding(new Insets(10, 0, 0, 0)); - Button saveButton = new Button("保存"); + Button saveButton = new Button("出库"); saveButton.setOnAction(e -> handleSave()); Button clearButton = new Button("清空"); @@ -107,32 +106,57 @@ public class OutboundView extends BorderPane { private TableView createTableView() { TableView table = new TableView<>(); - TableColumn idCol = new TableColumn<>("出库单号"); + TableColumn idCol = new TableColumn<>("单号"); idCol.setCellValueFactory(new PropertyValueFactory<>("id")); + idCol.setPrefWidth(150); TableColumn goodsCol = new TableColumn<>("货物名称"); goodsCol.setCellValueFactory(new PropertyValueFactory<>("goodsId")); + goodsCol.setPrefWidth(120); TableColumn quantityCol = new TableColumn<>("数量"); quantityCol.setCellValueFactory(new PropertyValueFactory<>("quantity")); + quantityCol.setPrefWidth(80); - TableColumn supplierCol = new TableColumn<>("供应商"); - supplierCol.setCellValueFactory(new PropertyValueFactory<>("supplier")); + TableColumn customerCol = new TableColumn<>("供应商"); + customerCol.setCellValueFactory(new PropertyValueFactory<>("customer")); + customerCol.setPrefWidth(120); TableColumn timeCol = new TableColumn<>("出库时间"); - timeCol.setCellValueFactory(new PropertyValueFactory<>("inboundTime")); // 保持字段名不变,但实际表示出库时间 + timeCol.setCellValueFactory(new PropertyValueFactory<>("outboundTime")); + timeCol.setPrefWidth(180); + timeCol.setCellFactory(column -> new TableCell() { + private final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + @Override + protected void updateItem(LocalDateTime item, boolean empty) { + super.updateItem(item, empty); + if (empty || item == null) { + setText(null); + } else { + setText(formatter.format(item)); + } + } + }); TableColumn operatorCol = new TableColumn<>("操作员"); operatorCol.setCellValueFactory(new PropertyValueFactory<>("operator")); + operatorCol.setPrefWidth(100); TableColumn remarkCol = new TableColumn<>("备注"); remarkCol.setCellValueFactory(new PropertyValueFactory<>("remark")); + remarkCol.setPrefWidth(150); - table.getColumns().addAll(idCol, goodsCol, quantityCol, supplierCol, + table.getColumns().addAll(idCol, goodsCol, quantityCol, customerCol, timeCol, operatorCol, remarkCol); - table.getItems().addListener((javafx.collections.ListChangeListener.Change c) -> { - updateTotal(); + // 添加双击事件处理 + table.setOnMouseClicked(event -> { + if (event.getClickCount() == 2) { + OutboundRecord selectedRecord = table.getSelectionModel().getSelectedItem(); + if (selectedRecord != null) { + fillFields(selectedRecord); + } + } }); return table; @@ -161,98 +185,89 @@ public class OutboundView extends BorderPane { private void handleSave() { try { String goodsName = goodsField.getText().trim(); - String supplier = supplierField.getText().trim(); + String customer = customerField.getText().trim(); String quantityText = quantityField.getText().trim(); String remark = remarkField.getText().trim(); // 输入验证 - if (goodsName.isEmpty() || supplier.isEmpty() || quantityText.isEmpty()) { + if (goodsName.isEmpty() || customer.isEmpty() || quantityText.isEmpty()) { showAlert("错误", "请填写完整的出库信息!"); return; } - int quantity; - try { - quantity = Integer.parseInt(quantityText); - if (quantity <= 0) { - showAlert("错误", "数量必须大于0!"); - return; - } - } catch (NumberFormatException e) { - showAlert("错误", "请输入有效的数量!"); + int quantity = Integer.parseInt(quantityText); + if (quantity <= 0) { + showAlert("错误", "数量必须大于0!"); return; } - // 检查库存是否足够 - if (!isStockSufficient(goodsName, quantity)) { - showAlert("错误", "库存不足!"); - return; - } - - // 创建出库记录 - String id = "OUT" + System.currentTimeMillis(); - LocalDateTime now = LocalDateTime.now(); - - // 修改数据库连接为相对路径 String url = "jdbc:sqlite:db/dbuml.db3"; try (Connection conn = DriverManager.getConnection(url)) { - String sql = "INSERT INTO warehouse (id, goods_id, quantity, supplier, inbound_time, operator, remark, type) " + - "VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; - - try (PreparedStatement pstmt = conn.prepareStatement(sql)) { - pstmt.setString(1, id); - pstmt.setString(2, goodsName); - pstmt.setInt(3, quantity); - pstmt.setString(4, supplier); - pstmt.setString(5, now.toString()); - pstmt.setString(6, "当前用户"); - pstmt.setString(7, remark); - pstmt.setString(8, "OUT"); // 设置类型为出库 - - pstmt.executeUpdate(); + // 首先查询当前库存 + String checkSql = "SELECT id, quantity FROM warehouse WHERE goods_id = ?"; + try (PreparedStatement checkStmt = conn.prepareStatement(checkSql)) { + checkStmt.setString(1, goodsName); + ResultSet rs = checkStmt.executeQuery(); + + if (rs.next()) { + int currentStock = rs.getInt("quantity"); + String recordId = rs.getString("id"); + + if (currentStock < quantity) { + showAlert("错误", "库存不足!当前库存: " + currentStock); + return; + } + + int remainingStock = currentStock - quantity; + + if (remainingStock == 0) { + // 如果全部出库,删除记录 + String deleteSql = "DELETE FROM warehouse WHERE id = ?"; + try (PreparedStatement deleteStmt = conn.prepareStatement(deleteSql)) { + deleteStmt.setString(1, recordId); + deleteStmt.executeUpdate(); + } + } else { + // 更新剩余库存 + String updateSql = "UPDATE warehouse SET quantity = ? WHERE id = ?"; + try (PreparedStatement updateStmt = conn.prepareStatement(updateSql)) { + updateStmt.setInt(1, remainingStock); + updateStmt.setString(2, recordId); + updateStmt.executeUpdate(); + } + } + + // 刷新表格显示 + loadOutboundRecords(); + + // 清空输入 + handleClear(); + + // 添加操作日志 + String details = String.format("出库货物:%s,数量:%d,供应商:%s", + goodsName, quantity, customer); + DataManager.getInstance().addOperationLog("出库", goodsName, "当前用户", details); + + showAlert("成功", "出库记录已保存!"); + } else { + showAlert("错误", "未找到该货物的库存记录!"); + } } } - - // 创建记录对象并添加到表格 - OutboundRecord record = new OutboundRecord( - id, - goodsName, - quantity, - supplier, - now, - "当前用户", - remark - ); - - // 添加到表格 - tableView.getItems().add(record); - - // 更新总计 - updateTotal(); - - // 清空输入 - handleClear(); - - // 添加操作日志 - String details = String.format("出库货物:%s,数量:%d,供应商:%s", - goodsName, quantity, supplier); - DataManager.getInstance().addOperationLog("出库", goodsName, "当前用户", details); - - showAlert("成功", "出库记录已保存!"); - + } catch (NumberFormatException e) { + showAlert("错误", "请输入有效的数量!"); } catch (Exception e) { - showAlert("错误", "保存失败:" + e.getMessage()); e.printStackTrace(); + showAlert("错误", "保存失败:" + e.getMessage()); } } private void handleClear() { goodsField.clear(); - supplierField.clear(); + customerField.clear(); quantityField.clear(); remarkField.clear(); } - private void showAlert(String title, String content) { Alert alert = new Alert(Alert.AlertType.INFORMATION); alert.setTitle(title); @@ -261,26 +276,42 @@ public class OutboundView extends BorderPane { alert.showAndWait(); } - // 添加加载数据的方法 private void loadOutboundRecords() { String url = "jdbc:sqlite:db/dbuml.db3"; try (Connection conn = DriverManager.getConnection(url)) { - String sql = "SELECT * FROM warehouse WHERE type = 'OUT' ORDER BY inbound_time DESC"; + String sql = "SELECT * FROM warehouse ORDER BY inbound_time DESC"; try (Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) { - + + tableView.getItems().clear(); while (rs.next()) { - OutboundRecord record = new OutboundRecord( - rs.getString("id"), - rs.getString("goods_id"), - rs.getInt("quantity"), - rs.getString("supplier"), - LocalDateTime.parse(rs.getString("inbound_time")), // 实际表示出库时间 - rs.getString("operator"), - rs.getString("remark") - ); - tableView.getItems().add(record); + try { + String id = rs.getString("id"); + String goodsId = rs.getString("goods_id"); + int quantity = rs.getInt("quantity"); + String supplier = rs.getString("supplier"); + String timeStr = rs.getString("inbound_time"); + String operator = rs.getString("operator"); + String remark = rs.getString("remark"); + + LocalDateTime dateTime = LocalDateTime.parse(timeStr); + + OutboundRecord record = new OutboundRecord( + id, + goodsId, + quantity, + supplier, + dateTime, + operator, + remark + ); + tableView.getItems().add(record); + + } catch (Exception e) { + e.printStackTrace(); + } } + updateTotal(); } } catch (Exception e) { e.printStackTrace(); @@ -288,24 +319,11 @@ public class OutboundView extends BorderPane { } } - // 查询库存是否足够 - private boolean isStockSufficient(String goodsName, int quantity) { - String url = "jdbc:sqlite:db/dbuml.db3"; - try (Connection conn = DriverManager.getConnection(url)) { - String sql = "SELECT SUM(quantity) AS total_stock FROM warehouse WHERE goods_id = ? AND type = 'IN'"; - try (PreparedStatement pstmt = conn.prepareStatement(sql)) { - pstmt.setString(1, goodsName); - try (ResultSet rs = pstmt.executeQuery()) { - if (rs.next()) { - int totalStock = rs.getInt("total_stock"); - return totalStock >= quantity; - } - } - } - } catch (SQLException e) { - e.printStackTrace(); - showAlert("错误", "查询库存失败:" + e.getMessage()); - } - return false; // 默认返回false,防止未知错误导致库存检查失败 + // ��加填充字段的方法 + private void fillFields(OutboundRecord record) { + goodsField.setText(record.getGoodsId()); + customerField.setText(record.getCustomer()); + quantityField.setText(String.valueOf(record.getQuantity())); + remarkField.setText(record.getRemark()); } -} +} \ No newline at end of file