Browse Source

库存相关的,临时保存一下,还没做完

张洋 1 week ago
parent
commit
44edbebe0e
100 changed files with 5244 additions and 51 deletions
  1. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/DuiLib_d.dll
  2. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/bb_pill_red.png
  3. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/btn_org_h.png
  4. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/btn_org_n.png
  5. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/btn_org_p.png
  6. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/btn_pill48_grn_h.png
  7. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/btn_pill48_grn_n.png
  8. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/btn_pill48_grn_p.png
  9. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/btn_pill48_org_h.png
  10. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/btn_pill48_org_n.png
  11. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/btn_pill48_org_p.png
  12. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/gd_combo40_h.png
  13. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/gd_combo40_n.png
  14. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/gd_combo40_p.png
  15. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/gd_combo44_h.png
  16. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/gd_combo44_n.png
  17. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/gd_combo44_p.png
  18. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/gd_pill48_ghost_h.png
  19. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/gd_pill48_ghost_n.png
  20. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/gd_pill48_ghost_p.png
  21. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_btn_ghost_h.png
  22. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_btn_ghost_n.png
  23. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_btn_ghost_p.png
  24. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_btn_primary_h.png
  25. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_btn_primary_n.png
  26. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_btn_primary_p.png
  27. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_chk_off_24.png
  28. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_chk_on_24.png
  29. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_dlg_close_h.png
  30. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_dlg_close_n.png
  31. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_dlg_close_p.png
  32. 77 0
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_doc_detail_wnd.xml
  33. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_dot7.png
  34. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_key_h.png
  35. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_key_n.png
  36. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_key_p.png
  37. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_keydel_h.png
  38. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_keydel_n.png
  39. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_keydel_p.png
  40. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_keyfn_h.png
  41. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_keyfn_n.png
  42. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_keyfn_p.png
  43. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_keyok_h.png
  44. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_keyok_n.png
  45. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_keyok_p.png
  46. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_pbar_grn.png
  47. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_pbar_org.png
  48. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_pbar_track.png
  49. 74 0
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_pd_detail_wnd.xml
  50. 24 0
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_ck.xml
  51. 26 0
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_ck_edit.xml
  52. 22 0
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_ck_stat.xml
  53. 18 0
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_cx.xml
  54. 23 0
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_cx_amt.xml
  55. 18 0
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_doc_detail.xml
  56. 24 0
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_pd.xml
  57. 15 0
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_pd_detail.xml
  58. 24 0
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_pd_edit.xml
  59. 19 0
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_pd_stat.xml
  60. 19 0
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_pick.xml
  61. 24 0
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_rk.xml
  62. 25 0
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_rk_edit.xml
  63. 22 0
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_rk_stat.xml
  64. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_segcard.png
  65. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_seggray_h.png
  66. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_seggray_p.png
  67. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_seggrn_h.png
  68. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_seggrn_n.png
  69. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_seggrn_p.png
  70. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_stat_blue.png
  71. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_stat_grn.png
  72. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_stat_org.png
  73. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_stat_pur.png
  74. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_stat_red.png
  75. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_switch_off.png
  76. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_switch_on.png
  77. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_tabcard.png
  78. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_tabgray_h.png
  79. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_tabgray_p.png
  80. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_tabgrn_h.png
  81. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_tabgrn_n.png
  82. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_tabgrn_p.png
  83. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_tag_blue.png
  84. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_tag_gray.png
  85. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_tag_grn.png
  86. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_tag_org.png
  87. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_tag_pur.png
  88. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_tag_red.png
  89. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_tblcard.png
  90. BIN
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_tot_bg.png
  91. 967 11
      bin/Win32/Debug/zhipuzi_pos_windows/skin/kucun_page.xml
  92. 7 0
      bin/Win32/Debug/zhipuzi_pos_windows/skin/main.xml
  93. BIN
      dll/debug/DuiLib_d.dll
  94. BIN
      lib/debug/DuiLib_d.lib
  95. 591 18
      zhipuzi_pos_windows/page/CKucunPageUI.cpp
  96. 54 22
      zhipuzi_pos_windows/page/CKucunPageUI.h
  97. 2179 0
      zhipuzi_pos_windows/page/CKucunViews.cpp
  98. 542 0
      zhipuzi_pos_windows/page/CKucunViews.h
  99. 329 0
      zhipuzi_pos_windows/wnd/CKucunDetailWnd.cpp
  100. 121 0
      zhipuzi_pos_windows/wnd/CKucunDetailWnd.h

BIN
bin/Win32/Debug/zhipuzi_pos_windows/DuiLib_d.dll


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


+ 77 - 0
bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_doc_detail_wnd.xml

@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Window size="660,626" caption="0,0,0,56" roundcorner="10,10" shadowsize="3" showshadow="true">
+	<!-- 入库单 / 出库单 详情弹框(设计稿 t10 / t12)。同一张皮肤两用:标题、单号、
+	     类型标签、合计文案由 C++ 按单据类型填。窗高 = 366 + 52*明细行数,运行时按实际行数
+	     SetWindowPos + CenterWindow(见 CKucunDetailWnd::SetWindowHeight)。
+	     分段:mhead 56(含底边 1px) / mbody inset 20,16,20,18(左,上,右,下)/ mfoot 68(含顶边 1px)。
+	     mbody 内:kd_info 104(两行 46 + 12 间距) + 14 间距 + 表格卡 315(5 行初值)
+	               + 10 间距 + kd_sum 25。 -->
+	<VerticalLayout bkcolor="#FFFFFFFF">
+		<HorizontalLayout name="kd_head" height="56" inset="20,0,20,0" childpadding="12" childvalign="vcenter" bordersize="0,0,0,1" bordercolor="#FFE8EAED">
+			<Label name="kd_title" text="入库单详情" font="116" textcolor="#FF1F2329" maxheight="24" valign="vcenter" autocalcwidth="true" />
+			<Label name="kd_sub" text="出库单 / 盘点单详情同构" font="12" textcolor="#FF8A9099" maxheight="20" valign="vcenter" autocalcwidth="true" />
+			<Control />
+			<Button name="kd_close" width="28" maxheight="28" normalimage="file='kc_dlg_close_n.png'" hotimage="file='kc_dlg_close_h.png'" pushedimage="file='kc_dlg_close_p.png'" />
+		</HorizontalLayout>
+		<VerticalLayout name="kd_body" inset="20,16,20,18">
+			<VerticalLayout name="kd_info" height="104">
+				<HorizontalLayout name="kd_inforow1" height="46" childpadding="16">
+					<VerticalLayout name="kd_c1" width="196">
+						<Label name="kd_l1" text="标签" height="16" font="12" textcolor="#FF8A9099" align="left" valign="vcenter" />
+						<Control height="4" />
+						<Label name="kd_v1" text="值" height="26" font="113" textcolor="#FF1F2329" align="left" valign="vcenter" maxheight="26" />
+					</VerticalLayout>
+					<VerticalLayout name="kd_c2" width="196">
+						<Label name="kd_l2" text="标签" height="16" font="12" textcolor="#FF8A9099" align="left" valign="vcenter" />
+						<Control height="4" />
+						<Label name="kd_v2" text="值" height="26" font="113" textcolor="#FF1F2329" align="left" valign="vcenter" maxheight="26" />
+					</VerticalLayout>
+					<VerticalLayout name="kd_c3" width="196">
+						<Label name="kd_l3" text="标签" height="16" font="12" textcolor="#FF8A9099" align="left" valign="vcenter" />
+						<Control height="4" />
+						<Label name="kd_v3" text="值" height="26" font="113" textcolor="#FF1F2329" align="left" valign="vcenter" maxheight="26" />
+					</VerticalLayout>
+				</HorizontalLayout>
+				<Control height="12" />
+				<HorizontalLayout name="kd_inforow2" height="46" childpadding="16">
+					<VerticalLayout name="kd_c4" width="196">
+						<Label name="kd_l4" text="标签" height="16" font="12" textcolor="#FF8A9099" align="left" valign="vcenter" />
+						<Control height="4" />
+						<Label name="kd_v4" text="值" height="26" font="113" textcolor="#FF1F2329" align="left" valign="vcenter" maxheight="26" />
+					</VerticalLayout>
+					<VerticalLayout name="kd_c5" width="196">
+						<Label name="kd_l5" text="标签" height="16" font="12" textcolor="#FF8A9099" align="left" valign="vcenter" />
+						<Control height="4" />
+						<Label name="kd_v5" text="值" height="26" font="113" textcolor="#FF1F2329" align="left" valign="vcenter" maxheight="26" />
+					</VerticalLayout>
+					<VerticalLayout name="kd_c6" width="196">
+						<Label name="kd_l6" text="标签" height="16" font="12" textcolor="#FF8A9099" align="left" valign="vcenter" />
+						<Control height="4" />
+						<Label name="kd_v6" text="值" height="26" font="113" textcolor="#FF1F2329" align="left" valign="vcenter" maxheight="26" />
+					</VerticalLayout>
+				</HorizontalLayout>
+			</VerticalLayout>
+			<Control height="14" />
+			<!-- 表格卡:外框 + 43px 表头灰带 + 表头下分隔线都由 kc_tblcard.png 画;ListHeader 全透明让底图透出。 -->
+			<VerticalLayout name="kd_tblcard" height="315" bkimage="file='kc_tblcard.png' corner='10,45,10,10'">
+				<List name="kd_list" inset="1,1,1,10" vscrollbar="false" bkcolor="#00000000" itemhotbkcolor="#00000000" itemselectedbkcolor="#00000000">
+					<ListHeader height="44" bkcolor="#00000000" bordercolor="#00000000" bordersize="0" />
+					<ListHeaderItem text="商品名称" width="210" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+					<ListHeaderItem text="单位" width="74" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+					<ListHeaderItem text="数量" width="99" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+					<ListHeaderItem text="单价(元)" width="111" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+					<ListHeaderItem text="金额(元)" width="124" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+				</List>
+			</VerticalLayout>
+			<Control height="10" />
+			<HorizontalLayout name="kd_sum" height="25" childpadding="10" childalign="right" childvalign="vcenter">
+				<Label name="kd_sum_lab" text="商品 5 种 · 合计" font="13" textcolor="#FF5F6368" maxheight="22" valign="vcenter" autocalcwidth="true" />
+				<Label name="kd_sum_amt" text="¥1,280.00" font="116" textcolor="#FF2E9B5C" maxheight="25" valign="vcenter" autocalcwidth="true" />
+			</HorizontalLayout>
+		</VerticalLayout>
+		<HorizontalLayout name="kd_foot" height="68" inset="20,0,20,0" childpadding="12" childalign="right" childvalign="vcenter" bkcolor="#FFFAFBFC" bordersize="0,1,0,0" bordercolor="#FFE8EAED">
+			<Button name="kd_btn_close" text="关闭" width="65" maxheight="40" font="113" align="center" valign="vcenter" textcolor="#FF5F6368" hottextcolor="#FF1F2329" pushedtextcolor="#FF1F2329" normalimage="file='kc_btn_ghost_n.png' corner='20,20,20,20'" hotimage="file='kc_btn_ghost_h.png' corner='20,20,20,20'" pushedimage="file='kc_btn_ghost_p.png' corner='20,20,20,20'" />
+			<Button name="kd_btn_print" text="打印小票" width="103" maxheight="40" font="113" align="left" valign="vcenter" textpadding="31,0,0,0" textcolor="#FFFFFFFF" hottextcolor="#FFFFFFFF" pushedtextcolor="#FFFFFFFF" normalimage="file='kc_btn_primary_n.png' corner='30,20,20,20'" hotimage="file='kc_btn_primary_h.png' corner='30,20,20,20'" pushedimage="file='kc_btn_primary_p.png' corner='30,20,20,20'" />
+		</HorizontalLayout>
+	</VerticalLayout>
+</Window>

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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


+ 74 - 0
bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_pd_detail_wnd.xml

@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Window size="660,626" caption="0,0,0,56" roundcorner="10,10" shadowsize="3" showshadow="true">
+	<!-- 盘点单 详情弹框(设计稿 t13)。与入库/出库弹框同构,只多一列(账面 / 实盘 / 差异 / 盈亏金额)。
+	     窗高公式一致:366 + 52*明细行数。 -->
+	<VerticalLayout bkcolor="#FFFFFFFF">
+		<HorizontalLayout name="kd_head" height="56" inset="20,0,20,0" childpadding="12" childvalign="vcenter" bordersize="0,0,0,1" bordercolor="#FFE8EAED">
+			<Label name="kd_title" text="盘点单详情" font="116" textcolor="#FF1F2329" maxheight="24" valign="vcenter" autocalcwidth="true" />
+			<Label name="kd_sub" text="含 账面 / 实盘 / 差异 列" font="12" textcolor="#FF8A9099" maxheight="20" valign="vcenter" autocalcwidth="true" />
+			<Control />
+			<Button name="kd_close" width="28" maxheight="28" normalimage="file='kc_dlg_close_n.png'" hotimage="file='kc_dlg_close_h.png'" pushedimage="file='kc_dlg_close_p.png'" />
+		</HorizontalLayout>
+		<VerticalLayout name="kd_body" inset="20,16,20,18">
+			<VerticalLayout name="kd_info" height="104">
+				<HorizontalLayout name="kd_inforow1" height="46" childpadding="16">
+					<VerticalLayout name="kd_c1" width="196">
+						<Label name="kd_l1" text="标签" height="16" font="12" textcolor="#FF8A9099" align="left" valign="vcenter" />
+						<Control height="4" />
+						<Label name="kd_v1" text="值" height="26" font="113" textcolor="#FF1F2329" align="left" valign="vcenter" maxheight="26" />
+					</VerticalLayout>
+					<VerticalLayout name="kd_c2" width="196">
+						<Label name="kd_l2" text="标签" height="16" font="12" textcolor="#FF8A9099" align="left" valign="vcenter" />
+						<Control height="4" />
+						<Label name="kd_v2" text="值" height="26" font="113" textcolor="#FF1F2329" align="left" valign="vcenter" maxheight="26" />
+					</VerticalLayout>
+					<VerticalLayout name="kd_c3" width="196">
+						<Label name="kd_l3" text="标签" height="16" font="12" textcolor="#FF8A9099" align="left" valign="vcenter" />
+						<Control height="4" />
+						<Label name="kd_v3" text="值" height="26" font="113" textcolor="#FF1F2329" align="left" valign="vcenter" maxheight="26" />
+					</VerticalLayout>
+				</HorizontalLayout>
+				<Control height="12" />
+				<HorizontalLayout name="kd_inforow2" height="46" childpadding="16">
+					<VerticalLayout name="kd_c4" width="196">
+						<Label name="kd_l4" text="标签" height="16" font="12" textcolor="#FF8A9099" align="left" valign="vcenter" />
+						<Control height="4" />
+						<Label name="kd_v4" text="值" height="26" font="113" textcolor="#FF1F2329" align="left" valign="vcenter" maxheight="26" />
+					</VerticalLayout>
+					<VerticalLayout name="kd_c5" width="196">
+						<Label name="kd_l5" text="标签" height="16" font="12" textcolor="#FF8A9099" align="left" valign="vcenter" />
+						<Control height="4" />
+						<Label name="kd_v5" text="值" height="26" font="113" textcolor="#FF1F2329" align="left" valign="vcenter" maxheight="26" />
+					</VerticalLayout>
+					<VerticalLayout name="kd_c6" width="196">
+						<Label name="kd_l6" text="标签" height="16" font="12" textcolor="#FF8A9099" align="left" valign="vcenter" />
+						<Control height="4" />
+						<Label name="kd_v6" text="值" height="26" font="113" textcolor="#FF1F2329" align="left" valign="vcenter" maxheight="26" />
+					</VerticalLayout>
+				</HorizontalLayout>
+			</VerticalLayout>
+			<Control height="14" />
+			<!-- 表格卡:外框 + 43px 表头灰带 + 表头下分隔线都由 kc_tblcard.png 画;ListHeader 全透明让底图透出。 -->
+			<VerticalLayout name="kd_tblcard" height="315" bkimage="file='kc_tblcard.png' corner='10,45,10,10'">
+				<List name="kd_list" inset="1,1,1,10" vscrollbar="false" bkcolor="#00000000" itemhotbkcolor="#00000000" itemselectedbkcolor="#00000000">
+					<ListHeader height="44" bkcolor="#00000000" bordercolor="#00000000" bordersize="0" />
+					<ListHeaderItem text="商品名称" width="136" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+					<ListHeaderItem text="单位" width="62" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+					<ListHeaderItem text="账面库存" width="80" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+					<ListHeaderItem text="实盘库存" width="80" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+					<ListHeaderItem text="差异" width="87" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+					<ListHeaderItem text="盈亏金额(元)" width="173" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+				</List>
+			</VerticalLayout>
+			<Control height="10" />
+			<HorizontalLayout name="kd_sum" height="25" childpadding="10" childalign="right" childvalign="vcenter">
+				<Label name="kd_sum_lab" text="差异商品 5 项 · 盈亏合计" font="13" textcolor="#FF5F6368" maxheight="22" valign="vcenter" autocalcwidth="true" />
+				<Label name="kd_sum_amt" text="¥1,280.00" font="116" textcolor="#FFE14B4A" maxheight="25" valign="vcenter" autocalcwidth="true" />
+			</HorizontalLayout>
+		</VerticalLayout>
+		<HorizontalLayout name="kd_foot" height="68" inset="20,0,20,0" childpadding="12" childalign="right" childvalign="vcenter" bkcolor="#FFFAFBFC" bordersize="0,1,0,0" bordercolor="#FFE8EAED">
+			<Button name="kd_btn_close" text="关闭" width="65" maxheight="40" font="113" align="center" valign="vcenter" textcolor="#FF5F6368" hottextcolor="#FF1F2329" pushedtextcolor="#FF1F2329" normalimage="file='kc_btn_ghost_n.png' corner='20,20,20,20'" hotimage="file='kc_btn_ghost_h.png' corner='20,20,20,20'" pushedimage="file='kc_btn_ghost_p.png' corner='20,20,20,20'" />
+			<Button name="kd_btn_print" text="打印小票" width="103" maxheight="40" font="113" align="left" valign="vcenter" textpadding="31,0,0,0" textcolor="#FFFFFFFF" hottextcolor="#FFFFFFFF" pushedtextcolor="#FFFFFFFF" normalimage="file='kc_btn_primary_n.png' corner='30,20,20,20'" hotimage="file='kc_btn_primary_h.png' corner='30,20,20,20'" pushedimage="file='kc_btn_primary_p.png' corner='30,20,20,20'" />
+		</HorizontalLayout>
+	</VerticalLayout>
+</Window>

+ 24 - 0
bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_ck.xml

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Window>
+	<!-- 出库记录行:对齐 kc_ck_list 表头 —— 出库单号(余量) / 出库类型167 / 商品数107 / 金额(元)155 / 经手人119 / 状态131 / 操作299。
+		     列控件必须是 ListContainerElement 的直接子控件 —— 框架会按表头列矩形强制对齐
+		     (DuiLib/Control/UIList.cpp 的 CListContainerElementUI::SetPos)。
+		     正文 #1F2329;数值列右对齐 + 13px 粗体;表头 #5F6368 + 13px 粗体。
+		     行下边框画出设计稿的行分隔线(.tr 的 border-bottom)。 -->
+	<ListContainerElement height="54" inset="0" childvalign="vcenter" bordersize="0,0,0,1" bordercolor="#FFE8EAED">
+		<Label name="col_no" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<HorizontalLayout name="col_type" width="167" inset="14,0,0,0" childvalign="vcenter">
+			<Label name="tag_type" font="112" textcolor="#FF5F6368" maxheight="24" bkimage="file='kc_tag_gray.png' corner='12,12,12,12'" textpadding="12,0,12,0" autocalcwidth="true" valign="vcenter" />
+		</HorizontalLayout>
+		<Label name="col_goods" width="107" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_amount" width="155" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_handler" width="119" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<HorizontalLayout name="col_status" width="131" inset="14,0,0,0" childvalign="vcenter">
+			<Label name="tag_status" font="112" textcolor="#FF5F6368" maxheight="24" bkimage="file='kc_tag_gray.png' corner='12,12,12,12'" textpadding="12,0,12,0" autocalcwidth="true" valign="vcenter" />
+		</HorizontalLayout>
+		<HorizontalLayout name="col_op" width="299" inset="14,0,0,0" childpadding="14" childvalign="vcenter">
+			<Button name="op_detail" text="详情" font="13" textcolor="#FF2E9B5C" hottextcolor="#FF1B8A4C" pushedtextcolor="#FF1B8A4C" normalimage="" hotimage="" pushedimage="" width="44" />
+			<Button name="op_print" text="打印" font="13" textcolor="#FF2E9B5C" hottextcolor="#FF1B8A4C" pushedtextcolor="#FF1B8A4C" normalimage="" hotimage="" pushedimage="" width="44" />
+		</HorizontalLayout>
+	</ListContainerElement>
+</Window>

+ 26 - 0
bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_ck_edit.xml

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Window>
+	<!-- 新建出库单 · 明细行(设计稿 v4 p2 / p7)。
+	     列控件必须是 ListContainerElement 的直接子控件:框架会把每列 left/right 强制对齐
+	     kc_ckn_list 表头列矩形,所以这里的 width 必须与 kucun_page.xml 里 ListHeaderItem 逐列一致。
+	     列顺序:name flex / cat 137 / unit 100 / book 162 / qty 174 / note 261 / note_hint flex / op 187(列宽 = 设计稿百分比 × 表格内宽 1244)
+	     与入库行的差别:多一列只读的「当前库存」(用于超库存判定),金额列换成可编辑的「备注」。
+	     可编辑单元格是 Button,控件名由 C++ 重命名为 kc_ckn_qty_<行号> / kc_ckn_note_<行号>,
+	     行尾按钮重命名为 kc_ckn_del_<行号>;超库存时 C++ 把底图换成 btn_r8_red_*。 -->
+	<ListContainerElement height="56" inset="0" childvalign="vcenter" bordersize="0,0,0,1" bordercolor="#FFE8EAED">
+		<Label name="col_name" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_cat" width="137" font="13" textcolor="#FF5F6368" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_unit" width="100" font="13" textcolor="#FF5F6368" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_book" width="162" font="13" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<HorizontalLayout name="col_qty" width="174" inset="14,0,14,0" childvalign="vcenter">
+				<Button name="cell_qty" maxheight="44" font="14" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,12,0" normalimage="file='input_r8_n.png' corner='8,8,8,8'" hotimage="file='input_r8_h.png' corner='8,8,8,8'" pushedimage="file='input_r8_n.png' corner='8,8,8,8'" />
+		</HorizontalLayout>
+		<HorizontalLayout name="col_note" width="261" inset="14,0,14,0" childvalign="vcenter">
+				<Button name="cell_note" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="12,0,12,0" maxheight="44" normalimage="file='input_r8_n.png' corner='8,8,8,8'" hotimage="file='input_r8_h.png' corner='8,8,8,8'" pushedimage="file='input_r8_n.png' corner='8,8,8,8'" />
+				<Label name="col_note_hint" text="" visible="false" font="12" textcolor="#FFE14B4A" align="left" valign="vcenter" />
+		</HorizontalLayout>
+		<HorizontalLayout name="col_op" width="187" inset="14,0,0,0" childvalign="vcenter">
+				<Button name="btn_del" text="删除" width="56" maxheight="28" font="13" textcolor="#FF2E9B5C" hottextcolor="#FF1B8A4C" pushedtextcolor="#FF1B8A4C" align="left" normalimage="" hotimage="" pushedimage="" />
+		</HorizontalLayout>
+	</ListContainerElement>
+</Window>

+ 22 - 0
bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_ck_stat.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Window>
+	<!-- 出库统计行:对齐 kc_ck_list_stat 表头 —— 商品名称(余量) / 分类119 / 单位96 / 出库单数119 / 出库数量143 / 金额(元)143 / 金额占比358。占比条填充色用主题的 org 橙。
+		     列控件必须是 ListContainerElement 的直接子控件 —— 框架会按表头列矩形强制对齐
+		     (DuiLib/Control/UIList.cpp 的 CListContainerElementUI::SetPos)。
+		     正文 #1F2329;数值列右对齐 + 13px 粗体;表头 #5F6368 + 13px 粗体。
+		     行下边框画出设计稿的行分隔线(.tr 的 border-bottom)。 -->
+	<ListContainerElement height="54" inset="0" childvalign="vcenter" bordersize="0,0,0,1" bordercolor="#FFE8EAED">
+		<Label name="col_name" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_cat" width="119" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_unit" width="96" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_cnt" width="119" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_qty" width="143" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_amount" width="143" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<HorizontalLayout name="col_ratio" width="358" inset="14,0,14,0" childpadding="8" childvalign="vcenter">
+			<HorizontalLayout name="bar_track" width="120" height="8" maxheight="8" bkimage="file='kc_pbar_track.png' corner='4,4,4,4'" childpadding="0">
+				<Control name="bar_fill" width="0" height="8" maxheight="8" bkimage="file='kc_pbar_org.png' corner='4,4,4,4'" />
+			</HorizontalLayout>
+			<Label name="bar_pct" width="58" font="12" textcolor="#FF5F6368" align="left" valign="vcenter" />
+		</HorizontalLayout>
+	</ListContainerElement>
+</Window>

+ 18 - 0
bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_cx.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Window>
+	<!-- 库存台账行:对齐 kc_cx_list 表头 —— 商品名称(余量) / 分类167 / 单位143 / 当前库存191 / 安全库存191 / 状态215。
+		     列控件必须是 ListContainerElement 的直接子控件 —— 框架会按表头列矩形强制对齐
+		     (DuiLib/Control/UIList.cpp 的 CListContainerElementUI::SetPos)。
+		     正文 #1F2329;数值列右对齐 + 13px 粗体;表头 #5F6368 + 13px 粗体。
+		     行下边框画出设计稿的行分隔线(.tr 的 border-bottom)。 -->
+	<ListContainerElement height="54" inset="0" childvalign="vcenter" bordersize="0,0,0,1" bordercolor="#FFE8EAED">
+		<Label name="col_name" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_cat" width="167" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_unit" width="143" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_cur" width="191" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_safe" width="191" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<HorizontalLayout name="col_status" width="215" inset="14,0,0,0" childvalign="vcenter">
+			<Label name="tag_status" font="112" textcolor="#FF5F6368" maxheight="24" bkimage="file='kc_tag_gray.png' corner='12,12,12,12'" textpadding="12,0,12,0" autocalcwidth="true" valign="vcenter" />
+		</HorizontalLayout>
+	</ListContainerElement>
+</Window>

+ 23 - 0
bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_cx_amt.xml

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Window>
+	<!-- 库存金额行:对齐 kc_cx_amt_list 表头 —— 商品名称(余量) / 成本价模式119 / 当前进货价107 / 加权平均成本价131 / 当前库存96 / 库存单位84 / 库存成本119 / 当前销售价107 / 预计销售额107 / 预计利润84 / 预计利润率107。预计利润正负与利润率高低由 C++ 着色。
+		     列控件必须是 ListContainerElement 的直接子控件 —— 框架会按表头列矩形强制对齐
+		     (DuiLib/Control/UIList.cpp 的 CListContainerElementUI::SetPos)。
+		     正文 #1F2329;数值列右对齐 + 13px 粗体;表头 #5F6368 + 13px 粗体。
+		     行下边框画出设计稿的行分隔线(.tr 的 border-bottom)。 -->
+	<ListContainerElement height="54" inset="0" childvalign="vcenter" bordersize="0,0,0,1" bordercolor="#FFE8EAED">
+		<Label name="col_name" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<HorizontalLayout name="col_mode" width="119" inset="14,0,0,0" childvalign="vcenter">
+			<Label name="tag_mode" font="112" textcolor="#FF5F6368" maxheight="24" bkimage="file='kc_tag_gray.png' corner='12,12,12,12'" textpadding="12,0,12,0" autocalcwidth="true" valign="vcenter" />
+		</HorizontalLayout>
+		<Label name="col_in" width="107" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_avg" width="131" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_cur" width="96" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_unit" width="84" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_cost" width="119" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_sale" width="107" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_amt" width="107" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_profit" width="84" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_rate" width="107" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+	</ListContainerElement>
+</Window>

+ 18 - 0
bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_doc_detail.xml

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Window>
+	<!-- 单据详情明细行(入库单 / 出库单弹框,对齐 kd_list 表头):
+	     商品名称(210) / 单位(74) / 数量(99) / 单价(元)(111) / 金额(元)(124)。
+	     列控件必须是 ListContainerElement 的直接子控件、且数量与表头列数一一对应 —— 框架会把
+	     每个子控件的左右边界强制覆盖成对应表头项的矩形
+	     (DuiLib/Control/UIList.cpp 的 CListContainerElementUI::SetPos,3217 到 3235 行);
+	     多一个子控件就会撞上 pHeaderItem==NULL 而整体提前 return。
+	     行高 52,行下边框 1px 画设计稿的 .tr border-bottom;最后一行也带,
+	     由 kc_tblcard.png 的圆角底边兜住,视觉上与设计稿一致。 -->
+	<ListContainerElement height="52" inset="0" childvalign="vcenter" bordersize="0,0,0,1" bordercolor="#FFE8EAED">
+		<Label name="col_name" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_unit" font="13" textcolor="#FF5F6368" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_qty" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_price" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_amount" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+	</ListContainerElement>
+</Window>

+ 24 - 0
bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_pd.xml

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Window>
+	<!-- 盘点记录行:对齐 kc_pd_list 表头 —— 盘点单号(余量) / 盘点范围155 / 商品数96 / 盘盈96 / 盘亏96 / 盈亏金额(元)143 / 盘点人107 / 盘点结果119 / 操作203。盘点结果 = 盘盈(蓝) / 盘亏(红) / 无差异(灰),由 C++ 切胶囊底图与文字色。
+		     列控件必须是 ListContainerElement 的直接子控件 —— 框架会按表头列矩形强制对齐
+		     (DuiLib/Control/UIList.cpp 的 CListContainerElementUI::SetPos)。
+		     正文 #1F2329;数值列右对齐 + 13px 粗体;表头 #5F6368 + 13px 粗体。
+		     行下边框画出设计稿的行分隔线(.tr 的 border-bottom)。 -->
+	<ListContainerElement height="54" inset="0" childvalign="vcenter" bordersize="0,0,0,1" bordercolor="#FFE8EAED">
+		<Label name="col_no" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_scope" width="155" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_goods" width="96" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_gain" width="96" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_loss" width="96" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_amount" width="143" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_handler" width="107" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<HorizontalLayout name="col_result" width="119" inset="14,0,0,0" childvalign="vcenter">
+			<Label name="tag_result" font="112" textcolor="#FF5F6368" maxheight="24" bkimage="file='kc_tag_gray.png' corner='12,12,12,12'" textpadding="12,0,12,0" autocalcwidth="true" valign="vcenter" />
+		</HorizontalLayout>
+		<HorizontalLayout name="col_op" width="203" inset="14,0,0,0" childpadding="14" childvalign="vcenter">
+			<Button name="op_detail" text="详情" font="13" textcolor="#FF2E9B5C" hottextcolor="#FF1B8A4C" pushedtextcolor="#FF1B8A4C" normalimage="" hotimage="" pushedimage="" width="44" />
+			<Button name="op_print" text="打印" font="13" textcolor="#FF2E9B5C" hottextcolor="#FF1B8A4C" pushedtextcolor="#FF1B8A4C" normalimage="" hotimage="" pushedimage="" width="44" />
+		</HorizontalLayout>
+	</ListContainerElement>
+</Window>

+ 15 - 0
bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_pd_detail.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Window>
+	<!-- 盘点单详情明细行(对齐 kd_list 表头):
+	     商品名称(136) / 单位(62) / 账面库存(80) / 实盘库存(80) / 差异(87) / 盈亏金额(元)(173)。
+	     列控件必须是 ListContainerElement 的直接子控件、且数量与表头列数一一对应(同上)。
+	     差异列与盈亏列的文字色由 C++ 按正负切换:盘盈 #FF2E9B5C、盘亏 #FFE14B4A、无差异 #FF1F2329。 -->
+	<ListContainerElement height="52" inset="0" childvalign="vcenter" bordersize="0,0,0,1" bordercolor="#FFE8EAED">
+		<Label name="col_name" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_unit" font="13" textcolor="#FF5F6368" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_book" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_real" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_diff" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_pl" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+	</ListContainerElement>
+</Window>

+ 24 - 0
bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_pd_edit.xml

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Window>
+	<!-- 新建盘点单 · 明细行(设计稿 v4 p3 全部 / p4 部分)。
+	     列控件必须是 ListContainerElement 的直接子控件:框架会把每列 left/right 强制对齐
+	     kc_pdn_list 表头列矩形,所以这里的 width 必须与 kucun_page.xml 里 ListHeaderItem 逐列一致。
+	     列顺序:name flex / cat 137 / unit 100 / book 149 / qty 174 / diff 124 / note 187 / op 162(列宽 = 设计稿百分比 × 表格内宽 1244)
+	     差异列 col_diff 文本与颜色由 C++ 按「实盘 − 账面」计算(盘盈绿 / 盘亏红 / 无差异灰)。
+	     实盘数量可编辑,控件名由 C++ 重命名为 kc_pdn_qty_<行号>;未录入时显示灰色占位「未录」。
+	     行尾按钮重命名为 kc_pdn_del_<行号>,作用是把该商品移出本次盘点范围。 -->
+	<ListContainerElement height="56" inset="0" childvalign="vcenter" bordersize="0,0,0,1" bordercolor="#FFE8EAED">
+		<Label name="col_name" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_cat" width="137" font="13" textcolor="#FF5F6368" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_unit" width="100" font="13" textcolor="#FF5F6368" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_book" width="149" font="13" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<HorizontalLayout name="col_qty" width="174" inset="14,0,14,0" childvalign="vcenter">
+				<Button name="cell_qty" maxheight="44" font="14" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,12,0" normalimage="file='input_r8_n.png' corner='8,8,8,8'" hotimage="file='input_r8_h.png' corner='8,8,8,8'" pushedimage="file='input_r8_n.png' corner='8,8,8,8'" />
+		</HorizontalLayout>
+		<Label name="col_diff" width="124" font="113" textcolor="#FFA8ADB3" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_note" width="187" font="113" textcolor="#FFA8ADB3" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<HorizontalLayout name="col_op" width="162" inset="14,0,0,0" childvalign="vcenter">
+				<Button name="btn_del" text="明细" width="56" maxheight="28" font="13" textcolor="#FF2E9B5C" hottextcolor="#FF1B8A4C" pushedtextcolor="#FF1B8A4C" align="left" normalimage="" hotimage="" pushedimage="" />
+		</HorizontalLayout>
+	</ListContainerElement>
+</Window>

+ 19 - 0
bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_pd_stat.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Window>
+	<!-- 盘点差异行:对齐 kc_pd_list_stat 表头 —— 商品名称(余量) / 分类143 / 单位119 / 盘点单数143 / 差异143 / 盈亏金额(元)215 / 结果191。差异正负与结果胶囊色由 C++ 设置。
+		     列控件必须是 ListContainerElement 的直接子控件 —— 框架会按表头列矩形强制对齐
+		     (DuiLib/Control/UIList.cpp 的 CListContainerElementUI::SetPos)。
+		     正文 #1F2329;数值列右对齐 + 13px 粗体;表头 #5F6368 + 13px 粗体。
+		     行下边框画出设计稿的行分隔线(.tr 的 border-bottom)。 -->
+	<ListContainerElement height="54" inset="0" childvalign="vcenter" bordersize="0,0,0,1" bordercolor="#FFE8EAED">
+		<Label name="col_name" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_cat" width="143" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_unit" width="119" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_cnt" width="143" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_diff" width="143" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_amount" width="215" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<HorizontalLayout name="col_result" width="191" inset="14,0,0,0" childvalign="vcenter">
+			<Label name="tag_result" font="112" textcolor="#FF5F6368" maxheight="24" bkimage="file='kc_tag_gray.png' corner='12,12,12,12'" textpadding="12,0,12,0" autocalcwidth="true" valign="vcenter" />
+		</HorizontalLayout>
+	</ListContainerElement>
+</Window>

+ 19 - 0
bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_pick.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Window>
+	<!-- 添加商品弹层 · 商品行(设计稿 v4 p5 / p7)。
+	     整行可点:CListContainerElement 抬手会发 DUI_MSGTYPE_ITEMCLICK(CMainWnd::Notify 把它
+	     转给 HandleClickMsg),宿主页收到后按 GetItemIndex 取行号切换勾选态,
+	     因此行根节点固定 name="pk_row";同时必须保持 3 个直接子控件与 kc_pick_list 的 3 个表头列
+	     一一对应 —— CListContainerElementUI::SetPos 会把第 i 个直接子控件强制对齐第 i 个表头列矩形。
+	     勾选方块 pk_cb 是普通 Control,C++ 用 SetBkImage 在 kc_chk_off_24 / kc_chk_on_24 之间切
+	     (不是 gd_check_off/on:那套是 15x15,设计稿 .cb 是 24x24 r=6)。
+	     列宽:商品(flex,内含勾选块 24 + 名称) / 分类·单位200 / 库存140。 -->
+	<ListContainerElement name="pk_row" height="56" inset="0" childvalign="vcenter">
+		<HorizontalLayout name="col_name" inset="18,0,0,0" childpadding="12" childvalign="vcenter">
+			<Control name="pk_cb" bkimage="kc_chk_off_24.png" width="24" maxheight="24" />
+			<Label name="pk_name" font="14" textcolor="#FF1F2329" align="left" valign="vcenter" />
+		</HorizontalLayout>
+		<Label name="pk_meta" width="200" font="12" textcolor="#FF8A9099" align="left" valign="vcenter" textpadding="10,0,0,0" />
+		<Label name="pk_stock" width="140" font="13" textcolor="#FF5F6368" align="right" valign="vcenter" textpadding="0,0,22,0" />
+	</ListContainerElement>
+</Window>

+ 24 - 0
bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_rk.xml

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Window>
+	<!-- 入库记录行:对齐 kc_rk_list 表头 —— 入库单号(余量) / 入库类型167 / 商品数119 / 金额(元)167 / 经手人143 / 状态143 / 操作239。类型与状态都是圆角胶囊,底图 / 文字色由 C++ 切换;操作列间距 14px(原设计稿)。
+		     列控件必须是 ListContainerElement 的直接子控件 —— 框架会按表头列矩形强制对齐
+		     (DuiLib/Control/UIList.cpp 的 CListContainerElementUI::SetPos)。
+		     正文 #1F2329;数值列右对齐 + 13px 粗体;表头 #5F6368 + 13px 粗体。
+		     行下边框画出设计稿的行分隔线(.tr 的 border-bottom)。 -->
+	<ListContainerElement height="54" inset="0" childvalign="vcenter" bordersize="0,0,0,1" bordercolor="#FFE8EAED">
+		<Label name="col_no" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<HorizontalLayout name="col_type" width="167" inset="14,0,0,0" childvalign="vcenter">
+			<Label name="tag_type" font="112" textcolor="#FF5F6368" maxheight="24" bkimage="file='kc_tag_gray.png' corner='12,12,12,12'" textpadding="12,0,12,0" autocalcwidth="true" valign="vcenter" />
+		</HorizontalLayout>
+		<Label name="col_goods" width="119" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_amount" width="167" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_handler" width="143" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<HorizontalLayout name="col_status" width="143" inset="14,0,0,0" childvalign="vcenter">
+			<Label name="tag_status" font="112" textcolor="#FF5F6368" maxheight="24" bkimage="file='kc_tag_gray.png' corner='12,12,12,12'" textpadding="12,0,12,0" autocalcwidth="true" valign="vcenter" />
+		</HorizontalLayout>
+		<HorizontalLayout name="col_op" width="239" inset="14,0,0,0" childpadding="14" childvalign="vcenter">
+			<Button name="op_detail" text="详情" font="13" textcolor="#FF2E9B5C" hottextcolor="#FF1B8A4C" pushedtextcolor="#FF1B8A4C" normalimage="" hotimage="" pushedimage="" width="44" />
+			<Button name="op_print" text="打印" font="13" textcolor="#FF2E9B5C" hottextcolor="#FF1B8A4C" pushedtextcolor="#FF1B8A4C" normalimage="" hotimage="" pushedimage="" width="44" />
+		</HorizontalLayout>
+	</ListContainerElement>
+</Window>

+ 25 - 0
bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_rk_edit.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Window>
+	<!-- 新建入库单 · 明细行(设计稿 v4 p1 / p6)。
+	     列控件必须是 ListContainerElement 的直接子控件:框架会把每列 left/right 强制对齐
+	     kc_rkn_list 表头列矩形,所以这里的 width 必须与 kucun_page.xml 里 ListHeaderItem 逐列一致。
+	     列顺序:name flex / cat 149 / unit 124 / qty 187 / price 174 / amount 174 / op 187(列宽 = 设计稿百分比 × 表格内宽 1244)
+	     可编辑单元格是 Button:底图走 input_r8_*,C++ 按状态换成 btn_r8_green_*(编辑中)
+	     或 btn_r8_red_*(超库存);控件名由 C++ 重命名为 kc_rkn_qty_<行号> / kc_rkn_price_<行号>,
+	     行尾按钮重命名为 kc_rkn_del_<行号>。 -->
+	<ListContainerElement height="56" inset="0" childvalign="vcenter" bordersize="0,0,0,1" bordercolor="#FFE8EAED">
+		<Label name="col_name" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_cat" width="149" font="13" textcolor="#FF5F6368" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_unit" width="124" font="13" textcolor="#FF5F6368" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<HorizontalLayout name="col_qty" width="187" inset="14,0,14,0" childvalign="vcenter">
+				<Button name="cell_qty" maxheight="44" font="14" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,12,0" normalimage="file='input_r8_n.png' corner='8,8,8,8'" hotimage="file='input_r8_h.png' corner='8,8,8,8'" pushedimage="file='input_r8_n.png' corner='8,8,8,8'" />
+		</HorizontalLayout>
+		<HorizontalLayout name="col_price" width="174" inset="14,0,14,0" childvalign="vcenter">
+				<Button name="cell_price" maxheight="44" font="14" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,12,0" normalimage="file='input_r8_n.png' corner='8,8,8,8'" hotimage="file='input_r8_h.png' corner='8,8,8,8'" pushedimage="file='input_r8_n.png' corner='8,8,8,8'" />
+		</HorizontalLayout>
+		<Label name="col_amount" width="174" font="13" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<HorizontalLayout name="col_op" width="187" inset="14,0,0,0" childvalign="vcenter">
+				<Button name="btn_del" text="删除" width="56" maxheight="28" font="13" textcolor="#FF2E9B5C" hottextcolor="#FF1B8A4C" pushedtextcolor="#FF1B8A4C" align="left" normalimage="" hotimage="" pushedimage="" />
+		</HorizontalLayout>
+	</ListContainerElement>
+</Window>

+ 22 - 0
bin/Win32/Debug/zhipuzi_pos_windows/skin/kc_row_rk_stat.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Window>
+	<!-- 入库统计行:对齐 kc_rk_list_stat 表头 —— 商品名称(余量) / 分类119 / 单位96 / 入库单数119 / 入库数量143 / 金额(元)143 / 金额占比358。占比条 120x8 胶囊,填充宽度由 C++ 按占比设置。
+		     列控件必须是 ListContainerElement 的直接子控件 —— 框架会按表头列矩形强制对齐
+		     (DuiLib/Control/UIList.cpp 的 CListContainerElementUI::SetPos)。
+		     正文 #1F2329;数值列右对齐 + 13px 粗体;表头 #5F6368 + 13px 粗体。
+		     行下边框画出设计稿的行分隔线(.tr 的 border-bottom)。 -->
+	<ListContainerElement height="54" inset="0" childvalign="vcenter" bordersize="0,0,0,1" bordercolor="#FFE8EAED">
+		<Label name="col_name" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_cat" width="119" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_unit" width="96" font="13" textcolor="#FF1F2329" align="left" valign="vcenter" textpadding="14,0,0,0" />
+		<Label name="col_cnt" width="119" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_qty" width="143" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<Label name="col_amount" width="143" font="113" textcolor="#FF1F2329" align="right" valign="vcenter" textpadding="0,0,14,0" />
+		<HorizontalLayout name="col_ratio" width="358" inset="14,0,14,0" childpadding="8" childvalign="vcenter">
+			<HorizontalLayout name="bar_track" width="120" height="8" maxheight="8" bkimage="file='kc_pbar_track.png' corner='4,4,4,4'" childpadding="0">
+				<Control name="bar_fill" width="0" height="8" maxheight="8" bkimage="file='kc_pbar_grn.png' corner='4,4,4,4'" />
+			</HorizontalLayout>
+			<Label name="bar_pct" width="58" font="12" textcolor="#FF5F6368" align="left" valign="vcenter" />
+		</HorizontalLayout>
+	</ListContainerElement>
+</Window>

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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


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


+ 967 - 11
bin/Win32/Debug/zhipuzi_pos_windows/skin/kucun_page.xml

@@ -1,15 +1,971 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Window>
+	<!-- 进销存(库存)页面:一级胶囊 Tab(库存查询 / 入库 / 出库 / 库存盘点)+ 4 个视图容器。
+	     布局口径按设计稿 v2 终稿:统计卡 → 切换行(胶囊居左)→ 筛选行(筛选居左、新建按钮居右)→ 表格区。
+	     全部圆角走 8x 超采样 PNG 九宫格,不使用 borderround。
+	     注意:main.xml 的全局 Default 会给所有 Button 套 btn_green_* 三态图,
+	     因此非绿色基础的按钮必须显式写 normalimage / hotimage / pushedimage 覆盖。 -->
+	<Default name="Combo" value="itemhottextcolor=&quot;#FF60B177&quot; itemhotbkcolor=&quot;#FFF2F7F4&quot; itemselectedtextcolor=&quot;#FF60B177&quot; itemselectedbkcolor=&quot;#FFE8F5EE&quot;" />
 	<KucunPage>
-		<HorizontalLayout>
-			<Control width="1" bkcolor="#FFD1D1D1"></Control>
-			
-			<VerticalLayout name="shangpin_food_layout">
-				<Control></Control>
-				<Label text="库存功能暂未上线,敬请期待" align="center" font="20" padding="0,0,0,0"></Label>
-				<Control></Control>
-			</VerticalLayout>
-				
-		</HorizontalLayout>
+		<VerticalLayout name="kc_page" bkcolor="#FFF5F7FA" childpadding="0">
+
+			<!-- 【R48】三个「新建单」页已从本容器**上提**到 kc_page(见文件下方 kc_view_*_new),
+			     因为设计稿 v4 的新建单页是通栏独立整页;本容器只负责 4 个记录 Tab 的整页滚动。
+			     整页滚动(设计稿 .content{overflow:auto}):滚动范围要覆盖含一级 Tab 在内的一整页,
+			     所以滚动容器放在页面根、而不是放在各个视图里(R45 调整)。
+			     右 inset 归 0 才能让 vscrollbar 贴住页面最右边缘(inset 的 right 非 0 时滚动条会被
+			     一起收缩,见 baobiao_page.xml 同款注释);右侧 28px 留白改由每个直接子项自己的
+			     padding="0,0,28,0" 承担。
+			     注意:视图容器必须能被撑成固定高度。CVerticalLayoutUI::SetPos 会把 EstimateSize().cy==0
+			     的子项当弹性项,用 cyExpand 吃掉剩余高度;若视图容器留在弹性状态,cyNeeded 恒等于
+			     视口高、滚动范围恒为 0,页面根本不滚。高度由 FitListHeight / SyncTableHeight
+			     沿父链逐级写死(到视图容器为止)。 -->
+			<VerticalLayout name="kc_scroll" vscrollbar="true" bkcolor="#FFF5F7FA" inset="28,18,0,24" childpadding="16">
+
+
+				<!-- 一级 Tab:库存查询 / 入库 / 出库 / 库存盘点 -->
+				<HorizontalLayout name="kc_tabrow" height="52" padding="0,0,28,0" childvalign="vcenter">
+					<HorizontalLayout width="366" maxheight="52" bkimage="file='kc_tabcard.png' corner='10,10,10,10'" inset="7,7,7,7" childpadding="8" childvalign="vcenter">
+						<Button name="kc_tab_chaxun" text="库存查询" font="114" textcolor="#FFFFFFFF" hottextcolor="#FFFFFFFF" pushedtextcolor="#FFFFFFFF" width="96" maxheight="38" align="center" normalimage="file='kc_tabgrn_n.png' corner='19,19,19,19'" hotimage="file='kc_tabgrn_h.png' corner='19,19,19,19'" pushedimage="file='kc_tabgrn_p.png' corner='19,19,19,19'" />
+						<Button name="kc_tab_ruku" text="入库" font="14" textcolor="#FF5F6368" hottextcolor="#FF2E9B5C" pushedtextcolor="#FF2E9B5C" width="68" maxheight="38" align="center" normalimage="" hotimage="file='kc_tabgray_h.png' corner='19,19,19,19'" pushedimage="file='kc_tabgray_p.png' corner='19,19,19,19'" />
+						<Button name="kc_tab_chuku" text="出库" font="14" textcolor="#FF5F6368" hottextcolor="#FF2E9B5C" pushedtextcolor="#FF2E9B5C" width="68" maxheight="38" align="center" normalimage="" hotimage="file='kc_tabgray_h.png' corner='19,19,19,19'" pushedimage="file='kc_tabgray_p.png' corner='19,19,19,19'" />
+						<Button name="kc_tab_pandian" text="库存盘点" font="14" textcolor="#FF5F6368" hottextcolor="#FF2E9B5C" pushedtextcolor="#FF2E9B5C" width="96" maxheight="38" align="center" normalimage="" hotimage="file='kc_tabgray_h.png' corner='19,19,19,19'" pushedimage="file='kc_tabgray_p.png' corner='19,19,19,19'" />
+					</HorizontalLayout>
+					<Control />
+					<Label text="数据为占位示例,接口联调后替换" font="12" textcolor="#FFA8ADB3" maxheight="17" autocalcwidth="true" />
+				</HorizontalLayout>
+
+			<!-- ==================== 视图 1:库存查询(库存状态 / 库存金额) ==================== -->
+			<!-- v2 终稿版式:统计卡,切换胶囊(居左),筛选行(筛选居左、只看预警开关居右),最后是表格区。
+				统计卡底色按品类走 kc_stat_*(蓝 / 橙 / 红 / 绿),左侧 3px 色条 + 26px 粗体数字 + 13px 灰色单位;
+				数字统一 #1F2329,品类只靠色条 + 底色区分(设计稿里数字色取主题的 t1 变量)。
+				两级 Tab 都按设计稿 v2 重做(R45):一级 Tab = 白底描边卡 kc_tabcard.png + 主绿胶囊 kc_tabgrn_*,切换胶囊 = 全圆描边卡 kc_segcard.png + kc_seggrn_*。
+				滚动由页面级容器 kc_scroll 承担(见文件末尾 kc_page / kc_scroll 段),各视图与各 List 都不再自带滚动条。 -->
+			<VerticalLayout name="kc_view_chaxun" padding="0,0,28,0" childpadding="16">
+				<!-- 统计卡:商品总数 / 预警商品 / 缺货商品 / 库存总值 -->
+				<HorizontalLayout height="96" childpadding="16">
+					<VerticalLayout bkimage="file='kc_stat_blue.png' corner='10,10,10,10'" inset="18,16,18,16" childpadding="0">
+						<HorizontalLayout height="20" childvalign="vcenter">
+							<Control width="3" maxheight="13" bkcolor="#FF4A90E2" borderround="3,3" />
+							<Control width="8" />
+							<Label text="商品总数" font="13" textcolor="#FF5F6368" maxheight="20" autocalcwidth="true" />
+						</HorizontalLayout>
+						<Control height="8" />
+						<Label name="kc_cx_stat_total" showhtml="true" font="126" textcolor="#FF1F2329" height="36" text="--{x 4}{c #8A9099}{f 13}项{/f}{/c}" />
+					</VerticalLayout>
+					<VerticalLayout bkimage="file='kc_stat_org.png' corner='10,10,10,10'" inset="18,16,18,16" childpadding="0">
+						<HorizontalLayout height="20" childvalign="vcenter">
+							<Control width="3" maxheight="13" bkcolor="#FFE08A17" borderround="3,3" />
+							<Control width="8" />
+							<Label text="预警商品" font="13" textcolor="#FF5F6368" maxheight="20" autocalcwidth="true" />
+						</HorizontalLayout>
+						<Control height="8" />
+						<Label name="kc_cx_stat_warn" showhtml="true" font="126" textcolor="#FF1F2329" height="36" text="--{x 4}{c #8A9099}{f 13}项{/f}{/c}" />
+					</VerticalLayout>
+					<VerticalLayout bkimage="file='kc_stat_red.png' corner='10,10,10,10'" inset="18,16,18,16" childpadding="0">
+						<HorizontalLayout height="20" childvalign="vcenter">
+							<Control width="3" maxheight="13" bkcolor="#FFE14B4A" borderround="3,3" />
+							<Control width="8" />
+							<Label text="缺货商品" font="13" textcolor="#FF5F6368" maxheight="20" autocalcwidth="true" />
+						</HorizontalLayout>
+						<Control height="8" />
+						<Label name="kc_cx_stat_lack" showhtml="true" font="126" textcolor="#FF1F2329" height="36" text="--{x 4}{c #8A9099}{f 13}项{/f}{/c}" />
+					</VerticalLayout>
+					<VerticalLayout bkimage="file='kc_stat_grn.png' corner='10,10,10,10'" inset="18,16,18,16" childpadding="0">
+						<HorizontalLayout height="20" childvalign="vcenter">
+							<Control width="3" maxheight="13" bkcolor="#FF2E9B5C" borderround="3,3" />
+							<Control width="8" />
+							<Label text="库存总值" font="13" textcolor="#FF5F6368" maxheight="20" autocalcwidth="true" />
+						</HorizontalLayout>
+						<Control height="8" />
+						<Label name="kc_cx_stat_value" showhtml="true" font="126" textcolor="#FF1F2329" height="36" text="--{x 4}{c #8A9099}{f 13}元{/f}{/c}" />
+					</VerticalLayout>
+				</HorizontalLayout>
+
+				<!-- 切换行:库存状态 / 库存金额(居左) -->
+				<HorizontalLayout height="42" childvalign="vcenter">
+					<HorizontalLayout width="182" maxheight="42" bkimage="file='kc_segcard.png' corner='21,21,21,21'" inset="5,5,5,5" childpadding="4" childvalign="vcenter">
+						<Button name="kc_cx_seg_state" text="库存状态" font="113" textcolor="#FFFFFFFF" hottextcolor="#FFFFFFFF" pushedtextcolor="#FFFFFFFF" width="84" maxheight="32" align="center" normalimage="file='kc_seggrn_n.png' corner='16,16,16,16'" hotimage="file='kc_seggrn_h.png' corner='16,16,16,16'" pushedimage="file='kc_seggrn_p.png' corner='16,16,16,16'" />
+						<Button name="kc_cx_seg_amt" text="库存金额" font="13" textcolor="#FF5F6368" hottextcolor="#FF2E9B5C" pushedtextcolor="#FF2E9B5C" width="84" maxheight="32" align="center" normalimage="" hotimage="file='kc_seggray_h.png' corner='16,16,16,16'" pushedimage="file='kc_seggray_p.png' corner='16,16,16,16'" />
+					</HorizontalLayout>
+					<Control />
+				</HorizontalLayout>
+
+				<!-- 筛选行:搜索 + 分类下拉(居左);「只看预警商品」开关(居右,库存金额视图下整组隐藏) -->
+				<HorizontalLayout height="40" childpadding="12" childvalign="vcenter">
+					<HorizontalLayout name="kc_cx_search_box" visible="true" width="240" bkimage="file='dc_search.png' corner='20,20,20,20'" inset="12,0,12,0" childpadding="8" childvalign="vcenter">
+						<Control bkimage="dc_ico_search16.png" width="16" height="16" maxheight="16" />
+						<Edit name="kc_cx_search_edit" tooltip="请输入商品名称或拼音码" font="12" textcolor="#FF1F2329" maxheight="24" bkcolor="#00000000" nativebkcolor="#FFEFF1F3" />
+						<Label name="kc_cx_search_tishi" text="请输入商品名称或拼音码" width="150" height="20" font="12" float="true" pos="40,10,190,30" mouse="false" valign="center" textcolor="#FFA8ADB3" />
+					</HorizontalLayout>
+					<Combo name="kc_cx_combo_cat" width="150" height="40" maxheight="40" normalimage="file='gd_combo40_n.png' corner='8,8,22,8'" hotimage="file='gd_combo40_h.png' corner='8,8,22,8'" pushedimage="file='gd_combo40_p.png' corner='8,8,22,8'" textpadding="11,0,30,0" />
+					<Control />
+					<HorizontalLayout name="kc_cx_swx" width="160" childvalign="vcenter" childpadding="8">
+						<Label text="只看预警商品" font="13" textcolor="#FF5F6368" maxheight="20" autocalcwidth="true" />
+						<!-- 开关用「两张整图换 bkimage」而不是轨道 + 定位子控件:整图自带圆角 AA,且只需一次 SetBkImage。
+							main.xml 的全局 Default 会给 Button 套 btn_green_*,这里三个态都要显式覆盖。 -->
+						<Button name="kc_cx_warn_switch" width="44" height="24" maxheight="24" normalimage="file='kc_switch_off.png'" hotimage="file='kc_switch_off.png'" pushedimage="file='kc_switch_off.png'" />
+					</HorizontalLayout>
+				</HorizontalLayout>
+
+				<!-- 库存状态:库存台账(卡片高度由 C++ 按行数设定,页面级滚动条据此算范围) -->
+				<VerticalLayout name="kc_cx_body_state" bkimage="file='bb_card10.png' corner='10,10,10,10'" inset="22,18,22,18" childpadding="0">
+					<HorizontalLayout height="22" childvalign="vcenter">
+						<Control width="3" maxheight="15" bkcolor="#FF2E9B5C" borderround="3,3" />
+						<Control width="10" />
+						<Label text="库存台账" font="116" textcolor="#FF1F2329" maxheight="22" autocalcwidth="true" />
+						<Control width="6" />
+						<Label text="实时反映当前门店所有原料 / 商品的库存水平" font="12" textcolor="#FF8A9099" maxheight="17" autocalcwidth="true" />
+						<Control />
+						<Label name="kc_cx_list_count" text="共 0 项" font="12" textcolor="#FF8A9099" maxheight="17" autocalcwidth="true" />
+					</HorizontalLayout>
+					<Control height="14" />
+					<VerticalLayout name="kc_cx_tblcard" bkimage="file='kc_tblcard.png' corner='10,45,10,10'" childpadding="0">
+						<List name="kc_cx_list" height="481" vscrollbar="false" inset="1,1,1,10" bkcolor="#00000000" itemhotbkcolor="#FFF7FAF8" itemselectedbkcolor="#FFEAF5EE">
+							<ListHeader height="44" bkcolor="#00000000" bordercolor="#00000000" bordersize="0" />
+							<ListHeaderItem text="商品名称" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="分类" width="167" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="单位" width="143" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="当前库存" width="191" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="安全库存" width="191" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="状态" width="215" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+						</List>
+					</VerticalLayout>
+					<Label name="kc_cx_list_foot" text="已全部加载 · 共 0 项" font="12" textcolor="#FF8A9099" height="44" valign="center" align="center" bkcolor="#FFFAFBFC" />
+				</VerticalLayout>
+
+				<!-- 库存金额:只读报表,11 列。口径 —— 库存成本 = 加权平均成本价 x 当前库存;
+					预计销售额 = 当前销售价 x 当前库存;预计利润 = 预计销售额 - 库存成本;
+					预计利润率 = 预计利润 / 预计销售额。不提供「只看预警商品」开关。 -->
+				<VerticalLayout name="kc_cx_body_amt" visible="false" bkimage="file='bb_card10.png' corner='10,10,10,10'" inset="22,18,22,18" childpadding="0">
+					<HorizontalLayout height="22" childvalign="vcenter">
+						<Control width="3" maxheight="15" bkcolor="#FF2E9B5C" borderround="3,3" />
+						<Control width="10" />
+						<Label text="库存金额" font="116" textcolor="#FF1F2329" maxheight="22" autocalcwidth="true" />
+						<Control width="6" />
+						<Label text="库存成本 = 加权平均成本价 x 当前库存;预计利润 = 预计销售额 - 库存成本" font="12" textcolor="#FF8A9099" maxheight="17" autocalcwidth="true" />
+						<Control />
+						<Label name="kc_cx_amt_count" text="共 0 项" font="12" textcolor="#FF8A9099" maxheight="17" autocalcwidth="true" />
+					</HorizontalLayout>
+					<Control height="14" />
+					<VerticalLayout name="kc_cx_tblcard_amt" bkimage="file='kc_tblcard.png' corner='10,45,10,10'" childpadding="0">
+						<List name="kc_cx_amt_list" height="481" vscrollbar="false" inset="1,1,1,10" bkcolor="#00000000" itemhotbkcolor="#FFF7FAF8" itemselectedbkcolor="#FFEAF5EE">
+							<ListHeader height="44" bkcolor="#00000000" bordercolor="#00000000" bordersize="0" />
+							<ListHeaderItem text="商品名称" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="成本价模式" width="119" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="当前进货价" width="107" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="加权平均成本价" width="131" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="当前库存" width="96" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="库存单位" width="84" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="库存成本" width="119" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="当前销售价" width="107" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="预计销售额" width="107" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="预计利润" width="84" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="预计利润率" width="107" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+						</List>
+					</VerticalLayout>
+					<Label name="kc_cx_amt_foot" text="已全部加载 · 共 0 项" font="12" textcolor="#FF8A9099" height="44" valign="center" align="center" bkcolor="#FFFAFBFC" />
+				</VerticalLayout>
+			</VerticalLayout>
+
+			<!-- ==================== 视图 2:入库(入库记录 / 入库统计) ==================== -->
+			<VerticalLayout name="kc_view_ruku" visible="false" padding="0,0,28,0" childpadding="16">
+				<HorizontalLayout height="96" childpadding="16">
+					<VerticalLayout bkimage="file='kc_stat_blue.png' corner='10,10,10,10'" inset="18,16,18,16" childpadding="0">
+						<HorizontalLayout height="20" childvalign="vcenter">
+							<Control width="3" maxheight="13" bkcolor="#FF4A90E2" borderround="3,3" />
+							<Control width="8" />
+							<Label text="本月入库单数" font="13" textcolor="#FF5F6368" maxheight="20" autocalcwidth="true" />
+						</HorizontalLayout>
+						<Control height="8" />
+						<Label name="kc_rk_stat_num" showhtml="true" font="126" textcolor="#FF1F2329" height="36" text="--{x 4}{c #8A9099}{f 13}单{/f}{/c}" />
+					</VerticalLayout>
+					<VerticalLayout bkimage="file='kc_stat_grn.png' corner='10,10,10,10'" inset="18,16,18,16" childpadding="0">
+						<HorizontalLayout height="20" childvalign="vcenter">
+							<Control width="3" maxheight="13" bkcolor="#FF2E9B5C" borderround="3,3" />
+							<Control width="8" />
+							<Label text="本月入库金额" font="13" textcolor="#FF5F6368" maxheight="20" autocalcwidth="true" />
+						</HorizontalLayout>
+						<Control height="8" />
+						<Label name="kc_rk_stat_amount" showhtml="true" font="126" textcolor="#FF1F2329" height="36" text="--{x 4}{c #8A9099}{f 13}元{/f}{/c}" />
+					</VerticalLayout>
+					<VerticalLayout bkimage="file='kc_stat_pur.png' corner='10,10,10,10'" inset="18,16,18,16" childpadding="0">
+						<HorizontalLayout height="20" childvalign="vcenter">
+							<Control width="3" maxheight="13" bkcolor="#FF7C6BD6" borderround="3,3" />
+							<Control width="8" />
+							<Label text="入库商品数" font="13" textcolor="#FF5F6368" maxheight="20" autocalcwidth="true" />
+						</HorizontalLayout>
+						<Control height="8" />
+						<Label name="kc_rk_stat_goods" showhtml="true" font="126" textcolor="#FF1F2329" height="36" text="--{x 4}{c #8A9099}{f 13}项{/f}{/c}" />
+					</VerticalLayout>
+					<VerticalLayout bkimage="file='kc_stat_org.png' corner='10,10,10,10'" inset="18,16,18,16" childpadding="0">
+						<HorizontalLayout height="20" childvalign="vcenter">
+							<Control width="3" maxheight="13" bkcolor="#FFE08A17" borderround="3,3" />
+							<Control width="8" />
+							<Label text="本月退货入库" font="13" textcolor="#FF5F6368" maxheight="20" autocalcwidth="true" />
+						</HorizontalLayout>
+						<Control height="8" />
+						<Label name="kc_rk_stat_return" showhtml="true" font="126" textcolor="#FF1F2329" height="36" text="--{x 4}{c #8A9099}{f 13}单{/f}{/c}" />
+					</VerticalLayout>
+				</HorizontalLayout>
+				<HorizontalLayout height="42" childvalign="vcenter">
+					<HorizontalLayout width="182" maxheight="42" bkimage="file='kc_segcard.png' corner='21,21,21,21'" inset="5,5,5,5" childpadding="4" childvalign="vcenter">
+						<Button name="kc_rk_seg_record" text="入库记录" font="113" textcolor="#FFFFFFFF" hottextcolor="#FFFFFFFF" pushedtextcolor="#FFFFFFFF" width="84" maxheight="32" align="center" normalimage="file='kc_seggrn_n.png' corner='16,16,16,16'" hotimage="file='kc_seggrn_h.png' corner='16,16,16,16'" pushedimage="file='kc_seggrn_p.png' corner='16,16,16,16'" />
+						<Button name="kc_rk_seg_stat" text="入库统计" font="13" textcolor="#FF5F6368" hottextcolor="#FF2E9B5C" pushedtextcolor="#FF2E9B5C" width="84" maxheight="32" align="center" normalimage="" hotimage="file='kc_seggray_h.png' corner='16,16,16,16'" pushedimage="file='kc_seggray_p.png' corner='16,16,16,16'" />
+					</HorizontalLayout>
+					<Control />
+				</HorizontalLayout>
+				<!-- 筛选行:记录态只用「全部类型」下拉;统计态 = 时段 + 搜索 + 全部分类(时段在搜索框左边)。
+					两态共用同一行 —— 不可见子项会被 HorizontalLayout 跳过,不会占位,所以只需一个「新建入库单」按钮。 -->
+				<HorizontalLayout height="40" childpadding="12" childvalign="vcenter">
+					<Combo name="kc_rk_combo_range" visible="false" width="120" height="40" maxheight="40" normalimage="file='gd_combo40_n.png' corner='8,8,22,8'" hotimage="file='gd_combo40_h.png' corner='8,8,22,8'" pushedimage="file='gd_combo40_p.png' corner='8,8,22,8'" textpadding="11,0,30,0" />
+					<HorizontalLayout name="kc_rk_search_box" visible="false" width="240" bkimage="file='dc_search.png' corner='20,20,20,20'" inset="12,0,12,0" childpadding="8" childvalign="vcenter">
+						<Control bkimage="dc_ico_search16.png" width="16" height="16" maxheight="16" />
+						<Edit name="kc_rk_search_edit" tooltip="请输入商品名称或拼音码" font="12" textcolor="#FF1F2329" maxheight="24" bkcolor="#00000000" nativebkcolor="#FFEFF1F3" />
+						<Label name="kc_rk_search_tishi" text="请输入商品名称或拼音码" width="150" height="20" font="12" float="true" pos="40,10,190,30" mouse="false" valign="center" textcolor="#FFA8ADB3" />
+					</HorizontalLayout>
+					<Combo name="kc_rk_combo_type" width="140" height="40" maxheight="40" normalimage="file='gd_combo40_n.png' corner='8,8,22,8'" hotimage="file='gd_combo40_h.png' corner='8,8,22,8'" pushedimage="file='gd_combo40_p.png' corner='8,8,22,8'" textpadding="11,0,30,0" />
+					<Combo name="kc_rk_combo_cat" visible="false" width="150" height="40" maxheight="40" normalimage="file='gd_combo40_n.png' corner='8,8,22,8'" hotimage="file='gd_combo40_h.png' corner='8,8,22,8'" pushedimage="file='gd_combo40_p.png' corner='8,8,22,8'" textpadding="11,0,30,0" />
+					<Control />
+					<Button name="kc_rk_new_btn" text="新建入库单" font="14" textcolor="#FFFFFFFF" width="128" height="40" maxheight="40" normalimage="file='btn_green_zhengchang.png' corner='8,8,8,8'" hotimage="file='btn_green_xuanfu.png' corner='8,8,8,8'" pushedimage="file='btn_green_dianji.png' corner='8,8,8,8'" />
+				</HorizontalLayout>
+				<!-- 入库记录 -->
+				<VerticalLayout name="kc_rk_body_record" bkimage="file='bb_card10.png' corner='10,10,10,10'" inset="22,18,22,18" childpadding="0">
+					<HorizontalLayout height="22" childvalign="vcenter">
+						<Control width="3" maxheight="15" bkcolor="#FF2E9B5C" borderround="3,3" />
+						<Control width="10" />
+						<Label text="入库记录" font="116" textcolor="#FF1F2329" maxheight="22" autocalcwidth="true" />
+						<Control width="6" />
+						<Label text="采购 / 调拨 / 退货入库,保存后立即生效并增加库存,按入库时间倒序" font="12" textcolor="#FF8A9099" maxheight="17" autocalcwidth="true" />
+						<Control />
+						<Label name="kc_rk_list_count" text="共 0 项" font="12" textcolor="#FF8A9099" maxheight="17" autocalcwidth="true" />
+					</HorizontalLayout>
+					<Control height="14" />
+					<VerticalLayout name="kc_rk_tblcard" bkimage="file='kc_tblcard.png' corner='10,45,10,10'" childpadding="0">
+						<List name="kc_rk_list" height="441" vscrollbar="false" inset="1,1,1,10" bkcolor="#00000000" itemhotbkcolor="#FFF7FAF8" itemselectedbkcolor="#FFEAF5EE">
+							<ListHeader height="44" bkcolor="#00000000" bordercolor="#00000000" bordersize="0" />
+							<ListHeaderItem text="入库单号" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="入库类型" width="167" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="商品数" width="119" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="金额(元)" width="167" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="经手人" width="143" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="状态" width="143" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="操作" width="239" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+						</List>
+					</VerticalLayout>
+					<Label name="kc_rk_list_foot" text="按时间倒序 · 已全部加载 · 共 0 条" font="12" textcolor="#FF8A9099" height="44" valign="center" align="center" bkcolor="#FFFAFBFC" />
+				</VerticalLayout>
+				<!-- 入库统计(按商品维度汇总) -->
+				<VerticalLayout name="kc_rk_body_stat" visible="false" bkimage="file='bb_card10.png' corner='10,10,10,10'" inset="22,18,22,18" childpadding="0">
+					<HorizontalLayout height="22" childvalign="vcenter">
+						<Control width="3" maxheight="15" bkcolor="#FF2E9B5C" borderround="3,3" />
+						<Control width="10" />
+						<Label text="入库统计" font="116" textcolor="#FF1F2329" maxheight="22" autocalcwidth="true" />
+						<Control width="6" />
+						<Label text="按商品维度汇总本期入库数据,占比 = 该商品金额 / 入库总金额" font="12" textcolor="#FF8A9099" maxheight="17" autocalcwidth="true" />
+						<Control />
+						<Label name="kc_rk_stat_count" text="共 0 项" font="12" textcolor="#FF8A9099" maxheight="17" autocalcwidth="true" />
+					</HorizontalLayout>
+					<Control height="14" />
+					<VerticalLayout name="kc_rk_tblcard_stat" bkimage="file='kc_tblcard.png' corner='10,45,10,10'" childpadding="0">
+						<List name="kc_rk_list_stat" height="441" vscrollbar="false" inset="1,1,1,10" bkcolor="#00000000" itemhotbkcolor="#FFF7FAF8" itemselectedbkcolor="#FFEAF5EE">
+							<ListHeader height="44" bkcolor="#00000000" bordercolor="#00000000" bordersize="0" />
+							<ListHeaderItem text="商品名称" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="分类" width="119" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="单位" width="96" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="入库单数" width="119" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="入库数量" width="143" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="金额(元)" width="143" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="金额占比" width="358" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+						</List>
+					</VerticalLayout>
+					<Label name="kc_rk_stat_foot" text="已全部加载 · 共 0 项" font="12" textcolor="#FF8A9099" height="44" valign="center" align="center" bkcolor="#FFFAFBFC" />
+				</VerticalLayout>
+			</VerticalLayout>
+
+			<!-- ==================== 视图 3:出库(出库记录 / 出库统计) ==================== -->
+			<VerticalLayout name="kc_view_chuku" visible="false" padding="0,0,28,0" childpadding="16">
+				<HorizontalLayout height="96" childpadding="16">
+					<VerticalLayout bkimage="file='kc_stat_blue.png' corner='10,10,10,10'" inset="18,16,18,16" childpadding="0">
+						<HorizontalLayout height="20" childvalign="vcenter">
+							<Control width="3" maxheight="13" bkcolor="#FF4A90E2" borderround="3,3" />
+							<Control width="8" />
+							<Label text="本月出库单数" font="13" textcolor="#FF5F6368" maxheight="20" autocalcwidth="true" />
+						</HorizontalLayout>
+						<Control height="8" />
+						<Label name="kc_ck_stat_num" showhtml="true" font="126" textcolor="#FF1F2329" height="36" text="--{x 4}{c #8A9099}{f 13}单{/f}{/c}" />
+					</VerticalLayout>
+					<VerticalLayout bkimage="file='kc_stat_org.png' corner='10,10,10,10'" inset="18,16,18,16" childpadding="0">
+						<HorizontalLayout height="20" childvalign="vcenter">
+							<Control width="3" maxheight="13" bkcolor="#FFE08A17" borderround="3,3" />
+							<Control width="8" />
+							<Label text="本月出库金额" font="13" textcolor="#FF5F6368" maxheight="20" autocalcwidth="true" />
+						</HorizontalLayout>
+						<Control height="8" />
+						<Label name="kc_ck_stat_amount" showhtml="true" font="126" textcolor="#FF1F2329" height="36" text="--{x 4}{c #8A9099}{f 13}元{/f}{/c}" />
+					</VerticalLayout>
+					<VerticalLayout bkimage="file='kc_stat_red.png' corner='10,10,10,10'" inset="18,16,18,16" childpadding="0">
+						<HorizontalLayout height="20" childvalign="vcenter">
+							<Control width="3" maxheight="13" bkcolor="#FFE14B4A" borderround="3,3" />
+							<Control width="8" />
+							<Label text="损耗金额" font="13" textcolor="#FF5F6368" maxheight="20" autocalcwidth="true" />
+						</HorizontalLayout>
+						<Control height="8" />
+						<Label name="kc_ck_stat_loss" showhtml="true" font="126" textcolor="#FF1F2329" height="36" text="--{x 4}{c #8A9099}{f 13}元{/f}{/c}" />
+					</VerticalLayout>
+					<VerticalLayout bkimage="file='kc_stat_pur.png' corner='10,10,10,10'" inset="18,16,18,16" childpadding="0">
+						<HorizontalLayout height="20" childvalign="vcenter">
+							<Control width="3" maxheight="13" bkcolor="#FF7C6BD6" borderround="3,3" />
+							<Control width="8" />
+							<Label text="出库商品数" font="13" textcolor="#FF5F6368" maxheight="20" autocalcwidth="true" />
+						</HorizontalLayout>
+						<Control height="8" />
+						<Label name="kc_ck_stat_goods" showhtml="true" font="126" textcolor="#FF1F2329" height="36" text="--{x 4}{c #8A9099}{f 13}项{/f}{/c}" />
+					</VerticalLayout>
+				</HorizontalLayout>
+				<HorizontalLayout height="42" childvalign="vcenter">
+					<HorizontalLayout width="182" maxheight="42" bkimage="file='kc_segcard.png' corner='21,21,21,21'" inset="5,5,5,5" childpadding="4" childvalign="vcenter">
+						<Button name="kc_ck_seg_record" text="出库记录" font="113" textcolor="#FFFFFFFF" hottextcolor="#FFFFFFFF" pushedtextcolor="#FFFFFFFF" width="84" maxheight="32" align="center" normalimage="file='kc_seggrn_n.png' corner='16,16,16,16'" hotimage="file='kc_seggrn_h.png' corner='16,16,16,16'" pushedimage="file='kc_seggrn_p.png' corner='16,16,16,16'" />
+						<Button name="kc_ck_seg_stat" text="出库统计" font="13" textcolor="#FF5F6368" hottextcolor="#FF2E9B5C" pushedtextcolor="#FF2E9B5C" width="84" maxheight="32" align="center" normalimage="" hotimage="file='kc_seggray_h.png' corner='16,16,16,16'" pushedimage="file='kc_seggray_p.png' corner='16,16,16,16'" />
+					</HorizontalLayout>
+					<Control />
+				</HorizontalLayout>
+				<HorizontalLayout height="40" childpadding="12" childvalign="vcenter">
+					<Combo name="kc_ck_combo_range" visible="false" width="120" height="40" maxheight="40" normalimage="file='gd_combo40_n.png' corner='8,8,22,8'" hotimage="file='gd_combo40_h.png' corner='8,8,22,8'" pushedimage="file='gd_combo40_p.png' corner='8,8,22,8'" textpadding="11,0,30,0" />
+					<HorizontalLayout name="kc_ck_search_box" visible="false" width="240" bkimage="file='dc_search.png' corner='20,20,20,20'" inset="12,0,12,0" childpadding="8" childvalign="vcenter">
+						<Control bkimage="dc_ico_search16.png" width="16" height="16" maxheight="16" />
+						<Edit name="kc_ck_search_edit" tooltip="请输入商品名称或拼音码" font="12" textcolor="#FF1F2329" maxheight="24" bkcolor="#00000000" nativebkcolor="#FFEFF1F3" />
+						<Label name="kc_ck_search_tishi" text="请输入商品名称或拼音码" width="150" height="20" font="12" float="true" pos="40,10,190,30" mouse="false" valign="center" textcolor="#FFA8ADB3" />
+					</HorizontalLayout>
+					<Combo name="kc_ck_combo_type" width="140" height="40" maxheight="40" normalimage="file='gd_combo40_n.png' corner='8,8,22,8'" hotimage="file='gd_combo40_h.png' corner='8,8,22,8'" pushedimage="file='gd_combo40_p.png' corner='8,8,22,8'" textpadding="11,0,30,0" />
+					<Combo name="kc_ck_combo_cat" visible="false" width="150" height="40" maxheight="40" normalimage="file='gd_combo40_n.png' corner='8,8,22,8'" hotimage="file='gd_combo40_h.png' corner='8,8,22,8'" pushedimage="file='gd_combo40_p.png' corner='8,8,22,8'" textpadding="11,0,30,0" />
+					<Control />
+					<Button name="kc_ck_new_btn" text="新建出库单" font="14" textcolor="#FFFFFFFF" width="128" height="40" maxheight="40" normalimage="file='btn_org_n.png' corner='8,8,8,8'" hotimage="file='btn_org_h.png' corner='8,8,8,8'" pushedimage="file='btn_org_p.png' corner='8,8,8,8'" />
+				</HorizontalLayout>
+				<!-- 出库记录 -->
+				<VerticalLayout name="kc_ck_body_record" bkimage="file='bb_card10.png' corner='10,10,10,10'" inset="22,18,22,18" childpadding="0">
+					<HorizontalLayout height="22" childvalign="vcenter">
+						<Control width="3" maxheight="15" bkcolor="#FFE08A17" borderround="3,3" />
+						<Control width="10" />
+						<Label text="出库记录" font="116" textcolor="#FF1F2329" maxheight="22" autocalcwidth="true" />
+						<Control width="6" />
+						<Label text="调拨出库 / 报损 / 采购退货,保存后立即生效并减少库存,按出库时间倒序" font="12" textcolor="#FF8A9099" maxheight="17" autocalcwidth="true" />
+						<Control />
+						<Label name="kc_ck_list_count" text="共 0 项" font="12" textcolor="#FF8A9099" maxheight="17" autocalcwidth="true" />
+					</HorizontalLayout>
+					<Control height="14" />
+					<VerticalLayout name="kc_ck_tblcard" bkimage="file='kc_tblcard.png' corner='10,45,10,10'" childpadding="0">
+						<List name="kc_ck_list" height="441" vscrollbar="false" inset="1,1,1,10" bkcolor="#00000000" itemhotbkcolor="#FFF7FAF8" itemselectedbkcolor="#FFEAF5EE">
+							<ListHeader height="44" bkcolor="#00000000" bordercolor="#00000000" bordersize="0" />
+							<ListHeaderItem text="出库单号" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="出库类型" width="167" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="商品数" width="107" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="金额(元)" width="155" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="经手人" width="119" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="状态" width="131" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="操作" width="299" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+						</List>
+					</VerticalLayout>
+					<Label name="kc_ck_list_foot" text="按时间倒序 · 已全部加载 · 共 0 条" font="12" textcolor="#FF8A9099" height="44" valign="center" align="center" bkcolor="#FFFAFBFC" />
+				</VerticalLayout>
+				<!-- 出库统计(按商品维度汇总) -->
+				<VerticalLayout name="kc_ck_body_stat" visible="false" bkimage="file='bb_card10.png' corner='10,10,10,10'" inset="22,18,22,18" childpadding="0">
+					<HorizontalLayout height="22" childvalign="vcenter">
+						<Control width="3" maxheight="15" bkcolor="#FFE08A17" borderround="3,3" />
+						<Control width="10" />
+						<Label text="出库统计" font="116" textcolor="#FF1F2329" maxheight="22" autocalcwidth="true" />
+						<Control width="6" />
+						<Label text="按商品维度汇总本期出库数据,占比 = 该商品金额 / 出库总金额" font="12" textcolor="#FF8A9099" maxheight="17" autocalcwidth="true" />
+						<Control />
+						<Label name="kc_ck_stat_count" text="共 0 项" font="12" textcolor="#FF8A9099" maxheight="17" autocalcwidth="true" />
+					</HorizontalLayout>
+					<Control height="14" />
+					<VerticalLayout name="kc_ck_tblcard_stat" bkimage="file='kc_tblcard.png' corner='10,45,10,10'" childpadding="0">
+						<List name="kc_ck_list_stat" height="441" vscrollbar="false" inset="1,1,1,10" bkcolor="#00000000" itemhotbkcolor="#FFF7FAF8" itemselectedbkcolor="#FFEAF5EE">
+							<ListHeader height="44" bkcolor="#00000000" bordercolor="#00000000" bordersize="0" />
+							<ListHeaderItem text="商品名称" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="分类" width="119" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="单位" width="96" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="出库单数" width="119" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="出库数量" width="143" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="金额(元)" width="143" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="金额占比" width="358" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+						</List>
+					</VerticalLayout>
+					<Label name="kc_ck_stat_foot" text="已全部加载 · 共 0 项" font="12" textcolor="#FF8A9099" height="44" valign="center" align="center" bkcolor="#FFFAFBFC" />
+				</VerticalLayout>
+			</VerticalLayout>
+
+			<!-- ==================== 视图 4:库存盘点(盘点记录 / 盘点差异) ==================== -->
+			<VerticalLayout name="kc_view_pandian" visible="false" padding="0,0,28,0" childpadding="16">
+				<HorizontalLayout height="96" childpadding="16">
+					<VerticalLayout bkimage="file='kc_stat_blue.png' corner='10,10,10,10'" inset="18,16,18,16" childpadding="0">
+						<HorizontalLayout height="20" childvalign="vcenter">
+							<Control width="3" maxheight="13" bkcolor="#FF4A90E2" borderround="3,3" />
+							<Control width="8" />
+							<Label text="本月盘点" font="13" textcolor="#FF5F6368" maxheight="20" autocalcwidth="true" />
+						</HorizontalLayout>
+						<Control height="8" />
+						<Label name="kc_pd_stat_num" showhtml="true" font="126" textcolor="#FF1F2329" height="36" text="--{x 4}{c #8A9099}{f 13}次{/f}{/c}" />
+					</VerticalLayout>
+					<VerticalLayout bkimage="file='kc_stat_grn.png' corner='10,10,10,10'" inset="18,16,18,16" childpadding="0">
+						<HorizontalLayout height="20" childvalign="vcenter">
+							<Control width="3" maxheight="13" bkcolor="#FF2E9B5C" borderround="3,3" />
+							<Control width="8" />
+							<Label text="盘盈商品" font="13" textcolor="#FF5F6368" maxheight="20" autocalcwidth="true" />
+						</HorizontalLayout>
+						<Control height="8" />
+						<Label name="kc_pd_stat_gain" showhtml="true" font="126" textcolor="#FF1F2329" height="36" text="--{x 4}{c #8A9099}{f 13}项{/f}{/c}" />
+					</VerticalLayout>
+					<VerticalLayout bkimage="file='kc_stat_red.png' corner='10,10,10,10'" inset="18,16,18,16" childpadding="0">
+						<HorizontalLayout height="20" childvalign="vcenter">
+							<Control width="3" maxheight="13" bkcolor="#FFE14B4A" borderround="3,3" />
+							<Control width="8" />
+							<Label text="盘亏商品" font="13" textcolor="#FF5F6368" maxheight="20" autocalcwidth="true" />
+						</HorizontalLayout>
+						<Control height="8" />
+						<Label name="kc_pd_stat_loss" showhtml="true" font="126" textcolor="#FF1F2329" height="36" text="--{x 4}{c #8A9099}{f 13}项{/f}{/c}" />
+					</VerticalLayout>
+					<VerticalLayout bkimage="file='kc_stat_org.png' corner='10,10,10,10'" inset="18,16,18,16" childpadding="0">
+						<HorizontalLayout height="20" childvalign="vcenter">
+							<Control width="3" maxheight="13" bkcolor="#FFE08A17" borderround="3,3" />
+							<Control width="8" />
+							<Label text="盈亏金额" font="13" textcolor="#FF5F6368" maxheight="20" autocalcwidth="true" />
+						</HorizontalLayout>
+						<Control height="8" />
+						<Label name="kc_pd_stat_amount" showhtml="true" font="126" textcolor="#FF1F2329" height="36" text="--{x 4}{c #8A9099}{f 13}元{/f}{/c}" />
+					</VerticalLayout>
+				</HorizontalLayout>
+				<HorizontalLayout height="42" childvalign="vcenter">
+					<HorizontalLayout width="182" maxheight="42" bkimage="file='kc_segcard.png' corner='21,21,21,21'" inset="5,5,5,5" childpadding="4" childvalign="vcenter">
+						<Button name="kc_pd_seg_record" text="盘点记录" font="113" textcolor="#FFFFFFFF" hottextcolor="#FFFFFFFF" pushedtextcolor="#FFFFFFFF" width="84" maxheight="32" align="center" normalimage="file='kc_seggrn_n.png' corner='16,16,16,16'" hotimage="file='kc_seggrn_h.png' corner='16,16,16,16'" pushedimage="file='kc_seggrn_p.png' corner='16,16,16,16'" />
+						<Button name="kc_pd_seg_stat" text="盘点差异" font="13" textcolor="#FF5F6368" hottextcolor="#FF2E9B5C" pushedtextcolor="#FF2E9B5C" width="84" maxheight="32" align="center" normalimage="" hotimage="file='kc_seggray_h.png' corner='16,16,16,16'" pushedimage="file='kc_seggray_p.png' corner='16,16,16,16'" />
+					</HorizontalLayout>
+					<Control />
+				</HorizontalLayout>
+				<HorizontalLayout height="40" childpadding="12" childvalign="vcenter">
+					<Combo name="kc_pd_combo_range" visible="false" width="120" height="40" maxheight="40" normalimage="file='gd_combo40_n.png' corner='8,8,22,8'" hotimage="file='gd_combo40_h.png' corner='8,8,22,8'" pushedimage="file='gd_combo40_p.png' corner='8,8,22,8'" textpadding="11,0,30,0" />
+					<HorizontalLayout name="kc_pd_search_box" visible="false" width="240" bkimage="file='dc_search.png' corner='20,20,20,20'" inset="12,0,12,0" childpadding="8" childvalign="vcenter">
+						<Control bkimage="dc_ico_search16.png" width="16" height="16" maxheight="16" />
+						<Edit name="kc_pd_search_edit" tooltip="请输入商品名称或拼音码" font="12" textcolor="#FF1F2329" maxheight="24" bkcolor="#00000000" nativebkcolor="#FFEFF1F3" />
+						<Label name="kc_pd_search_tishi" text="请输入商品名称或拼音码" width="150" height="20" font="12" float="true" pos="40,10,190,30" mouse="false" valign="center" textcolor="#FFA8ADB3" />
+					</HorizontalLayout>
+					<Combo name="kc_pd_combo_result" width="140" height="40" maxheight="40" normalimage="file='gd_combo40_n.png' corner='8,8,22,8'" hotimage="file='gd_combo40_h.png' corner='8,8,22,8'" pushedimage="file='gd_combo40_p.png' corner='8,8,22,8'" textpadding="11,0,30,0" />
+					<Combo name="kc_pd_combo_cat" visible="false" width="150" height="40" maxheight="40" normalimage="file='gd_combo40_n.png' corner='8,8,22,8'" hotimage="file='gd_combo40_h.png' corner='8,8,22,8'" pushedimage="file='gd_combo40_p.png' corner='8,8,22,8'" textpadding="11,0,30,0" />
+					<Control />
+					<Button name="kc_pd_new_btn" text="新建盘点单" font="14" textcolor="#FFFFFFFF" width="128" height="40" maxheight="40" normalimage="file='btn_green_zhengchang.png' corner='8,8,8,8'" hotimage="file='btn_green_xuanfu.png' corner='8,8,8,8'" pushedimage="file='btn_green_dianji.png' corner='8,8,8,8'" />
+				</HorizontalLayout>
+				<!-- 盘点记录(无草稿 / 进行中态,盘点结果 = 盘盈 / 盘亏 / 无差异) -->
+				<VerticalLayout name="kc_pd_body_record" bkimage="file='bb_card10.png' corner='10,10,10,10'" inset="22,18,22,18" childpadding="0">
+					<HorizontalLayout height="22" childvalign="vcenter">
+						<Control width="3" maxheight="15" bkcolor="#FF2E9B5C" borderround="3,3" />
+						<Control width="10" />
+						<Label text="盘点记录" font="116" textcolor="#FF1F2329" maxheight="22" autocalcwidth="true" />
+						<Control width="6" />
+						<Label text="实物盘点,保存后立即生成盘盈盘亏并校正账面库存(无草稿态),按盘点时间倒序" font="12" textcolor="#FF8A9099" maxheight="17" autocalcwidth="true" />
+						<Control />
+						<Label name="kc_pd_list_count" text="共 0 项" font="12" textcolor="#FF8A9099" maxheight="17" autocalcwidth="true" />
+					</HorizontalLayout>
+					<Control height="14" />
+					<VerticalLayout name="kc_pd_tblcard" bkimage="file='kc_tblcard.png' corner='10,45,10,10'" childpadding="0">
+						<List name="kc_pd_list" height="441" vscrollbar="false" inset="1,1,1,10" bkcolor="#00000000" itemhotbkcolor="#FFF7FAF8" itemselectedbkcolor="#FFEAF5EE">
+							<ListHeader height="44" bkcolor="#00000000" bordercolor="#00000000" bordersize="0" />
+							<ListHeaderItem text="盘点单号" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="盘点范围" width="155" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="商品数" width="96" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="盘盈" width="96" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="盘亏" width="96" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="盈亏金额(元)" width="143" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="盘点人" width="107" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="盘点结果" width="119" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="操作" width="203" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+						</List>
+					</VerticalLayout>
+					<Label name="kc_pd_list_foot" text="按时间倒序 · 已全部加载 · 共 0 条" font="12" textcolor="#FF8A9099" height="44" valign="center" align="center" bkcolor="#FFFAFBFC" />
+				</VerticalLayout>
+				<!-- 盘点差异(只列有差异的商品) -->
+				<VerticalLayout name="kc_pd_body_stat" visible="false" bkimage="file='bb_card10.png' corner='10,10,10,10'" inset="22,18,22,18" childpadding="0">
+					<HorizontalLayout height="22" childvalign="vcenter">
+						<Control width="3" maxheight="15" bkcolor="#FF2E9B5C" borderround="3,3" />
+						<Control width="10" />
+						<Label text="盘点差异" font="116" textcolor="#FF1F2329" maxheight="22" autocalcwidth="true" />
+						<Control width="6" />
+						<Label text="本期已完成盘点单的差异商品(仅列出有差异项),金额 = 差异 x 移动加权成本单价" font="12" textcolor="#FF8A9099" maxheight="17" autocalcwidth="true" />
+						<Control />
+						<Label name="kc_pd_stat_count" text="共 0 项" font="12" textcolor="#FF8A9099" maxheight="17" autocalcwidth="true" />
+					</HorizontalLayout>
+					<Control height="14" />
+					<VerticalLayout name="kc_pd_tblcard_stat" bkimage="file='kc_tblcard.png' corner='10,45,10,10'" childpadding="0">
+						<List name="kc_pd_list_stat" height="441" vscrollbar="false" inset="1,1,1,10" bkcolor="#00000000" itemhotbkcolor="#FFF7FAF8" itemselectedbkcolor="#FFEAF5EE">
+							<ListHeader height="44" bkcolor="#00000000" bordercolor="#00000000" bordersize="0" />
+							<ListHeaderItem text="商品名称" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="分类" width="143" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="单位" width="119" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="盘点单数" width="143" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="差异" width="143" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="盈亏金额(元)" width="215" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="结果" width="191" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+						</List>
+					</VerticalLayout>
+					<Label name="kc_pd_stat_foot" text="已全部加载 · 共 0 项" font="12" textcolor="#FF8A9099" height="44" valign="center" align="center" bkcolor="#FFFAFBFC" />
+				</VerticalLayout>
+			</VerticalLayout>
+			</VerticalLayout>
+
+			<!-- ==================== 子视图 A:新建入库单(设计稿 v4 p1) ==================== -->
+			<!-- 独立整页:挂 kc_page(**不再**是 kc_scroll 的子项)。设计稿 .pbar/.pbody/.pfoot 三段都通栏,
+			     留在滚动容器里会被 inset + 子项 padding 夹住 ⇒ 只能做成圆角卡片。三页与 kc_scroll 互斥显隐,
+			     CVerticalLayoutUI::SetPos 会 continue 跳过不可见子项 ⇒ 同一时刻只有一个弹性子项参与高度分配。
+			     本页的底栏 kc_new_foot_rk 与键盘面板 kc_keypad 都放在页面级(声明在 3 个视图之后)。 -->
+			<VerticalLayout name="kc_view_rk_new" visible="false" childpadding="0">
+
+				<!-- 页头 .pbar(高 64 / 白底 / 下 1px #E8EAED / 左右 24 / 子项间距 14) -->
+				<HorizontalLayout name="kc_rkn_bar" height="64" bkcolor="#FFFFFFFF" bordersize="0,0,0,1" bordercolor="#FFE8EAED" inset="24,0,24,0" childpadding="14" childvalign="vcenter">
+					<Button name="kc_rkn_back" text="← 返回" font="14" textcolor="#FF5F6368" hottextcolor="#FF2E9B5C" pushedtextcolor="#FF2E9B5C" width="78" maxheight="48" normalimage="file='gd_pill48_ghost_n.png' corner='24,24,24,24'" hotimage="file='gd_pill48_ghost_h.png' corner='24,24,24,24'" pushedimage="file='gd_pill48_ghost_p.png' corner='24,24,24,24'" />
+					<Label text="新建入库单" font="118" textcolor="#FF1F2329" maxheight="26" autocalcwidth="true" />
+					<Label text="保存后立即生效并增加库存" font="12" textcolor="#FF8A9099" maxheight="20" autocalcwidth="true" />
+					<Control />
+					<Label name="kc_rkn_no" text="单号 保存后由后端生成" font="13" textcolor="#FF8A9099" maxheight="22" autocalcwidth="true" />
+				</HorizontalLayout>
+
+				<!-- 主体 .pbody(#F5F7FA / padding 14 24 18 / 弹性 + 自带滚动条)。
+				     右 inset 归 0 ⇒ 滚动条贴页右缘;右侧 24px 留白改由每个子项自己 padding=&quot;0,0,24,0&quot; 承担。
+				     高度不写死(弹性)⇒ 页头/底栏固定、主体吃满中间;内容超高时自己滚,不再要 kc_scroll。 -->
+				<VerticalLayout name="kc_rkn_body" vscrollbar="true" bkcolor="#FFF5F7FA" inset="24,14,0,18" childpadding="0">
+
+					<!-- .card:白底 1px #E8EAED + r10;两个字段**等宽**(.formgrid.g2 = 1fr 1fr,gap 12)
+					     —— 宽度都不写,HorizontalLayout 里两个无固定宽的子项自动均分剩余宽度。 -->
+					<VerticalLayout height="98" padding="0,0,24,0" bkimage="file='bb_card10.png' corner='10,10,10,10'" inset="20,14,20,14" childpadding="0">
+						<HorizontalLayout height="69" childpadding="12" childvalign="vcenter">
+							<VerticalLayout childpadding="7">
+								<HorizontalLayout height="18" childpadding="5" childvalign="vcenter">
+									<Label text="*" font="13" textcolor="#FFE14B4A" maxheight="18" autocalcwidth="true" />
+									<Label text="入库类型" font="13" textcolor="#FF5F6368" maxheight="18" autocalcwidth="true" />
+								</HorizontalLayout>
+								<Combo name="kc_rkn_combo_type" height="44" maxheight="44" normalimage="file='gd_combo44_n.png' corner='8,8,22,8'" hotimage="file='gd_combo44_h.png' corner='8,8,22,8'" pushedimage="file='gd_combo44_p.png' corner='8,8,22,8'" textpadding="12,0,30,0" />
+							</VerticalLayout>
+							<VerticalLayout childpadding="7">
+								<Label text="备注" font="13" textcolor="#FF5F6368" height="18" />
+								<Button name="kc_rkn_note" text="采购到货,含配送费" font="13" textcolor="#FFA8ADB3" align="left" valign="vcenter" textpadding="12,0,12,0" height="44" maxheight="44" normalimage="file='input_r8_n.png' corner='8,8,8,8'" hotimage="file='input_r8_h.png' corner='8,8,8,8'" pushedimage="file='input_r8_n.png' corner='8,8,8,8'" />
+							</VerticalLayout>
+						</HorizontalLayout>
+					</VerticalLayout>
+
+					<Control height="12" padding="0,0,24,0" />
+
+					<!-- .addbar:白底 1px + r10,padding 10 / 14;提示左、按钮右 -->
+					<HorizontalLayout height="70" padding="0,0,24,0" bkimage="file='bb_card10.png' corner='10,10,10,10'" inset="14,10,14,10" childpadding="12" childvalign="vcenter">
+						<Label name="kc_rkn_tip" text="已添加 0 个商品 · 点「添加商品」勾选更多,或直接扫条码追加;点数量 / 单价单元格调出数字键盘" font="13" textcolor="#FF5F6368" maxheight="20" autocalcwidth="true" />
+						<Control />
+						<Button name="kc_rkn_add" text="添加商品" font="114" textcolor="#FFFFFFFF" hottextcolor="#FFFFFFFF" pushedtextcolor="#FFFFFFFF" width="102" maxheight="48" normalimage="file='btn_pill48_grn_n.png' corner='24,24,24,24'" hotimage="file='btn_pill48_grn_h.png' corner='24,24,24,24'" pushedimage="file='btn_pill48_grn_p.png' corner='24,24,24,24'" />
+					</HorizontalLayout>
+
+					<Control height="12" padding="0,0,24,0" />
+
+					<!-- .table:kc_tblcard.png 一张图烤进「1px 外框 + 43px 表头灰带 + 表头下 1px 分隔线」,
+					     表头灰带因此**齐卡片边框**(不是内缩)。List 用 inset=&quot;1,1,1,10&quot; 让开这三段与
+					     底部 r10 圆角带;表头不设底色,让烤进去的灰带透出来。ListHeader 必须保持可见
+					     (CListUI::SetPos 只在 !IsVisible() 时才用外框 rc 重排一遍)。
+					     高度由 C++ SyncTableHeight 写死 = 表头 44 + n*56 + List 上下 inset 11。 -->
+					<VerticalLayout name="kc_rkn_tblcard" height="223" padding="0,0,24,0" bkimage="file='kc_tblcard.png' corner='10,45,10,10'" childpadding="0">
+						<List name="kc_rkn_list" height="223" vscrollbar="false" inset="1,1,1,10" bkcolor="#00000000" itemhotbkcolor="#FFF7FAF8" itemselectedbkcolor="0">
+							<ListHeader height="44" bkcolor="#00000000" bordercolor="#00000000" bordersize="0" />
+							<ListHeaderItem text="商品名称" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="分类" width="149" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="单位" width="124" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="入库数量" width="187" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="单价(元)" width="174" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="金额(元)" width="174" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="操作" width="187" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+						</List>
+					</VerticalLayout>
+
+					<Control height="10" padding="0,0,24,0" />
+
+					<!-- .totbar:高 48 / #E8EAED / r8 / 左右 16;左组靠左,金额组靠**右**
+					     (靠一个无 width 的 &lt;Control /&gt; 当弹性 spacer 顶开;原实现漏了这个
+					     spacer,又塞了两个空占位 Label,导致金额紧贴「入库总数」)。 -->
+					<HorizontalLayout height="48" padding="0,0,24,0" bkimage="file='kc_tot_bg.png' corner='8,8,8,8'" inset="16,0,16,0" childpadding="0" childvalign="vcenter">
+						<Label text="合计商品" font="13" textcolor="#FF5F6368" maxheight="22" autocalcwidth="true" />
+						<Control width="5" />
+						<Label name="kc_rkn_tot_goods" text="0" font="113" textcolor="#FF1F2329" maxheight="22" autocalcwidth="true" />
+						<Control width="26" />
+						<Label text="入库总数" font="13" textcolor="#FF5F6368" maxheight="22" autocalcwidth="true" />
+						<Control width="5" />
+						<Label name="kc_rkn_tot_qty" text="0" font="113" textcolor="#FF1F2329" maxheight="22" autocalcwidth="true" />
+						<Control />
+						<Label name="kc_rkn_tot_amt_lab" text="入库金额" font="13" textcolor="#FF5F6368" maxheight="22" autocalcwidth="true" />
+						<Control width="34" />
+						<Label name="kc_rkn_tot_amt" text="¥0.00" font="119" textcolor="#FF2E9B5C" maxheight="26" autocalcwidth="true" />
+					</HorizontalLayout>
+
+				</VerticalLayout>
+			</VerticalLayout>
+
+			<!-- ==================== 子视图 B:新建出库单(设计稿 v4 p2) ==================== -->
+			<!-- 独立整页:挂 kc_page(**不再**是 kc_scroll 的子项)。设计稿 .pbar/.pbody/.pfoot 三段都通栏,
+			     留在滚动容器里会被 inset + 子项 padding 夹住 ⇒ 只能做成圆角卡片。三页与 kc_scroll 互斥显隐,
+			     CVerticalLayoutUI::SetPos 会 continue 跳过不可见子项 ⇒ 同一时刻只有一个弹性子项参与高度分配。
+			     本页的底栏 kc_new_foot_ck 与键盘面板 kc_keypad 都放在页面级(声明在 3 个视图之后)。 -->
+			<VerticalLayout name="kc_view_ck_new" visible="false" childpadding="0">
+
+				<!-- 页头 .pbar(高 64 / 白底 / 下 1px #E8EAED / 左右 24 / 子项间距 14) -->
+				<HorizontalLayout name="kc_ckn_bar" height="64" bkcolor="#FFFFFFFF" bordersize="0,0,0,1" bordercolor="#FFE8EAED" inset="24,0,24,0" childpadding="14" childvalign="vcenter">
+					<Button name="kc_ckn_back" text="← 返回" font="14" textcolor="#FF5F6368" hottextcolor="#FF2E9B5C" pushedtextcolor="#FF2E9B5C" width="78" maxheight="48" normalimage="file='gd_pill48_ghost_n.png' corner='24,24,24,24'" hotimage="file='gd_pill48_ghost_h.png' corner='24,24,24,24'" pushedimage="file='gd_pill48_ghost_p.png' corner='24,24,24,24'" />
+					<Label text="新建出库单" font="118" textcolor="#FF1F2329" maxheight="26" autocalcwidth="true" />
+					<Label text="保存后立即生效并减少库存" font="12" textcolor="#FF8A9099" maxheight="20" autocalcwidth="true" />
+					<Control />
+					<Label name="kc_ckn_no" text="单号 保存后由后端生成" font="13" textcolor="#FF8A9099" maxheight="22" autocalcwidth="true" />
+				</HorizontalLayout>
+
+				<!-- 主体 .pbody(#F5F7FA / padding 14 24 18 / 弹性 + 自带滚动条)。
+				     右 inset 归 0 ⇒ 滚动条贴页右缘;右侧 24px 留白改由每个子项自己 padding=&quot;0,0,24,0&quot; 承担。
+				     高度不写死(弹性)⇒ 页头/底栏固定、主体吃满中间;内容超高时自己滚,不再要 kc_scroll。 -->
+				<VerticalLayout name="kc_ckn_body" vscrollbar="true" bkcolor="#FFF5F7FA" inset="24,14,0,18" childpadding="0">
+
+					<!-- .card:白底 1px #E8EAED + r10;两个字段**等宽**(.formgrid.g2 = 1fr 1fr,gap 12)
+					     —— 宽度都不写,HorizontalLayout 里两个无固定宽的子项自动均分剩余宽度。 -->
+					<VerticalLayout height="98" padding="0,0,24,0" bkimage="file='bb_card10.png' corner='10,10,10,10'" inset="20,14,20,14" childpadding="0">
+						<HorizontalLayout height="69" childpadding="12" childvalign="vcenter">
+							<VerticalLayout childpadding="7">
+								<HorizontalLayout height="18" childpadding="5" childvalign="vcenter">
+									<Label text="*" font="13" textcolor="#FFE14B4A" maxheight="18" autocalcwidth="true" />
+									<Label text="出库类型" font="13" textcolor="#FF5F6368" maxheight="18" autocalcwidth="true" />
+								</HorizontalLayout>
+								<Combo name="kc_ckn_combo_type" height="44" maxheight="44" normalimage="file='gd_combo44_n.png' corner='8,8,22,8'" hotimage="file='gd_combo44_h.png' corner='8,8,22,8'" pushedimage="file='gd_combo44_p.png' corner='8,8,22,8'" textpadding="12,0,30,0" />
+							</VerticalLayout>
+							<VerticalLayout childpadding="7">
+								<Label text="备注" font="13" textcolor="#FF5F6368" height="18" />
+								<Button name="kc_ckn_note" text="晚市备料" font="13" textcolor="#FFA8ADB3" align="left" valign="vcenter" textpadding="12,0,12,0" height="44" maxheight="44" normalimage="file='input_r8_n.png' corner='8,8,8,8'" hotimage="file='input_r8_h.png' corner='8,8,8,8'" pushedimage="file='input_r8_n.png' corner='8,8,8,8'" />
+							</VerticalLayout>
+						</HorizontalLayout>
+					</VerticalLayout>
+
+					<Control height="12" padding="0,0,24,0" />
+
+					<!-- .addbar:白底 1px + r10,padding 10 / 14;提示左、按钮右 -->
+					<HorizontalLayout height="70" padding="0,0,24,0" bkimage="file='bb_card10.png' corner='10,10,10,10'" inset="14,10,14,10" childpadding="12" childvalign="vcenter">
+						<Label name="kc_ckn_tip" text="已添加 0 个商品 · 点「添加商品」勾选更多,或直接扫条码追加;点数量单元格调出数字键盘" font="13" textcolor="#FF5F6368" maxheight="20" autocalcwidth="true" />
+						<Control />
+						<Button name="kc_ckn_add" text="添加商品" font="114" textcolor="#FFFFFFFF" hottextcolor="#FFFFFFFF" pushedtextcolor="#FFFFFFFF" width="102" maxheight="48" normalimage="file='btn_pill48_org_n.png' corner='24,24,24,24'" hotimage="file='btn_pill48_org_h.png' corner='24,24,24,24'" pushedimage="file='btn_pill48_org_p.png' corner='24,24,24,24'" />
+					</HorizontalLayout>
+
+					<Control height="12" padding="0,0,24,0" />
+
+					<!-- .table:kc_tblcard.png 一张图烤进「1px 外框 + 43px 表头灰带 + 表头下 1px 分隔线」,
+					     表头灰带因此**齐卡片边框**(不是内缩)。List 用 inset=&quot;1,1,1,10&quot; 让开这三段与
+					     底部 r10 圆角带;表头不设底色,让烤进去的灰带透出来。ListHeader 必须保持可见
+					     (CListUI::SetPos 只在 !IsVisible() 时才用外框 rc 重排一遍)。
+					     高度由 C++ SyncTableHeight 写死 = 表头 44 + n*56 + List 上下 inset 11。 -->
+					<VerticalLayout name="kc_ckn_tblcard" height="223" padding="0,0,24,0" bkimage="file='kc_tblcard.png' corner='10,45,10,10'" childpadding="0">
+						<List name="kc_ckn_list" height="223" vscrollbar="false" inset="1,1,1,10" bkcolor="#00000000" itemhotbkcolor="#FFF7FAF8" itemselectedbkcolor="0">
+							<ListHeader height="44" bkcolor="#00000000" bordercolor="#00000000" bordersize="0" />
+							<ListHeaderItem text="商品名称" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="分类" width="137" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="单位" width="100" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="当前库存" width="162" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="出库数量" width="174" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="备注" width="261" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="操作" width="187" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+						</List>
+					</VerticalLayout>
+
+					<Control height="10" padding="0,0,24,0" />
+
+					<!-- .totbar:高 48 / #E8EAED / r8 / 左右 16;左组靠左,金额组靠**右**
+					     (靠一个无 width 的 &lt;Control /&gt; 当弹性 spacer 顶开;原实现漏了这个
+					     spacer,又塞了两个空占位 Label,导致金额紧贴「入库总数」)。 -->
+					<HorizontalLayout height="48" padding="0,0,24,0" bkimage="file='kc_tot_bg.png' corner='8,8,8,8'" inset="16,0,16,0" childpadding="0" childvalign="vcenter">
+						<Label text="合计商品" font="13" textcolor="#FF5F6368" maxheight="22" autocalcwidth="true" />
+						<Control width="5" />
+						<Label name="kc_ckn_tot_goods" text="0" font="113" textcolor="#FF1F2329" maxheight="22" autocalcwidth="true" />
+						<Control width="26" />
+						<Label text="出库总数" font="13" textcolor="#FF5F6368" maxheight="22" autocalcwidth="true" />
+						<Control width="5" />
+						<Label name="kc_ckn_tot_qty" text="0" font="113" textcolor="#FF1F2329" maxheight="22" autocalcwidth="true" />
+						<Control width="26" />
+						<Label text="库存不足" font="13" textcolor="#FF5F6368" maxheight="22" autocalcwidth="true" />
+						<Control width="5" />
+						<Label name="kc_ckn_tot_lack" text="0 项" font="112" textcolor="#FFE14B4A" maxheight="26" bkimage="file='kc_tag_red.png' corner='12,12,12,12'" textpadding="12,0,12,0" autocalcwidth="true" valign="vcenter" />
+					</HorizontalLayout>
+
+				</VerticalLayout>
+			</VerticalLayout>
+
+			<!-- ==================== 子视图 C:新建盘点单(设计稿 v4 p3) ==================== -->
+			<!-- 独立整页:挂 kc_page(**不再**是 kc_scroll 的子项)。设计稿 .pbar/.pbody/.pfoot 三段都通栏,
+			     留在滚动容器里会被 inset + 子项 padding 夹住 ⇒ 只能做成圆角卡片。三页与 kc_scroll 互斥显隐,
+			     CVerticalLayoutUI::SetPos 会 continue 跳过不可见子项 ⇒ 同一时刻只有一个弹性子项参与高度分配。
+			     本页的底栏 kc_new_foot_pd 与键盘面板 kc_keypad 都放在页面级(声明在 3 个视图之后)。 -->
+			<VerticalLayout name="kc_view_pd_new" visible="false" childpadding="0">
+
+				<!-- 页头 .pbar(高 64 / 白底 / 下 1px #E8EAED / 左右 24 / 子项间距 14) -->
+				<HorizontalLayout name="kc_pdn_bar" height="64" bkcolor="#FFFFFFFF" bordersize="0,0,0,1" bordercolor="#FFE8EAED" inset="24,0,24,0" childpadding="14" childvalign="vcenter">
+					<Button name="kc_pdn_back" text="← 返回" font="14" textcolor="#FF5F6368" hottextcolor="#FF2E9B5C" pushedtextcolor="#FF2E9B5C" width="78" maxheight="48" normalimage="file='gd_pill48_ghost_n.png' corner='24,24,24,24'" hotimage="file='gd_pill48_ghost_h.png' corner='24,24,24,24'" pushedimage="file='gd_pill48_ghost_p.png' corner='24,24,24,24'" />
+					<Label text="新建盘点单" font="118" textcolor="#FF1F2329" maxheight="26" autocalcwidth="true" />
+					<Label text="完成后自动生成盘盈盘亏并校正账面库存" font="12" textcolor="#FF8A9099" maxheight="20" autocalcwidth="true" />
+					<Control />
+					<Label name="kc_pdn_no" text="单号 保存后由后端生成" font="13" textcolor="#FF8A9099" maxheight="22" autocalcwidth="true" />
+				</HorizontalLayout>
+
+				<!-- 主体 .pbody(#F5F7FA / padding 14 24 18 / 弹性 + 自带滚动条)。
+				     右 inset 归 0 ⇒ 滚动条贴页右缘;右侧 24px 留白改由每个子项自己 padding=&quot;0,0,24,0&quot; 承担。
+				     高度不写死(弹性)⇒ 页头/底栏固定、主体吃满中间;内容超高时自己滚,不再要 kc_scroll。 -->
+				<VerticalLayout name="kc_pdn_body" vscrollbar="true" bkcolor="#FFF5F7FA" inset="24,14,0,18" childpadding="0">
+
+					<!-- .card:白底 1px #E8EAED + r10;两个字段**等宽**(.formgrid.g2 = 1fr 1fr,gap 12)
+					     —— 宽度都不写,HorizontalLayout 里两个无固定宽的子项自动均分剩余宽度。 -->
+					<VerticalLayout height="98" padding="0,0,24,0" bkimage="file='bb_card10.png' corner='10,10,10,10'" inset="20,14,20,14" childpadding="0">
+						<HorizontalLayout height="69" childpadding="12" childvalign="vcenter">
+							<VerticalLayout childpadding="7">
+								<HorizontalLayout height="18" childpadding="5" childvalign="vcenter">
+									<Label text="*" font="13" textcolor="#FFE14B4A" maxheight="18" autocalcwidth="true" />
+									<Label text="盘点范围" font="13" textcolor="#FF5F6368" maxheight="18" autocalcwidth="true" />
+								</HorizontalLayout>
+								<Combo name="kc_pdn_combo_type" height="44" maxheight="44" normalimage="file='gd_combo44_n.png' corner='8,8,22,8'" hotimage="file='gd_combo44_h.png' corner='8,8,22,8'" pushedimage="file='gd_combo44_p.png' corner='8,8,22,8'" textpadding="12,0,30,0" />
+							</VerticalLayout>
+							<VerticalLayout childpadding="7">
+								<Label text="备注" font="13" textcolor="#FF5F6368" height="18" />
+								<Button name="kc_pdn_note" text="月末盘点" font="13" textcolor="#FFA8ADB3" align="left" valign="vcenter" textpadding="12,0,12,0" height="44" maxheight="44" normalimage="file='input_r8_n.png' corner='8,8,8,8'" hotimage="file='input_r8_h.png' corner='8,8,8,8'" pushedimage="file='input_r8_n.png' corner='8,8,8,8'" />
+							</VerticalLayout>
+						</HorizontalLayout>
+					</VerticalLayout>
+
+					<Control height="12" padding="0,0,24,0" />
+
+					<!-- .addbar:白底 1px + r10,padding 10 / 14;提示左、按钮右 -->
+					<HorizontalLayout height="70" padding="0,0,24,0" bkimage="file='bb_card10.png' corner='10,10,10,10'" inset="14,10,14,10" childpadding="12" childvalign="vcenter">
+						<Label name="kc_pdn_tip" text="盘点范围:全部商品(共 0 项,已录入 0 项)· 点实盘数量单元格调出数字键盘" font="13" textcolor="#FF5F6368" maxheight="20" autocalcwidth="true" />
+						<Control />
+						<Button name="kc_pdn_fill" text="按账面库存填充" font="114" textcolor="#FF5F6368" hottextcolor="#FF2E9B5C" pushedtextcolor="#FF2E9B5C" width="158" maxheight="48" normalimage="file='gd_pill48_ghost_n.png' corner='24,24,24,24'" hotimage="file='gd_pill48_ghost_h.png' corner='24,24,24,24'" pushedimage="file='gd_pill48_ghost_p.png' corner='24,24,24,24'" />
+					</HorizontalLayout>
+
+					<Control height="12" padding="0,0,24,0" />
+
+					<!-- .table:kc_tblcard.png 一张图烤进「1px 外框 + 43px 表头灰带 + 表头下 1px 分隔线」,
+					     表头灰带因此**齐卡片边框**(不是内缩)。List 用 inset=&quot;1,1,1,10&quot; 让开这三段与
+					     底部 r10 圆角带;表头不设底色,让烤进去的灰带透出来。ListHeader 必须保持可见
+					     (CListUI::SetPos 只在 !IsVisible() 时才用外框 rc 重排一遍)。
+					     高度由 C++ SyncTableHeight 写死 = 表头 44 + n*56 + List 上下 inset 11。 -->
+					<VerticalLayout name="kc_pdn_tblcard" height="223" padding="0,0,24,0" bkimage="file='kc_tblcard.png' corner='10,45,10,10'" childpadding="0">
+						<List name="kc_pdn_list" height="223" vscrollbar="false" inset="1,1,1,10" bkcolor="#00000000" itemhotbkcolor="#FFF7FAF8" itemselectedbkcolor="0">
+							<ListHeader height="44" bkcolor="#00000000" bordercolor="#00000000" bordersize="0" />
+							<ListHeaderItem text="商品名称" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="分类" width="137" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="单位" width="100" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="账面库存" width="149" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="实盘数量" width="174" align="right" font="113" textcolor="#FF5F6368" textpadding="0,0,14,0" />
+							<ListHeaderItem text="差异" width="124" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="备注" width="187" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+							<ListHeaderItem text="操作" width="162" align="left" font="113" textcolor="#FF5F6368" textpadding="14,0,0,0" />
+						</List>
+					</VerticalLayout>
+
+					<Control height="10" padding="0,0,24,0" />
+
+					<!-- .totbar:高 48 / #E8EAED / r8 / 左右 16;左组靠左,金额组靠**右**
+					     (靠一个无 width 的 &lt;Control /&gt; 当弹性 spacer 顶开;原实现漏了这个
+					     spacer,又塞了两个空占位 Label,导致金额紧贴「入库总数」)。 -->
+					<HorizontalLayout height="48" padding="0,0,24,0" bkimage="file='kc_tot_bg.png' corner='8,8,8,8'" inset="16,0,16,0" childpadding="0" childvalign="vcenter">
+						<Label text="已录入" font="13" textcolor="#FF5F6368" maxheight="22" autocalcwidth="true" />
+						<Control width="5" />
+						<Label name="kc_pdn_tot_in" text="0" font="113" textcolor="#FF1F2329" maxheight="22" autocalcwidth="true" />
+						<Control width="26" />
+						<Label text="盘盈" font="13" textcolor="#FF5F6368" maxheight="22" autocalcwidth="true" />
+						<Control width="5" />
+						<Label name="kc_pdn_tot_gain" text="0 项" font="112" textcolor="#FF2E9B5C" maxheight="26" bkimage="file='kc_tag_grn.png' corner='12,12,12,12'" textpadding="12,0,12,0" autocalcwidth="true" valign="vcenter" />
+						<Control width="26" />
+						<Label text="盘亏" font="13" textcolor="#FF5F6368" maxheight="22" autocalcwidth="true" />
+						<Control width="5" />
+						<Label name="kc_pdn_tot_loss" text="0 项" font="112" textcolor="#FFE14B4A" maxheight="26" bkimage="file='kc_tag_red.png' corner='12,12,12,12'" textpadding="12,0,12,0" autocalcwidth="true" valign="vcenter" />
+						<Control />
+						<Label name="kc_pdn_tot_amt_lab" text="盈亏金额" font="13" textcolor="#FF5F6368" maxheight="22" autocalcwidth="true" />
+						<Control width="34" />
+						<Label name="kc_pdn_tot_amt" text="¥0.00" font="119" textcolor="#FF2E9B5C" maxheight="26" autocalcwidth="true" />
+					</HorizontalLayout>
+
+				</VerticalLayout>
+			</VerticalLayout>
+
+			<!-- ==================== 页面级数字键盘 / 文本输入面板(p6) ==================== -->
+			<!-- 设计稿 p6:点明细行的数量 / 单价 / 备注单元格后,底部停靠一块输入面板(非弹层)。
+			     通栏白条(.kbar:高 236 / 白底 / 上 1px #E8EAED / 左右 24),与三个底栏
+			     一起挂在页面根容器下、且声明在三个底栏**之前** ⇒ 弹出时正好夹在「主体」与
+			     「底栏」中间(设计稿 p6 的顺序)。主体靠自己的 vscrollbar 接管滚动。
+			       kc_kp_pad  数字键盘(数量 / 单价):4 列 x 4 行,确认 = 提交并收起
+			       kc_kp_txt  文本输入(备注):内嵌一个原生 Edit;它挂在页面级、不在任何滚动容器里,
+			                  因此不会出现「原生编辑框不随列表滚动」的老问题。
+			     键盘底图全部复用现网资产:数字 key_normal/hover/pushed,删除 dc_pill_red,
+			     确认 gd_btn_green_*,清除与关闭用白底描边的 key_hover。 -->
+			<VerticalLayout name="kc_keypad" visible="false" height="236" bkcolor="#FFFFFFFF" bordersize="0,1,0,0" bordercolor="#FFE8EAED" inset="24,0,24,0" childpadding="0">
+
+				<HorizontalLayout name="kc_kp_pad" childpadding="0" childvalign="vcenter">
+					<VerticalLayout width="300" childpadding="0">
+						<Control />
+						<Label name="kc_kp_tip" text="正在编辑 · 数量单价用数字键盘输入" font="13" textcolor="#FF5F6368" height="18" />
+						<Control height="8" />
+						<Label name="kc_kp_field" text="--" font="115" textcolor="#FF1F2329" height="22" />
+						<Control height="4" />
+						<HorizontalLayout height="46" childpadding="0" childvalign="bottom">
+							<Label name="kc_kp_value" text="0" font="136" textcolor="#FF60B177" maxheight="46" autocalcwidth="true" />
+							<Label name="kc_kp_unit" text="" font="16" textcolor="#FF8A9099" maxheight="22" autocalcwidth="true" />
+							<Control />
+						</HorizontalLayout>
+						<Control />
+					</VerticalLayout>
+					<Control width="28" />
+					<HorizontalLayout name="kc_kp_grid" childpadding="8">
+						<VerticalLayout childpadding="8" childvalign="vcenter">
+							<Button name="kc_kp_k1" text="1" font="122" textcolor="#FF1F2329" hottextcolor="#FF1F2329" pushedtextcolor="#FF1F2329" height="48" maxheight="48" normalimage="file='kc_key_n.png' corner='9,9,9,9'" hotimage="file='kc_key_h.png' corner='9,9,9,9'" pushedimage="file='kc_key_p.png' corner='9,9,9,9'" />
+							<Button name="kc_kp_k4" text="4" font="122" textcolor="#FF1F2329" hottextcolor="#FF1F2329" pushedtextcolor="#FF1F2329" height="48" maxheight="48" normalimage="file='kc_key_n.png' corner='9,9,9,9'" hotimage="file='kc_key_h.png' corner='9,9,9,9'" pushedimage="file='kc_key_p.png' corner='9,9,9,9'" />
+							<Button name="kc_kp_k7" text="7" font="122" textcolor="#FF1F2329" hottextcolor="#FF1F2329" pushedtextcolor="#FF1F2329" height="48" maxheight="48" normalimage="file='kc_key_n.png' corner='9,9,9,9'" hotimage="file='kc_key_h.png' corner='9,9,9,9'" pushedimage="file='kc_key_p.png' corner='9,9,9,9'" />
+							<Button name="kc_kp_k0" text="0" font="122" textcolor="#FF1F2329" hottextcolor="#FF1F2329" pushedtextcolor="#FF1F2329" height="48" maxheight="48" normalimage="file='kc_key_n.png' corner='9,9,9,9'" hotimage="file='kc_key_h.png' corner='9,9,9,9'" pushedimage="file='kc_key_p.png' corner='9,9,9,9'" />
+						</VerticalLayout>
+						<VerticalLayout childpadding="8" childvalign="vcenter">
+							<Button name="kc_kp_k2" text="2" font="122" textcolor="#FF1F2329" hottextcolor="#FF1F2329" pushedtextcolor="#FF1F2329" height="48" maxheight="48" normalimage="file='kc_key_n.png' corner='9,9,9,9'" hotimage="file='kc_key_h.png' corner='9,9,9,9'" pushedimage="file='kc_key_p.png' corner='9,9,9,9'" />
+							<Button name="kc_kp_k5" text="5" font="122" textcolor="#FF1F2329" hottextcolor="#FF1F2329" pushedtextcolor="#FF1F2329" height="48" maxheight="48" normalimage="file='kc_key_n.png' corner='9,9,9,9'" hotimage="file='kc_key_h.png' corner='9,9,9,9'" pushedimage="file='kc_key_p.png' corner='9,9,9,9'" />
+							<Button name="kc_kp_k8" text="8" font="122" textcolor="#FF1F2329" hottextcolor="#FF1F2329" pushedtextcolor="#FF1F2329" height="48" maxheight="48" normalimage="file='kc_key_n.png' corner='9,9,9,9'" hotimage="file='kc_key_h.png' corner='9,9,9,9'" pushedimage="file='kc_key_p.png' corner='9,9,9,9'" />
+							<Button name="kc_kp_k00" text="00" font="122" textcolor="#FF1F2329" hottextcolor="#FF1F2329" pushedtextcolor="#FF1F2329" height="48" maxheight="48" normalimage="file='kc_key_n.png' corner='9,9,9,9'" hotimage="file='kc_key_h.png' corner='9,9,9,9'" pushedimage="file='kc_key_p.png' corner='9,9,9,9'" />
+						</VerticalLayout>
+						<VerticalLayout childpadding="8" childvalign="vcenter">
+							<Button name="kc_kp_k3" text="3" font="122" textcolor="#FF1F2329" hottextcolor="#FF1F2329" pushedtextcolor="#FF1F2329" height="48" maxheight="48" normalimage="file='kc_key_n.png' corner='9,9,9,9'" hotimage="file='kc_key_h.png' corner='9,9,9,9'" pushedimage="file='kc_key_p.png' corner='9,9,9,9'" />
+							<Button name="kc_kp_k6" text="6" font="122" textcolor="#FF1F2329" hottextcolor="#FF1F2329" pushedtextcolor="#FF1F2329" height="48" maxheight="48" normalimage="file='kc_key_n.png' corner='9,9,9,9'" hotimage="file='kc_key_h.png' corner='9,9,9,9'" pushedimage="file='kc_key_p.png' corner='9,9,9,9'" />
+							<Button name="kc_kp_k9" text="9" font="122" textcolor="#FF1F2329" hottextcolor="#FF1F2329" pushedtextcolor="#FF1F2329" height="48" maxheight="48" normalimage="file='kc_key_n.png' corner='9,9,9,9'" hotimage="file='kc_key_h.png' corner='9,9,9,9'" pushedimage="file='kc_key_p.png' corner='9,9,9,9'" />
+							<Button name="kc_kp_kdot" text="." font="122" textcolor="#FF1F2329" hottextcolor="#FF1F2329" pushedtextcolor="#FF1F2329" height="48" maxheight="48" normalimage="file='kc_key_n.png' corner='9,9,9,9'" hotimage="file='kc_key_h.png' corner='9,9,9,9'" pushedimage="file='kc_key_p.png' corner='9,9,9,9'" />
+						</VerticalLayout>
+						<VerticalLayout childpadding="8" childvalign="vcenter">
+							<Button name="kc_kp_del" text="删除" font="115" textcolor="#FFE14B4A" hottextcolor="#FFE14B4A" pushedtextcolor="#FFE14B4A" height="48" maxheight="48" normalimage="file='kc_keydel_n.png' corner='9,9,9,9'" hotimage="file='kc_keydel_h.png' corner='9,9,9,9'" pushedimage="file='kc_keydel_p.png' corner='9,9,9,9'" />
+							<Button name="kc_kp_clr" text="清除" font="15" textcolor="#FF5F6368" hottextcolor="#FF5F6368" pushedtextcolor="#FF5F6368" height="48" maxheight="48" normalimage="file='kc_keyfn_n.png' corner='9,9,9,9'" hotimage="file='kc_keyfn_h.png' corner='9,9,9,9'" pushedimage="file='kc_keyfn_p.png' corner='9,9,9,9'" />
+							<Button name="kc_kp_ok" text="确认" font="116" textcolor="#FFFFFFFF" hottextcolor="#FFFFFFFF" pushedtextcolor="#FFFFFFFF" height="104" maxheight="104" normalimage="file='kc_keyok_n.png' corner='9,9,9,9'" hotimage="file='kc_keyok_h.png' corner='9,9,9,9'" pushedimage="file='kc_keyok_p.png' corner='9,9,9,9'" />
+						</VerticalLayout>
+					</HorizontalLayout>
+				</HorizontalLayout>
+
+				<HorizontalLayout name="kc_kp_txt" visible="false" childpadding="0" childvalign="vcenter">
+					<VerticalLayout width="300" childpadding="0">
+						<Control />
+						<Label text="正在编辑 · 备注(文字)" font="13" textcolor="#FF5F6368" height="18" />
+						<Control height="8" />
+						<Label name="kc_kp_txtfield" text="--" font="15" textcolor="#FF1F2329" height="22" />
+						<Control />
+					</VerticalLayout>
+					<Control width="28" />
+					<VerticalLayout childpadding="0" childvalign="vcenter">
+						<HorizontalLayout height="56" bkimage="file='input_normal.png' corner='8,8,8,8'" inset="16,0,16,0" childpadding="0" childvalign="vcenter">
+							<Edit name="kc_kp_edit" tooltip="输入备注内容" font="16" textcolor="#FF1F2329" maxheight="32" bkcolor="#00000000" nativebkcolor="#FFFFFFFF" />
+						</HorizontalLayout>
+						<Control height="14" />
+						<HorizontalLayout height="48" childpadding="12" childvalign="vcenter">
+							<Label text="回车或点右侧按钮提交备注" font="12" textcolor="#FF8A9099" maxheight="18" autocalcwidth="true" />
+							<Control />
+							<Button name="kc_kp_txtcancel" text="取消" font="14" textcolor="#FF5F6368" width="112" height="48" maxheight="48" normalimage="file='gd_btn_ghost_n.png' corner='8,8,8,8'" hotimage="file='gd_btn_ghost_h.png' corner='8,8,8,8'" pushedimage="file='gd_btn_ghost_p.png' corner='8,8,8,8'" />
+							<Control width="12" />
+							<Button name="kc_kp_txtok" text="确定" font="14" textcolor="#FFFFFFFF" width="136" height="48" maxheight="48" normalimage="file='btn_green_zhengchang.png' corner='8,8,8,8'" hotimage="file='btn_green_xuanfu.png' corner='8,8,8,8'" pushedimage="file='btn_green_dianji.png' corner='8,8,8,8'" />
+						</HorizontalLayout>
+					</VerticalLayout>
+				</HorizontalLayout>
+
+			</VerticalLayout>
+
+			<!-- ==================== 新建入库单 底栏(页面级 / 声明在 kc_keypad 之后) ==================== -->
+			<!-- 底栏 .pfoot(页面级、在 kc_keypad 之后声明 ⇒ 键盘弹出时正好落在
+			     主体与底栏之间,与设计稿 p6 的 .kbar 位置一致):高 72 / 白底 / 上 1px / 左右 24。 -->
+			<HorizontalLayout name="kc_new_foot_rk" visible="false" height="72" bkcolor="#FFFFFFFF" bordersize="0,1,0,0" bordercolor="#FFE8EAED" inset="24,0,24,0" childpadding="12" childvalign="vcenter">
+				<Label name="kc_rkn_foot_tip" text="提示:单号 / 入库日期由后端生成,经手人自动关联当前账号;数量为必填,单价可在商品档案中统一维护" font="12" textcolor="#FF8A9099" maxheight="20" autocalcwidth="true" />
+				<Control />
+				<Button name="kc_rkn_cancel" text="取消" font="114" textcolor="#FF5F6368" hottextcolor="#FF2E9B5C" pushedtextcolor="#FF2E9B5C" width="74" maxheight="48" normalimage="file='gd_pill48_ghost_n.png' corner='24,24,24,24'" hotimage="file='gd_pill48_ghost_h.png' corner='24,24,24,24'" pushedimage="file='gd_pill48_ghost_p.png' corner='24,24,24,24'" />
+				<Button name="kc_rkn_save" text="保存入库" font="114" textcolor="#FFFFFFFF" hottextcolor="#FFFFFFFF" pushedtextcolor="#FFFFFFFF" width="102" maxheight="48" normalimage="file='btn_pill48_grn_n.png' corner='24,24,24,24'" hotimage="file='btn_pill48_grn_h.png' corner='24,24,24,24'" pushedimage="file='btn_pill48_grn_p.png' corner='24,24,24,24'" />
+			</HorizontalLayout>
+
+			<!-- ==================== 新建出库单 底栏(页面级 / 声明在 kc_keypad 之后) ==================== -->
+			<!-- 底栏 .pfoot(页面级、在 kc_keypad 之后声明 ⇒ 键盘弹出时正好落在
+			     主体与底栏之间,与设计稿 p6 的 .kbar 位置一致):高 72 / 白底 / 上 1px / 左右 24。 -->
+			<HorizontalLayout name="kc_new_foot_ck" visible="false" height="72" bkcolor="#FFFFFFFF" bordersize="0,1,0,0" bordercolor="#FFE8EAED" inset="24,0,24,0" childpadding="12" childvalign="vcenter">
+				<Label name="kc_ckn_foot_tip" text="提示:单号 / 出库日期由后端生成,经手人自动关联当前账号;出库数量超过当前库存时标红,保存前请确认" font="12" textcolor="#FF8A9099" maxheight="20" autocalcwidth="true" />
+				<Control />
+				<Button name="kc_ckn_cancel" text="取消" font="114" textcolor="#FF5F6368" hottextcolor="#FF2E9B5C" pushedtextcolor="#FF2E9B5C" width="74" maxheight="48" normalimage="file='gd_pill48_ghost_n.png' corner='24,24,24,24'" hotimage="file='gd_pill48_ghost_h.png' corner='24,24,24,24'" pushedimage="file='gd_pill48_ghost_p.png' corner='24,24,24,24'" />
+				<Button name="kc_ckn_save" text="保存出库" font="114" textcolor="#FFFFFFFF" hottextcolor="#FFFFFFFF" pushedtextcolor="#FFFFFFFF" width="102" maxheight="48" normalimage="file='btn_pill48_org_n.png' corner='24,24,24,24'" hotimage="file='btn_pill48_org_h.png' corner='24,24,24,24'" pushedimage="file='btn_pill48_org_p.png' corner='24,24,24,24'" />
+			</HorizontalLayout>
+
+			<!-- ==================== 新建盘点单 底栏(页面级 / 声明在 kc_keypad 之后) ==================== -->
+			<!-- 底栏 .pfoot(页面级、在 kc_keypad 之后声明 ⇒ 键盘弹出时正好落在
+			     主体与底栏之间,与设计稿 p6 的 .kbar 位置一致):高 72 / 白底 / 上 1px / 左右 24。 -->
+			<HorizontalLayout name="kc_new_foot_pd" visible="false" height="72" bkcolor="#FFFFFFFF" bordersize="0,1,0,0" bordercolor="#FFE8EAED" inset="24,0,24,0" childpadding="12" childvalign="vcenter">
+				<Label name="kc_pdn_foot_tip" text="提示:单号 / 盘点日期由后端生成,盘点人自动关联当前账号;差异由「实盘数量 − 账面库存」自动计算" font="12" textcolor="#FF8A9099" maxheight="20" autocalcwidth="true" />
+				<Control />
+				<Button name="kc_pdn_cancel" text="取消" font="114" textcolor="#FF5F6368" hottextcolor="#FF2E9B5C" pushedtextcolor="#FF2E9B5C" width="74" maxheight="48" normalimage="file='gd_pill48_ghost_n.png' corner='24,24,24,24'" hotimage="file='gd_pill48_ghost_h.png' corner='24,24,24,24'" pushedimage="file='gd_pill48_ghost_p.png' corner='24,24,24,24'" />
+				<Button name="kc_pdn_save" text="完成盘点" font="114" textcolor="#FFFFFFFF" hottextcolor="#FFFFFFFF" pushedtextcolor="#FFFFFFFF" width="102" maxheight="48" normalimage="file='btn_pill48_grn_n.png' corner='24,24,24,24'" hotimage="file='btn_pill48_grn_h.png' corner='24,24,24,24'" pushedimage="file='btn_pill48_grn_p.png' corner='24,24,24,24'" />
+			</HorizontalLayout>
+
+			<!-- ==================== 添加商品弹层(p5 / p7) ==================== -->
+			<!-- 遮罩 + 居中层用「上下左右各夹一个弹性 <Control />」做出来:
+			     VerticalLayout 里两个弹性项均分剩余空间 ⇒ 垂直居中;HorizontalLayout 同理 ⇒ 水平居中。
+			     整层怎么铺满整页:本层是根 VerticalLayout 里唯一带 float 的子项,
+			     用百分比浮动 float="0,0,1,1"(左上 0%,0% 右下 100%,100%)铺满父级 ——
+			     不走 pos 手算坐标(pos 只支持像素/负值靠右,表达不了「铺满」),
+			     也不新开模态窗口(本项目 ShowModal 走真模态 DialogBoxIndirectParam,
+			     会 DestroyWindow 再重建阴影窗,代价远大于收益)。
+			     注意:float 子项在 CVerticalLayoutUI 里被排除出「弹性项」统计
+			     (UIVerticalLayout.cpp 里对 IsFloat() 为真的子项直接 continue),
+			     所以它不会跟底下的 kc_view_* 抢剩余高度、能真正盖满整页。
+			     遮罩 #6B1F2329 走 DuiLib DrawColor 的 Gdiplus 分支,半透明有效。
+			     关闭入口:右上「关闭」+ 底部「取消」两个按钮。 -->
+			<VerticalLayout name="kc_pick_overlay" visible="false" bkcolor="#6B1F2329" childpadding="0" float="0,0,1,1">
+				<Control />
+				<HorizontalLayout height="560" childpadding="0">
+					<Control />
+					<VerticalLayout width="940" bkimage="file='bb_card10.png' corner='10,10,10,10'" childpadding="0">
+						<HorizontalLayout height="56" inset="20,0,20,0" childvalign="vcenter">
+							<Label text="添加商品" font="117" textcolor="#FF1F2329" maxheight="24" autocalcwidth="true" />
+							<Control width="12" />
+							<Label text="勾选后确定,追加到明细表" font="12" textcolor="#FF8A9099" maxheight="18" autocalcwidth="true" />
+							<Control />
+							<Button name="kc_pick_close" text="关闭" font="13" textcolor="#FF5F6368" width="72" maxheight="34" normalimage="file='gd_btn_ghost_n.png' corner='8,8,8,8'" hotimage="file='gd_btn_ghost_h.png' corner='8,8,8,8'" pushedimage="file='gd_btn_ghost_p.png' corner='8,8,8,8'" />
+						</HorizontalLayout>
+						<Control height="1" bkcolor="#FFE8EAED" />
+						<HorizontalLayout inset="18,14,18,14" childpadding="14">
+							<VerticalLayout name="kc_pick_cat" width="168" bkcolor="#FFF7F8FA" borderround="16,16" inset="8,8,8,8" childpadding="2">
+								<Button name="kc_pick_cat_0" text="全部商品" font="113" textcolor="#FF2E9B5C" hottextcolor="#FF2E9B5C" pushedtextcolor="#FF1B8A4C" height="44" maxheight="44" align="left" textpadding="14,0,10,0" normalimage="file='dc_pill_h.png' corner='11,11,11,11'" hotimage="file='dc_pill_h.png' corner='11,11,11,11'" pushedimage="file='dc_pill.png' corner='11,11,11,11'" />
+								<Button name="kc_pick_cat_1" text="主食" font="13" textcolor="#FF5F6368" hottextcolor="#FF2E9B5C" pushedtextcolor="#FF2E9B5C" height="44" maxheight="44" align="left" textpadding="14,0,10,0" normalimage="" hotimage="file='dc_pill_h.png' corner='11,11,11,11'" pushedimage="file='dc_pill.png' corner='11,11,11,11'" />
+								<Button name="kc_pick_cat_2" text="主料" font="13" textcolor="#FF5F6368" hottextcolor="#FF2E9B5C" pushedtextcolor="#FF2E9B5C" height="44" maxheight="44" align="left" textpadding="14,0,10,0" normalimage="" hotimage="file='dc_pill_h.png' corner='11,11,11,11'" pushedimage="file='dc_pill.png' corner='11,11,11,11'" />
+								<Button name="kc_pick_cat_3" text="调料" font="13" textcolor="#FF5F6368" hottextcolor="#FF2E9B5C" pushedtextcolor="#FF2E9B5C" height="44" maxheight="44" align="left" textpadding="14,0,10,0" normalimage="" hotimage="file='dc_pill_h.png' corner='11,11,11,11'" pushedimage="file='dc_pill.png' corner='11,11,11,11'" />
+								<Button name="kc_pick_cat_4" text="蔬菜" font="13" textcolor="#FF5F6368" hottextcolor="#FF2E9B5C" pushedtextcolor="#FF2E9B5C" height="44" maxheight="44" align="left" textpadding="14,0,10,0" normalimage="" hotimage="file='dc_pill_h.png' corner='11,11,11,11'" pushedimage="file='dc_pill.png' corner='11,11,11,11'" />
+								<Button name="kc_pick_cat_5" text="肉类" font="13" textcolor="#FF5F6368" hottextcolor="#FF2E9B5C" pushedtextcolor="#FF2E9B5C" height="44" maxheight="44" align="left" textpadding="14,0,10,0" normalimage="" hotimage="file='dc_pill_h.png' corner='11,11,11,11'" pushedimage="file='dc_pill.png' corner='11,11,11,11'" />
+								<Button name="kc_pick_cat_6" text="蛋类" font="13" textcolor="#FF5F6368" hottextcolor="#FF2E9B5C" pushedtextcolor="#FF2E9B5C" height="44" maxheight="44" align="left" textpadding="14,0,10,0" normalimage="" hotimage="file='dc_pill_h.png' corner='11,11,11,11'" pushedimage="file='dc_pill.png' corner='11,11,11,11'" />
+							</VerticalLayout>
+							<VerticalLayout childpadding="0">
+								<HorizontalLayout height="44" childpadding="0" childvalign="vcenter">
+									<HorizontalLayout width="460" bkimage="file='input_normal.png' corner='8,8,8,8'" inset="14,0,12,0" childpadding="8" childvalign="vcenter">
+										<Control bkimage="dc_ico_search16.png" width="16" maxheight="16" />
+										<Edit name="kc_pick_search" tooltip="搜索商品名称 / 拼音码 / 条码" font="13" textcolor="#FF1F2329" maxheight="24" bkcolor="#00000000" nativebkcolor="#FFFFFFFF" />
+									</HorizontalLayout>
+									<Control />
+									<Label name="kc_pick_selcnt" text="已选 0 项" font="113" textcolor="#FF2E9B5C" maxheight="20" autocalcwidth="true" />
+								</HorizontalLayout>
+								<Control height="10" />
+								<List name="kc_pick_list" vscrollbar="true" bkcolor="#FFFFFFFF" itemhotbkcolor="#FFF7FAF8" itemselectedbkcolor="#FFF7FAF8">
+									<ListHeader height="44" bkcolor="#FFF0F2F5" bordercolor="#FFE8EAED" bordersize="0,0,0,1" />
+									<ListHeaderItem text="商品" align="left" font="13" textcolor="#FF5F6368" textpadding="18,0,0,0" />
+									<ListHeaderItem text="分类 · 单位" width="200" align="left" font="13" textcolor="#FF5F6368" textpadding="10,0,0,0" />
+									<ListHeaderItem text="库存" width="140" align="right" font="13" textcolor="#FF5F6368" textpadding="0,0,22,0" />
+								</List>
+							</VerticalLayout>
+						</HorizontalLayout>
+						<Control height="1" bkcolor="#FFE8EAED" />
+						<HorizontalLayout height="72" inset="20,0,20,0" childvalign="vcenter">
+							<Label text="已存在明细中的商品会自动跳过" font="12" textcolor="#FF8A9099" maxheight="18" autocalcwidth="true" />
+							<Control />
+							<Button name="kc_pick_clear" text="清空" font="14" textcolor="#FF5F6368" width="96" maxheight="48" normalimage="file='gd_btn_ghost_n.png' corner='8,8,8,8'" hotimage="file='gd_btn_ghost_h.png' corner='8,8,8,8'" pushedimage="file='gd_btn_ghost_p.png' corner='8,8,8,8'" />
+							<Control width="12" />
+							<Button name="kc_pick_cancel" text="取消" font="14" textcolor="#FF5F6368" width="112" maxheight="48" normalimage="file='gd_btn_ghost_n.png' corner='8,8,8,8'" hotimage="file='gd_btn_ghost_h.png' corner='8,8,8,8'" pushedimage="file='gd_btn_ghost_p.png' corner='8,8,8,8'" />
+							<Control width="12" />
+							<Button name="kc_pick_ok" text="确定追加" font="14" textcolor="#FFFFFFFF" width="136" maxheight="48" normalimage="file='btn_green_zhengchang.png' corner='8,8,8,8'" hotimage="file='btn_green_xuanfu.png' corner='8,8,8,8'" pushedimage="file='btn_green_dianji.png' corner='8,8,8,8'" />
+						</HorizontalLayout>
+					</VerticalLayout>
+					<Control />
+				</HorizontalLayout>
+				<Control />
+			</VerticalLayout>
+		</VerticalLayout>
 	</KucunPage>
-</Window>
+</Window>

+ 7 - 0
bin/Win32/Debug/zhipuzi_pos_windows/skin/main.xml

@@ -110,5 +110,12 @@
 			</Container>
 		</HorizontalLayout>
 		
+		<!-- R44:单据详情弹框的全局压暗遮罩(设计稿 .mask = rgba(31,35,41,.45) ⇒ #731F2329)。
+		     float="0,0,1,1" 是百分比浮动 = 铺满父级(见 UIContainer.cpp 的 GetFloatPercent 分支),
+		     且 float 子项永远最后绘制 ⇒ 盖住左导航与 page 内容。
+		     mouse="true" 让它吃掉整窗鼠标事件,视觉与交互都等价于模态。
+		     显隐由 CMainWnd::ShowGlobalDim() 在开 / 关详情弹框前后切换。 -->
+		<Control name="kc_global_dim" float="0,0,1,1" bkcolor="#731F2329" mouse="true" visible="false" />
+
 	</VerticalLayout>        
 </Window>

BIN
dll/debug/DuiLib_d.dll


BIN
lib/debug/DuiLib_d.lib


+ 591 - 18
zhipuzi_pos_windows/page/CKucunPageUI.cpp

@@ -2,67 +2,640 @@
 #include "CKucunPageUI.h"
 
 #include "../control/ControlEx.h"
+#include "../wnd/CMainWnd.h"
+#include "../wnd/CKucunDetailWnd.h"
 
-#include "../tool/CSqlite3.h"
+// ============================================================================
+// 库存页宿主:主态 / 子视图态切换 + 页面级键盘与「添加商品」弹层
+//
+// 视图清单(都在 kucun_page.xml 里,靠名字找、靠 SetVisible 切):
+//   主态    kc_scroll(整页滚动)内:kc_tabrow + kc_view_chaxun / ruku / chuku / pandian
+//   子视图  kc_view_rk_new / kc_view_ck_new / kc_view_pd_new
+//           ——【R48】这三页从 kc_scroll 里**上提**到 kc_page 下了:
+//           设计稿 v4 的新建单页是通栏独立整页(.pbar 64 / .pbody 弹性 / .pfoot 72),
+//           留在滚动容器里会被 kc_scroll 的 inset 与子项 padding 夹成圆角卡片。
+//           三页与 kc_scroll 互斥显隐;CVerticalLayoutUI::SetPos 会 continue 跳过不可见子项
+//           (UIVerticalLayout.cpp:66/122),所以同时只有一个弹性子项参与高度分配。
+//   浮层    kc_keypad(三张子视图共用)、kc_pick_overlay(float="0,0,1,1" 铺满整页)
+//   底栏    kc_new_foot_rk / ck / pd ——【R48】页面级、声明在 kc_keypad **之后**,
+//           于是键盘面板弹出时正好夹在「主体」与「底栏」中间(设计稿 p6 的 .kbar 位置)
+// ============================================================================
 
-CKucunPageUI::CKucunPageUI()
+namespace
 {
+	// 弹层的 7 个分类页签:0 = 全部商品,1~6 与商品档案里的分类名一一对应
+	const wchar_t* const KC_PICK_CATS[7] =
+	{
+		L"", L"主食", L"主料", L"调料", L"蔬菜", L"肉类", L"蛋类"
+	};
+
+	const wchar_t* const KC_VIEW_MAIN[4] =
+	{
+		L"kc_view_chaxun", L"kc_view_ruku", L"kc_view_chuku", L"kc_view_pandian"
+	};
+	const wchar_t* const KC_TAB_NAME[4] =
+	{
+		L"kc_tab_chaxun", L"kc_tab_ruku", L"kc_tab_chuku", L"kc_tab_pandian"
+	};
+	const wchar_t* const KC_VIEW_SUB[3] =
+	{
+		L"kc_view_rk_new", L"kc_view_ck_new", L"kc_view_pd_new"
+	};
+	// 【R48】与 KC_VIEW_SUB 一一对应的页面级底栏
+	const wchar_t* const KC_SUB_FOOT[3] =
+	{
+		L"kc_new_foot_rk", L"kc_new_foot_ck", L"kc_new_foot_pd"
+	};
+
+	// 记录列表行里的「详情 / 打印」是行的孙控件,要顺着父链找回行元素才能读到单号
+	CListContainerElementUI* KcFindRow(CControlUI* p)
+	{
+		while (p != NULL)
+		{
+			CListContainerElementUI* e =
+				static_cast<CListContainerElementUI*>(p->GetInterface(DUI_CTR_LISTCONTAINERELEMENT));
+			if (e != NULL) return e;
+			p = p->GetParent();
+		}
+		return NULL;
+	}
+
+	std::wstring KcRowNo(CControlUI* p)
+	{
+		CListContainerElementUI* row = KcFindRow(p);
+		if (row == NULL) return L"";
+		CLabelUI* lab = static_cast<CLabelUI*>(row->FindSubControl(L"col_no"));
+		if (lab == NULL) return L"";
+		return std::wstring((LPCTSTR)lab->GetText());
+	}
+
+	// 弹层商品行:3 个直接子控件必须与 kc_pick_list 的 3 个表头列一一对应
+	CListContainerElementUI* KcBuildPickRow(CPaintManagerUI* pm)
+	{
+		CDialogBuilder builder;
+		CDialogBuilderCallbackEx cb;
+		CControlUI* p = builder.Create(L"kc_row_pick.xml", (UINT)0, &cb, pm);
+		return static_cast<CListContainerElementUI*>(p);
+	}
+
+	void KcPickRowText(CListContainerElementUI* row, LPCTSTR name, LPCTSTR text)
+	{
+		if (row == NULL) return;
+		CLabelUI* p = static_cast<CLabelUI*>(row->FindSubControl(name));
+		if (p != NULL) p->SetText(text);
+	}
+
+	// 小写化,用于拼音码 / 名称的模糊匹配。
+	// 只做 ASCII —— 拼音码本来就是 ASCII,商品名是中文、大小写无关,
+	// 不引 <cwctype> 免得再添一个头依赖。
+	std::wstring KcLower(const std::wstring& s)
+	{
+		std::wstring o = s;
+		for (size_t i = 0; i < o.size(); i++)
+		{
+			wchar_t c = o[i];
+			if (c >= L'A' && c <= L'Z') o[i] = (wchar_t)(c - L'A' + L'a');
+		}
+		return o;
+	}
 }
 
+CKucunPageUI::CKucunPageUI()
+	: m_pKpHost(NULL), m_pPickOverlay(NULL), m_pPickList(NULL),
+	  m_nPickCat(0), m_nTopTab(0), m_nSubView(-1), m_nPageWidth(0)
+{
+	for (int i = 0; i < 4; i++) m_pViews[i] = NULL;
+	for (int i = 0; i < 3; i++) m_pEdit[i] = NULL;
+
+	// 弹层候选项来自商品档案,勾选态(on)跨分类保留
+	const std::vector<KcGoods>& all = KcAllGoods();
+	for (size_t i = 0; i < all.size(); i++)
+	{
+		KcPickItem it;
+		it.name = all[i].name;
+		it.cat = all[i].cat;
+		it.unit = all[i].unit;
+		it.stock = all[i].stock;
+		it.on = false;
+		m_pick.push_back(it);
+	}
+}
 
 CKucunPageUI::~CKucunPageUI()
 {
+	for (int i = 0; i < 4; i++)
+	{
+		if (m_pViews[i]) { delete m_pViews[i]; m_pViews[i] = NULL; }
+	}
+	for (int i = 0; i < 3; i++)
+	{
+		if (m_pEdit[i]) { delete m_pEdit[i]; m_pEdit[i] = NULL; }
+	}
 }
 
 void CKucunPageUI::InitControl()
 {
+	CPaintManagerUI* pm = GetManager();
+
+	// ---- 4 个记录视图 ----
+	CContainerUI* h[4] = { NULL, NULL, NULL, NULL };
+	for (int i = 0; i < 4; i++)
+	{
+		h[i] = static_cast<CContainerUI*>(FindSubControl(KC_VIEW_MAIN[i]));
+	}
+
+	m_pViews[0] = new CKucunChaxunView(pm, h[0]);
+	m_pViews[1] = new CKucunRukuView(pm, h[1]);
+	m_pViews[2] = new CKucunChukuView(pm, h[2]);
+	m_pViews[3] = new CKucunPandianView(pm, h[3]);
+
+	for (int i = 0; i < 4; i++)
+	{
+		if (m_pViews[i]) m_pViews[i]->OnInitControl();
+	}
 
+	// ---- 3 个编辑子视图(共用页面级键盘面板 kc_keypad)----
+	m_pKpHost = static_cast<CContainerUI*>(FindSubControl(L"kc_keypad"));
+
+	CContainerUI* sh = NULL;
+	sh = static_cast<CContainerUI*>(FindSubControl(KC_VIEW_SUB[0]));
+	m_pEdit[0] = new CKucunRkNewView(pm, sh, m_pKpHost);
+	sh = static_cast<CContainerUI*>(FindSubControl(KC_VIEW_SUB[1]));
+	m_pEdit[1] = new CKucunCkNewView(pm, sh, m_pKpHost);
+	sh = static_cast<CContainerUI*>(FindSubControl(KC_VIEW_SUB[2]));
+	m_pEdit[2] = new CKucunPdNewView(pm, sh, m_pKpHost);
+
+	for (int i = 0; i < 3; i++)
+	{
+		if (m_pEdit[i]) m_pEdit[i]->OnInitControl();
+	}
+
+	// ---- 添加商品弹层 ----
+	m_pPickOverlay = static_cast<CContainerUI*>(FindSubControl(L"kc_pick_overlay"));
+	m_pPickList = static_cast<CListUI*>(FindSubControl(L"kc_pick_list"));
+
+	SetTopTab(0);
 }
 
-//初始化当前页面的展示,处理默认展示效果,在页面被加载的时候调用
 void CKucunPageUI::InitShow()
 {
-	
+	// 每次重新进入本页都回到一级 Tab 主态(子视图 / 浮层 / 键盘全部收起)
+	SetTopTab(m_nTopTab);
+
+	for (int i = 0; i < 4; i++)
+	{
+		if (m_pViews[i]) m_pViews[i]->InitShow();
+	}
 }
 
-//处理按钮点击类事件
-void CKucunPageUI::HandleClickMsg(TNotifyUI& msg)
+// ---------------------------------------------------------------- 视图显隐
+void CKucunPageUI::HideAllViews()
 {
-	CDuiString name = msg.pSender->GetName();
+	for (int i = 0; i < 4; i++)
+	{
+		CControlUI* p = FindSubControl(KC_VIEW_MAIN[i]);
+		if (p) p->SetVisible(false);
+	}
+	for (int i = 0; i < 3; i++)
+	{
+		CControlUI* p = FindSubControl(KC_VIEW_SUB[i]);
+		if (p) p->SetVisible(false);
+	}
+
+	CControlUI* pTabRow = FindSubControl(L"kc_tabrow");
+	if (pTabRow) pTabRow->SetVisible(false);
 
+	// 【R48】三个「新建单」页上提到 kc_page 之后,进子视图必须把整页滚动容器一起收起来:
+	// 它也是 kc_page 的弹性子项,不收就会跟子视图抢中间那段高度;顺带 4 个记录 Tab 也还在。
+	CControlUI* pScroll = FindSubControl(L"kc_scroll");
+	if (pScroll) pScroll->SetVisible(false);
+
+	// 三个页面级底栏一次全收,由 ShowSubView 只放当前那个
+	for (int i = 0; i < 3; i++)
+	{
+		CControlUI* pF = FindSubControl(KC_SUB_FOOT[i]);
+		if (pF) pF->SetVisible(false);
+	}
+
+	if (m_pKpHost) m_pKpHost->SetVisible(false);
+	if (m_pPickOverlay) m_pPickOverlay->SetVisible(false);
+
+	// 三个子视图各自清掉「正在编辑」状态(内部顺带把 kc_keypad 收走)
+	for (int i = 0; i < 3; i++)
+	{
+		if (m_pEdit[i]) m_pEdit[i]->CloseKeypad();
+	}
 }
 
-//处理option切换事件
-void CKucunPageUI::HandleSelectChangeMsg(TNotifyUI& msg)
+void CKucunPageUI::SetTopTab(int idx)
+{
+	HideAllViews();
+
+	m_nTopTab = idx;
+	m_nSubView = -1;
+
+	// 【R48】回到记录态要恢复整页滚动容器(三个新建单页已被 HideAllViews 收起)
+	CControlUI* pScroll = FindSubControl(L"kc_scroll");
+	if (pScroll) pScroll->SetVisible(true);
+
+	CControlUI* pTabRow = FindSubControl(L"kc_tabrow");
+	if (pTabRow) pTabRow->SetVisible(true);
+
+	for (int i = 0; i < 4; i++)
+	{
+		// 一级 Tab 三态(R45 对着设计稿 v2 重做):选中 = 白底描边卡 kc_tabcard.png 里的
+		// 主绿胶囊 kc_tabgrn_*,未选中 = 透明底 + 灰字,hover / pushed 走 kc_tabgray_*。
+		// 圆度来自源图自身(源图 radius 19),九宫格 corner 只定「取多大一块」。
+		CButtonUI* pTab = static_cast<CButtonUI*>(FindSubControl(KC_TAB_NAME[i]));
+		if (pTab)
+		{
+			bool act = (i == idx);
+			pTab->SetNormalImage(act ? L"file='kc_tabgrn_n.png' corner='19,19,19,19'" : L"");
+			pTab->SetHotImage(act ? L"file='kc_tabgrn_h.png' corner='19,19,19,19'" : L"file='kc_tabgray_h.png' corner='19,19,19,19'");
+			pTab->SetPushedImage(act ? L"file='kc_tabgrn_p.png' corner='19,19,19,19'" : L"file='kc_tabgray_p.png' corner='19,19,19,19'");
+			pTab->SetFont(act ? 114 : 14);
+			pTab->SetTextColor(act ? 0xFFFFFFFF : 0xFF5F6368);
+			pTab->SetHotTextColor(act ? 0xFFFFFFFF : 0xFF2E9B5C);
+			pTab->SetPushedTextColor(act ? 0xFFFFFFFF : 0xFF2E9B5C);
+		}
+		CControlUI* pView = FindSubControl(KC_VIEW_MAIN[i]);
+		if (pView) pView->SetVisible(i == idx);
+	}
+
+	// 记录视图里也有原生 Edit(搜索框),显隐后要手工同步一次
+	KcSyncNativeEditsIn(this);
+}
+
+void CKucunPageUI::ShowSubView(int idx)
+{
+	if (idx < 0 || idx > 2 || m_pEdit[idx] == NULL) return;
+
+	HideAllViews();
+
+	CControlUI* p = FindSubControl(KC_VIEW_SUB[idx]);
+	if (p == NULL) return;
+	p->SetVisible(true);
+
+	// 【R48】页面级底栏与视图一对一,这里只放当前这张
+	CControlUI* pFoot = FindSubControl(KC_SUB_FOOT[idx]);
+	if (pFoot) pFoot->SetVisible(true);
+
+	m_nSubView = idx;
+
+	m_pEdit[idx]->InitShow();     // 重置明细为种子数据并刷新合计
+
+	KcSyncNativeEditsIn(this);
+}
+
+CKucunEditViewBase* CKucunPageUI::CurEdit() const
+{
+	if (m_nSubView < 0 || m_nSubView > 2) return NULL;
+	return m_pEdit[m_nSubView];
+}
+
+// ---------------------------------------------------------------- 添加商品弹层
+void CKucunPageUI::ShowPick(bool bShow)
+{
+	if (m_pPickOverlay == NULL) return;
+
+	if (bShow)
+	{
+		// 弹层的搜索框 / 键盘都不能占着布局,先进来就收掉
+		CKucunEditViewBase* v = CurEdit();
+		if (v) v->CloseKeypad();
+
+		// 每次打开都从「全不选」起步(设计稿口径:勾选后确定,追加到明细表)
+		for (size_t i = 0; i < m_pick.size(); i++) m_pick[i].on = false;
+		m_strPickSearch.clear();
+
+		CEditUI* pSearch = static_cast<CEditUI*>(FindSubControl(L"kc_pick_search"));
+		if (pSearch != NULL) pSearch->SetText(L"");
+
+		PickSetCat(0);            // 分类复位到「全部商品」并重建列表
+	}
+
+	m_pPickOverlay->SetVisible(bShow);
+	// 弹层里有原生 Edit(搜索框):显隐之后必须手工同步一次(见 KcSyncNativeEdit 注释)
+	KcSyncNativeEditsIn(this);
+}
+
+void CKucunPageUI::PickSetCat(int idx)
+{
+	if (idx < 0 || idx > 6) idx = 0;
+	m_nPickCat = idx;
+
+	for (int i = 0; i < 7; i++)
+	{
+		CButtonUI* p = static_cast<CButtonUI*>(FindSubControl(
+			(std::wstring(L"kc_pick_cat_") + std::to_wstring(i)).c_str()));
+		if (p == NULL) continue;
+
+		bool act = (i == idx);
+		p->SetNormalImage(act ? L"file='dc_pill_h.png' corner='11,11,11,11'" : L"");
+		p->SetTextColor(act ? 0xFF2E9B5C : 0xFF5F6368);
+		p->SetHotTextColor(act ? 0xFF2E9B5C : 0xFF2E9B5C);
+		p->SetPushedTextColor(act ? 0xFF1B8A4C : 0xFF2E9B5C);
+		p->SetFont(act ? 113 : 13);
+	}
+
+	RefreshPickList();
+}
+
+void CKucunPageUI::RefreshPickList()
+{
+	if (m_pPickList == NULL) return;
+
+	m_pPickList->RemoveAll();
+	m_pickView.clear();
+
+	std::wstring kw = KcLower(m_strPickSearch);
+
+	for (int i = 0; i < (int)m_pick.size(); i++)
+	{
+		const KcPickItem& it = m_pick[i];
+
+		// 分类过滤(0 = 全部)
+		if (m_nPickCat > 0 && KC_PICK_CATS[m_nPickCat] != it.cat) continue;
+		// 关键字过滤:名称命中,或拼音码命中
+		if (!kw.empty())
+		{
+			KcGoods g;
+			std::wstring py = KcLookupGoods(it.name, g) ? KcLower(g.py) : L"";
+			if (KcLower(it.name).find(kw) == std::wstring::npos &&
+				py.find(kw) == std::wstring::npos) continue;
+		}
+
+		CListContainerElementUI* row = KcBuildPickRow(GetManager());
+		if (row == NULL) continue;
+
+		KcPickRowText(row, L"pk_name", it.name.c_str());
+		std::wstring meta = it.cat + L" · " + it.unit;
+		KcPickRowText(row, L"pk_meta", meta.c_str());
+		KcPickRowText(row, L"pk_stock", std::to_wstring(it.stock).c_str());
+
+		CControlUI* pCb = row->FindSubControl(L"pk_cb");
+		if (pCb != NULL) pCb->SetBkImage(it.on ? L"kc_chk_on_24.png" : L"kc_chk_off_24.png");
+
+		m_pPickList->Add(row);
+		m_pickView.push_back(i);
+	}
+
+	SyncPickSelCnt();
+}
+
+void CKucunPageUI::TogglePickRow(int idx)
+{
+	if (idx < 0 || idx >= (int)m_pickView.size()) return;
+
+	int gi = m_pickView[idx];
+	m_pick[gi].on = !m_pick[gi].on;
+
+	CListContainerElementUI* row =
+		static_cast<CListContainerElementUI*>(m_pPickList->GetItemAt(idx));
+	if (row != NULL)
+	{
+		CControlUI* pCb = row->FindSubControl(L"pk_cb");
+		if (pCb != NULL) pCb->SetBkImage(m_pick[gi].on ? L"kc_chk_on_24.png" : L"kc_chk_off_24.png");
+	}
+
+	SyncPickSelCnt();
+}
+
+void CKucunPageUI::SyncPickSelCnt()
+{
+	int n = 0;
+	for (size_t i = 0; i < m_pick.size(); i++)
+	{
+		if (m_pick[i].on) n++;
+	}
+	CLabelUI* p = static_cast<CLabelUI*>(FindSubControl(L"kc_pick_selcnt"));
+	if (p != NULL) p->SetText((L"已选 " + std::to_wstring(n) + L" 项").c_str());
+}
+
+std::vector<std::wstring> CKucunPageUI::CollectPicked() const
+{
+	std::vector<std::wstring> out;
+	for (size_t i = 0; i < m_pick.size(); i++)
+	{
+		if (m_pick[i].on) out.push_back(m_pick[i].name);
+	}
+	return out;
+}
+
+// ---------------------------------------------------------------- 事件
+void CKucunPageUI::HandleClickMsg(TNotifyUI& msg)
 {
-	CDuiString name = msg.pSender->GetName();
+	std::wstring n = (LPCTSTR)msg.pSender->GetName();
 
-	COptionUI* curOption = static_cast<COptionUI*>(msg.pSender);
-	std::wstring groupname = curOption->GetGroup();
+	// ---- 一级 Tab ----
+	if (n == L"kc_tab_chaxun") { SetTopTab(0); return; }
+	if (n == L"kc_tab_ruku") { SetTopTab(1); return; }
+	if (n == L"kc_tab_chuku") { SetTopTab(2); return; }
+	if (n == L"kc_tab_pandian") { SetTopTab(3); return; }
 
+	// ---- 记录视图的「新建」按钮:进对应的全屏子视图 ----
+	if (n == L"kc_rk_new_btn") { ShowSubView(0); return; }
+	if (n == L"kc_ck_new_btn") { ShowSubView(1); return; }
+	if (n == L"kc_pd_new_btn") { ShowSubView(2); return; }
+
+	// ---- 记录行内「详情」:开真模态单据详情弹框(R44,设计稿 t10 / t12 / t13) ----
+	// 皮肤按 KcDocDetail::kind 自动选:入库 / 出库共用 5 列的 kc_doc_detail_wnd.xml,
+	// 盘点用 6 列的 kc_pd_detail_wnd.xml。窗高按明细行数在 LoadDetail() 里算,
+	// 所以必须 LoadDetail() -> CenterWindow() -> ShowModal() 这个顺序。
+	if (n == L"op_detail")
+	{
+		if (m_is_show_modal_wnd) return;   // 已有模态在跑,忽略连点
+
+		std::wstring no = KcRowNo(msg.pSender);
+		if (no.empty())
+		{
+			if (m_pMainWnd != NULL) m_pMainWnd->ShowToast(L"未取到单号");
+			return;
+		}
+
+		KcDocDetail doc;
+		if (!KcLookupDetail(no, doc))
+		{
+			// 列表里出现的单号都应该在 g_docs 里,走到这里说明数据表漏了一条
+			if (m_pMainWnd != NULL) m_pMainWnd->ShowToast(L"未找到单据详情:" + no);
+			return;
+		}
+
+		CKucunDetailWnd* pDlg = new CKucunDetailWnd(doc);
+		m_is_show_modal_wnd = true;
+		m_curModalWnd = pDlg;
+
+		pDlg->Create(GetManager()->GetPaintWindow(), _T(""), UI_WNDSTYLE_DIALOG, WS_EX_WINDOWEDGE);
+		pDlg->SetIcon(IDI_ICON_DUILIB);
+		pDlg->LoadDetail();                // 铺数据 + 按明细行数调窗高
+
+		// 设计稿弹框后面那层 rgba(31,35,41,.45) 的整页压暗遮罩
+		if (m_pMainWnd != NULL) m_pMainWnd->ShowGlobalDim(true);
+
+		pDlg->CenterWindow();
+		pDlg->ShowModal();
+
+		if (m_pMainWnd != NULL) m_pMainWnd->ShowGlobalDim(false);
+
+		m_is_show_modal_wnd = false;
+		m_curModalWnd = NULL;
+
+		const bool bPrint = pDlg->IsPrintClicked();
+		delete pDlg;
+
+		if (bPrint && m_pMainWnd != NULL)
+		{
+			m_pMainWnd->ShowToast(L"打印小票:热敏小票本轮未接入");
+		}
+		return;
+	}
+
+	// ---- 记录行内「打印」:热敏小票本轮不做,仍只回显单号 ----
+	if (n == L"op_print")
+	{
+		std::wstring no = KcRowNo(msg.pSender);
+		if (m_pMainWnd != NULL)
+		{
+			m_pMainWnd->ShowToast(L"打印(占位):" + (no.empty() ? std::wstring(L"未取到单号") : no));
+		}
+		return;
+	}
+
+	// ---- 添加商品弹层 ----
+	if (n == L"pk_row")
+	{
+		// 整行可点:ListContainerElement 抬手发的 itemclick,sender 就是行元素
+		int idx = (m_pPickList != NULL) ? m_pPickList->GetItemIndex(msg.pSender) : -1;
+		TogglePickRow(idx);
+		return;
+	}
+	if (n == L"kc_pick_close" || n == L"kc_pick_cancel") { ShowPick(false); return; }
+	if (n == L"kc_pick_clear")
+	{
+		for (size_t i = 0; i < m_pick.size(); i++) m_pick[i].on = false;
+		RefreshPickList();
+		return;
+	}
+	if (n == L"kc_pick_ok")
+	{
+		std::vector<std::wstring> picked = CollectPicked();
+		CKucunEditViewBase* v = CurEdit();
+		ShowPick(false);
+		if (v != NULL) v->AppendPicked(picked);
+		return;
+	}
+	if (n.size() > 12 && n.compare(0, 12, L"kc_pick_cat_") == 0)
+	{
+		PickSetCat(_wtoi(n.c_str() + 12));
+		return;
+	}
+
+	// ---- 编辑子视图的页面级按钮(返回 / 取消 / 保存 / 添加商品 / 按账面填充)----
+	if (n == L"kc_rkn_back" || n == L"kc_rkn_cancel" ||
+		n == L"kc_ckn_back" || n == L"kc_ckn_cancel" ||
+		n == L"kc_pdn_back" || n == L"kc_pdn_cancel")
+	{
+		SetTopTab(m_nTopTab);
+		return;
+	}
+	if (n == L"kc_rkn_save" || n == L"kc_ckn_save" || n == L"kc_pdn_save")
+	{
+		std::wstring tip = (n == L"kc_rkn_save") ? L"入库单已保存(占位)"
+			: ((n == L"kc_ckn_save") ? L"出库单已保存(占位)" : L"盘点单已完成(占位)");
+		if (m_pMainWnd != NULL) m_pMainWnd->ShowToast(tip);
+		SetTopTab(m_nTopTab);
+		return;
+	}
+	// 【R48】盘点单的添加条按设计稿 p3 只留「按账面库存填充」一个按钮(.addbar 里就它一枚
+	// ghost 胶囊):盘点范围是「全部商品」,缺的行由 FillByBook 按账面补全,不需要再挑商品。
+	// 所以 kc_pdn_add 这个按钮在 XML 里已删除,这里的分发也一并去掉。
+	if (n == L"kc_rkn_add" || n == L"kc_ckn_add")
+	{
+		ShowPick(true);
+		return;
+	}
+	if (n == L"kc_pdn_fill")
+	{
+		if (m_pEdit[2] != NULL) m_pEdit[2]->FillByBook();
+		return;
+	}
+
+	// ---- 子视图的单元格 / 行内按钮:按前缀转发给对应子视图 ----
+	if (n.compare(0, 7, L"kc_rkn_") == 0) { if (m_pEdit[0]) m_pEdit[0]->OnClick(msg); return; }
+	if (n.compare(0, 7, L"kc_ckn_") == 0) { if (m_pEdit[1]) m_pEdit[1]->OnClick(msg); return; }
+	if (n.compare(0, 7, L"kc_pdn_") == 0) { if (m_pEdit[2]) m_pEdit[2]->OnClick(msg); return; }
+
+	// ---- 页面级小键盘:只有当前打开它的那个子视图认领 ----
+	if (n.compare(0, 6, L"kc_kp_") == 0)
+	{
+		CKucunEditViewBase* v = CurEdit();
+		if (v != NULL) v->OnClick(msg);
+		return;
+	}
+
+	// ---- 记录视图:按前缀路由 ----
+	if (n.compare(0, 6, L"kc_cx_") == 0) { if (m_pViews[0]) m_pViews[0]->OnClick(msg); }
+	else if (n.compare(0, 6, L"kc_rk_") == 0) { if (m_pViews[1]) m_pViews[1]->OnClick(msg); }
+	else if (n.compare(0, 6, L"kc_ck_") == 0) { if (m_pViews[2]) m_pViews[2]->OnClick(msg); }
+	else if (n.compare(0, 6, L"kc_pd_") == 0) { if (m_pViews[3]) m_pViews[3]->OnClick(msg); }
+}
+
+void CKucunPageUI::HandleSelectChangeMsg(TNotifyUI& msg)
+{
+	// 本页面无 Option / CheckBox 控件(弹层勾选方块是 Control,靠整行 itemclick 切换)
+	(void)msg;
 }
 
-//处理下拉框、radio的切换事件
 void CKucunPageUI::HandleItemSelectMsg(TNotifyUI& msg)
 {
+	std::wstring n = (LPCTSTR)msg.pSender->GetName();
 
+	// 盘点单的「盘点范围」下拉:选到「部分商品」直接把添加商品弹层叫出来,
+	// 这样设计稿 p4(部分商品)不用单独建视图 —— 它就是 p3 加一次勾选。
+	if (n == L"kc_pdn_combo_type" && msg.wParam == 1)
+	{
+		ShowPick(true);
+		return;
+	}
+
+	if (n.compare(0, 7, L"kc_rkn_") == 0) { if (m_pEdit[0]) m_pEdit[0]->OnItemSelect(msg); return; }
+	if (n.compare(0, 7, L"kc_ckn_") == 0) { if (m_pEdit[1]) m_pEdit[1]->OnItemSelect(msg); return; }
+	if (n.compare(0, 7, L"kc_pdn_") == 0) { if (m_pEdit[2]) m_pEdit[2]->OnItemSelect(msg); return; }
+
+	if (n.compare(0, 6, L"kc_cx_") == 0) { if (m_pViews[0]) m_pViews[0]->OnItemSelect(msg); }
+	else if (n.compare(0, 6, L"kc_rk_") == 0) { if (m_pViews[1]) m_pViews[1]->OnItemSelect(msg); }
+	else if (n.compare(0, 6, L"kc_ck_") == 0) { if (m_pViews[2]) m_pViews[2]->OnItemSelect(msg); }
+	else if (n.compare(0, 6, L"kc_pd_") == 0) { if (m_pViews[3]) m_pViews[3]->OnItemSelect(msg); }
 }
 
-//处理编辑框输入内容改变事件
 void CKucunPageUI::HandleTextChangedMsg(TNotifyUI& msg)
 {
-	CDuiString name = msg.pSender->GetName();
+	std::wstring n = (LPCTSTR)msg.pSender->GetName();
+
+	// 弹层搜索:名称 / 拼音码模糊过滤
+	if (n == L"kc_pick_search")
+	{
+		m_strPickSearch = (LPCTSTR)msg.pSender->GetText();
+		RefreshPickList();
+		return;
+	}
+
+	if (n.compare(0, 7, L"kc_rkn_") == 0) { if (m_pEdit[0]) m_pEdit[0]->OnTextChanged(msg); return; }
+	if (n.compare(0, 7, L"kc_ckn_") == 0) { if (m_pEdit[1]) m_pEdit[1]->OnTextChanged(msg); return; }
+	if (n.compare(0, 7, L"kc_pdn_") == 0) { if (m_pEdit[2]) m_pEdit[2]->OnTextChanged(msg); return; }
+
+	if (n.compare(0, 6, L"kc_cx_") == 0) { if (m_pViews[0]) m_pViews[0]->OnTextChanged(msg); }
+	else if (n.compare(0, 6, L"kc_rk_") == 0) { if (m_pViews[1]) m_pViews[1]->OnTextChanged(msg); }
+	else if (n.compare(0, 6, L"kc_ck_") == 0) { if (m_pViews[2]) m_pViews[2]->OnTextChanged(msg); }
+	else if (n.compare(0, 6, L"kc_pd_") == 0) { if (m_pViews[3]) m_pViews[3]->OnTextChanged(msg); }
 }
 
-//处理扫码枪捕捉到的扫码信息
 void CKucunPageUI::HandleTextCapture(std::string content)
 {
-
 }
 
 void CKucunPageUI::SetPos(RECT rc, bool bNeedInvalidate)
 {
 	m_nPageWidth = rc.right - rc.left;
-
 	CContainerUI::SetPos(rc, bNeedInvalidate);
 }

+ 54 - 22
zhipuzi_pos_windows/page/CKucunPageUI.h

@@ -1,43 +1,39 @@
 #pragma once
 
 #include "pch.h"
+#include <string>
+#include <vector>
 #include "../ui/CBasePageUI.h"
+#include "CKucunViews.h"
 
-#include "../zhipuzi/CFood.h"
-#include "../zhipuzi/CFoodtype.h"
-#include "../zhipuzi/CFoodpackage.h"
-
-#include "../control/CDiandanFoodItemUI.h"
-#include "../zhipuzi/CDiandanOrder.h"
-
+// ============================================================================
+// 库存页宿主(进销存)
+//
+// kucun_page.xml 一棵树里同时住着 5 种「页面」:
+//   主态    : kc_tabrow(一级胶囊 Tab)+ 4 个记录视图 kc_view_{chaxun,ruku,chuku,pandian}
+//   子视图态: kc_view_{rkn,ckn,pdn}_new —— 设计稿 v4 的三张「独立页面」,
+//             不注册新 Page,靠 SetVisible 与主态互斥切换,视觉/交互上等同独立页。
+//   浮层    : kc_keypad(页面级数字键盘,三张子视图共用)+ kc_pick_overlay(添加商品弹层)。
+//
+// 为什么子视图要做成「同页显隐」而不是新 Page:注册新 Page 要动 CNavigation/更多宫格/
+// 右侧导航三处,且失去「返回即回主态」的零成本上下文。显隐切换则完全复用已经跑通的
+// kc_view_* 套路,改造成本接近 0。
+// ============================================================================
 class CKucunPageUI : public CBasePageUI
 {
 public:
 	CKucunPageUI();
 	~CKucunPageUI();
 
-	//初始化页面控件,页面创建构造的时候调用一次,注意和InitShow的区别,这个不触发控件的任何事件
 	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);
 
-	//处理自定义消息,各个页面处理各个页面自己的(是自己处理的消息返回true,不是自己处理的消息返回false)
 	bool HandleCustomMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
 	{
 		return false;
@@ -46,6 +42,42 @@ public:
 	void SetPos(RECT rc, bool bNeedInvalidate = true);
 
 private:
-	//当前控件的实际宽度
+	// 一级 Tab 切换:显示对应视图并刷新 Tab 样式
+	void SetTopTab(int idx);
+
+	// 主态 / 子视图态 互斥显隐。ShowMain 时把 kc_tabrow 与 4 个记录视图一起放出来,
+	// 子视图态则把 kc_tabrow 与 4 个记录视图一起收掉。
+	void HideAllViews();
+	void ShowMain();
+	void ShowSubView(int idx);            // 0 入库 / 1 出库 / 2 盘点
+	CKucunEditViewBase* CurEdit() const;  // 当前子视图;主态返回 NULL
+
+	// ---- 「添加商品」弹层(页面级,非模态:真模态会 DestroyWindow 重建阴影窗)----
+	void ShowPick(bool bShow);
+	void PickSetCat(int idx);             // 0 = 全部商品,1~6 = 分类
+	void RefreshPickList();               // 按分类 + 搜索重填列表(勾选态跨分类保留)
+	void TogglePickRow(int idx);          // idx = 列表可见行号
+	void SyncPickSelCnt();
+	std::vector<std::wstring> CollectPicked() const;
+
+	// 4 个记录视图(库存查询 / 入库 / 出库 / 库存盘点),构造时创建、页面复用期间常驻
+	CKucunViewBase* m_pViews[4];
+	// 3 个编辑子视图(新建入库单 / 出库单 / 盘点单)
+	CKucunEditViewBase* m_pEdit[3];
+	// 页面级小键盘面板宿主(kc_keypad)——三张子视图与它不同源,需要单独持有做上报
+	CContainerUI* m_pKpHost;
+	CContainerUI* m_pPickOverlay;
+	CListUI* m_pPickList;
+
+	// 弹层候选项:m_pick 是全集(on 跨分类保留),m_pickView 是当前过滤后要显示的下标
+	std::vector<KcPickItem> m_pick;
+	std::vector<int> m_pickView;
+	int m_nPickCat;
+	std::wstring m_strPickSearch;
+
+	int m_nTopTab;
+	int m_nSubView;   // -1 = 主态;0 / 1 / 2 = 编辑子视图
+
+	// 当前控件的实际宽度
 	int m_nPageWidth;
-};
+};

+ 2179 - 0
zhipuzi_pos_windows/page/CKucunViews.cpp

@@ -0,0 +1,2179 @@
+#include "pch.h"
+#include "CKucunViews.h"
+#include "../control/ControlEx.h"
+
+namespace
+{
+	// 数值格式化(KcGroupInt / KcFormatMoney / KcFormatInt)已提到 CKucunViews.h 做 inline,
+	// 详情弹框 CKucunDetailWnd 与本文件共用同一份实现。
+
+	// 库存台账:状态由 当前库存 vs 安全库存 推导
+	// 口径(与设计稿 t5 副标题「仅显示预警 / 缺货商品」一致):
+	//   缺货   = 当前库存 < 安全库存
+	//   预警   = 安全库存 <= 当前库存 < 2 x 安全库存
+	//   正常   = 其余
+	int KcCxStatus(int cur, int safe)
+	{
+		if (cur < safe) return 2;
+		if (safe > 0 && cur < safe * 2) return 1;
+		return 0;
+	}
+
+	// 胶囊标签底图 / 文字色表已提到 CKucunViews.h(KcTagImage / KcTagText / KcApplyTag)。
+
+	// ---- 占位假数据(数值口径逐项对齐设计稿 t2 / t3 / t4 / t6 / t7 / t8) ----
+	// 入库记录:类型 = 采购入库 / 调拨入库 / 退货入库,状态 = 0 已入库 1 待入库
+	const KcRkItem g_rk[] = {
+		{ L"CG20260928001", L"采购入库", L"张丽", 5, 1280.0, 0 },
+		{ L"CG20260927003", L"采购入库", L"王强", 3, 2150.0, 0 },
+		{ L"CG20260926002", L"调拨入库", L"张丽", 2, 860.0, 0 },
+		{ L"CG20260925006", L"退货入库", L"李明", 6, 1530.0, 0 },
+		{ L"CG20260924001", L"采购入库", L"王强", 4, 1600.0, 0 },
+	};
+	const int g_rk_n = (int)(sizeof(g_rk) / sizeof(g_rk[0]));
+
+	// 入库统计(按商品维度):入库数量列在设计稿里带单位("60 桶"),由 C++ 拼
+	const KcRkStat g_rk_stat[] = {
+		{ L"食用油", L"调料", L"桶", 4, 60,  3300.0 },
+		{ L"大米",   L"主食", L"斤", 3, 150, 1980.0 },
+		{ L"牛肉",   L"肉类", L"斤", 2, 80,  1600.0 },
+		{ L"面粉",   L"主料", L"袋", 2, 40,  1040.0 },
+		{ L"生抽",   L"调料", L"瓶", 1, 20,  500.0 },
+	};
+	const int g_rk_stat_n = (int)(sizeof(g_rk_stat) / sizeof(g_rk_stat[0]));
+
+	// 出库记录:类型 = 调拨出库 / 报损 / 采购退货,状态 = 0 已出库
+	const KcCkItem g_ck[] = {
+		{ L"CK20260928002", L"调拨出库", L"张丽", 4, 420.0, 0 },
+		{ L"CK20260927004", L"报损",     L"王强", 2, 96.0,  0 },
+		{ L"CK20260926001", L"采购退货", L"李明", 3, 540.0, 0 },
+		{ L"CK20260925003", L"调拨出库", L"张丽", 5, 680.0, 0 },
+		{ L"CK20260924002", L"报损",     L"王强", 1, 45.0,  0 },
+	};
+	const int g_ck_n = (int)(sizeof(g_ck) / sizeof(g_ck[0]));
+
+	const KcRkStat g_ck_stat[] = {
+		{ L"面粉",   L"主料", L"袋", 5, 35, 1450.0 },
+		{ L"大米",   L"主食", L"斤", 4, 60, 1240.0 },
+		{ L"牛肉",   L"肉类", L"斤", 3, 22, 980.0 },
+		{ L"食用油", L"调料", L"桶", 3, 8,  880.0 },
+		{ L"鸡蛋",   L"蛋类", L"斤", 3, 18, 630.0 },
+	};
+	const int g_ck_stat_n = (int)(sizeof(g_ck_stat) / sizeof(g_ck_stat[0]));
+
+	// 盘点记录:结果 = 0 盘盈(蓝) 1 盘亏(红) 2 无差异(灰);无草稿 / 进行中态
+	const KcPdItem g_pd[] = {
+		{ L"PD20260925001", L"全部商品",    L"张丽", 8, 3, 2, -130.0, 1 },
+		{ L"PD20260910002", L"主食 / 调料", L"王强", 5, 0, 0, 0.0,    2 },
+	};
+	const int g_pd_n = (int)(sizeof(g_pd) / sizeof(g_pd[0]));
+
+	// 盘点差异(按商品维度):diff 正负 ≠ 结果着色,两列各自算
+	const KcPdStat g_pd_stat[] = {
+		{ L"大米", L"主食", L"斤", 2, 5,  65.0,   0 },
+		{ L"鸡蛋", L"蛋类", L"斤", 1, 3,  39.0,   0 },
+		{ L"土豆", L"蔬菜", L"斤", 1, 3,  6.0,    0 },
+		{ L"番茄", L"蔬菜", L"斤", 2, -4, -24.0,  1 },
+		{ L"牛肉", L"肉类", L"斤", 1, -6, -216.0, 1 },
+	};
+	const int g_pd_stat_n = (int)(sizeof(g_pd_stat) / sizeof(g_pd_stat[0]));
+
+	// ---- 商品档案(占位):三张编辑页 + 「添加商品」弹层 + 库存查询两张表共用 ----
+	// 名称 / 分类 / 单位 / 拼音码 / 库存 / 入库默认单价 与设计稿 v4 的「添加商品」列表逐项一致;
+	// safe / avgCost / inPrice / salePrice 四个字段取自设计稿 v2 的 t1 台账与 t9 库存金额报表,
+	// 保证「库存查询」「库存金额」「添加商品」三处的数字彼此自洽。
+	const KcGoods g_goods[] = {
+		// name,  cat,    unit,  py,     stock, price,  safe, fixedCost, avgCost, inPrice, salePrice
+		{ L"大米",   L"主食", L"斤", L"dm",  320, 3.20,  100, false, 4.20,  4.50,  6.80  },
+		{ L"面粉",   L"主料", L"袋", L"mf",  45,  45.00, 30,  true,  26.00, 26.00, 38.00 },
+		{ L"食用油", L"调料", L"桶", L"syy", 12,  86.00, 20,  false, 57.50, 55.00, 86.00 },
+		{ L"番茄",   L"蔬菜", L"斤", L"fq",  8,   4.50,  30,  false, 4.00,  3.80,  6.50  },
+		{ L"牛肉",   L"肉类", L"斤", L"nr",  56,  38.00, 40,  true,  28.00, 28.00, 39.90 },
+		{ L"鸡蛋",   L"蛋类", L"斤", L"jd",  18,  6.00,  25,  false, 5.40,  5.20,  7.90  },
+		{ L"生抽",   L"调料", L"瓶", L"sc",  60,  15.00, 15,  true,  8.50,  8.50,  15.00 },
+		{ L"土豆",   L"蔬菜", L"斤", L"td",  5,   2.80,  40,  false, 2.60,  2.60,  4.50  },
+	};
+	const int g_goods_n = (int)(sizeof(g_goods) / sizeof(g_goods[0]));
+
+	// 库存查询 / 添加商品弹层共用的分类下拉项(与 g_goods 的 cat 取值一一对应)
+	const wchar_t* const KC_CATS[6] =
+	{
+		L"主食", L"主料", L"调料", L"蔬菜", L"肉类", L"蛋类"
+	};
+
+	// ---- 单据详情明细(t10 入库 / t12 出库 / t13 盘点为设计稿原文,其余同构占位) ----
+	// 列口径:入库/出库 = 商品 / 单位 / 数量 / 单价 / 金额;盘点 = 商品 / 单位 / 账面 / 实盘 / 差异 / 盈亏
+	const KcDetailRow g_drk1[] = {
+		{ L"大米", L"斤", 100, 4.20, 420.00, 0, 0, 0, 0.0 },
+		{ L"面粉", L"袋", 5, 26.00, 130.00, 0, 0, 0, 0.0 },
+		{ L"食用油", L"桶", 5, 55.00, 275.00, 0, 0, 0, 0.0 },
+		{ L"生抽", L"瓶", 20, 8.50, 170.00, 0, 0, 0, 0.0 },
+		{ L"牛肉", L"斤", 10, 28.50, 285.00, 0, 0, 0, 0.0 },
+	};
+	const KcDetailRow g_drk2[] = {
+		{ L"大米", L"斤", 200, 3.20, 640.00, 0, 0, 0, 0.0 },
+		{ L"牛肉", L"斤", 30, 38.00, 1140.00, 0, 0, 0, 0.0 },
+		{ L"食用油", L"桶", 5, 74.00, 370.00, 0, 0, 0, 0.0 },
+	};
+	const KcDetailRow g_drk3[] = {
+		{ L"食用油", L"桶", 10, 60.00, 600.00, 0, 0, 0, 0.0 },
+		{ L"面粉", L"袋", 5, 52.00, 260.00, 0, 0, 0, 0.0 },
+	};
+	const KcDetailRow g_drk4[] = {
+		{ L"大米", L"斤", 100, 3.20, 320.00, 0, 0, 0, 0.0 },
+		{ L"面粉", L"袋", 10, 32.00, 320.00, 0, 0, 0, 0.0 },
+		{ L"食用油", L"桶", 2, 86.00, 172.00, 0, 0, 0, 0.0 },
+		{ L"牛肉", L"斤", 10, 38.00, 380.00, 0, 0, 0, 0.0 },
+		{ L"鸡蛋", L"斤", 20, 6.00, 120.00, 0, 0, 0, 0.0 },
+		{ L"生抽", L"瓶", 10, 21.80, 218.00, 0, 0, 0, 0.0 },
+	};
+	const KcDetailRow g_drk5[] = {
+		{ L"大米", L"斤", 250, 3.20, 800.00, 0, 0, 0, 0.0 },
+		{ L"牛肉", L"斤", 10, 38.00, 380.00, 0, 0, 0, 0.0 },
+		{ L"鸡蛋", L"斤", 30, 6.00, 180.00, 0, 0, 0, 0.0 },
+		{ L"土豆", L"斤", 80, 3.00, 240.00, 0, 0, 0, 0.0 },
+	};
+	const KcDetailRow g_dck1[] = {
+		{ L"面粉", L"袋", 2, 28.00, 56.00, 0, 0, 0, 0.0 },
+		{ L"大米", L"斤", 8, 15.50, 124.00, 0, 0, 0, 0.0 },
+		{ L"牛肉", L"斤", 3, 40.00, 120.00, 0, 0, 0, 0.0 },
+		{ L"鸡蛋", L"斤", 12, 10.00, 120.00, 0, 0, 0, 0.0 },
+	};
+	const KcDetailRow g_dck2[] = {
+		{ L"番茄", L"斤", 12, 4.50, 54.00, 0, 0, 0, 0.0 },
+		{ L"鸡蛋", L"斤", 7, 6.00, 42.00, 0, 0, 0, 0.0 },
+	};
+	const KcDetailRow g_dck3[] = {
+		{ L"大米", L"斤", 50, 3.20, 160.00, 0, 0, 0, 0.0 },
+		{ L"面粉", L"袋", 4, 45.00, 180.00, 0, 0, 0, 0.0 },
+		{ L"食用油", L"桶", 2, 100.00, 200.00, 0, 0, 0, 0.0 },
+	};
+	const KcDetailRow g_dck4[] = {
+		{ L"大米", L"斤", 20, 3.20, 64.00, 0, 0, 0, 0.0 },
+		{ L"面粉", L"袋", 2, 45.00, 90.00, 0, 0, 0, 0.0 },
+		{ L"食用油", L"桶", 2, 86.00, 172.00, 0, 0, 0, 0.0 },
+		{ L"牛肉", L"斤", 5, 38.00, 190.00, 0, 0, 0, 0.0 },
+		{ L"生抽", L"瓶", 10, 16.40, 164.00, 0, 0, 0, 0.0 },
+	};
+	const KcDetailRow g_dck5[] = {
+		{ L"番茄", L"斤", 10, 4.50, 45.00, 0, 0, 0, 0.0 },
+	};
+	const KcDetailRow g_dpd1[] = {
+		{ L"大米", L"斤", 0, 0.0, 0.0, 315, 320, 5, 65.00 },
+		{ L"鸡蛋", L"斤", 0, 0.0, 0.0, 15, 18, 3, 39.00 },
+		{ L"土豆", L"斤", 0, 0.0, 0.0, 2, 5, 3, 6.00 },
+		{ L"番茄", L"斤", 0, 0.0, 0.0, 12, 8, -4, -24.00 },
+		{ L"牛肉", L"斤", 0, 0.0, 0.0, 62, 56, -6, -216.00 },
+	};
+	const KcDetailRow g_dpd2[] = {
+		{ L"大米", L"斤", 0, 0.0, 0.0, 300, 300, 0, 0.00 },
+		{ L"面粉", L"袋", 0, 0.0, 0.0, 40, 40, 0, 0.00 },
+		{ L"食用油", L"桶", 0, 0.0, 0.0, 10, 10, 0, 0.00 },
+		{ L"生抽", L"瓶", 0, 0.0, 0.0, 50, 50, 0, 0.00 },
+		{ L"鸡蛋", L"斤", 0, 0.0, 0.0, 20, 20, 0, 0.00 },
+	};
+
+	// ---- 单据详情头(kind:0 入库 / 1 出库 / 2 盘点) ----
+	struct KcDocRec
+	{
+		int kind; LPCTSTR title, sub, no, f2lab, f2txt; int f2tag;
+		LPCTSTR status; int statTag; LPCTSTR whoLab, who, timeLab, time; int printCnt;
+		const KcDetailRow* rows; int n;
+	};
+	const KcDocRec g_docs[] = {
+		{ 0, L"入库单详情", L"出库单 / 盘点单详情同构", L"CG20260928001", L"入库类型", L"采购入库", KC_TAG_GRN,
+		  L"已入库", KC_TAG_GRN, L"经手人", L"张丽", L"入库时间", L"2026-09-28 14:32", 0,
+		  g_drk1, 5 },
+		{ 0, L"入库单详情", L"出库单 / 盘点单详情同构", L"CG20260927003", L"入库类型", L"采购入库", KC_TAG_GRN,
+		  L"已入库", KC_TAG_GRN, L"经手人", L"王强", L"入库时间", L"2026-09-27 10:05", 0,
+		  g_drk2, 3 },
+		{ 0, L"入库单详情", L"出库单 / 盘点单详情同构", L"CG20260926002", L"入库类型", L"调拨入库", KC_TAG_BLUE,
+		  L"已入库", KC_TAG_GRN, L"经手人", L"张丽", L"入库时间", L"2026-09-26 09:18", 0,
+		  g_drk3, 2 },
+		{ 0, L"入库单详情", L"出库单 / 盘点单详情同构", L"CG20260925006", L"入库类型", L"退货入库", KC_TAG_ORG,
+		  L"已入库", KC_TAG_GRN, L"经手人", L"李明", L"入库时间", L"2026-09-25 16:02", 0,
+		  g_drk4, 6 },
+		{ 0, L"入库单详情", L"出库单 / 盘点单详情同构", L"CG20260924001", L"入库类型", L"采购入库", KC_TAG_GRN,
+		  L"已入库", KC_TAG_GRN, L"经手人", L"王强", L"入库时间", L"2026-09-24 08:47", 0,
+		  g_drk5, 4 },
+		{ 1, L"出库单详情", L"入库单 / 盘点单详情同构", L"CK20260928002", L"出库类型", L"调拨出库", KC_TAG_BLUE,
+		  L"已出库", KC_TAG_GRN, L"经手人", L"张丽", L"出库时间", L"2026-09-28 11:20", 0,
+		  g_dck1, 4 },
+		{ 1, L"出库单详情", L"入库单 / 盘点单详情同构", L"CK20260927004", L"出库类型", L"报损", KC_TAG_RED,
+		  L"已出库", KC_TAG_GRN, L"经手人", L"王强", L"出库时间", L"2026-09-27 15:33", 0,
+		  g_dck2, 2 },
+		{ 1, L"出库单详情", L"入库单 / 盘点单详情同构", L"CK20260926001", L"出库类型", L"采购退货", KC_TAG_ORG,
+		  L"已出库", KC_TAG_GRN, L"经手人", L"李明", L"出库时间", L"2026-09-26 14:11", 0,
+		  g_dck3, 3 },
+		{ 1, L"出库单详情", L"入库单 / 盘点单详情同构", L"CK20260925003", L"出库类型", L"调拨出库", KC_TAG_BLUE,
+		  L"已出库", KC_TAG_GRN, L"经手人", L"张丽", L"出库时间", L"2026-09-25 10:26", 0,
+		  g_dck4, 5 },
+		{ 1, L"出库单详情", L"入库单 / 盘点单详情同构", L"CK20260924002", L"出库类型", L"报损", KC_TAG_RED,
+		  L"已出库", KC_TAG_GRN, L"经手人", L"王强", L"出库时间", L"2026-09-24 17:50", 0,
+		  g_dck5, 1 },
+		{ 2, L"盘点单详情", L"含 账面 / 实盘 / 差异 列", L"PD20260925001", L"盘点范围", L"全部商品", -1,
+		  L"已完成", KC_TAG_GRN, L"盘点人", L"张丽", L"盘点时间", L"2026-09-25 16:40", 0,
+		  g_dpd1, 5 },
+		{ 2, L"盘点单详情", L"含 账面 / 实盘 / 差异 列", L"PD20260910002", L"盘点范围", L"主食 / 调料", -1,
+		  L"已完成", KC_TAG_GRN, L"盘点人", L"王强", L"盘点时间", L"2026-09-10 15:20", 0,
+		  g_dpd2, 5 },
+	};
+	const int g_docs_n = (int)(sizeof(g_docs) / sizeof(g_docs[0]));
+}
+
+// ============================ 商品档案访问器 ============================
+const std::vector<KcGoods>& KcAllGoods()
+{
+	static std::vector<KcGoods> s_all;
+	if (s_all.empty())
+	{
+		for (int i = 0; i < g_goods_n; i++) s_all.push_back(g_goods[i]);
+	}
+	return s_all;
+}
+
+bool KcLookupGoods(const std::wstring& name, KcGoods& out)
+{
+	const std::vector<KcGoods>& all = KcAllGoods();
+	for (size_t i = 0; i < all.size(); i++)
+	{
+		if (all[i].name == name) { out = all[i]; return true; }
+	}
+	return false;
+}
+
+// ============================ 单据详情访问器 ============================
+// 把匿名命名空间里的静态表拷成值语义的 KcDocDetail,弹框侧不再依赖任何文件内私有符号
+bool KcLookupDetail(const std::wstring& no, KcDocDetail& out)
+{
+	for (int i = 0; i < g_docs_n; i++)
+	{
+		const KcDocRec& d = g_docs[i];
+		if (no != d.no) continue;
+
+		out.kind = d.kind;
+		out.title = d.title;
+		out.sub = d.sub;
+		out.no = d.no;
+		out.f2lab = d.f2lab;
+		out.f2txt = d.f2txt;
+		out.f2tag = d.f2tag;
+		out.status = d.status;
+		out.statTag = d.statTag;
+		out.whoLab = d.whoLab;
+		out.who = d.who;
+		out.timeLab = d.timeLab;
+		out.time = d.time;
+		out.printCnt = d.printCnt;
+		out.rows.clear();
+		for (int k = 0; k < d.n; k++) out.rows.push_back(d.rows[k]);
+		return true;
+	}
+	return false;
+}
+
+// ============================ CKucunViewBase ============================
+CControlUI* CKucunViewBase::Find(LPCTSTR name)
+{
+	if (m_pHost == NULL) return NULL;
+	return m_pHost->FindSubControl(name);
+}
+
+CListContainerElementUI* CKucunViewBase::NewRow(LPCTSTR xmlfile)
+{
+	CDialogBuilder builder;
+	CDialogBuilderCallbackEx cb;
+	CControlUI* p = builder.Create(xmlfile, (UINT)0, &cb, m_pManager);
+	return static_cast<CListContainerElementUI*>(p);
+}
+
+void CKucunViewBase::ClearList(CListUI* list)
+{
+	if (list == NULL) return;
+	while (list->GetCount() > 0) list->RemoveAt(0);
+}
+
+void CKucunViewBase::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 CKucunViewBase::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 CKucunViewBase::SetRowWidth(CListContainerElementUI* row, LPCTSTR name, int width)
+{
+	if (row == NULL) return;
+	CControlUI* p = row->FindSubControl(name);
+	if (p) p->SetFixedWidth(width);
+}
+
+void CKucunViewBase::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);
+}
+
+// 统计卡整数:数值 26px 粗体 + 单位 13px 灰(showhtml 里 {f 13} 切字号、{c #8A9099} 转灰)
+void CKucunViewBase::SetStatInt(LPCTSTR name, int val, LPCWSTR unit)
+{
+	CLabelUI* p = FindC<CLabelUI>(name);
+	if (p == NULL) return;
+	std::wstring s = KcGroupInt(std::to_wstring(val));
+	s += L"{x 4}{c #8A9099}{f 13}"; s += unit; s += L"{/f}{/c}";
+	p->SetText(s.c_str());
+	p->SetFont(p->GetFont());   // 重置 autocalcwidth 缓存
+}
+
+void CKucunViewBase::SetStatMoney(LPCTSTR name, double val, LPCWSTR unit)
+{
+	CLabelUI* p = FindC<CLabelUI>(name);
+	if (p == NULL) return;
+	std::wstring s = KcFormatInt(val);
+	s += L"{x 4}{c #8A9099}{f 13}"; s += unit; s += L"{/f}{/c}";
+	p->SetText(s.c_str());
+	p->SetFont(p->GetFont());
+}
+
+void CKucunViewBase::SetListCount(LPCTSTR labelName, int n)
+{
+	CLabelUI* p = FindC<CLabelUI>(labelName);
+	if (p == NULL) return;
+	std::wstring s = L"共 "; s += std::to_wstring(n); s += L" 项";
+	p->SetText(s.c_str());
+}
+
+// 台账 / 库存金额的表尾:分页口径(每页 KC_PAGE_SIZE 条)
+void CKucunViewBase::SetFootPaged(LPCTSTR name, int shown, int total)
+{
+	CLabelUI* p = FindC<CLabelUI>(name);
+	if (p == NULL) return;
+	std::wstring s;
+	if (shown < total)
+	{
+		s = L"上滑自动加载下一页 · 已显示 ";
+		s += std::to_wstring(shown); s += L" / "; s += std::to_wstring(total); s += L" 项";
+	}
+	else
+	{
+		s = L"已全部加载 · 共 "; s += std::to_wstring(total); s += L" 项";
+	}
+	p->SetText(s.c_str());
+}
+
+// 记录列表的表尾:按时间倒序 + 「默认加载最近 N 条」
+void CKucunViewBase::SetFootRecord(LPCTSTR name, int shown, int total)
+{
+	CLabelUI* p = FindC<CLabelUI>(name);
+	if (p == NULL) return;
+	std::wstring s;
+	if (shown < total)
+	{
+		s = L"按时间倒序 · 默认加载最近 "; s += std::to_wstring(KC_PAGE_SIZE);
+		s += L" 条 · 上滑自动加载更多 · 已显示 "; s += std::to_wstring(shown); s += L" 条";
+	}
+	else
+	{
+		s = L"按时间倒序 · 已全部加载 · 共 "; s += std::to_wstring(total); s += L" 条";
+	}
+	p->SetText(s.c_str());
+}
+
+// 统计视图的表尾:一次全量,不分页
+void CKucunViewBase::SetFootAll(LPCTSTR name, int total)
+{
+	CLabelUI* p = FindC<CLabelUI>(name);
+	if (p == NULL) return;
+	std::wstring s = L"已全部加载 · 共 "; s += std::to_wstring(total); s += L" 项";
+	p->SetText(s.c_str());
+}
+
+// 切换胶囊三态(R45 对着设计稿 v2 重做):选中 = 全圆实心绿胶囊 + 白字,
+// 未选中 = 透明底 + 灰字;hover / pushed 兜底图换成灰度胶囊,保证触屏下按下去有反馈。
+void CKucunViewBase::StyleSeg(CButtonUI* p, bool act)
+{
+	if (p == NULL) return;
+	// 圆度来自源图自身(kc_seggrn_* 源图 radius 16),九宫格 corner 只定「取多大一块」
+	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);
+}
+
+// ---------------------------------------------------------------- 页面级滚动的高度传播
+// 【R45】滚动条上移到页面级容器 kc_scroll(见 kucun_page.xml)之后,滚动容器里
+// 「最多只能有一个弹性子项」:CVerticalLayoutUI::SetPos 会对 EstimateSize().cy == 0
+// 的子项做 cyExpand 均分剩余高度,视图容器若留在弹性状态,cyFixed 恒等于视口高
+// ⇒ cyNeeded 恒等于视口高 ⇒ 滚动范围恒为 0,整页根本不滚。
+// 而 CContainerUI::DoPaint 会把绘制裁剪到自己的 m_rcItem 上,容器没被撑开时
+// 溢出的行既画不出来、外层也拿不到真实高度。
+// 所以「把某层撑开后,必须沿父链逐级把祖先的高度也算出来写死」,一直做到视图容器为止
+// (遇到滚动容器 kc_scroll 就停,滚动容器自身的尺寸由页面根给,不能写死)。
+// 【R48】三个「新建单」页已经从 kc_scroll 提到 kc_page 下、并且自带滚动主体
+// (kc_rkn_body / kc_ckn_body / kc_pdn_body,弹性高度 + vscrollbar="true")。
+// 这些页里**不能**再往上写死高度 —— body 一旦有了固定高度,竖向布局就按这个高度摆放,
+// body 自己的滚动范围恒为 0、整页也不会滚。所以父链走到 body 就停。
+// 每层的算法:各「可见、非 float」子项的固定高度之和 + 上下 inset + childpadding*(nVis-1);
+// 只要发现某个可见子项没有确定高度(弹性项)就整层放弃,绝不瞎猜。
+static void KcPropagateFixedHeightUp(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("kc_scroll")) == 0) return;   // 滚动容器不写死
+		if (nm != NULL &&
+			(_tcscmp(nm, _T("kc_rkn_body")) == 0 ||
+			 _tcscmp(nm, _T("kc_ckn_body")) == 0 ||
+			 _tcscmp(nm, _T("kc_pdn_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;
+	}
+}
+
+// 整页滚动适配:把 List 高度撑成「表头(44) + nRows*行高(54) + List 自身的上下 inset」,
+// 再沿父链把每层容器的高度逐级写死(见 KcPropagateFixedHeightUp)。
+// 空表至少留一行高,避免卡片塌陷。
+void CKucunViewBase::FitListHeight(LPCTSTR listName, int nRows)
+{
+	CListUI* pList = FindC<CListUI>(listName);
+	if (pList == NULL) return;
+	const int HEADER_H = 44;   // 与 kucun_page.xml 中 <ListHeader height="44"> 一致
+	const int ROW_H = 54;      // 与 kc_row_*.xml 中 <ListContainerElement height="54"> 一致
+	int rows = (nRows > 0) ? nRows : 1;
+	// 【R45】8 张记录表的 List 新增 inset="1,1,1,10"(让出 kc_tblcard.png 的 1px 外框
+	// 与 10px 圆角底带)。inset 由 CContainerUI::SetPos 扣在自己的内容区上、不改 m_rcItem,
+	// 所以固定高度必须把这 11px 一并算上,否则最下面一行会被裁掉。
+	RECT rcLi = pList->GetInset();
+	int h = rcLi.top + rcLi.bottom + HEADER_H + rows * ROW_H;
+	pList->SetFixedHeight(h);
+
+	// 【R45】最后一行不画行分隔线(设计稿 .tr:last-child{border-bottom:none})。
+	// 行模板 kc_row_*.xml 统一带 bordersize="0,0,0,1",若不清掉,最后一行的底边会停在
+	// kc_tblcard.png 圆角底带上方 10px 处,和卡片自己的 1px 下边框凑成两条平行线。
+	// 表底那条线交给 kc_tblcard.png 的外框负责。
+	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);
+		}
+	}
+
+	KcPropagateFixedHeightUp(pList);
+}
+
+void CKucunViewBase::AddComboItem(CComboUI* combo, LPCWSTR text)
+{
+	if (combo == NULL) return;
+	CListLabelElementUI* pElem = new CListLabelElementUI();
+	pElem->SetText(text);
+	combo->Add(pElem);
+}
+
+void CKucunViewBase::SelectCombo(CComboUI* combo, int idx)
+{
+	if (combo == NULL) return;
+	combo->SelectItem(idx, false);
+}
+
+void CKucunViewBase::ReadSearch(LPCTSTR editName, std::wstring& out)
+{
+	CEditUI* pEdit = FindC<CEditUI>(editName);
+	if (pEdit != NULL) out = (LPCTSTR)pEdit->GetText();
+}
+
+void CKucunViewBase::SyncSearchTishi(LPCTSTR tishiName, LPCTSTR editName)
+{
+	CEditUI* pEdit = FindC<CEditUI>(editName);
+	if (pEdit == NULL) return;
+	CLabelUI* pTishi = FindC<CLabelUI>(tishiName);
+	if (pTishi == NULL) return;
+	// 只看「有没有内容」:Edit 是透明的,占位 Label 压在它下面那层,没有原生 placeholder 可用。
+	pTishi->SetVisible(((LPCTSTR)pEdit->GetText())[0] == 0);
+}
+
+// ============================ 视图1:库存查询 ============================
+// 两个子视图共用统计卡与筛选行,只有表格区互换:
+//   kc_cx_body_state  库存状态(库存台账,6 列,带「只看预警商品」开关)
+//   kc_cx_body_amt    库存金额(11 列只读报表,设计稿 t9,无开关)
+void CKucunChaxunView::OnInitControl()
+{
+	CComboUI* pCat = FindC<CComboUI>(L"kc_cx_combo_cat");
+	if (pCat)
+	{
+		AddComboItem(pCat, L"全部分类");
+		for (int i = 0; i < 6; i++) AddComboItem(pCat, KC_CATS[i]);
+		SelectCombo(pCat, 0);
+	}
+	ApplyWarnSwitch();
+	SetSeg(0, false);
+}
+
+void CKucunChaxunView::InitShow()
+{
+	// 统计卡口径:缺货 = 当前库存 < 安全库存;预警 = 安全库存 <= 当前库存 < 2 x 安全库存。
+	// 库存总值 = 加权平均成本价 x 当前库存(与「库存金额」报表的库存成本同口径)。
+	const std::vector<KcGoods>& all = KcAllGoods();
+	int nTotal = (int)all.size(), nWarn = 0, nLack = 0;
+	double dValue = 0.0;
+	for (size_t i = 0; i < all.size(); i++)
+	{
+		int st = KcCxStatus(all[i].stock, all[i].safe);
+		if (st == 1) nWarn++;
+		else if (st == 2) nLack++;
+		dValue += all[i].avgCost * all[i].stock;
+	}
+	SetStatInt(L"kc_cx_stat_total", nTotal, L"项");
+	SetStatInt(L"kc_cx_stat_warn", nWarn, L"项");
+	SetStatInt(L"kc_cx_stat_lack", nLack, L"项");
+	SetStatMoney(L"kc_cx_stat_value", dValue, L"元");
+
+	// 搜索框 / 分类下拉复位(重新进页面时不该带着上次的条件)
+	CComboUI* pCat = FindC<CComboUI>(L"kc_cx_combo_cat");
+	if (pCat) SelectCombo(pCat, 0);
+	CEditUI* pEdit = FindC<CEditUI>(L"kc_cx_search_edit");
+	if (pEdit) pEdit->SetText(L"");
+	m_strSearch.clear();
+	SyncSearchTishi(L"kc_cx_search_tishi", L"kc_cx_search_edit");
+
+	SetSeg(m_nSeg, true);
+}
+
+void CKucunChaxunView::SetSeg(int active, bool bBuild)
+{
+	m_nSeg = active;
+	StyleSeg(FindC<CButtonUI>(L"kc_cx_seg_state"), active == 0);
+	StyleSeg(FindC<CButtonUI>(L"kc_cx_seg_amt"), active == 1);
+
+	// 「只看预警商品」只在库存状态视图出现(设计稿 t9 的工具条没有这一项)
+	CControlUI* pSwx = Find(L"kc_cx_swx");
+	if (pSwx) pSwx->SetVisible(active == 0);
+
+	CControlUI* pState = Find(L"kc_cx_body_state");
+	CControlUI* pAmt = Find(L"kc_cx_body_amt");
+	if (pState) pState->SetVisible(active == 0);
+	if (pAmt) pAmt->SetVisible(active == 1);
+
+	if (bBuild) { if (active == 0) BuildStateRows(); else BuildAmtRows(); }
+}
+
+// 开关用「两张整图换 bkimage」:圆点位置已经烘进 PNG,不需要浮层定位子控件。
+// main.xml 的全局 Default 会给所有 Button 套 btn_green_*,所以三个态都要显式覆盖。
+void CKucunChaxunView::ApplyWarnSwitch()
+{
+	CButtonUI* p = FindC<CButtonUI>(L"kc_cx_warn_switch");
+	if (p == NULL) return;
+	LPCTSTR img = m_bWarnOnly ? L"file='kc_switch_on.png'" : L"file='kc_switch_off.png'";
+	p->SetNormalImage(img);
+	p->SetHotImage(img);
+	p->SetPushedImage(img);
+}
+
+// 分类 + 关键字过滤(两张表共用)
+bool CKucunChaxunView::RowPass(const KcGoods& g, const std::wstring& cat) const
+{
+	if (!cat.empty() && cat != L"全部分类" && g.cat != cat) return false;
+	if (!m_strSearch.empty() && g.name.find(m_strSearch) == std::wstring::npos) return false;
+	return true;
+}
+
+void CKucunChaxunView::BuildStateRows()
+{
+	CListUI* pList = FindC<CListUI>(L"kc_cx_list");
+	if (pList == NULL) return;
+
+	std::wstring cat;
+	CComboUI* pCat = FindC<CComboUI>(L"kc_cx_combo_cat");
+	if (pCat) cat = (LPCTSTR)pCat->GetText();
+	ReadSearch(L"kc_cx_search_edit", m_strSearch);
+
+	const std::vector<KcGoods>& all = KcAllGoods();
+	ClearList(pList);
+	int nMatched = 0, nAdded = 0;
+	for (size_t i = 0; i < all.size(); i++)
+	{
+		const KcGoods& g = all[i];
+		int st = KcCxStatus(g.stock, g.safe);
+		if (m_bWarnOnly && st == 0) continue;      // 开关开 = 只要「预警 + 缺货」
+		if (!RowPass(g, cat)) continue;
+		nMatched++;
+		if (nAdded >= KC_PAGE_SIZE) continue;      // 本页已满,只继续统计总数
+
+		CListContainerElementUI* row = NewRow(L"kc_row_cx.xml");
+		if (row == NULL) continue;
+		SetRowText(row, L"col_name", g.name.c_str());
+		SetRowText(row, L"col_cat", g.cat.c_str());
+		SetRowText(row, L"col_unit", g.unit.c_str());
+		SetRowText(row, L"col_cur", std::to_wstring(g.stock).c_str());
+		SetRowText(row, L"col_safe", std::to_wstring(g.safe).c_str());
+
+		const wchar_t* stxt; int stag;
+		if (st == 0) { stxt = L"正常";     stag = KC_TAG_GRN; }
+		else if (st == 1) { stxt = L"预警";   stag = KC_TAG_ORG; }
+		else { stxt = L"缺货";             stag = KC_TAG_RED; }
+		SetTag(row, L"tag_status", stxt, stag);
+
+		pList->Add(row);
+		nAdded++;
+	}
+	SetListCount(L"kc_cx_list_count", nAdded);
+	SetFootPaged(L"kc_cx_list_foot", nAdded, nMatched);
+	FitListHeight(L"kc_cx_list", nAdded);
+}
+
+void CKucunChaxunView::BuildAmtRows()
+{
+	CListUI* pList = FindC<CListUI>(L"kc_cx_amt_list");
+	if (pList == NULL) return;
+
+	std::wstring cat;
+	CComboUI* pCat = FindC<CComboUI>(L"kc_cx_combo_cat");
+	if (pCat) cat = (LPCTSTR)pCat->GetText();
+	ReadSearch(L"kc_cx_search_edit", m_strSearch);
+
+	// 报表口径(设计稿 t9):
+	//   库存成本   = 加权平均成本价 x 当前库存
+	//   预计销售额 = 当前销售价   x 当前库存
+	//   预计利润   = 预计销售额 - 库存成本
+	//   预计利润率 = 预计利润 / 预计销售额
+	const std::vector<KcGoods>& all = KcAllGoods();
+	ClearList(pList);
+	int nMatched = 0, nAdded = 0;
+	for (size_t i = 0; i < all.size(); i++)
+	{
+		const KcGoods& g = all[i];
+		if (!RowPass(g, cat)) continue;
+		nMatched++;
+		if (nAdded >= KC_PAGE_SIZE) continue;
+
+		CListContainerElementUI* row = NewRow(L"kc_row_cx_amt.xml");
+		if (row == NULL) continue;
+		double cost = g.avgCost * g.stock;
+		double amt = g.salePrice * g.stock;
+		double profit = amt - cost;
+
+		SetRowText(row, L"col_name", g.name.c_str());
+		SetTag(row, L"tag_mode", g.fixedCost ? L"固定价" : L"加权平均",
+			g.fixedCost ? KC_TAG_GRAY : KC_TAG_BLUE);
+		SetRowText(row, L"col_in", KcFormatMoney(g.inPrice).c_str());
+		SetRowText(row, L"col_avg", KcFormatMoney(g.avgCost).c_str());
+		SetRowText(row, L"col_cur", std::to_wstring(g.stock).c_str());
+		SetRowText(row, L"col_unit", g.unit.c_str());
+		SetRowText(row, L"col_cost", KcFormatMoney(cost).c_str());
+		SetRowText(row, L"col_sale", KcFormatMoney(g.salePrice).c_str());
+		SetRowText(row, L"col_amt", KcFormatMoney(amt).c_str());
+		SetRowText(row, L"col_profit", KcFormatMoney(profit).c_str());
+		wchar_t buf[32];
+		swprintf_s(buf, _countof(buf), L"%.1f%%", amt > 0.0 ? profit * 100.0 / amt : 0.0);
+		SetRowText(row, L"col_rate", buf);
+
+		pList->Add(row);
+		nAdded++;
+	}
+	SetListCount(L"kc_cx_amt_count", nAdded);
+	SetFootPaged(L"kc_cx_amt_foot", nAdded, nMatched);
+	FitListHeight(L"kc_cx_amt_list", nAdded);
+}
+
+void CKucunChaxunView::OnClick(TNotifyUI& msg)
+{
+	CDuiString name = msg.pSender->GetName();
+	if (name == L"kc_cx_seg_state") { SetSeg(0, true); }
+	else if (name == L"kc_cx_seg_amt") { SetSeg(1, true); }
+	else if (name == L"kc_cx_warn_switch")
+	{
+		m_bWarnOnly = !m_bWarnOnly;
+		ApplyWarnSwitch();
+		BuildStateRows();
+	}
+}
+
+void CKucunChaxunView::OnItemSelect(TNotifyUI& msg)
+{
+	CDuiString name = msg.pSender->GetName();
+	if (name == L"kc_cx_combo_cat")
+	{
+		if (m_nSeg == 0) BuildStateRows();
+		else BuildAmtRows();
+	}
+}
+
+void CKucunChaxunView::OnTextChanged(TNotifyUI& msg)
+{
+	CDuiString name = msg.pSender->GetName();
+	if (name != L"kc_cx_search_edit") return;
+	SyncSearchTishi(L"kc_cx_search_tishi", L"kc_cx_search_edit");
+	if (m_nSeg == 0) BuildStateRows();
+	else BuildAmtRows();
+}
+
+// ============================ 视图2:入库 ============================
+// 记录态工具条:[全部类型 下拉] ...... [新建入库单]
+// 统计态工具条:[本月 时段] [搜索] [全部分类] ...... [新建入库单]
+// 两态共用同一行 —— HorizontalLayout 会跳过不可见子项,所以只用一份控件 + 一个按钮。
+void CKucunRukuView::OnInitControl()
+{
+	CComboUI* pRange = FindC<CComboUI>(L"kc_rk_combo_range");
+	if (pRange)
+	{
+		AddComboItem(pRange, L"本月"); AddComboItem(pRange, L"上月"); AddComboItem(pRange, L"最近三个月");
+		SelectCombo(pRange, 0);
+	}
+	CComboUI* pType = FindC<CComboUI>(L"kc_rk_combo_type");
+	if (pType)
+	{
+		AddComboItem(pType, L"全部类型"); AddComboItem(pType, L"采购入库");
+		AddComboItem(pType, L"调拨入库"); AddComboItem(pType, L"退货入库");
+		SelectCombo(pType, 0);
+	}
+	CComboUI* pCat = FindC<CComboUI>(L"kc_rk_combo_cat");
+	if (pCat)
+	{
+		AddComboItem(pCat, L"全部分类");
+		for (int i = 0; i < 6; i++) AddComboItem(pCat, KC_CATS[i]);
+		SelectCombo(pCat, 0);
+	}
+	SetSeg(0, false);
+}
+
+
+void CKucunRukuView::InitShow()
+{
+	int nNum = g_rk_n, nGoods = 0, nReturn = 0;
+	double dAmount = 0.0;
+	for (int i = 0; i < g_rk_n; i++)
+	{
+		dAmount += g_rk[i].amount;
+		nGoods += g_rk[i].goods;
+		if (g_rk[i].type == L"退货入库") nReturn++;
+	}
+	SetStatInt(L"kc_rk_stat_num", nNum, L"单");
+	SetStatMoney(L"kc_rk_stat_amount", dAmount, L"元");
+	SetStatInt(L"kc_rk_stat_goods", nGoods, L"项");
+	SetStatInt(L"kc_rk_stat_return", nReturn, L"单");
+
+	CEditUI* pEdit = FindC<CEditUI>(L"kc_rk_search_edit");
+	if (pEdit) pEdit->SetText(L"");
+	m_strSearch.clear();
+	SyncSearchTishi(L"kc_rk_search_tishi", L"kc_rk_search_edit");
+	SetSeg(m_nSeg, true);
+}
+
+void CKucunRukuView::SetSeg(int active, bool bBuild)
+{
+	m_nSeg = active;
+	StyleSeg(FindC<CButtonUI>(L"kc_rk_seg_record"), active == 0);
+	StyleSeg(FindC<CButtonUI>(L"kc_rk_seg_stat"), active == 1);
+
+	// 时段筛选与搜索、分类下拉只在统计态出现(设计稿:记录列表不做搜索框、不做时段筛选)
+	CControlUI* pRange = Find(L"kc_rk_combo_range");
+	if (pRange) pRange->SetVisible(active == 1);
+	CControlUI* pSearch = Find(L"kc_rk_search_box");
+	if (pSearch) pSearch->SetVisible(active == 1);
+	CControlUI* pCat = Find(L"kc_rk_combo_cat");
+	if (pCat) pCat->SetVisible(active == 1);
+	CControlUI* pType = Find(L"kc_rk_combo_type");
+	if (pType) pType->SetVisible(active == 0);
+
+	CControlUI* pBodyRec = Find(L"kc_rk_body_record");
+	CControlUI* pBodyStat = Find(L"kc_rk_body_stat");
+	if (pBodyRec) pBodyRec->SetVisible(active == 0);
+	if (pBodyStat) pBodyStat->SetVisible(active == 1);
+
+	KcSyncNativeEditsIn(pSearch);   // 含原生 Edit:显隐后必须手工催一次 SetPos
+
+	if (bBuild) { if (active == 0) BuildRecordRows(); else BuildStatRows(); }
+}
+
+void CKucunRukuView::BuildRecordRows()
+{
+	CListUI* pList = FindC<CListUI>(L"kc_rk_list");
+	if (pList == NULL) return;
+	std::wstring t;
+	CComboUI* pType = FindC<CComboUI>(L"kc_rk_combo_type");
+	if (pType) t = (LPCTSTR)pType->GetText();
+	bool all = (t.empty() || t == L"全部类型");
+
+	ClearList(pList);
+	int nMatched = 0, nAdded = 0;
+	for (int i = 0; i < g_rk_n; i++)
+	{
+		if (!all && g_rk[i].type != t) continue;
+		nMatched++;
+		if (nAdded >= KC_PAGE_SIZE) continue;
+
+		CListContainerElementUI* row = NewRow(L"kc_row_rk.xml");
+		if (row == NULL) continue;
+		SetRowText(row, L"col_no", g_rk[i].no.c_str());
+		SetTag(row, L"tag_type", g_rk[i].type.c_str(),
+			g_rk[i].type == L"采购入库" ? KC_TAG_GRN
+			: (g_rk[i].type == L"调拨入库" ? KC_TAG_BLUE : KC_TAG_ORG));
+		SetRowText(row, L"col_goods", std::to_wstring(g_rk[i].goods).c_str());
+		SetRowText(row, L"col_amount", KcFormatMoney(g_rk[i].amount).c_str());
+		SetRowText(row, L"col_handler", g_rk[i].handler.c_str());
+		SetTag(row, L"tag_status", g_rk[i].status == 0 ? L"已入库" : L"待入库",
+			g_rk[i].status == 0 ? KC_TAG_GRN : KC_TAG_ORG);
+
+		pList->Add(row);
+		nAdded++;
+	}
+	SetListCount(L"kc_rk_list_count", nAdded);
+	SetFootRecord(L"kc_rk_list_foot", nAdded, nMatched);
+	FitListHeight(L"kc_rk_list", nAdded);
+}
+
+void CKucunRukuView::BuildStatRows()
+{
+	CListUI* pList = FindC<CListUI>(L"kc_rk_list_stat");
+	if (pList == NULL) return;
+
+	std::wstring cat;
+	CComboUI* pCat = FindC<CComboUI>(L"kc_rk_combo_cat");
+	if (pCat) cat = (LPCTSTR)pCat->GetText();
+	ReadSearch(L"kc_rk_search_edit", m_strSearch);
+
+	// 占比分母 = 未过滤的入库总金额(设计稿:占比 = 该商品金额 / 入库总金额)
+	double total = 0.0;
+	for (int i = 0; i < g_rk_stat_n; i++) total += g_rk_stat[i].amount;
+
+	ClearList(pList);
+	int nAdded = 0;
+	for (int i = 0; i < g_rk_stat_n; i++)
+	{
+		const KcRkStat& it = g_rk_stat[i];
+		if (!cat.empty() && cat != L"全部分类" && it.cat != cat) continue;
+		if (!m_strSearch.empty() && it.name.find(m_strSearch) == std::wstring::npos) continue;
+
+		CListContainerElementUI* row = NewRow(L"kc_row_rk_stat.xml");
+		if (row == NULL) continue;
+		SetRowText(row, L"col_name", it.name.c_str());
+		SetRowText(row, L"col_cat", it.cat.c_str());
+		SetRowText(row, L"col_unit", it.unit.c_str());
+		SetRowText(row, L"col_cnt", std::to_wstring(it.cnt).c_str());
+		// 入库数量列设计稿带单位("60 桶")
+		SetRowText(row, L"col_qty", (std::to_wstring(it.qty) + L" " + it.unit).c_str());
+		SetRowText(row, L"col_amount", KcFormatMoney(it.amount).c_str());
+
+		double pct = total > 0.0 ? it.amount * 100.0 / total : 0.0;
+		int fillw = (int)(120.0 * pct / 100.0 + 0.5);
+		if (fillw > 120) fillw = 120;
+		if (fillw < 0) fillw = 0;
+		SetRowWidth(row, L"bar_fill", fillw);
+		wchar_t buf[32];
+		swprintf_s(buf, _countof(buf), L"%.0f%%", pct);
+		SetRowText(row, L"bar_pct", buf);
+
+		pList->Add(row);
+		nAdded++;
+	}
+	SetListCount(L"kc_rk_stat_count", nAdded);
+	SetFootAll(L"kc_rk_stat_foot", nAdded);
+	FitListHeight(L"kc_rk_list_stat", nAdded);
+}
+
+void CKucunRukuView::OnClick(TNotifyUI& msg)
+{
+	CDuiString name = msg.pSender->GetName();
+	if (name == L"kc_rk_seg_record") SetSeg(0, true);
+	else if (name == L"kc_rk_seg_stat") SetSeg(1, true);
+}
+
+void CKucunRukuView::OnItemSelect(TNotifyUI& msg)
+{
+	CDuiString name = msg.pSender->GetName();
+	if (m_nSeg == 0)
+	{
+		if (name == L"kc_rk_combo_type") BuildRecordRows();
+	}
+	else
+	{
+		// 时段下拉目前只切文案:占位数据没有日期字段,等接口联调后接真实筛选
+		if (name == L"kc_rk_combo_range") BuildStatRows();
+		else if (name == L"kc_rk_combo_cat") BuildStatRows();
+	}
+}
+
+void CKucunRukuView::OnTextChanged(TNotifyUI& msg)
+{
+	if (m_nSeg != 1) return;
+	if (msg.pSender->GetName() != CDuiString(L"kc_rk_search_edit")) return;
+	SyncSearchTishi(L"kc_rk_search_tishi", L"kc_rk_search_edit");
+	BuildStatRows();
+}
+
+// ============================ 视图3:出库 ============================
+void CKucunChukuView::OnInitControl()
+{
+	CComboUI* pRange = FindC<CComboUI>(L"kc_ck_combo_range");
+	if (pRange)
+	{
+		AddComboItem(pRange, L"本月"); AddComboItem(pRange, L"上月"); AddComboItem(pRange, L"最近三个月");
+		SelectCombo(pRange, 0);
+	}
+	CComboUI* pType = FindC<CComboUI>(L"kc_ck_combo_type");
+	if (pType)
+	{
+		AddComboItem(pType, L"全部类型"); AddComboItem(pType, L"调拨出库");
+		AddComboItem(pType, L"报损"); AddComboItem(pType, L"采购退货");
+		SelectCombo(pType, 0);
+	}
+	CComboUI* pCat = FindC<CComboUI>(L"kc_ck_combo_cat");
+	if (pCat)
+	{
+		AddComboItem(pCat, L"全部分类");
+		for (int i = 0; i < 6; i++) AddComboItem(pCat, KC_CATS[i]);
+		SelectCombo(pCat, 0);
+	}
+	SetSeg(0, false);
+}
+
+void CKucunChukuView::InitShow()
+{
+	int nNum = g_ck_n, nGoods = 0;
+	double dAmount = 0.0, dLoss = 0.0;
+	for (int i = 0; i < g_ck_n; i++)
+	{
+		dAmount += g_ck[i].amount;
+		nGoods += g_ck[i].goods;
+		if (g_ck[i].type == L"报损") dLoss += g_ck[i].amount;
+	}
+	SetStatInt(L"kc_ck_stat_num", nNum, L"单");
+	SetStatMoney(L"kc_ck_stat_amount", dAmount, L"元");
+	SetStatMoney(L"kc_ck_stat_loss", dLoss, L"元");
+	SetStatInt(L"kc_ck_stat_goods", nGoods, L"项");
+
+	CEditUI* pEdit = FindC<CEditUI>(L"kc_ck_search_edit");
+	if (pEdit) pEdit->SetText(L"");
+	m_strSearch.clear();
+	SyncSearchTishi(L"kc_ck_search_tishi", L"kc_ck_search_edit");
+	SetSeg(m_nSeg, true);
+}
+
+void CKucunChukuView::SetSeg(int active, bool bBuild)
+{
+	m_nSeg = active;
+	StyleSeg(FindC<CButtonUI>(L"kc_ck_seg_record"), active == 0);
+	StyleSeg(FindC<CButtonUI>(L"kc_ck_seg_stat"), active == 1);
+
+	CControlUI* pRange = Find(L"kc_ck_combo_range");
+	if (pRange) pRange->SetVisible(active == 1);
+	CControlUI* pSearch = Find(L"kc_ck_search_box");
+	if (pSearch) pSearch->SetVisible(active == 1);
+	CControlUI* pCat = Find(L"kc_ck_combo_cat");
+	if (pCat) pCat->SetVisible(active == 1);
+	CControlUI* pType = Find(L"kc_ck_combo_type");
+	if (pType) pType->SetVisible(active == 0);
+
+	CControlUI* pBodyRec = Find(L"kc_ck_body_record");
+	CControlUI* pBodyStat = Find(L"kc_ck_body_stat");
+	if (pBodyRec) pBodyRec->SetVisible(active == 0);
+	if (pBodyStat) pBodyStat->SetVisible(active == 1);
+
+	KcSyncNativeEditsIn(pSearch);
+
+	if (bBuild) { if (active == 0) BuildRecordRows(); else BuildStatRows(); }
+}
+
+void CKucunChukuView::BuildRecordRows()
+{
+	CListUI* pList = FindC<CListUI>(L"kc_ck_list");
+	if (pList == NULL) return;
+	std::wstring t;
+	CComboUI* pType = FindC<CComboUI>(L"kc_ck_combo_type");
+	if (pType) t = (LPCTSTR)pType->GetText();
+	bool all = (t.empty() || t == L"全部类型");
+
+	ClearList(pList);
+	int nMatched = 0, nAdded = 0;
+	for (int i = 0; i < g_ck_n; i++)
+	{
+		if (!all && g_ck[i].type != t) continue;
+		nMatched++;
+		if (nAdded >= KC_PAGE_SIZE) continue;
+
+		CListContainerElementUI* row = NewRow(L"kc_row_ck.xml");
+		if (row == NULL) continue;
+		SetRowText(row, L"col_no", g_ck[i].no.c_str());
+		SetTag(row, L"tag_type", g_ck[i].type.c_str(),
+			g_ck[i].type == L"调拨出库" ? KC_TAG_BLUE
+			: (g_ck[i].type == L"报损" ? KC_TAG_RED : KC_TAG_ORG));
+		SetRowText(row, L"col_goods", std::to_wstring(g_ck[i].goods).c_str());
+		SetRowText(row, L"col_amount", KcFormatMoney(g_ck[i].amount).c_str());
+		SetRowText(row, L"col_handler", g_ck[i].handler.c_str());
+		SetTag(row, L"tag_status", g_ck[i].status == 0 ? L"已出库" : L"待出库",
+			g_ck[i].status == 0 ? KC_TAG_GRN : KC_TAG_ORG);
+
+		pList->Add(row);
+		nAdded++;
+	}
+	SetListCount(L"kc_ck_list_count", nAdded);
+	SetFootRecord(L"kc_ck_list_foot", nAdded, nMatched);
+	FitListHeight(L"kc_ck_list", nAdded);
+}
+
+void CKucunChukuView::BuildStatRows()
+{
+	CListUI* pList = FindC<CListUI>(L"kc_ck_list_stat");
+	if (pList == NULL) return;
+
+	std::wstring cat;
+	CComboUI* pCat = FindC<CComboUI>(L"kc_ck_combo_cat");
+	if (pCat) cat = (LPCTSTR)pCat->GetText();
+	ReadSearch(L"kc_ck_search_edit", m_strSearch);
+
+	double total = 0.0;
+	for (int i = 0; i < g_ck_stat_n; i++) total += g_ck_stat[i].amount;
+
+	ClearList(pList);
+	int nAdded = 0;
+	for (int i = 0; i < g_ck_stat_n; i++)
+	{
+		const KcRkStat& it = g_ck_stat[i];
+		if (!cat.empty() && cat != L"全部分类" && it.cat != cat) continue;
+		if (!m_strSearch.empty() && it.name.find(m_strSearch) == std::wstring::npos) continue;
+
+		CListContainerElementUI* row = NewRow(L"kc_row_ck_stat.xml");
+		if (row == NULL) continue;
+		SetRowText(row, L"col_name", it.name.c_str());
+		SetRowText(row, L"col_cat", it.cat.c_str());
+		SetRowText(row, L"col_unit", it.unit.c_str());
+		SetRowText(row, L"col_cnt", std::to_wstring(it.cnt).c_str());
+		SetRowText(row, L"col_qty", (std::to_wstring(it.qty) + L" " + it.unit).c_str());
+		SetRowText(row, L"col_amount", KcFormatMoney(it.amount).c_str());
+
+		double pct = total > 0.0 ? it.amount * 100.0 / total : 0.0;
+		int fillw = (int)(120.0 * pct / 100.0 + 0.5);
+		if (fillw > 120) fillw = 120;
+		if (fillw < 0) fillw = 0;
+		SetRowWidth(row, L"bar_fill", fillw);
+		wchar_t buf[32];
+		swprintf_s(buf, _countof(buf), L"%.0f%%", pct);
+		SetRowText(row, L"bar_pct", buf);
+
+		pList->Add(row);
+		nAdded++;
+	}
+	SetListCount(L"kc_ck_stat_count", nAdded);
+	SetFootAll(L"kc_ck_stat_foot", nAdded);
+	FitListHeight(L"kc_ck_list_stat", nAdded);
+}
+
+void CKucunChukuView::OnClick(TNotifyUI& msg)
+{
+	CDuiString name = msg.pSender->GetName();
+	if (name == L"kc_ck_seg_record") SetSeg(0, true);
+	else if (name == L"kc_ck_seg_stat") SetSeg(1, true);
+}
+
+void CKucunChukuView::OnItemSelect(TNotifyUI& msg)
+{
+	CDuiString name = msg.pSender->GetName();
+	if (m_nSeg == 0)
+	{
+		if (name == L"kc_ck_combo_type") BuildRecordRows();
+	}
+	else
+	{
+		if (name == L"kc_ck_combo_range") BuildStatRows();
+		else if (name == L"kc_ck_combo_cat") BuildStatRows();
+	}
+}
+
+void CKucunChukuView::OnTextChanged(TNotifyUI& msg)
+{
+	if (m_nSeg != 1) return;
+	if (msg.pSender->GetName() != CDuiString(L"kc_ck_search_edit")) return;
+	SyncSearchTishi(L"kc_ck_search_tishi", L"kc_ck_search_edit");
+	BuildStatRows();
+}
+
+// ============================ 视图4:库存盘点 ============================
+void CKucunPandianView::OnInitControl()
+{
+	CComboUI* pRange = FindC<CComboUI>(L"kc_pd_combo_range");
+	if (pRange)
+	{
+		AddComboItem(pRange, L"本月"); AddComboItem(pRange, L"上月"); AddComboItem(pRange, L"最近三个月");
+		SelectCombo(pRange, 0);
+	}
+	CComboUI* pResult = FindC<CComboUI>(L"kc_pd_combo_result");
+	if (pResult)
+	{
+		AddComboItem(pResult, L"全部结果"); AddComboItem(pResult, L"盘盈");
+		AddComboItem(pResult, L"盘亏"); AddComboItem(pResult, L"无差异");
+		SelectCombo(pResult, 0);
+	}
+	CComboUI* pCat = FindC<CComboUI>(L"kc_pd_combo_cat");
+	if (pCat)
+	{
+		AddComboItem(pCat, L"全部分类");
+		for (int i = 0; i < 6; i++) AddComboItem(pCat, KC_CATS[i]);
+		SelectCombo(pCat, 0);
+	}
+	SetSeg(0, false);
+}
+
+void CKucunPandianView::InitShow()
+{
+	int nNum = g_pd_n, nGain = 0, nLoss = 0;
+	double dAmount = 0.0;
+	for (int i = 0; i < g_pd_n; i++)
+	{
+		nGain += g_pd[i].gain;
+		nLoss += g_pd[i].loss;
+		dAmount += g_pd[i].amount;
+	}
+	SetStatInt(L"kc_pd_stat_num", nNum, L"次");
+	SetStatInt(L"kc_pd_stat_gain", nGain, L"项");
+	SetStatInt(L"kc_pd_stat_loss", nLoss, L"项");
+	SetStatMoney(L"kc_pd_stat_amount", dAmount, L"元");
+
+	CEditUI* pEdit = FindC<CEditUI>(L"kc_pd_search_edit");
+	if (pEdit) pEdit->SetText(L"");
+	m_strSearch.clear();
+	SyncSearchTishi(L"kc_pd_search_tishi", L"kc_pd_search_edit");
+	SetSeg(m_nSeg, true);
+}
+
+void CKucunPandianView::SetSeg(int active, bool bBuild)
+{
+	m_nSeg = active;
+	StyleSeg(FindC<CButtonUI>(L"kc_pd_seg_record"), active == 0);
+	StyleSeg(FindC<CButtonUI>(L"kc_pd_seg_stat"), active == 1);
+
+	CControlUI* pRange = Find(L"kc_pd_combo_range");
+	if (pRange) pRange->SetVisible(active == 1);
+	CControlUI* pSearch = Find(L"kc_pd_search_box");
+	if (pSearch) pSearch->SetVisible(active == 1);
+	CControlUI* pCat = Find(L"kc_pd_combo_cat");
+	if (pCat) pCat->SetVisible(active == 1);
+	CControlUI* pResult = Find(L"kc_pd_combo_result");
+	if (pResult) pResult->SetVisible(active == 0);
+
+	CControlUI* pBodyRec = Find(L"kc_pd_body_record");
+	CControlUI* pBodyStat = Find(L"kc_pd_body_stat");
+	if (pBodyRec) pBodyRec->SetVisible(active == 0);
+	if (pBodyStat) pBodyStat->SetVisible(active == 1);
+
+	KcSyncNativeEditsIn(pSearch);
+
+	if (bBuild) { if (active == 0) BuildRecordRows(); else BuildDiffRows(); }
+}
+
+void CKucunPandianView::BuildRecordRows()
+{
+	CListUI* pList = FindC<CListUI>(L"kc_pd_list");
+	if (pList == NULL) return;
+
+	// 下拉项顺序:全部结果 / 盘盈 / 盘亏 / 无差异  ->  结果码 -1 / 0 / 1 / 2
+	int sel = 0;
+	CComboUI* pResult = FindC<CComboUI>(L"kc_pd_combo_result");
+	if (pResult) sel = pResult->GetCurSel();
+	const int fmap[4] = { -1, 0, 1, 2 };
+	int filter = fmap[(sel >= 0 && sel < 4) ? sel : 0];
+
+	ClearList(pList);
+	int nMatched = 0, nAdded = 0;
+	for (int i = 0; i < g_pd_n; i++)
+	{
+		if (filter >= 0 && g_pd[i].result != filter) continue;
+		nMatched++;
+		if (nAdded >= KC_PAGE_SIZE) continue;
+
+		CListContainerElementUI* row = NewRow(L"kc_row_pd.xml");
+		if (row == NULL) continue;
+		SetRowText(row, L"col_no", g_pd[i].no.c_str());
+		SetRowText(row, L"col_scope", g_pd[i].scope.c_str());
+		SetRowText(row, L"col_goods", std::to_wstring(g_pd[i].goods).c_str());
+		SetRowText(row, L"col_gain", std::to_wstring(g_pd[i].gain).c_str());
+		SetRowText(row, L"col_loss", std::to_wstring(g_pd[i].loss).c_str());
+		SetRowText(row, L"col_amount", KcFormatMoney(g_pd[i].amount).c_str());
+		SetRowText(row, L"col_handler", g_pd[i].handler.c_str());
+
+		// 盘点结果:0 盘盈(蓝) / 1 盘亏(红) / 2 无差异(灰)
+		const wchar_t* rtxt; int rtag;
+		if (g_pd[i].result == 0) { rtxt = L"盘盈";   rtag = KC_TAG_BLUE; }
+		else if (g_pd[i].result == 1) { rtxt = L"盘亏";   rtag = KC_TAG_RED; }
+		else { rtxt = L"无差异"; rtag = KC_TAG_GRAY; }
+		SetTag(row, L"tag_result", rtxt, rtag);
+
+		pList->Add(row);
+		nAdded++;
+	}
+	SetListCount(L"kc_pd_list_count", nAdded);
+	SetFootRecord(L"kc_pd_list_foot", nAdded, nMatched);
+	FitListHeight(L"kc_pd_list", nAdded);
+}
+
+void CKucunPandianView::BuildDiffRows()
+{
+	CListUI* pList = FindC<CListUI>(L"kc_pd_list_stat");
+	if (pList == NULL) return;
+
+	std::wstring cat;
+	CComboUI* pCat = FindC<CComboUI>(L"kc_pd_combo_cat");
+	if (pCat) cat = (LPCTSTR)pCat->GetText();
+	ReadSearch(L"kc_pd_search_edit", m_strSearch);
+
+	ClearList(pList);
+	int nAdded = 0;
+	for (int i = 0; i < g_pd_stat_n; i++)
+	{
+		const KcPdStat& it = g_pd_stat[i];
+		if (!cat.empty() && cat != L"全部分类" && it.cat != cat) continue;
+		if (!m_strSearch.empty() && it.name.find(m_strSearch) == std::wstring::npos) continue;
+
+		CListContainerElementUI* row = NewRow(L"kc_row_pd_stat.xml");
+		if (row == NULL) continue;
+		SetRowText(row, L"col_name", it.name.c_str());
+		SetRowText(row, L"col_cat", it.cat.c_str());
+		SetRowText(row, L"col_unit", it.unit.c_str());
+		SetRowText(row, L"col_cnt", std::to_wstring(it.cnt).c_str());
+		// 差异列带正负号(设计稿 t8 是 "+5" / "-4"),并按正负着色:盈绿亏红
+		wchar_t dbuf[16];
+		swprintf_s(dbuf, _countof(dbuf), L"%+d", it.diff);
+		SetRowText(row, L"col_diff", dbuf);
+		SetRowColor(row, L"col_diff", it.diff > 0 ? KC_COLOR_NORMAL
+			: (it.diff < 0 ? KC_COLOR_LACK : 0xFF1F2329));
+		// 盈亏金额同样带符号(设计稿 t8 是 "+65.00" / "-216.00")
+		std::wstring amt = KcFormatMoney(it.amount);
+		if (it.amount > 0.0) amt = L"+" + amt;
+		SetRowText(row, L"col_amount", amt.c_str());
+
+		const wchar_t* rtxt; int rtag;
+		if (it.diff > 0) { rtxt = L"盘盈"; rtag = KC_TAG_BLUE; }
+		else if (it.diff < 0) { rtxt = L"盘亏"; rtag = KC_TAG_RED; }
+		else { rtxt = L"无差异"; rtag = KC_TAG_GRAY; }
+		SetTag(row, L"tag_result", rtxt, rtag);
+
+		pList->Add(row);
+		nAdded++;
+	}
+	SetListCount(L"kc_pd_stat_count", nAdded);
+	SetFootAll(L"kc_pd_stat_foot", nAdded);
+	FitListHeight(L"kc_pd_list_stat", nAdded);
+}
+
+void CKucunPandianView::OnClick(TNotifyUI& msg)
+{
+	CDuiString name = msg.pSender->GetName();
+	if (name == L"kc_pd_seg_record") SetSeg(0, true);
+	else if (name == L"kc_pd_seg_stat") SetSeg(1, true);
+}
+
+void CKucunPandianView::OnItemSelect(TNotifyUI& msg)
+{
+	CDuiString name = msg.pSender->GetName();
+	if (m_nSeg == 0)
+	{
+		if (name == L"kc_pd_combo_result") BuildRecordRows();
+	}
+	else
+	{
+		if (name == L"kc_pd_combo_range") BuildDiffRows();
+		else if (name == L"kc_pd_combo_cat") BuildDiffRows();
+	}
+}
+
+void CKucunPandianView::OnTextChanged(TNotifyUI& msg)
+{
+	if (m_nSeg != 1) return;
+	if (msg.pSender->GetName() != CDuiString(L"kc_pd_search_edit")) return;
+	SyncSearchTishi(L"kc_pd_search_tishi", L"kc_pd_search_edit");
+	BuildDiffRows();
+}
+
+// ================================================================================
+// 编辑视图基类:新建入库单 / 新建出库单 / 新建盘点单(设计稿 v4 p1~p4 / p6~p8)
+//
+// 三张页在 kucun_page.xml 里是与 kc_view_* 同级的全屏子视图,靠 SetVisible 切换;
+// 明细行落在一个 List 里,可编辑单元格是 Button(点它把页面级键盘面板叫出来)。
+// 键盘面板与本视图不在同一棵子树下(它在页面根容器下),所以 Find 要穿透两个 host。
+// ================================================================================
+
+// 单元格底图三态:默认 input_r8_*;编辑中 btn_r8_green_*;告警(出库超库存)btn_r8_red_*
+static const wchar_t* KC_CELL_N = L"file='input_r8_n.png' corner='8,8,8,8'";
+static const wchar_t* KC_CELL_H = L"file='input_r8_h.png' corner='8,8,8,8'";
+static const wchar_t* KC_CELL_P = L"file='input_r8_n.png' corner='8,8,8,8'";
+static const wchar_t* KC_CELL_EN = L"file='btn_r8_green_n.png' corner='8,8,8,8'";
+static const wchar_t* KC_CELL_EH = L"file='btn_r8_green_h.png' corner='8,8,8,8'";
+static const wchar_t* KC_CELL_EP = L"file='btn_r8_green_p.png' corner='8,8,8,8'";
+static const wchar_t* KC_CELL_WN = L"file='btn_r8_red_n.png' corner='8,8,8,8'";
+static const wchar_t* KC_CELL_WH = L"file='btn_r8_red_h.png' corner='8,8,8,8'";
+static const wchar_t* KC_CELL_WP = L"file='btn_r8_red_p.png' corner='8,8,8,8'";
+
+CControlUI* CKucunEditViewBase::Find(LPCTSTR name)
+{
+	CControlUI* p = CKucunViewBase::Find(name);
+	if (p == NULL && m_pKpHost != NULL) p = m_pKpHost->FindSubControl(name);
+	// 【R49】底栏 kc_new_foot_* 与键盘面板 kc_keypad 是**兄弟**(同挂页面级容器),
+	// 既不在本视图子树里、也不在 kc_keypad 里 ⇒ 再往上一层到共同父级找一次。
+	if (p == NULL && m_pKpHost != NULL)
+	{
+		CContainerUI* pPar = static_cast<CContainerUI*>(m_pKpHost->GetParent());
+		if (pPar != NULL) p = pPar->FindSubControl(name);
+	}
+	return p;
+}
+
+std::wstring CKucunEditViewBase::PrefixW() const
+{
+	std::wstring s = Prefix();
+	return s;
+}
+
+std::wstring CKucunEditViewBase::CellName(LPCWSTR kind, int idx) const
+{
+	std::wstring s = Prefix();
+	s += L"_";
+	s += kind;
+	s += L"_";
+	s += std::to_wstring(idx);
+	return s;
+}
+
+CListUI* CKucunEditViewBase::FindList()
+{
+	return FindC<CListUI>(ListName());
+}
+
+CListContainerElementUI* CKucunEditViewBase::RowAt(int i)
+{
+	CListUI* pList = FindList();
+	if (pList == NULL) return NULL;
+	if (i < 0 || i >= (int)pList->GetCount()) return NULL;
+	return static_cast<CListContainerElementUI*>(pList->GetItemAt(i));
+}
+
+void CKucunEditViewBase::SetCellText(int i, LPCWSTR kind, LPCTSTR text)
+{
+	CButtonUI* p = FindC<CButtonUI>(CellName(kind, i).c_str());
+	if (p != NULL) p->SetText(text);
+}
+
+// 行内只读列(col_book / col_diff / col_amount / col_note):先按行号取到行控件,
+// 再按列名找 Label。行控件必须从 List 现取 —— 名字里没有行号,不能走 Find。
+void CKucunEditViewBase::SetRowLabel(int i, LPCTSTR name, LPCTSTR text, DWORD color)
+{
+	CListContainerElementUI* row = RowAt(i);
+	if (row == NULL) return;
+	CLabelUI* p = static_cast<CLabelUI*>(row->FindSubControl(name));
+	if (p == NULL) return;
+	p->SetText(text);
+	if (color != 0) p->SetTextColor(color);
+}
+
+// 【R48】行内「备注格换成红字提示」:设计稿 p2 第 3 行超库存时,备注格不是输入框而是
+// 一行 12px 红字(<span class="hint">超出可用库存 8 斤</span>)。两个控件互斥显隐。
+// text 传 NULL / 空串 = 恢复输入框。
+void CKucunEditViewBase::SetRowNoteHint(int i, LPCTSTR text)
+{
+	CListContainerElementUI* row = RowAt(i);
+	if (row == NULL) return;
+	bool show = (text != NULL && text[0] != _T('\0'));
+	CLabelUI* pHint = static_cast<CLabelUI*>(row->FindSubControl(L"col_note_hint"));
+	if (pHint != NULL)
+	{
+		if (show) pHint->SetText(text);
+		pHint->SetVisible(show);
+	}
+	CButtonUI* pIn = FindC<CButtonUI>(CellName(L"note", i).c_str());
+	if (pIn != NULL) pIn->SetVisible(!show);
+}
+
+void CKucunEditViewBase::SetLabel(LPCTSTR name, LPCTSTR text, DWORD color)
+{
+	CLabelUI* p = FindC<CLabelUI>(name);
+	if (p == NULL) return;
+	p->SetText(text);
+	if (color != 0) p->SetTextColor(color);
+	// 【R48】合计条改成「静态标签 + 动态值标签」之后,值文本的宽度会变("0" → "145"、"0 项" → "12 项")。
+	// autocalcwidth 只在 EstimateSize 被调用时才算宽度,而 EstimateSize 只在重排时跑;
+	// CLabelUI::SetText 既不置 m_bNeedEstimateSize、也不会触发重排。所以两件事都得补:
+	//   ① SetFont 踢一脚 —— CLabelUI::SetFont 是唯一**无条件**置 m_bNeedEstimateSize 的
+	//      (UILabel.cpp::SetFont,无早退判断),传当前字体号即可;
+	//   ② NeedParentUpdate 让父布局重排一次,否则新文字仍按旧宽度摆放、会被裁掉。
+	p->SetFont(p->GetFont());
+	p->NeedParentUpdate();
+}
+
+// ---------------------------------------------------------------- 构建 / 刷新
+void CKucunEditViewBase::InitShow()
+{
+	CloseKeypad();
+	m_lines.clear();
+	m_headNote.clear();
+	SeedLines();
+
+	// 单据头的「备注」字段(Button 当单元格用)
+	// 【R48】占位文案按页取(设计稿 p1「采购到货,含配送费」/ p2「晚市备料」/ p3「月末盘点」)
+	std::wstring hn = PrefixW() + L"_note";
+	CButtonUI* pNote = FindC<CButtonUI>(hn.c_str());
+	if (pNote != NULL)
+	{
+		pNote->SetText(HeadNotePh());
+		pNote->SetTextColor(0xFFA8ADB3);
+	}
+
+	RefreshAll();
+}
+
+void CKucunEditViewBase::BuildRows()
+{
+	CListUI* pList = FindList();
+	if (pList == NULL) return;
+	ClearList(pList);
+
+	for (int i = 0; i < (int)m_lines.size(); i++)
+	{
+		CListContainerElementUI* row = NewRow(RowXml());
+		if (row == NULL) continue;
+
+		// 模板里的固定控件名 -> 带行号的唯一名,宿主按名反解 (kind, 行号)
+		CControlUI* p = NULL;
+		p = row->FindSubControl(L"cell_qty");
+		if (p != NULL) p->SetName(CellName(L"qty", i).c_str());
+		p = row->FindSubControl(L"cell_price");
+		if (p != NULL) p->SetName(CellName(L"price", i).c_str());
+		p = row->FindSubControl(L"cell_note");
+		if (p != NULL) p->SetName(CellName(L"note", i).c_str());
+		p = row->FindSubControl(L"btn_del");
+		if (p != NULL) p->SetName(CellName(L"del", i).c_str());
+
+		SetRowText(row, L"col_name", m_lines[i].name.c_str());
+		SetRowText(row, L"col_cat", m_lines[i].cat.c_str());
+		SetRowText(row, L"col_unit", m_lines[i].unit.c_str());
+
+		FillReadonly(row, i);       // 只读列:当前库存 / 账面库存 / 备注占位
+		pList->Add(row);
+		RefreshRow(i);              // 可编辑列 + 计算列 + 着色
+	}
+	SyncTableHeight();
+}
+
+void CKucunEditViewBase::RefreshAll()
+{
+	BuildRows();
+	RefreshTot();
+}
+
+// 明细表高度:List = 上下 inset(1+10) + 表头 44 + n * 行高 56;外层卡片 = List 高度。
+// 【R48】卡片换成 kc_tblcard.png("1px 外框 + 43px 表头灰带 + 表头下 1px 分隔线" 一张图烤死),
+// 卡片自己**不再**有上下 inset(原来是 bb_card10 + inset 20,12,20,12 ⇒ CARD_INSET_Y = 24),
+// 表头灰带与底部圆角带都由这张图的 inset="1,1,1,10" 让开 ⇒ 卡片高恒等于 List 高。
+// 【R48】也不再沿父链写死祖先高度:这三个页的滚动主体 kc_*_body 是弹性项、自己管滚动
+// (见 KcPropagateFixedHeightUp 的新停靠条件)。卡片自身必须写死,否则在 body 里会被当弹性项压扁。
+void CKucunEditViewBase::SyncTableHeight()
+{
+	CListUI* pList = FindList();
+	if (pList == NULL) return;
+	const int HEADER_H = 44;
+	const int ROW_H = 56;
+	int rows = (int)m_lines.size();
+	if (rows < 1) rows = 1;
+	RECT rcLi = pList->GetInset();
+	int lh = rcLi.top + rcLi.bottom + HEADER_H + rows * ROW_H;
+	pList->SetFixedHeight(lh);
+	CControlUI* pCard = Find(TblCardName());
+	if (pCard != NULL) pCard->SetFixedHeight(lh);
+
+	// 【R48】行底边线由行模板的 bordersize="0,0,0,1" 自己提供(设计稿 .tr{border-bottom:1px
+	// solid var(--line)},实测每条明细行底边确有一条 #E8EAED)。但**最后一行不能有**:
+	// 它离表格卡的下边框只隔 10px 圆角带,两条线会并排出现
+	// (设计稿 .tr:last-child{border-bottom:none})。做法与记录表的 FitListHeight 一致。
+	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);
+		}
+	}
+}
+
+void CKucunEditViewBase::ApplyCellStyle(int i, int col)
+{
+	LPCWSTR kind = (col == KC_ECOL_QTY) ? L"qty" : ((col == KC_ECOL_PRICE) ? L"price" : L"note");
+	CButtonUI* p = FindC<CButtonUI>(CellName(kind, i).c_str());
+	if (p == NULL) return;
+
+	bool bEditing = (m_nEditRow == i && m_nEditCol == col);
+	bool bWarn = (col == KC_ECOL_QTY) && IsQtyWarn(i);
+	bool bPh = (!bEditing) && IsCellPlaceholder(i, col);
+
+	const wchar_t* n = KC_CELL_N; const wchar_t* h = KC_CELL_H; const wchar_t* pu = KC_CELL_P;
+	DWORD tc = 0xFF1F2329;
+	if (bEditing) { n = KC_CELL_EN; h = KC_CELL_EH; pu = KC_CELL_EP; tc = 0xFF2E9B5C; }
+	else if (bWarn) { n = KC_CELL_WN; h = KC_CELL_WH; pu = KC_CELL_WP; tc = 0xFFE14B4A; }
+	else if (bPh) { tc = 0xFFA8ADB3; }
+
+	p->SetNormalImage(n);
+	p->SetHotImage(h);
+	p->SetPushedImage(pu);
+	p->SetTextColor(tc);
+}
+
+// ---------------------------------------------------------------- 键盘面板
+void CKucunEditViewBase::OpenKeypad(int row, int col)
+{
+	m_nEditRow = row;
+	m_nEditCol = col;
+
+	if (row < 0) m_editBuf = m_headNote;
+	else if (col == KC_ECOL_QTY) m_editBuf = m_lines[row].qty;
+	else if (col == KC_ECOL_PRICE) m_editBuf = m_lines[row].price;
+	else m_editBuf = m_lines[row].note;
+
+	KeypadShow(col == KC_ECOL_NOTE);
+	KeypadRefresh();
+
+	CControlUI* pKp = Find(L"kc_keypad");
+	if (pKp != NULL) pKp->SetVisible(true);
+
+	for (int i = 0; i < (int)m_lines.size(); i++)
+	{
+		ApplyCellStyle(i, KC_ECOL_QTY);
+		ApplyCellStyle(i, KC_ECOL_PRICE);
+		ApplyCellStyle(i, KC_ECOL_NOTE);
+	}
+}
+
+void CKucunEditViewBase::KeypadShow(bool bText)
+{
+	CControlUI* pPad = Find(L"kc_kp_pad");
+	CControlUI* pTxt = Find(L"kc_kp_txt");
+	if (pPad != NULL) pPad->SetVisible(!bText);
+	if (pTxt != NULL) pTxt->SetVisible(bText);
+
+	// 【R49】设计稿 p6 底栏:数字键盘态换成键盘说明,文本态 / 收起时还原本页原文案。
+	SyncFootTip(!bText);
+
+	if (bText)
+	{
+		CEditUI* pEdit = FindC<CEditUI>(L"kc_kp_edit");
+		if (pEdit != NULL)
+		{
+			pEdit->SetText(m_editBuf.c_str());
+			pEdit->SetFocus();
+		}
+	}
+}
+
+void CKucunEditViewBase::KeypadRefresh()
+{
+	std::wstring field;
+	std::wstring unit;
+
+	if (m_nEditRow < 0) field = L"备注";
+	else
+	{
+		field = m_lines[m_nEditRow].name;
+		field += L" · ";
+		// 【R49】数量列的字段名按页面给(入库数量 / 出库数量 / 实盘数量),见 QtyColLabel。
+		field += (m_nEditCol == KC_ECOL_QTY) ? QtyColLabel()
+			: ((m_nEditCol == KC_ECOL_PRICE) ? L"单价" : L"备注");
+		// 【R49】设计稿 p6 左栏:数值后跟一个 16px 灰的小号单位(「80 斤」)。
+		// 只有数量列有单位;单价列是「元」不显示(设计稿同)、备注列是文字。
+		if (m_nEditCol == KC_ECOL_QTY) unit = m_lines[m_nEditRow].unit;
+	}
+
+	SetLabel(L"kc_kp_field", field.c_str(), 0);
+	SetLabel(L"kc_kp_txtfield", field.c_str(), 0);
+	SetLabel(L"kc_kp_value", m_editBuf.empty() ? L"0" : m_editBuf.c_str(), 0);
+
+	std::wstring unitTxt;
+	if (!unit.empty())
+	{
+		unitTxt = L" ";                     // 与数值之间留一个空格(设计稿:80 斤)
+		unitTxt += unit;
+	}
+	SetLabel(L"kc_kp_unit", unitTxt.c_str(), 0);
+}
+
+// 【R49】键盘态底栏提示:原始文案从 XML 现场记一次,不在 C++ 里复制一份,
+// 免得以后改 XML 文案时两边对不上。
+CLabelUI* CKucunEditViewBase::FootTipLabel()
+{
+	std::wstring nm = PrefixW();
+	nm += L"_foot_tip";
+	return FindC<CLabelUI>(nm.c_str());
+}
+
+void CKucunEditViewBase::SyncFootTip(bool bKeypad)
+{
+	CLabelUI* p = FootTipLabel();
+	if (p == NULL) return;
+
+	if (m_footTipDefault.empty()) m_footTipDefault = (LPCTSTR)p->GetText();
+
+	p->SetText(bKeypad ? L"数字键盘仅用于数量 / 单价输入;确认后回到明细表"
+		: m_footTipDefault.c_str());
+	// autocalcwidth 的 Label 换文案后必须踢 SetFont 再让父级重排一次(同 SetLabel 的注释)
+	p->SetFont(p->GetFont());
+	p->NeedParentUpdate();
+}
+
+void CKucunEditViewBase::KpDigit(LPCWSTR t)
+{
+	if (m_editBuf == L"0") m_editBuf.clear();
+	if (m_editBuf.size() + wcslen(t) > 12) return;
+	m_editBuf += t;
+	KeypadRefresh();
+}
+
+void CKucunEditViewBase::KpDot()
+{
+	if (m_nEditCol != KC_ECOL_PRICE) return;                  // 只有单价允许小数
+	if (m_editBuf.find(L'.') != std::wstring::npos) return;
+	if (m_editBuf.empty()) m_editBuf = L"0";
+	m_editBuf += L".";
+	KeypadRefresh();
+}
+
+void CKucunEditViewBase::KpDel()
+{
+	if (!m_editBuf.empty()) m_editBuf.erase(m_editBuf.size() - 1);
+	KeypadRefresh();
+}
+
+void CKucunEditViewBase::KpClear()
+{
+	m_editBuf.clear();
+	KeypadRefresh();
+}
+
+void CKucunEditViewBase::KpCommit()
+{
+	CEditUI* pEdit = FindC<CEditUI>(L"kc_kp_edit");
+
+	if (m_nEditRow < 0)
+	{
+		// 单据头备注
+		if (pEdit != NULL) m_headNote = (LPCTSTR)pEdit->GetText();
+		std::wstring hn = PrefixW() + L"_note";
+		CButtonUI* pNote = FindC<CButtonUI>(hn.c_str());
+		if (pNote != NULL)
+		{
+			if (m_headNote.empty())
+			{
+				pNote->SetText(HeadNotePh());
+				pNote->SetTextColor(0xFFA8ADB3);
+			}
+			else
+			{
+				pNote->SetText(m_headNote.c_str());
+				pNote->SetTextColor(0xFF1F2329);
+			}
+		}
+		CloseKeypad();
+		return;
+	}
+
+	if (m_nEditCol == KC_ECOL_NOTE)
+	{
+		if (pEdit != NULL) m_editBuf = (LPCTSTR)pEdit->GetText();
+		m_lines[m_nEditRow].note = m_editBuf;
+		SetCellText(m_nEditRow, L"note", m_editBuf.c_str());
+		CloseKeypad();
+		return;
+	}
+
+	if (m_nEditCol == KC_ECOL_QTY) m_lines[m_nEditRow].qty = m_editBuf;
+	else m_lines[m_nEditRow].price = m_editBuf;
+
+	LPCWSTR kind = (m_nEditCol == KC_ECOL_QTY) ? L"qty" : L"price";
+	SetCellText(m_nEditRow, kind, m_editBuf.c_str());
+
+	int row = m_nEditRow;
+	CloseKeypad();          // 内部会把所有单元格的样式复位
+	RefreshRow(row);        // 复位之后再按最新数据着色(告警 / 占位)
+	RefreshTot();
+}
+
+void CKucunEditViewBase::CloseKeypad()
+{
+	m_nEditRow = -1;
+	m_editBuf.clear();
+
+	CControlUI* pKp = Find(L"kc_keypad");
+	if (pKp != NULL) pKp->SetVisible(false);
+	// 键盘的文本面板里有原生 Edit:容器隐下去之后必须催一次 SetPos,
+	// 否则它会孤零零留在屏幕上(原因见 CKucunViews.h 里 KcSyncNativeEdit 的注释)。
+	if (pKp != NULL) KcSyncNativeEditsIn(pKp);
+
+	SyncFootTip(false);	// 【R49】收起键盘 ⇔ 底栏提示还原
+
+	for (int i = 0; i < (int)m_lines.size(); i++)
+	{
+		ApplyCellStyle(i, KC_ECOL_QTY);
+		ApplyCellStyle(i, KC_ECOL_PRICE);
+		ApplyCellStyle(i, KC_ECOL_NOTE);
+	}
+}
+
+// ---------------------------------------------------------------- 事件
+void CKucunEditViewBase::OnClick(TNotifyUI& msg)
+{
+	std::wstring n = (LPCTSTR)msg.pSender->GetName();
+
+	// ---- 键盘面板(与子视图同级,由 CKucunPageUI 转发过来) ----
+	if (n.size() >= 6 && n.compare(0, 6, L"kc_kp_") == 0)
+	{
+		if (n == L"kc_kp_del") KpDel();
+		else if (n == L"kc_kp_clr") KpClear();
+		else if (n == L"kc_kp_ok") KpCommit();
+		else if (n == L"kc_kp_txtcancel") CloseKeypad();	// 「关闭」键已按设计稿删除(第 4 列只剩 删除 / 清除 / 确认)
+		else if (n == L"kc_kp_txtok") KpCommit();
+		else if (n == L"kc_kp_kdot") KpDot();
+		else if (n.compare(0, 7, L"kc_kp_k") == 0) KpDigit(n.substr(7).c_str());
+		return;
+	}
+
+	// ---- 本视图的单元格 / 行内按钮 ----
+	std::wstring pfx = PrefixW();
+	if (n.size() <= pfx.size() || n.compare(0, pfx.size(), pfx) != 0) return;
+	std::wstring tail = n.substr(pfx.size());          // 例:"_qty_3"
+
+	if (tail == L"_note") { OpenKeypad(-1, KC_ECOL_NOTE); return; }   // 单据头备注
+	if (tail.size() < 4 || tail[0] != L'_') return;
+
+	std::wstring::size_type p = tail.rfind(L'_');
+	if (p == std::wstring::npos || p == 0) return;
+	std::wstring kind = tail.substr(1, p - 1);
+	int idx = _wtoi(tail.c_str() + p + 1);
+	if (idx < 0 || idx >= (int)m_lines.size()) return;
+
+	if (kind == L"qty") OpenKeypad(idx, KC_ECOL_QTY);
+	else if (kind == L"price") OpenKeypad(idx, KC_ECOL_PRICE);
+	else if (kind == L"note") OpenKeypad(idx, KC_ECOL_NOTE);
+	else if (kind == L"del")
+	{
+		CloseKeypad();
+		m_lines.erase(m_lines.begin() + idx);
+		RefreshAll();
+	}
+}
+
+void CKucunEditViewBase::OnItemSelect(TNotifyUI& msg)
+{
+	// 单据头下拉:切换类型 / 范围只改显示,不改明细(占位实现)
+	(void)msg;
+}
+
+// ---------------------------------------------------------------- 与「添加商品」弹层对接
+void CKucunEditViewBase::AppendPicked(const std::vector<std::wstring>& names)
+{
+	std::vector<KcEditLine> added;
+
+	for (size_t k = 0; k < names.size(); k++)
+	{
+		KcGoods g;
+		if (!KcLookupGoods(names[k], g)) continue;
+
+		if (!ReplaceOnPick())
+		{
+			bool dup = false;
+			for (size_t i = 0; i < m_lines.size(); i++)
+			{
+				if (m_lines[i].name == g.name) { dup = true; break; }
+			}
+			if (dup) continue;      // 已在明细里的商品跳过
+		}
+
+		KcEditLine ln;
+		ln.name = g.name;
+		ln.cat = g.cat;
+		ln.unit = g.unit;
+		ln.book = g.stock;
+		OnLineAdded(ln);
+		added.push_back(ln);
+	}
+
+	if (ReplaceOnPick())
+	{
+		if (added.empty()) return;      // 没勾任何商品 ⇒ 保留原范围
+		m_lines = added;
+	}
+	else
+	{
+		for (size_t i = 0; i < added.size(); i++) m_lines.push_back(added[i]);
+	}
+
+	CloseKeypad();
+	RefreshAll();
+}
+
+// ============================ 子视图 A:新建入库单 ============================
+void CKucunRkNewView::OnInitControl()
+{
+	CComboUI* p = FindC<CComboUI>(L"kc_rkn_combo_type");
+	if (p != NULL)
+	{
+		AddComboItem(p, L"采购入库");
+		AddComboItem(p, L"调拨入库");
+		AddComboItem(p, L"退货入库");
+		SelectCombo(p, 0);
+	}
+}
+
+void CKucunRkNewView::SeedLines()
+{
+	// 设计稿 v4 p1:大米 80 x 3.20 / 食用油 25 x 86.00 / 生抽 40 x 15.00
+	static const wchar_t* nm[3] = { L"大米", L"食用油", L"生抽" };
+	static const wchar_t* qt[3] = { L"80", L"25", L"40" };
+	static const wchar_t* pr[3] = { L"3.20", L"86.00", L"15.00" };
+	for (int i = 0; i < 3; i++)
+	{
+		KcGoods g;
+		if (!KcLookupGoods(nm[i], g)) continue;
+		KcEditLine ln;
+		ln.name = g.name; ln.cat = g.cat; ln.unit = g.unit; ln.book = g.stock;
+		ln.qty = qt[i]; ln.price = pr[i];
+		m_lines.push_back(ln);
+	}
+}
+
+void CKucunRkNewView::OnLineAdded(KcEditLine& line)
+{
+	line.qty = L"1";
+	KcGoods g;
+	if (KcLookupGoods(line.name, g)) line.price = KcFormatMoney(g.price);
+}
+
+void CKucunRkNewView::FillReadonly(CListContainerElementUI* row, int i)
+{
+	(void)row; (void)i;      // 入库明细没有只读数值列
+}
+
+void CKucunRkNewView::RefreshRow(int i)
+{
+	if (i < 0 || i >= (int)m_lines.size()) return;
+	const KcEditLine& ln = m_lines[i];
+
+	SetCellText(i, L"qty", ln.qty.c_str());
+	SetCellText(i, L"price", ln.price.c_str());
+
+	double q = ln.qty.empty() ? 0.0 : _wtof(ln.qty.c_str());
+	double p = ln.price.empty() ? 0.0 : _wtof(ln.price.c_str());
+	// 【R48】设计稿 p1 表内金额列是**纯数字、深色、不带 ¥**(.td.num{color:var(--t1)}):
+	// 金额的货币符号只在合计条上出现一次。旧实现是绿色 + "¥" 前缀,一并去掉。
+	SetRowLabel(i, L"col_amount", KcFormatMoney(q * p).c_str());
+
+	ApplyCellStyle(i, KC_ECOL_QTY);
+	ApplyCellStyle(i, KC_ECOL_PRICE);
+}
+
+void CKucunRkNewView::RefreshTot()
+{
+	int n = (int)m_lines.size();
+	double q = 0.0, amt = 0.0;
+	for (int i = 0; i < n; i++)
+	{
+		double qq = m_lines[i].qty.empty() ? 0.0 : _wtof(m_lines[i].qty.c_str());
+		double pp = m_lines[i].price.empty() ? 0.0 : _wtof(m_lines[i].price.c_str());
+		q += qq;
+		amt += qq * pp;
+	}
+
+	// 【R48】设计稿 p1 合计条是「静态标签 + 动态值」两组:
+	//   合计商品 [3 项]   入库总数 [145]            →右侧→   入库金额 ¥3,006.00
+	// 标签("合计商品" / "入库总数" / "入库金额")已经写死在 kucun_page.xml 里,
+	// 这里只写值,别再拼整句。
+	wchar_t buf[192];
+	swprintf_s(buf, L"%d 项", n);
+	SetLabel(L"kc_rkn_tot_goods", buf, 0);
+	swprintf_s(buf, L"%.0f", q);
+	SetLabel(L"kc_rkn_tot_qty", buf, 0);
+	SetLabel(L"kc_rkn_tot_amt", (L"\u00A5" + KcFormatMoney(amt)).c_str(), 0);
+
+	swprintf_s(buf, L"已添加 %d 个商品 · 点「添加商品」勾选更多,或直接扫条码追加;"
+		L"点数量 / 单价单元格调出数字键盘", n);
+	SetLabel(L"kc_rkn_tip", buf, 0);
+}
+
+// ============================ 子视图 B:新建出库单 ============================
+void CKucunCkNewView::OnInitControl()
+{
+	CComboUI* p = FindC<CComboUI>(L"kc_ckn_combo_type");
+	if (p != NULL)
+	{
+		AddComboItem(p, L"调拨出库");
+		AddComboItem(p, L"报损");
+		AddComboItem(p, L"采购退货");
+		SelectCombo(p, 0);
+	}
+}
+
+void CKucunCkNewView::SeedLines()
+{
+	// 设计稿 v4 p2:面粉 20(当前 45)/ 鸡蛋 10(18)/ 番茄 15(8,超库存 ⇒ 标红)
+	static const wchar_t* nm[3] = { L"面粉", L"鸡蛋", L"番茄" };
+	static const wchar_t* qt[3] = { L"20", L"10", L"15" };
+	static const wchar_t* nt[3] = { L"晚市面点", L"日常备料", L"超库存示例" };
+	for (int i = 0; i < 3; i++)
+	{
+		KcGoods g;
+		if (!KcLookupGoods(nm[i], g)) continue;
+		KcEditLine ln;
+		ln.name = g.name; ln.cat = g.cat; ln.unit = g.unit; ln.book = g.stock;
+		ln.qty = qt[i]; ln.note = nt[i];
+		m_lines.push_back(ln);
+	}
+}
+
+void CKucunCkNewView::OnLineAdded(KcEditLine& line)
+{
+	line.qty = L"1";
+}
+
+bool CKucunCkNewView::IsQtyWarn(int i) const
+{
+	if (i < 0 || i >= (int)m_lines.size()) return false;
+	if (m_lines[i].qty.empty()) return false;
+	return _wtof(m_lines[i].qty.c_str()) > (double)m_lines[i].book;
+}
+
+void CKucunCkNewView::FillReadonly(CListContainerElementUI* row, int i)
+{
+	if (i < 0 || i >= (int)m_lines.size()) return;
+	SetRowText(row, L"col_book", std::to_wstring(m_lines[i].book).c_str());
+}
+
+void CKucunCkNewView::RefreshRow(int i)
+{
+	if (i < 0 || i >= (int)m_lines.size()) return;
+	const KcEditLine& ln = m_lines[i];
+
+	SetCellText(i, L"qty", ln.qty.c_str());
+
+	// 【R48】设计稿 p2 第 3 行:超库存时备注格不是输入框,而是一行红字提示
+	// 「超出可用库存 7 斤」(.hint{font-size:12px;color:var(--red)}),两者互斥显隐。
+	if (IsQtyWarn(i))
+	{
+		int over = (int)_wtof(ln.qty.c_str()) - ln.book;
+		wchar_t hb[96];
+		swprintf_s(hb, L"超出可用库存 %d %s", over, ln.unit.c_str());
+		SetRowNoteHint(i, hb);
+	}
+	else
+	{
+		SetRowNoteHint(i, NULL);
+		SetCellText(i, L"note", ln.note.c_str());
+	}
+
+	ApplyCellStyle(i, KC_ECOL_QTY);
+	ApplyCellStyle(i, KC_ECOL_NOTE);
+}
+
+void CKucunCkNewView::RefreshTot()
+{
+	int n = (int)m_lines.size();
+	double q = 0.0;
+	int lack = 0;
+	for (int i = 0; i < n; i++)
+	{
+		q += m_lines[i].qty.empty() ? 0.0 : _wtof(m_lines[i].qty.c_str());
+		if (IsQtyWarn(i)) lack++;
+	}
+
+	// 【R48】设计稿 p2 合计条:合计商品 [3 项]  出库总数 [45]  库存不足 [tag red 1 项]
+	// 「库存不足」的值是一枚胶囊 tag(12px 粗体 + 圆角底图)。>0 红胶囊、==0 灰胶囊,
+	// 底图和文字色都要跟着换(只换文字色会得到「灰字压红底」)。
+	wchar_t buf[192];
+	swprintf_s(buf, L"%d 项", n);
+	SetLabel(L"kc_ckn_tot_goods", buf, 0);
+	swprintf_s(buf, L"%.0f", q);
+	SetLabel(L"kc_ckn_tot_qty", buf, 0);
+	swprintf_s(buf, L"%d 项", lack);
+	SetLabel(L"kc_ckn_tot_lack", buf, lack > 0 ? KC_COLOR_LACK : 0xFF8A9099);
+	CLabelUI* pTag = FindC<CLabelUI>(L"kc_ckn_tot_lack");
+	if (pTag != NULL)
+	{
+		pTag->SetBkImage(lack > 0 ? L"file='kc_tag_red.png' corner='12,12,12,12'"
+			: L"file='kc_tag_gray.png' corner='12,12,12,12'");
+		pTag->NeedParentUpdate();
+	}
+
+	swprintf_s(buf, L"已添加 %d 个商品 · 点「添加商品」勾选更多,或直接扫条码追加;"
+		L"点数量单元格调出数字键盘", n);
+	SetLabel(L"kc_ckn_tip", buf, 0);
+}
+
+// ============================ 子视图 C:新建盘点单 ============================
+void CKucunPdNewView::OnInitControl()
+{
+	CComboUI* p = FindC<CComboUI>(L"kc_pdn_combo_type");
+	if (p != NULL)
+	{
+		AddComboItem(p, L"全部商品");
+		AddComboItem(p, L"部分商品");
+		AddComboItem(p, L"按分类");
+		SelectCombo(p, 0);
+	}
+}
+
+void CKucunPdNewView::SeedLines()
+{
+	// 设计稿 v4 p3:大米 320->320 / 面粉 45->43 / 食用油 12->12 / 番茄 8->6 / 鸡蛋 18->19
+	static const wchar_t* nm[5] = { L"大米", L"面粉", L"食用油", L"番茄", L"鸡蛋" };
+	static const wchar_t* qt[5] = { L"320", L"43", L"12", L"6", L"19" };
+	for (int i = 0; i < 5; i++)
+	{
+		KcGoods g;
+		if (!KcLookupGoods(nm[i], g)) continue;
+		KcEditLine ln;
+		ln.name = g.name; ln.cat = g.cat; ln.unit = g.unit; ln.book = g.stock;
+		ln.qty = qt[i];
+		m_lines.push_back(ln);
+	}
+}
+
+void CKucunPdNewView::OnLineAdded(KcEditLine& line)
+{
+	line.qty.clear();       // 新加入的商品默认「未录」
+}
+
+// 「按账面库存」一键填充:把所有行(含未录行)的实盘数量写成账面库存 ⇒ 差异全为 0。
+// 设计稿 p3 底栏旁边那个 ghost 按钮就是干这个的,方便「先全对一遍再改少数几个」。
+void CKucunPdNewView::FillByBook()
+{
+	for (size_t i = 0; i < m_lines.size(); i++)
+	{
+		m_lines[i].qty = std::to_wstring(m_lines[i].book);
+	}
+	CloseKeypad();
+	RefreshAll();
+}
+
+bool CKucunPdNewView::IsCellPlaceholder(int i, int col) const
+{
+	if (col != KC_ECOL_QTY) return false;
+	if (i < 0 || i >= (int)m_lines.size()) return false;
+	return m_lines[i].qty.empty();
+}
+
+void CKucunPdNewView::FillReadonly(CListContainerElementUI* row, int i)
+{
+	if (i < 0 || i >= (int)m_lines.size()) return;
+	SetRowText(row, L"col_book", std::to_wstring(m_lines[i].book).c_str());
+	SetRowText(row, L"col_note", L"\u2014");
+}
+
+void CKucunPdNewView::RefreshRow(int i)
+{
+	if (i < 0 || i >= (int)m_lines.size()) return;
+	const KcEditLine& ln = m_lines[i];
+
+	SetCellText(i, L"qty", ln.qty.empty() ? L"未录" : ln.qty.c_str());
+
+	if (ln.qty.empty())
+	{
+		SetRowLabel(i, L"col_diff", L"\u2014", 0xFFA8ADB3);
+	}
+	else
+	{
+		int diff = (int)_wtof(ln.qty.c_str()) - ln.book;
+		wchar_t buf[32];
+		if (diff > 0) swprintf_s(buf, L"+%d", diff);
+		else swprintf_s(buf, L"%d", diff);
+		SetRowLabel(i, L"col_diff", buf, diff > 0 ? KC_COLOR_NORMAL : (diff < 0 ? KC_COLOR_LACK : 0xFFA8ADB3));
+	}
+
+	ApplyCellStyle(i, KC_ECOL_QTY);
+}
+
+void CKucunPdNewView::RefreshTot()
+{
+	int n = (int)m_lines.size();
+	int filled = 0, gain = 0, loss = 0;
+	double amt = 0.0;
+
+	for (int i = 0; i < n; i++)
+	{
+		const KcEditLine& ln = m_lines[i];
+		if (ln.qty.empty()) continue;
+		filled++;
+		int diff = (int)_wtof(ln.qty.c_str()) - ln.book;
+		if (diff > 0) gain++;
+		else if (diff < 0) loss++;
+
+		KcGoods g;
+		double price = KcLookupGoods(ln.name, g) ? g.price : 0.0;
+		amt += diff * price;
+	}
+
+	// 【R48】设计稿 p3 合计条:已录入 [5 项]  盘盈 [tag grn 1 项]  盘亏 [tag red 2 项]
+	//                        →右侧→   盈亏金额 -¥86.00(负数红字,负号在 ¥ 之前)
+	// 标签「已录入 / 盘盈 / 盘亏 / 盈亏金额」都写死在 kucun_page.xml,这里只写值。
+	// 两枚 tag 的底图随计数切换(>0 彩色胶囊、==0 灰胶囊)。
+	wchar_t buf[192];
+	swprintf_s(buf, L"%d 项", filled);
+	SetLabel(L"kc_pdn_tot_in", buf, 0);
+	swprintf_s(buf, L"%d 项", gain);
+	SetLabel(L"kc_pdn_tot_gain", buf, gain > 0 ? KC_COLOR_NORMAL : 0xFF8A9099);
+	swprintf_s(buf, L"%d 项", loss);
+	SetLabel(L"kc_pdn_tot_loss", buf, loss > 0 ? KC_COLOR_LACK : 0xFF8A9099);
+
+	CLabelUI* pGain = FindC<CLabelUI>(L"kc_pdn_tot_gain");
+	if (pGain != NULL)
+	{
+		pGain->SetBkImage(gain > 0 ? L"file='kc_tag_grn.png' corner='12,12,12,12'"
+			: L"file='kc_tag_gray.png' corner='12,12,12,12'");
+		pGain->NeedParentUpdate();
+	}
+	CLabelUI* pLoss = FindC<CLabelUI>(L"kc_pdn_tot_loss");
+	if (pLoss != NULL)
+	{
+		pLoss->SetBkImage(loss > 0 ? L"file='kc_tag_red.png' corner='12,12,12,12'"
+			: L"file='kc_tag_gray.png' corner='12,12,12,12'");
+		pLoss->NeedParentUpdate();
+	}
+
+	std::wstring amtTxt = (amt < 0 ? L"-\u00A5" : L"\u00A5") + KcFormatMoney(amt < 0 ? -amt : amt);
+	SetLabel(L"kc_pdn_tot_amt", amtTxt.c_str(), amt < 0 ? KC_COLOR_LACK : KC_COLOR_NORMAL);
+
+	if (n > 0 && filled < n)
+		swprintf_s(buf, L"盘点范围:全部商品(共 %d 项,已录入 %d 项)· 点实盘数量单元格调出数字键盘", n, filled);
+	else
+		swprintf_s(buf, L"盘点范围:全部商品(共 %d 项,已全部录入)· 差异 = 实盘 − 账面", n);
+	SetLabel(L"kc_pdn_tip", buf, 0);
+}

+ 542 - 0
zhipuzi_pos_windows/page/CKucunViews.h

@@ -0,0 +1,542 @@
+#pragma once
+
+#include "pch.h"
+#include <string>
+#include <vector>
+#include "../ui/CBasePageUI.h"
+// 注意:不要在此 include ControlEx.h —— 它会反过来 include CKucunPageUI.h,
+// 而 CKucunPageUI.h 又 include 本文件,形成循环包含导致 CKucunViewBase 未声明。
+// CDialogBuilderCallbackEx 仅在 CKucunViews.cpp 中使用,放 cpp 里 include。
+
+// 进销存(库存)各视图共用的状态/结果配色(仅 6 位 #RRGGBB,禁止 8 位)
+#define KC_COLOR_NORMAL   0xFF2E9B5C   // 正常/已入库/已出库/盘盈(绿)
+#define KC_COLOR_WARN     0xFFE08A17   // 库存预警/待处理(橙)
+#define KC_COLOR_LACK     0xFFE14B4A   // 缺货/盘亏(红)
+#define KC_COLOR_BLUE     0xFF4A90E2   // 加权平均/盘盈(蓝)
+#define KC_COLOR_GRAY     0xFF5F6368   // 无差异/固定价(灰)
+
+// 列表每「页」条数(设计稿口径:默认加载最近 20 条,上滑自动加载更多)
+#define KC_PAGE_SIZE      20
+
+// ---------------- 胶囊标签(设计稿 .tag) ----------------
+// 与 .workbuddy/design/gen_kucun_v2_assets.py 产出的 kc_tag_*.png 一一对应:
+// 底图 = 品类淡色底,文字色 = 同色系深色。--t3 那套灰用于「无差异 / 固定价」。
+// 行模板里标签是一个 maxheight=24 的 Label,配上 bkimage + corner='12,12,12,12'
+// + textpadding='12,0,12,0' + autocalcwidth='true',宽度自动贴合文字。
+enum
+{
+	KC_TAG_GRN = 0,   // 正常 / 已入库 / 采购入库
+	KC_TAG_ORG,       // 库存预警 / 退货入库
+	KC_TAG_RED,       // 缺货 / 盘亏 / 报损
+	KC_TAG_BLUE,      // 加权平均 / 盘盈 / 调拨
+	KC_TAG_PUR,       // 备用(设计稿 .tag.pur,暂未用到)
+	KC_TAG_GRAY       // 无差异 / 固定价
+};
+
+// ---------------- 数值 / 文案格式化(页面各视图与单据详情弹框共用) ----------------
+// 这三个函数原先在 CKucunViews.cpp 的匿名 namespace 里;R44 的详情弹框也要用,
+// 于是提到头文件做 inline —— 全工程一份实现,避免两处逻辑漂移。
+inline std::wstring KcGroupInt(const std::wstring& s)
+{
+	std::wstring out;
+	int n = (int)s.length();
+	int cnt = 0;
+	for (int i = n - 1; i >= 0; i--)
+	{
+		out.insert(out.begin(), s[i]);
+		if (s[i] != L'.')
+		{
+			cnt++;
+			if (cnt % 3 == 0 && i > 0) out.insert(out.begin(), L',');
+		}
+	}
+	return out;
+}
+
+// 金额:千分位 + 2 位小数;负值带前缀 "-"
+inline std::wstring KcFormatMoney(double v)
+{
+	bool neg = v < 0;
+	double a = neg ? -v : v;
+	long long whole = (long long)floor(a + 1e-9);
+	int dec = (int)(floor((a - floor(a)) * 100.0 + 0.5));
+	if (dec >= 100) { dec -= 100; whole += 1; }
+	std::wstring ws = std::to_wstring(whole);
+	std::wstring decs = (dec < 10 ? (L"0" + std::to_wstring(dec)) : std::to_wstring(dec));
+	std::wstring s = KcGroupInt(ws) + L"." + decs;
+	return (neg ? L"-" : L"") + s;
+}
+
+// 统计卡金额:设计稿 t1~t9 的四个数字全是整数(8,420 / -130 / 12,860),
+// 不带 ¥ 前缀、不做小数,所以这里单独走一套取整 + 千分位。
+inline std::wstring KcFormatInt(double v)
+{
+	bool neg = v < 0;
+	double a = neg ? -v : v;
+	long long w = (long long)floor(a + 0.5);
+	std::wstring s = KcGroupInt(std::to_wstring(w));
+	return (neg && w != 0) ? (L"-" + s) : s;
+}
+
+// 数量:整数不带小数点(设计稿里 100 / 5 / 20 都这么写),有小数才补 2 位。
+inline std::wstring KcFormatQty(double v)
+{
+	long long w = (long long)floor(v + 1e-9);
+	if (fabs(v - (double)w) < 1e-9) return std::to_wstring(w);
+	return KcFormatMoney(v);
+}
+
+// 盘点差异:正数带 "+",负数自带 "-",0 就是 "0"
+inline std::wstring KcSignedInt(int v)
+{
+	if (v > 0) return L"+" + std::to_wstring(v);
+	return std::to_wstring(v);
+}
+
+// 盘点盈亏金额:正数带 "+"(+65.00),负数自带 "-"(-24.00)
+inline std::wstring KcSignedMoney(double v)
+{
+	std::wstring s = KcFormatMoney(v);
+	if (v > 1e-9) s = L"+" + s;
+	return s;
+}
+
+// ---------------- 胶囊标签(设计稿 .tag)底图与文字色 ----------------
+// 底图必须带 corner,否则九宫格退化成拉伸整图、圆角会被拉成椭圆。
+// 与 .workbuddy/design/gen_kucun_v2_assets.py 产出的 kc_tag_*.png 一一对应。
+inline const wchar_t* KcTagImage(int style)
+{
+	static const wchar_t* const kImg[6] =
+	{
+		L"file='kc_tag_grn.png' corner='12,12,12,12'",
+		L"file='kc_tag_org.png' corner='12,12,12,12'",
+		L"file='kc_tag_red.png' corner='12,12,12,12'",
+		L"file='kc_tag_blue.png' corner='12,12,12,12'",
+		L"file='kc_tag_pur.png' corner='12,12,12,12'",
+		L"file='kc_tag_gray.png' corner='12,12,12,12'",
+	};
+	return kImg[(style >= 0 && style <= KC_TAG_GRAY) ? style : KC_TAG_GRAY];
+}
+
+inline DWORD KcTagText(int style)
+{
+	static const DWORD kTxt[6] =
+	{
+		KC_COLOR_NORMAL, KC_COLOR_WARN, KC_COLOR_LACK, KC_COLOR_BLUE, 0xFF7C6BD6, KC_COLOR_GRAY,
+	};
+	return kTxt[(style >= 0 && style <= KC_TAG_GRAY) ? style : KC_TAG_GRAY];
+}
+
+// 一次性写好「文字 + 底图 + 文字色」三件套(列表行里的标签与弹框表头标签共用)
+inline void KcApplyTag(CLabelUI* p, const std::wstring& text, int style)
+{
+	if (p == NULL) return;
+	p->SetText(text.c_str());
+	p->SetBkImage(KcTagImage(style));
+	p->SetTextColor(KcTagText(style));
+}
+
+// 各视图的占位假数据结构(数值口径对齐设计稿 t1~t9)
+struct KcRkItem { std::wstring no, type, handler; int goods; double amount; int status; };
+struct KcRkStat { std::wstring name, cat, unit; int cnt; int qty; double amount; };
+struct KcCkItem { std::wstring no, type, handler; int goods; double amount; int status; };
+struct KcPdItem { std::wstring no, scope, handler; int goods, gain, loss; double amount; int result; };
+struct KcPdStat { std::wstring name, cat, unit; int cnt; int diff; double amount; int result; };
+
+// ---------------- 商品档案(进销存共用的占位数据) ----------------
+// 三张编辑页(入库 / 出库 / 盘点)与「添加商品」弹层都从这里取数,
+// 保证名称 / 分类 / 单位 / 库存 / 单价在各个页面之间自洽。
+// 「库存查询」台账与「库存金额」报表也直接由这份档案派生,不再另开一份假数据。
+struct KcGoods
+{
+	std::wstring name;      // 商品名称
+	std::wstring cat;       // 分类
+	std::wstring unit;      // 单位
+	std::wstring py;        // 拼音码(搜索用)
+	int          stock;     // 当前库存 / 账面库存
+	double       price;     // 入库单默认单价(编辑页取这个值;与下面三个成本口径无关)
+
+	// ---- 以下 5 个字段只服务「库存查询 / 库存金额」两张表 ----
+	int          safe;      // 安全库存:当前库存 < safe 判缺货,safe <= 当前库存 < 2*safe 判预警
+	bool         fixedCost; // 成本价模式:true = 固定价,false = 加权平均
+	double       avgCost;   // 加权平均成本价(库存成本 = avgCost * 当前库存)
+	double       inPrice;   // 当前进货价(报表只读展示)
+	double       salePrice; // 当前销售价(预计销售额 = salePrice * 当前库存)
+};
+// 全部商品(顺序即「添加商品」弹层顺序);cat 为空时返回全部
+const std::vector<KcGoods>& KcAllGoods();
+// 按名称取一条;命中返回 true 并填充出参
+bool KcLookupGoods(const std::wstring& name, KcGoods& out);
+
+// ---------------- 单据详情(t10 入库单 / t12 出库单 / t13 盘点单 的详情弹框) ----------------
+// 明细行两种口径共用同一条结构:入库 / 出库只填 qty·price·amount,盘点只填 book·real·diff·pl。
+// 不拆成两个结构,是因为弹框只有一张皮肤、一条填表逻辑,判别靠 KcDocDetail::kind。
+struct KcDetailRow
+{
+	std::wstring name, unit;          // 商品名称 / 单位
+	double       qty, price, amount;  // 入库 / 出库:数量 / 单价 / 金额(盘点行恒 0)
+	int          book, real, diff;    // 盘点:账面库存 / 实盘库存 / 差异(入库出库行恒 0)
+	double       pl;                  // 盘点:盈亏金额(入库出库行恒 0)
+};
+
+// 单据详情整单模型 —— 弹框照着这份数据填 6 格表头 + 明细表 + 合计 + 页脚按钮
+struct KcDocDetail
+{
+	int          kind;                // 0 = 入库单  1 = 出库单  2 = 盘点单
+	std::wstring title, sub;          // 弹框标题 / 标题右侧 12px 副标
+	std::wstring no;                  // 单号(第 1 格)
+	std::wstring f2lab, f2txt;        // 第 2 格:入库类型 / 出库类型 / 盘点范围
+	int          f2tag;               // 第 2 格样式:胶囊下标;-1 = 纯文本,不用胶囊
+	std::wstring status;              // 状态文案(第 3 格)
+	int          statTag;             // 状态胶囊样式
+	std::wstring whoLab, who;         // 经手人 / 盘点人(第 4 格)
+	std::wstring timeLab, time;       // 入库 / 出库 / 盘点时间(第 5 格)
+	int          printCnt;            // 打印次数(第 6 格)
+	std::vector<KcDetailRow> rows;    // 商品明细
+};
+// 按单号取整单详情(当前 12 张记录单全覆盖);未命中返回 false 且不改动 out
+bool KcLookupDetail(const std::wstring& no, KcDocDetail& out);
+
+// ---------------- 单据明细行模型(三张编辑页共用) ----------------
+struct KcEditLine
+{
+	std::wstring name, cat, unit;   // 商品名称 / 分类 / 单位
+	int          book;              // 只读列:当前库存(出库) / 账面库存(盘点)
+	std::wstring qty;               // 可编辑:入库数量 / 出库数量 / 实盘数量(空 = 未录)
+	std::wstring price;             // 可编辑(仅入库):单价
+	std::wstring note;              // 可编辑(仅出库):备注
+};
+
+// 「添加商品」弹层的候选项
+struct KcPickItem { std::wstring name, cat, unit; int stock; bool on; };
+
+// 小键盘可编辑列
+enum { KC_ECOL_QTY = 0, KC_ECOL_PRICE = 1, KC_ECOL_NOTE = 2 };
+
+// ---------------- 原生 Edit 的可见性手工同步(DuiLib 特有大坑) ----------------
+// Edit 是独立窗口:非分层模式下是 WS_CHILD,分层模式下甚至是顶层 WS_POPUP。
+// 父容器 SetVisible(false) **不会**自动把它藏起来 —— 框架的兜底在
+// CEditWnd::CalPos():父链上只要有不可见祖先,就把矩形塌成 0 尺寸。
+// 但那条路径只在 SetPos 时走到,而 CPaintManagerUI 重排子树时用 UIFIND_VISIBLE
+// 过滤(UIManager.cpp:4355),隐下去的子树根本收不到 SetPos
+// ⇒ 原生编辑框会孤零零留在屏幕上,还接着吃键盘输入。
+// 所以:任何「把含 Edit 的容器隐下去」之后,必须手动催一次 SetPos(GetPos()),
+// 让 CalPos 重新跑一遍、看到不可见的祖先、把原生窗压成 0。
+inline void KcSyncNativeEdit(CControlUI* pEdit)
+{
+	if (pEdit != NULL) pEdit->SetPos(pEdit->GetPos());
+}
+
+// 对一棵子树里的所有 Edit 逐个同步(宿主页切视图 / 隐浮层时调用)
+inline void KcSyncNativeEditsIn(CControlUI* pRoot)
+{
+	if (pRoot == NULL) return;
+	CEditUI* pEdit = static_cast<CEditUI*>(pRoot->GetInterface(DUI_CTR_EDIT));
+	if (pEdit != NULL) KcSyncNativeEdit(pEdit);
+
+	CContainerUI* pBox = static_cast<CContainerUI*>(pRoot->GetInterface(DUI_CTR_CONTAINER));
+	if (pBox == NULL) return;
+	for (int i = 0; i < pBox->GetCount(); i++) KcSyncNativeEditsIn(pBox->GetItemAt(i));
+}
+
+// 视图基类:持有宿主容器(kc_view_*)+ 管理器,提供查控件、建行、填统计卡等通用能力
+class CKucunViewBase
+{
+public:
+	CKucunViewBase(CPaintManagerUI* pm, CContainerUI* host)
+		: m_pManager(pm), m_pHost(host) {}
+	virtual ~CKucunViewBase() {}
+
+	// 每次页面被选中调用:清空并重建列表与统计卡
+	virtual void InitShow() = 0;
+	// 控件构造时调用一次:填充下拉框等
+	virtual void OnInitControl() {}
+	// 事件转发(由宿主页 CKucunPageUI 按 name 前缀路由)
+	virtual void OnClick(TNotifyUI& msg) {}
+	virtual void OnItemSelect(TNotifyUI& msg) {}
+	virtual void OnTextChanged(TNotifyUI& msg) {}
+
+protected:
+	// 子类(编辑视图)要同时查本视图 host 与页面级键盘面板 host,因此声明为虚函数
+	virtual CControlUI* Find(LPCTSTR name);
+	template<typename T> T* FindC(LPCTSTR name) { return static_cast<T*>(Find(name)); }
+
+	CListContainerElementUI* NewRow(LPCTSTR xmlfile);
+	void ClearList(CListUI* list);
+	void SetRowText(CListContainerElementUI* row, LPCTSTR name, LPCTSTR text);
+	void SetRowColor(CListContainerElementUI* row, LPCTSTR name, DWORD color);
+	void SetRowWidth(CListContainerElementUI* row, LPCTSTR name, int width);
+	// 写一列圆角胶囊标签(文字 + 底图 + 文字色三件套一起换)
+	void SetTag(CListContainerElementUI* row, LPCTSTR name, LPCTSTR text, int style);
+
+	// ---- 统计卡(设计稿 .stat:26px 粗体数字 + 13px 灰色单位,数字一律 #1F2329) ----
+	// 整串走 showhtml,单位用 {f 13} 切小字号、{c #8A9099} 转灰,与设计稿 .stat .u 一致。
+	void SetStatInt(LPCTSTR name, int val, LPCWSTR unit);
+	void SetStatMoney(LPCTSTR name, double val, LPCWSTR unit);
+
+	// ---- sect-h 右侧计数 + 表尾加载状态 ----
+	void SetListCount(LPCTSTR labelName, int n);
+	void SetFootPaged(LPCTSTR name, int shown, int total);    // 台账 / 库存金额(项)
+	void SetFootRecord(LPCTSTR name, int shown, int total);   // 入库 / 出库 / 盘点记录(条)
+	void SetFootAll(LPCTSTR name, int total);                 // 各统计视图(项)
+
+	// 切换胶囊的通用三态样式(一级 Tab 与各视图的 seg 共用一套 bb_tabs_* 资源)
+	static void StyleSeg(CButtonUI* p, bool act);
+
+	// 整页滚动适配:List 自带滚动条已关(vscrollbar=false),必须按行数把 List 高度撑成
+	// 「表头(44) + nRows*54」,外层视图容器(VerticalLayout vscrollbar=true)才会按真实内容
+	// 高度计算滚动范围。否则固定高度下多出行被裁切(看不见数据)。
+	//
+	// 【R42 补】只撑 List 还不够:List 的父卡片(kc_cx_body_state 等)没有显式 height 时,
+	// CVerticalLayoutUI 会把 EstimateSize()==0 的子项当成「弹性项」压成剩余高度,
+	// 而 CContainerUI::DoPaint 会按自己的 m_rcItem 裁剪子控件 ⇒ 卡片内溢出的行依然看不见、
+	// 外层也拿不到正确的滚动范围。这里按「子项固定高度之和 + inset + childpadding」
+	// 把父卡片一并撑开;遇到有弹性子项/未声明高度时直接放弃(不瞎猜)。
+	void FitListHeight(LPCTSTR listName, int nRows);
+
+	void AddComboItem(CComboUI* combo, LPCWSTR text);
+	void SelectCombo(CComboUI* combo, int idx);
+	// 从 Edit 控件里读当前搜索词(控件不存在时保留原值)
+	void ReadSearch(LPCTSTR editName, std::wstring& out);
+	// 搜索框占位提示(float 浮在 Edit 上的那个灰字 Label):Edit 有内容就藏、清空再放回来。
+	// 必须在 OnTextChanged 里调 —— 占位 Label 不是 Edit 的一部分,DuiLib 不会自己藏。
+	void SyncSearchTishi(LPCTSTR tishiName, LPCTSTR editName);
+
+	CPaintManagerUI* m_pManager;
+	CContainerUI* m_pHost;
+};
+
+// 视图1:库存查询(库存状态台账 / 库存金额报表 双视图 + 只看预警开关 + 分类/搜索筛选)
+class CKucunChaxunView : public CKucunViewBase
+{
+public:
+	CKucunChaxunView(CPaintManagerUI* pm, CContainerUI* host) : CKucunViewBase(pm, host) {}
+	virtual void OnInitControl();
+	virtual void InitShow();
+	virtual void OnClick(TNotifyUI& msg);
+	virtual void OnItemSelect(TNotifyUI& msg);
+	virtual void OnTextChanged(TNotifyUI& msg);
+private:
+	void SetSeg(int active, bool bBuild = true);   // 0 = 库存状态 1 = 库存金额
+	void ApplyWarnSwitch();
+	void BuildStateRows();
+	void BuildAmtRows();
+	bool RowPass(const KcGoods& g, const std::wstring& cat) const;
+
+	int m_nSeg = 0;
+	bool m_bWarnOnly = false;
+	std::wstring m_strCat;
+	std::wstring m_strSearch;
+};
+
+// 视图2:入库(记录 / 统计 双视图)
+class CKucunRukuView : public CKucunViewBase
+{
+public:
+	CKucunRukuView(CPaintManagerUI* pm, CContainerUI* host) : CKucunViewBase(pm, host) {}
+	virtual void OnInitControl();
+	virtual void InitShow();
+	virtual void OnClick(TNotifyUI& msg);
+	virtual void OnItemSelect(TNotifyUI& msg);
+	virtual void OnTextChanged(TNotifyUI& msg);
+private:
+	void BuildRecordRows();
+	void BuildStatRows();
+	void SetSeg(int active, bool bBuild = true);   // 0 = 记录 1 = 统计
+	int m_nSeg = 0;
+	std::wstring m_strSearch;
+};
+
+// 视图3:出库(记录 / 统计 双视图)
+class CKucunChukuView : public CKucunViewBase
+{
+public:
+	CKucunChukuView(CPaintManagerUI* pm, CContainerUI* host) : CKucunViewBase(pm, host) {}
+	virtual void OnInitControl();
+	virtual void InitShow();
+	virtual void OnClick(TNotifyUI& msg);
+	virtual void OnItemSelect(TNotifyUI& msg);
+	virtual void OnTextChanged(TNotifyUI& msg);
+private:
+	void BuildRecordRows();
+	void BuildStatRows();
+	void SetSeg(int active, bool bBuild = true);
+	int m_nSeg = 0;
+	std::wstring m_strSearch;
+};
+
+// 视图4:库存盘点(记录 / 差异 双视图)
+class CKucunPandianView : public CKucunViewBase
+{
+public:
+	CKucunPandianView(CPaintManagerUI* pm, CContainerUI* host) : CKucunViewBase(pm, host) {}
+	virtual void OnInitControl();
+	virtual void InitShow();
+	virtual void OnClick(TNotifyUI& msg);
+	virtual void OnItemSelect(TNotifyUI& msg);
+	virtual void OnTextChanged(TNotifyUI& msg);
+private:
+	void BuildRecordRows();
+	void BuildDiffRows();
+	void SetSeg(int active, bool bBuild = true);   // 0 = 记录 1 = 差异
+	int m_nSeg = 0;
+	std::wstring m_strSearch;
+};
+
+// ==================== 编辑视图基类(新建入库单 / 出库单 / 盘点单) ====================
+// 设计稿 v4 的三个「独立页面」,实为 kucun_page.xml 里与 kc_view_* 同级的全屏子视图。
+// 三者共用:明细行增删、点单元格调出页面级键盘、合计条刷新、与「添加商品」弹层对接。
+class CKucunEditViewBase : public CKucunViewBase
+{
+public:
+	CKucunEditViewBase(CPaintManagerUI* pm, CContainerUI* host, CContainerUI* kpHost)
+		: CKucunViewBase(pm, host), m_pKpHost(kpHost), m_nEditRow(-1), m_nEditCol(0) {}
+	virtual ~CKucunEditViewBase() {}
+
+	virtual void InitShow();
+	virtual void OnClick(TNotifyUI& msg);
+	virtual void OnItemSelect(TNotifyUI& msg);
+
+	// 键盘面板与本视图不在同一棵子树下,查找要穿透两个 host
+	virtual CControlUI* Find(LPCTSTR name);
+
+	// 由宿主页 CKucunPageUI 在「添加商品」弹层确定时调用:把勾选的商品追加/替换进明细
+	void AppendPicked(const std::vector<std::wstring>& names);
+	// 离开本视图时收起键盘
+	void CloseKeypad();
+	// 页面级动作兜底(默认无操作):目前只有盘点视图用「按账面库存填充」,
+	// 其余视图覆写为空。宿主页在按钮名精确命中时调用,不进 OnClick 的前缀路由。
+	virtual void FillByBook() {}
+
+protected:
+	// ---------- 子类必须实现 ----------
+	virtual LPCTSTR RowXml() const = 0;            // 明细行皮肤文件
+	virtual LPCTSTR Prefix() const = 0;            // L"kc_rkn" / L"kc_ckn" / L"kc_pdn"
+	virtual LPCTSTR ListName() const = 0;          // 明细 List 的 name
+	virtual LPCTSTR TblCardName() const = 0;       // 明细表外层卡片的 name
+	virtual void    SeedLines() = 0;               // 塞入初始占位明细
+	virtual void    FillReadonly(CListContainerElementUI* row, int i) = 0;  // 写只读列
+	virtual void    RefreshRow(int i) = 0;         // 刷新第 i 行全部列(含计算列 / 着色)
+	virtual void    RefreshTot() = 0;              // 刷新合计条
+	virtual bool    IsQtyWarn(int i) const { return false; }   // 出库:超当前库存
+	// 「添加商品」把商品加进明细后的一次性初始化(默认单价 / 默认数量)
+	virtual void    OnLineAdded(KcEditLine& line) { (void)line; }
+	// 勾选商品后是否「替换」明细(盘点部分商品用;入库 / 出库是追加)
+	virtual bool    ReplaceOnPick() const { return false; }
+	// 该单元格是否处于「未录入」占位态(盘点未录 ⇒ 灰字)
+	virtual bool    IsCellPlaceholder(int i, int col) const { (void)i; (void)col; return false; }
+	// 【R48】单据头「备注」字段的占位文案(设计稿 p1/p2/p3 各不相同:
+	// 采购到货,含配送费 / 晚市备料 / 月末盘点),显示在 Button 上当 placeholder。
+	virtual LPCWSTR HeadNotePh() const { return L"点此输入备注"; }
+	// 【R49】键盘左栏「商品 · 字段」里的字段名。设计稿 p6 是「大米 · 入库数量」,
+	// 三个新建页各不相同(入库数量 / 出库数量 / 实盘数量),交给子类给。
+	virtual LPCWSTR QtyColLabel() const { return L"数量"; }
+
+	// ---------- 通用实现 ----------
+	void BuildRows();
+	void RefreshAll();                             // 重建行 + 刷合计
+	void SyncTableHeight();                        // List + 外层卡片一起撑
+	void ApplyCellStyle(int i, int col);           // 单元格三态底图
+	std::wstring CellName(LPCWSTR kind, int idx) const;   // kc_rkn_qty_3
+	std::wstring PrefixW() const;
+	CListContainerElementUI* RowAt(int i);
+	void SetCellText(int i, LPCWSTR kind, LPCTSTR text);
+	void SetRowLabel(int i, LPCTSTR name, LPCTSTR text, DWORD color = 0);
+	void SetLabel(LPCTSTR name, LPCTSTR text, DWORD color = 0);
+	// 【R48】出库明细「超库存」时,把备注格的输入按钮换成一行红字提示
+	// (设计稿 p2 第 3 行 .hint「超出可用库存 8 斤」)。text 传 NULL / 空串则恢复输入框。
+	// 两个控件都在行模板的 col_note 容器里互斥显隐。
+	void SetRowNoteHint(int i, LPCTSTR text);
+
+	// 键盘
+	void OpenKeypad(int row, int col);
+	void KeypadShow(bool bText);                   // true = 文本面板,false = 数字键盘
+	void KeypadRefresh();
+	void KpDigit(LPCTSTR t);
+	void KpDot();
+	void KpDel();
+	void KpClear();
+	void KpCommit();
+
+	CListUI* FindList();
+	// 【R49】键盘态底栏提示:数字键盘弹出时把本页底栏提示换成设计稿 p6 的
+	// 「数字键盘仅用于数量 / 单价输入;确认后回到明细表」,收起后还原。
+	// 默认文案从 XML 现场记一次(m_footTipDefault),不在 C++ 里复制一份。
+	void      SyncFootTip(bool bKeypad);
+	CLabelUI* FootTipLabel();
+
+	std::vector<KcEditLine> m_lines;
+	CContainerUI* m_pKpHost;
+	std::wstring  m_headNote;      // 单据头「备注」字段(row = -1 时复用键盘)
+	int           m_nEditRow;      // -1 = 未在编辑
+	int           m_nEditCol;
+	std::wstring  m_editBuf;       // 键盘正在编辑的值
+	std::wstring  m_footTipDefault;   // 【R49】底栏提示的原始文案(首次切键盘态时记下)
+};
+
+// 子视图 A:新建入库单(设计稿 v4 p1 / p6 / p8)
+class CKucunRkNewView : public CKucunEditViewBase
+{
+public:
+	CKucunRkNewView(CPaintManagerUI* pm, CContainerUI* host, CContainerUI* kpHost)
+		: CKucunEditViewBase(pm, host, kpHost) {}
+	virtual void OnInitControl();
+protected:
+	virtual LPCTSTR RowXml() const { return L"kc_row_rk_edit.xml"; }
+	virtual LPCTSTR Prefix() const { return L"kc_rkn"; }
+	virtual LPCTSTR ListName() const { return L"kc_rkn_list"; }
+	virtual LPCTSTR TblCardName() const { return L"kc_rkn_tblcard"; }
+	virtual void    SeedLines();
+	virtual void    FillReadonly(CListContainerElementUI* row, int i);
+	virtual void    RefreshRow(int i);
+	virtual void    RefreshTot();
+	virtual void    OnLineAdded(KcEditLine& line);   // 默认数量 1 + 单价取档案
+	virtual LPCWSTR HeadNotePh() const { return L"采购到货,含配送费"; }
+	virtual LPCWSTR QtyColLabel() const { return L"入库数量"; }
+};
+
+// 子视图 B:新建出库单(设计稿 v4 p2 / p7)
+class CKucunCkNewView : public CKucunEditViewBase
+{
+public:
+	CKucunCkNewView(CPaintManagerUI* pm, CContainerUI* host, CContainerUI* kpHost)
+		: CKucunEditViewBase(pm, host, kpHost) {}
+	virtual void OnInitControl();
+protected:
+	virtual LPCTSTR RowXml() const { return L"kc_row_ck_edit.xml"; }
+	virtual LPCTSTR Prefix() const { return L"kc_ckn"; }
+	virtual LPCTSTR ListName() const { return L"kc_ckn_list"; }
+	virtual LPCTSTR TblCardName() const { return L"kc_ckn_tblcard"; }
+	virtual void    SeedLines();
+	virtual void    FillReadonly(CListContainerElementUI* row, int i);
+	virtual void    RefreshRow(int i);
+	virtual void    RefreshTot();
+	virtual bool    IsQtyWarn(int i) const;
+	virtual void    OnLineAdded(KcEditLine& line);   // 默认出库数量 1
+	virtual LPCWSTR HeadNotePh() const { return L"晚市备料"; }
+	virtual LPCWSTR QtyColLabel() const { return L"出库数量"; }
+};
+
+// 子视图 C:新建盘点单(设计稿 v4 p3 全部 / p4 部分)
+class CKucunPdNewView : public CKucunEditViewBase
+{
+public:
+	CKucunPdNewView(CPaintManagerUI* pm, CContainerUI* host, CContainerUI* kpHost)
+		: CKucunEditViewBase(pm, host, kpHost) {}
+	virtual void OnInitControl();
+protected:
+	virtual LPCTSTR RowXml() const { return L"kc_row_pd_edit.xml"; }
+	virtual LPCTSTR Prefix() const { return L"kc_pdn"; }
+	virtual LPCTSTR ListName() const { return L"kc_pdn_list"; }
+	virtual LPCTSTR TblCardName() const { return L"kc_pdn_tblcard"; }
+	virtual void    SeedLines();
+	virtual void    FillReadonly(CListContainerElementUI* row, int i);
+	virtual void    RefreshRow(int i);
+	virtual void    RefreshTot();
+	virtual void    OnLineAdded(KcEditLine& line);
+	virtual bool    ReplaceOnPick() const { return true; }     // 盘点「部分商品」= 勾选结果即范围
+	virtual bool    IsCellPlaceholder(int i, int col) const;   // 实盘数量空 ⇒ 显示灰色「未录」
+	virtual void    FillByBook();                              // 「按账面库存」一键把实盘填成账面
+	virtual LPCWSTR HeadNotePh() const { return L"月末盘点"; }
+	virtual LPCWSTR QtyColLabel() const { return L"实盘数量"; }
+};

+ 329 - 0
zhipuzi_pos_windows/wnd/CKucunDetailWnd.cpp

@@ -0,0 +1,329 @@
+#include "pch.h"
+#include "CKucunDetailWnd.h"
+#include "../control/ControlEx.h"
+
+namespace
+{
+	CLabelUI* KdFind(CListContainerElementUI* row, LPCTSTR name)
+	{
+		if (row == NULL) return NULL;
+		return static_cast<CLabelUI*>(row->FindSubControl(name));
+	}
+
+	void KdSet(CListContainerElementUI* row, LPCTSTR name, const std::wstring& text)
+	{
+		CLabelUI* p = KdFind(row, name);
+		if (p != NULL) p->SetText(text.c_str());
+	}
+
+	void KdSetColor(CListContainerElementUI* row, LPCTSTR name, DWORD color)
+	{
+		CLabelUI* p = KdFind(row, name);
+		if (p != NULL) p->SetTextColor(color);
+	}
+
+	// 盘盈绿 / 盘亏红 / 无差异灰(与设计稿 t13 的 --grn / --red / --t1 口径一致)
+	DWORD KdDiffColor(int diff)
+	{
+		if (diff > 0) return KC_COLOR_NORMAL;
+		if (diff < 0) return KC_COLOR_LACK;
+		return KC_COLOR_GRAY;
+	}
+
+	DWORD KdPlColor(double pl)
+	{
+		if (pl > 1e-9) return KC_COLOR_NORMAL;
+		if (pl < -1e-9) return KC_COLOR_LACK;
+		return KC_COLOR_GRAY;
+	}
+
+	// 明细行模板实例化(与 CKucunViewBase::NewRow 同一手法)
+	CListContainerElementUI* KdNewRow(CPaintManagerUI* pm, LPCTSTR xmlfile)
+	{
+		CDialogBuilder builder;
+		CDialogBuilderCallbackEx cb;
+		CControlUI* p = builder.Create(xmlfile, (UINT)0, &cb, pm);
+		return static_cast<CListContainerElementUI*>(p);
+	}
+
+	// autocalcwidth 的 Label 改完文字必须踢一脚:SetText 之后只有 szAvailable 变化时
+	// EstimateSize 才会重算,而弹框按行数改窗高常常是同尺寸重排 —— 靠不住。
+	// CLabelUI::SetFont 是唯一无条件置位 m_bNeedEstimateSize 的入口(它没有早退判断),
+	// 项目里 SetStatInt 也是这么刷的。
+	void KdKick(CLabelUI* p)
+	{
+		if (p != NULL) p->SetFont(p->GetFont());
+	}
+
+	// 表头 6 格里的「值」:f2tag >= 0 用胶囊,否则纯文本
+	void KdSetValue(CPaintManagerUI& pm, LPCTSTR name, const std::wstring& text, int tag)
+	{
+		CLabelUI* p = static_cast<CLabelUI*>(pm.FindControl(name));
+		if (p == NULL) return;
+		if (tag >= 0)
+		{
+			KcApplyTag(p, text, tag);
+		}
+		else
+		{
+			p->SetText(text.c_str());
+			p->SetTextColor(0xFF1F2329);
+		}
+		KdKick(p);
+	}
+
+	void KdSetLabel(CPaintManagerUI& pm, LPCTSTR name, const std::wstring& text)
+	{
+		CLabelUI* p = static_cast<CLabelUI*>(pm.FindControl(name));
+		if (p == NULL) return;
+		p->SetText(text.c_str());
+		KdKick(p);
+	}
+}
+
+// ---------------------------------------------------------------- 窗口消息
+LRESULT CKucunDetailWnd::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;
+}
+
+// 无边框圆角窗:系统区一律裁成 0,靠 Window region + 分层阴影出圆角
+LRESULT CKucunDetailWnd::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 CKucunDetailWnd::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:
+		// ESC 关闭。注意不能只挂在 IMessageFilterUI::MessageHandler 上 ——
+		// 真模态走 DialogBoxIndirectParam,系统循环不调主循环的 TranslateMessage,
+		// 只有窗口过程这条链是稳的(见项目铁律:真模态 pre-filter 断链)。
+		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 CKucunDetailWnd::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);
+
+	// 入库单 / 出库单 共用一张皮肤(都是 商品名称 / 单位 / 数量 / 单价 / 金额 五列),
+	// 盘点单多出 账面 / 实盘 / 差异 / 盈亏金额,皮肤里表头 6 列,单独一张。
+	LPCTSTR skin = (m_doc.kind == 2) ? _T("kc_pd_detail_wnd.xml") : _T("kc_doc_detail_wnd.xml");
+
+	CDialogBuilder builder;
+	CControlUI* pRoot = builder.Create(skin, (UINT)0, NULL, &m_pm);
+	ASSERT(pRoot && "CKucunDetailWnd: 皮肤 XML 解析失败");
+
+	m_pm.AttachDialog(pRoot);
+	m_pm.AddNotifier(this);
+
+	return 0;
+}
+
+void CKucunDetailWnd::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 CKucunDetailWnd::LoadDetail()
+{
+	FillInfo();
+	FillRows();
+	FillSum();
+
+	// 表格卡高度 = 45(表头) + 52*n(行) + 10(下圆角区),与 kc_tblcard.png 的 corner='10,45,10,10' 对齐。
+	// List 是 kd_tblcard 里唯一子项且没写 height ⇒ 会被垂直布局当弹性项、自动吃掉剩余高度。
+	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 CKucunDetailWnd::FillInfo()
+{
+	// 标题 / 副标:入库单与出库单共用同一张 kc_doc_detail_wnd.xml,靠这两行区分;
+	// 盘点单虽然另有一张皮肤,也统一从数据里取,不给皮肤写死。
+	KdSetLabel(m_pm, L"kd_title", m_doc.title);
+	KdSetLabel(m_pm, L"kd_sub", m_doc.sub);
+
+	// 六格固定顺序:单号 / 类型(或盘点范围) / 状态 / 经手人(盘点人) / 时间 / 打印次数
+	KdSetLabel(m_pm, L"kd_l1", L"单号");
+	KdSetLabel(m_pm, L"kd_v1", m_doc.no);
+
+	KdSetLabel(m_pm, L"kd_l2", m_doc.f2lab);
+	KdSetValue(m_pm, L"kd_v2", m_doc.f2txt, m_doc.f2tag);
+
+	KdSetLabel(m_pm, L"kd_l3", L"状态");
+	KdSetValue(m_pm, L"kd_v3", m_doc.status, m_doc.statTag);
+
+	KdSetLabel(m_pm, L"kd_l4", m_doc.whoLab);
+	KdSetLabel(m_pm, L"kd_v4", m_doc.who);
+
+	KdSetLabel(m_pm, L"kd_l5", m_doc.timeLab);
+	KdSetLabel(m_pm, L"kd_v5", m_doc.time);
+
+	KdSetLabel(m_pm, L"kd_l6", L"打印次数");
+	KdSetLabel(m_pm, L"kd_v6", std::to_wstring(m_doc.printCnt) + L" 次");
+}
+
+void CKucunDetailWnd::FillRows()
+{
+	CListUI* pList = static_cast<CListUI*>(m_pm.FindControl(L"kd_list"));
+	if (pList == NULL) return;
+	while (pList->GetCount() > 0) pList->RemoveAt(0);
+
+	const bool bPd = (m_doc.kind == 2);
+	LPCTSTR rowXml = bPd ? L"kc_row_pd_detail.xml" : L"kc_row_doc_detail.xml";
+
+	for (size_t i = 0; i < m_doc.rows.size(); i++)
+	{
+		const KcDetailRow& r = m_doc.rows[i];
+		CListContainerElementUI* row = KdNewRow(&m_pm, rowXml);
+		if (row == NULL) continue;
+
+		KdSet(row, L"col_name", r.name);
+		KdSet(row, L"col_unit", r.unit);
+
+		if (bPd)
+		{
+			KdSet(row, L"col_book", std::to_wstring(r.book));
+			KdSet(row, L"col_real", std::to_wstring(r.real));
+			KdSet(row, L"col_diff", KcSignedInt(r.diff));
+			KdSetColor(row, L"col_diff", KdDiffColor(r.diff));
+			KdSet(row, L"col_pl", KcSignedMoney(r.pl));
+			KdSetColor(row, L"col_pl", KdPlColor(r.pl));
+		}
+		else
+		{
+			KdSet(row, L"col_qty", KcFormatQty(r.qty));
+			KdSet(row, L"col_price", KcFormatMoney(r.price));
+			KdSet(row, L"col_amount", KcFormatMoney(r.amount));
+		}
+
+		pList->Add(row);
+	}
+}
+
+void CKucunDetailWnd::FillSum()
+{
+	const bool bPd = (m_doc.kind == 2);
+	int    n = 0;
+	double total = 0.0;
+
+	if (bPd)
+	{
+		// 盘点:只数有差异的商品,合计走盈亏金额(可为负)
+		for (size_t i = 0; i < m_doc.rows.size(); i++)
+		{
+			if (m_doc.rows[i].diff != 0) n++;
+			total += m_doc.rows[i].pl;
+		}
+	}
+	else
+	{
+		n = (int)m_doc.rows.size();
+		for (size_t i = 0; i < m_doc.rows.size(); i++) total += m_doc.rows[i].amount;
+	}
+
+	KdSetLabel(m_pm, L"kd_sum_lab",
+		bPd ? (L"差异商品 " + std::to_wstring(n) + L" 项 · 盈亏合计")
+		: (L"商品 " + std::to_wstring(n) + L" 种 · 合计"));
+
+	KdSetLabel(m_pm, L"kd_sum_amt", L"¥" + KcFormatMoney(total));
+}

+ 121 - 0
zhipuzi_pos_windows/wnd/CKucunDetailWnd.h

@@ -0,0 +1,121 @@
+#pragma once
+
+#include "pch.h"
+#include "../ui/CModalWnd.h"
+#include "../page/CKucunViews.h"
+
+/**
+ * 单据详情弹框(设计稿 t10 入库单 / t12 出库单 / t13 盘点单)
+ *
+ * 入库单与出库单共用 skin/kc_doc_detail_wnd.xml(5 列),盘点单用 skin/kc_pd_detail_wnd.xml(6 列);
+ * 由 KcDocDetail::kind 在 OnCreate 里选皮肤,同一份填表逻辑走下来。
+ *
+ * 真模态(CModalWnd + UI_CLASSSTYLE_DIALOG),骨架与 CNumInputWnd 一致 ——
+ * 几个 WM_NCxxx 的返回值是 DuiLib 无边框圆角窗的固定套路,别删。
+ *
+ * 窗高随明细行数变化:H = 366 + 52 * nRows(56 标题 + 502 主体 + 68 页脚;5 行 = 626、4 行 = 574)。
+ * LoadDetail() 里先按行数 SetWindowPos 再让调用方 CenterWindow(),顺序不能反。
+ *
+ * 调用范式(与 CDiandanPageUI 里开 CDiandanNatureWnd 完全一致):
+ *     KcDocDetail d;
+ *     if (!KcLookupDetail(no, d)) { toast; return; }
+ *     CKucunDetailWnd* pDlg = new CKucunDetailWnd(d);
+ *     m_is_show_modal_wnd = true;
+ *     m_curModalWnd = pDlg;
+ *     pDlg->Create(m_pManager->GetPaintWindow(), _T(""), UI_WNDSTYLE_DIALOG, WS_EX_WINDOWEDGE);
+ *     pDlg->SetIcon(IDI_ICON_DUILIB);
+ *     pDlg->LoadDetail();          // 铺数据 + 调窗高
+ *     pDlg->CenterWindow();
+ *     pDlg->ShowModal();
+ *     m_is_show_modal_wnd = false;
+ *     bool bPrint = pDlg->IsPrintClicked();
+ *     delete pDlg;                 // 必须手动 delete
+ */
+class CKucunDetailWnd : public CModalWnd
+{
+public:
+	explicit CKucunDetailWnd(const KcDocDetail& doc) : m_doc(doc) {}
+	virtual ~CKucunDetailWnd() {}
+
+	LPCTSTR GetWindowClassName() const
+	{
+		return _T("KcDocDetailWndFrame");
+	}
+
+	UINT GetClassStyle() const
+	{
+		return UI_CLASSSTYLE_DIALOG;
+	}
+
+	void OnFinalMessage(HWND /*hWnd*/)
+	{
+		m_pm.RemovePreMessageFilter(this);
+	}
+
+	void Notify(TNotifyUI& msg);
+
+	LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
+
+	LRESULT OnNcActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+	{
+		if (::IsIconic(*this))
+		{
+			bHandled = FALSE;
+		}
+		return (wParam == 0) ? TRUE : FALSE;
+	}
+
+	LRESULT OnNcCalcSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+	{
+		return 0;
+	}
+
+	LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
+	{
+		return 0;
+	}
+
+	LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
+
+	LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled);
+
+	LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+	// CModalWnd 纯虚:单据详情弹框不接扫码枪
+	void HandleTextCapture(std::string /*content*/)
+	{
+	}
+
+	// IMessageFilterUI 纯虚(CModalWnd 继承自它)。真模态走 DialogBoxIndirectParam,
+	// 系统循环不跑主循环的 TranslateMessage ⇒ 这个 pre-filter 在模态下收不到键盘消息。
+	// 所以 ESC 放在 HandleMessage 的 WM_KEYDOWN 分支里(窗口过程那条链才稳),这里留空实现。
+	LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, bool& bHandled)
+	{
+		return false;
+	}
+
+	// 铺数据 + 按明细行数调整窗高。必须在 Create 之后(控件已建)、CenterWindow 之前调用。
+	void LoadDetail();
+
+	// 用户是否点了「打印小票」。热敏小票本轮不做,调用方据此决定要不要弹提示。
+	bool IsPrintClicked() const { return m_bPrint; }
+
+	// 窗高公式:56(标题) + 502(主体) + 68(页脚) = 626(5 行) / 574(4 行)。
+	// 主体 502 = inset 16+18 + info 104 + 14 + 表格卡(45+52n+10) + 10 + 合计 25。
+	static int WindowHeightFor(int nRows)
+	{
+		int n = (nRows > 0) ? nRows : 1;
+		return 366 + 52 * n;
+	}
+
+public:
+	CPaintManagerUI m_pm;
+
+private:
+	void FillInfo();
+	void FillRows();
+	void FillSum();
+
+	KcDocDetail m_doc;
+	bool        m_bPrint = false;
+};

Some files were not shown because too many files changed in this diff