From 0275102b79ccf2c7fe1acf11117de8a89cca372f Mon Sep 17 00:00:00 2001
From: chenluhua1980 <Chenluhua@qq.com>
Date: 星期五, 26 十二月 2025 15:27:03 +0800
Subject: [PATCH] 1.生产总览页面框架实现;

---
 SourceCode/Bond/Servo/CPageProdOverview.cpp |  140 +++++
 SourceCode/Bond/Servo/Servo.vcxproj         |    8 
 SourceCode/Bond/Servo/resource.h            |    9 
 SourceCode/Bond/Servo/Servo.cpp             |    2 
 SourceCode/Bond/Servo/CPanelProduction.cpp  |   24 +
 SourceCode/Bond/BondEq/AccordionWnd.cpp     |   16 
 SourceCode/Bond/Servo/AccordionWnd.h        |  131 +++++
 SourceCode/Bond/Servo/CPanelProduction.h    |    5 
 SourceCode/Bond/Servo/CPageProdOverview.h   |   37 +
 SourceCode/Bond/Servo/Servo.vcxproj.filters |    8 
 SourceCode/Bond/Servo/AccordionWnd.cpp      |  787 ++++++++++++++++++++++++++++++++
 SourceCode/Bond/Servo/Servo.rc              |   25 +
 SourceCode/Bond/Servo/HmLabel.cpp           |  177 +++++++
 SourceCode/Bond/Servo/HmLabel.h             |   33 +
 14 files changed, 1,393 insertions(+), 9 deletions(-)

diff --git a/SourceCode/Bond/BondEq/AccordionWnd.cpp b/SourceCode/Bond/BondEq/AccordionWnd.cpp
index 5da6615..026628e 100644
--- a/SourceCode/Bond/BondEq/AccordionWnd.cpp
+++ b/SourceCode/Bond/BondEq/AccordionWnd.cpp
@@ -47,9 +47,16 @@
 
 BOOL CAccordionWnd::RegisterWndClass()
 {
-	WNDCLASS wc;
+	WNDCLASS wcExisting = {};
+	HINSTANCE hInstance = AfxGetInstanceHandle();
+	if (::GetClassInfo(hInstance, ACCORDIONWND_CLASS, &wcExisting) ||
+		::GetClassInfo(NULL, ACCORDIONWND_CLASS, &wcExisting)) {
+		return TRUE;
+	}
+
+	WNDCLASS wc = {};
 	wc.lpszClassName = ACCORDIONWND_CLASS;
-	wc.hInstance = AfxGetInstanceHandle();
+	wc.hInstance = hInstance;
 	wc.lpfnWndProc = WindowProc;
 	wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
 	wc.hIcon = 0;
@@ -60,7 +67,10 @@
 	wc.cbWndExtra = 0;
 
 	// 注册自定义类
-	return (::RegisterClass(&wc) != 0);
+	if (::RegisterClass(&wc) != 0) {
+		return TRUE;
+	}
+	return (::GetLastError() == ERROR_CLASS_ALREADY_EXISTS);
 }
 
 CAccordionWnd * CAccordionWnd::FromHandle(HWND hWnd)
diff --git a/SourceCode/Bond/Servo/AccordionWnd.cpp b/SourceCode/Bond/Servo/AccordionWnd.cpp
new file mode 100644
index 0000000..83af762
--- /dev/null
+++ b/SourceCode/Bond/Servo/AccordionWnd.cpp
@@ -0,0 +1,787 @@
+#include "stdafx.h"
+#include "AccordionWnd.h"
+
+
+#define ITEM_HEIGHT				32
+#define ITEM_SPACE				5
+#define TIMER_ID_CHECKHOVER		1
+#define EXPAND_ICON_WIDE		16
+
+#define BORDER			5
+#define SHADOWWIDE		5
+
+CAccordionWnd::CAccordionWnd()
+{
+	m_hWnd = NULL;
+	m_crFrame = GetSysColor(COLOR_WINDOWFRAME);
+	m_crBkgnd = RGB(255, 255, 255);//GetSysColor(COLOR_BTNFACE); ;
+	m_nPadding[PADDING_LEFT] = 5;
+	m_nPadding[PADDING_TOP] = 5;
+	m_nPadding[PADDING_RIGHT] = 5;
+	m_nPadding[PADDING_BOTTOM] = 5;
+	m_crItemBackground[0] = RGB(218, 218, 218);
+	m_crItemBackground[1] = RGB(34, 177, 76);
+	m_crItemFrame[0] = RGB(128, 128, 128);
+	m_crItemFrame[1] = RGB(128, 128, 128);
+	m_crItemText[0] = RGB(68, 84, 111);
+	m_crItemText[1] = RGB(0, 0, 0);
+	m_crSeparateLine = RGB(222, 222, 222);
+	m_crHoverItemBackground = RGB(244, 245, 247);
+	m_crHoverItemFrame = RGB(200, 222, 255);
+	m_hIconExpand = NULL;
+	m_hIconClose = NULL;
+	m_nHoverItem = -1;
+	m_nCheckHoverItem = -1;
+	m_bShadow = FALSE;
+	m_crShadowBkgnd = GetSysColor(COLOR_BTNFACE);
+}
+
+
+CAccordionWnd::~CAccordionWnd()
+{
+	for (size_t i = 0; i < m_vectorItems.size(); i++) {
+		delete m_vectorItems[i];
+	}
+	m_vectorItems.clear();
+}
+
+BOOL CAccordionWnd::RegisterWndClass()
+{
+	WNDCLASS wcExisting = {};
+	HINSTANCE hInstance = AfxGetInstanceHandle();
+	if (::GetClassInfo(hInstance, ACCORDIONWND_CLASS, &wcExisting) ||
+		::GetClassInfo(NULL, ACCORDIONWND_CLASS, &wcExisting)) {
+		return TRUE;
+	}
+
+	WNDCLASS wc = {};
+	wc.lpszClassName = ACCORDIONWND_CLASS;
+	wc.hInstance = hInstance;
+	wc.lpfnWndProc = WindowProc;
+	wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
+	wc.hIcon = 0;
+	wc.lpszMenuName = NULL;
+	wc.hbrBackground = NULL;
+	wc.style = CS_GLOBALCLASS | CS_DBLCLKS;
+	wc.cbClsExtra = 0;
+	wc.cbWndExtra = 0;
+
+	// 注册自定义类
+	if (::RegisterClass(&wc) != 0) {
+		return TRUE;
+	}
+	return (::GetLastError() == ERROR_CLASS_ALREADY_EXISTS);
+}
+
+CAccordionWnd* CAccordionWnd::FromHandle(HWND hWnd)
+{
+	CAccordionWnd* pAccordionWnd = (CAccordionWnd*)::GetProp(hWnd, ACCORDIONWND_TAG);
+	return pAccordionWnd;
+}
+
+CAccordionWnd* CAccordionWnd::Hook(HWND hWnd)
+{
+	CAccordionWnd* pAccordionWnd = (CAccordionWnd*)GetProp(hWnd, ACCORDIONWND_TAG);
+	if (pAccordionWnd == NULL) {
+		pAccordionWnd = new CAccordionWnd();
+		pAccordionWnd->m_hWnd = hWnd;
+
+		SetProp(hWnd, ACCORDIONWND_TAG, (HANDLE)pAccordionWnd);
+	}
+
+
+	return pAccordionWnd;
+}
+
+void CAccordionWnd::LoadExpandIcon(CString strExpandFile, CString strCloseFile)
+{
+	m_hIconExpand = (HICON)::LoadImage(AfxGetInstanceHandle(), strExpandFile, IMAGE_ICON, EXPAND_ICON_WIDE, EXPAND_ICON_WIDE,
+		LR_LOADFROMFILE | LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
+	m_hIconClose = (HICON)::LoadImage(AfxGetInstanceHandle(), strCloseFile, IMAGE_ICON, EXPAND_ICON_WIDE, EXPAND_ICON_WIDE,
+		LR_LOADFROMFILE | LR_DEFAULTCOLOR | LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
+}
+
+void CAccordionWnd::Setpadding(int type, unsigned int nPadding)
+{
+	if (type >= PADDING_LEFT && PADDING_LEFT <= PADDING_BOTTOM) {
+		m_nPadding[type] = nPadding;
+	}
+}
+
+void CAccordionWnd::SetDefaultItemBackgroundColor(COLORREF crNormal, COLORREF crSel)
+{
+	m_crItemBackground[0] = crNormal;
+	m_crItemBackground[1] = crSel;
+}
+
+void CAccordionWnd::SetDefaultItemFrameColor(COLORREF crNormal, COLORREF crSel)
+{
+	m_crItemFrame[0] = crNormal;
+	m_crItemFrame[1] = crSel;
+}
+
+void CAccordionWnd::SetDefaultItemTextColor(COLORREF crNormal, COLORREF crSel)
+{
+	m_crItemText[0] = crNormal;
+	m_crItemText[1] = crSel;
+}
+
+void CAccordionWnd::Init()
+{
+}
+
+void CAccordionWnd::Release()
+{
+	// delete
+	delete this;
+}
+
+/*
+ * 添加项目
+ * pszName -- 名称
+ * pWnd -- 绑定的窗口
+ * nExpandHeight -- 展开高度,如果为0则自动设置为窗口高
+ */
+void CAccordionWnd::AddItem(char* pszName, CWnd* pWnd, int nExpandHeight, BOOL bExpand/* = TRUE*/, BOOL bEnable/* = TRUE*/)
+{
+	ACCORDIONITEM* pItem = new ACCORDIONITEM;
+	memset(pItem, 0, sizeof(ACCORDIONITEM));
+	pItem->pWnd = pWnd;
+	pItem->bExpand = bExpand;
+	pItem->bEnable = bEnable;
+	strcpy_s(pItem->text, sizeof(pItem->text), pszName);
+	if (nExpandHeight == 0) {
+		RECT rect;
+		pWnd->GetWindowRect(&rect);
+		pItem->nExpandHeight = rect.bottom - rect.top;
+	}
+	else if (nExpandHeight == -1) {
+		pItem->nExpandHeight = -1;
+	}
+	else {
+		pItem->nExpandHeight = nExpandHeight;
+	}
+	m_vectorItems.push_back(pItem);
+
+
+	// 重新调整个子窗口的位置
+	ResizeItemWnd();
+}
+
+void CAccordionWnd::ResizeItemWnd()
+{
+	RECT rcClient, rcItemClient;
+	GetClientRect(m_hWnd, &rcClient);
+
+	for (size_t i = 0; i < m_vectorItems.size(); i++) {
+		ACCORDIONITEM* pItem = m_vectorItems.at(i);
+		if (pItem->pWnd != NULL) {
+			GetItemRect(rcClient, (UINT)i, &rcItemClient);
+			rcItemClient.top += ITEM_HEIGHT;
+			if (pItem->nExpandHeight == -1) {
+				rcItemClient.bottom = rcClient.bottom;
+			}
+			else {
+				rcItemClient.bottom = rcItemClient.top + pItem->nExpandHeight;
+			}
+
+			pItem->pWnd->MoveWindow(&rcItemClient);
+			pItem->pWnd->ShowWindow(pItem->bExpand ? SW_SHOW : SW_HIDE);
+		}
+	}
+}
+
+BOOL CAccordionWnd::GetItemHeaderRect(RECT rcClient, unsigned int nIndex, LPRECT lpRect)
+{
+	RECT rcItem;
+	if (!GetItemRect(rcClient, nIndex, &rcItem)) {
+		return FALSE;
+	}
+
+	rcItem.bottom = rcItem.top + ITEM_HEIGHT;
+	CopyRect(lpRect, &rcItem);
+	return TRUE;
+}
+
+BOOL CAccordionWnd::GetItemRect(RECT rcClient, unsigned int nIndex, LPRECT lpRect)
+{
+	if (nIndex >= m_vectorItems.size()) {
+		return FALSE;
+	}
+
+	RECT rcItemHeader;
+	rcItemHeader.left = rcClient.left + m_nPadding[PADDING_LEFT];
+	rcItemHeader.right = rcClient.right - m_nPadding[PADDING_RIGHT];
+	rcItemHeader.top = rcClient.top + m_nPadding[PADDING_TOP];
+	rcItemHeader.bottom = rcItemHeader.top + ITEM_HEIGHT;
+	for (size_t i = 0; i < m_vectorItems.size(); i++) {
+		ACCORDIONITEM* pItem = m_vectorItems.at(i);
+		if (pItem->bExpand) {
+			rcItemHeader.bottom += pItem->nExpandHeight;
+		}
+
+		if (i == nIndex) {
+			break;;
+		}
+
+		rcItemHeader.top = rcItemHeader.bottom + ITEM_SPACE;
+		rcItemHeader.bottom = rcItemHeader.top + ITEM_HEIGHT;
+	}
+
+
+	CopyRect(lpRect, &rcItemHeader);
+	return TRUE;
+}
+
+int CAccordionWnd::HitTest(POINT pt, int& nHitTest)
+{
+	int nRet = -1;
+	nHitTest = -1;
+	RECT rcClient;
+	GetClientRect(m_hWnd, &rcClient);
+	if (PtInRect(&rcClient, pt)) {
+		nRet = 1;
+	}
+
+	int nItemIndex = -1;
+	RECT rcItemHeader;
+	for (size_t i = 0; i < m_vectorItems.size(); i++) {
+		GetItemHeaderRect(rcClient, (unsigned int)i, &rcItemHeader);
+
+		if (PtInRect(&rcItemHeader, pt)) {
+			nItemIndex = (unsigned int)i;
+
+			break;
+		}
+	}
+
+	if (nItemIndex != -1) {
+		nRet = 2;
+		nHitTest = nItemIndex;
+	}
+
+	return nRet;
+}
+
+BOOL CAccordionWnd::Togle(unsigned int nIndex)
+{
+	if (nIndex >= m_vectorItems.size()) {
+		return FALSE;
+	}
+
+	ACCORDIONITEM* pItem = m_vectorItems[nIndex];
+	pItem->bExpand = !pItem->bExpand;
+
+
+	// 重新调整个子窗口的位置
+	ResizeItemWnd();
+
+	RECT rcClient;
+	GetClientRect(m_hWnd, &rcClient);
+	::InvalidateRect(m_hWnd, &rcClient, TRUE);
+
+	return TRUE;
+}
+
+void CAccordionWnd::Notify(int nCode, int dwData, int dwData1/* = 0*/, int dwData2/* = 0*/)
+{
+	HWND hParent;
+	hParent = GetParent(m_hWnd);
+	if (hParent != NULL) {
+		ACCORDION_NMHDR accordionWndnmhdr;
+		accordionWndnmhdr.nmhdr.hwndFrom = m_hWnd;
+		accordionWndnmhdr.nmhdr.idFrom = GetWindowLong(m_hWnd, GWL_ID);
+		accordionWndnmhdr.nmhdr.code = nCode;
+		accordionWndnmhdr.dwData = dwData;
+		accordionWndnmhdr.dwData1 = dwData1;
+		accordionWndnmhdr.dwData2 = dwData2;
+		SendMessage(hParent, WM_NOTIFY, (WPARAM)accordionWndnmhdr.nmhdr.idFrom, (LPARAM)&accordionWndnmhdr);
+	}
+}
+
+/*
+ * 拦截窗口消息函数
+ */
+LRESULT CALLBACK CAccordionWnd::WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+	CAccordionWnd* pAccordionWnd = (CAccordionWnd*)GetProp(hWnd, ACCORDIONWND_TAG);
+	if (pAccordionWnd == NULL && uMsg != WM_NCCREATE)
+	{
+		return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
+	}
+
+
+	// 如果Hook则响应消息
+	ASSERT(hWnd);
+	switch (uMsg)
+	{
+	case WM_NCCREATE:
+		return CAccordionWnd::OnNcCreate(hWnd, wParam, lParam);
+
+	case WM_DESTROY:
+		return pAccordionWnd->OnDestroy(wParam, lParam);
+
+	case WM_NCCALCSIZE:
+		return pAccordionWnd->OnNcCalcsize(wParam, lParam);
+
+	case WM_NCPAINT:
+		return pAccordionWnd->OnNcPaint(wParam, lParam);
+
+	case WM_PAINT:
+		return pAccordionWnd->OnPaint(wParam, lParam);
+
+	case WM_TIMER:
+		return pAccordionWnd->OnTimer(wParam, lParam);
+
+	case WM_MOUSEMOVE:
+		return pAccordionWnd->OnMouseMove(wParam, lParam);
+
+	case WM_LBUTTONDOWN:
+		return pAccordionWnd->OnLButtonDown(wParam, lParam);
+
+	case WM_LBUTTONUP:
+		return pAccordionWnd->OnLButtonUp(wParam, lParam);
+
+	case WM_MOUSEWHEEL:
+		return pAccordionWnd->OnMouseWheel(wParam, lParam);
+
+	case WM_SIZE:
+		return pAccordionWnd->OnSize(wParam, lParam);
+
+	case WM_GETDLGCODE:
+		return DLGC_WANTALLKEYS;
+
+	default:
+		break;
+	}
+
+	return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
+}
+
+/*
+ * WM_NCCREATE
+ * 窗口创建前的初始化工作
+ */
+LRESULT CAccordionWnd::OnNcCreate(HWND hWnd, WPARAM wParam, LPARAM lParam)
+{
+	CAccordionWnd* pAccordionWnd = (CAccordionWnd*)GetProp(hWnd, ACCORDIONWND_TAG);
+	ASSERT(pAccordionWnd == NULL);
+
+	Hook(hWnd);
+	return ::DefWindowProc(hWnd, WM_NCCREATE, wParam, lParam);
+}
+
+/*
+ * WM_NCCALCSIZE
+ */
+LRESULT CAccordionWnd::OnNcCalcsize(WPARAM wParam, LPARAM lParam)
+{
+	if (!m_bShadow) {
+		return ::DefWindowProc(m_hWnd, WM_NCCALCSIZE, wParam, lParam);
+	}
+
+
+	LPRECT lprcWnd = (LPRECT)lParam;
+	lprcWnd->left += BORDER;
+	lprcWnd->top += BORDER;
+	lprcWnd->right -= (BORDER + SHADOWWIDE);
+	lprcWnd->bottom -= (BORDER + SHADOWWIDE);
+
+	return 0;
+}
+
+/*
+ * WM_DESTROY
+ * 窗口销毁时
+ */
+LRESULT CAccordionWnd::OnDestroy(WPARAM wParam, LPARAM lParam)
+{
+	Release();
+	return ::DefWindowProc(m_hWnd, WM_DESTROY, wParam, lParam);
+}
+
+
+/*
+ * WM_TIMER
+ */
+LRESULT CAccordionWnd::OnTimer(WPARAM wParam, LPARAM lParam)
+{
+	int nTimerId = (int)wParam;
+	if (m_nTimerId == nTimerId) {
+
+		POINT pt;
+		::GetCursorPos(&pt);
+		::ScreenToClient(m_hWnd, &pt);
+
+		int nRet, nHitTest;
+		nRet = HitTest(pt, nHitTest);
+		if (m_nCheckHoverItem != nHitTest) {
+			KillTimer(m_hWnd, m_nTimerId);
+			m_nHoverItem = nHitTest;
+			m_nCheckHoverItem = nHitTest;
+
+			RECT rcClient;
+			GetClientRect(m_hWnd, &rcClient);
+			::InvalidateRect(m_hWnd, &rcClient, TRUE);
+		}
+	}
+
+
+	return ::DefWindowProc(m_hWnd, WM_TIMER, wParam, lParam);
+}
+
+/*
+ * WM_MOUSEMOVE
+ * 鼠标移动时,检测鼠标位置并回调给主窗口
+ */
+LRESULT CAccordionWnd::OnMouseMove(WPARAM wParam, LPARAM lParam)
+{
+	POINT pt;
+	pt.x = (int)LOWORD(lParam);
+	pt.y = (int)HIWORD(lParam);
+
+	int nRet, nHitTest;
+	nRet = HitTest(pt, nHitTest);
+
+	if (nRet == 2) {
+		ACCORDIONITEM* pItem = m_vectorItems[nHitTest];
+		if (pItem != NULL && pItem->bEnable) {
+			::SetCursor(LoadCursor(NULL, IDC_HAND));
+		}
+	}
+	else {
+		::SetCursor(LoadCursor(NULL, IDC_ARROW));
+	}
+
+	int nLastItem = m_nHoverItem;
+	if (m_nHoverItem != nHitTest) {
+		m_nHoverItem = nHitTest;
+
+		RECT rcClient, rcLastItemClient, rcCurItemClient;
+		GetClientRect(m_hWnd, &rcClient);
+		GetItemRect(rcClient, nLastItem, &rcLastItemClient);
+		::InvalidateRect(m_hWnd, &rcLastItemClient, nHitTest < 0);
+
+		if (nHitTest >= 0) {
+			ACCORDIONITEM* pItem = m_vectorItems.at(nHitTest);
+			if (!pItem->bEnable) {
+				m_nHoverItem = -1;
+			}
+			else {
+				KillTimer(m_hWnd, m_nTimerId);
+				m_nTimerId = SetTimer(m_hWnd, TIMER_ID_CHECKHOVER, 200, NULL);
+				m_nCheckHoverItem = m_nHoverItem;
+
+				GetItemRect(rcClient, m_nHoverItem, &rcCurItemClient);
+				::InvalidateRect(m_hWnd, &rcCurItemClient, TRUE);
+			}
+		}
+	}
+
+
+	return ::DefWindowProc(m_hWnd, WM_MOUSEMOVE, wParam, lParam);
+}
+
+/*
+ * WM_LBUTTONDOWN
+ * 鼠标左键下压
+ */
+LRESULT CAccordionWnd::OnLButtonDown(WPARAM wParam, LPARAM lParam)
+{
+	POINT pt;
+	pt.x = (int)LOWORD(lParam);
+	pt.y = (int)HIWORD(lParam);
+
+	int nRet, nHitTest;
+	nRet = HitTest(pt, nHitTest);
+
+	if (nRet == 2) {
+		ACCORDIONITEM* pItem = m_vectorItems[nHitTest];
+		if (pItem != NULL && pItem->bEnable) {
+			::SetCursor(LoadCursor(NULL, IDC_HAND));
+		}
+	}
+	else {
+		::SetCursor(LoadCursor(NULL, IDC_ARROW));
+	}
+
+
+	return ::DefWindowProc(m_hWnd, WM_LBUTTONDOWN, wParam, lParam);
+}
+
+/*
+ * WM_LBUTTONUP
+ * 鼠标左键释放
+ */
+LRESULT CAccordionWnd::OnLButtonUp(WPARAM wParam, LPARAM lParam)
+{
+	POINT pt;
+	pt.x = (int)LOWORD(lParam);
+	pt.y = (int)HIWORD(lParam);
+
+	int nRet, nHitTest;
+	nRet = HitTest(pt, nHitTest);
+
+	if (nRet == 2) {
+		ACCORDIONITEM* pItem = m_vectorItems[nHitTest];
+		if (pItem != NULL && pItem->bEnable) {
+			::SetCursor(LoadCursor(NULL, IDC_HAND));
+			Togle(nHitTest);
+		}
+	}
+	else {
+		::SetCursor(LoadCursor(NULL, IDC_ARROW));
+	}
+
+
+	return ::DefWindowProc(m_hWnd, WM_LBUTTONUP, wParam, lParam);
+}
+
+/*
+ * WM_MOUSEWHEEL
+ * 鼠标滚轮滚动时,缩放图像
+ */
+LRESULT CAccordionWnd::OnMouseWheel(WPARAM wParam, LPARAM lParam)
+{
+	return ::DefWindowProc(m_hWnd, WM_MOUSEWHEEL, wParam, lParam);
+}
+
+/*
+ * WM_NCPAINT
+ */
+LRESULT CAccordionWnd::OnNcPaint(WPARAM wParam, LPARAM lParam)
+{
+	LRESULT lRet = ::DefWindowProc(m_hWnd, WM_NCPAINT, wParam, lParam);
+
+
+	// 然后画边框
+	long styleEx = GetWindowLong(m_hWnd, GWL_EXSTYLE);
+	if ((styleEx & WS_EX_CLIENTEDGE) == WS_EX_CLIENTEDGE) {
+
+		RECT rcWindow, rcClient;
+		GetClientRect(m_hWnd, &rcClient);
+		::ClientToScreen(m_hWnd, (LPPOINT)&rcClient.left);
+		::ClientToScreen(m_hWnd, (LPPOINT)&rcClient.right);
+		GetWindowRect(m_hWnd, &rcWindow);
+		::OffsetRect(&rcClient, -rcWindow.left, -rcWindow.top);
+		::OffsetRect(&rcWindow, -rcWindow.left, -rcWindow.top);
+
+		HRGN hRgnWnd = CreateRectRgnIndirect(&rcWindow);
+		HRGN hRgnClient = CreateRectRgnIndirect(&rcClient);
+
+		HDC hDC = GetWindowDC(m_hWnd);
+		::SelectClipRgn(hDC, hRgnWnd);
+		::ExtSelectClipRgn(hDC, hRgnClient, RGN_DIFF);
+
+
+		// 没有阴影的边框
+		if (!m_bShadow) {
+			HBRUSH hBrushBK, hBrushFrame;
+			hBrushBK = CreateSolidBrush(m_crBkgnd);
+			::FillRect(hDC, &rcWindow, hBrushBK);
+			DeleteObject(hBrushBK);
+
+			hBrushFrame = CreateSolidBrush(m_crFrame);
+			::FrameRect(hDC, &rcWindow, hBrushFrame);
+			DeleteObject(hBrushFrame);
+		}
+
+		// 有阴影的边框
+		else {
+
+			RECT rcFrame0, rcFrame1;
+			rcFrame0.left = rcWindow.left + SHADOWWIDE;
+			rcFrame0.top = rcWindow.top + SHADOWWIDE;
+			rcFrame0.right = rcWindow.right;
+			rcFrame0.bottom = rcWindow.bottom;
+			rcFrame1.left = rcWindow.left;
+			rcFrame1.top = rcWindow.top;
+			rcFrame1.right = rcWindow.right - SHADOWWIDE;
+			rcFrame1.bottom = rcWindow.bottom - SHADOWWIDE;
+
+
+			// 背景框和对话框(父窗体)背景色一致
+			HBRUSH hBrushBK, hBrushFrame;
+			hBrushBK = CreateSolidBrush(m_crShadowBkgnd);
+			::FillRect(hDC, &rcWindow, hBrushBK);
+			DeleteObject(hBrushBK);
+
+
+			// 阴影框
+			BYTE r = GetRValue(m_crShadowBkgnd);
+			BYTE g = GetGValue(m_crShadowBkgnd);
+			BYTE b = GetBValue(m_crShadowBkgnd);
+			BYTE rstep = (r - GetRValue(m_crFrame)) / SHADOWWIDE;
+			BYTE gstep = (r - GetGValue(m_crFrame)) / SHADOWWIDE;
+			BYTE bstep = (r - GetBValue(m_crFrame)) / SHADOWWIDE;
+
+			for (int i = 0; i < SHADOWWIDE; i++) {
+				hBrushBK = CreateSolidBrush(RGB(r - i * rstep, g - i * gstep, b - i * bstep));
+				::FillRect(hDC, &rcFrame0, hBrushBK);
+				DeleteObject(hBrushBK);
+				rcFrame0.bottom -= 1;
+				rcFrame0.right -= 1;
+			}
+
+
+			// 前景框
+			hBrushBK = CreateSolidBrush(m_crBkgnd);
+			::FillRect(hDC, &rcFrame1, hBrushBK);
+			DeleteObject(hBrushBK);
+
+			hBrushFrame = CreateSolidBrush(m_crFrame);
+			::FrameRect(hDC, &rcFrame1, hBrushFrame);
+			DeleteObject(hBrushFrame);
+		}
+
+
+		::DeleteObject(hRgnWnd);
+		::DeleteObject(hRgnClient);
+		ReleaseDC(m_hWnd, hDC);
+	}
+
+	return lRet;
+}
+
+/*
+ * WM_PAINT
+ */
+LRESULT CAccordionWnd::OnPaint(WPARAM wParam, LPARAM lParam)
+{
+	HDC hDC, hMemDC;
+	HBITMAP hBitmap;
+	RECT rcClient;
+	CString strText;
+	HFONT hFont;
+	HBRUSH hBrushBK;
+
+
+	// BeginPaint
+	PAINTSTRUCT ps;
+	hDC = BeginPaint(m_hWnd, &ps);
+	GetClientRect(m_hWnd, &rcClient);
+
+	hMemDC = ::CreateCompatibleDC(hDC);
+	hBitmap = ::CreateCompatibleBitmap(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);
+
+
+	// 绘子项列表
+	hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
+	::SelectObject(hMemDC, hFont);
+
+	HPEN hPenSeparate = ::CreatePen(PS_SOLID, 1, m_crSeparateLine);
+	RECT rcItem, rcItemHeader;
+	for (size_t i = 0; i < m_vectorItems.size(); i++) {
+		ACCORDIONITEM* pItem = m_vectorItems[i];
+		GetItemRect(rcClient, (UINT)i, &rcItem);
+		GetItemHeaderRect(rcClient, (UINT)i, &rcItemHeader);
+
+
+		// 热点项的背景色和边框
+		if (m_nHoverItem == (int)i) {
+			HBRUSH hbrItemHeaderBackground = CreateSolidBrush(m_crHoverItemBackground);
+			HBRUSH hbrItemFrame = CreateSolidBrush(m_crHoverItemFrame);
+
+			HRGN hRgn = CreateRoundRectRgn(rcItemHeader.left, rcItemHeader.top, rcItemHeader.right, rcItemHeader.bottom, 2, 2);
+			::FillRgn(hMemDC, hRgn, hbrItemHeaderBackground);
+			::FrameRgn(hMemDC, hRgn, hbrItemFrame, 1, 1);
+			::DeleteObject(hbrItemHeaderBackground);
+			::DeleteObject(hbrItemFrame);
+			::DeleteObject(hRgn);
+		}
+
+
+		// 箭头
+		BOOL bDrawIcon = DrawIconEx(hMemDC, rcItemHeader.left + (ITEM_HEIGHT - EXPAND_ICON_WIDE) / 2, rcItemHeader.top + (ITEM_HEIGHT - EXPAND_ICON_WIDE) / 2,
+			pItem->bExpand ? m_hIconExpand : m_hIconClose, EXPAND_ICON_WIDE, EXPAND_ICON_WIDE, 0, 0, DI_NORMAL);
+
+
+		// 文本
+		::SetTextColor(hMemDC, m_nHoverItem == (int)i ? m_crItemText[1] : m_crItemText[0]);
+		RECT rcText;
+		rcText.left = rcItemHeader.left + (bDrawIcon ? ITEM_HEIGHT : (ITEM_HEIGHT - EXPAND_ICON_WIDE) / 2);
+		rcText.top = rcItemHeader.top;
+		rcText.right = rcItemHeader.right;
+		rcText.bottom = rcItemHeader.bottom;
+		::DrawText(hMemDC, pItem->text, (int)strlen(pItem->text), &rcText, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
+
+
+		// 文本右边分隔线
+		SIZE sizeText;
+		GetTextExtentPoint32(hMemDC, pItem->text, (int)strlen(pItem->text), &sizeText);
+
+
+		HPEN hOldPen = (HPEN)::SelectObject(hMemDC, hPenSeparate);
+		MoveToEx(hMemDC, rcText.left + sizeText.cx + 10, rcItemHeader.top + (rcItemHeader.bottom - rcItemHeader.top - 1) / 2, NULL);
+		LineTo(hMemDC, rcItemHeader.right - 10, rcItemHeader.top + (rcItemHeader.bottom - rcItemHeader.top - 1) / 2);
+		::SelectObject(hMemDC, hOldPen);
+
+
+		rcItemHeader.top = rcItemHeader.bottom + ITEM_SPACE;
+		rcItemHeader.bottom = rcItemHeader.top + ITEM_HEIGHT;
+	}
+	::DeleteObject(hPenSeparate);
+
+
+	// EndPaint
+	::BitBlt(hDC, 0, 0, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top,
+		hMemDC, 0, 0, SRCCOPY);
+	EndPaint(m_hWnd, &ps);
+	::DeleteObject(hBitmap);
+	::DeleteDC(hMemDC);
+
+
+	return 1;
+}
+
+/*
+ * WM_SIZE
+ */
+LRESULT CAccordionWnd::OnSize(WPARAM wParam, LPARAM lParam)
+{
+	LRESULT lRet = ::DefWindowProc(m_hWnd, WM_SIZE, wParam, lParam);
+
+	ResizeItemWnd();
+
+	return lRet;
+}
+
+/*
+ * 设置背景色
+ * color -- 背景色
+ */
+void CAccordionWnd::SetBkgndColor(COLORREF color)
+{
+	m_crBkgnd = color;
+}
+
+
+/*
+ * 设置阴影的背景色(即父窗口的背景)
+ * color -- 背景色
+ */
+void CAccordionWnd::SetShadowBkgnd(COLORREF color)
+{
+	m_crShadowBkgnd = color;
+}
+
+/*
+ * 设置边框颜色
+ * color -- 边框颜色
+ */
+void CAccordionWnd::SetFrameColor(COLORREF color, BOOL bShadow/* = FALSE*/)
+{
+	m_crFrame = color;
+	m_bShadow = bShadow;
+	SetWindowPos(m_hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
+}
+
diff --git a/SourceCode/Bond/Servo/AccordionWnd.h b/SourceCode/Bond/Servo/AccordionWnd.h
new file mode 100644
index 0000000..46fa7a1
--- /dev/null
+++ b/SourceCode/Bond/Servo/AccordionWnd.h
@@ -0,0 +1,131 @@
+#pragma once
+#include <functional>
+#include <vector>
+
+#ifndef ACCORDIONWND_TAG
+
+#ifdef _WIN32
+
+#define ACCORDIONWND_CLASSA		"AccordionWnd"
+#define ACCORDIONWND_CLASSW		L"AccordionWnd"
+
+#ifdef UNICODE
+#define ACCORDIONWND_CLASS		ACCORDIONWND_CLASSW
+#else
+#define ACCORDIONWND_CLASS		ACCORDIONWND_CLASSA
+#endif
+
+#else
+#define ACCORDIONWND_CLASS      "AccordionWnd"
+#endif
+
+
+#define ACCORDIONWND_TAG		_T("ACCORDIONWND_TAG")
+
+#define ACCORDIONWND_FIRST		(0U-3590U)
+#define ACCORDIONWND_LAST		(0U-5350U)
+#define ACCORDIONWND_ONTOGLE	(ACCORDIONWND_FIRST - 1)
+
+typedef struct tagACCORDION_NMHDR
+{
+	NMHDR		nmhdr;
+	DWORD		dwData;
+	DWORD		dwData1;
+	DWORD		dwData2;
+} ACCORDION_NMHDR;
+
+typedef struct tagACCORDIONITEM
+{
+	unsigned int id;
+	int nExpandHeight;
+	COLORREF crBackground[2];
+	COLORREF crFrame[2];
+	COLORREF crText[2];
+	char text[256];
+	CWnd *pWnd;
+	BOOL bExpand;
+	BOOL bEnable;				// 是否可以点击展开和收起
+} ACCORDIONITEM;
+
+#endif
+
+#define PADDING_LEFT		0
+#define PADDING_TOP			1
+#define PADDING_RIGHT		2
+#define PADDING_BOTTOM		3
+
+class CAccordionWnd
+{
+public:
+	CAccordionWnd();
+	~CAccordionWnd();
+
+
+public:
+	static BOOL RegisterWndClass();
+	static CAccordionWnd * FromHandle(HWND hWnd);
+	void SetFrameColor(COLORREF color, BOOL bShadow = FALSE);
+	void SetBkgndColor(COLORREF color);
+	void SetShadowBkgnd(COLORREF color);
+
+public:
+	void LoadExpandIcon(CString strExpandFile, CString strCloseFile);
+	void Setpadding(int type, unsigned int nPadding);
+	void SetDefaultItemBackgroundColor(COLORREF crNormal, COLORREF crSel);
+	void SetDefaultItemFrameColor(COLORREF crNormal, COLORREF crSel);
+	void SetDefaultItemTextColor(COLORREF crNormal, COLORREF crSel);
+	void AddItem(char *pszName, CWnd *pWnd, int nExpandHeight, BOOL bExpand = TRUE, BOOL bEnable = TRUE);
+	BOOL Togle(unsigned int nIndex);
+	int GetItemHeaderHeight();
+	BOOL IsExpand(unsigned int nIndex);
+
+private:
+	void Init();
+	void Notify(int nCode, int dwData, int dwData1 = 0, int dwData2 = 0);
+	void Release();
+	void ResizeItemWnd();
+	static CAccordionWnd* Hook(HWND hWnd);
+	static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+	static LRESULT OnNcCreate(HWND hWnd, WPARAM wParam, LPARAM lParam);
+	LRESULT OnDestroy(WPARAM wParam, LPARAM lParam);
+	LRESULT OnTimer(WPARAM wParam, LPARAM lParam);
+	LRESULT OnNcPaint(WPARAM wParam, LPARAM lParam);
+	LRESULT OnNcCalcsize(WPARAM wParam, LPARAM lParam);
+	LRESULT OnPaint(WPARAM wParam, LPARAM lParam);
+	LRESULT OnMouseMove(WPARAM wParam, LPARAM lParam);
+	LRESULT OnLButtonDown(WPARAM wParam, LPARAM lParam);
+	LRESULT OnLButtonUp(WPARAM wParam, LPARAM lParam);
+	LRESULT OnMouseWheel(WPARAM wParam, LPARAM lParam);
+	LRESULT OnSize(WPARAM wParam, LPARAM lParam);
+
+private:
+	HWND		m_hWnd;
+	COLORREF	m_crBkgnd;
+	COLORREF	m_crFrame;
+	HICON		m_hIconClose;
+	HICON		m_hIconExpand;
+	int			m_nHoverItem;
+	int			m_nCheckHoverItem;
+	BOOL		m_bShadow;				// 阴影
+	COLORREF	m_crShadowBkgnd;		// 阴影背景色(即父窗口的颜色)
+
+private:
+	unsigned int m_nPadding[4];
+	COLORREF m_crItemBackground[2];
+	COLORREF m_crItemFrame[2];
+	COLORREF m_crItemText[2];
+	COLORREF m_crSeparateLine;
+	COLORREF m_crHoverItemBackground;
+	COLORREF m_crHoverItemFrame;
+	CString m_strExpandIconFilepath[2];
+
+private:
+	std::vector<ACCORDIONITEM *> m_vectorItems;
+	int m_nTimerId;
+
+private:
+	int HitTest(POINT pt, int &nHitTest);
+	BOOL GetItemHeaderRect(RECT rcClient, unsigned int nIndex, LPRECT lpRect);
+	BOOL GetItemRect(RECT rcClient, unsigned int nIndex, LPRECT lpRect);
+};
+
diff --git a/SourceCode/Bond/Servo/CPageProdOverview.cpp b/SourceCode/Bond/Servo/CPageProdOverview.cpp
new file mode 100644
index 0000000..6ca851e
--- /dev/null
+++ b/SourceCode/Bond/Servo/CPageProdOverview.cpp
@@ -0,0 +1,140 @@
+锘�// CPageProOverview.cpp: 瀹炵幇鏂囦欢
+//
+
+#include "stdafx.h"
+#include "Servo.h"
+#include "CPageProdOverview.h"
+#include "afxdialogex.h"
+
+namespace
+{
+	constexpr UINT_PTR kTimerRefreshId = 2001;
+	constexpr UINT kTimerRefreshIntervalMs = 5000;
+}
+
+IMPLEMENT_DYNAMIC(CPageProdOverview, CDialogEx)
+
+CPageProdOverview::CPageProdOverview(CWnd* pParent /*=nullptr*/)
+	: CDialogEx(IDD_PROD_OVERVIEW, pParent)
+	, m_clrBackground(RGB(240, 240, 240))
+{
+}
+
+CPageProdOverview::~CPageProdOverview()
+{
+}
+
+void CPageProdOverview::DoDataExchange(CDataExchange* pDX)
+{
+	CDialogEx::DoDataExchange(pDX);
+}
+
+void CPageProdOverview::SetBackgroundColor(COLORREF color)
+{
+	m_clrBackground = color;
+	m_brushBackground.DeleteObject();
+	m_brushBackground.CreateSolidBrush(m_clrBackground);
+	if (::IsWindow(m_hWnd)) {
+		Invalidate();
+	}
+}
+
+BEGIN_MESSAGE_MAP(CPageProdOverview, CDialogEx)
+	ON_WM_CTLCOLOR()
+	ON_WM_DESTROY()
+	ON_WM_SIZE()
+	ON_WM_TIMER()
+END_MESSAGE_MAP()
+
+BOOL CPageProdOverview::OnInitDialog()
+{
+	CDialogEx::OnInitDialog();
+
+
+	// 浣跨敤鑷畾涔夋爣绛�
+	if (CWnd* pDay = GetDlgItem(IDC_PROD_DAY_OUTPUT)) {
+		m_labelDayOut.SubclassWindow(pDay->GetSafeHwnd());
+		m_labelDayOut.setFontSize(28);
+		m_labelDayOut.setNoteTextColor(RGB(128, 128, 128));
+		m_labelDayOut.setNote1(_T("鐧界彮浜у嚭"));
+		m_labelDayOut.setBackground(m_clrBackground);
+		m_labelDayOut.setForeground(RGB(18, 18, 18), TRUE);
+	}
+	if (CWnd* pNight = GetDlgItem(IDC_PROD_NIGHT_OUTPUT)) {
+		m_labelNightOut.SubclassWindow(pNight->GetSafeHwnd());
+		m_labelNightOut.setFontSize(28);
+		m_labelNightOut.setNoteTextColor(RGB(128, 128, 128));
+		m_labelNightOut.setNote1(_T("澶滅彮浜у嚭"));
+		m_labelNightOut.setBackground(m_clrBackground);
+		m_labelNightOut.setForeground(RGB(18, 18, 18), TRUE);
+	}
+	if (CWnd* pDayTakt = GetDlgItem(IDC_PROD_DAY_TAKT)) {
+		m_labelDayTakt.SubclassWindow(pDayTakt->GetSafeHwnd());
+		m_labelDayTakt.setFontSize(28);
+		m_labelDayTakt.setNoteTextColor(RGB(128, 128, 128));
+		m_labelDayTakt.setNote1(_T("鐧界彮骞冲潎TT"));
+		m_labelDayTakt.setBackground(m_clrBackground);
+		m_labelDayTakt.setForeground(RGB(18, 18, 18), TRUE);
+	}
+	if (CWnd* pNightTakt = GetDlgItem(IDC_PROD_NIGHT_TAKT)) {
+		m_labelNightTakt.SubclassWindow(pNightTakt->GetSafeHwnd());
+		m_labelNightTakt.setFontSize(28);
+		m_labelNightTakt.setNoteTextColor(RGB(128, 128, 128));
+		m_labelNightTakt.setNote1(_T("澶滅彮骞冲潎TT"));
+		m_labelNightTakt.setBackground(m_clrBackground);
+		m_labelNightTakt.setForeground(RGB(18, 18, 18), TRUE);
+	}
+
+	RefreshData();
+	m_timerId = SetTimer(kTimerRefreshId, kTimerRefreshIntervalMs, nullptr);
+	return TRUE;
+}
+
+HBRUSH CPageProdOverview::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
+{
+	HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
+
+	if (nCtlColor == CTLCOLOR_DLG || nCtlColor == CTLCOLOR_STATIC) {
+		if (m_brushBackground.GetSafeHandle() == NULL) {
+			m_brushBackground.CreateSolidBrush(m_clrBackground);
+		}
+		pDC->SetBkMode(TRANSPARENT);
+		return (HBRUSH)m_brushBackground.GetSafeHandle();
+	}
+
+	return hbr;
+}
+
+void CPageProdOverview::OnDestroy()
+{
+	if (m_timerId != 0) {
+		KillTimer(m_timerId);
+		m_timerId = 0;
+	}
+	CDialogEx::OnDestroy();
+}
+
+void CPageProdOverview::OnSize(UINT nType, int cx, int cy)
+{
+	CDialogEx::OnSize(nType, cx, cy);
+}
+
+void CPageProdOverview::OnTimer(UINT_PTR nIDEvent)
+{
+	if (nIDEvent == kTimerRefreshId) {
+		RefreshData();
+	}
+	CDialogEx::OnTimer(nIDEvent);
+}
+
+void CPageProdOverview::RefreshData()
+{
+	CString text;
+	text.Format(_T("%d"), 123);
+	m_labelDayOut.setText(text);
+	text.Format(_T("%d"), 1235);
+	m_labelNightOut.setText(text);
+
+	m_labelDayTakt.setText(_T("1236"));
+	m_labelNightTakt.setText(_T("1238"));
+}
diff --git a/SourceCode/Bond/Servo/CPageProdOverview.h b/SourceCode/Bond/Servo/CPageProdOverview.h
new file mode 100644
index 0000000..6198d90
--- /dev/null
+++ b/SourceCode/Bond/Servo/CPageProdOverview.h
@@ -0,0 +1,37 @@
+锘�#pragma once
+#include <chrono>
+#include "HmLabel.h"
+
+// CPageProOverview 瀵硅瘽妗�
+class CPageProdOverview : public CDialogEx
+{
+	DECLARE_DYNAMIC(CPageProdOverview)
+
+public:
+	CPageProdOverview(CWnd* pParent = nullptr);   // 鏍囧噯鏋勯�犲嚱鏁�
+	virtual ~CPageProdOverview();
+	void SetBackgroundColor(COLORREF color);
+
+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);
+	afx_msg void OnTimer(UINT_PTR nIDEvent);
+
+private:
+	void RefreshData();
+
+private:
+	COLORREF m_clrBackground{ RGB(240, 240, 240) };
+	CBrush m_brushBackground;
+	UINT_PTR m_timerId = 0;
+	CHmLabel m_labelDayOut;
+	CHmLabel m_labelNightOut;
+	CHmLabel m_labelDayTakt;
+	CHmLabel m_labelNightTakt;
+};
diff --git a/SourceCode/Bond/Servo/CPanelProduction.cpp b/SourceCode/Bond/Servo/CPanelProduction.cpp
index bbc5900..814a631 100644
--- a/SourceCode/Bond/Servo/CPanelProduction.cpp
+++ b/SourceCode/Bond/Servo/CPanelProduction.cpp
@@ -22,6 +22,8 @@
 	m_hPlaceholder = nullptr;
 	m_bShiftSummaryValid = FALSE;
 	m_pStatsThread = nullptr;
+	m_pAccordionWnd = nullptr;
+	m_pPageProdOverview = nullptr;
 }
 
 CPanelProduction::~CPanelProduction()
@@ -61,6 +63,25 @@
 	pLine1->SetBkgndColor(RGB(225, 225, 225));
 	pLine1->SetLineColor(RGB(198, 198, 198));
 	pLine1->EnableResize();
+
+	CString strExpandIcon, strCloseIcon;
+	strExpandIcon.Format(_T("%s\\res\\arrow_down.ico"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir);
+	strCloseIcon.Format(_T("%s\\res\\arrow_right.ico"), (LPTSTR)(LPCTSTR)theApp.m_strAppDir);
+
+	m_pAccordionWnd = CAccordionWnd::FromHandle(GetDlgItem(IDC_ACCORDION_WND1)->m_hWnd);
+	m_pAccordionWnd->SetBkgndColor(m_crBkgnd);
+	m_pAccordionWnd->SetFrameColor(RGB(220, 220, 200), TRUE);
+	m_pAccordionWnd->Setpadding(PADDING_LEFT, 2);
+	m_pAccordionWnd->Setpadding(PADDING_TOP, 2);
+	m_pAccordionWnd->Setpadding(PADDING_RIGHT, 2);
+	m_pAccordionWnd->Setpadding(PADDING_BOTTOM, 2);
+	m_pAccordionWnd->LoadExpandIcon(strExpandIcon, strCloseIcon);
+
+	m_pPageProdOverview = new CPageProdOverview();
+	m_pPageProdOverview->SetBackgroundColor(m_crBkgnd);
+	m_pPageProdOverview->Create(IDD_PROD_OVERVIEW, GetDlgItem(IDC_ACCORDION_WND1));
+	m_pPageProdOverview->ShowWindow(SW_HIDE);
+	m_pAccordionWnd->AddItem("鐢熶骇鎬昏", m_pPageProdOverview, 280, TRUE, TRUE);
 
 	SetTimer(1, 1000 * 10, nullptr);
 	StartStatsThread();
@@ -107,6 +128,9 @@
 	GetClientRect(&rcClient);
 	pItem = GetDlgItem(IDC_LINE1);
 	pItem->MoveWindow(rcClient.right - 3, 0, 3, rcClient.Height());
+
+	pItem = GetDlgItem(IDC_ACCORDION_WND1);
+	pItem->MoveWindow(5, 5, rcClient.Width() - 10, rcClient.Height() - 10);
 }
 
 #define PRODUCTION_PANEL_MIN_WIDTH		88
diff --git a/SourceCode/Bond/Servo/CPanelProduction.h b/SourceCode/Bond/Servo/CPanelProduction.h
index 527db4f..cbf285f 100644
--- a/SourceCode/Bond/Servo/CPanelProduction.h
+++ b/SourceCode/Bond/Servo/CPanelProduction.h
@@ -1,8 +1,9 @@
 锘�#pragma once
 #include "BlButton.h"
 #include <afxmt.h>
-
+#include "AccordionWnd.h"
 #include "ProductionStats.h"
+#include "CPageProdOverview.h"
 
 // CPanelProduction dialog
 class CPanelProduction : public CDialogEx
@@ -21,6 +22,7 @@
 	int m_nPanelWidth;
 	CBlButton m_btnClose;
 	HWND m_hPlaceholder;
+	CAccordionWnd* m_pAccordionWnd;
 
 	// Production shift summary (updated by background thread)
 	ProductionShiftSummary m_shiftSummary;
@@ -28,6 +30,7 @@
 	CCriticalSection m_csShiftSummary;
 	CWinThread* m_pStatsThread;
 	CEvent m_evStopStats;
+	CPageProdOverview* m_pPageProdOverview;
 
 protected:
 	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
diff --git a/SourceCode/Bond/Servo/HmLabel.cpp b/SourceCode/Bond/Servo/HmLabel.cpp
new file mode 100644
index 0000000..c60cacb
--- /dev/null
+++ b/SourceCode/Bond/Servo/HmLabel.cpp
@@ -0,0 +1,177 @@
+#include "stdafx.h"
+#include "HmLabel.h"
+
+
+CHmLabel::CHmLabel()
+{
+	m_crFrame = RGB(128, 128, 128);
+	m_crBackground = RGB(255, 0, 0);
+	m_crForeground = RGB(255, 255, 255);
+	m_hFont = NULL;
+	m_hFontNote = NULL;
+}
+
+
+CHmLabel::~CHmLabel()
+{
+	if (m_hFont != NULL) {
+		::DeleteObject(m_hFont);
+		m_hFont = NULL;
+	}
+
+	if (m_hFontNote != NULL) {
+		::DeleteObject(m_hFontNote);
+		m_hFontNote = NULL;
+	}
+}
+
+BEGIN_MESSAGE_MAP(CHmLabel, CStatic)
+	ON_WM_PAINT()
+	ON_WM_NCPAINT()
+END_MESSAGE_MAP()
+
+void CHmLabel::setText(CString strText)
+{
+	SetWindowText(strText);
+	Invalidate();
+}
+
+void CHmLabel::setNote1(CString strNote1)
+{
+	m_strNote1 = strNote1;
+}
+
+void CHmLabel::setFontSize(int size)
+{
+	if (m_hFont != NULL) {
+		::DeleteObject(m_hFont);
+		m_hFont = NULL;
+	}
+
+	m_hFont = CreateFont(size, 0, 0, 0, FW_MEDIUM,
+		FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_CHARACTER_PRECIS,
+		CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, _T("宋体"));
+}
+
+void CHmLabel::setNoteFontSize(int size)
+{
+	if (m_hFontNote != NULL) {
+		::DeleteObject(m_hFontNote);
+		m_hFontNote = NULL;
+	}
+
+	m_hFontNote = CreateFont(size, 0, 0, 0, FW_MEDIUM,
+		FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_CHARACTER_PRECIS,
+		CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, _T("宋体"));
+}
+
+void CHmLabel::setNoteTextColor(COLORREF color, BOOL bInvalidate/* = FALSE*/)
+{
+	m_crNote = color;
+	if (bInvalidate) Invalidate(TRUE);
+}
+
+void CHmLabel::setBackground(COLORREF color, BOOL bInvalidate/* = FALSE*/)
+{
+	m_crBackground = color;
+	if (bInvalidate) Invalidate(TRUE);
+}
+
+void CHmLabel::setForeground(COLORREF color, BOOL bInvalidate/* = FALSE*/)
+{
+	m_crForeground = color;
+	if (bInvalidate) Invalidate(TRUE);
+}
+
+void CHmLabel::OnPaint()
+{
+	CPaintDC dc(this); // device context for painting
+					   // TODO: 在此处添加消息处理程序代码
+					   // 不为绘图消息调用 CStatic::OnPaint()
+
+
+	HDC hMemDC;
+	HBITMAP hBitmap;
+	RECT rcClient;
+	CString strText;
+	HBRUSH hBrushBK;
+
+
+	GetClientRect(&rcClient);
+	hMemDC = ::CreateCompatibleDC(dc.m_hDC);
+	hBitmap = ::CreateCompatibleBitmap(dc.m_hDC, rcClient.right - rcClient.left,
+		rcClient.bottom - rcClient.top);
+	::SelectObject(hMemDC, hBitmap);
+
+	
+	// 背景颜色
+	hBrushBK = CreateSolidBrush(m_crBackground);
+	::FillRect(hMemDC, &rcClient, hBrushBK);
+	DeleteObject(hBrushBK);
+
+
+	// 文字
+	char szText[256];
+	GetWindowText(szText, 256);
+	RECT rcText = rcClient;
+	SetBkMode(hMemDC, TRANSPARENT);
+	SetTextColor(hMemDC, m_crForeground);
+	::SelectObject(hMemDC, m_hFont == NULL ? (HFONT)GetStockObject(DEFAULT_GUI_FONT) : m_hFont);
+	::DrawTextA(hMemDC, szText, (int)strlen(szText), &rcText, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
+
+
+	// Note1
+	SetTextColor(hMemDC, m_crNote);
+	::SelectObject(hMemDC, m_hFontNote == NULL ? (HFONT)GetStockObject(DEFAULT_GUI_FONT) : m_hFontNote);
+	::DrawText(hMemDC, m_strNote1, m_strNote1.GetLength(), &rcClient, DT_CENTER | DT_BOTTOM | DT_SINGLELINE | DT_END_ELLIPSIS);
+
+
+	// EndPaint
+	::BitBlt(dc.m_hDC, 0, 0, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top,
+		hMemDC, 0, 0, SRCCOPY);
+	::DeleteObject(hBitmap);
+	::DeleteDC(hMemDC);
+}
+
+
+void CHmLabel::OnNcPaint()
+{
+	// TODO: 在此处添加消息处理程序代码
+	// 不为绘图消息调用 CStatic::OnNcPaint()
+	long styleEx = GetWindowLong(m_hWnd, GWL_EXSTYLE);
+	if ((styleEx & WS_EX_CLIENTEDGE) == WS_EX_CLIENTEDGE) {
+
+		RECT rect, rcClient;
+		GetClientRect(&rcClient);
+		::ClientToScreen(m_hWnd, (LPPOINT)&rcClient.left);
+		::ClientToScreen(m_hWnd, (LPPOINT)&rcClient.right);
+		GetWindowRect(&rect);
+		::OffsetRect(&rcClient, -rect.left, -rect.top);
+
+		rect.right -= rect.left;
+		rect.bottom -= rect.top;
+		rect.left = 0;
+		rect.top = 0;
+
+		HRGN hRgnWnd = CreateRectRgnIndirect(&rect);
+		HRGN hRgnClient = CreateRectRgnIndirect(&rcClient);
+
+		HBRUSH hBrushBK, hBrushFrame;
+		HDC hDC = ::GetWindowDC(m_hWnd);
+		::SelectClipRgn(hDC, hRgnWnd);
+		::ExtSelectClipRgn(hDC, hRgnClient, RGN_DIFF);
+
+		hBrushBK = CreateSolidBrush(m_crBackground);
+		::FillRect(hDC, &rect, hBrushBK);
+		DeleteObject(hBrushBK);
+
+		hBrushFrame = CreateSolidBrush(m_crFrame);
+		::FrameRect(hDC, &rect, hBrushFrame);
+
+		::DeleteObject(hRgnWnd);
+		::DeleteObject(hRgnClient);
+		DeleteObject(hBrushFrame);
+		::ReleaseDC(m_hWnd, hDC);
+	}
+}
+
diff --git a/SourceCode/Bond/Servo/HmLabel.h b/SourceCode/Bond/Servo/HmLabel.h
new file mode 100644
index 0000000..d7623e1
--- /dev/null
+++ b/SourceCode/Bond/Servo/HmLabel.h
@@ -0,0 +1,33 @@
+#pragma once
+class CHmLabel : public CStatic
+{
+public:
+	CHmLabel();
+	~CHmLabel();
+
+public:
+	void setText(CString strText);
+	void setNote1(CString strNote1);
+	void setFontSize(int size);
+	void setNoteFontSize(int size);
+	void setBackground(COLORREF color, BOOL bInvalidate = FALSE);
+	void setForeground(COLORREF color, BOOL bInvalidate = FALSE);
+	void setNoteTextColor(COLORREF color, BOOL bInvalidate = FALSE);
+
+private:
+	COLORREF m_crFrame;
+	COLORREF m_crBackground;
+	COLORREF m_crForeground;
+	COLORREF m_crNote;
+	HFONT m_hFont;
+	HFONT m_hFontNote;
+
+private:
+	CString m_strNote1;
+
+public:
+	DECLARE_MESSAGE_MAP()
+	afx_msg void OnPaint();
+	afx_msg void OnNcPaint();
+};
+
diff --git a/SourceCode/Bond/Servo/Servo.cpp b/SourceCode/Bond/Servo/Servo.cpp
index f4f67b4..c46246e 100644
--- a/SourceCode/Bond/Servo/Servo.cpp
+++ b/SourceCode/Bond/Servo/Servo.cpp
@@ -19,6 +19,7 @@
 #include "CControlJobManagerDlg.h"
 #include "ToolUnits.h"
 #include "CUserManager2.h"
+#include "AccordionWnd.h"
 
 
 // 澹版槑鍏ㄥ眬鍙橀噺锛岀敤浜庣鐞� GDI+ 鍒濆鍖�
@@ -116,6 +117,7 @@
 	CEqsGraphWnd::RegisterWndClass();
 	CMapPosWnd::RegisterWndClass();
 	CHmTab::RegisterWndClass();
+	CAccordionWnd::RegisterWndClass();
 
 
 	// 鍒濆鍖朢x搴�
diff --git a/SourceCode/Bond/Servo/Servo.rc b/SourceCode/Bond/Servo/Servo.rc
index 3f3b197..1cc02ae 100644
--- a/SourceCode/Bond/Servo/Servo.rc
+++ b/SourceCode/Bond/Servo/Servo.rc
@@ -812,8 +812,18 @@
 STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU
 FONT 8, "MS Shell Dlg", 400, 0, 0x1
 BEGIN
-    LTEXT           "Test",IDC_STATIC,95,67,15,8
     CONTROL         "Custom1",IDC_LINE1,"BYVerticalLine",WS_TABSTOP,286,7,18,240
+    CONTROL         "Custom1",IDC_ACCORDION_WND1,"AccordionWnd",WS_TABSTOP,7,7,271,240
+END
+
+IDD_PROD_OVERVIEW DIALOGEX 0, 0, 271, 159
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_SYSMENU
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+    CTEXT           "0",IDC_PROD_DAY_OUTPUT,16,12,68,45,SS_CENTERIMAGE
+    CTEXT           "0",IDC_PROD_NIGHT_OUTPUT,126,12,68,45,SS_CENTERIMAGE
+    CTEXT           "-",IDC_PROD_DAY_TAKT,16,82,68,45,SS_CENTERIMAGE
+    CTEXT           "-",IDC_PROD_NIGHT_TAKT,126,82,68,45,SS_CENTERIMAGE
 END
 
 
@@ -1253,6 +1263,14 @@
         TOPMARGIN, 7
         BOTTOMMARGIN, 247
     END
+
+    IDD_PROD_OVERVIEW, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 264
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 152
+    END
 END
 #endif    // APSTUDIO_INVOKED
 
@@ -1507,6 +1525,11 @@
     0
 END
 
+IDD_PROD_OVERVIEW AFX_DIALOG_LAYOUT
+BEGIN
+    0
+END
+
 
 /////////////////////////////////////////////////////////////////////////////
 //
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj b/SourceCode/Bond/Servo/Servo.vcxproj
index ddcddc3..8b7b8a4 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj
+++ b/SourceCode/Bond/Servo/Servo.vcxproj
@@ -222,6 +222,7 @@
     <ClInclude Include="..\jsoncpp\include\json\value.h" />
     <ClInclude Include="..\jsoncpp\include\json\writer.h" />
     <ClInclude Include="..\jsoncpp\lib_json\json_batchallocator.h" />
+    <ClInclude Include="AccordionWnd.h" />
     <ClInclude Include="CBaseDlg.h" />
     <ClInclude Include="CCarrierSlotGrid.h" />
     <ClInclude Include="CCarrierSlotSelector.h" />
@@ -243,9 +244,11 @@
     <ClInclude Include="CPageCollectionEvent.h" />
     <ClInclude Include="CPageGlassList.h" />
     <ClInclude Include="CPageLinkSignal.h" />
+    <ClInclude Include="CPageProdOverview.h" />
     <ClInclude Include="CPageReport.h" />
     <ClInclude Include="CPageVarialbles.h" />
     <ClInclude Include="CPanelProduction.h" />
+    <ClInclude Include="HmLabel.h" />
     <ClInclude Include="ProductionStats.h" />
     <ClInclude Include="CParam.h" />
     <ClInclude Include="CCjPage1.h" />
@@ -445,6 +448,7 @@
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
     </ClCompile>
+    <ClCompile Include="AccordionWnd.cpp" />
     <ClCompile Include="CBaseDlg.cpp" />
     <ClCompile Include="CCarrierSlotGrid.cpp" />
     <ClCompile Include="CCarrierSlotSelector.cpp" />
@@ -466,10 +470,12 @@
     <ClCompile Include="CPageCollectionEvent.cpp" />
     <ClCompile Include="CPageGlassList.cpp" />
     <ClCompile Include="CPageLinkSignal.cpp" />
+    <ClCompile Include="CPageProdOverview.cpp" />
     <ClCompile Include="CPageReport.cpp" />
     <ClCompile Include="CPageVarialbles.cpp" />
     <ClCompile Include="ConfigurationProduction.cpp" />
     <ClCompile Include="CPanelProduction.cpp" />
+    <ClCompile Include="HmLabel.cpp" />
     <ClCompile Include="ProductionStats.cpp" />
     <ClCompile Include="CParam.cpp" />
     <ClCompile Include="CCjPage1.cpp" />
@@ -662,4 +668,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 652252b..ccbde0c 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj.filters
+++ b/SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -239,6 +239,9 @@
     <ClCompile Include="ConfigurationProduction.cpp" />
     <ClCompile Include="CPanelProduction.cpp" />
     <ClCompile Include="ProductionStats.cpp" />
+    <ClCompile Include="AccordionWnd.cpp" />
+    <ClCompile Include="CPageProdOverview.cpp" />
+    <ClCompile Include="HmLabel.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="AlarmManager.h" />
@@ -520,6 +523,9 @@
     <ClInclude Include="CEventEditDlg.h" />
     <ClInclude Include="CReportEditDlg.h" />
     <ClInclude Include="CPanelProduction.h" />
+    <ClInclude Include="AccordionWnd.h" />
+    <ClInclude Include="CPageProdOverview.h" />
+    <ClInclude Include="HmLabel.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Servo.rc" />
@@ -563,4 +569,4 @@
       <UniqueIdentifier>{885738f6-3122-4bb9-8308-46b7f692fb13}</UniqueIdentifier>
     </Filter>
   </ItemGroup>
-</Project>
+</Project>
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/resource.h b/SourceCode/Bond/Servo/resource.h
index e81edcd..8f303c6 100644
--- a/SourceCode/Bond/Servo/resource.h
+++ b/SourceCode/Bond/Servo/resource.h
@@ -61,7 +61,7 @@
 #define IDD_CJ_PAGE3                    180
 #define IDD_DIALOG_USER_MANAGER2        181
 #define IDD_DIALOG_USER_EDIT2           182
-#define IDD_DIALOG1                     184
+#define IDD_PROD_OVERVIEW				183
 #define IDD_DIALOG_USERX_LOG            184
 #define IDD_DIALOG_VARIABLE_EDIT2       186
 #define IDD_DIALOG_REPORT_EDIT          187
@@ -323,6 +323,11 @@
 #define IDC_EDIT_EVT_NAME               1244
 #define IDC_EDIT_EVT_DESC               1245
 #define IDC_LIST_EVT_RPTS               1246
+#define IDC_ACCORDION_WND1              1247
+#define IDC_PROD_DAY_OUTPUT				1248
+#define IDC_PROD_NIGHT_OUTPUT			1249
+#define IDC_PROD_DAY_TAKT				1250
+#define IDC_PROD_NIGHT_TAKT				1251
 #define ID_MENU_HELP_ABOUT              32771
 #define ID_MENU_FILE_EXIT               32772
 #define ID_MENU_FILE_SECSTEST           32773
@@ -362,7 +367,7 @@
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #define _APS_NEXT_RESOURCE_VALUE        191
 #define _APS_NEXT_COMMAND_VALUE         32804
-#define _APS_NEXT_CONTROL_VALUE         1247
+#define _APS_NEXT_CONTROL_VALUE         1252
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif

--
Gitblit v1.9.3