From 18108a94f48b2cd6f9fce59aa5ed1d1ccc3f27b2 Mon Sep 17 00:00:00 2001
From: mrDarker <mr.darker@163.com>
Date: 星期三, 18 六月 2025 17:34:44 +0800
Subject: [PATCH] 1. 系统日志修复关闭连接 2. 删除之前模仿台达的数据库管理类 3. 重做配方主界面 4. 配方管理类添加更新PPID和描述的函数

---
 SourceCode/Bond/Servo/RecipeManager.cpp    |   44 +++++++
 SourceCode/Bond/Servo/resource.h           |    0 
 SourceCode/Bond/Servo/SystemLogManager.cpp |   11 +
 SourceCode/Bond/Servo/RecipeManager.h      |    6 +
 SourceCode/Bond/Servo/Servo.cpp            |   33 ++---
 SourceCode/Bond/Servo/Servo.rc             |    0 
 SourceCode/Bond/Servo/SystemLogManager.h   |    5 
 SourceCode/Bond/Servo/PageRecipe.h         |    8 
 SourceCode/Bond/Servo/PageRecipe.cpp       |  210 ++++++++++++++++++++++++++++------
 9 files changed, 250 insertions(+), 67 deletions(-)

diff --git a/SourceCode/Bond/Servo/PageRecipe.cpp b/SourceCode/Bond/Servo/PageRecipe.cpp
index 85f369a..468bc34 100644
--- a/SourceCode/Bond/Servo/PageRecipe.cpp
+++ b/SourceCode/Bond/Servo/PageRecipe.cpp
@@ -5,8 +5,6 @@
 #include "Servo.h"
 #include "afxdialogex.h"
 #include "PageRecipe.h"
-#include "SECSRuntimeManager.h"
-
 
 // CPageRecipe 瀵硅瘽妗�
 
@@ -22,7 +20,7 @@
 {
 }
 
-void CPageRecipe::FillDataToListCtrl(const std::vector<std::string>& vecData) {
+void CPageRecipe::FillDataToListCtrl(const std::vector<RecipeInfo>& vecRecipe) {
 	CListCtrl* pListCtrl = (CListCtrl*)GetDlgItem(IDC_LIST_PPID);
 	if (pListCtrl == nullptr || pListCtrl->m_hWnd == nullptr) {
 		return;
@@ -32,26 +30,23 @@
 	pListCtrl->DeleteAllItems();
 
 	// 閬嶅巻鏁版嵁骞舵彃鍏ュ埌CListCtrl涓�
-	for (int i = 0; i < static_cast<int>(vecData.size()); ++i) {
-		// 鎻掑叆琛�
-		pListCtrl->InsertItem(i, _T(""));
+	for (int i = 0; i < static_cast<int>(vecRecipe.size()); ++i) {
+		const RecipeInfo& recipe = vecRecipe[i];
 
-		// 璁剧疆 Recipe No锛堢1鍒楋級
-		CString strRecipeNo;
-		strRecipeNo.Format(_T("%d"), i);
-		pListCtrl->SetItemText(i, 1, strRecipeNo);
+		m_listPPID.InsertItem(i, _T("")); // 绗�0鍒楃┖鐧�
 
-		// 璁剧疆 PPID锛堢2鍒楋級
-		CString strPPID = CA2T(vecData[i].c_str());
-		if (strPPID.CompareNoCase(_T("NULL")) == 0) {
-			strPPID.Empty();
-		}
-		pListCtrl->SetItemText(i, 2, strPPID);
+		CString strNo;
+		strNo.Format(_T("%d"), i + 1);
+		m_listPPID.SetItemText(i, 1, strNo);
+
+		m_listPPID.SetItemText(i, 2, CA2T(recipe.strPPID.c_str()));
+		m_listPPID.SetItemText(i, 3, CA2T(recipe.strDescription.c_str()));
+		m_listPPID.SetItemText(i, 4, CA2T(recipe.strCreateTime.c_str()));
 	}
 
 	// 鑾峰彇鍒楁暟
-	int nColCount = pListCtrl->GetHeaderCtrl()->GetItemCount();
-	pListCtrl->SetColumnWidth(nColCount - 1, LVSCW_AUTOSIZE_USEHEADER);
+	int nColCount = m_listPPID.GetHeaderCtrl()->GetItemCount();
+	m_listPPID.SetColumnWidth(nColCount - 1, LVSCW_AUTOSIZE_USEHEADER);
 }
 
 void CPageRecipe::DoDataExchange(CDataExchange* pDX)
@@ -59,15 +54,16 @@
 	CDialogEx::DoDataExchange(pDX);
 	DDX_Control(pDX, IDC_LIST_PPID, m_listPPID);
 	DDX_Control(pDX, IDC_EDIT_PPID, m_editPPID);
+	DDX_Control(pDX, IDC_EDIT_DESC, m_editDesc);
 }
 
 
 BEGIN_MESSAGE_MAP(CPageRecipe, CDialogEx)
+	ON_WM_SIZE()
 	ON_BN_CLICKED(IDC_BUTTON_SEARCH, &CPageRecipe::OnBnClickedButtonSearch)
 	ON_BN_CLICKED(IDC_BUTTON_MODIFY, &CPageRecipe::OnBnClickedButtonModify)
 	ON_BN_CLICKED(IDC_BUTTON_DELETE, &CPageRecipe::OnBnClickedButtonDelete)
 	ON_BN_CLICKED(IDC_BUTTON_DELETE_ALL, &CPageRecipe::OnBnClickedButtonDeleteAll)
-	ON_BN_CLICKED(IDC_BUTTON_SAVE, &CPageRecipe::OnBnClickedButtonSave)
 	ON_BN_CLICKED(IDC_BUTTON_REFRESH, &CPageRecipe::OnBnClickedButtonRefresh)
 	ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_PPID, &CPageRecipe::OnLvnItemChangedListPPID)
 END_MESSAGE_MAP()
@@ -88,17 +84,82 @@
 
 	HIMAGELIST imageList = ImageList_Create(24, 24, ILC_COLOR24, 1, 1);
 	ListView_SetImageList(pListCtrl->GetSafeHwnd(), imageList, LVSIL_SMALL);
-	pListCtrl->InsertColumn(0, _T(""), LVCFMT_RIGHT, 0);
-	pListCtrl->InsertColumn(1, _T("Recipe No"), LVCFMT_LEFT, 100);
-	pListCtrl->InsertColumn(2, _T("PPID"), LVCFMT_LEFT, 100);
-	pListCtrl->SetColumnWidth(2, LVSCW_AUTOSIZE_USEHEADER);
+	pListCtrl->InsertColumn(0, _T(""), LVCFMT_RIGHT, 0); // 闅愯棌鍒�
+	pListCtrl->InsertColumn(1, _T("No."), LVCFMT_LEFT, 80);
+	pListCtrl->InsertColumn(2, _T("PPID"), LVCFMT_LEFT, 120);
+	pListCtrl->InsertColumn(3, _T("鎻忚堪"), LVCFMT_LEFT, 180);
+	pListCtrl->InsertColumn(4, _T("鍒涘缓鏃堕棿"), LVCFMT_LEFT, 160);
+	pListCtrl->SetColumnWidth(4, LVSCW_AUTOSIZE_USEHEADER);
 
 	// 鑾峰彇鎵�鏈夋暟鎹�
-	auto vecData = SECSRuntimeManager::getInstance().getAllPPID();
+	auto vecData = RecipeManager::getInstance().getAllRecipes();
 	FillDataToListCtrl(vecData);
 
 	return TRUE;  // return TRUE unless you set the focus to a control
 	// 寮傚父: OCX 灞炴�ч〉搴旇繑鍥� FALSE
+}
+
+void CPageRecipe::OnSize(UINT nType, int cx, int cy)
+{
+	CDialogEx::OnSize(nType, cx, cy);
+
+	if (m_listPPID.GetSafeHwnd()) {
+		// 宸︿晶鍒楄〃瀹介珮鑷�傚簲
+		int margin = 10;
+		int buttonWidth = 80;
+		int buttonHeight = 30;
+		int buttonSpacing = 10;
+
+		CRect rect;
+		GetClientRect(&rect);
+
+		int listWidth = rect.Width() - buttonWidth - 3 * margin;
+		int listHeight = rect.Height() - 2 * margin;
+
+		m_listPPID.MoveWindow(margin, margin + 80, listWidth, listHeight - 80);
+
+		// 缂栬緫妗嗚皟鏁翠綅缃細鍙宠竟瀵归綈鍒楄〃锛屽乏杈瑰浐瀹氳捣濮�
+		int labelWidth = 60;
+		int rightEdge = rect.right - buttonWidth - 2 * margin;
+
+		if (m_editPPID.GetSafeHwnd()) {
+			m_editPPID.MoveWindow(labelWidth, margin, rightEdge - labelWidth, 25);
+		}
+		if (m_editDesc.GetSafeHwnd()) {
+			m_editDesc.MoveWindow(labelWidth, margin + 35, rightEdge - labelWidth, 25);
+		}
+
+		// 鎸夐挳绔栫洿鎺掑垪鍦ㄥ彸渚�
+		CWnd* buttons[] = {
+			GetDlgItem(IDC_BUTTON_SEARCH),
+			GetDlgItem(IDC_BUTTON_MODIFY),
+			GetDlgItem(IDC_BUTTON_DELETE),
+			GetDlgItem(IDC_BUTTON_DELETE_ALL),
+			GetDlgItem(IDC_BUTTON_REFRESH)
+		};
+
+		int y = margin;
+		for (auto pBtn : buttons) {
+			if (pBtn && pBtn->GetSafeHwnd()) {
+				pBtn->MoveWindow(rect.right - buttonWidth - margin, y, buttonWidth, buttonHeight);
+				y += buttonHeight + buttonSpacing;
+			}
+		}
+
+		// 鍒楀閲嶈
+		int col0 = 50;  // No.
+		int col1 = 120; // PPID
+		int col3 = 160; // 鍒涘缓鏃堕棿鑷姩濉厖
+		int col2 = listWidth - col0 - col1 - col3 - 2;  // 鎻忚堪鑷姩濉厖
+		if (col2 < 80) { 
+			col2 = 80;
+		}
+
+		m_listPPID.SetColumnWidth(1, col0);
+		m_listPPID.SetColumnWidth(2, col1);
+		m_listPPID.SetColumnWidth(3, col2);
+		m_listPPID.SetColumnWidth(4, col3);
+	}
 }
 
 void CPageRecipe::OnBnClickedButtonSearch()
@@ -122,50 +183,114 @@
 {
 	// TODO: 鍦ㄦ娣诲姞鎺т欢閫氱煡澶勭悊绋嬪簭浠g爜
 	POSITION pos = m_listPPID.GetFirstSelectedItemPosition();
-	if (!pos) return;
+	if (!pos) {
+		AfxMessageBox(_T("璇烽�夋嫨瑕佷慨鏀圭殑閰嶆柟"));
+		return;
+	}
 
 	int nSel = m_listPPID.GetNextSelectedItem(pos);
+	CString strOldPPID = m_listPPID.GetItemText(nSel, 2);
+	CString strOldDesc = m_listPPID.GetItemText(nSel, 3);
 
-	CString strNewPPID;
+	CString strNewPPID, strNewDesc;
 	m_editPPID.GetWindowText(strNewPPID);
-	m_listPPID.SetItemText(nSel, 2, strNewPPID);
+	m_editDesc.GetWindowText(strNewDesc);
+
+	// 鍒ょ┖
+	if (strOldPPID.IsEmpty() || strNewPPID.IsEmpty()) {
+		AfxMessageBox(_T("PPID 涓嶈兘涓虹┖"));
+		return;
+	}
+
+	std::string oldPPID = CT2A(strOldPPID);
+	std::string newPPID = CT2A(strNewPPID);
+	std::string newDesc = CT2A(strNewDesc);
+
+	bool bPPIDChanged = (strOldPPID.Compare(strNewPPID) != 0);
+	bool bDescChanged = (strOldDesc.Compare(strNewDesc) != 0);
+
+	if (!bPPIDChanged && !bDescChanged) {
+		return;
+	}
+
+	if (bPPIDChanged) {
+		// 鏂� PPID 涓嶅彲閲嶅
+		if (RecipeManager::getInstance().ppidExists(newPPID)) {
+			AfxMessageBox(_T("鏂� PPID 宸插瓨鍦紝璇蜂娇鐢ㄥ叾浠栧��"));
+			return;
+		}
+
+		// 璋冪敤 updatePPID锛屽悓鏃舵洿鏂版弿杩�
+		if (RecipeManager::getInstance().updatePPID(oldPPID, newPPID)) {
+			m_listPPID.SetItemText(nSel, 2, strNewPPID);
+		}
+		else {
+			AfxMessageBox(_T("鏇存柊澶辫触锛岃妫�鏌ユ棩蹇�"));
+		}
+	}
+
+	if (bDescChanged) {
+		// 鏇存柊鎻忚堪
+		if (RecipeManager::getInstance().updateDescription(oldPPID, newDesc)) {
+			m_listPPID.SetItemText(nSel, 3, strNewDesc);
+		}
+		else {
+			AfxMessageBox(_T("鎻忚堪鏇存柊澶辫触"));
+		}
+	}
 }
 
 void CPageRecipe::OnBnClickedButtonDelete()
 {
 	// TODO: 鍦ㄦ娣诲姞鎺т欢閫氱煡澶勭悊绋嬪簭浠g爜
 	POSITION pos = m_listPPID.GetFirstSelectedItemPosition();
-	if (!pos) return;
+	if (!pos) { 
+		return;
+	}
 
 	int nSel = m_listPPID.GetNextSelectedItem(pos);
-	m_listPPID.SetItemText(nSel, 2, _T(""));
+	CString strPPID = m_listPPID.GetItemText(nSel, 2);
+	std::string ppid = CT2A(strPPID);
+
+	if (!ppid.empty()) {
+		CString msg;
+		msg.Format(_T("纭畾瑕佸垹闄ら厤鏂� [%s] 鍚楋紵"), strPPID);
+		if (IDYES == AfxMessageBox(msg, MB_YESNO | MB_ICONQUESTION)) {
+			if (RecipeManager::getInstance().deleteRecipeByPPID(ppid)) {
+				m_listPPID.DeleteItem(nSel);
+			}
+			else {
+				AfxMessageBox(_T("鍒犻櫎澶辫触"));
+			}
+		}
+	}
 }
 
 void CPageRecipe::OnBnClickedButtonDeleteAll()
 {
 	// TODO: 鍦ㄦ娣诲姞鎺т欢閫氱煡澶勭悊绋嬪簭浠g爜
-	int nCount = m_listPPID.GetItemCount();
-	for (int i = 0; i < nCount; ++i) {
-		m_listPPID.SetItemText(i, 2, _T(""));
+	if (IDYES != AfxMessageBox(_T("纭畾瑕佸垹闄ゅ叏閮ㄩ厤鏂硅褰曞悧锛�"), MB_YESNO | MB_ICONWARNING)) {
+		return;
 	}
-}
 
-void CPageRecipe::OnBnClickedButtonSave()
-{
-	// TODO: 鍦ㄦ娣诲姞鎺т欢閫氱煡澶勭悊绋嬪簭浠g爜
-	std::vector<std::string> vecPPID;
+	// 鑾峰彇鎵�鏈� PPID
 	int nCount = m_listPPID.GetItemCount();
 	for (int i = 0; i < nCount; ++i) {
-		CString str = m_listPPID.GetItemText(i, 2);
-		vecPPID.emplace_back(CT2A(str));
+		CString strPPID = m_listPPID.GetItemText(i, 2);
+		std::string ppid = CT2A(strPPID);
+		if (!ppid.empty()) {
+			RecipeManager::getInstance().deleteRecipeByPPID(ppid);
+		}
 	}
-	SECSRuntimeManager::getInstance().setAllPPID(vecPPID);
+
+	// 娓呯┖鍒楄〃鏄剧ず
+	m_listPPID.DeleteAllItems();
 }
 
 void CPageRecipe::OnBnClickedButtonRefresh()
 {
 	// TODO: 鍦ㄦ娣诲姞鎺т欢閫氱煡澶勭悊绋嬪簭浠g爜
-	auto vecData = SECSRuntimeManager::getInstance().getAllPPID();
+	auto vecData = RecipeManager::getInstance().getAllRecipes();
 	FillDataToListCtrl(vecData);
 }
 
@@ -180,5 +305,8 @@
 		int nItem = pNMLV->iItem;
 		CString strPPID = m_listPPID.GetItemText(nItem, 2);
 		m_editPPID.SetWindowText(strPPID);
+
+		CString strDesc = m_listPPID.GetItemText(nItem, 3);
+		m_editDesc.SetWindowText(strDesc);
 	}
 }
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/PageRecipe.h b/SourceCode/Bond/Servo/PageRecipe.h
index 69f4cab..5df946e 100644
--- a/SourceCode/Bond/Servo/PageRecipe.h
+++ b/SourceCode/Bond/Servo/PageRecipe.h
@@ -1,7 +1,6 @@
 锘�#pragma once
 #include "afxdialogex.h"
-//#include "ListCtrlEx.h"
-
+#include "RecipeManager.h"
 
 // CPageRecipe 瀵硅瘽妗�
 
@@ -14,7 +13,7 @@
 	virtual ~CPageRecipe();
 
 private:
-	void FillDataToListCtrl(const std::vector<std::string>& vecData);
+	void FillDataToListCtrl(const std::vector<RecipeInfo>& vecRecipe);
 
 // 瀵硅瘽妗嗘暟鎹�
 #ifdef AFX_DESIGN_TIME
@@ -24,11 +23,11 @@
 protected:
 	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 鏀寔
 	virtual BOOL OnInitDialog();
+	afx_msg void OnSize(UINT nType, int cx, int cy);
 	afx_msg void OnBnClickedButtonSearch();
 	afx_msg void OnBnClickedButtonModify();
 	afx_msg void OnBnClickedButtonDelete();
 	afx_msg void OnBnClickedButtonDeleteAll();
-	afx_msg void OnBnClickedButtonSave();
 	afx_msg void OnBnClickedButtonRefresh();
 	afx_msg void OnLvnItemChangedListPPID(NMHDR* pNMHDR, LRESULT* pResult);
 	DECLARE_MESSAGE_MAP()
@@ -36,4 +35,5 @@
 private:
 	CListCtrl m_listPPID;
 	CEdit m_editPPID;
+	CEdit m_editDesc;
 };
diff --git a/SourceCode/Bond/Servo/RecipeManager.cpp b/SourceCode/Bond/Servo/RecipeManager.cpp
index 247cd40..6e58418 100644
--- a/SourceCode/Bond/Servo/RecipeManager.cpp
+++ b/SourceCode/Bond/Servo/RecipeManager.cpp
@@ -56,7 +56,7 @@
             device_id INTEGER NOT NULL,
             device_name TEXT NOT NULL,
             recipe_id INTEGER NOT NULL,
-            FOREIGN KEY(ppid) REFERENCES recipes(ppid) ON DELETE CASCADE,
+            FOREIGN KEY(ppid) REFERENCES recipes(ppid) ON DELETE CASCADE ON UPDATE CASCADE,
             UNIQUE (ppid, device_id),
             UNIQUE (ppid, device_name)
         );
@@ -331,6 +331,48 @@
     return addRecipe(recipe);
 }
 
+bool RecipeManager::updatePPID(const std::string& oldPPID, const std::string& newPPID) {
+    if (!m_pDB || oldPPID.empty() || newPPID.empty()) {
+        std::cerr << "[updatePPID] Invalid input." << std::endl;
+        return false;
+    }
+
+    std::lock_guard<std::recursive_mutex> lock(m_mutex);
+
+    // 检查是否已经存在相同的 newPPID
+    auto check = m_pDB->fetchResults("SELECT COUNT(*) FROM recipes WHERE ppid = '" + newPPID + "';");
+    if (!check.empty() && !check[0].empty() && check[0][0] != "0") {
+        std::cerr << "[updatePPID] New PPID already exists: " << newPPID << std::endl;
+        return false;
+    }
+
+    m_pDB->executeQuery("BEGIN TRANSACTION;");
+
+    std::ostringstream sql;
+    sql << "UPDATE recipes SET ppid = '" << newPPID << "' WHERE ppid = '" << oldPPID << "';";
+    if (!m_pDB->executeQuery(sql.str())) {
+        std::cerr << "[updatePPID] Failed to update recipes table." << std::endl;
+        m_pDB->executeQuery("ROLLBACK;");
+        return false;
+    }
+
+    m_pDB->executeQuery("COMMIT;");
+    return true;
+}
+
+bool RecipeManager::updateDescription(const std::string& ppid, const std::string& newDescription) {
+    if (!m_pDB || ppid.empty()) {
+        std::cerr << "[updateRecipeDescription] Invalid input." << std::endl;
+        return false;
+    }
+
+    std::ostringstream oss;
+    oss << "UPDATE recipes SET description = '" << newDescription << "' WHERE ppid = '" << ppid << "';";
+
+    std::lock_guard<std::recursive_mutex> lock(m_mutex);
+    return m_pDB->executeQuery(oss.str());
+}
+
 bool RecipeManager::updateDeviceRecipeIDByID(const std::string& ppid, int nDeviceID, int nNewRecipeID) {
 	if (!m_pDB || ppid.empty() || nDeviceID <= 0 || nNewRecipeID <= 0) {
 		return false;
diff --git a/SourceCode/Bond/Servo/RecipeManager.h b/SourceCode/Bond/Servo/RecipeManager.h
index b5aceaa..a51e14d 100644
--- a/SourceCode/Bond/Servo/RecipeManager.h
+++ b/SourceCode/Bond/Servo/RecipeManager.h
@@ -73,6 +73,12 @@
     // 更新指定 PPID 的配方
     bool updateRecipe(const RecipeInfo& recipe);
 
+	// 更新 PPID(通过旧 PPID 和新 PPID)
+    bool updatePPID(const std::string& oldPPID, const std::string& newPPID);
+
+	// 更新配方描述(通过 PPID)
+    bool updateDescription(const std::string& ppid, const std::string& newDescription);
+
 	// 更新设备配方ID(通过 PPID 和设备ID)
     bool updateDeviceRecipeIDByID(const std::string& ppid, int nDeviceID, int nNewRecipeID);
 
diff --git a/SourceCode/Bond/Servo/Servo.cpp b/SourceCode/Bond/Servo/Servo.cpp
index 71f2ed2..be05f20 100644
--- a/SourceCode/Bond/Servo/Servo.cpp
+++ b/SourceCode/Bond/Servo/Servo.cpp
@@ -7,7 +7,6 @@
 #include "ServoDlg.h"
 #include "ServoGraph.h"
 #include "AlarmManager.h"
-#include "SECSRuntimeManager.h"
 #include "TransferManager.h"
 #include "SystemLogManager.h"
 #include "UserManager.h"
@@ -136,20 +135,6 @@
 		return FALSE;
 	}
 
-	// 初始化SECS运行设置管理库
-	try {
-		if (!SECSRuntimeManager::getInstance().initRuntimeSetting()) {
-			AfxMessageBox("初始化SECS运行设置失败!");
-			return FALSE;
-		}
-	}
-	catch (const std::exception& ex) {
-		CString errorMsg;
-		errorMsg.Format(_T("初始化SECS运行设置失败:%s"), CString(ex.what()));
-		AfxMessageBox(errorMsg, MB_ICONERROR);
-		return FALSE;
-	}
-
 	// 初始化搬运记录管理库
 	try {
 		if (!TransferManager::getInstance().initTransferTable()) {
@@ -166,7 +151,7 @@
 
 	// 初始化运行日志管理库
 	try {
-		if (!SystemLogManager::getInstance().initializeLogTable()) {
+		if (!SystemLogManager::getInstance().initSystemLogTable()) {
 			AfxMessageBox("初始化运行日志管理库失败!");
 			return FALSE;
 		}
@@ -251,12 +236,22 @@
 	// 销毁报警表
 	AlarmManager::getInstance().termAlarmTable();
 
-	// 销毁SECS运行设置管理库
-	SECSRuntimeManager::getInstance().termRuntimeSetting();
-
 	// 销毁搬运记录管理库
 	TransferManager::getInstance().termTransferTable();
 
+	// 销毁运行日志
+	SystemLogManager::getInstance().termSystemLogTable();
+
+	// 销毁用户表
+#if !defined(_DEBUG)
+// 清除 UserManager 的无操作检测
+	UserManager::getInstance().terminateIdleDetection();
+	KillTimer(1);
+#endif
+
+	// 销毁配方表
+	RecipeManager::getInstance().termRecipeTable();
+
 	return CWinApp::ExitInstance();
 }
 
diff --git a/SourceCode/Bond/Servo/Servo.rc b/SourceCode/Bond/Servo/Servo.rc
index 22445c9..fb18f5b 100644
--- a/SourceCode/Bond/Servo/Servo.rc
+++ b/SourceCode/Bond/Servo/Servo.rc
Binary files differ
diff --git a/SourceCode/Bond/Servo/SystemLogManager.cpp b/SourceCode/Bond/Servo/SystemLogManager.cpp
index 7289fb6..a62e07e 100644
--- a/SourceCode/Bond/Servo/SystemLogManager.cpp
+++ b/SourceCode/Bond/Servo/SystemLogManager.cpp
@@ -29,7 +29,7 @@
 }
 
 // 初始化日志表
-bool SystemLogManager::initializeLogTable() {
+bool SystemLogManager::initSystemLogTable() {
     // 获取可执行文件路径
     char szPath[MAX_PATH];
     GetModuleFileName(NULL, szPath, MAX_PATH);
@@ -63,6 +63,15 @@
     return m_pDB->executeQuery(createTableQuery);
 }
 
+// 终止数据库连接
+void SystemLogManager::termSystemLogTable() {
+    if (!m_pDB) {
+        return;
+    }
+
+    m_pDB->disconnect();
+}
+
 // 添加日志(使用当前用户)
 bool SystemLogManager::log(LogType logType, const std::string& event) {
     if (!m_pDB) {
diff --git a/SourceCode/Bond/Servo/SystemLogManager.h b/SourceCode/Bond/Servo/SystemLogManager.h
index 5ae9ab0..3665e9f 100644
--- a/SourceCode/Bond/Servo/SystemLogManager.h
+++ b/SourceCode/Bond/Servo/SystemLogManager.h
@@ -21,7 +21,10 @@
     static SystemLogManager& getInstance();
 
     // 初始化日志表
-    bool initializeLogTable();
+    bool initSystemLogTable();
+
+    // 终止数据库连接
+    void termSystemLogTable();
 
     // 添加日志
     bool log(LogType logType, const std::string& event);
diff --git a/SourceCode/Bond/Servo/resource.h b/SourceCode/Bond/Servo/resource.h
index 2108414..dbea761 100644
--- a/SourceCode/Bond/Servo/resource.h
+++ b/SourceCode/Bond/Servo/resource.h
Binary files differ

--
Gitblit v1.9.3