Browse Source

完成呼叫取餐功能

张洋 3 weeks ago
parent
commit
10742fad81

BIN
bin/Win32/Debug/zhipuzi_pos_windows/skin/hq_slot_active.png


BIN
bin/Win32/Debug/zhipuzi_pos_windows/skin/hq_slot_n.png


BIN
bin/Win32/Debug/zhipuzi_pos_windows/skin/hq_tip_ok.png


+ 50 - 0
bin/Win32/Debug/zhipuzi_pos_windows/skin/huhuanqucan_page.xml

@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Window>
+	<HuhuanqucanPage>
+		<!-- 呼叫取餐:按用户设计稿逐像素量测还原(2026-09-19) -->
+		<!-- 垂直账本:顶部 hint 已删除 | 垫45 | 标签22+垫20+码行106+垫33+键盘338+垫27+按钮68=614 | 垫45(弹框704=45+614+45,两弹性垫片自动均分) -->
+		<VerticalLayout bkcolor="#FFF5F7FA">
+		<Control/>
+			<VerticalLayout name="hq_box" height="519" childpadding="0" childalign="center">
+				<Label name="hq_label" text="取餐码" height="22" font="16" textcolor="#FF5F6368" align="center" padding="0,0,0,20"/>
+				<HorizontalLayout name="hq_code_row" width="419" height="106" childpadding="25" padding="0,0,0,33">
+			<VerticalLayout name="hq_slot_0" width="86" height="106" bkimage="file='hq_slot_n.png' corner='10,10,10,10'">
+				<Label name="hq_digit_0" text="" font="40" textcolor="#FF60B177" align="center" valign="vcenter" height="106"/>
+				</VerticalLayout>
+			<VerticalLayout name="hq_slot_1" width="86" height="106" bkimage="file='hq_slot_n.png' corner='10,10,10,10'">
+				<Label name="hq_digit_1" text="" font="40" textcolor="#FF60B177" align="center" valign="vcenter" height="106"/>
+				</VerticalLayout>
+			<VerticalLayout name="hq_slot_2" width="86" height="106" bkimage="file='hq_slot_n.png' corner='10,10,10,10'">
+				<Label name="hq_digit_2" text="" font="40" textcolor="#FF60B177" align="center" valign="vcenter" height="106"/>
+				</VerticalLayout>
+			<VerticalLayout name="hq_slot_3" width="86" height="106" bkimage="file='hq_slot_n.png' corner='10,10,10,10'">
+				<Label name="hq_digit_3" text="" font="40" textcolor="#FF60B177" align="center" valign="vcenter" height="106"/>
+				</VerticalLayout>
+				</HorizontalLayout>
+				<VerticalLayout name="hq_keypad" width="442" height="338" childpadding="14">
+			<HorizontalLayout width="442" height="74" childpadding="14">
+				<Button name="key_1" text="1" width="138" height="74" font="26" textcolor="#FF1F2329" normalimage="file='key_normal.png' corner='12,12,12,12'" hotimage="file='key_hover.png' corner='12,12,12,12'" pushedimage="file='key_pushed.png' corner='12,12,12,12'" pushedtextcolor="#FF60B177"/>
+				<Button name="key_2" text="2" width="138" height="74" font="26" textcolor="#FF1F2329" normalimage="file='key_normal.png' corner='12,12,12,12'" hotimage="file='key_hover.png' corner='12,12,12,12'" pushedimage="file='key_pushed.png' corner='12,12,12,12'" pushedtextcolor="#FF60B177"/>
+				<Button name="key_3" text="3" width="138" height="74" font="26" textcolor="#FF1F2329" normalimage="file='key_normal.png' corner='12,12,12,12'" hotimage="file='key_hover.png' corner='12,12,12,12'" pushedimage="file='key_pushed.png' corner='12,12,12,12'" pushedtextcolor="#FF60B177"/>
+			</HorizontalLayout>
+			<HorizontalLayout width="442" height="74" childpadding="14">
+				<Button name="key_4" text="4" width="138" height="74" font="26" textcolor="#FF1F2329" normalimage="file='key_normal.png' corner='12,12,12,12'" hotimage="file='key_hover.png' corner='12,12,12,12'" pushedimage="file='key_pushed.png' corner='12,12,12,12'" pushedtextcolor="#FF60B177"/>
+				<Button name="key_5" text="5" width="138" height="74" font="26" textcolor="#FF1F2329" normalimage="file='key_normal.png' corner='12,12,12,12'" hotimage="file='key_hover.png' corner='12,12,12,12'" pushedimage="file='key_pushed.png' corner='12,12,12,12'" pushedtextcolor="#FF60B177"/>
+				<Button name="key_6" text="6" width="138" height="74" font="26" textcolor="#FF1F2329" normalimage="file='key_normal.png' corner='12,12,12,12'" hotimage="file='key_hover.png' corner='12,12,12,12'" pushedimage="file='key_pushed.png' corner='12,12,12,12'" pushedtextcolor="#FF60B177"/>
+			</HorizontalLayout>
+			<HorizontalLayout width="442" height="74" childpadding="14">
+				<Button name="key_7" text="7" width="138" height="74" font="26" textcolor="#FF1F2329" normalimage="file='key_normal.png' corner='12,12,12,12'" hotimage="file='key_hover.png' corner='12,12,12,12'" pushedimage="file='key_pushed.png' corner='12,12,12,12'" pushedtextcolor="#FF60B177"/>
+				<Button name="key_8" text="8" width="138" height="74" font="26" textcolor="#FF1F2329" normalimage="file='key_normal.png' corner='12,12,12,12'" hotimage="file='key_hover.png' corner='12,12,12,12'" pushedimage="file='key_pushed.png' corner='12,12,12,12'" pushedtextcolor="#FF60B177"/>
+				<Button name="key_9" text="9" width="138" height="74" font="26" textcolor="#FF1F2329" normalimage="file='key_normal.png' corner='12,12,12,12'" hotimage="file='key_hover.png' corner='12,12,12,12'" pushedimage="file='key_pushed.png' corner='12,12,12,12'" pushedtextcolor="#FF60B177"/>
+			</HorizontalLayout>
+			<HorizontalLayout width="442" height="74" childpadding="14">
+				<Button name="key_clear" text="清空" width="138" height="74" font="16" textcolor="#FF5F6368" normalimage="file='key_normal.png' corner='12,12,12,12'" hotimage="file='key_hover.png' corner='12,12,12,12'" pushedimage="file='key_pushed.png' corner='12,12,12,12'" pushedtextcolor="#FF60B177"/>
+				<Button name="key_0" text="0" width="138" height="74" font="26" textcolor="#FF1F2329" normalimage="file='key_normal.png' corner='12,12,12,12'" hotimage="file='key_hover.png' corner='12,12,12,12'" pushedimage="file='key_pushed.png' corner='12,12,12,12'" pushedtextcolor="#FF60B177"/>
+				<Button name="key_del" text="删除" width="138" height="74" font="16" textcolor="#FF5F6368" normalimage="file='key_normal.png' corner='12,12,12,12'" hotimage="file='key_hover.png' corner='12,12,12,12'" pushedimage="file='key_pushed.png' corner='12,12,12,12'" pushedtextcolor="#FF60B177"/>
+			</HorizontalLayout>
+				</VerticalLayout>
+			</VerticalLayout>
+			<Control/>
+		</VerticalLayout>
+	</HuhuanqucanPage>
+</Window>

BIN
bin/Win32/Debug/zhipuzi_pos_windows/skin/nav_huhuanqucan.png


BIN
bin/Win32/Debug/zhipuzi_pos_windows/skin/nav_huhuanqucan_grn36.png


BIN
bin/Win32/Debug/zhipuzi_pos_windows/skin/nav_huhuanqucan_on.png


+ 5 - 0
zhipuzi_pos_windows/control/ControlEx.h

@@ -25,6 +25,7 @@
 #include "../page/CShoukuanOrderInfoPageUI.h"
 #include "../page/CAIxuexiPageUI.h"
 #include "../page/CYubaozhuangbiaoqianPageUI.h"
+#include "../page/CHuhuanqucanPageUI.h"
 
 #include "CWaimaiOrderItemUI.h"
 #include "CDianneiOrderItemUI.h"
@@ -135,6 +136,10 @@ public:
 		{
 			return new CYubaozhuangbiaoqianPageUI;
 		}
+		else if (_tcscmp(pstrClass, _T("HuhuanqucanPage")) == 0)
+		{
+			return new CHuhuanqucanPageUI;
+		}
 
 		//控件相关的
 		else if (_tcscmp(pstrClass, _T("WaimaiOrderItem")) == 0)

+ 20 - 1
zhipuzi_pos_windows/page/CGengduoPageUI.cpp

@@ -211,6 +211,12 @@ void CGengduoPageUI::Refresh()
 			pImage->SetBkImage(L"nav_biaoqian_grn36.png");
 			pItem->SetName(L"yubaozhuangbiaoqian");
 		}
+		else if (*it == "huhuanqucan")
+		{
+			pTitle->SetText(L"呼叫取餐");
+			pImage->SetBkImage(L"nav_huhuanqucan_grn36.png");
+			pItem->SetName(L"huhuanqucan");
+		}
 		else
 		{
 			continue;
@@ -395,7 +401,20 @@ void CGengduoPageUI::Refresh()
 			pFront->SetName(L"gengduo_front");
 			pBack->SetName(L"gengduo_back");
 			pExchange->SetName(L"gengduo_exchange");
-			}
+		}
+
+		else if (*it == "huhuanqucan")
+		{
+			pTitle->SetText(L"呼叫取餐");
+			pImage->SetBkImage(L"nav_huhuanqucan_grn36.png");
+			pItem->SetName(L"huhuanqucan");
+
+			pExchange->SetText(L"上移");
+
+			pFront->SetName(L"gengduo_front");
+			pBack->SetName(L"gengduo_back");
+			pExchange->SetName(L"gengduo_exchange");
+		}
 		else
 		{
 			continue;

+ 164 - 0
zhipuzi_pos_windows/page/CHuhuanqucanPageUI.cpp

@@ -0,0 +1,164 @@
+#include "pch.h"
+#include "CHuhuanqucanPageUI.h"
+
+#include "../worker/CHuhuanqucanWorker.h"
+
+CHuhuanqucanPageUI::CHuhuanqucanPageUI()
+{
+}
+
+CHuhuanqucanPageUI::~CHuhuanqucanPageUI()
+{
+}
+
+void CHuhuanqucanPageUI::InitControl()
+{
+    for (int i = 0; i < 4; i++)
+    {
+        std::wstring d = L"hq_digit_" + std::to_wstring(i);
+        std::wstring s = L"hq_slot_" + std::to_wstring(i);
+        m_pDigit[i] = static_cast<CLabelUI*>(FindSubControl(d.c_str()));
+        m_pSlot[i] = FindSubControl(s.c_str());
+    }
+}
+
+void CHuhuanqucanPageUI::InitShow()
+{
+    m_strCode.clear();
+    UpdateCodeUI();
+}
+
+void CHuhuanqucanPageUI::HandleClickMsg(TNotifyUI& msg)
+{
+    CDuiString name = msg.pSender->GetName();
+    std::wstring ws = name;
+
+    //键盘:key_clear 清空 / key_del 删除 / key_0..key_9 输入对应数字(满 4 位自动触发呼叫)
+    if (ws.rfind(L"key_", 0) == 0)
+    {
+        if (ws == L"key_clear")
+        {
+            ClearCode();
+        }
+        else if (ws == L"key_del")
+        {
+            DeleteDigit();
+        }
+        else
+        {
+            wchar_t ch = ws[ws.size() - 1];
+            AppendDigit(ch);
+        }
+    }
+}
+
+void CHuhuanqucanPageUI::HandleSelectChangeMsg(TNotifyUI& msg)
+{
+}
+
+void CHuhuanqucanPageUI::HandleItemSelectMsg(TNotifyUI& msg)
+{
+}
+
+void CHuhuanqucanPageUI::HandleTextChangedMsg(TNotifyUI& msg)
+{
+}
+
+void CHuhuanqucanPageUI::HandleTextCapture(std::string content)
+{
+    //扫码枪录入的取餐号(UTF-8)。去掉首尾空白/换行,只保留数字。
+    std::wstring wcontent = CLewaimaiString::UTF8ToUnicode(content);
+    std::wstring digits;
+    for (wchar_t c : wcontent)
+    {
+        if (c >= L'0' && c <= L'9')
+        {
+            digits.push_back(c);
+        }
+    }
+
+    //取餐码固定 4 位,与键盘输入规则一致;不是 4 位数字则忽略
+    if (digits.size() != 4)
+    {
+        CLewaimaiLog::OutputDebugMessage(L"呼叫取餐:扫码内容非 4 位数字,已忽略:" + wcontent);
+        return;
+    }
+
+    //显示扫码得到的取餐码并触发呼叫(与键盘满 4 位走同一逻辑)
+    m_strCode = digits;
+    UpdateCodeUI();
+    StartCall();
+}
+
+bool CHuhuanqucanPageUI::HandleCustomMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    return false;
+}
+
+void CHuhuanqucanPageUI::AppendDigit(wchar_t ch)
+{
+    if (m_strCode.size() >= 4) return;
+
+    m_strCode.push_back(ch);
+    UpdateCodeUI();
+
+    //满 4 位数字立即自动呼叫,无需再点「呼叫取餐」按钮
+    if (m_strCode.size() == 4)
+    {
+        StartCall();
+    }
+}
+
+void CHuhuanqucanPageUI::DeleteDigit()
+{
+    if (m_strCode.empty()) return;
+
+    m_strCode.pop_back();
+    UpdateCodeUI();
+}
+
+void CHuhuanqucanPageUI::ClearCode()
+{
+    if (m_strCode.empty()) return;
+
+    m_strCode.clear();
+    UpdateCodeUI();
+}
+
+void CHuhuanqucanPageUI::UpdateCodeUI()
+{
+    for (int i = 0; i < 4; i++)
+    {
+        if (m_pDigit[i] != NULL)
+        {
+            if (i < (int)m_strCode.size())
+            {
+                m_pDigit[i]->SetText(std::wstring(1, m_strCode[i]).c_str());
+            }
+            else
+            {
+                m_pDigit[i]->SetText(L"");
+            }
+        }
+
+        bool bShow = (i == (int)m_strCode.size()) && ((int)m_strCode.size() < 4);
+
+        //当前格切换 2px 主绿焦点描边(设计稿规格),其余格用普通灰描边
+        if (m_pSlot[i] != NULL)
+        {
+            m_pSlot[i]->SetBkImage(bShow ? L"file='hq_slot_active.png' corner='10,10,10,10'" : L"file='hq_slot_n.png' corner='10,10,10,10'");
+        }
+    }
+}
+
+void CHuhuanqucanPageUI::StartCall()
+{
+    if (m_strCode.size() != 4) return;
+
+    //交给 worker 异步处理:语音播报和 API 网络呼叫各自独立进行,互不等待
+    CHuhuanqucanWorker::GetInstance()->AddCall(m_strCode);
+
+    //清空输入,准备下一次呼叫
+    m_strCode.clear();
+    UpdateCodeUI();
+}

+ 45 - 0
zhipuzi_pos_windows/page/CHuhuanqucanPageUI.h

@@ -0,0 +1,45 @@
+#pragma once
+
+#include "pch.h"
+#include "../ui/CBasePageUI.h"
+
+//呼叫取餐页面:输入 4 位取餐码后交给 CHuhuanqucanWorker 异步处理,
+//语音播报和 /waimaiorder/calltakefood 网络呼叫各自独立进行
+class CHuhuanqucanPageUI : public CBasePageUI
+{
+public:
+    CHuhuanqucanPageUI();
+    ~CHuhuanqucanPageUI();
+
+    //初始化页面控件(页面创建构造时调用一次)
+    void InitControl();
+    //初始化展示(每次被选中加载时调用)
+    void InitShow();
+
+    //处理按钮点击
+    void HandleClickMsg(TNotifyUI& msg);
+    //处理 option 切换
+    void HandleSelectChangeMsg(TNotifyUI& msg);
+    //处理下拉框 / radio 切换
+    void HandleItemSelectMsg(TNotifyUI& msg);
+    //处理编辑框内容改变
+    void HandleTextChangedMsg(TNotifyUI& msg);
+    //处理扫码枪内容
+    void HandleTextCapture(std::string content);
+    //处理自定义消息
+    bool HandleCustomMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+private:
+    //输入与呼叫
+    void AppendDigit(wchar_t ch);
+    void DeleteDigit();
+    void ClearCode();
+    void UpdateCodeUI();
+    void StartCall();
+
+private:
+    std::wstring m_strCode;       //当前输入的取餐码
+
+    CLabelUI*   m_pDigit[4] = { NULL, NULL, NULL, NULL };
+    CControlUI* m_pSlot[4] = { NULL, NULL, NULL, NULL };    //4 个取餐码格子(切换焦点描边用)
+};

BIN
zhipuzi_pos_windows/resource/skin.zip


+ 7 - 0
zhipuzi_pos_windows/tool/CAppEnv.cpp

@@ -6,6 +6,7 @@
 #include "../worker/CMqttClientWorker.h"
 #include "../worker/CCommonWorker.h"
 #include "../worker/CVoiceWorker.h"
+#include "../worker/CHuhuanqucanWorker.h"
 #include "../worker/CDiandanAIShibieWorker.h"
 
 #include "CShuangpingTool.h"
@@ -37,6 +38,9 @@ void CAppEnv::Start()
 	//启动声音任务
 	CVoiceWorker::GetInstance()->Start();
 
+	//启动呼叫取餐任务
+	CHuhuanqucanWorker::GetInstance()->Start();
+
 	//启动AI识别任务
 	CDiandanAIShibieWorker::GetInstance()->Start();
 
@@ -60,6 +64,9 @@ void CAppEnv::Stop()
 	//停止声音任务
 	CVoiceWorker::GetInstance()->Stop();
 
+	//停止呼叫取餐任务
+	CHuhuanqucanWorker::GetInstance()->Stop();
+
 	//暂停AI识别任务
 	CDiandanAIShibieWorker::GetInstance()->Stop();
 	

+ 2 - 2
zhipuzi_pos_windows/tool/CSetting.cpp

@@ -389,13 +389,13 @@ void CSetting::Init()
 	std::string setting_gongneng_changyong_string = "setting_gongneng_changyong_string";
 	if (m_paramsMap.find(setting_gongneng_changyong_string) == m_paramsMap.end())
 	{
-		m_paramsMap[setting_gongneng_changyong_string] = "diandan,dingdan,huiyuan,baobiao,jiaoban,setting";
+		m_paramsMap[setting_gongneng_changyong_string] = "diandan,dingdan,huiyuan,shangpin,shoukuan,baobiao,jiaoban,setting";
 	}
 
 	std::string setting_gongneng_gengduo_string = "setting_gongneng_gengduo_string";
 	if (m_paramsMap.find(setting_gongneng_gengduo_string) == m_paramsMap.end())
 	{
-		m_paramsMap[setting_gongneng_gengduo_string] = "shangpin,kucun,caigou,zhengcan,saomashouyin,shoukuan";
+		m_paramsMap[setting_gongneng_gengduo_string] = "zhengcan,saomashouyin,yubaozhuangbiaoqian,huhuanqucan,kucun,caigou";
 	}
 
 	//快捷键相关的设置(微信收款默认CTRL+D)

+ 24 - 1
zhipuzi_pos_windows/wnd/CMainWnd.cpp

@@ -391,7 +391,7 @@ void CMainWnd::HandleSelectChangeMsg(TNotifyUI& msg)
 	std::wstring ws_name = name;
 
 	if (ws_name == _T("main_diandan") || ws_name == _T("main_dingdan") || ws_name == _T("main_huiyuan") || ws_name == _T("main_baobiao") || ws_name == _T("main_jiaoban") || ws_name == _T("main_setting") || ws_name == _T("main_gengduo") \
-		|| ws_name == _T("main_shangpin") || ws_name == _T("main_kucun") || ws_name == _T("main_caigou") || ws_name == _T("main_zhengcan") || ws_name == _T("main_saomashouyin") || ws_name == _T("main_shoukuan") || ws_name == _T("main_yubaozhuangbiaoqian"))
+		|| ws_name == _T("main_shangpin") || ws_name == _T("main_kucun") || ws_name == _T("main_caigou") || ws_name == _T("main_zhengcan") || ws_name == _T("main_saomashouyin") || ws_name == _T("main_shoukuan") || ws_name == _T("main_yubaozhuangbiaoqian") || ws_name == _T("main_huhuanqucan"))
 	{
 		SwitchPageByName(ws_name);
 	}
@@ -1307,6 +1307,14 @@ void CMainWnd::UpdateGongnengDaohang()
 			newOption->SetNormalImage(L"file='nav_biaoqian.png' source='0,0,24,24' dest='24,10,48,34'");
 			newOption->SetSelectedImage(L"file='nav_biaoqian_on.png' source='0,0,24,24' dest='24,10,48,34'");
 		}
+		else if (curName == "huhuanqucan")
+		{
+			newOption->SetName(L"main_huhuanqucan");
+			newOption->SetText(L"呼叫取餐");
+
+			newOption->SetNormalImage(L"file='nav_huhuanqucan.png' source='0,0,24,24' dest='24,10,48,34'");
+			newOption->SetSelectedImage(L"file='nav_huhuanqucan_on.png' source='0,0,24,24' dest='24,10,48,34'");
+		}
 
 		layout->Add(newOption);
 	}
@@ -1427,6 +1435,10 @@ void CMainWnd::SwitchPageByName(std::wstring name)
 	{
 		this->SwitchPage(YUBAOZHUANGBIAOQIAN);
 	}
+	else if (name == L"main_huhuanqucan")
+	{
+		this->SwitchPage(HUHUANQUCAN);
+	}
 	else
 	{
 		//没开通的页面暂时不跳转
@@ -1672,6 +1684,12 @@ void CMainWnd::CreatePages()
 		pChildContainer = static_cast<CBasePageUI*>(builder.Create(_T("yubaozhuangbiaoqian_page.xml"), (UINT)0, &cb, &m_pm));
 		m_pages[YUBAOZHUANGBIAOQIAN] = pChildContainer;
 	}
+	{
+		CDialogBuilder builder;
+		CDialogBuilderCallbackEx cb;
+		pChildContainer = static_cast<CBasePageUI*>(builder.Create(_T("huhuanqucan_page.xml"), (UINT)0, &cb, &m_pm));
+		m_pages[HUHUANQUCAN] = pChildContainer;
+	}
 
 	//对所有页面进行初始化构造控件
 	for (std::map<int, CBasePageUI*>::iterator it = m_pages.begin(); it != m_pages.end(); it++)
@@ -1828,6 +1846,11 @@ void CMainWnd::UpdateGongnengString()
 		TmpgengduoVector.push_back("yubaozhuangbiaoqian");
 	}
 
+	if (TmpMap.find("huhuanqucan") == TmpMap.end())
+	{
+		TmpgengduoVector.push_back("huhuanqucan");
+	}
+
 	//这个时候已经过滤掉了不需要的,加上了被删除的,可以保存数据库了
 	gengduoVector = TmpgengduoVector;
 

+ 1 - 0
zhipuzi_pos_windows/wnd/CMainWnd.h

@@ -39,6 +39,7 @@ public:
 		SHOUKUANINFO, //收款订单详情
 		AIXUEXI, //AI学习
 		YUBAOZHUANGBIAOQIAN, //预包装标签
+		HUHUANQUCAN, //呼叫取餐
 	};
 
     LPCTSTR GetWindowClassName() const

+ 129 - 0
zhipuzi_pos_windows/worker/CHuhuanqucanWorker.cpp

@@ -0,0 +1,129 @@
+#include "pch.h"
+#include "CHuhuanqucanWorker.h"
+
+#include "../tool/CSpeech.h"
+
+#include "../tool/CAppEnv.h"
+
+#include "../network/CZhipuziHttpClient.h"
+
+CHuhuanqucanWorker::CHuhuanqucanWorker()
+{
+	m_is_work = false;
+}
+
+CHuhuanqucanWorker::~CHuhuanqucanWorker()
+{
+
+}
+
+void CHuhuanqucanWorker::Start()
+{
+	m_is_work = true;
+
+	//处理呼叫取餐的语音播报
+	std::thread(&CHuhuanqucanWorker::HandleVoice, this).detach();
+	CAppEnv::GetInstance()->AddWorkerNum();
+
+	//处理呼叫取餐的网络请求
+	std::thread(&CHuhuanqucanWorker::HandleApi, this).detach();
+	CAppEnv::GetInstance()->AddWorkerNum();
+}
+
+void CHuhuanqucanWorker::Stop()
+{
+	m_is_work = false;
+}
+
+//呼叫取餐:同一个 code 同时进语音队列和网络队列,两条线各走各的;两个队列用各自独立的 mutex,互不竞争
+void CHuhuanqucanWorker::AddCall(std::wstring code)
+{
+	m_voice_mutex.lock();
+	m_voice_queue.push(code);
+	m_voice_mutex.unlock();
+
+	m_api_mutex.lock();
+	m_api_queue.push(code);
+	m_api_mutex.unlock();
+}
+
+//语音播报:不管网络呼叫结果怎么样,这里都正常播报(独立锁,不阻塞 API 线程)
+void CHuhuanqucanWorker::HandleVoice()
+{
+	while (m_is_work)
+	{
+		m_voice_mutex.lock();
+
+		if (m_voice_queue.empty())
+		{
+			m_voice_mutex.unlock();
+
+			Sleep(100);
+			continue;
+		}
+
+		std::wstring code = m_voice_queue.front();
+		m_voice_queue.pop();
+
+		m_voice_mutex.unlock();
+
+		//本地语音播报:XXXX号,请取餐!
+		CSpeech::TTSSpeak(CLewaimaiString::UnicodeToUTF8(code) + "号,请取餐!");
+	}
+
+	CAppEnv::GetInstance()->DelWorkerNum(L"CHuhuanqucanWorker::HandleVoice");
+}
+
+//网络呼叫:结果只写调试日志,不反哺语音、不反哺界面(独立锁,不阻塞语音线程)
+void CHuhuanqucanWorker::HandleApi()
+{
+	while (m_is_work)
+	{
+		m_api_mutex.lock();
+
+		if (m_api_queue.empty())
+		{
+			m_api_mutex.unlock();
+
+			Sleep(100);
+			continue;
+		}
+
+		std::wstring code = m_api_queue.front();
+		m_api_queue.pop();
+
+		m_api_mutex.unlock();
+
+		std::map<std::string, std::string> params;
+		params["code"] = CLewaimaiString::UnicodeToUTF8(code);
+
+		std::string response;
+		bool ret = CZhipuziHttpClient::GetInstance()->Request("/waimaiorder/calltakefood", params, response);
+
+		if (!ret)
+		{
+			CLewaimaiLog::OutputDebugMessage(L"呼叫取餐网络请求失败,code:" + code);
+			continue;
+		}
+
+		rapidjson::Document document;
+		document.Parse(response.c_str());
+
+		if (document.HasParseError() || !document.HasMember("errcode") || !document.HasMember("errmsg"))
+		{
+			CLewaimaiLog::OutputDebugMessage(L"呼叫取餐服务器返回数据格式错误,code:" + code);
+			continue;
+		}
+
+		int errcode = document["errcode"].GetInt();
+		if (errcode != 0)
+		{
+			CLewaimaiLog::OutputDebugMessage(L"呼叫取餐失败,code:" + code + L",errmsg:" + CLewaimaiString::UTF8ToUnicode(std::string(document["errmsg"].GetString())));
+			continue;
+		}
+
+		CLewaimaiLog::OutputDebugMessage(L"呼叫取餐成功,code:" + code);
+	}
+
+	CAppEnv::GetInstance()->DelWorkerNum(L"CHuhuanqucanWorker::HandleApi");
+}

+ 43 - 0
zhipuzi_pos_windows/worker/CHuhuanqucanWorker.h

@@ -0,0 +1,43 @@
+#pragma once
+
+#include "pch.h"
+
+//这个类专门用于处理呼叫取餐:语音播报和 API 网络呼叫拆分独立进行,
+//不管网络呼叫结果怎么样,语音播报都正常进行
+class CHuhuanqucanWorker
+{
+public:
+	CHuhuanqucanWorker();
+	~CHuhuanqucanWorker();
+
+	static CHuhuanqucanWorker* GetInstance()
+	{
+		static CHuhuanqucanWorker instance;
+
+		return &instance;
+	}
+
+	//开始工作
+	void Start();
+
+	//停止工作
+	void Stop();
+
+	//呼叫取餐(code 入两个独立队列,语音和网络各自消费、互不影响)
+	void AddCall(std::wstring code);
+
+	//语音播报队列处理
+	void HandleVoice();
+
+	//网络呼叫队列处理
+	void HandleApi();
+
+private:
+	bool m_is_work;
+
+	std::queue<std::wstring> m_voice_queue;
+	std::mutex m_voice_mutex;
+
+	std::queue<std::wstring> m_api_queue;
+	std::mutex m_api_mutex;
+};

+ 4 - 0
zhipuzi_pos_windows/zhipuzi_pos_windows.vcxproj

@@ -250,6 +250,7 @@ copy $(ProjectDir)conf\ $(SolutionDir)bin\$(Platform)\$(Configuration)\conf\</Co
     <ClInclude Include="ai\YoloFeatureManager.h" />
     <ClInclude Include="control\CFoodXuexiImageItemUI.h" />
     <ClInclude Include="page\CYubaozhuangbiaoqianPageUI.h" />
+    <ClInclude Include="page\CHuhuanqucanPageUI.h" />
     <ClInclude Include="page\CAIxuexiPageUI.h" />
     <ClInclude Include="tool\tts\CryptoUtil.h" />
     <ClInclude Include="tool\tts\PcmPlayer.h" />
@@ -301,6 +302,7 @@ copy $(ProjectDir)conf\ $(SolutionDir)bin\$(Platform)\$(Configuration)\conf\</Co
     <ClInclude Include="wnd\CImageAttentionWnd.h" />
     <ClInclude Include="worker\CCommonWorker.h" />
     <ClInclude Include="worker\CVoiceWorker.h" />
+    <ClInclude Include="worker\CHuhuanqucanWorker.h" />
     <ClInclude Include="page\CJiaobanPageUI.h" />
     <ClInclude Include="page\CBaobiaoPageUI.h" />
     <ClInclude Include="wnd\CHuiyuanAddWnd.h" />
@@ -383,6 +385,7 @@ copy $(ProjectDir)conf\ $(SolutionDir)bin\$(Platform)\$(Configuration)\conf\</Co
     <ClCompile Include="ai\YoloFeatureManager.cpp" />
     <ClCompile Include="control\CFoodXuexiImageItemUI.cpp" />
     <ClCompile Include="page\CYubaozhuangbiaoqianPageUI.cpp" />
+    <ClCompile Include="page\CHuhuanqucanPageUI.cpp" />
     <ClCompile Include="sqlite3\shell.c">
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
       <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
@@ -443,6 +446,7 @@ copy $(ProjectDir)conf\ $(SolutionDir)bin\$(Platform)\$(Configuration)\conf\</Co
     <ClCompile Include="wnd\CImageAttentionWnd.cpp" />
     <ClCompile Include="worker\CCommonWorker.cpp" />
     <ClCompile Include="worker\CVoiceWorker.cpp" />
+    <ClCompile Include="worker\CHuhuanqucanWorker.cpp" />
     <ClCompile Include="page\CJiaobanPageUI.cpp" />
     <ClCompile Include="page\CBaobiaoPageUI.cpp" />
     <ClCompile Include="wnd\CHuiyuanAddWnd.cpp" />

+ 12 - 0
zhipuzi_pos_windows/zhipuzi_pos_windows.vcxproj.filters

@@ -237,6 +237,9 @@
     <ClInclude Include="worker\CVoiceWorker.h">
       <Filter>头文件</Filter>
     </ClInclude>
+    <ClInclude Include="worker\CHuhuanqucanWorker.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
     <ClInclude Include="worker\CCommonWorker.h">
       <Filter>头文件</Filter>
     </ClInclude>
@@ -399,6 +402,9 @@
     <ClInclude Include="page\CYubaozhuangbiaoqianPageUI.h">
       <Filter>头文件</Filter>
     </ClInclude>
+    <ClInclude Include="page\CHuhuanqucanPageUI.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
     <ClInclude Include="tool\tts\CryptoUtil.h">
       <Filter>头文件</Filter>
     </ClInclude>
@@ -614,6 +620,9 @@
     <ClCompile Include="worker\CVoiceWorker.cpp">
       <Filter>源文件</Filter>
     </ClCompile>
+    <ClCompile Include="worker\CHuhuanqucanWorker.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
     <ClCompile Include="worker\CCommonWorker.cpp">
       <Filter>源文件</Filter>
     </ClCompile>
@@ -770,6 +779,9 @@
     <ClCompile Include="page\CYubaozhuangbiaoqianPageUI.cpp">
       <Filter>源文件</Filter>
     </ClCompile>
+    <ClCompile Include="page\CHuhuanqucanPageUI.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
     <ClCompile Include="tool\tts\CryptoUtil.cpp">
       <Filter>源文件</Filter>
     </ClCompile>