From b17d444a0da9cabf775f90be04d14fac113bb9fb Mon Sep 17 00:00:00 2001
From: LAPTOP-SNT8I5JK\Boounion <Chenluhua@qq.com>
Date: 星期六, 13 九月 2025 17:56:36 +0800
Subject: [PATCH] 1.优化代码; 2.增加CControlJobManagerDlg对话框, 准备处理批任务。

---
 SourceCode/Bond/Servo/Servo.vcxproj             |    6 
 SourceCode/Bond/Servo/CCjPage1.cpp              |  110 ++++++++
 SourceCode/Bond/Servo/ProcessJob.h              |    4 
 SourceCode/Bond/Servo/ProcessJob.cpp            |   19 
 SourceCode/Bond/Servo/resource.h                |    0 
 SourceCode/Bond/Servo/CPageCollectionEvent.cpp  |    1 
 SourceCode/Bond/Servo/CControlJob.cpp           |   32 -
 SourceCode/Bond/Servo/CControlJob.h             |    2 
 SourceCode/Bond/Servo/TerminalDisplayDlg.cpp    |    1 
 SourceCode/Bond/Servo/CControlJobManagerDlg.h   |   34 ++
 SourceCode/Bond/Servo/GroupLabel.h              |   46 +++
 SourceCode/Bond/Servo/PageLog.cpp               |    2 
 SourceCode/Bond/Servo/CCjPage1.h                |   36 ++
 SourceCode/Bond/Servo/CControlJobManagerDlg.cpp |  131 ++++++++++
 SourceCode/Bond/Servo/CLoadPort.cpp             |    1 
 SourceCode/Bond/Servo/ServoDlg.cpp              |   20 -
 SourceCode/Bond/Servo/CPageVarialbles.cpp       |    1 
 SourceCode/Bond/Servo/Servo.vcxproj.filters     |    6 
 SourceCode/Bond/Servo/CEquipment.cpp            |    2 
 SourceCode/Bond/Servo/CServoUtilsTool.cpp       |    9 
 SourceCode/Bond/Servo/GroupLabel.cpp            |  275 +++++++++++++++++++++
 SourceCode/Bond/Servo/Servo.rc                  |    0 
 SourceCode/Bond/Servo/CPageReport.cpp           |    1 
 23 files changed, 680 insertions(+), 59 deletions(-)

diff --git a/SourceCode/Bond/Servo/CCjPage1.cpp b/SourceCode/Bond/Servo/CCjPage1.cpp
new file mode 100644
index 0000000..f81f8dd
--- /dev/null
+++ b/SourceCode/Bond/Servo/CCjPage1.cpp
@@ -0,0 +1,110 @@
+锘�// CPjPage1.cpp: 瀹炵幇鏂囦欢
+//
+
+#include "stdafx.h"
+#include "Servo.h"
+#include "CCjPage1.h"
+#include "afxdialogex.h"
+
+
+// CPjPage1 瀵硅瘽妗�
+
+IMPLEMENT_DYNAMIC(CCjPage1, CDialogEx)
+
+CCjPage1::CCjPage1(CWnd* pParent /*=nullptr*/)
+	: CDialogEx(IDD_CJ_PAGE1, pParent)
+{
+    m_crBkgnd = RGB(255, 255, 255);
+    m_crBkgndCached = CLR_INVALID;
+}
+
+CCjPage1::~CCjPage1()
+{
+}
+
+void CCjPage1::DoDataExchange(CDataExchange* pDX)
+{
+	CDialogEx::DoDataExchange(pDX);
+}
+
+
+BEGIN_MESSAGE_MAP(CCjPage1, CDialogEx)
+	ON_WM_CTLCOLOR()
+	ON_WM_DESTROY()
+	ON_WM_SIZE()
+END_MESSAGE_MAP()
+
+
+// CPjPage1 娑堟伅澶勭悊绋嬪簭
+
+
+BOOL CCjPage1::OnInitDialog()
+{
+	CDialogEx::OnInitDialog();
+    Resize();
+
+	return TRUE;  // return TRUE unless you set the focus to a control
+				  // 寮傚父: OCX 灞炴�ч〉搴旇繑鍥� FALSE
+}
+
+
+HBRUSH CCjPage1::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
+{
+    HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
+
+    // 鎯崇粰鍝簺鎺т欢鏀瑰簳鑹插氨鎶婂畠浠殑绫诲瀷鍐欒繘鏉ワ細
+    const bool needCustomBg =
+        (nCtlColor == CTLCOLOR_STATIC) ||
+        (nCtlColor == CTLCOLOR_DLG) ||   // 瀵硅瘽妗嗗簳鑹�
+        (nCtlColor == CTLCOLOR_BTN);        // 鎸夐挳锛堝彲閫夛級
+
+    if (needCustomBg)
+    {
+        // 鑻ョ涓�娆″垱寤猴紝鎴栭鑹叉敼鍙樺垯閲嶅缓
+        if (m_brBkgnd.GetSafeHandle() == nullptr || m_crBkgndCached != m_crBkgnd)
+        {
+            if (m_brBkgnd.GetSafeHandle())
+                m_brBkgnd.DeleteObject();
+
+            m_brBkgnd.CreateSolidBrush(m_crBkgnd);
+            m_crBkgndCached = m_crBkgnd;
+        }
+
+        // 鏂囨湰鍓嶆櫙/鑳屾櫙璁剧疆锛堜粎褰卞搷鏂囨湰缁樺埗锛�
+        pDC->SetBkColor(m_crBkgnd);
+        pDC->SetTextColor(RGB(0, 0, 0));
+        // 濡傞渶璁╅潤鎬佹枃鏈�忔槑鍙犲湪搴曡壊涓婏紝鍙敤锛�
+        // pDC->SetBkMode(TRANSPARENT);
+
+        return (HBRUSH)m_brBkgnd; // 瀹夊叏鐨勯殣寮忚浆鎹�
+    }
+
+    // 鍏朵粬鎺т欢绫诲瀷娌跨敤鍩虹被榛樿鐨勫埛瀛�
+    return hbr;
+}
+
+void CCjPage1::OnDestroy()
+{
+	CDialogEx::OnDestroy();
+
+	// TODO: 鍦ㄦ澶勬坊鍔犳秷鎭鐞嗙▼搴忎唬鐮�
+}
+
+void CCjPage1::OnSize(UINT nType, int cx, int cy)
+{
+	CDialogEx::OnSize(nType, cx, cy);
+    if (GetDlgItem(IDC_LABEL_NO_SEL) == nullptr) return;
+    Resize();
+}
+
+void CCjPage1::Resize()
+{
+    CWnd* pItem;
+    CRect rcClient, rcItem;
+    GetClientRect(&rcClient);
+    pItem = GetDlgItem(IDC_LABEL_NO_SEL);
+    pItem->GetWindowRect(&rcItem);
+    pItem->MoveWindow((rcClient.Width() - rcItem.Width()) / 2,
+        (rcClient.Height() - rcItem.Height()) / 2,
+        rcItem.Width(), rcItem.Height());
+}
diff --git a/SourceCode/Bond/Servo/CCjPage1.h b/SourceCode/Bond/Servo/CCjPage1.h
new file mode 100644
index 0000000..168fe9c
--- /dev/null
+++ b/SourceCode/Bond/Servo/CCjPage1.h
@@ -0,0 +1,36 @@
+锘�#pragma once
+
+
+// CPjPage1 瀵硅瘽妗�
+
+class CCjPage1 : public CDialogEx
+{
+	DECLARE_DYNAMIC(CCjPage1)
+
+public:
+	CCjPage1(CWnd* pParent = nullptr);   // 鏍囧噯鏋勯�犲嚱鏁�
+	virtual ~CCjPage1();
+
+private:
+	void Resize();
+
+private:
+	COLORREF m_crBkgnd;
+	COLORREF m_crBkgndCached;
+	CBrush m_brBkgnd;
+
+// 瀵硅瘽妗嗘暟鎹�
+#ifdef AFX_DESIGN_TIME
+	enum { IDD = IDD_CJ_PAGE1 };
+#endif
+
+protected:
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 鏀寔
+
+	DECLARE_MESSAGE_MAP()
+public:
+	virtual BOOL OnInitDialog();
+	afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
+	afx_msg void OnDestroy();
+	afx_msg void OnSize(UINT nType, int cx, int cy);
+};
diff --git a/SourceCode/Bond/Servo/CControlJob.cpp b/SourceCode/Bond/Servo/CControlJob.cpp
index 8dc2b18..be1b43a 100644
--- a/SourceCode/Bond/Servo/CControlJob.cpp
+++ b/SourceCode/Bond/Servo/CControlJob.cpp
@@ -4,9 +4,12 @@
 #include "SerializeUtil.h"
 
 static inline std::string trimCopy(std::string s) {
-    auto notspace = [](int ch) { return !std::isspace(ch); };
-    s.erase(s.begin(), std::find_if(s.begin(), s.end(), notspace));
-    s.erase(std::find_if(s.rbegin(), s.rend(), notspace).base(), s.end());
+    s.erase(s.begin(),
+        std::find_if(s.begin(), s.end(),
+            [](char c) { return !std::isspace(static_cast<unsigned char>(c)); }));
+    s.erase(std::find_if(s.rbegin(), s.rend(),
+        [](char c) { return !std::isspace(static_cast<unsigned char>(c)); }).base(),
+        s.end());
     return s;
 }
 
@@ -281,23 +284,12 @@
         out = CControlJob(cjId);
         out.setPriority(prio);
 
-        // 直接恢复内部状态(若你要求走状态机,可在这里按合法过渡调用 queue()/start()/...)
-        // 简化:直接赋值(你在 CControlJob.cpp 内部,可访问私有成员)
-        struct Access : CControlJob {
-            using CControlJob::m_state;
-            using CControlJob::m_failReason;
-            using CControlJob::m_tQueued;
-            using CControlJob::m_tStart;
-            using CControlJob::m_tEnd;
-            using CControlJob::m_pjIds;
-        };
-        auto& a = reinterpret_cast<Access&>(out);
-        a.m_state = static_cast<CJState>(st);
-        a.m_failReason = std::move(failText);
-        a.m_tQueued = std::move(tQ);
-        a.m_tStart = std::move(tS);
-        a.m_tEnd = std::move(tE);
-        a.m_pjIds = std::move(pjIds);
+        out.m_state = static_cast<CJState>(st);
+        out.m_failReason = std::move(failText);
+        out.m_tQueued = std::move(tQ);
+        out.m_tStart = std::move(tS);
+        out.m_tEnd = std::move(tE);
+        out.m_pjIds = std::move(pjIds);
 
         return true;
     }
diff --git a/SourceCode/Bond/Servo/CControlJob.h b/SourceCode/Bond/Servo/CControlJob.h
index 8533018..3053795 100644
--- a/SourceCode/Bond/Servo/CControlJob.h
+++ b/SourceCode/Bond/Servo/CControlJob.h
@@ -68,7 +68,7 @@
             const std::function<bool(const std::string&)>& getPjExistsFn,
             const std::function<bool(const std::string&)>& canJoinFn
         );
-        const std::vector<CControlJob::ValidationIssue>& CControlJob::issues();
+        const std::vector<ValidationIssue>& CControlJob::issues();
 
         // —— S14F9 → S14F10 的“应用结果”模型 —— //
         struct CreateRequest {
diff --git a/SourceCode/Bond/Servo/CControlJobManagerDlg.cpp b/SourceCode/Bond/Servo/CControlJobManagerDlg.cpp
new file mode 100644
index 0000000..e801498
--- /dev/null
+++ b/SourceCode/Bond/Servo/CControlJobManagerDlg.cpp
@@ -0,0 +1,131 @@
+锘�// CControlJobManagerDlg.cpp: 瀹炵幇鏂囦欢
+//
+
+#include "stdafx.h"
+#include "Servo.h"
+#include "CControlJobManagerDlg.h"
+#include "afxdialogex.h"
+
+
+// CControlJobManagerDlg 瀵硅瘽妗�
+
+IMPLEMENT_DYNAMIC(CControlJobManagerDlg, CDialogEx)
+
+CControlJobManagerDlg::CControlJobManagerDlg(CWnd* pParent /*=nullptr*/)
+	: CDialogEx(IDD_DIALOG_CONTROL_JOB_MANAGER, pParent)
+{
+	m_pPage1 = nullptr;
+}
+
+CControlJobManagerDlg::~CControlJobManagerDlg()
+{
+}
+
+void CControlJobManagerDlg::DoDataExchange(CDataExchange* pDX)
+{
+	CDialogEx::DoDataExchange(pDX);
+}
+
+
+BEGIN_MESSAGE_MAP(CControlJobManagerDlg, CDialogEx)
+	ON_WM_SIZE()
+	ON_WM_GETMINMAXINFO()
+END_MESSAGE_MAP()
+
+
+// CControlJobManagerDlg 娑堟伅澶勭悊绋嬪簭
+
+
+BOOL CControlJobManagerDlg::OnInitDialog()
+{
+	CDialogEx::OnInitDialog();
+
+	
+	// page1
+	m_pPage1 = new CCjPage1(this);
+	m_pPage1->Create(IDD_CJ_PAGE1, this);
+	m_pPage1->ShowWindow(SW_SHOW);
+
+
+	Resize();
+
+
+	return TRUE;  // return TRUE unless you set the focus to a control
+				  // 寮傚父: OCX 灞炴�ч〉搴旇繑鍥� FALSE
+}
+
+void CControlJobManagerDlg::OnSize(UINT nType, int cx, int cy)
+{
+	CDialogEx::OnSize(nType, cx, cy);
+	if (GetDlgItem(IDC_TREE1) == nullptr) return;
+
+	Resize();
+}
+
+void CControlJobManagerDlg::Resize()
+{
+	CWnd* pItem;
+	CRect rcClient, rcItem;
+	GetClientRect(&rcClient);
+
+	GetDlgItem(IDCANCEL)->GetWindowRect(&rcItem);
+	ScreenToClient(&rcItem);
+
+	const int LEFTWIDTH = 218;
+	int x = 12;
+	int x2 = rcClient.right - 12;
+	int y2 = rcClient.bottom - 12;
+
+
+	// 鍏堢Щ鍔ㄦ寜閽�
+	pItem = GetDlgItem(IDC_BUTTON_BATH_COMPLETION);
+	pItem->GetWindowRect(&rcItem);
+	pItem->MoveWindow(x, y2 - rcItem.Height(), rcItem.Width(), rcItem.Height());
+	x += rcItem.Width();
+	x += 8;
+
+	pItem = GetDlgItem(IDC_BUTTON_BATH_NEW);
+	pItem->GetWindowRect(&rcItem);
+	pItem->MoveWindow(x, y2 - rcItem.Height(), rcItem.Width(), rcItem.Height());
+	x += rcItem.Width();
+	x += 8;
+
+	pItem = GetDlgItem(IDC_BUTTON_BATH_DELETE);
+	pItem->GetWindowRect(&rcItem);
+	pItem->MoveWindow(x, y2 - rcItem.Height(), rcItem.Width(), rcItem.Height());
+	x += rcItem.Width();
+	x += 8;
+
+	pItem = GetDlgItem(IDCANCEL);
+	pItem->GetWindowRect(&rcItem);
+	pItem->MoveWindow(x2 - rcItem.Width(), y2 - rcItem.Height(), rcItem.Width(), rcItem.Height());
+	y2 -= rcItem.Height();
+	y2 -= 8;
+
+
+	// 鏍戞帶浠�
+	x = 12;
+	pItem = GetDlgItem(IDC_TREE1);
+	pItem->MoveWindow(x, 12, LEFTWIDTH, y2 - 12);
+	x += LEFTWIDTH;
+	x += 5;
+
+
+	// 瀛愰〉闈�
+	if (m_pPage1 != nullptr) {
+		m_pPage1->MoveWindow(x, 12, x2 - x, y2 - 12);
+	}
+}
+
+void CControlJobManagerDlg::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
+{
+	CDialogEx::OnGetMinMaxInfo(lpMMI);
+
+	// 璁剧疆鏈�灏忓楂橈紙姣斿 400x300锛�
+	lpMMI->ptMinTrackSize.x = 600;
+	lpMMI->ptMinTrackSize.y = 400;
+
+	// 涔熷彲浠ラ『渚胯缃渶澶у楂�
+	// lpMMI->ptMaxTrackSize.x = 800;
+	// lpMMI->ptMaxTrackSize.y = 600;
+}
diff --git a/SourceCode/Bond/Servo/CControlJobManagerDlg.h b/SourceCode/Bond/Servo/CControlJobManagerDlg.h
new file mode 100644
index 0000000..ebc1f11
--- /dev/null
+++ b/SourceCode/Bond/Servo/CControlJobManagerDlg.h
@@ -0,0 +1,34 @@
+锘�#pragma once
+#include "CCjPage1.h"
+
+
+// CControlJobManagerDlg 瀵硅瘽妗�
+
+class CControlJobManagerDlg : public CDialogEx
+{
+	DECLARE_DYNAMIC(CControlJobManagerDlg)
+
+public:
+	CControlJobManagerDlg(CWnd* pParent = nullptr);   // 鏍囧噯鏋勯�犲嚱鏁�
+	virtual ~CControlJobManagerDlg();
+
+private:
+	void Resize();
+
+private:
+	CCjPage1* m_pPage1;
+
+// 瀵硅瘽妗嗘暟鎹�
+#ifdef AFX_DESIGN_TIME
+	enum { IDD = IDD_DIALOG_CONTROL_JOB_MANAGER };
+#endif
+
+protected:
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 鏀寔
+
+	DECLARE_MESSAGE_MAP()
+public:
+	virtual BOOL OnInitDialog();
+	afx_msg void OnSize(UINT nType, int cx, int cy);
+	afx_msg void OnGetMinMaxInfo(MINMAXINFO* lpMMI);
+};
diff --git a/SourceCode/Bond/Servo/CEquipment.cpp b/SourceCode/Bond/Servo/CEquipment.cpp
index 6a3b56d..48ba657 100644
--- a/SourceCode/Bond/Servo/CEquipment.cpp
+++ b/SourceCode/Bond/Servo/CEquipment.cpp
@@ -2237,7 +2237,7 @@
 				return -1;
 			});
 		pStep->setName(STEP_EQ_FAC_DATA_REPORT);
-		pStep->setProp("Port", (void*)port);
+		pStep->setProp("Port", (void*)(__int64)port);
 		pStep->setWriteSignalDev(writeSignalDev);
 		if (addStep(STEP_ID_FAC_DATA_REPORT, pStep) != 0) {
 			delete pStep;
diff --git a/SourceCode/Bond/Servo/CLoadPort.cpp b/SourceCode/Bond/Servo/CLoadPort.cpp
index 22b517b..13df4d9 100644
--- a/SourceCode/Bond/Servo/CLoadPort.cpp
+++ b/SourceCode/Bond/Servo/CLoadPort.cpp
@@ -404,7 +404,6 @@
 			m_portStatusReport.serialize(ar);
 		}
 		else {
-			int temp;
 			ar >> m_nIndex;
 			m_portStatusReport.serialize(ar);
 		}
diff --git a/SourceCode/Bond/Servo/CPageCollectionEvent.cpp b/SourceCode/Bond/Servo/CPageCollectionEvent.cpp
index a7108fb..b7d3322 100644
--- a/SourceCode/Bond/Servo/CPageCollectionEvent.cpp
+++ b/SourceCode/Bond/Servo/CPageCollectionEvent.cpp
@@ -106,7 +106,6 @@
 	CHMPropertyPage::OnSize(nType, cx, cy);
 	if (GetDlgItem(IDC_LIST1) == nullptr) return;
 
-	CWnd* pItem;
 	CRect rcClient, rcItem;
 	GetClientRect(&rcClient);
 	m_listCtrl.MoveWindow(12, 12, rcClient.Width() - 24, rcClient.Height() - 24);
diff --git a/SourceCode/Bond/Servo/CPageReport.cpp b/SourceCode/Bond/Servo/CPageReport.cpp
index 94f55b8..0066c9b 100644
--- a/SourceCode/Bond/Servo/CPageReport.cpp
+++ b/SourceCode/Bond/Servo/CPageReport.cpp
@@ -108,7 +108,6 @@
 	CHMPropertyPage::OnSize(nType, cx, cy);
 	if (GetDlgItem(IDC_LIST1) == nullptr) return;
 
-	CWnd* pItem;
 	CRect rcClient, rcItem;
 	GetClientRect(&rcClient);
 	m_listCtrl.MoveWindow(12, 12, rcClient.Width() - 24, rcClient.Height() - 24);
diff --git a/SourceCode/Bond/Servo/CPageVarialbles.cpp b/SourceCode/Bond/Servo/CPageVarialbles.cpp
index 415a5dc..5f4f5cc 100644
--- a/SourceCode/Bond/Servo/CPageVarialbles.cpp
+++ b/SourceCode/Bond/Servo/CPageVarialbles.cpp
@@ -108,7 +108,6 @@
 
 	if (GetDlgItem(IDC_LIST1) == nullptr) return;
 
-	CWnd* pItem;
 	CRect rcClient, rcItem;
 	GetClientRect(&rcClient);
 	m_listCtrl.MoveWindow(12, 12, rcClient.Width() - 24, rcClient.Height() - 24);
diff --git a/SourceCode/Bond/Servo/CServoUtilsTool.cpp b/SourceCode/Bond/Servo/CServoUtilsTool.cpp
index 1bf444a..19fa4d9 100644
--- a/SourceCode/Bond/Servo/CServoUtilsTool.cpp
+++ b/SourceCode/Bond/Servo/CServoUtilsTool.cpp
@@ -39,11 +39,6 @@
 			if (unit == 1) return "烘烤B腔";
 		}
 
-		if (eqid == EQ_ID_VACUUMBAKE) {
-			if (unit == 0) return "烘烤A腔";
-			if (unit == 1) return "烘烤B腔";
-		}
-
 		if (eqid == EQ_ID_Bonder1) {
 			return "Bonder1";
 		}
@@ -56,8 +51,8 @@
 
 			if (unit == 0) return "后烘烤A腔";
 			if (unit == 1) return "冷却A";
-			if (unit == 0) return "后烘烤B腔";
-			if (unit == 1) return "冷却B";
+			if (unit == 2) return "后烘烤B腔";
+			if (unit == 3) return "冷却B";
 		}
 
 		if (eqid == EQ_ID_MEASUREMENT) {
diff --git a/SourceCode/Bond/Servo/GroupLabel.cpp b/SourceCode/Bond/Servo/GroupLabel.cpp
new file mode 100644
index 0000000..57f31d0
--- /dev/null
+++ b/SourceCode/Bond/Servo/GroupLabel.cpp
@@ -0,0 +1,275 @@
+#include "stdafx.h"
+#include "GroupLabel.h"
+
+
+CGroupLabel::CGroupLabel()
+{
+	m_crBkgnd = RGB(255, 255, 255);
+	m_crLine = RGB(188, 188, 188);
+	m_crText = RGB(88, 88, 88);
+	m_nPadding[PADDING_LEFT] = 5;
+	m_nPadding[PADDING_TOP] = 5;
+	m_nPadding[PADDING_RIGHT] = 5;
+	m_nPadding[PADDING_BOTTOM] = 5;
+	m_nTextAlign = TEXT_ALIGN_CENTER;
+	m_bEnableResize = FALSE;
+}
+
+
+CGroupLabel::~CGroupLabel()
+{
+}
+BEGIN_MESSAGE_MAP(CGroupLabel, CStatic)
+	ON_WM_PAINT()
+	ON_WM_LBUTTONDOWN()
+	ON_WM_SETCURSOR()
+END_MESSAGE_MAP()
+
+
+void CGroupLabel::EnableResize()
+{
+	m_bEnableResize = TRUE;
+
+	DWORD dwStyle = GetStyle();
+	dwStyle |= SS_NOTIFY;
+	SetWindowLong(GetSafeHwnd(), GWL_STYLE, dwStyle);
+}
+
+void CGroupLabel::DisableResize()
+{
+	m_bEnableResize = FALSE;
+}
+
+void CGroupLabel::OnPaint()
+{
+	CPaintDC dc(this); // device context for painting
+					   // TODO: 在此处添加消息处理程序代码
+					   // 不为绘图消息调用 CStatic::OnPaint()
+
+
+	HDC hMemDC;
+	HBITMAP hBitmap;
+	RECT rcClient;
+	CString strText;
+	HFONT hFont;
+	HBRUSH hBrushBK;
+
+			
+	::GetClientRect(m_hWnd, &rcClient);
+	hMemDC = ::CreateCompatibleDC(dc.m_hDC);
+	hBitmap = ::CreateCompatibleBitmap(dc.m_hDC, rcClient.right - rcClient.left,
+		rcClient.bottom - rcClient.top);
+	::SelectObject(hMemDC, hBitmap);
+	::SetBkMode(hMemDC, TRANSPARENT);
+
+
+	// 背景颜色
+	hBrushBK = CreateSolidBrush(m_crBkgnd);
+	::FillRect(hMemDC, &rcClient, hBrushBK);
+	DeleteObject(hBrushBK);
+
+
+	// 窗口标题
+	int x1, x2, x3, x4;
+	x1 = rcClient.left + m_nPadding[PADDING_LEFT];
+	x4 = rcClient.right - m_nPadding[PADDING_RIGHT];
+	hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
+	::SelectObject(hMemDC, hFont);
+	::SetTextColor(hMemDC, m_crText);
+	char szTitle[256];
+	int nTextLen = ::GetWindowText(m_hWnd, szTitle, 256);
+	if (nTextLen > 0) {
+		RECT rcTitle;
+		SIZE sizeText;
+
+		rcTitle.left = x1;
+		rcTitle.top = rcClient.top + 2;
+		rcTitle.bottom = rcClient.bottom - 2;
+		rcTitle.right = x4;
+
+#define TEXT_SPAGE	12
+		GetTextExtentPoint32(hMemDC, szTitle, nTextLen, &sizeText);
+		if (TEXT_ALIGN_LEFT == m_nTextAlign) {
+			::DrawText(hMemDC, szTitle, nTextLen, &rcTitle, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
+			x1 += sizeText.cx + TEXT_SPAGE;
+		}
+		else if (TEXT_ALIGN_CENTER == m_nTextAlign) {
+			::DrawText(hMemDC, szTitle, nTextLen, &rcTitle, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
+			x2 = x1 + (x4 - x1 - sizeText.cx - TEXT_SPAGE * 2) / 2;
+			x3 = x2 + sizeText.cx + TEXT_SPAGE * 2;
+		}
+		else {
+			::DrawText(hMemDC, szTitle, nTextLen, &rcTitle, DT_RIGHT | DT_VCENTER | DT_SINGLELINE);
+			x4 -= (sizeText.cx + TEXT_SPAGE);
+		}
+
+
+	}
+
+
+	// 分隔线
+	HPEN hPen = CreatePen(PS_SOLID, 1, m_crLine);
+	HPEN hOldPen = (HPEN)SelectObject(hMemDC, hPen);
+	int y = (rcClient.bottom - rcClient.top) / 2;
+
+	if (TEXT_ALIGN_LEFT == m_nTextAlign) {
+		::MoveToEx(hMemDC, x1, y, NULL);
+		::LineTo(hMemDC, x4, y);
+	}
+	else if (TEXT_ALIGN_CENTER == m_nTextAlign) {
+		::MoveToEx(hMemDC, x1, y, NULL);
+		::LineTo(hMemDC, x2, y);
+		::MoveToEx(hMemDC, x3, y, NULL);
+		::LineTo(hMemDC, x4, y);
+	}
+	else {
+		::MoveToEx(hMemDC, x1, y, NULL);
+		::LineTo(hMemDC, x4, y);
+	}
+
+	SelectObject(hMemDC, hOldPen);
+	::DeleteObject(hPen);
+
+
+	// EndPaint
+	::BitBlt(dc.m_hDC, 0, 0, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top,
+		hMemDC, 0, 0, SRCCOPY);
+	::DeleteObject(hBitmap);
+	::DeleteDC(hMemDC);
+}
+
+void CGroupLabel::SetTextAlignMode(int nAlign)
+{
+	if (nAlign == TEXT_ALIGN_LEFT || nAlign == TEXT_ALIGN_CENTER || nAlign == TEXT_ALIGN_RIGHT) {
+		m_nTextAlign = nAlign;
+
+		RECT rcClient;
+		::GetClientRect(m_hWnd, &rcClient);
+		::InvalidateRect(m_hWnd, &rcClient, TRUE);
+	}
+}
+
+void CGroupLabel::Setpadding(int type, unsigned int nPadding)
+{
+	if (type >= PADDING_LEFT && PADDING_LEFT <= PADDING_BOTTOM) {
+		m_nPadding[type] = nPadding;
+	}
+}
+
+/*
+ * 设置背景色
+ * color -- 背景色
+ */
+void CGroupLabel::SetBkgndColor(COLORREF color)
+{
+	m_crBkgnd = color;
+}
+
+/*
+ * 设置文本色
+ * color -- 背景色
+ */
+void CGroupLabel::SetTextColor(COLORREF color)
+{
+	m_crText = color;
+
+	RECT rcClient;
+	::GetClientRect(m_hWnd, &rcClient);
+	::InvalidateRect(m_hWnd, &rcClient, TRUE);
+}
+
+/*
+ * 设置线色
+ * color -- 背景色
+ */
+void CGroupLabel::SetLineColor(COLORREF color)
+{
+	m_crLine = color;
+
+	RECT rcClient;
+	::GetClientRect(m_hWnd, &rcClient);
+	::InvalidateRect(m_hWnd, &rcClient, TRUE);
+}
+
+ void CGroupLabel::OnLButtonDown(UINT nFlags, CPoint point)
+ {
+	 if (!m_bEnableResize) {
+		 CStatic::OnLButtonDown(nFlags, point);
+		 return;
+	 }
+
+	 CPoint pt, ptNew;
+	 pt = point;
+	 int nMoveY = 0;
+
+	 // 捕捉鼠标消息,检测是否拖动
+	 CRect rcParent, rcWindows;
+	 GetClientRect(&rcWindows);
+	 ::ClientToScreen(m_hWnd, (LPPOINT)&rcWindows);
+	 ::ClientToScreen(m_hWnd, (LPPOINT)&rcWindows.right);
+	 GetParent()->GetClientRect(&rcParent);
+	 ::ClientToScreen(GetParent()->m_hWnd, (LPPOINT)&rcParent);
+	 HDC hDC = ::GetDC(::GetDesktopWindow());
+	 ::DrawFocusRect(hDC, &rcWindows);
+
+	 if (::GetCapture() == NULL) {
+		 SetCapture();
+		 ASSERT(this == GetCapture());
+		 AfxLockTempMaps();
+		 for (;;) {
+			 MSG msg;
+			 VERIFY(::GetMessage(&msg, NULL, 0, 0));
+
+			 if (GetCapture() != this) break;
+
+			 switch (msg.message)
+			 {
+			 case WM_MOUSEMOVE:
+				 ptNew = msg.pt;
+				 if (ptNew.y < rcParent.top) ptNew.y = rcParent.top;
+				 ::DrawFocusRect(hDC, &rcWindows);
+				 rcWindows.top = ptNew.y - 3;
+				 rcWindows.bottom = ptNew.y + 3;
+				 ::DrawFocusRect(hDC, &rcWindows);
+				 ::ScreenToClient(m_hWnd, &ptNew);
+				 break;
+
+			 case WM_LBUTTONUP:
+				 ptNew = msg.pt;
+				 ::ScreenToClient(m_hWnd, &ptNew);
+				 nMoveY = ptNew.y - pt.y;
+				 goto ExitLoop;
+
+			 case WM_KEYDOWN:
+				 if (msg.wParam == VK_ESCAPE) {
+					 goto ExitLoop;
+				 }
+				 break;
+
+			 default:
+				 DispatchMessage(&msg);
+				 break;
+			 }
+		 }
+
+	 ExitLoop:
+		 ::DrawFocusRect(hDC, &rcWindows);
+		 ::ReleaseDC(::GetDesktopWindow(), hDC);
+		 ReleaseCapture();
+		 ::InvalidateRect(m_hWnd, NULL, TRUE);
+		 GetParent()->SendMessage(ID_MSG_RESIZEY, nMoveY, 0);
+		 AfxUnlockTempMaps(FALSE);
+	 }
+
+	 CStatic::OnLButtonDown(nFlags, point);
+ }
+
+ BOOL CGroupLabel::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
+ {
+	 if (m_bEnableResize) {
+		 ::SetCursor(::LoadCursor(NULL, IDC_SIZENS));
+		 return TRUE;
+	 }
+
+	 return CStatic::OnSetCursor(pWnd, nHitTest, message);
+ }
diff --git a/SourceCode/Bond/Servo/GroupLabel.h b/SourceCode/Bond/Servo/GroupLabel.h
new file mode 100644
index 0000000..ba259f6
--- /dev/null
+++ b/SourceCode/Bond/Servo/GroupLabel.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#define PADDING_LEFT		0
+#define PADDING_TOP			1
+#define PADDING_RIGHT		2
+#define PADDING_BOTTOM		3
+
+#define TEXT_ALIGN_LEFT		0
+#define TEXT_ALIGN_CENTER	1
+#define TEXT_ALIGN_RIGHT	3
+
+#define ID_MSG_RESIZEY		WM_USER+123
+
+class CGroupLabel : public CStatic
+{
+public:
+	CGroupLabel();
+	~CGroupLabel();
+
+
+public:
+	void SetBkgndColor(COLORREF color);
+	void SetTextColor(COLORREF color);
+	void SetLineColor(COLORREF color);
+	void Setpadding(int type, unsigned int nPadding);
+	void SetTextAlignMode(int nAlign);
+	void EnableResize();
+	void DisableResize();
+
+private:
+	COLORREF	m_crBkgnd;
+	unsigned int m_nPadding[4];
+	COLORREF	m_crLine;
+	COLORREF	m_crText;
+	int			m_nTextAlign;
+
+private:
+	BOOL m_bEnableResize;
+
+	DECLARE_MESSAGE_MAP()
+	afx_msg void OnPaint();
+public:
+	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
+	afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
+};
+
diff --git a/SourceCode/Bond/Servo/PageLog.cpp b/SourceCode/Bond/Servo/PageLog.cpp
index 98bcfae..555f862 100644
--- a/SourceCode/Bond/Servo/PageLog.cpp
+++ b/SourceCode/Bond/Servo/PageLog.cpp
@@ -84,7 +84,7 @@
 										std::regex((LPTSTR)(LPCTSTR)m_strFilterText));
 								}
 								catch (const std::regex_error& e) {
-
+									TRACE(_T("正在表达式匹配检测异常: %s\n"), e.what());
 								}
 							}
 							if (m_filterMode == FilterMode::Exclude) {
diff --git a/SourceCode/Bond/Servo/ProcessJob.cpp b/SourceCode/Bond/Servo/ProcessJob.cpp
index b672e27..57c771c 100644
--- a/SourceCode/Bond/Servo/ProcessJob.cpp
+++ b/SourceCode/Bond/Servo/ProcessJob.cpp
@@ -7,9 +7,12 @@
 
 namespace SERVO {
     static inline std::string trimCopy(std::string s) {
-        auto notspace = [](int ch) { return !std::isspace(ch); };
-        s.erase(s.begin(), std::find_if(s.begin(), s.end(), notspace));
-        s.erase(std::find_if(s.rbegin(), s.rend(), notspace).base(), s.end());
+        s.erase(s.begin(),
+            std::find_if(s.begin(), s.end(),
+                [](char c) { return !std::isspace(static_cast<unsigned char>(c)); }));
+        s.erase(std::find_if(s.rbegin(), s.rend(),
+            [](char c) { return !std::isspace(static_cast<unsigned char>(c)); }).base(),
+            s.end());
         return s;
     }
 
@@ -61,7 +64,7 @@
         m_pauseEvents.erase(std::unique(m_pauseEvents.begin(), m_pauseEvents.end()), m_pauseEvents.end());
     }
 
-    const std::vector<CProcessJob::ValidationIssue>& CProcessJob::issues()
+    const std::vector<CProcessJob::ValidationIssue>& CProcessJob::issues() const
     {
         return m_issues;
     }
@@ -278,7 +281,7 @@
 
         // 配方
         uint8_t recipeType = static_cast<uint8_t>(m_recipeMethod);
-        write_pod(os, m_recipeMethod);
+        write_pod(os, recipeType);
         write_string(os, m_recipeSpec);
 
         // 物料(多 Carrier & Slot)
@@ -399,13 +402,13 @@
             return "InProcess";
             break;
         case SERVO::PJState::Paused:
-            return "Queued";
+            return "Paused";
             break;
         case SERVO::PJState::Aborting:
             return "Aborting";
             break;
         case SERVO::PJState::Completed:
-            return "Queued";
+            return "Completed";
             break;
         case SERVO::PJState::Aborted:
             return "Aborted";
@@ -420,7 +423,7 @@
         return "";
     }
 
-    CarrierSlotInfo* CProcessJob::getCarrier(std::string& strId)
+    CarrierSlotInfo* CProcessJob::getCarrier(const  std::string& strId)
     {
         for (auto& item : m_carriers) {
             if (item.carrierId.compare(strId) == 0) {
diff --git a/SourceCode/Bond/Servo/ProcessJob.h b/SourceCode/Bond/Servo/ProcessJob.h
index 1300b46..28b83e1 100644
--- a/SourceCode/Bond/Servo/ProcessJob.h
+++ b/SourceCode/Bond/Servo/ProcessJob.h
@@ -121,7 +121,7 @@
         };
         // 返回问题清单(空=通过)
         bool validate(const IResourceView& rv);
-        const std::vector<ValidationIssue>& issues();
+        const std::vector<ValidationIssue>& issues() const;
 
         // —— 状态机(带守卫)——
         bool queue();           // NoState -> Queued
@@ -155,7 +155,7 @@
 
         // 访问器
         const std::vector<CarrierSlotInfo>& carriers() const noexcept { return m_carriers; }
-        CarrierSlotInfo* getCarrier(std::string& strId);
+        CarrierSlotInfo* getCarrier(const std::string& strId);
 
         // 判定是否“按载具/卡位”方式
         bool usesCarrierSlots() const noexcept { return !m_carriers.empty(); }
diff --git a/SourceCode/Bond/Servo/Servo.rc b/SourceCode/Bond/Servo/Servo.rc
index f4782c3..8ee0574 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 3022283..5b150fd 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj
+++ b/SourceCode/Bond/Servo/Servo.vcxproj
@@ -212,6 +212,7 @@
     <ClInclude Include="CBaseDlg.h" />
     <ClInclude Include="CControlJob.h" />
     <ClInclude Include="CControlJobDlg.h" />
+    <ClInclude Include="CControlJobManagerDlg.h" />
     <ClInclude Include="CCustomCheckBox.h" />
     <ClInclude Include="CCollectionEvent.h" />
     <ClInclude Include="CEquipmentPage3.h" />
@@ -225,6 +226,7 @@
     <ClInclude Include="CPageReport.h" />
     <ClInclude Include="CPageVarialbles.h" />
     <ClInclude Include="CParam.h" />
+    <ClInclude Include="CCjPage1.h" />
     <ClInclude Include="CProcessDataListDlg.h" />
     <ClInclude Include="CReport.h" />
     <ClInclude Include="CRobotCmdContainerDlg.h" />
@@ -254,6 +256,7 @@
     <ClInclude Include="GridControl\TitleTip.h" />
     <ClInclude Include="CRobotTask.h" />
     <ClInclude Include="CSlot.h" />
+    <ClInclude Include="GroupLabel.h" />
     <ClInclude Include="HorizontalLine.h" />
     <ClInclude Include="InputDialog.h" />
     <ClInclude Include="JobSlotGrid.h" />
@@ -388,6 +391,7 @@
     <ClCompile Include="CBaseDlg.cpp" />
     <ClCompile Include="CControlJob.cpp" />
     <ClCompile Include="CControlJobDlg.cpp" />
+    <ClCompile Include="CControlJobManagerDlg.cpp" />
     <ClCompile Include="CCustomCheckBox.cpp" />
     <ClCompile Include="CCollectionEvent.cpp" />
     <ClCompile Include="CEquipmentPage3.cpp" />
@@ -401,6 +405,7 @@
     <ClCompile Include="CPageReport.cpp" />
     <ClCompile Include="CPageVarialbles.cpp" />
     <ClCompile Include="CParam.cpp" />
+    <ClCompile Include="CCjPage1.cpp" />
     <ClCompile Include="CProcessDataListDlg.cpp" />
     <ClCompile Include="CReport.cpp" />
     <ClCompile Include="CRobotCmdContainerDlg.cpp" />
@@ -428,6 +433,7 @@
     <ClCompile Include="GridControl\TitleTip.cpp" />
     <ClCompile Include="CRobotTask.cpp" />
     <ClCompile Include="CSlot.cpp" />
+    <ClCompile Include="GroupLabel.cpp" />
     <ClCompile Include="HorizontalLine.cpp" />
     <ClCompile Include="InputDialog.cpp" />
     <ClCompile Include="JobSlotGrid.cpp" />
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj.filters b/SourceCode/Bond/Servo/Servo.vcxproj.filters
index 796971e..d7b7472 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj.filters
+++ b/SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -198,6 +198,9 @@
     <ClCompile Include="GlassLogDb.cpp" />
     <ClCompile Include="sqlite3.c" />
     <ClCompile Include="CProcessDataListDlg.cpp" />
+    <ClCompile Include="GroupLabel.cpp" />
+    <ClCompile Include="CControlJobManagerDlg.cpp" />
+    <ClCompile Include="CCjPage1.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="AlarmManager.h" />
@@ -421,6 +424,9 @@
     <ClInclude Include="sqlite3.h" />
     <ClInclude Include="sqlite3ext.h" />
     <ClInclude Include="CProcessDataListDlg.h" />
+    <ClInclude Include="GroupLabel.h" />
+    <ClInclude Include="CControlJobManagerDlg.h" />
+    <ClInclude Include="CCjPage1.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Servo.rc" />
diff --git a/SourceCode/Bond/Servo/ServoDlg.cpp b/SourceCode/Bond/Servo/ServoDlg.cpp
index 74f8607..4158bae 100644
--- a/SourceCode/Bond/Servo/ServoDlg.cpp
+++ b/SourceCode/Bond/Servo/ServoDlg.cpp
@@ -28,6 +28,7 @@
 #include "CPageCollectionEvent.h"
 #include "CControlJobDlg.h"
 #include "InputDialog.h"
+#include "CControlJobManagerDlg.h"
 
 
 #ifdef _DEBUG
@@ -989,20 +990,6 @@
 {
 	int id = (int)lParam;
 	if (id == IDC_BUTTON_RUN || id == IDC_BUTTON_STOP) {
-		//CInputDialog inputDialog(_T("验证用户"), _T("请输入用户密码:"));
-		//if (inputDialog.DoModal() != IDOK) {
-		//	AfxMessageBox(_T("取消验证!"));
-		//	return 0;
-		//}
-	
-		//CString inputText = inputDialog.GetInputText();
-		//std::string strPass = UserManager::getInstance().getCurrentPass();
-		//if (inputText.Compare(strPass.c_str()) != 0) {
-		//	AfxMessageBox(_T("密码错误!"));
-		//	SystemLogManager::getInstance().log(SystemLogManager::LogType::Info, _T("验证时,密码错误!"));
-		//	return 0;
-		//}
-		
 		UserRole emRole = UserManager::getInstance().getCurrentUserRole();
 		if (emRole != UserRole::SuperAdmin) {
 			AfxMessageBox(_T("当前用户并非管理员!!!")); 
@@ -1052,9 +1039,14 @@
 		}
 	}
 	else if (id == IDC_BUTTON_JOBS) {
+		CControlJobManagerDlg dlg;
+		dlg.DoModal();
+
+		/*
 		CControlJobDlg dlg;
 		dlg.SetControlJob(theApp.m_model.m_master.getControlJob());
 		dlg.DoModal();
+		*/
 	}
 	else if (id == IDC_BUTTON_PORT_CONFIG) {
 		CPortConfigurationDlg dlg;
diff --git a/SourceCode/Bond/Servo/TerminalDisplayDlg.cpp b/SourceCode/Bond/Servo/TerminalDisplayDlg.cpp
index a7a88be..81b3e4e 100644
--- a/SourceCode/Bond/Servo/TerminalDisplayDlg.cpp
+++ b/SourceCode/Bond/Servo/TerminalDisplayDlg.cpp
@@ -104,7 +104,6 @@
 
 void CTerminalDisplayDlg::Resize()
 {
-	CWnd* pItem;
 	CRect rcClient, rcItem;
 	GetClientRect(&rcClient);
 	rcClient.top += 38;
diff --git a/SourceCode/Bond/Servo/resource.h b/SourceCode/Bond/Servo/resource.h
index bd3bb31..7e8dbb3 100644
--- a/SourceCode/Bond/Servo/resource.h
+++ b/SourceCode/Bond/Servo/resource.h
Binary files differ

--
Gitblit v1.9.3