Imports System.Data.SqlClient Imports System.IO Imports NPOI.XSSF.UserModel Imports NPOI.SS.UserModel Public Class Frm_01_finish_rcp Private isFlashing As Boolean = False Dim cmd As New SqlCommand Dim da As New SqlDataAdapter Dim sql As String Dim colorArray(10) As Color Dim conn As New SqlConnection Private Sub SetupAutoCompleteForCustomer() Dim customerList As New AutoCompleteStringCollection() : customerList.AddRange(New String() {"客戶A", "客戶B", "客戶C", "客戶D"}) ' 可從數據庫加載 cbo_customer.AutoCompleteMode = AutoCompleteMode.SuggestAppend : cbo_customer.AutoCompleteSource = AutoCompleteSource.CustomSource cbo_customer.AutoCompleteCustomSource = customerList End Sub Private Sub SetupAutoCompleteForColor() Dim colorList As New AutoCompleteStringCollection() : colorList.AddRange(New String() {"紅色", "藍色", "綠色", "黑色", "白色"}) ' 可從數據庫加載 txtColor.AutoCompleteMode = AutoCompleteMode.SuggestAppend : txtColor.AutoCompleteSource = AutoCompleteSource.CustomSource txtColor.AutoCompleteCustomSource = colorList End Sub Private Sub Set_清單1(條件 As String) Dim ds1 As New DataSet 處方清單_dgv.DataSource = Nothing : ds1.Clear() 處方清單_dgv.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.EnableResizing 處方清單_dgv.ColumnHeadersHeight = 30 : 處方清單_dgv.AllowUserToAddRows = False : 處方清單_dgv.RowTemplate.Height = 20 處方清單_dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect SQL_塗飾處方清單(條件) da.Fill(ds1) : 處方清單_dgv.DataSource = ds1.Tables(0) : conn.Close() 處方清單_dgv.Columns(0).FillWeight = 200 For i As Integer = 0 To 處方清單_dgv.Columns.Count - 1 : 處方清單_dgv.Columns(i).ReadOnly = True : Next End Sub Private Sub Frm_01_finish_rcp_Load(sender As Object, e As EventArgs) Handles MyBase.Load Me.MdiParent = FrmMDI : Me.WindowState = 2 : Me.AutoScroll = True Set_清單1("") Timer1.Interval = 1000 ' 每 500 毫秒闪烁一次 txtCustomer.AutoCompleteMode = AutoCompleteMode.SuggestAppend : txtCustomer.AutoCompleteSource = AutoCompleteSource.CustomSource SetupAutoCompleteForCustomer() : SetupAutoCompleteForColor() End Sub Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick If isFlashing Then : 模式通知_lb.Text = "修改模式" : Else : 模式通知_lb.Text = "" : End If : isFlashing = Not isFlashing ' 切换闪烁状态 End Sub Private Sub 處方清單_dgv_SelectionChanged(sender As Object, e As EventArgs) Handles 處方清單_dgv.SelectionChanged Dim ds1 As New DataSet 處方_dgv.DataSource = Nothing : ds1.Clear() 處方_dgv.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.EnableResizing 處方_dgv.ColumnHeadersHeight = 30 : 處方_dgv.AllowUserToAddRows = False : 處方_dgv.RowTemplate.Height = 25 處方_dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect SQL_塗飾處方明細(處方清單_dgv.Rows(處方清單_dgv.CurrentCell.RowIndex).Cells(0).Value) da.Fill(ds1) : 處方_dgv.DataSource = ds1.Tables(0) : conn.Close() 處方_dgv.Columns(0).FillWeight = 220 : 處方_dgv.Columns(2).FillWeight = 180 For i As Integer = 0 To 處方_dgv.Columns.Count - 1 : 處方_dgv.Columns(i).ReadOnly = True : Next For Each row As DataGridViewRow In 處方_dgv.Rows : For Each cell As DataGridViewCell In row.Cells : cell.Tag = cell.Value : Next : Next End Sub Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles 關鍵字_tb.TextChanged Set_清單1("WHERE rcp_name LIKE N'%" & 關鍵字_tb.Text & "%'") End Sub Private Sub 處方_dgv_CellPainting(sender As Object, e As DataGridViewCellPaintingEventArgs) Handles 處方_dgv.CellPainting If e.RowIndex >= 0 AndAlso e.ColumnIndex >= 0 Then ' 自定义单元格绘制,确保字体位置居中,并选中单元格背景色为蓝色 Dim cell As DataGridViewCell = 處方_dgv.Rows(e.RowIndex).Cells(e.ColumnIndex) If cell.Style.ForeColor = Color.Red OrElse e.State.HasFlag(DataGridViewElementStates.Selected) Then ' 判断是否需要自定义绘制 Dim backgroundColor As Color = If(e.State.HasFlag(DataGridViewElementStates.Selected), ' 获取背景颜色 e.CellStyle.SelectionBackColor, e.CellStyle.BackColor) e.Graphics.FillRectangle(New SolidBrush(backgroundColor), e.CellBounds) ' 填充背景色 e.Paint(e.ClipBounds, DataGridViewPaintParts.Border) ' 使用默认的边框样式绘制边框 Dim textFormat As TextFormatFlags = TextFormatFlags.VerticalCenter ' 根据单元格的对齐方式调整文本绘制位置 If e.CellStyle.Alignment = DataGridViewContentAlignment.MiddleRight Then : textFormat = textFormat Or TextFormatFlags.Right ElseIf e.CellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter Then : textFormat = textFormat Or TextFormatFlags.HorizontalCenter Else : textFormat = textFormat Or TextFormatFlags.Left : End If ' 绘制文本内容 TextRenderer.DrawText(e.Graphics, cell.Value?.ToString(), e.CellStyle.Font, e.CellBounds, cell.Style.ForeColor, textFormat) e.Handled = True ' 阻止默认绘制 End If End If End Sub Private Sub 處方_dgv_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles 處方_dgv.CellValueChanged Dim currentCell As DataGridViewCell = 處方_dgv.Rows(e.RowIndex).Cells(e.ColumnIndex) ' 获取修改的单元格 If currentCell.Tag IsNot Nothing AndAlso Not currentCell.Value.Equals(currentCell.Tag) Then ' 检查 Tag 是否存在,以及当前值是否与原值不同 currentCell.Style.ForeColor = Color.Red ' 如果值被修改,将字体设置为红色 Else currentCell.Style.ForeColor = Color.Black ' 如果值未修改,恢复默认字体颜色 End If End Sub Private Sub Button1_Click(sender As Object, e As EventArgs) Handles btnEdit.Click ' 启用 Label1 模式通知_lb.Enabled = True ' 启动 Timer1 Timer1.Start() ' 确保当前 DataGridView 的焦点单元格有效 Dim currentCell As DataGridViewCell = 處方_dgv.CurrentCell If currentCell Is Nothing Then MessageBox.Show("请选中一个单元格进行编辑。") Return End If ' 获取当前选中行的第 0 列和第 2 列的值 Dim sysName As String = 處方_dgv.CurrentRow.Cells(0).Value.ToString() ' 化学品名称 Dim qty As String = 處方_dgv.CurrentRow.Cells(2).Value.ToString() ' 份数 ' 从数据库获取化学品名称作为自动完成数据 Dim suggestions As List(Of String) = ChemicalNamesFromDatabase() ' 初始化并显示 AutoCompleteInputBox,传入从数据库获取的建议列表 Dim inputBox As New AutoCompleteWithListBox("输入化学品名称", suggestions, sysName, qty) Dim my_input() As String If inputBox.ShowDialog() = DialogResult.OK Then my_input = Split(inputBox.UserInput, " ") ' Dim chemName = inputBox.UserInput ' 显示结果 MessageBox.Show($"选择的化学品:{my_input(1)}{vbNewLine}数量:{inputBox.Quantity}") End If Dim chemName = my_input(1) Dim re_qty = inputBox.Quantity ' 更新 DataGridView 的单元格信息 If inputBox.DialogResult = DialogResult.OK Then ' 判断化学品名称是否被修改 If sysName <> chemName Then 處方_dgv.CurrentRow.Cells("化工品名").Value = my_input(1) ' 更新化学品名称 處方_dgv.CurrentRow.Cells("化工品名").Style.ForeColor = Color.Red ' 设置化学品名称为红色字体 ' 查询化工分类并更新 Dim type1 As String = GetChemicalTypesFromDatabase(my_input(1)) 處方_dgv.CurrentRow.Cells("化工分类").Value = type1 ' 更新化工分类 End If ' 判断份数是否被修改 If qty <> inputBox.Quantity Then 處方_dgv.CurrentRow.Cells("份数").Value = re_qty ' 更新份数 處方_dgv.CurrentRow.Cells("份数").Style.ForeColor = Color.Red ' 设置份数为红色字体 End If End If End Sub Private Function GetChemicalTypesFromDatabase(chemicalName As String) As String ' 数据库连接字符串 Dim connectionString As String = connstring ' 请替换为你的实际数据库连接字符串 ' 查询语句 Dim query As String = "SELECT type FROM ht_k3_material WHERE name = @sys_name" Dim type1 As String = "" ' 使用 SQL 连接和命令 Using connection As New SqlConnection(connectionString) Dim command As New SqlCommand(query, connection) ' 添加查询参数 command.Parameters.AddWithValue("@sys_name", chemicalName) ' 打开数据库连接 connection.Open() ' 执行查询并获取结果 Dim result = command.ExecuteScalar() If result IsNot Nothing Then type1 = result.ToString() ' 确保返回类型为字符串 End If End Using ' 返回化工分类 Return type1 End Function ' 原本返回的是 String(),现在改为 List(Of String) Private Function ChemicalNamesFromDatabase() As List(Of String) Dim connectionString As String = connstring ' 换成你的数据库连接字符串 Dim query As String = "SELECT code,name FROM ht_k3_material" Dim chemicalNames As New List(Of String)() Using connection As New SqlConnection(connectionString) Using command As New SqlCommand(query, connection) connection.Open() Using reader As SqlDataReader = command.ExecuteReader() While reader.Read() ' 将 sys_name 添加到列表中 chemicalNames.Add(reader("code").ToString() & " " & reader("name").ToString()) End While End Using End Using End Using ' 返回 List(Of String) Return chemicalNames End Function Private Sub Button2_Click(sender As Object, e As EventArgs) Handles btnSave.Click ' 數據庫連接字串 Dim connectionString As String = connstring ' 確保你的連接字符串正確 ' **(A) 取得選中的 rcp_name** If 處方清單_dgv.CurrentRow Is Nothing OrElse 處方清單_dgv.CurrentRow.Cells("配料名称").Value Is Nothing Then MessageBox.Show("請先選擇一個配料名称 (rcp_name)!", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Warning) Return End If Dim rcpName As String = 處方清單_dgv.CurrentRow.Cells("配料名称").Value.ToString() ' **(B) 確保 dgv2 內有數據** If 處方_dgv.Rows.Count = 0 Then MessageBox.Show("沒有數據可更新!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information) Return End If ' **(C) 記錄目前選中的行** Dim selectedRowIndex As Integer = 處方_dgv.CurrentCell.RowIndex Dim selectedId As String = If(處方_dgv.CurrentRow.Cells("id").Value IsNot Nothing, 處方_dgv.CurrentRow.Cells("id").Value.ToString(), "") ' **(D) 開始 SQL Transaction** Using conn As New SqlConnection(connectionString) conn.Open() Using trans As SqlTransaction = conn.BeginTransaction() Try ' **(E) 刪除資料表中該 rcp_name 的所有數據** Dim deleteQuery As String = "DELETE FROM ht_finish_rcp WHERE rcp_name = @rcp_name;" Using cmd As New SqlCommand(deleteQuery, conn, trans) cmd.Parameters.AddWithValue("@rcp_name", rcpName) cmd.ExecuteNonQuery() End Using ' **(F) 遍歷 dgv2,將沒有刪除線的數據重新插入** Dim insertQuery As String = "INSERT INTO ht_finish_rcp (id, rcp_name, chem_name, percents, edited_date) VALUES (@id, @rcp_name, @chem_name, @percents, @edited_date);" For Each row As DataGridViewRow In 處方_dgv.Rows ' 確保不是空白行 If row.IsNewRow Then Continue For ' **(G) 檢查是否有刪除線 (Strikeout)** Dim hasStrikeout As Boolean = False For Each cell As DataGridViewCell In row.Cells If cell.Style.Font IsNot Nothing AndAlso cell.Style.Font.Strikeout Then hasStrikeout = True Exit For End If Next If hasStrikeout Then Debug.Print("跳過刪除線記錄:" & row.Cells("化工品名").Value.ToString()) ' Debug 記錄 Continue For ' **跳過刪除線的記錄,不插入數據庫** End If ' 取得數據 Dim idString As String = If(row.Cells("id").Value IsNot Nothing, row.Cells("id").Value.ToString(), "") If String.IsNullOrEmpty(idString) Then Continue For ' 跳過無效數據 Dim chemName As String = row.Cells("化工品名").Value.ToString() Dim percents As String = row.Cells("份数").Value.ToString() Dim dPercents As Decimal = 0 Decimal.TryParse(percents, dPercents) ' **(H) 插入新數據** Using cmd As New SqlCommand(insertQuery, conn, trans) cmd.Parameters.AddWithValue("@id", idString) cmd.Parameters.AddWithValue("@rcp_name", rcpName) cmd.Parameters.AddWithValue("@chem_name", chemName) cmd.Parameters.AddWithValue("@percents", dPercents) cmd.Parameters.AddWithValue("@edited_date", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")) cmd.ExecuteNonQuery() End Using Next ' **(I) 提交 Transaction** trans.Commit() MessageBox.Show("所有數據已成功同步至資料庫!", "更新成功", MessageBoxButtons.OK, MessageBoxIcon.Information) ' **(J) 重新載入 dgv2 的資料** ReloadDGV2(rcpName) ' **(K) 恢復選取的 row** RestoreSelectedRow(selectedRowIndex, selectedId) Catch ex As Exception ' **(L) 出錯時回滾** trans.Rollback() MessageBox.Show("更新失敗:" & ex.Message, "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error) End Try End Using End Using End Sub Private Sub RestoreSelectedRow(previousRowIndex As Integer, previousId As String) ' **確保 dgv2 內有數據** If 處方_dgv.Rows.Count = 0 Then Return ' **嘗試選擇原來的行** For Each row As DataGridViewRow In 處方_dgv.Rows If row.Cells("id").Value IsNot Nothing AndAlso row.Cells("id").Value.ToString() = previousId Then 處方_dgv.CurrentCell = row.Cells(0) row.Selected = True Return End If Next ' **如果原行被刪除,則選擇前一行** Dim newRowIndex As Integer = previousRowIndex If newRowIndex >= 處方_dgv.Rows.Count Then newRowIndex = 處方_dgv.Rows.Count - 1 ' 如果超過範圍,則選擇最後一行 End If If newRowIndex >= 0 Then 處方_dgv.CurrentCell = 處方_dgv.Rows(newRowIndex).Cells(0) 處方_dgv.Rows(newRowIndex).Selected = True End If End Sub Private Sub ReloadDGV2(rcpName As String) ' **SQL 查詢 rcp_name 的新數據** Dim query As String = "SELECT chem_name AS 化工品名, percents as 份数,id, EDITED_DATE FROM ht_finish_rcp WHERE rcp_name = @rcp_name" Dim connectionString As String = connstring Dim adapter As New SqlDataAdapter(query, connectionString) adapter.SelectCommand.Parameters.AddWithValue("@rcp_name", rcpName) Dim dt As New DataTable() adapter.Fill(dt) ' **重新綁定 DataGridView** 處方_dgv.DataSource = dt 處方_dgv.Columns(0).Width = 220 處方_dgv.Columns(2).Width = 220 End Sub ''' ''' 小工具:安全取得某欄位字串;如果是 Nothing 則回傳 "" ''' Private Function SafeCellValue(row As DataGridViewRow, columnName As String) As String If row.Cells(columnName).Value IsNot Nothing Then Return row.Cells(columnName).Value.ToString().Trim() End If Return String.Empty End Function Private Sub Button4_Click(sender As Object, e As EventArgs) Handles btnCancel.Click 關鍵字_tb.Enabled = False 'For Each cell As DataGridViewCell In dgv2.CurrentRow.Cells ' ' 将单元格的值恢复为 Tag 中存储的原始值 ' cell.Value = cell.Tag ' ' 将字体颜色恢复为默认黑色 ' cell.Style.ForeColor = Color.Black 'Next Try ' **檢查 DataGridView 是否有未保存的變更** If 處方_dgv IsNot Nothing AndAlso 處方_dgv.DataSource IsNot Nothing Then Dim dt As DataTable = CType(處方_dgv.DataSource, DataTable) ' **取消所有變更** dt.RejectChanges() End If ' **清除選取** 處方_dgv.ClearSelection() ' **隱藏 DataGridView 的空白行** 處方_dgv.AllowUserToAddRows = False ' **確保數值欄位不為 null** For Each row As DataGridViewRow In 處方_dgv.Rows If Not row.IsNewRow Then ' 避免影響新行 For Each cell As DataGridViewCell In row.Cells ' **如果是數值欄位,將 null 設為 0** If IsDBNull(cell.Value) AndAlso IsNumeric(cell.OwningColumn.DataPropertyName) Then cell.Value = 0 End If Next End If Next Catch ex As Exception MessageBox.Show("取消變更時發生錯誤:" & ex.Message, "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error) End Try End Sub Private Sub dgv2_DataError(sender As Object, e As DataGridViewDataErrorEventArgs) Handles 處方_dgv.DataError ' **防止 "無法將 null 設定給 DataGridView" 錯誤** If e.Exception IsNot Nothing Then MessageBox.Show("數據錯誤:" & e.Exception.Message, "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Warning) ' **只修正數值欄位,避免影響文字欄位** Try Dim columnName As String = 處方_dgv.Columns(e.ColumnIndex).DataPropertyName If IsNumeric(columnName) Then 處方_dgv.Rows(e.RowIndex).Cells(e.ColumnIndex).Value = 0 ' 設為 0,避免錯誤 Else 處方_dgv.Rows(e.RowIndex).Cells(e.ColumnIndex).Value = DBNull.Value ' 保持空值 End If Catch ex As Exception Debug.Print("無法修正 DataGridView 錯誤:" & ex.Message) End Try End If End Sub Private Sub Button3_Click(sender As Object, e As EventArgs) Handles btnDelete.Click If 處方_dgv.CurrentRow IsNot Nothing Then For Each cell As DataGridViewCell In 處方_dgv.CurrentRow.Cells ' 设置字体为带删除线的样式 Dim currentFont As Font = cell.Style.Font If currentFont Is Nothing Then currentFont = 處方_dgv.Font ' 使用默认字体 End If cell.Style.Font = New Font(currentFont, FontStyle.Strikeout) ' 设置背景颜色为红色 cell.Style.BackColor = Color.Red Next End If End Sub Private Function GetNewIDWithIncrement() As Decimal ' 如果 dgv2 为空,则返回 1 作为第一行的 ID If 處方_dgv.Rows.Count = 0 Then Return 1D Dim selectedIndex As Integer = 處方_dgv.CurrentRow.Index Dim currentID As Decimal = Convert.ToDecimal(處方_dgv.Rows(selectedIndex).Cells("id").Value) ' 如果选中的是最后一行,直接加 1 If selectedIndex = 處方_dgv.Rows.Count - 1 Then Return currentID + 1D End If ' 否则,在当前选中行后插入新记录,新 ID = 当前行 ID + 0.1 Return currentID + 0.1D End Function Private Sub Button5_Click(sender As Object, e As EventArgs) Handles btnInsert.Click ' 1️⃣ 获取 DataGridView 绑定的 DataTable Dim dt As DataTable = CType(處方_dgv.DataSource, DataTable) ' 2️⃣ 获取新 ID(当前选中行 ID + 0.1) Dim newID As Decimal = GetNewIDWithIncrement() ' 3️⃣ 读取数据库中的化工品建议列表 Dim suggestions As List(Of String) = ChemicalNamesFromDatabase().ToList() ' 4️⃣ 打开输入框,用户输入化工品名和数量 Dim inputBox As New AutoCompleteWithListBox("输入化学品名称", suggestions, "", "0") Dim my_input() As String If inputBox.ShowDialog() = DialogResult.OK Then ' 5️⃣ 读取用户输入 my_input = Split(inputBox.UserInput, " ") Dim chemName As String = my_input(1) Dim qty As String = inputBox.Quantity Dim type1 As String = GetChemicalTypesFromDatabase(chemName) ' 🚨 份数不可为 0,弹出警告并返回 🚨 If String.IsNullOrWhiteSpace(qty) OrElse Not IsNumeric(qty) OrElse Convert.ToDecimal(qty) = 0 Then MessageBox.Show("份数不可为 0,请输入正确的数量!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error) Return ' 直接退出,不执行插入 End If ' 6️⃣ 在 DataTable 中插入新行 Dim newRow As DataRow = dt.NewRow() newRow("化工品名") = chemName newRow("份数") = qty newRow("化工分类") = type1 newRow("id") = newID ' ID 采用小数递增 ' 檢查 DataTable 是否已經有 "Status" 欄位,沒有則新增 If Not dt.Columns.Contains("Status") Then dt.Columns.Add("Status", GetType(String)) ' 新增一個 "Status" 欄位,型別為 String End If ' **新增数据,标记为 "NEW"** newRow("Status") = "NEW" ' 这里添加一个新列 "Status" 作为标记 ' 7️⃣ 插入新行到选中行的下一行 dt.Rows.InsertAt(newRow, 處方_dgv.CurrentRow.Index + 1) ' 8️⃣ 重新绑定 DataGridView 處方_dgv.DataSource = dt ' 9️⃣ 设置新行的字体颜色为红色,表示未保存 For Each cell As DataGridViewCell In 處方_dgv.Rows(處方_dgv.CurrentRow.Index + 1).Cells cell.Style.ForeColor = Color.Red Next End If End Sub Private Sub Button6_Click(sender As Object, e As EventArgs) Handles btnGenerate.Click Dim my_list As String For Each row As DataGridViewRow In 處方_dgv.Rows If row.Cells("化工分类").Value.ToString = "" And Not (row.Cells("化工品名").Value Like "水*") Then my_list += row.Cells("化工品名").Value & vbNewLine End If Next If Microsoft.VisualBasic.Len(my_list) > 0 Then MsgBox("以下化工品名有误:" & vbNewLine & vbNewLine & my_list) Exit Sub End If ' **(1) 請使用者輸入泡料總重量** Dim totalWeightStr As String = InputBox("请输入配料的总重量 (kg):", "输入总重量") Dim totalWeight As Decimal ' **(2) 檢查輸入是否合法** If Not Decimal.TryParse(totalWeightStr, totalWeight) OrElse totalWeight <= 0 Then MessageBox.Show("請输入有效的总重量!", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Warning) Return End If ' **(3) 計算總份數** Dim totalPortions As Decimal = 0 For Each row As DataGridViewRow In 處方_dgv.Rows If row.IsNewRow Then Continue For ' 跳過新行 Dim portionStr As String = row.Cells("份数").Value.ToString() Dim portion As Decimal = 0 If Decimal.TryParse(portionStr, portion) Then totalPortions += portion End If Next ' **(4) 確保份數不為 0** If totalPortions = 0 Then MessageBox.Show("化工品的總份數為 0,無法計算重量!", "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Warning) Return End If ' **(5) 清空 dgv3 並填充新數據** Dim dt As New DataTable() dt.Columns.Add("化工品名", GetType(String)) dt.Columns.Add("化工分类", GetType(String)) dt.Columns.Add("份数", GetType(Decimal)) dt.Columns.Add("重量 (kg)", GetType(Decimal)) dt.Columns.Add("总重量 (kg)", GetType(Decimal)) dt.Columns.Add("化工代码", GetType(String)) ' **(6) 計算每個化工的重量並填入 dgv3** Dim totalCalculatedWeight As Decimal = 0 For Each row As DataGridViewRow In 處方_dgv.Rows If row.IsNewRow Then Continue For Dim chemName As String = row.Cells("化工品名").Value.ToString() Dim chemCategory As String = row.Cells("化工分类").Value.ToString() Dim portion As Decimal = Convert.ToDecimal(row.Cells("份数").Value) ' 計算該化工品的重量 Dim weight As Decimal = Math.Round((portion / totalPortions) * totalWeight, 1) totalCalculatedWeight += weight ' 累計總重量 ' **(7) 加入 DataTable** dt.Rows.Add(chemName, chemCategory, portion, weight, totalWeight) Next ' **(8) 添加總計行** Dim totalRow As DataRow = dt.NewRow() totalRow("化工品名") = "总计" totalRow("化工分类") = "" totalRow("份数") = totalPortions totalRow("重量 (kg)") = totalCalculatedWeight totalRow("总重量 (kg)") = totalWeight dt.Rows.Add(totalRow) ' **(9) 更新 dgv3** DGV3.DataSource = dt ' **(3) 設定總計行樣式(紅色粗體)** Dim lastRowIndex As Integer = DGV3.Rows.Count - 1 If lastRowIndex >= 0 Then Dim lastRow As DataGridViewRow = DGV3.Rows(lastRowIndex) If lastRow.Cells(0).Value IsNot Nothing AndAlso lastRow.Cells(0).Value.ToString() = "总计" Then For Each cell As DataGridViewCell In lastRow.Cells cell.Style.Font = New Font("Microsoft YaHei", 10, FontStyle.Bold) cell.Style.ForeColor = Color.Red Next End If End If ' **(10) 美化 dgv3** ' CustomizeDataGridView(DGV3) End Sub Private Sub Button_領料_Click(sender As Object, e As EventArgs) Handles Button7.Click ' ------------------------ 1️⃣ 生成領料單號 ------------------------ Dim out_Number As String = GenerateSerialNumber(DateTimePicker1.Value) ' ------------------------ 2️⃣ 計算總重量 ------------------------ Dim totalWeight As Double = DGV3.Rows.Cast(Of DataGridViewRow)(). Sum(Function(r) Convert.ToDouble(r.Cells(4).Value)) totalWeight = Math.Round(totalWeight) ' 四捨五入取整 ' ------------------------ 3️⃣ 讀取 Excel 模板 ------------------------ Dim templatePath As String = "C:\表格模版\涂饰配料标签模版.xlsx" Dim savePath As String = Path.Combine("C:\GHS", out_Number & ".xlsx") Dim workbook As IWorkbook Using fs As New FileStream(templatePath, FileMode.Open, FileAccess.Read) workbook = New XSSFWorkbook(fs) End Using ' 假設我們要操作第 1 個工作表 Dim sheet As ISheet = workbook.GetSheetAt(0) ' ------------------------ 4️⃣ 寫入 Excel ------------------------ ' ========== (A) 設置 rcp_name 到 A1、B1 ========== ' 假設 DGV1.CurrentRow.Cells("配料名称") 有你想填入的值 Dim rcpName As String = 處方清單_dgv.CurrentRow.Cells("配料名称").Value.ToString() ' 先確保第 1 行(索引0)已存在 Dim row0 As IRow = sheet.GetRow(0) If row0 Is Nothing Then row0 = sheet.CreateRow(0) End If ' A1 => GetCell(0) Dim cellA1 As ICell = row0.GetCell(0) If cellA1 Is Nothing Then cellA1 = row0.CreateCell(0) End If cellA1.SetCellValue(rcpName) ' B1 => GetCell(1) Dim cellB1 As ICell = row0.GetCell(1) If cellB1 Is Nothing Then cellB1 = row0.CreateCell(1) End If cellB1.SetCellValue(rcpName) ' ========== (B) 成份明細 D2:D14 (化工品) & E2:E14 (重量) ========== ' 從 DGV3 把化工品名稱、重量 分別寫到 D、E 欄 (索引3, 4) ' 從 Excel 的第 2 行(索引1)開始,直到第 14 行(索引13) Dim startExcelRow As Integer = 1 ' D2 所在的行索引 Dim endExcelRow As Integer = 15 ' D14 所在的行索引 Dim rowIndex As Integer = startExcelRow For Each dgvRow As DataGridViewRow In DGV3.Rows If rowIndex > endExcelRow Then Exit For Dim chemName As String = dgvRow.Cells("化工品名").Value.ToString() Dim weight As Double = Convert.ToDouble(dgvRow.Cells(3).Value) ' 確保 Excel 行存在 Dim excelRow As IRow = sheet.GetRow(rowIndex) If excelRow Is Nothing Then excelRow = sheet.CreateRow(rowIndex) End If ' D欄(索引3) 寫化工品名 Dim chemCell As ICell = excelRow.GetCell(2) If chemCell Is Nothing Then chemCell = excelRow.CreateCell(2) End If chemCell.SetCellValue(chemName) ' E欄(索引4) 寫重量 Dim weightCell As ICell = excelRow.GetCell(3) If weightCell Is Nothing Then weightCell = excelRow.CreateCell(3) End If weightCell.SetCellValue(weight) rowIndex += 1 Next ' ========== 設置字體樣式(可選) ========== Dim cellStyle As ICellStyle = workbook.CreateCellStyle() Dim font As IFont = workbook.CreateFont() font.FontHeightInPoints = 16 font.Boldweight = FontBoldWeight.Normal cellStyle.SetFont(font) cellStyle.Alignment = HorizontalAlignment.Right cellStyle.VerticalAlignment = VerticalAlignment.Center ' 如果想給前面寫入的 D/E 欄都設置樣式,可在上面循環裡賦值 ' 或者這裡再遍歷一次已寫入的行 ' ========== 移除最後一行(若你不想保留 '总计' 那一行) ========== ' 假設 DGV3.Rows.Count = n,那麼最後一行索引就是 n (對 NPOI 來說) ' 如果確定要刪除那一行,就這樣做: Dim lastRowIndex As Integer = DGV3.Rows.Count If sheet.GetRow(lastRowIndex) IsNot Nothing Then sheet.RemoveRow(sheet.GetRow(lastRowIndex)) End If ' ========== 重算總重量並取平均值 ========== totalWeight = DGV3.Rows.Cast(Of DataGridViewRow)(). Sum(Function(r) Convert.ToDouble(r.Cells(4).Value)) Dim avgWeight As Double = totalWeight / DGV3.Rows.Count ' ========== (C) B15: 領料單號, B16: 平均重量, E15: 調料日期 ========== ' Excel中 B15 => (Row=14, Col=1), B16 => (Row=15, Col=1), E15 => (Row=14, Col=4) ' 先確保 row14, row15 都存在 Dim row14 As IRow = sheet.GetRow(16) If row14 Is Nothing Then row14 = sheet.CreateRow(16) Dim row15 As IRow = sheet.GetRow(17) If row15 Is Nothing Then row15 = sheet.CreateRow(17) ' B15 => 領料單號 Dim cellB15 As ICell = row14.GetCell(1) If cellB15 Is Nothing Then cellB15 = row14.CreateCell(1) cellB15.SetCellValue(out_Number) ' B16 => 平均重量 Dim cellB16 As ICell = row15.GetCell(1) If cellB16 Is Nothing Then cellB16 = row15.CreateCell(1) cellB16.SetCellValue(Math.Round(avgWeight, 0)) ' E15 => 日期 Dim cellE15 As ICell = row14.GetCell(4) If cellE15 Is Nothing Then cellE15 = row14.CreateCell(4) cellE15.SetCellValue(DateTimePicker1.Value.ToString("yyyy-MM-dd")) ' ------------------------ 5️⃣ 保存 Excel ------------------------ Using fs As New FileStream(savePath, FileMode.Create, FileAccess.Write) workbook.Write(fs) End Using ' ------------------------ 6️⃣ 寫入數據庫 ------------------------ Dim connectionString As String = connstring Using conn As New SqlConnection(connectionString) conn.Open() Using trans As SqlTransaction = conn.BeginTransaction() Try Dim insertQuery As String = " INSERT INTO HT_finish_out (out_no, [date], chem_name, qty, cust, color, rcp_name) VALUES (@out_no, @date, @chem_name, @qty, @cust, @color,@rcp_name)" For Each dgvRow As DataGridViewRow In DGV3.Rows Dim chemName As String = dgvRow.Cells("化工品名").Value.ToString().Trim() ' 假設某行叫 "总计" 就跳過 If chemName = "总计" Then Continue For Dim cust As String = txtCustomer.Text.Trim() Dim color As String = txtColor.Text.Trim() Using cmd As New SqlCommand(insertQuery, conn, trans) cmd.Parameters.AddWithValue("@out_no", out_Number) cmd.Parameters.AddWithValue("@date", DateTimePicker1.Value) cmd.Parameters.AddWithValue("@chem_name", chemName) cmd.Parameters.AddWithValue("@qty", Convert.ToDouble(dgvRow.Cells(3).Value)) cmd.Parameters.AddWithValue("@cust", cust) cmd.Parameters.AddWithValue("@color", color) cmd.Parameters.AddWithValue("@rcp_name", 處方清單_dgv.Rows(處方清單_dgv.CurrentCell.RowIndex).Cells("配料名称").Value) cmd.ExecuteNonQuery() End Using Next trans.Commit() Catch ex As Exception trans.Rollback() MessageBox.Show("數據庫錯誤:" & ex.Message, "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error) Return End Try End Using End Using ' ------------------------ 7️⃣ 自動打開 Excel ------------------------ Process.Start("explorer.exe", savePath) ' ------------------------ 8️⃣ 提示成功 ------------------------ MessageBox.Show("領料單已成功導出!單號:" & out_Number, "成功", MessageBoxButtons.OK, MessageBoxIcon.Information) End Sub Private Function GenerateSerialNumber(dateStr As String) As String Dim connectionString As String = connstring ' 請替換為你的資料庫連接字串 Dim dateStr1 As String = DateTimePicker1.Value.ToString("yyMMdd") ' 取得 "250131" 格式 ' **SQL 查詢,獲取當天的最大流水號** Dim query As String = "SELECT MAX(CAST(SUBSTRING(out_no, 9, LEN(out_no) - 8) AS INT)) " & "FROM HT_finish_out WHERE out_no LIKE 'P" & dateStr1 & "-%';" Dim maxSerial As Integer = 0 Using conn As New SqlConnection(connectionString) conn.Open() Using cmd As New SqlCommand(query, conn) Dim result As Object = cmd.ExecuteScalar() If result IsNot DBNull.Value AndAlso result IsNot Nothing Then maxSerial = Convert.ToInt32(result) End If End Using End Using ' **流水號遞增** Dim newSerial As Integer = maxSerial + 1 ' **返回格式化的領料單號** Return "P" & dateStr1 & "-" & newSerial.ToString() End Function Private Sub ExportToExcel(orderNumber As String) Dim savePath As String = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), orderNumber & ".xlsx") ' **(1) 創建 Excel Workbook** Dim workbook As IWorkbook = New XSSFWorkbook() Dim sheet As ISheet = workbook.CreateSheet("領料單") ' **(2) 設定標題行** Dim headerRow As IRow = sheet.CreateRow(0) For col As Integer = 0 To DGV3.Columns.Count - 1 Dim cell As ICell = headerRow.CreateCell(col) cell.SetCellValue(DGV3.Columns(col).HeaderText) ' **設定標題格式** Dim headerStyle As ICellStyle = workbook.CreateCellStyle() Dim font As IFont = workbook.CreateFont() font.IsBold = True headerStyle.SetFont(font) headerStyle.Alignment = HorizontalAlignment.Center cell.CellStyle = headerStyle Next ' **(3) 填充數據** For row As Integer = 0 To DGV3.Rows.Count - 1 Dim dataRow As IRow = sheet.CreateRow(row + 1) For col As Integer = 0 To DGV3.Columns.Count - 1 Dim cell As ICell = dataRow.CreateCell(col) Dim value As Object = DGV3.Rows(row).Cells(col).Value If value IsNot Nothing Then If TypeOf value Is Decimal OrElse TypeOf value Is Double Then cell.SetCellValue(Convert.ToDouble(value)) Else cell.SetCellValue(value.ToString()) End If End If Next Next ' **(4) 自動調整欄位寬度** For col As Integer = 0 To DGV3.Columns.Count - 1 sheet.AutoSizeColumn(col) Next ' **(5) 寫入文件** Using fs As New FileStream(savePath, FileMode.Create, FileAccess.Write) workbook.Write(fs) End Using ' **(6) 自動開啟 Excel 文件** If File.Exists(savePath) Then Process.Start("explorer.exe", savePath) End If End Sub Private Sub Button1_Click_1(sender As Object, e As EventArgs) Handles btnSaveAs.Click ' 使用 InputBox 获取用户输入的配料名称 Dim rcpName As String = InputBox("请输入配料名称:", "输入配料名称", "") ' 检查用户是否输入了配料名称 If String.IsNullOrEmpty(rcpName) Then MessageBox.Show("请输入配料名称", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error) Return End If ' 检查 rcp_name 是否存在,如果存在,则在后面加上 "副本" rcpName = CheckAndModifyRcpName(rcpName) ' 获取选择的日期 Dim createdDate As DateTime = DateTimePicker1.Value ' 数据库连接字符串 Dim connectionString As String = connstring ' 获取当前最大ID Dim maxId As Integer = GetMaxId(connectionString) Dim newId As Integer = maxId + 1 ' 生成新的ID ' 使用连接保存数据 Using conn As New SqlConnection(connectionString) conn.Open() ' 遍历 dgv2 中的每一行,将数据插入到数据库 For Each row As DataGridViewRow In 處方_dgv.Rows If row.IsNewRow Then Continue For ' 跳过新行 ' 获取每一列的值 Dim chemName As String = row.Cells("化工品名").Value.ToString() Dim percents As Double = Convert.ToDouble(row.Cells("份数").Value) ' 插入数据的 SQL 查询 Dim query As String = "INSERT INTO HT_finish_rcp (rcp_name, chem_name, percents, created_date, id) " & "VALUES (@rcp_name, @chem_name, @percents, @created_date, @id)" Using cmd As New SqlCommand(query, conn) cmd.Parameters.AddWithValue("@rcp_name", rcpName) cmd.Parameters.AddWithValue("@chem_name", chemName) cmd.Parameters.AddWithValue("@percents", percents) cmd.Parameters.AddWithValue("@created_date", createdDate) cmd.Parameters.AddWithValue("@id", newId) ' 执行插入 cmd.ExecuteNonQuery() newId += 1 ' 每次插入后,id+1 End Using Next ' 显示保存成功的消息 MessageBox.Show("数据已成功保存!", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information) End Using End Sub Private Function CheckAndModifyRcpName(rcpName As String) As String Dim connectionString As String = connstring Dim query As String = "SELECT COUNT(*) FROM HT_finish_rcp WHERE rcp_name = @rcp_name" Using conn As New SqlConnection(connectionString) conn.Open() Using cmd As New SqlCommand(query, conn) cmd.Parameters.AddWithValue("@rcp_name", rcpName) Dim count As Integer = Convert.ToInt32(cmd.ExecuteScalar()) ' 如果 rcp_name 已经存在,则添加 "副本" If count > 0 Then rcpName = rcpName & "副本" End If End Using End Using Return rcpName End Function Private Function GetMaxId(connectionString As String) As Integer Dim query As String = "SELECT MAX(id) FROM HT_finish_rcp" Using conn As New SqlConnection(connectionString) conn.Open() Using cmd As New SqlCommand(query, conn) Dim result As Object = cmd.ExecuteScalar() If result IsNot DBNull.Value AndAlso result IsNot Nothing Then Return Convert.ToInt32(result) Else Return 0 ' 如果没有记录,返回0 End If End Using End Using End Function ' 删除指定配料名称的所有记录 Private Sub DeleteRcpNameRecords(rcpName As String) Dim connectionString As String = connstring Dim query As String = "DELETE FROM HT_finish_rcp WHERE rcp_name = @rcp_name" Using conn As New SqlConnection(connectionString) conn.Open() Using cmd As New SqlCommand(query, conn) cmd.Parameters.AddWithValue("@rcp_name", rcpName) ' 执行删除操作 cmd.ExecuteNonQuery() End Using End Using End Sub Private Sub RefreshDgv1() Dim connectionString As String = connstring Dim query As String = "SELECT rcp_name as 配料名称,created_date as 创建日期 FROM HT_finish_rcp group by rcp_name,created_date order by id" Using conn As New SqlConnection(connectionString) conn.Open() ' 使用 DataAdapter 将数据库数据填充到 DataTable Using da As New SqlDataAdapter(query, conn) Dim dt As New DataTable() da.Fill(dt) ' 将填充的数据绑定到 dgv1 處方清單_dgv.DataSource = dt End Using End Using End Sub End Class