|
|
@@ -0,0 +1,1198 @@
|
|
|
+#include "pch.h"
|
|
|
+#include "CCaigouViews.h"
|
|
|
+#include "../control/ControlEx.h"
|
|
|
+
|
|
|
+// 分类下拉项(与商品档案 cat 取值一一对应;CG_CATS 在头文件以 extern 声明)
|
|
|
+extern const wchar_t* const CG_CATS[6] =
|
|
|
+{
|
|
|
+ L"主食", L"主料", L"调料", L"蔬菜", L"肉类", L"蛋类"
|
|
|
+};
|
|
|
+
|
|
|
+namespace
|
|
|
+{
|
|
|
+ // 采购记录(设计稿口径;以 2026-10-14 为今天:本月 3 / 上月 5 / 近三个月 8)
|
|
|
+ const CgRecItem g_rec[] = {
|
|
|
+ { L"CG20261013001", L"2026-10-13 09:26", L"张丽", 5, 12860.00, CG_ST_AUDITED },
|
|
|
+ { L"CG20261012003", L"2026-10-12 15:41", L"王强", 3, 5300.00, CG_ST_PENDING },
|
|
|
+ { L"CG20261008002", L"2026-10-08 11:05", L"李明", 2, 1860.00, CG_ST_REJECTED },
|
|
|
+ { L"CG20260928001", L"2026-09-28 10:12", L"张丽", 5, 12860.00, CG_ST_DONE },
|
|
|
+ { L"CG20260927003", L"2026-09-27 16:38", L"王强", 3, 5300.00, CG_ST_AUDITED },
|
|
|
+ { L"CG20260926002", L"2026-09-26 09:47", L"张丽", 2, 860.00, CG_ST_PENDING },
|
|
|
+ { L"CG20260925006", L"2026-09-25 14:22", L"李明", 6, 15300.00, CG_ST_AUDITED },
|
|
|
+ { L"CG20260924001", L"2026-09-24 11:30", L"王强", 4, 1600.00, CG_ST_DONE },
|
|
|
+ { L"CG20260820003", L"2026-08-20 10:08", L"张丽", 3, 12400.00, CG_ST_AUDITED },
|
|
|
+ };
|
|
|
+ const int g_rec_n = (int)(sizeof(g_rec) / sizeof(g_rec[0]));
|
|
|
+
|
|
|
+ // 采购统计(按商品维度)
|
|
|
+ const CgStatItem g_stat[] = {
|
|
|
+ { L"食用油", L"调料", L"桶", 4, 60, 3300.00 },
|
|
|
+ { L"大米", L"主食", L"斤", 3, 150, 1980.00 },
|
|
|
+ { L"牛肉", L"肉类", L"斤", 2, 80, 1600.00 },
|
|
|
+ { L"面粉", L"主料", L"袋", 2, 40, 1040.00 },
|
|
|
+ { L"生抽", L"调料", L"瓶", 1, 20, 500.00 },
|
|
|
+ };
|
|
|
+ const int g_stat_n = (int)(sizeof(g_stat) / sizeof(g_stat[0]));
|
|
|
+
|
|
|
+ // 采购订单详情明细(与记录表一一对应;每行 2 条明细)
|
|
|
+ const CgDetailRow g_d1[] = { { L"大米", L"斤", 100, 4.20, 420.00 }, { L"面粉", L"袋", 5, 26.00, 130.00 } };
|
|
|
+ const CgDetailRow g_d2[] = { { L"食用油", L"桶", 5, 55.00, 275.00 }, { L"牛肉", L"斤", 10, 28.50, 285.00 } };
|
|
|
+ const CgDetailRow g_d3[] = { { L"番茄", L"斤", 12, 4.50, 54.00 }, { L"鸡蛋", L"斤", 7, 6.00, 42.00 } };
|
|
|
+ const CgDetailRow g_d4[] = { { L"大米", L"斤", 100, 3.20, 320.00 }, { L"面粉", L"袋", 10, 32.00, 320.00 } };
|
|
|
+ const CgDetailRow g_d5[] = { { L"牛肉", L"斤", 30, 38.00, 1140.00 }, { L"食用油", L"桶", 5, 74.00, 370.00 } };
|
|
|
+ const CgDetailRow g_d6[] = { { L"大米", L"斤", 50, 3.20, 160.00 }, { L"面粉", L"袋", 4, 45.00, 180.00 } };
|
|
|
+ const CgDetailRow g_d7[] = { { L"食用油", L"桶", 10, 60.00, 600.00 }, { L"生抽", L"瓶", 20, 8.50, 170.00 } };
|
|
|
+ const CgDetailRow g_d8[] = { { L"大米", L"斤", 20, 3.20, 64.00 }, { L"面粉", L"袋", 2, 45.00, 90.00 } };
|
|
|
+ const CgDetailRow g_d9[] = { { L"牛肉", L"斤", 10, 38.00, 380.00 }, { L"鸡蛋", L"斤", 20, 6.00, 120.00 } };
|
|
|
+
|
|
|
+ struct CgDocRec
|
|
|
+ {
|
|
|
+ LPCTSTR no; int status; LPCTSTR handler, time; int goods; LPCTSTR note;
|
|
|
+ const CgDetailRow* rows; int n;
|
|
|
+ };
|
|
|
+ const CgDocRec g_docs[] = {
|
|
|
+ { L"CG20261013001", CG_ST_AUDITED, L"张丽", L"2026-10-13 09:26", 5, L"含配送费,送到后厨", g_d1, 2 },
|
|
|
+ { L"CG20261012003", CG_ST_PENDING, L"王强", L"2026-10-12 15:41", 3, L"", g_d2, 2 },
|
|
|
+ { L"CG20261008002", CG_ST_REJECTED, L"李明", L"2026-10-08 11:05", 2, L"供应商缺货,已驳回", g_d3, 2 },
|
|
|
+ { L"CG20260928001", CG_ST_DONE, L"张丽", L"2026-09-28 10:12", 5, L"", g_d4, 2 },
|
|
|
+ { L"CG20260927003", CG_ST_AUDITED, L"王强", L"2026-09-27 16:38", 3, L"", g_d5, 2 },
|
|
|
+ { L"CG20260926002", CG_ST_PENDING, L"张丽", L"2026-09-26 09:47", 2, L"", g_d6, 2 },
|
|
|
+ { L"CG20260925006", CG_ST_AUDITED, L"李明", L"2026-09-25 14:22", 6, L"周末备货", g_d7, 2 },
|
|
|
+ { L"CG20260924001", CG_ST_DONE, L"王强", L"2026-09-24 11:30", 4, L"", g_d8, 2 },
|
|
|
+ { L"CG20260820003", CG_ST_AUDITED, L"张丽", L"2026-08-20 10:08", 3, L"", g_d9, 2 },
|
|
|
+ };
|
|
|
+ const int g_docs_n = (int)(sizeof(g_docs) / sizeof(g_docs[0]));
|
|
|
+
|
|
|
+ // 行元素回溯:从被点的子控件一路向上找到 ListContainerElement
|
|
|
+ CListContainerElementUI* CgFindRow(CControlUI* p)
|
|
|
+ {
|
|
|
+ while (p != NULL)
|
|
|
+ {
|
|
|
+ CListContainerElementUI* row = dynamic_cast<CListContainerElementUI*>(p);
|
|
|
+ if (row != NULL) return row;
|
|
|
+ p = p->GetParent();
|
|
|
+ }
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 整页滚动高度传播(参照 KcPropagateFixedHeightUp):写到 cg_scroll / cg_cgn_body 就停
|
|
|
+ static void CgPropagateFixedHeightUp(CControlUI* pFrom)
|
|
|
+ {
|
|
|
+ for (int guard = 0; pFrom != NULL && guard < 8; guard++)
|
|
|
+ {
|
|
|
+ CControlUI* p = pFrom->GetParent();
|
|
|
+ if (p == NULL) return;
|
|
|
+ CContainerUI* pC = dynamic_cast<CContainerUI*>(p);
|
|
|
+ if (pC == NULL) return;
|
|
|
+ LPCTSTR nm = pC->GetName();
|
|
|
+ if (nm != NULL && (_tcscmp(nm, _T("cg_scroll")) == 0 ||
|
|
|
+ _tcscmp(nm, _T("cg_cgn_body")) == 0)) return;
|
|
|
+
|
|
|
+ RECT rcIn = pC->GetInset();
|
|
|
+ int total = rcIn.top + rcIn.bottom;
|
|
|
+ int nVis = 0;
|
|
|
+ bool bOk = true;
|
|
|
+ for (int i = 0; i < pC->GetCount(); i++)
|
|
|
+ {
|
|
|
+ CControlUI* q = pC->GetItemAt(i);
|
|
|
+ if (q == NULL || !q->IsVisible() || q->IsFloat()) continue;
|
|
|
+ int ch = q->GetFixedHeight();
|
|
|
+ if (ch <= 0) ch = q->GetMaxHeight();
|
|
|
+ if (ch <= 0 || ch > 4000) { bOk = false; break; }
|
|
|
+ total += ch;
|
|
|
+ nVis++;
|
|
|
+ }
|
|
|
+ if (!bOk || nVis <= 0) return;
|
|
|
+ if (nVis > 1) total += pC->GetChildPadding() * (nVis - 1);
|
|
|
+ pC->SetFixedHeight(total);
|
|
|
+ pFrom = pC;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// ============================ 周期(自然月) ============================
|
|
|
+void CgPeriodBounds(int period, std::wstring& from, std::wstring& to)
|
|
|
+{
|
|
|
+ SYSTEMTIME st;
|
|
|
+ ::GetLocalTime(&st);
|
|
|
+ const int y = st.wYear, m = st.wMonth;
|
|
|
+ int fromY = y, fromM = m;
|
|
|
+ if (period == 1) { fromM = m - 1; if (fromM < 1) { fromM = 12; fromY = y - 1; } }
|
|
|
+ else if (period == 2) { fromM = m - 2; while (fromM < 1) { fromM += 12; fromY--; } }
|
|
|
+ const int toY = (period == 2) ? y : fromY;
|
|
|
+ const int toM = (period == 2) ? m : fromM;
|
|
|
+
|
|
|
+ int dd = 31;
|
|
|
+ switch (toM)
|
|
|
+ {
|
|
|
+ case 2: dd = ((toY % 4 == 0 && toY % 100 != 0) || toY % 400 == 0) ? 29 : 28; break;
|
|
|
+ case 4: case 6: case 9: case 11: dd = 30; break;
|
|
|
+ default: dd = 31; break;
|
|
|
+ }
|
|
|
+ wchar_t b1[16], b2[16];
|
|
|
+ swprintf_s(b1, _countof(b1), L"%04d-%02d-01", fromY, fromM);
|
|
|
+ swprintf_s(b2, _countof(b2), L"%04d-%02d-%02d", toY, toM, dd);
|
|
|
+ from = b1;
|
|
|
+ to = b2;
|
|
|
+}
|
|
|
+
|
|
|
+bool CgInPeriod(const std::wstring& date, int period)
|
|
|
+{
|
|
|
+ if (date.size() < 10) return false;
|
|
|
+ std::wstring from, to;
|
|
|
+ CgPeriodBounds(period, from, to);
|
|
|
+ const std::wstring d = date.substr(0, 10);
|
|
|
+ return d >= from && d <= to;
|
|
|
+}
|
|
|
+
|
|
|
+std::wstring CgPeriodRangeText(int period)
|
|
|
+{
|
|
|
+ std::wstring from, to;
|
|
|
+ CgPeriodBounds(period, from, to);
|
|
|
+ return from + L" ~ " + to;
|
|
|
+}
|
|
|
+
|
|
|
+// ============================ 采购订单详情访问器 ============================
|
|
|
+bool CgLookupDetail(const std::wstring& no, CgDocDetail& out)
|
|
|
+{
|
|
|
+ for (int i = 0; i < g_docs_n; i++)
|
|
|
+ {
|
|
|
+ const CgDocRec& d = g_docs[i];
|
|
|
+ if (no != d.no) continue;
|
|
|
+ out.no = d.no;
|
|
|
+ out.status = d.status;
|
|
|
+ out.handler = d.handler;
|
|
|
+ out.time = d.time;
|
|
|
+ out.goods = d.goods;
|
|
|
+ out.note = d.note;
|
|
|
+ out.rows.clear();
|
|
|
+ for (int k = 0; k < d.n; k++) out.rows.push_back(d.rows[k]);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+// ============================ CCaigouViewBase ============================
|
|
|
+CControlUI* CCaigouViewBase::Find(LPCTSTR name)
|
|
|
+{
|
|
|
+ if (m_pHost == NULL) return NULL;
|
|
|
+ return m_pHost->FindSubControl(name);
|
|
|
+}
|
|
|
+
|
|
|
+CListContainerElementUI* CCaigouViewBase::NewRow(LPCTSTR xmlfile)
|
|
|
+{
|
|
|
+ CDialogBuilder builder;
|
|
|
+ CDialogBuilderCallbackEx cb;
|
|
|
+ CControlUI* p = builder.Create(xmlfile, (UINT)0, &cb, m_pManager);
|
|
|
+ return static_cast<CListContainerElementUI*>(p);
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouViewBase::ClearList(CListUI* list)
|
|
|
+{
|
|
|
+ if (list == NULL) return;
|
|
|
+ while (list->GetCount() > 0) list->RemoveAt(0);
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouViewBase::SetRowText(CListContainerElementUI* row, LPCTSTR name, LPCTSTR text)
|
|
|
+{
|
|
|
+ if (row == NULL) return;
|
|
|
+ CLabelUI* p = static_cast<CLabelUI*>(row->FindSubControl(name));
|
|
|
+ if (p) p->SetText(text);
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouViewBase::SetRowColor(CListContainerElementUI* row, LPCTSTR name, DWORD color)
|
|
|
+{
|
|
|
+ if (row == NULL) return;
|
|
|
+ CLabelUI* p = static_cast<CLabelUI*>(row->FindSubControl(name));
|
|
|
+ if (p) p->SetTextColor(color);
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouViewBase::SetRowWidth(CListContainerElementUI* row, LPCTSTR name, int width)
|
|
|
+{
|
|
|
+ if (row == NULL) return;
|
|
|
+ CControlUI* p = row->FindSubControl(name);
|
|
|
+ if (p) p->SetFixedWidth(width);
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouViewBase::SetTag(CListContainerElementUI* row, LPCTSTR name, LPCTSTR text, int style)
|
|
|
+{
|
|
|
+ if (row == NULL) return;
|
|
|
+ CLabelUI* p = static_cast<CLabelUI*>(row->FindSubControl(name));
|
|
|
+ if (p == NULL) return;
|
|
|
+ KcApplyTag(p, std::wstring(text), style); // 底图 + 文字色(共用库存页口径)
|
|
|
+ // ⭐【R75】cg_row_rec.xml 的 tag_status 是 autocalcwidth ⇒ 状态文案换长度时
|
|
|
+ // 只 SetText 会被按旧宽度裁掉(「待审核」↔「已驳回」长度虽同为 3 字,但换别的
|
|
|
+ // 文案就会露)。补 SetFont + NeedParentUpdate,机制见 SetLabelText 注释。
|
|
|
+ p->SetFont(p->GetFont());
|
|
|
+ p->NeedParentUpdate();
|
|
|
+}
|
|
|
+
|
|
|
+// ⭐【R75】给 autocalcwidth 标签写文本的唯一正确姿势(逐字照搬库存页 SetLabel / R48)。
|
|
|
+// 已在 DuiLib 源码坐实(UILabel.cpp):SetText 虽会 NeedParentUpdate,但不置
|
|
|
+// m_bNeedEstimateSize ⇒ EstimateSize 走缓存、标签仍按旧文字宽度摆放、多出的字符被裁掉;
|
|
|
+// 只有 SetFont 会无条件置 m_bNeedEstimateSize,逼下一次布局按当前文字重新量宽。
|
|
|
+// 症状实例:键盘面板输入 555 只显示 5。
|
|
|
+void CCaigouViewBase::SetLabelText(CControlUI* p, LPCTSTR text, DWORD color)
|
|
|
+{
|
|
|
+ if (p == NULL) return;
|
|
|
+ CLabelUI* pl = static_cast<CLabelUI*>(p);
|
|
|
+ pl->SetText(text);
|
|
|
+ if (color != 0) pl->SetTextColor(color);
|
|
|
+ // ① SetFont 踢一脚 —— CLabelUI::SetFont 是唯一**无条件**置 m_bNeedEstimateSize 的
|
|
|
+ // (UILabel.cpp:74-79,无早退判断),传当前字体号即可;
|
|
|
+ // ② NeedParentUpdate 让父布局重排一次,否则新文字仍按旧宽度摆放、会被裁掉。
|
|
|
+ pl->SetFont(pl->GetFont());
|
|
|
+ pl->NeedParentUpdate();
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouViewBase::SetLabel(LPCTSTR name, LPCTSTR text, DWORD color)
|
|
|
+{
|
|
|
+ SetLabelText(Find(name), text, color);
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouViewBase::SetStatInt(LPCTSTR name, int val, LPCWSTR unit)
|
|
|
+{
|
|
|
+ std::wstring s = KcGroupInt(std::to_wstring(val));
|
|
|
+ s += L"{x 4}{c #8A9099}{f 13}"; s += unit; s += L"{/f}{/c}";
|
|
|
+ SetLabel(name, s.c_str()); // 走 SetLabel:统计卡数字位数会变(0 → 12,345)
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouViewBase::SetStatMoney(LPCTSTR name, double val, LPCWSTR unit)
|
|
|
+{
|
|
|
+ std::wstring s = L"¥" + KcFormatMoney(val);
|
|
|
+ s += L"{x 4}{c #8A9099}{f 13}"; s += unit; s += L"{/f}{/c}";
|
|
|
+ SetLabel(name, s.c_str()); // 同上:金额位数会变
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouViewBase::SetListCount(LPCTSTR labelName, int n)
|
|
|
+{
|
|
|
+ std::wstring s = L"共 "; s += std::to_wstring(n); s += L" 项";
|
|
|
+ SetLabel(labelName, s.c_str()); // 同上:项数会变(共 3 项 → 共 128 项)
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouViewBase::FitListHeight(LPCTSTR listName, int nRows, int rowH)
|
|
|
+{
|
|
|
+ CListUI* pList = FindC<CListUI>(listName);
|
|
|
+ if (pList == NULL) return;
|
|
|
+ const int HEADER_H = 44;
|
|
|
+ int rows = (nRows > 0) ? nRows : 1;
|
|
|
+ RECT rcLi = pList->GetInset();
|
|
|
+ int h = rcLi.top + rcLi.bottom + HEADER_H + rows * rowH;
|
|
|
+ pList->SetFixedHeight(h);
|
|
|
+
|
|
|
+ int nCount = pList->GetCount();
|
|
|
+ if (nCount > 0)
|
|
|
+ {
|
|
|
+ CControlUI* pLast = pList->GetItemAt(nCount - 1);
|
|
|
+ if (pLast != NULL)
|
|
|
+ {
|
|
|
+ RECT rcNoBorder = { 0, 0, 0, 0 };
|
|
|
+ pLast->SetBorderSize(rcNoBorder);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ CgPropagateFixedHeightUp(pList);
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouViewBase::AddComboItem(CComboUI* combo, LPCWSTR text)
|
|
|
+{
|
|
|
+ if (combo == NULL) return;
|
|
|
+ CListLabelElementUI* pElem = new CListLabelElementUI();
|
|
|
+ pElem->SetText(text);
|
|
|
+ combo->Add(pElem);
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouViewBase::SelectCombo(CComboUI* combo, int idx)
|
|
|
+{
|
|
|
+ if (combo == NULL) return;
|
|
|
+ combo->SelectItem(idx, false);
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouViewBase::ReadSearch(LPCTSTR editName, std::wstring& out)
|
|
|
+{
|
|
|
+ CEditUI* pEdit = FindC<CEditUI>(editName);
|
|
|
+ if (pEdit != NULL) out = (LPCTSTR)pEdit->GetText();
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouViewBase::SyncSearchTishi(LPCTSTR tishiName, LPCTSTR editName)
|
|
|
+{
|
|
|
+ CEditUI* pEdit = FindC<CEditUI>(editName);
|
|
|
+ if (pEdit == NULL) return;
|
|
|
+ CLabelUI* pTishi = FindC<CLabelUI>(tishiName);
|
|
|
+ if (pTishi == NULL) return;
|
|
|
+ pTishi->SetVisible(((LPCTSTR)pEdit->GetText())[0] == 0);
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouViewBase::StyleSeg(CButtonUI* p, bool act)
|
|
|
+{
|
|
|
+ if (p == NULL) return;
|
|
|
+ p->SetNormalImage(act ? L"file='kc_seggrn_n.png' corner='16,16,16,16'" : L"");
|
|
|
+ p->SetHotImage(act ? L"file='kc_seggrn_h.png' corner='16,16,16,16'"
|
|
|
+ : L"file='kc_seggray_h.png' corner='16,16,16,16'");
|
|
|
+ p->SetPushedImage(act ? L"file='kc_seggrn_p.png' corner='16,16,16,16'"
|
|
|
+ : L"file='kc_seggray_p.png' corner='16,16,16,16'");
|
|
|
+ p->SetFont(act ? 113 : 13);
|
|
|
+ p->SetTextColor(act ? 0xFFFFFFFF : 0xFF5F6368);
|
|
|
+ p->SetHotTextColor(act ? 0xFFFFFFFF : 0xFF2E9B5C);
|
|
|
+ p->SetPushedTextColor(act ? 0xFFFFFFFF : 0xFF2E9B5C);
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouViewBase::StylePeriodSeg(CButtonUI* p, bool act)
|
|
|
+{
|
|
|
+ if (p == NULL) return;
|
|
|
+ p->SetNormalImage(act ? L"file='kc_ovseg_on_n.png' corner='6,6,6,6'" : L"");
|
|
|
+ p->SetHotImage(act ? L"file='kc_ovseg_on_h.png' corner='6,6,6,6'"
|
|
|
+ : L"file='kc_ovseg_off_h.png' corner='6,6,6,6'");
|
|
|
+ p->SetPushedImage(act ? L"file='kc_ovseg_on_p.png' corner='6,6,6,6'"
|
|
|
+ : L"file='kc_ovseg_off_h.png' corner='6,6,6,6'");
|
|
|
+ p->SetTextColor(act ? 0xFF2E9B5C : 0xFF5F6368);
|
|
|
+ p->SetHotTextColor(0xFF2E9B5C);
|
|
|
+ p->SetPushedTextColor(0xFF2E9B5C);
|
|
|
+}
|
|
|
+
|
|
|
+// ============================ CCaigouMainView ============================
|
|
|
+void CCaigouMainView::OnInitControl()
|
|
|
+{
|
|
|
+ // 状态下拉:全部状态 / 待审核 / 已通过 / 已拒绝 / 已完成
|
|
|
+ CComboUI* pRec = FindC<CComboUI>(L"cg_rec_combo_status");
|
|
|
+ if (pRec)
|
|
|
+ {
|
|
|
+ AddComboItem(pRec, L"全部状态");
|
|
|
+ AddComboItem(pRec, L"待审核");
|
|
|
+ AddComboItem(pRec, L"已通过");
|
|
|
+ AddComboItem(pRec, L"已拒绝");
|
|
|
+ AddComboItem(pRec, L"已完成");
|
|
|
+ SelectCombo(pRec, 0);
|
|
|
+ }
|
|
|
+ // 统计态分类下拉(与添加商品同分类)
|
|
|
+ CComboUI* pStat = FindC<CComboUI>(L"cg_stat_combo_cat");
|
|
|
+ if (pStat)
|
|
|
+ {
|
|
|
+ AddComboItem(pStat, L"全部分类");
|
|
|
+ for (int i = 0; i < 6; i++) AddComboItem(pStat, CG_CATS[i]);
|
|
|
+ SelectCombo(pStat, 0);
|
|
|
+ }
|
|
|
+ SetSeg(0, false);
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouMainView::InitShow()
|
|
|
+{
|
|
|
+ RefreshOverview();
|
|
|
+ SetSeg(m_nSeg, true);
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouMainView::SetSeg(int active, bool bBuild)
|
|
|
+{
|
|
|
+ m_nSeg = (active == 1) ? 1 : 0;
|
|
|
+ CControlUI* pRec = Find(L"cg_rec_body");
|
|
|
+ CControlUI* pStat = Find(L"cg_stat_body");
|
|
|
+ CControlUI* pFrowRec = Find(L"cg_frow_rec");
|
|
|
+ CControlUI* pFrowStat = Find(L"cg_frow_stat");
|
|
|
+ if (pRec) pRec->SetVisible(m_nSeg == 0);
|
|
|
+ if (pStat) pStat->SetVisible(m_nSeg == 1);
|
|
|
+ if (pFrowRec) pFrowRec->SetVisible(m_nSeg == 0);
|
|
|
+ if (pFrowStat) pFrowStat->SetVisible(m_nSeg == 1);
|
|
|
+
|
|
|
+ StyleSeg(static_cast<CButtonUI*>(Find(L"cg_seg_rec")), m_nSeg == 0);
|
|
|
+ StyleSeg(static_cast<CButtonUI*>(Find(L"cg_seg_stat")), m_nSeg == 1);
|
|
|
+
|
|
|
+ if (bBuild)
|
|
|
+ {
|
|
|
+ if (m_nSeg == 0) BuildRecordRows();
|
|
|
+ else BuildStatRows();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouMainView::SetPeriod(int period, bool bBuild)
|
|
|
+{
|
|
|
+ m_nPeriod = (period >= 0 && period <= 2) ? period : 0;
|
|
|
+ RefreshOverview();
|
|
|
+
|
|
|
+ // 周期分段控件 + 区间文案都在本视图 host(cg_scroll) 内,自己刷选中态与文案
|
|
|
+ static const LPCTSTR kNames[3] = { L"cg_per_0", L"cg_per_1", L"cg_per_2" };
|
|
|
+ for (int i = 0; i < 3; i++)
|
|
|
+ StylePeriodSeg(static_cast<CButtonUI*>(Find(kNames[i])), i == m_nPeriod);
|
|
|
+ CControlUI* pRange = Find(L"cg_per_range");
|
|
|
+ // ⭐【R75】cg_per_range 是 autocalcwidth,且区间文案长度按周期变
|
|
|
+ // (「2026-08-17 ~ 2026-08-23」日 / 「2026-08-01 ~ 2026-08-31」月)⇒ 必须走 SetLabelText
|
|
|
+ SetLabelText(pRange, CgPeriodRangeText(m_nPeriod).c_str());
|
|
|
+
|
|
|
+ if (bBuild)
|
|
|
+ {
|
|
|
+ if (m_nSeg == 0) BuildRecordRows();
|
|
|
+ else BuildStatRows();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouMainView::RefreshOverview()
|
|
|
+{
|
|
|
+ // 当前周期内全部记录(不过滤状态/搜索)算概览带
|
|
|
+ std::vector<CgRecItem> all;
|
|
|
+ for (int i = 0; i < g_rec_n; i++)
|
|
|
+ {
|
|
|
+ if (CgInPeriod(g_rec[i].date, m_nPeriod)) all.push_back(g_rec[i]);
|
|
|
+ }
|
|
|
+ int total = (int)all.size();
|
|
|
+ double amount = 0.0;
|
|
|
+ int audit = 0, reject = 0;
|
|
|
+ for (size_t i = 0; i < all.size(); i++)
|
|
|
+ {
|
|
|
+ amount += all[i].amount;
|
|
|
+ if (all[i].status == CG_ST_PENDING) audit++;
|
|
|
+ else if (all[i].status == CG_ST_REJECTED) reject++;
|
|
|
+ }
|
|
|
+ SetStatInt(L"cg_ov_total", total, L"单");
|
|
|
+ SetStatMoney(L"cg_ov_amount", amount, L"元");
|
|
|
+ SetStatInt(L"cg_ov_audit", audit, L"单");
|
|
|
+ SetStatInt(L"cg_ov_reject", reject, L"单");
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouMainView::BuildRecordRows()
|
|
|
+{
|
|
|
+ CListUI* pList = FindC<CListUI>(L"cg_rec_list");
|
|
|
+ if (pList == NULL) return;
|
|
|
+ ClearList(pList);
|
|
|
+ m_rec.clear();
|
|
|
+
|
|
|
+ // 【R76】记录卡**不**吃 m_strSearch:筛选行里唯一的搜索框
|
|
|
+ // (cg_stat_search_edit「搜索商品名称/拼音码」)物理上属于统计卡(cg_frow_stat,
|
|
|
+ // 记录态 visible="false"),记录卡没有自己的搜索框。
|
|
|
+ // 原来这里拿 m_strSearch 去比 单号/经手人 ⇒ 在统计卡搜「米」再切到采购记录,
|
|
|
+ // 记录会被一个「商品名称」关键词按「单号/经手人」过滤掉,结果莫名其妙为空。
|
|
|
+ // 记录卡只按 周期 + 状态下拉 过滤。
|
|
|
+ for (int i = 0; i < g_rec_n; i++)
|
|
|
+ {
|
|
|
+ const CgRecItem& r = g_rec[i];
|
|
|
+ if (!CgInPeriod(r.date, m_nPeriod)) continue;
|
|
|
+ if (m_nStatus > 0 && r.status != (m_nStatus - 1)) continue; // 1 待审核 ... 4 已完成
|
|
|
+ m_rec.push_back(r);
|
|
|
+
|
|
|
+ CListContainerElementUI* row = NewRow(L"cg_row_rec.xml");
|
|
|
+ if (row == NULL) continue;
|
|
|
+ SetRowText(row, L"col_no", r.no.c_str());
|
|
|
+ SetRowText(row, L"col_time", r.date.c_str());
|
|
|
+ SetRowText(row, L"col_goods", std::to_wstring(r.goods).c_str());
|
|
|
+ SetRowText(row, L"col_amount", (L"¥" + KcFormatMoney(r.amount)).c_str());
|
|
|
+ SetRowText(row, L"col_handler", r.handler.c_str());
|
|
|
+ SetTag(row, L"tag_status", CgStatusText(r.status), CgStatusStyle(r.status));
|
|
|
+ pList->Add(row);
|
|
|
+ }
|
|
|
+
|
|
|
+ SetListCount(L"cg_rec_count", (int)m_rec.size());
|
|
|
+ // 页脚:周期 + 已显示 / 总数
|
|
|
+ CLabelUI* pFoot = FindC<CLabelUI>(L"cg_rec_foot");
|
|
|
+ if (pFoot != NULL)
|
|
|
+ {
|
|
|
+ std::wstring s = CgPeriodRangeText(m_nPeriod) + L" · 已全部加载 · 共 " +
|
|
|
+ std::to_wstring((int)m_rec.size()) + L" 条";
|
|
|
+ pFoot->SetText(s.c_str());
|
|
|
+ }
|
|
|
+ FitListHeight(L"cg_rec_list", (int)m_rec.size(), 54);
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouMainView::BuildStatRows()
|
|
|
+{
|
|
|
+ CListUI* pList = FindC<CListUI>(L"cg_stat_list");
|
|
|
+ if (pList == NULL) return;
|
|
|
+ ClearList(pList);
|
|
|
+
|
|
|
+ // 占比分母 = 本期**采购总金额**,**不随筛选变**。
|
|
|
+ // 卡片副标题写死了口径「占比 = 该商品金额 / 采购总金额」,而「采购总金额」就是概览带
|
|
|
+ // 那一格(本期全量)。若改成按筛选后的子集当分母,同一行在筛选前后占比会跳变,
|
|
|
+ // 与副标题自相矛盾。所以这里只筛「展示哪些行」,分母恒用全量。
|
|
|
+ double total = 0.0;
|
|
|
+ for (int i = 0; i < g_stat_n; i++) total += g_stat[i].amount;
|
|
|
+
|
|
|
+ // 【R76】统计卡筛选:分类下拉 + 商品名称搜索。两者都只影响**展示哪些行**。
|
|
|
+ // 原来这里两个筛选都没接 —— 下拉选「主料」列表照样显示全部 5 行
|
|
|
+ // (截图里 分类=主料 却列出 调料/主食/肉类/主料/调料,正是没生效的证据)。
|
|
|
+ const std::wstring kw = m_strSearch;
|
|
|
+
|
|
|
+ int shown = 0;
|
|
|
+ for (int i = 0; i < g_stat_n; i++)
|
|
|
+ {
|
|
|
+ const CgStatItem& s = g_stat[i];
|
|
|
+ // 分类筛选:0 = 全部分类;k>0 ⇒ CG_CATS[k-1](下拉第 0 项是「全部分类」)
|
|
|
+ if (m_nStatCat > 0 && s.cat != CG_CATS[m_nStatCat - 1]) continue;
|
|
|
+ // 商品名称搜索(搜索框提示语就是「搜索商品名称/拼音码」)
|
|
|
+ if (!kw.empty() && s.name.find(kw) == std::wstring::npos) continue;
|
|
|
+
|
|
|
+ CListContainerElementUI* row = NewRow(L"cg_row_stat.xml");
|
|
|
+ if (row == NULL) continue;
|
|
|
+ SetRowText(row, L"col_name", s.name.c_str());
|
|
|
+ SetRowText(row, L"col_cat", s.cat.c_str());
|
|
|
+ SetRowText(row, L"col_unit", s.unit.c_str());
|
|
|
+ SetRowText(row, L"col_cnt", std::to_wstring(s.orderCnt).c_str());
|
|
|
+ SetRowText(row, L"col_qty", std::to_wstring(s.qty).c_str());
|
|
|
+ SetRowText(row, L"col_amount", (L"¥" + KcFormatMoney(s.amount)).c_str());
|
|
|
+
|
|
|
+ // 占比条
|
|
|
+ int w = 0;
|
|
|
+ if (total > 1e-9) w = (int)(s.amount / total * 120.0 + 0.5);
|
|
|
+ if (w > 120) w = 120;
|
|
|
+ CControlUI* pFill = row->FindSubControl(L"bar_fill");
|
|
|
+ if (pFill) pFill->SetFixedWidth(w);
|
|
|
+ std::wstring pct = (total > 1e-9)
|
|
|
+ ? (KcFormatMoney(s.amount / total * 100.0) + L"%") : L"0%";
|
|
|
+ SetRowText(row, L"bar_pct", pct.c_str());
|
|
|
+
|
|
|
+ pList->Add(row);
|
|
|
+ shown++;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计数 / 页脚 / 列表高度全部按**筛选后**的行数算(原来硬用 g_stat_n,筛选后会虚高)
|
|
|
+ SetListCount(L"cg_stat_count", shown);
|
|
|
+ SetLabel(L"cg_stat_foot",
|
|
|
+ (L"已全部加载 · 共 " + std::to_wstring(shown) + L" 项").c_str());
|
|
|
+ FitListHeight(L"cg_stat_list", shown, 54);
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouMainView::ResetFilter()
|
|
|
+{
|
|
|
+ // 【R76】「重置」必须把**两张卡**的筛选一起清干净,并且改的是**模型**(成员)而不只是控件。
|
|
|
+ // 原来只清了记录卡的状态下拉 + 统计卡的搜索框,**漏了统计卡的分类下拉** ⇒
|
|
|
+ // 用户选完「主料」点重置,下拉还停在「主料」(本轮报的 bug)。
|
|
|
+ // 另外原来也没同步 m_nStatCat,即便把下拉 UI 拨回 0,下次 BuildStatRows 仍按旧分类过滤。
|
|
|
+
|
|
|
+ // 记录卡:状态下拉
|
|
|
+ m_nStatus = 0;
|
|
|
+ // 统计卡:分类下拉
|
|
|
+ m_nStatCat = 0;
|
|
|
+ // 两个搜索框共用 m_strSearch(当前只有统计卡一个搜索框),一并清空
|
|
|
+ m_strSearch.clear();
|
|
|
+
|
|
|
+ CComboUI* pRec = FindC<CComboUI>(L"cg_rec_combo_status");
|
|
|
+ if (pRec) SelectCombo(pRec, 0);
|
|
|
+ CComboUI* pStat = FindC<CComboUI>(L"cg_stat_combo_cat");
|
|
|
+ if (pStat) SelectCombo(pStat, 0); // ⭐ 分类下拉回到「全部分类」
|
|
|
+
|
|
|
+ CEditUI* pEdit = FindC<CEditUI>(L"cg_stat_search_edit");
|
|
|
+ if (pEdit) pEdit->SetText(L"");
|
|
|
+ SyncSearchTishi(L"cg_stat_search_tishi", L"cg_stat_search_edit");
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouMainView::ApplyRowFilter()
|
|
|
+{
|
|
|
+ // 真实接口前:内存已全量,重查即可(状态 / 分类 / 搜索都在 Build*Rows 内判)。
|
|
|
+ // ⭐【R76】要重刷**当前可见**的那张卡 —— 原来只无条件 BuildRecordRows(),
|
|
|
+ // 导致站在「采购统计」页点「查询 / 重置」时统计列表纹丝不动(下拉改了、行没变)。
|
|
|
+ // 切卡时 SetSeg() 会各自重建一次,所以这里只需管可见的那张。
|
|
|
+ if (m_nSeg == 0) BuildRecordRows();
|
|
|
+ else BuildStatRows();
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouMainView::OnClick(TNotifyUI& msg)
|
|
|
+{
|
|
|
+ std::wstring n = (LPCTSTR)msg.pSender->GetName();
|
|
|
+ if (n == L"cg_seg_rec") { SetSeg(0); return; }
|
|
|
+ if (n == L"cg_seg_stat") { SetSeg(1); return; }
|
|
|
+ if (n == L"cg_per_0") { SetPeriod(0); return; }
|
|
|
+ if (n == L"cg_per_1") { SetPeriod(1); return; }
|
|
|
+ if (n == L"cg_per_2") { SetPeriod(2); return; }
|
|
|
+ if (n == L"cg_rec_new_btn") { /* 宿主拦截,进新建态 */ return; }
|
|
|
+ if (n == L"cg_stat_new_btn") { /* 宿主拦截 */ return; }
|
|
|
+ if (n == L"cg_stat_query_btn" || n == L"cg_stat_reset_btn")
|
|
|
+ {
|
|
|
+ if (n == L"cg_stat_reset_btn") ResetFilter();
|
|
|
+ ApplyRowFilter();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (n == L"op_detail" || n == L"op_print")
|
|
|
+ {
|
|
|
+ // 记录行操作:交给宿主开详情弹框(宿主能拿到 m_pMainWnd)
|
|
|
+ return;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouMainView::OnItemSelect(TNotifyUI& msg)
|
|
|
+{
|
|
|
+ std::wstring n = (LPCTSTR)msg.pSender->GetName();
|
|
|
+ if (n == L"cg_rec_combo_status")
|
|
|
+ {
|
|
|
+ CComboUI* p = static_cast<CComboUI*>(msg.pSender);
|
|
|
+ m_nStatus = p->GetCurSel();
|
|
|
+ BuildRecordRows();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (n == L"cg_stat_combo_cat")
|
|
|
+ {
|
|
|
+ // 【R76】统计分类筛选:先落到成员(m_nStatCat),再按它重建。
|
|
|
+ // 原来只 BuildStatRows() 不存状态 —— 于是「重置」就算把下拉拨回 0,
|
|
|
+ // 也没人能告诉 BuildStatRows 该按什么分类过滤。
|
|
|
+ // 与记录卡的状态下拉同策略:选完即生效(不要求再点「查询」)。
|
|
|
+ CComboUI* p = static_cast<CComboUI*>(msg.pSender);
|
|
|
+ m_nStatCat = p->GetCurSel();
|
|
|
+ BuildStatRows();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouMainView::OnTextChanged(TNotifyUI& msg)
|
|
|
+{
|
|
|
+ std::wstring n = (LPCTSTR)msg.pSender->GetName();
|
|
|
+ if (n == L"cg_stat_search_edit")
|
|
|
+ {
|
|
|
+ ReadSearch(L"cg_stat_search_edit", m_strSearch);
|
|
|
+ SyncSearchTishi(L"cg_stat_search_tishi", L"cg_stat_search_edit");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouMainView::SubmitSearch()
|
|
|
+{
|
|
|
+ BuildRecordRows();
|
|
|
+}
|
|
|
+
|
|
|
+// ============================ CCaigouNewView(新建采购单) ============================
|
|
|
+void CCaigouNewView::OnInitControl()
|
|
|
+{
|
|
|
+ // 备注框是常驻原生 Edit,皮肤已铺好;此处无需额外初始化
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouNewView::InitShow()
|
|
|
+{
|
|
|
+ SeedLines();
|
|
|
+ BuildRows();
|
|
|
+ RefreshTot();
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouNewView::SeedLines()
|
|
|
+{
|
|
|
+ m_lines.clear();
|
|
|
+ // 初始塞 3 条样例商品(取自商品档案前 3 项)
|
|
|
+ const std::vector<KcGoods>& all = KcAllGoods();
|
|
|
+ for (int i = 0; i < 3 && i < (int)all.size(); i++)
|
|
|
+ {
|
|
|
+ CgEditLine ln;
|
|
|
+ ln.name = all[i].name;
|
|
|
+ ln.cat = all[i].cat;
|
|
|
+ ln.unit = all[i].unit;
|
|
|
+ ln.qty = L"1";
|
|
|
+ ln.price = KcFormatMoney(all[i].price);
|
|
|
+ m_lines.push_back(ln);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouNewView::BuildRows()
|
|
|
+{
|
|
|
+ CListUI* pList = FindC<CListUI>(ListName());
|
|
|
+ if (pList == NULL) return;
|
|
|
+ ClearList(pList);
|
|
|
+ for (size_t i = 0; i < m_lines.size(); i++)
|
|
|
+ {
|
|
|
+ CListContainerElementUI* row = NewRow(RowXml());
|
|
|
+ if (row == NULL) continue;
|
|
|
+ // 单元格控件按行号重命名,便于键盘回填时精准定位(沿用 kc 的 <前缀>_<列>_<行> 约定)
|
|
|
+ CControlUI* pQty = row->FindSubControl(L"cell_qty");
|
|
|
+ CControlUI* pPrice = row->FindSubControl(L"cell_price");
|
|
|
+ CControlUI* pDel = row->FindSubControl(L"btn_del");
|
|
|
+ if (pQty) pQty->SetName((PrefixW() + L"_qty_" + std::to_wstring(i)).c_str());
|
|
|
+ if (pPrice) pPrice->SetName((PrefixW() + L"_price_" + std::to_wstring(i)).c_str());
|
|
|
+ if (pDel) pDel->SetName((PrefixW() + L"_del_" + std::to_wstring(i)).c_str());
|
|
|
+ pList->Add(row);
|
|
|
+ }
|
|
|
+ for (size_t i = 0; i < m_lines.size(); i++) RefreshRow((int)i);
|
|
|
+ SyncTableHeight();
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouNewView::RefreshRow(int i)
|
|
|
+{
|
|
|
+ if (i < 0 || i >= (int)m_lines.size()) return;
|
|
|
+ CListUI* pList = FindC<CListUI>(ListName());
|
|
|
+ if (pList == NULL) return;
|
|
|
+ CListContainerElementUI* row = static_cast<CListContainerElementUI*>(pList->GetItemAt(i));
|
|
|
+ if (row == NULL) return;
|
|
|
+ const CgEditLine& ln = m_lines[i];
|
|
|
+
|
|
|
+ SetRowText(row, L"col_name", ln.name.c_str());
|
|
|
+ SetRowText(row, L"col_cat", ln.cat.c_str());
|
|
|
+ SetRowText(row, L"col_unit", ln.unit.c_str());
|
|
|
+
|
|
|
+ CControlUI* pQty = row->FindSubControl((PrefixW() + L"_qty_" + std::to_wstring(i)).c_str());
|
|
|
+ CControlUI* pPrice = row->FindSubControl((PrefixW() + L"_price_" + std::to_wstring(i)).c_str());
|
|
|
+ if (pQty) pQty->SetText(ln.qty.c_str());
|
|
|
+ if (pPrice) pPrice->SetText(ln.price.c_str());
|
|
|
+
|
|
|
+ // 金额 = 数量 * 单价
|
|
|
+ double q = 0, p = 0;
|
|
|
+ q = _wtof(ln.qty.c_str());
|
|
|
+ p = _wtof(ln.price.c_str());
|
|
|
+ double amt = q * p;
|
|
|
+ SetRowText(row, L"col_amount", (L"¥" + KcFormatMoney(amt)).c_str());
|
|
|
+
|
|
|
+ // 边框色跟着数量走:编辑中绿 / 采购数量为 0 琥珀 / 常态白
|
|
|
+ ApplyCellStyle(i, 0);
|
|
|
+ ApplyCellStyle(i, 1);
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouNewView::RefreshTot()
|
|
|
+{
|
|
|
+ int goods = (int)m_lines.size();
|
|
|
+ int qty = 0;
|
|
|
+ double amt = 0.0;
|
|
|
+ for (size_t i = 0; i < m_lines.size(); i++)
|
|
|
+ {
|
|
|
+ qty += (int)(_wtof(m_lines[i].qty.c_str()) + 1e-9);
|
|
|
+ amt += _wtof(m_lines[i].qty.c_str()) * _wtof(m_lines[i].price.c_str());
|
|
|
+ }
|
|
|
+ // 合计条三格 + 提示行都是 autocalcwidth ⇒ 一律走 SetLabel(只 SetText 会被按旧宽度裁掉)
|
|
|
+ SetLabel(L"cg_cgn_tot_goods", std::to_wstring(goods).c_str());
|
|
|
+ SetLabel(L"cg_cgn_tot_qty", std::to_wstring(qty).c_str());
|
|
|
+ SetLabel(L"cg_cgn_tot_amt", (L"¥" + KcFormatMoney(amt)).c_str());
|
|
|
+ SetLabel(L"cg_cgn_tip",
|
|
|
+ (L"已添加 " + std::to_wstring(goods) + L" 个商品 · 点「添加商品」勾选更多,或直接扫条码追加").c_str());
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouNewView::SyncTableHeight()
|
|
|
+{
|
|
|
+ FitListHeight(ListName(), (int)m_lines.size(), 56);
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouNewView::DeleteLine(int idx)
|
|
|
+{
|
|
|
+ if (idx < 0 || idx >= (int)m_lines.size()) return;
|
|
|
+ m_lines.erase(m_lines.begin() + idx);
|
|
|
+ CloseKeypad();
|
|
|
+ BuildRows();
|
|
|
+ RefreshTot();
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouNewView::AppendPicked(const std::vector<std::wstring>& names)
|
|
|
+{
|
|
|
+ for (size_t k = 0; k < names.size(); k++)
|
|
|
+ {
|
|
|
+ // 已在明细里的去重
|
|
|
+ bool dup = false;
|
|
|
+ for (size_t j = 0; j < m_lines.size(); j++)
|
|
|
+ {
|
|
|
+ if (m_lines[j].name == names[k]) { dup = true; break; }
|
|
|
+ }
|
|
|
+ if (dup) continue;
|
|
|
+
|
|
|
+ KcGoods g;
|
|
|
+ CgEditLine ln;
|
|
|
+ ln.name = names[k];
|
|
|
+ if (KcLookupGoods(names[k], g))
|
|
|
+ {
|
|
|
+ ln.cat = g.cat;
|
|
|
+ ln.unit = g.unit;
|
|
|
+ ln.price = KcFormatMoney(g.price);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ ln.cat = L""; ln.unit = L""; ln.price = L"0.00";
|
|
|
+ }
|
|
|
+ ln.qty = L"1";
|
|
|
+ m_lines.push_back(ln);
|
|
|
+ }
|
|
|
+ BuildRows();
|
|
|
+ RefreshTot();
|
|
|
+}
|
|
|
+
|
|
|
+// ---- 明细可编辑单元格的底图(三态:常态白 / 编辑中绿 / 采购数量为 0 琥珀)----
|
|
|
+// 全部复用现网资产:input_r8_*(常态)、btn_r8_green_*(编辑中)、btn_r8_org_*(数量为 0)。
|
|
|
+// 零新增美术资源;也绝不动全工程共用的 btn_r8_green/red_*。
|
|
|
+static const wchar_t* CG_CELL_N = L"file='input_r8_n.png' corner='8,8,8,8'";
|
|
|
+static const wchar_t* CG_CELL_H = L"file='input_r8_h.png' corner='8,8,8,8'";
|
|
|
+static const wchar_t* CG_CELL_P = L"file='input_r8_n.png' corner='8,8,8,8'";
|
|
|
+static const wchar_t* CG_CELL_EN = L"file='btn_r8_green_n.png' corner='8,8,8,8'";
|
|
|
+static const wchar_t* CG_CELL_EH = L"file='btn_r8_green_h.png' corner='8,8,8,8'";
|
|
|
+static const wchar_t* CG_CELL_EP = L"file='btn_r8_green_p.png' corner='8,8,8,8'";
|
|
|
+static const wchar_t* CG_CELL_ZN = L"file='btn_r8_org_n.png' corner='8,8,8,8'";
|
|
|
+static const wchar_t* CG_CELL_ZH = L"file='btn_r8_org_h.png' corner='8,8,8,8'";
|
|
|
+static const wchar_t* CG_CELL_ZP = L"file='btn_r8_org_p.png' corner='8,8,8,8'";
|
|
|
+
|
|
|
+// 键盘面板 cg_keypad / 底栏 cg_new_foot 是 cg_view_order_new 的**兄弟**(同挂 cg_page),
|
|
|
+// 所以 cg_kp_* / cg_cgn_foot_* 这些控件不在本视图子树里。依次在
|
|
|
+// 本视图 → 键盘面板 → 键盘面板父级(cg_page)里查,才能找到(否则键盘数值显示不刷新)。
|
|
|
+CControlUI* CCaigouNewView::Find(LPCTSTR name)
|
|
|
+{
|
|
|
+ CControlUI* p = CCaigouViewBase::Find(name);
|
|
|
+ if (p == NULL && m_pKpHost != NULL) p = m_pKpHost->FindSubControl(name);
|
|
|
+ if (p == NULL && m_pKpHost != NULL)
|
|
|
+ {
|
|
|
+ CContainerUI* pPar = static_cast<CContainerUI*>(m_pKpHost->GetParent());
|
|
|
+ if (pPar != NULL) p = pPar->FindSubControl(name);
|
|
|
+ }
|
|
|
+ return p;
|
|
|
+}
|
|
|
+
|
|
|
+// 数量为 0 判定:空串**不算** 0(采购页不存在「未录」,空只在中间态出现)
|
|
|
+bool CCaigouNewView::IsQtyZero(int i) const
|
|
|
+{
|
|
|
+ if (i < 0 || i >= (int)m_lines.size()) return false;
|
|
|
+ const std::wstring& q = m_lines[i].qty;
|
|
|
+ if (q.empty()) return false;
|
|
|
+ return _wtof(q.c_str()) <= 0.0;
|
|
|
+}
|
|
|
+
|
|
|
+// 单元格底图 / 文字色:编辑中(绿) > 数量为 0(琥珀) > 常态(白)。
|
|
|
+void CCaigouNewView::ApplyCellStyle(int i, int col)
|
|
|
+{
|
|
|
+ if (i < 0 || i >= (int)m_lines.size()) return;
|
|
|
+ const std::wstring nm =
|
|
|
+ PrefixW() + ((col == 0) ? L"_qty_" : L"_price_") + std::to_wstring(i);
|
|
|
+ CButtonUI* p = FindC<CButtonUI>(nm.c_str());
|
|
|
+ if (p == NULL) return;
|
|
|
+
|
|
|
+ const bool bEditing = (m_nEditRow == i && m_nEditCol == col);
|
|
|
+ const bool bZero = (col == 0) && (!bEditing) && IsQtyZero(i);
|
|
|
+
|
|
|
+ const wchar_t* n = CG_CELL_N;
|
|
|
+ const wchar_t* h = CG_CELL_H;
|
|
|
+ const wchar_t* pu = CG_CELL_P;
|
|
|
+ DWORD tc = 0xFF1F2329;
|
|
|
+ if (bEditing) { n = CG_CELL_EN; h = CG_CELL_EH; pu = CG_CELL_EP; tc = 0xFF2E9B5C; }
|
|
|
+ else if (bZero) { n = CG_CELL_ZN; h = CG_CELL_ZH; pu = CG_CELL_ZP; tc = KC_COLOR_WARN; }
|
|
|
+
|
|
|
+ p->SetNormalImage(n);
|
|
|
+ p->SetHotImage(h);
|
|
|
+ p->SetPushedImage(pu);
|
|
|
+ p->SetTextColor(tc);
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouNewView::ApplyAllCellStyles()
|
|
|
+{
|
|
|
+ for (int i = 0; i < (int)m_lines.size(); i++)
|
|
|
+ {
|
|
|
+ ApplyCellStyle(i, 0);
|
|
|
+ ApplyCellStyle(i, 1);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 「不存在空」:键盘清空 / 删空之后把缓冲补成 0(与入库同口径;采购页没有「未录」态)
|
|
|
+void CCaigouNewView::NormalizeBuf()
|
|
|
+{
|
|
|
+ if (m_editBuf.empty()) m_editBuf = L"0";
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouNewView::CloseKeypad()
|
|
|
+{
|
|
|
+ if (m_pKpHost != NULL) m_pKpHost->SetVisible(false);
|
|
|
+ m_nEditRow = -1;
|
|
|
+ m_nEditCol = 0;
|
|
|
+ m_editBuf.clear();
|
|
|
+ if (m_pKpHost != NULL) KcSyncNativeEditsIn(m_pKpHost);
|
|
|
+ KcSyncNativeEditsIn(m_pHost);
|
|
|
+ ApplyAllCellStyles(); // 收起后清掉「编辑中」绿框
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouNewView::OpenKeypad(int row, int col)
|
|
|
+{
|
|
|
+ if (row < 0 || row >= (int)m_lines.size()) return;
|
|
|
+ m_nEditRow = row;
|
|
|
+ m_nEditCol = col;
|
|
|
+ m_editBuf = (col == 0) ? m_lines[row].qty : m_lines[row].price;
|
|
|
+ NormalizeBuf();
|
|
|
+
|
|
|
+ if (m_pKpHost != NULL) m_pKpHost->SetVisible(true);
|
|
|
+ KeypadRefresh();
|
|
|
+ ApplyAllCellStyles();
|
|
|
+ // 键盘挤占主体高度 ⇒ 主体内的常驻原生 Edit(备注)要重新定位,否则会停在旧位置
|
|
|
+ KcSyncNativeEditsIn(m_pHost);
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouNewView::KeypadRefresh()
|
|
|
+{
|
|
|
+ // ⭐【R75】cg_kp_value / cg_kp_unit 都是 autocalcwidth 标签,写文本必须走 SetLabel
|
|
|
+ // (SetText + SetFont(GetFont()) + NeedParentUpdate())。
|
|
|
+ // 只调 SetText 的话,标签宽度停留在上一次文字算出的值 ⇒ 输入 555 时宽度仍是 "5"
|
|
|
+ // 的宽度,后两位被裁掉(用户反馈「输入 555 只显示第一个数字」就是这个原因)。
|
|
|
+ SetLabel(L"cg_kp_field", m_nEditCol == 0 ? L"采购数量" : L"单价");
|
|
|
+ SetLabel(L"cg_kp_value", m_editBuf.empty() ? L"0" : m_editBuf.c_str());
|
|
|
+ if (m_nEditRow >= 0 && m_nEditRow < (int)m_lines.size())
|
|
|
+ SetLabel(L"cg_kp_unit", m_lines[m_nEditRow].unit.c_str());
|
|
|
+ else
|
|
|
+ SetLabel(L"cg_kp_unit", L"");
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouNewView::KpDigit(LPCTSTR t)
|
|
|
+{
|
|
|
+ if (m_nEditRow < 0) return;
|
|
|
+ if (m_editBuf == L"0") m_editBuf.clear();
|
|
|
+ if (m_editBuf.size() + wcslen(t) > 12) return;
|
|
|
+ m_editBuf += t;
|
|
|
+ KeypadRefresh();
|
|
|
+ KpApply(); // 实时写回明细行(与入库同逻辑:每按一键即生效)
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouNewView::KpDot()
|
|
|
+{
|
|
|
+ if (m_nEditRow < 0) return;
|
|
|
+ if (m_nEditCol != 1) return; // 只有单价允许小数
|
|
|
+ if (m_editBuf.find(L".") != std::wstring::npos) return;
|
|
|
+ if (m_editBuf.empty()) m_editBuf = L"0";
|
|
|
+ m_editBuf += L".";
|
|
|
+ KeypadRefresh();
|
|
|
+ KpApply();
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouNewView::KpDel()
|
|
|
+{
|
|
|
+ if (m_nEditRow < 0) return;
|
|
|
+ if (!m_editBuf.empty()) m_editBuf.erase(m_editBuf.size() - 1);
|
|
|
+ NormalizeBuf();
|
|
|
+ KeypadRefresh();
|
|
|
+ KpApply();
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouNewView::KpClear()
|
|
|
+{
|
|
|
+ if (m_nEditRow < 0) return;
|
|
|
+ m_editBuf.clear();
|
|
|
+ NormalizeBuf();
|
|
|
+ KeypadRefresh();
|
|
|
+ KpApply();
|
|
|
+}
|
|
|
+
|
|
|
+// 把键盘缓冲**实时**写回明细:每按一键就生效,不等点「关闭」。
|
|
|
+// 写 m_lines → 刷本行单元格(含金额 / 边框色)→ 刷合计条。
|
|
|
+void CCaigouNewView::KpApply()
|
|
|
+{
|
|
|
+ if (m_nEditRow < 0 || m_nEditRow >= (int)m_lines.size()) return;
|
|
|
+ NormalizeBuf();
|
|
|
+ if (m_nEditCol == 0) m_lines[m_nEditRow].qty = m_editBuf;
|
|
|
+ else m_lines[m_nEditRow].price = m_editBuf;
|
|
|
+ RefreshRow(m_nEditRow);
|
|
|
+ RefreshTot();
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouNewView::KpCommit()
|
|
|
+{
|
|
|
+ KpApply();
|
|
|
+ CloseKeypad();
|
|
|
+}
|
|
|
+
|
|
|
+// 保存前数量校验(口径同入库):采集「采购数量为空 / ≤ 0」的行
|
|
|
+void CCaigouNewView::CollectQtyIssues(std::vector<KcQtyIssue>& out) const
|
|
|
+{
|
|
|
+ for (int i = 0; i < (int)m_lines.size(); i++)
|
|
|
+ {
|
|
|
+ const std::wstring& q = m_lines[i].qty;
|
|
|
+ if (!q.empty() && _wtof(q.c_str()) > 0.0) continue;
|
|
|
+
|
|
|
+ KcQtyIssue it;
|
|
|
+ it.row = i;
|
|
|
+ it.name = m_lines[i].name;
|
|
|
+ it.field = L"采购数量";
|
|
|
+ it.unfilled = false;
|
|
|
+ out.push_back(it);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouNewView::OnClick(TNotifyUI& msg)
|
|
|
+{
|
|
|
+ std::wstring n = (LPCTSTR)msg.pSender->GetName();
|
|
|
+
|
|
|
+ // 数字键盘
|
|
|
+ if (n == L"cg_kp_ok") { KpCommit(); return; }
|
|
|
+ if (n == L"cg_kp_del") { KpDel(); return; }
|
|
|
+ if (n == L"cg_kp_clr") { KpClear(); return; }
|
|
|
+ if (n == L"cg_kp_kdot") { KpDot(); return; }
|
|
|
+ if (n.size() >= 7 && n.compare(0, 7, L"cg_kp_k") == 0)
|
|
|
+ {
|
|
|
+ // cg_kp_k1..k9 / cg_kp_k0 / cg_kp_k00:数字来自按钮文本
|
|
|
+ // ("_kdot" 已在上面精确匹配并 return,不会误入这里)
|
|
|
+ std::wstring d = (LPCTSTR)msg.pSender->GetText();
|
|
|
+ if (!d.empty()) KpDigit(d.c_str());
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 明细行:数量 / 单价单元格 → 数字键盘;行尾删除按钮 → 删行。
|
|
|
+ // 判定用 tail = 控件名去掉 <前缀> 之后的部分(形如 "_qty_3" / "_price_3" / "_del_3"),
|
|
|
+ // 不要用「前缀长度 + 常数」硬算 substr 长度 —— _qty_ / _del_ 是 5 字符、_price_ 是 7 字符,
|
|
|
+ // 常数写错一位就会让匹配恒失败(表现为「点数量和单价单元格没反应」)。
|
|
|
+ // 与库存页 CKucunEditViewBase::OnClick 同法。
|
|
|
+ CListContainerElementUI* row = CgFindRow(msg.pSender);
|
|
|
+ if (row != NULL)
|
|
|
+ {
|
|
|
+ CListUI* pList = FindC<CListUI>(ListName());
|
|
|
+ int idx = (pList != NULL) ? pList->GetItemIndex(row) : -1;
|
|
|
+ if (idx >= 0)
|
|
|
+ {
|
|
|
+ const std::wstring pfx = PrefixW();
|
|
|
+ const std::wstring tail =
|
|
|
+ (n.size() > pfx.size()) ? n.substr(pfx.size()) : std::wstring();
|
|
|
+ if (tail.compare(0, 5, L"_qty_") == 0) { OpenKeypad(idx, 0); return; }
|
|
|
+ if (tail.compare(0, 7, L"_price_") == 0) { OpenKeypad(idx, 1); return; }
|
|
|
+ if (tail.compare(0, 5, L"_del_") == 0) { DeleteLine(idx); return; }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// ============================ CCaigouDetailWnd ============================
|
|
|
+namespace
|
|
|
+{
|
|
|
+ CLabelUI* CgDFind(CPaintManagerUI& pm, LPCTSTR name)
|
|
|
+ {
|
|
|
+ return static_cast<CLabelUI*>(pm.FindControl(name));
|
|
|
+ }
|
|
|
+ void CgDSet(CPaintManagerUI& pm, LPCTSTR name, const std::wstring& text)
|
|
|
+ {
|
|
|
+ CLabelUI* p = CgDFind(pm, name);
|
|
|
+ if (p == NULL) return;
|
|
|
+ p->SetText(text.c_str());
|
|
|
+ // ⭐【R75】cg_doc_detail_wnd.xml 的 kd_title / kd_sub / kd_v1~v6 / kd_sum_amt 全是
|
|
|
+ // autocalcwidth ⇒ 只 SetText 会被按旧宽度裁掉(单号/金额位数一变就露)。
|
|
|
+ // 与 CgDValue 同口径补 SetFont + NeedParentUpdate。
|
|
|
+ p->SetFont(p->GetFont());
|
|
|
+ p->NeedParentUpdate();
|
|
|
+ }
|
|
|
+ void CgDValue(CPaintManagerUI& pm, LPCTSTR name, const std::wstring& text, int tag)
|
|
|
+ {
|
|
|
+ CLabelUI* p = CgDFind(pm, name);
|
|
|
+ if (p == NULL) return;
|
|
|
+ if (tag >= 0) KcApplyTag(p, text, tag);
|
|
|
+ else { p->SetBkImage(L""); p->SetText(text.c_str()); p->SetTextColor(0xFF1F2329); }
|
|
|
+ p->SetFont(p->GetFont());
|
|
|
+ }
|
|
|
+ CListContainerElementUI* CgDNewRow(CPaintManagerUI* pm, LPCTSTR xmlfile)
|
|
|
+ {
|
|
|
+ CDialogBuilder builder;
|
|
|
+ CDialogBuilderCallbackEx cb;
|
|
|
+ CControlUI* p = builder.Create(xmlfile, (UINT)0, &cb, pm);
|
|
|
+ return static_cast<CListContainerElementUI*>(p);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+LRESULT CCaigouDetailWnd::OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
|
+{
|
|
|
+ POINT pt; pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam);
|
|
|
+ ::ScreenToClient(*this, &pt);
|
|
|
+ RECT rcClient; ::GetClientRect(*this, &rcClient);
|
|
|
+ RECT rcCaption = m_pm.GetCaptionRect();
|
|
|
+ if (pt.x >= rcClient.left + rcCaption.left && pt.x < rcClient.right - rcCaption.right
|
|
|
+ && pt.y >= rcCaption.top && pt.y < rcCaption.bottom)
|
|
|
+ {
|
|
|
+ CControlUI* pControl = static_cast<CControlUI*>(m_pm.FindControl(pt));
|
|
|
+ if (pControl && _tcscmp(pControl->GetClass(), L"ButtonUI") != 0) return HTCAPTION;
|
|
|
+ }
|
|
|
+ return HTCLIENT;
|
|
|
+}
|
|
|
+
|
|
|
+LRESULT CCaigouDetailWnd::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
|
+{
|
|
|
+ SIZE szRoundCorner = m_pm.GetRoundCorner();
|
|
|
+ if (!::IsIconic(*this) && (szRoundCorner.cx != 0 || szRoundCorner.cy != 0))
|
|
|
+ {
|
|
|
+ CDuiRect rcWnd; ::GetWindowRect(*this, &rcWnd);
|
|
|
+ rcWnd.Offset(-rcWnd.left, -rcWnd.top); rcWnd.right++; rcWnd.bottom++;
|
|
|
+ HRGN hRgn = ::CreateRoundRectRgn(rcWnd.left, rcWnd.top, rcWnd.right, rcWnd.bottom, szRoundCorner.cx, szRoundCorner.cy);
|
|
|
+ ::SetWindowRgn(*this, hRgn, TRUE); ::DeleteObject(hRgn);
|
|
|
+ }
|
|
|
+ bHandled = FALSE;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+LRESULT CCaigouDetailWnd::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
|
+{
|
|
|
+ LRESULT lRes = 0; BOOL bHandled = TRUE;
|
|
|
+ switch (uMsg)
|
|
|
+ {
|
|
|
+ case WM_CREATE: lRes = OnCreate(uMsg, wParam, lParam, bHandled); break;
|
|
|
+ case WM_NCACTIVATE: lRes = OnNcActivate(uMsg, wParam, lParam, bHandled); break;
|
|
|
+ case WM_NCCALCSIZE: lRes = OnNcCalcSize(uMsg, wParam, lParam, bHandled); break;
|
|
|
+ case WM_NCPAINT: lRes = OnNcPaint(uMsg, wParam, lParam, bHandled); break;
|
|
|
+ case WM_NCHITTEST: lRes = OnNcHitTest(uMsg, wParam, lParam, bHandled); break;
|
|
|
+ case WM_SIZE: lRes = OnSize(uMsg, wParam, lParam, bHandled); break;
|
|
|
+ case WM_KEYDOWN:
|
|
|
+ if (wParam == VK_ESCAPE) { Close(IDCANCEL); return TRUE; }
|
|
|
+ bHandled = FALSE; break;
|
|
|
+ default: bHandled = FALSE;
|
|
|
+ }
|
|
|
+ if (bHandled) return lRes;
|
|
|
+ if (m_pm.MessageHandler(uMsg, wParam, lParam, lRes)) return lRes;
|
|
|
+ return CWindowWnd::HandleMessage(uMsg, wParam, lParam);
|
|
|
+}
|
|
|
+
|
|
|
+LRESULT CCaigouDetailWnd::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
|
|
|
+{
|
|
|
+ LONG styleValue = ::GetWindowLong(*this, GWL_STYLE);
|
|
|
+ styleValue &= ~WS_CAPTION;
|
|
|
+ ::SetWindowLong(*this, GWL_STYLE, styleValue | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
|
|
|
+
|
|
|
+ m_pm.Init(m_hWnd);
|
|
|
+ m_pm.AddPreMessageFilter(this);
|
|
|
+
|
|
|
+ CDialogBuilder builder;
|
|
|
+ CControlUI* pRoot = builder.Create(_T("cg_doc_detail_wnd.xml"), (UINT)0, NULL, &m_pm);
|
|
|
+ ASSERT(pRoot && "CCaigouDetailWnd: 皮肤 XML 解析失败");
|
|
|
+ m_pm.AttachDialog(pRoot);
|
|
|
+ m_pm.AddNotifier(this);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouDetailWnd::Notify(TNotifyUI& msg)
|
|
|
+{
|
|
|
+ if (msg.sType != _T("click")) return;
|
|
|
+ std::wstring n = (LPCTSTR)msg.pSender->GetName();
|
|
|
+ if (n == L"kd_close" || n == L"kd_btn_close") { Close(IDCANCEL); return; }
|
|
|
+ if (n == L"kd_btn_print") { m_bPrint = true; Close(IDOK); return; }
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouDetailWnd::LoadDetail()
|
|
|
+{
|
|
|
+ FillInfo();
|
|
|
+ FillRows();
|
|
|
+ FillSum();
|
|
|
+
|
|
|
+ int n = (int)m_doc.rows.size();
|
|
|
+ int rows = (n > 0) ? n : 1;
|
|
|
+ CControlUI* pCard = m_pm.FindControl(L"kd_tblcard");
|
|
|
+ if (pCard != NULL) pCard->SetFixedHeight(45 + 52 * rows + 10);
|
|
|
+
|
|
|
+ ::SetWindowPos(m_hWnd, NULL, 0, 0, 660, WindowHeightFor(n),
|
|
|
+ SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouDetailWnd::FillInfo()
|
|
|
+{
|
|
|
+ CgDSet(m_pm, L"kd_title", L"采购订单详情");
|
|
|
+ CgDSet(m_pm, L"kd_sub", L"采购单详情");
|
|
|
+
|
|
|
+ CgDSet(m_pm, L"kd_l1", L"采购单号");
|
|
|
+ CgDSet(m_pm, L"kd_v1", m_doc.no);
|
|
|
+ CgDSet(m_pm, L"kd_l2", L"状态");
|
|
|
+ CgDValue(m_pm, L"kd_v2", CgStatusText(m_doc.status), CgStatusStyle(m_doc.status));
|
|
|
+ CgDSet(m_pm, L"kd_l3", L"经手人");
|
|
|
+ CgDSet(m_pm, L"kd_v3", m_doc.handler);
|
|
|
+ CgDSet(m_pm, L"kd_l4", L"下单时间");
|
|
|
+ CgDSet(m_pm, L"kd_v4", m_doc.time);
|
|
|
+ CgDSet(m_pm, L"kd_l5", L"商品数");
|
|
|
+ CgDSet(m_pm, L"kd_v5", std::to_wstring(m_doc.goods) + L" 项");
|
|
|
+ CgDSet(m_pm, L"kd_l6", L"备注");
|
|
|
+ CgDSet(m_pm, L"kd_v6", m_doc.note.empty() ? L"—" : m_doc.note);
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouDetailWnd::FillRows()
|
|
|
+{
|
|
|
+ CListUI* pList = static_cast<CListUI*>(m_pm.FindControl(L"kd_list"));
|
|
|
+ if (pList == NULL) return;
|
|
|
+ while (pList->GetCount() > 0) pList->RemoveAt(0);
|
|
|
+
|
|
|
+ for (size_t i = 0; i < m_doc.rows.size(); i++)
|
|
|
+ {
|
|
|
+ const CgDetailRow& r = m_doc.rows[i];
|
|
|
+ CListContainerElementUI* row = CgDNewRow(&m_pm, L"cg_row_doc_detail.xml");
|
|
|
+ if (row == NULL) continue;
|
|
|
+ CLabelUI* pName = static_cast<CLabelUI*>(row->FindSubControl(L"col_name"));
|
|
|
+ CLabelUI* pUnit = static_cast<CLabelUI*>(row->FindSubControl(L"col_unit"));
|
|
|
+ CLabelUI* pQty = static_cast<CLabelUI*>(row->FindSubControl(L"col_qty"));
|
|
|
+ CLabelUI* pPrice = static_cast<CLabelUI*>(row->FindSubControl(L"col_price"));
|
|
|
+ CLabelUI* pAmt = static_cast<CLabelUI*>(row->FindSubControl(L"col_amount"));
|
|
|
+ if (pName) pName->SetText(r.name.c_str());
|
|
|
+ if (pUnit) pUnit->SetText(r.unit.c_str());
|
|
|
+ if (pQty) pQty->SetText(KcFormatQty(r.qty).c_str());
|
|
|
+ if (pPrice) pPrice->SetText(KcFormatMoney(r.price).c_str());
|
|
|
+ if (pAmt) pAmt->SetText(KcFormatMoney(r.amount).c_str());
|
|
|
+ pList->Add(row);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void CCaigouDetailWnd::FillSum()
|
|
|
+{
|
|
|
+ int n = (int)m_doc.rows.size();
|
|
|
+ double total = 0.0;
|
|
|
+ for (size_t i = 0; i < m_doc.rows.size(); i++) total += m_doc.rows[i].amount;
|
|
|
+ CgDSet(m_pm, L"kd_sum_lab", L"商品 " + std::to_wstring(n) + L" 种 · 合计");
|
|
|
+ CgDSet(m_pm, L"kd_sum_amt", L"¥" + KcFormatMoney(total));
|
|
|
+}
|