From 3cb4638bcb93a8fdf4cfea140025bbc299d35d47 Mon Sep 17 00:00:00 2001
From: chenluhua1980 <Chenluhua@qq.com>
Date: 星期二, 18 十一月 2025 17:02:07 +0800
Subject: [PATCH] 1.权限完善。操作日志等

---
 SourceCode/Bond/Servo/Servo.vcxproj         |    4 
 SourceCode/Bond/Servo/Servo.vcxproj.filters |    4 
 SourceCode/Bond/Servo/resource.h            |    0 
 SourceCode/Bond/Servo/CUserXLogDlg.h        |   42 +++++++
 SourceCode/Bond/Servo/CUserManager2.cpp     |    8 +
 SourceCode/Bond/Servo/Servo.rc              |    0 
 SourceCode/Bond/Servo/ServoDlg.cpp          |   32 +++--
 SourceCode/Bond/Servo/CUserXLogDlg.cpp      |  178 +++++++++++++++++++++++++++++
 SourceCode/Bond/Servo/PageRecipe.cpp        |   34 ++++-
 9 files changed, 279 insertions(+), 23 deletions(-)

diff --git a/SourceCode/Bond/Servo/CUserManager2.cpp b/SourceCode/Bond/Servo/CUserManager2.cpp
index 25912eb..4f45e52 100644
--- a/SourceCode/Bond/Servo/CUserManager2.cpp
+++ b/SourceCode/Bond/Servo/CUserManager2.cpp
@@ -1,4 +1,4 @@
-#include "stdafx.h"
+锘�#include "stdafx.h"
 #include "CUserManager2.h"
 #include "ToolUnits.h"
 #include <vector>
@@ -40,7 +40,7 @@
 	return L"";
 }
 
-// 获取单例实例
+// 鑾峰彇鍗曚緥瀹炰緥
 CUserManager2& CUserManager2::getInstance() {
 	static CUserManager2 instance;
 	return instance;
@@ -69,6 +69,10 @@
 		const wchar_t* roles = L"Admin:100\nEngineer:50\nOperator:10\n";
 		(void)UX_SetRoleDefinitions(roles);
 		(void)UX_AddUser(L"admin", L"Administrator", L"admin123", L"Admin");
+
+		UX_DefineAction(L"start", L"鍚姩鏈哄彴", L"Operator"); 
+		UX_DefineAction(L"stop", L"鍋滄満", L"Operator");
+		UX_DefineAction(L"recipe", L"缂栬緫閰嶆柟", L"Engineer");
 	}
 }
 
diff --git a/SourceCode/Bond/Servo/CUserXLogDlg.cpp b/SourceCode/Bond/Servo/CUserXLogDlg.cpp
new file mode 100644
index 0000000..58e8950
--- /dev/null
+++ b/SourceCode/Bond/Servo/CUserXLogDlg.cpp
@@ -0,0 +1,178 @@
+锘�#include "stdafx.h"
+#include "Servo.h"
+#include "CUserXLogDlg.h"
+#include "afxdialogex.h"
+#include <functional>
+#include <vector>
+#include <sstream>
+
+namespace
+{
+	std::wstring ReadBufferVia(const std::function<int(wchar_t*, int)>& fn)
+	{
+		int need = fn(nullptr, 0);
+		if (need <= 0) {
+			return L"";
+		}
+
+		std::wstring buffer;
+		buffer.resize(static_cast<size_t>(need));
+		if (fn(buffer.data(), need) == UX_OK) {
+			if (!buffer.empty() && buffer.back() == L'\0') {
+				buffer.pop_back();
+			}
+			return buffer;
+		}
+
+		return L"";
+	}
+
+	std::vector<std::wstring> SplitLines(const std::wstring& text)
+	{
+		std::vector<std::wstring> lines;
+		std::wstringstream ss(text);
+		std::wstring line;
+		while (std::getline(ss, line)) {
+			lines.push_back(line);
+		}
+		return lines;
+	}
+}
+
+IMPLEMENT_DYNAMIC(CUserXLogDlg, CDialogEx)
+
+CUserXLogDlg::CUserXLogDlg(CWnd* pParent)
+	: CDialogEx(IDD_DIALOG_USERX_LOG, pParent)
+{
+}
+
+CUserXLogDlg::~CUserXLogDlg()
+{
+}
+
+void CUserXLogDlg::DoDataExchange(CDataExchange* pDX)
+{
+	CDialogEx::DoDataExchange(pDX);
+	DDX_Control(pDX, IDC_LIST1, m_listLogs);
+}
+
+BEGIN_MESSAGE_MAP(CUserXLogDlg, CDialogEx)
+	ON_WM_SIZE()
+	ON_WM_DESTROY()
+END_MESSAGE_MAP()
+
+BOOL CUserXLogDlg::OnInitDialog()
+{
+	CDialogEx::OnInitDialog();
+
+	InitListCtrl();
+	RefreshLogs();
+	AdjustLayout();
+
+	return TRUE;
+}
+
+void CUserXLogDlg::InitListCtrl()
+{
+	DWORD dwStyle = m_listLogs.GetExtendedStyle();
+	m_listLogs.SetExtendedStyle(dwStyle | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
+	m_listLogs.InsertColumn(0, _T("鏃堕棿"), LVCFMT_LEFT, 180);
+	m_listLogs.InsertColumn(1, _T("鐢ㄦ埛"), LVCFMT_LEFT, 120);
+	m_listLogs.InsertColumn(2, _T("鍔ㄤ綔"), LVCFMT_LEFT, 120);
+	m_listLogs.InsertColumn(3, _T("鎻忚堪"), LVCFMT_LEFT, 200);
+}
+
+void CUserXLogDlg::RefreshLogs()
+{
+	m_logs.clear();
+	m_listLogs.DeleteAllItems();
+
+	auto allLogs = ReadBufferVia([](wchar_t* buffer, int size) {
+		return UX_QueryLogs(200, buffer, size);
+	});
+
+	for (auto& rawLine : SplitLines(allLogs)) {
+		if (rawLine.empty()) continue;
+
+		auto trim = [](std::wstring value) {
+			size_t first = value.find_first_not_of(L" \t\r\n");
+			size_t last = value.find_last_not_of(L" \t\r\n");
+			if (first == std::wstring::npos || last == std::wstring::npos) {
+				return std::wstring();
+			}
+			return value.substr(first, last - first + 1);
+		};
+
+		auto takeField = [&](size_t& cursor) {
+			if (cursor == std::wstring::npos || cursor >= rawLine.length()) {
+				return std::wstring();
+			}
+			size_t pos = rawLine.find(L',', cursor);
+			std::wstring part = (pos == std::wstring::npos) ? rawLine.substr(cursor) : rawLine.substr(cursor, pos - cursor);
+			cursor = (pos == std::wstring::npos) ? std::wstring::npos : pos + 1;
+			return trim(part);
+		};
+
+		size_t cursor = 0;
+		LogItem item;
+		item.time = takeField(cursor).c_str();
+		item.user = takeField(cursor).c_str();
+		item.action = takeField(cursor).c_str();
+		if (cursor != std::wstring::npos && cursor < rawLine.length()) {
+			item.detail = trim(rawLine.substr(cursor)).c_str();
+		}
+
+		m_logs.push_back(item);
+	}
+
+	for (size_t i = 0; i < m_logs.size(); ++i) {
+		const auto& log = m_logs[i];
+		int row = m_listLogs.InsertItem(static_cast<int>(i), log.time);
+		m_listLogs.SetItemText(row, 1, log.user);
+		m_listLogs.SetItemText(row, 2, log.action);
+		m_listLogs.SetItemText(row, 3, log.detail);
+	}
+}
+
+void CUserXLogDlg::AdjustLayout()
+{
+	if (!::IsWindow(m_listLogs.GetSafeHwnd())) {
+		return;
+	}
+
+	CRect rcClient;
+	GetClientRect(&rcClient);
+	const int margin = 7;
+
+	CRect rcList(margin, margin, rcClient.right - margin, rcClient.bottom - 40);
+	m_listLogs.MoveWindow(rcList);
+
+	auto moveButton = [&](int id, int order) {
+		if (CWnd* pBtn = GetDlgItem(id)) {
+			CRect rc;
+			pBtn->GetWindowRect(&rc);
+			ScreenToClient(&rc);
+			int width = rc.Width();
+			int height = rc.Height();
+			rc.left = rcClient.right - margin - width - order * (width + margin);
+			rc.right = rc.left + width;
+			rc.top = rcClient.bottom - margin - height;
+			rc.bottom = rc.top + height;
+			pBtn->MoveWindow(rc);
+		}
+	};
+
+	moveButton(IDOK, 1);
+	moveButton(IDCANCEL, 0);
+}
+
+void CUserXLogDlg::OnSize(UINT nType, int cx, int cy)
+{
+	CDialogEx::OnSize(nType, cx, cy);
+	AdjustLayout();
+}
+
+void CUserXLogDlg::OnDestroy()
+{
+	CDialogEx::OnDestroy();
+}
diff --git a/SourceCode/Bond/Servo/CUserXLogDlg.h b/SourceCode/Bond/Servo/CUserXLogDlg.h
new file mode 100644
index 0000000..e28a810
--- /dev/null
+++ b/SourceCode/Bond/Servo/CUserXLogDlg.h
@@ -0,0 +1,42 @@
+锘�#pragma once
+
+#include <vector>
+#include <string>
+
+class CUserXLogDlg : public CDialogEx
+{
+	DECLARE_DYNAMIC(CUserXLogDlg)
+
+public:
+	CUserXLogDlg(CWnd* pParent = nullptr);
+	virtual ~CUserXLogDlg();
+
+#ifdef AFX_DESIGN_TIME
+	enum { IDD = IDD_DIALOG_USERX_LOG };
+#endif
+
+protected:
+	virtual void DoDataExchange(CDataExchange* pDX);
+
+	DECLARE_MESSAGE_MAP()
+public:
+	virtual BOOL OnInitDialog();
+	afx_msg void OnSize(UINT nType, int cx, int cy);
+	afx_msg void OnDestroy();
+
+private:
+	struct LogItem
+	{
+		CString time;
+		CString user;
+		CString action;
+		CString detail;
+	};
+
+	CListCtrl m_listLogs;
+	std::vector<LogItem> m_logs;
+
+	void InitListCtrl();
+	void RefreshLogs();
+	void AdjustLayout();
+};
diff --git a/SourceCode/Bond/Servo/PageRecipe.cpp b/SourceCode/Bond/Servo/PageRecipe.cpp
index cf387ce..3965041 100644
--- a/SourceCode/Bond/Servo/PageRecipe.cpp
+++ b/SourceCode/Bond/Servo/PageRecipe.cpp
@@ -386,13 +386,12 @@
 
 void CPageRecipe::OnBnClickedButtonNew()
 {
-	// TODO: 鍦ㄦ娣诲姞鎺т欢閫氱煡澶勭悊绋嬪簭浠g爜
-	//CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT);
-	//int nSel = pComboBox->GetCurSel();
-	//SERVO::CEquipment* pEq = (SERVO::CEquipment*)pComboBox->GetItemDataPtr(nSel);
-	//if (pEq == nullptr) {
-	//	return;
-	//}
+	int rc = UX_CanExecute(L"recipe");
+	if (rc != 1) {
+		AfxMessageBox("鎿嶄綔鏉冮檺涓嶈冻锛岃鑱旂郴绠$悊浜哄憳锛�");
+		return;
+	}
+	UX_RecordAction(L"recipe");
 
 	CRecipeDeviceBindDlg dlg(this);
 	if (dlg.DoModal() == IDOK) {
@@ -452,6 +451,13 @@
 
 void CPageRecipe::OnBnClickedButtonModify()
 {
+	int rc = UX_CanExecute(L"recipe");
+	if (rc != 1) {
+		AfxMessageBox("鎿嶄綔鏉冮檺涓嶈冻锛岃鑱旂郴绠$悊浜哄憳锛�");
+		return;
+	}
+	UX_RecordAction(L"recipe");
+
 	// TODO: 鍦ㄦ娣诲姞鎺т欢閫氱煡澶勭悊绋嬪簭浠g爜
 	CComboBox* pComboBox = (CComboBox*)GetDlgItem(IDC_COMBO_EQUIPMENT);
 	if (pComboBox == nullptr || !::IsWindow(pComboBox->m_hWnd)) {
@@ -492,6 +498,13 @@
 
 void CPageRecipe::OnBnClickedButtonDelete()
 {
+	int rc = UX_CanExecute(L"recipe");
+	if (rc != 1) {
+		AfxMessageBox("鎿嶄綔鏉冮檺涓嶈冻锛岃鑱旂郴绠$悊浜哄憳锛�");
+		return;
+	}
+	UX_RecordAction(L"recipe");
+
 	// TODO: 鍦ㄦ娣诲姞鎺т欢閫氱煡澶勭悊绋嬪簭浠g爜
 	POSITION pos = m_listPPID.GetFirstSelectedItemPosition();
 	if (!pos) { 
@@ -518,6 +531,13 @@
 
 void CPageRecipe::OnBnClickedButtonDeleteAll()
 {
+	int rc = UX_CanExecute(L"recipe");
+	if (rc != 1) {
+		AfxMessageBox("鎿嶄綔鏉冮檺涓嶈冻锛岃鑱旂郴绠$悊浜哄憳锛�");
+		return;
+	}
+	UX_RecordAction(L"recipe");
+
 	// TODO: 鍦ㄦ娣诲姞鎺т欢閫氱煡澶勭悊绋嬪簭浠g爜
 	if (IDYES != AfxMessageBox(_T("纭畾瑕佸垹闄ゅ叏閮ㄩ厤鏂硅褰曞悧锛�"), MB_YESNO | MB_ICONWARNING)) {
 		return;
diff --git a/SourceCode/Bond/Servo/Servo.rc b/SourceCode/Bond/Servo/Servo.rc
index 88ccd82..04a9f8f 100644
--- a/SourceCode/Bond/Servo/Servo.rc
+++ b/SourceCode/Bond/Servo/Servo.rc
Binary files differ
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj b/SourceCode/Bond/Servo/Servo.vcxproj
index f3e94f1..363766f 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj
+++ b/SourceCode/Bond/Servo/Servo.vcxproj
@@ -258,6 +258,7 @@
     <ClInclude Include="CUserManager2.h" />
     <ClInclude Include="CUserManager2Dlg.h" />
     <ClInclude Include="CUserEdit2Dlg.h" />
+    <ClInclude Include="CUserXLogDlg.h" />
     <ClInclude Include="CVariable.h" />
     <ClInclude Include="DeviceRecipeParamDlg.h" />
     <ClInclude Include="GlassJson.h" />
@@ -475,6 +476,7 @@
     <ClCompile Include="CUserManager2.cpp" />
     <ClCompile Include="CUserManager2Dlg.cpp" />
     <ClCompile Include="CUserEdit2Dlg.cpp" />
+    <ClCompile Include="CUserXLogDlg.cpp" />
     <ClCompile Include="CVariable.cpp" />
     <ClCompile Include="DeviceRecipeParamDlg.cpp" />
     <ClCompile Include="GlassJson.cpp" />
@@ -649,4 +651,4 @@
     <Error Condition="!Exists('..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Web.WebView2.1.0.2903.40\build\native\Microsoft.Web.WebView2.targets'))" />
     <Error Condition="!Exists('..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240803.1\build\native\Microsoft.Windows.ImplementationLibrary.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.ImplementationLibrary.1.0.240803.1\build\native\Microsoft.Windows.ImplementationLibrary.targets'))" />
   </Target>
-</Project>
+</Project>
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj.filters b/SourceCode/Bond/Servo/Servo.vcxproj.filters
index ef7e8a6..50f4087 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj.filters
+++ b/SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -232,6 +232,7 @@
     <ClCompile Include="CUserManager2.cpp" />
     <ClCompile Include="CUserManager2Dlg.cpp" />
     <ClCompile Include="CUserEdit2Dlg.cpp" />
+    <ClCompile Include="CUserXLogDlg.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="AlarmManager.h" />
@@ -507,6 +508,7 @@
     <ClInclude Include="CUserManager2.h" />
     <ClInclude Include="CUserManager2Dlg.h" />
     <ClInclude Include="CUserEdit2Dlg.h" />
+    <ClInclude Include="CUserXLogDlg.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Servo.rc" />
@@ -550,4 +552,4 @@
       <UniqueIdentifier>{885738f6-3122-4bb9-8308-46b7f692fb13}</UniqueIdentifier>
     </Filter>
   </ItemGroup>
-</Project>
+</Project>
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/ServoDlg.cpp b/SourceCode/Bond/Servo/ServoDlg.cpp
index 5705532..f563fbc 100644
--- a/SourceCode/Bond/Servo/ServoDlg.cpp
+++ b/SourceCode/Bond/Servo/ServoDlg.cpp
@@ -33,6 +33,7 @@
 #include "CControlJobManagerDlg.h"
 #include "CUserManager2.h"
 #include "CUserManager2Dlg.h"
+#include "CUserXLogDlg.h"
 
 
 #ifdef _DEBUG
@@ -1017,15 +1018,14 @@
 LRESULT CServoDlg::OnToolbarBtnClicked(WPARAM wParam, LPARAM lParam)
 {
 	int id = (int)lParam;
-	if (id == IDC_BUTTON_RUN || id == IDC_BUTTON_STOP) {
-		UserRole emRole = UserManager::getInstance().getCurrentUserRole();
-		if (emRole != UserRole::SuperAdmin) {
-			AfxMessageBox(_T("褰撳墠鐢ㄦ埛骞堕潪绠$悊鍛橈紒锛侊紒")); 
-			return 1;
-		}
-	}
-
 	if (id == IDC_BUTTON_RUN) {
+		int rc = UX_CanExecute(L"start");
+		if (rc != 1) {
+			AfxMessageBox("鎿嶄綔鏉冮檺涓嶈冻锛岃鑱旂郴绠$悊浜哄憳锛�");
+			return 0;
+		}
+		UX_RecordAction(L"start");
+
 		if (theApp.m_model.getMaster().getState() == SERVO::MASTERSTATE::MSERROR) {
 			AfxMessageBox("褰撳墠鏈夋満鍙板彂鐢熼敊璇紝涓嶈兘鍚姩锛岃纭瑙e喅闂鍚庡啀灏濊瘯閲嶆柊鍚姩锛�");
 		}
@@ -1062,6 +1062,13 @@
 		}
 	}
 	else if (id == IDC_BUTTON_STOP) {
+		int rc = UX_CanExecute(L"stop");
+		if (rc != 1) {
+			AfxMessageBox("鎿嶄綔鏉冮檺涓嶈冻锛岃鑱旂郴绠$悊浜哄憳锛�");
+			return 0;
+		}
+		UX_RecordAction(L"stop");
+
 		if (theApp.m_model.getMaster().stop() == 0) {
 			m_pTopToolbar->GetBtn(IDC_BUTTON_STOP)->EnableWindow(FALSE);
 		}
@@ -1101,12 +1108,13 @@
 			CUserManager2Dlg dlg;
 			dlg.DoModal();
 		}
+		else if (menuId == 1) {
+			CUserXLogDlg dlg;
+			dlg.DoModal();
+		}
 		else if (menuId == 2) {
 			CLoginDlg2 dlg;
-			if (dlg.DoModal() != IDOK) {
-				PostMessage(WM_CLOSE);
-			}
-			else {
+			if (dlg.DoModal() == IDOK) {
 				bool bRet = CUserManager2::getInstance().login((LPTSTR)(LPCTSTR)dlg.m_strUsername,
 					(LPTSTR)(LPCTSTR)dlg.m_strPassword);
 				if (!bRet) {
diff --git a/SourceCode/Bond/Servo/resource.h b/SourceCode/Bond/Servo/resource.h
index 6992734..05addab 100644
--- a/SourceCode/Bond/Servo/resource.h
+++ b/SourceCode/Bond/Servo/resource.h
Binary files differ

--
Gitblit v1.9.3