From 829fe6c6bc33d53fda9c31fd45a37e1df87befff Mon Sep 17 00:00:00 2001
From: mrDarker <mr.darker@163.com>
Date: 星期五, 30 一月 2026 11:16:24 +0800
Subject: [PATCH] Merge branch 'clh' into liuyang

---
 SourceCode/Bond/Servo/CUserXLogDlg.cpp |  178 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 178 insertions(+), 0 deletions(-)

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();
+}

--
Gitblit v1.9.3