@robot-admin/naive-ui-components 0.10.3 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (658) hide show
  1. package/CHANGELOG.md +111 -100
  2. package/LICENSE +21 -21
  3. package/README.md +463 -318
  4. package/README_EN.md +404 -0
  5. package/SECURITY.md +23 -0
  6. package/dist/C_ActionBar.cjs +1 -1
  7. package/dist/C_ActionBar.css +46 -48
  8. package/dist/C_ActionBar.d.cts +1 -1
  9. package/dist/C_ActionBar.js +1 -1
  10. package/dist/C_ActionBar2.cjs +1 -0
  11. package/dist/C_ActionBar2.js +1 -2
  12. package/dist/C_AntV.cjs +1 -1
  13. package/dist/C_AntV.css +3 -3
  14. package/dist/C_AntV.d.cts +1 -1
  15. package/dist/C_AntV.js +1 -1
  16. package/dist/C_AntV2.cjs +4 -0
  17. package/dist/C_AntV2.js +3 -4
  18. package/dist/C_AudioPlayer.cjs +1 -1
  19. package/dist/C_AudioPlayer.css +15 -7
  20. package/dist/C_AudioPlayer.d.cts +1 -1
  21. package/dist/C_AudioPlayer.js +1 -1
  22. package/dist/C_AudioPlayer2.cjs +1 -0
  23. package/dist/C_AudioPlayer2.js +1 -2
  24. package/dist/C_AvatarGroup.cjs +1 -1
  25. package/dist/C_AvatarGroup.css +15 -7
  26. package/dist/C_AvatarGroup.d.cts +1 -1
  27. package/dist/C_AvatarGroup2.cjs +1 -0
  28. package/dist/C_AvatarGroup2.js +1 -2
  29. package/dist/C_Barcode.cjs +1 -1
  30. package/dist/C_Barcode.css +0 -2
  31. package/dist/C_Barcode.d.cts +1 -1
  32. package/dist/C_Barcode2.cjs +1 -0
  33. package/dist/C_Barcode2.js +1 -2
  34. package/dist/C_Breadcrumb.cjs +1 -1
  35. package/dist/C_Breadcrumb.css +0 -2
  36. package/dist/C_Breadcrumb.d.cts +2 -2
  37. package/dist/C_Breadcrumb.d.ts +1 -2
  38. package/dist/C_Breadcrumb.js +1 -1
  39. package/dist/C_Breadcrumb2.cjs +1 -0
  40. package/dist/C_Breadcrumb2.js +1 -2
  41. package/dist/C_Captcha.cjs +1 -1
  42. package/dist/C_Captcha.css +46 -21
  43. package/dist/C_Captcha.d.cts +3 -2
  44. package/dist/C_Captcha.d.ts +3 -2
  45. package/dist/C_Captcha.js +1 -1
  46. package/dist/C_Captcha2.cjs +1 -0
  47. package/dist/C_Captcha2.js +1 -2
  48. package/dist/C_Cascade.cjs +1 -1
  49. package/dist/C_Cascade.css +0 -2
  50. package/dist/C_Cascade.d.cts +1 -1
  51. package/dist/C_Cascade.d.ts +1 -1
  52. package/dist/C_Cascade2.cjs +1 -0
  53. package/dist/C_Cascade2.js +1 -2
  54. package/dist/C_Chat.cjs +1 -1
  55. package/dist/C_Chat.css +0 -2
  56. package/dist/C_Chat.d.cts +1 -1
  57. package/dist/C_Chat.d.ts +1 -1
  58. package/dist/C_Chat.js +1 -1
  59. package/dist/C_Chat2.cjs +1 -0
  60. package/dist/C_Chat2.js +1 -2
  61. package/dist/C_City.cjs +1 -1
  62. package/dist/C_City.css +28 -30
  63. package/dist/C_City.d.cts +1 -1
  64. package/dist/C_City.d.ts +1 -1
  65. package/dist/C_City2.cjs +1 -0
  66. package/dist/C_City2.js +1 -2
  67. package/dist/C_Code.cjs +1 -1
  68. package/dist/C_Code.css +241 -4
  69. package/dist/C_Code.d.cts +1 -1
  70. package/dist/C_Code.d.ts +1 -1
  71. package/dist/C_Code.js +1 -1
  72. package/dist/C_Code2.cjs +1 -0
  73. package/dist/C_Code2.js +1 -2
  74. package/dist/C_CollapsePanel.cjs +1 -1
  75. package/dist/C_CollapsePanel.css +12 -6
  76. package/dist/C_CollapsePanel.d.cts +1 -1
  77. package/dist/C_CollapsePanel.js +1 -1
  78. package/dist/C_CollapsePanel2.cjs +1 -0
  79. package/dist/C_CollapsePanel2.js +1 -2
  80. package/dist/C_ContextMenu.cjs +1 -1
  81. package/dist/C_ContextMenu.css +16 -18
  82. package/dist/C_ContextMenu.d.cts +1 -1
  83. package/dist/C_ContextMenu.d.ts +1 -1
  84. package/dist/C_ContextMenu.js +1 -1
  85. package/dist/C_ContextMenu2.cjs +1 -0
  86. package/dist/C_ContextMenu2.js +1 -2
  87. package/dist/C_Cron.cjs +1 -1
  88. package/dist/C_Cron.css +18 -8
  89. package/dist/C_Cron.d.cts +1 -1
  90. package/dist/C_Cron.js +1 -1
  91. package/dist/C_Cron2.cjs +1 -0
  92. package/dist/C_Cron2.js +1 -2
  93. package/dist/C_Date.cjs +1 -1
  94. package/dist/C_Date.css +1 -0
  95. package/dist/C_Date.d.cts +2 -2
  96. package/dist/C_Date.d.ts +2 -2
  97. package/dist/C_Date2.cjs +1 -0
  98. package/dist/C_Date2.js +1 -2
  99. package/dist/C_Draggable.cjs +1 -1
  100. package/dist/C_Draggable.css +9 -5
  101. package/dist/C_Draggable.d.cts +1 -1
  102. package/dist/C_Draggable2.cjs +1 -0
  103. package/dist/C_Draggable2.js +1 -2
  104. package/dist/C_Editor.cjs +1 -1
  105. package/dist/C_Editor.css +80 -67
  106. package/dist/C_Editor.d.cts +1 -1
  107. package/dist/C_Editor.d.ts +1 -1
  108. package/dist/C_Editor2.cjs +1 -0
  109. package/dist/C_Editor2.js +1 -2
  110. package/dist/C_FilePreview.cjs +1 -1
  111. package/dist/C_FilePreview.css +0 -2
  112. package/dist/C_FilePreview.d.cts +1 -1
  113. package/dist/C_FilePreview.js +1 -1
  114. package/dist/C_FilePreview2.cjs +1 -0
  115. package/dist/C_FilePreview2.js +1 -2
  116. package/dist/C_Form.base.css +980 -0
  117. package/dist/C_Form.cjs +1 -1
  118. package/dist/C_Form.css +256 -155
  119. package/dist/C_Form.d.cts +2 -2
  120. package/dist/C_Form.d.ts +2 -2
  121. package/dist/C_Form.js +1 -1
  122. package/dist/C_Form2.cjs +1 -0
  123. package/dist/C_Form2.js +1 -2
  124. package/dist/C_FormSearch.cjs +1 -1
  125. package/dist/C_FormSearch.css +47 -47
  126. package/dist/C_FormSearch.d.cts +2 -2
  127. package/dist/C_FormSearch.d.ts +2 -2
  128. package/dist/C_FormSearch2.cjs +1 -0
  129. package/dist/C_FormSearch2.js +1 -2
  130. package/dist/C_FormulaEditor.cjs +1 -1
  131. package/dist/C_FormulaEditor.css +64 -38
  132. package/dist/C_FormulaEditor.d.cts +1 -1
  133. package/dist/C_FormulaEditor.js +1 -1
  134. package/dist/C_FormulaEditor2.cjs +2 -0
  135. package/dist/C_FormulaEditor2.js +2 -2
  136. package/dist/C_FullCalendar.cjs +1 -1
  137. package/dist/C_FullCalendar.css +0 -2
  138. package/dist/C_FullCalendar.d.cts +1 -1
  139. package/dist/C_FullCalendar2.cjs +1 -0
  140. package/dist/C_FullCalendar2.js +1 -2
  141. package/dist/C_GlobalSearch.cjs +1 -1
  142. package/dist/C_GlobalSearch.css +111 -113
  143. package/dist/C_GlobalSearch.d.cts +1 -1
  144. package/dist/C_GlobalSearch2.cjs +1 -0
  145. package/dist/C_GlobalSearch2.js +1 -2
  146. package/dist/C_Guide.cjs +1 -1
  147. package/dist/C_Guide.css +1 -0
  148. package/dist/C_Guide.d.cts +1 -1
  149. package/dist/C_Guide.d.ts +1 -1
  150. package/dist/C_Guide.js +1 -1
  151. package/dist/C_Guide2.cjs +1 -0
  152. package/dist/C_Guide2.js +1 -2
  153. package/dist/C_Icon.cjs +1 -1
  154. package/dist/C_Icon.css +58 -0
  155. package/dist/C_Icon.d.cts +1 -1
  156. package/dist/C_Icon.d.ts +1 -1
  157. package/dist/C_Icon2.cjs +1 -0
  158. package/dist/C_Icon2.js +1 -2
  159. package/dist/C_ImageCropper.cjs +1 -1
  160. package/dist/C_ImageCropper.css +0 -2
  161. package/dist/C_ImageCropper.d.cts +1 -1
  162. package/dist/C_ImageCropper.js +1 -1
  163. package/dist/C_ImageCropper2.cjs +1 -0
  164. package/dist/C_ImageCropper2.js +1 -2
  165. package/dist/C_Language.cjs +1 -1
  166. package/dist/C_Language.css +1 -0
  167. package/dist/C_Language.d.cts +1 -1
  168. package/dist/C_Language.d.ts +1 -1
  169. package/dist/C_Language.js +1 -1
  170. package/dist/C_Language2.cjs +1 -0
  171. package/dist/C_Language2.js +1 -2
  172. package/dist/C_Login.cjs +1 -1
  173. package/dist/C_Login.css +92 -76
  174. package/dist/C_Login.d.cts +1 -1
  175. package/dist/C_Login.d.ts +1 -1
  176. package/dist/C_Login.js +1 -1
  177. package/dist/C_Login2.cjs +1 -0
  178. package/dist/C_Login2.js +1 -2
  179. package/dist/C_Map.cjs +1 -1
  180. package/dist/C_Map.css +665 -5
  181. package/dist/C_Map.d.cts +1 -1
  182. package/dist/C_Map2.cjs +1 -0
  183. package/dist/C_Map2.js +1 -2
  184. package/dist/C_Markdown.cjs +1 -1
  185. package/dist/C_Markdown.css +940 -35
  186. package/dist/C_Markdown.d.cts +1 -1
  187. package/dist/C_Markdown.d.ts +1 -1
  188. package/dist/C_Markdown2.cjs +1 -0
  189. package/dist/C_Markdown2.js +1 -2
  190. package/dist/C_Menu.cjs +1 -1
  191. package/dist/C_Menu.css +1 -0
  192. package/dist/C_Menu.d.cts +3 -3
  193. package/dist/C_Menu.d.ts +3 -4
  194. package/dist/C_Menu.js +1 -1
  195. package/dist/C_Menu2.cjs +1 -0
  196. package/dist/C_Menu2.js +1 -2
  197. package/dist/C_NotificationCenter.cjs +1 -1
  198. package/dist/C_NotificationCenter.css +95 -47
  199. package/dist/C_NotificationCenter.d.cts +1 -1
  200. package/dist/C_NotificationCenter.js +1 -1
  201. package/dist/C_NotificationCenter2.cjs +1 -0
  202. package/dist/C_NotificationCenter2.js +1 -2
  203. package/dist/C_OrgChart.cjs +1 -1
  204. package/dist/C_OrgChart.css +6 -4
  205. package/dist/C_OrgChart.d.cts +1 -1
  206. package/dist/C_OrgChart.d.ts +1 -1
  207. package/dist/C_OrgChart2.cjs +1 -0
  208. package/dist/C_OrgChart2.js +1 -2
  209. package/dist/C_Progress.cjs +1 -1
  210. package/dist/C_Progress.css +1 -0
  211. package/dist/C_Progress.d.cts +1 -1
  212. package/dist/C_Progress.d.ts +1 -1
  213. package/dist/C_Progress2.cjs +1 -0
  214. package/dist/C_Progress2.js +1 -2
  215. package/dist/C_QRCode.cjs +1 -1
  216. package/dist/C_QRCode.css +8 -10
  217. package/dist/C_QRCode.d.cts +1 -1
  218. package/dist/C_QRCode2.cjs +1 -0
  219. package/dist/C_QRCode2.js +1 -2
  220. package/dist/C_Signature.cjs +1 -1
  221. package/dist/C_Signature.css +0 -2
  222. package/dist/C_Signature.d.cts +1 -1
  223. package/dist/C_Signature.js +1 -1
  224. package/dist/C_Signature2.cjs +1 -0
  225. package/dist/C_Signature2.js +1 -2
  226. package/dist/C_Skeleton.cjs +1 -1
  227. package/dist/C_Skeleton.css +0 -2
  228. package/dist/C_Skeleton.d.cts +1 -1
  229. package/dist/C_Skeleton.d.ts +1 -1
  230. package/dist/C_Skeleton2.cjs +1 -0
  231. package/dist/C_Skeleton2.js +1 -2
  232. package/dist/C_SplitPane.cjs +1 -1
  233. package/dist/C_SplitPane.css +27 -11
  234. package/dist/C_SplitPane.d.cts +1 -1
  235. package/dist/C_SplitPane.js +1 -1
  236. package/dist/C_SplitPane2.cjs +1 -0
  237. package/dist/C_SplitPane2.js +1 -2
  238. package/dist/C_Steps.cjs +1 -1
  239. package/dist/C_Steps.css +37 -39
  240. package/dist/C_Steps.d.cts +1 -1
  241. package/dist/C_Steps.d.ts +1 -1
  242. package/dist/C_Steps2.cjs +1 -0
  243. package/dist/C_Steps2.js +1 -2
  244. package/dist/C_Table.base.css +1588 -0
  245. package/dist/C_Table.cjs +1 -1
  246. package/dist/C_Table.css +1202 -112
  247. package/dist/C_Table.d.cts +2 -2
  248. package/dist/C_Table.d.ts +11 -2
  249. package/dist/C_Table.js +1 -1
  250. package/dist/C_TagsView.cjs +1 -1
  251. package/dist/C_TagsView.css +44 -40
  252. package/dist/C_TagsView.d.cts +2 -2
  253. package/dist/C_TagsView.d.ts +2 -3
  254. package/dist/C_TagsView.js +1 -1
  255. package/dist/C_TagsView2.cjs +1 -0
  256. package/dist/C_TagsView2.js +1 -2
  257. package/dist/C_Theme.cjs +1 -1
  258. package/dist/C_Theme.css +1 -0
  259. package/dist/C_Theme.d.cts +1 -1
  260. package/dist/C_Theme.d.ts +1 -1
  261. package/dist/C_Theme.js +1 -1
  262. package/dist/C_Theme2.cjs +1 -0
  263. package/dist/C_Theme2.js +1 -2
  264. package/dist/C_Time.cjs +1 -1
  265. package/dist/C_Time.css +0 -2
  266. package/dist/C_Time.d.cts +2 -2
  267. package/dist/C_Time.d.ts +2 -2
  268. package/dist/C_Time2.cjs +1 -0
  269. package/dist/C_Time2.js +1 -2
  270. package/dist/C_Timeline.cjs +1 -1
  271. package/dist/C_Timeline.css +44 -46
  272. package/dist/C_Timeline.d.cts +1 -1
  273. package/dist/C_Timeline.js +1 -1
  274. package/dist/C_Timeline2.cjs +1 -0
  275. package/dist/C_Timeline2.js +1 -2
  276. package/dist/C_Transfer.cjs +1 -1
  277. package/dist/C_Transfer.css +21 -9
  278. package/dist/C_Transfer.d.cts +1 -1
  279. package/dist/C_Transfer.js +1 -1
  280. package/dist/C_Transfer2.cjs +1 -0
  281. package/dist/C_Transfer2.js +1 -2
  282. package/dist/C_Tree.cjs +1 -1
  283. package/dist/C_Tree.css +0 -2
  284. package/dist/C_Tree.d.cts +1 -1
  285. package/dist/C_Tree.js +1 -1
  286. package/dist/C_Tree2.cjs +1 -0
  287. package/dist/C_Tree2.js +1 -2
  288. package/dist/C_Upload.cjs +1 -1
  289. package/dist/C_Upload.css +17 -17
  290. package/dist/C_Upload.d.cts +1 -1
  291. package/dist/C_Upload.js +1 -1
  292. package/dist/C_Upload2.cjs +1 -0
  293. package/dist/C_Upload2.js +1 -25
  294. package/dist/C_VideoPlayer.cjs +1 -1
  295. package/dist/C_VideoPlayer.css +35 -24
  296. package/dist/C_VideoPlayer.d.cts +2 -2
  297. package/dist/C_VideoPlayer.d.ts +2 -2
  298. package/dist/C_VideoPlayer.js +1 -1
  299. package/dist/C_VideoPlayer2.cjs +3 -0
  300. package/dist/C_VideoPlayer2.js +3 -4
  301. package/dist/C_VtableGantt.cjs +1 -1
  302. package/dist/C_VtableGantt.css +15 -7
  303. package/dist/C_VtableGantt.d.cts +1 -1
  304. package/dist/C_VtableGantt.d.ts +1 -1
  305. package/dist/C_VtableGantt.js +1 -1
  306. package/dist/C_VtableGantt2.cjs +1 -0
  307. package/dist/C_VtableGantt2.js +1 -2
  308. package/dist/C_WaterFall.cjs +1 -1
  309. package/dist/C_WaterFall.css +15 -17
  310. package/dist/C_WaterFall.d.cts +1 -1
  311. package/dist/C_WaterFall2.cjs +1 -0
  312. package/dist/C_WaterFall2.js +1 -2
  313. package/dist/C_WorkFlow.cjs +1 -1
  314. package/dist/C_WorkFlow.css +257 -197
  315. package/dist/C_WorkFlow.d.cts +1 -1
  316. package/dist/C_WorkFlow.js +1 -1
  317. package/dist/C_WorkFlow2.cjs +1 -0
  318. package/dist/C_WorkFlow2.js +1 -2
  319. package/dist/city.cjs +1 -0
  320. package/dist/city.js +1 -2
  321. package/dist/config.cjs +1 -0
  322. package/dist/config.d.cts +33 -0
  323. package/dist/config.d.ts +33 -0
  324. package/dist/config.js +1 -0
  325. package/dist/constants.d.cts +272 -0
  326. package/dist/constants.d.ts +6 -7
  327. package/dist/constants2.d.cts +177 -0
  328. package/dist/constants2.d.ts +5 -6
  329. package/dist/constants3.d.cts +479 -0
  330. package/dist/constants3.d.ts +17 -13
  331. package/dist/constants4.d.cts +420 -0
  332. package/dist/constants4.d.ts +30 -40
  333. package/dist/constants5.d.cts +491 -0
  334. package/dist/constants5.d.ts +22 -6
  335. package/dist/data.cjs +1 -0
  336. package/dist/data.d.cts +67 -0
  337. package/dist/data.d.ts +13 -13
  338. package/dist/data.js +1 -0
  339. package/dist/export-helper.cjs +1 -0
  340. package/dist/helpers.cjs +1 -0
  341. package/dist/helpers.js +1 -0
  342. package/dist/html.cjs +1 -0
  343. package/dist/html.js +1 -0
  344. package/dist/images/marker-icon-2x.png +0 -0
  345. package/dist/images/marker-icon.png +0 -0
  346. package/dist/images/marker-shadow.png +0 -0
  347. package/dist/index.cjs +1 -2
  348. package/dist/index.d.cts +60 -99
  349. package/dist/index.d.ts +41 -83
  350. package/dist/index.js +1 -2
  351. package/dist/index.vue.d.cts +79 -0
  352. package/dist/index.vue.d.ts +3 -4
  353. package/dist/index10.vue.d.cts +47 -0
  354. package/dist/index10.vue.d.ts +80 -40
  355. package/dist/index11.vue.d.cts +88 -0
  356. package/dist/index11.vue.d.ts +68 -78
  357. package/dist/index12.vue.d.cts +79 -0
  358. package/dist/index12.vue.d.ts +49 -45
  359. package/dist/index13.vue.d.cts +64 -0
  360. package/dist/index13.vue.d.ts +99 -34
  361. package/dist/index14.vue.d.cts +106 -0
  362. package/dist/index14.vue.d.ts +82 -99
  363. package/dist/index15.vue.d.cts +91 -0
  364. package/dist/index15.vue.d.ts +25 -83
  365. package/dist/index16.vue.d.cts +34 -0
  366. package/dist/index16.vue.d.ts +113 -24
  367. package/dist/index17.vue.d.cts +124 -0
  368. package/dist/index17.vue.d.ts +76 -110
  369. package/dist/index18.vue.d.cts +83 -0
  370. package/dist/index18.vue.d.ts +67 -73
  371. package/dist/index19.vue.d.cts +101 -0
  372. package/dist/index19.vue.d.ts +93 -59
  373. package/dist/index2.vue.d.cts +82 -0
  374. package/dist/index2.vue.d.ts +1 -2
  375. package/dist/index20.vue.d.cts +54 -0
  376. package/dist/index20.vue.d.ts +40 -88
  377. package/dist/index21.vue.d.cts +103 -0
  378. package/dist/index21.vue.d.ts +89 -41
  379. package/dist/index22.vue.d.cts +45 -0
  380. package/dist/index22.vue.d.ts +37 -96
  381. package/dist/index23.vue.d.cts +19 -0
  382. package/dist/index23.vue.d.ts +8 -35
  383. package/dist/{index28.vue.d.ts → index24.vue.d.cts} +5 -6
  384. package/dist/index24.vue.d.ts +650 -86
  385. package/dist/index25.vue.d.cts +96 -0
  386. package/dist/index25.vue.d.ts +86 -10
  387. package/dist/index26.vue.d.cts +111 -0
  388. package/dist/index26.vue.d.ts +3 -4
  389. package/dist/index27.vue.d.cts +80 -0
  390. package/dist/index27.vue.d.ts +3 -4
  391. package/dist/index3.vue.d.cts +87 -0
  392. package/dist/index3.vue.d.ts +2 -3
  393. package/dist/index4.vue.d.cts +37 -0
  394. package/dist/index4.vue.d.ts +5 -6
  395. package/dist/index5.vue.d.cts +133 -0
  396. package/dist/index5.vue.d.ts +2 -3
  397. package/dist/index6.vue.d.cts +29 -0
  398. package/dist/index6.vue.d.ts +25 -38
  399. package/dist/index7.vue.d.cts +32 -0
  400. package/dist/index7.vue.d.ts +117 -23
  401. package/dist/index8.vue.d.cts +127 -0
  402. package/dist/index8.vue.d.ts +17 -111
  403. package/dist/index9.vue.d.cts +34 -0
  404. package/dist/index9.vue.d.ts +38 -26
  405. package/dist/{menuAdapter.d.ts → public.d.ts} +2 -3
  406. package/dist/resolver.cjs +1 -2
  407. package/dist/resolver.d.cts +6 -4
  408. package/dist/resolver.d.ts +6 -4
  409. package/dist/resolver.js +1 -2
  410. package/dist/storage.cjs +1 -0
  411. package/dist/storage.js +1 -2
  412. package/dist/style.css +9864 -7702
  413. package/dist/types.d.cts +107 -0
  414. package/dist/types.d.ts +58 -0
  415. package/dist/types2.d.cts +58 -0
  416. package/dist/useCalendarEvents.d.cts +150 -0
  417. package/dist/useCalendarEvents.d.ts +3 -4
  418. package/dist/useCollapsePanel.d.cts +133 -0
  419. package/dist/useCollapsePanel.d.ts +1 -2
  420. package/dist/useCropperCore.d.cts +104 -0
  421. package/dist/useCropperCore.d.ts +12 -10
  422. package/dist/useDraggableLayout.d.cts +196 -0
  423. package/dist/useDraggableLayout.d.ts +18 -16
  424. package/dist/useDynamicFormState.d.cts +749 -0
  425. package/dist/useDynamicFormState.d.ts +234 -112
  426. package/dist/useEdgeInteraction.d.cts +324 -0
  427. package/dist/useEdgeInteraction.d.ts +6 -7
  428. package/dist/useFullscreen.d.cts +165 -0
  429. package/dist/useFullscreen.d.ts +1 -2
  430. package/dist/useGlobalSearch.d.cts +110 -0
  431. package/dist/useGlobalSearch.d.ts +17 -9
  432. package/dist/useInfiniteScroll.d.cts +177 -0
  433. package/dist/useInfiniteScroll.d.ts +11 -3
  434. package/dist/useQRCode.d.cts +89 -0
  435. package/dist/useQRCode.d.ts +7 -5
  436. package/dist/useSearchState.d.cts +871 -0
  437. package/dist/useSearchState.d.ts +828 -28
  438. package/dist/useSignatureHistory.d.cts +197 -0
  439. package/dist/useSignatureHistory.d.ts +9 -4
  440. package/dist/useSplitResize.d.cts +157 -0
  441. package/dist/useSplitResize.d.ts +3 -4
  442. package/dist/useTableQuery.cjs +3 -0
  443. package/dist/{useModalEdit.d.ts → useTableQuery.d.cts} +624 -211
  444. package/dist/useTableQuery.d.ts +1721 -0
  445. package/dist/useTableQuery.js +3 -0
  446. package/dist/useTimeSelection.d.cts +116 -0
  447. package/dist/useTimeSelection.d.ts +19 -8
  448. package/dist/useTreeOperations.d.cts +185 -0
  449. package/dist/useTreeOperations.d.ts +14 -12
  450. package/dist/useWorkflowValidation.d.cts +1051 -0
  451. package/dist/useWorkflowValidation.d.ts +66 -67
  452. package/dist/verification.d.cts +58 -0
  453. package/dist/verification.d.ts +58 -0
  454. package/package.json +101 -69
  455. package/dist/C_ActionBar-BAcfOfRw.css.map +0 -1
  456. package/dist/C_ActionBar-DG2HW7t5.css.map +0 -1
  457. package/dist/C_ActionBar.js.map +0 -1
  458. package/dist/C_ActionBar2.js.map +0 -1
  459. package/dist/C_AntV-D_jTK8oZ.css.map +0 -1
  460. package/dist/C_AntV-DanTAq22.css.map +0 -1
  461. package/dist/C_AntV.js.map +0 -1
  462. package/dist/C_AntV2.js.map +0 -1
  463. package/dist/C_AudioPlayer-BnYIJXPD.css.map +0 -1
  464. package/dist/C_AudioPlayer-ldTy9Y34.css.map +0 -1
  465. package/dist/C_AudioPlayer.js.map +0 -1
  466. package/dist/C_AudioPlayer2.js.map +0 -1
  467. package/dist/C_AvatarGroup-B9d-GJ9c.css.map +0 -1
  468. package/dist/C_AvatarGroup-SIzxuuZr.css.map +0 -1
  469. package/dist/C_AvatarGroup.js.map +0 -1
  470. package/dist/C_AvatarGroup2.js.map +0 -1
  471. package/dist/C_Barcode-CAU2mFcx.css.map +0 -1
  472. package/dist/C_Barcode-D2oJaEg3.css.map +0 -1
  473. package/dist/C_Barcode.js.map +0 -1
  474. package/dist/C_Barcode2.js.map +0 -1
  475. package/dist/C_Breadcrumb-BiH0d9AI.css.map +0 -1
  476. package/dist/C_Breadcrumb-Bqqrl8nX.css.map +0 -1
  477. package/dist/C_Breadcrumb.js.map +0 -1
  478. package/dist/C_Breadcrumb2.js.map +0 -1
  479. package/dist/C_Captcha-B3yrtG7t.css.map +0 -1
  480. package/dist/C_Captcha-D4hDdWDu.css.map +0 -1
  481. package/dist/C_Captcha.js.map +0 -1
  482. package/dist/C_Captcha2.js.map +0 -1
  483. package/dist/C_Cascade-CmCrLVft.css.map +0 -1
  484. package/dist/C_Cascade-U6A5AJJb.css.map +0 -1
  485. package/dist/C_Cascade.js.map +0 -1
  486. package/dist/C_Cascade2.js.map +0 -1
  487. package/dist/C_Chat-CF1SU7mc.css.map +0 -1
  488. package/dist/C_Chat-DeUv6uuI.css.map +0 -1
  489. package/dist/C_Chat.js.map +0 -1
  490. package/dist/C_Chat2.js.map +0 -1
  491. package/dist/C_City-DdkX6u64.css.map +0 -1
  492. package/dist/C_City-iP-dIvui.css.map +0 -1
  493. package/dist/C_City.js.map +0 -1
  494. package/dist/C_City2.js.map +0 -1
  495. package/dist/C_Code-BWmJMNS7.css.map +0 -1
  496. package/dist/C_Code-k14vjgVl.css.map +0 -1
  497. package/dist/C_Code.js.map +0 -1
  498. package/dist/C_Code2.js.map +0 -1
  499. package/dist/C_CollapsePanel-BSKcWSmY.css.map +0 -1
  500. package/dist/C_CollapsePanel-DRvRq8tB.css.map +0 -1
  501. package/dist/C_CollapsePanel.js.map +0 -1
  502. package/dist/C_CollapsePanel2.js.map +0 -1
  503. package/dist/C_ContextMenu-Bn_uhJSo.css.map +0 -1
  504. package/dist/C_ContextMenu-C9iuxG2n.css.map +0 -1
  505. package/dist/C_ContextMenu.js.map +0 -1
  506. package/dist/C_ContextMenu2.js.map +0 -1
  507. package/dist/C_Cron-BIQ2By9v.css.map +0 -1
  508. package/dist/C_Cron-BNSAGD6A.css.map +0 -1
  509. package/dist/C_Cron.js.map +0 -1
  510. package/dist/C_Cron2.js.map +0 -1
  511. package/dist/C_Date.js.map +0 -1
  512. package/dist/C_Date2.js.map +0 -1
  513. package/dist/C_Draggable-BDAbk4s5.css.map +0 -1
  514. package/dist/C_Draggable-UhfDLXop.css.map +0 -1
  515. package/dist/C_Draggable.js.map +0 -1
  516. package/dist/C_Draggable2.js.map +0 -1
  517. package/dist/C_Editor-CZOaChru.css.map +0 -1
  518. package/dist/C_Editor-kJAQq5z6.css.map +0 -1
  519. package/dist/C_Editor.js.map +0 -1
  520. package/dist/C_Editor2.js.map +0 -1
  521. package/dist/C_FilePreview-Bs_omgJS.css.map +0 -1
  522. package/dist/C_FilePreview-DbwoyF2j.css.map +0 -1
  523. package/dist/C_FilePreview.js.map +0 -1
  524. package/dist/C_FilePreview2.js.map +0 -1
  525. package/dist/C_Form-B_2ql62V.css.map +0 -1
  526. package/dist/C_Form-CX-7xsz3.css.map +0 -1
  527. package/dist/C_Form.js.map +0 -1
  528. package/dist/C_Form2.js.map +0 -1
  529. package/dist/C_FormSearch-C3F8peAY.css.map +0 -1
  530. package/dist/C_FormSearch-qW56bJPo.css.map +0 -1
  531. package/dist/C_FormSearch.js.map +0 -1
  532. package/dist/C_FormSearch2.js.map +0 -1
  533. package/dist/C_FormulaEditor-ChOvDbsZ.css.map +0 -1
  534. package/dist/C_FormulaEditor-mfiIUDY4.css.map +0 -1
  535. package/dist/C_FormulaEditor.js.map +0 -1
  536. package/dist/C_FormulaEditor2.js.map +0 -1
  537. package/dist/C_FullCalendar-C2nsqrgS.css.map +0 -1
  538. package/dist/C_FullCalendar-DdFtXVhy.css.map +0 -1
  539. package/dist/C_FullCalendar.js.map +0 -1
  540. package/dist/C_FullCalendar2.js.map +0 -1
  541. package/dist/C_GlobalSearch-Dq4Wo01K.css.map +0 -1
  542. package/dist/C_GlobalSearch-RB7J43gu.css.map +0 -1
  543. package/dist/C_GlobalSearch.js.map +0 -1
  544. package/dist/C_GlobalSearch2.js.map +0 -1
  545. package/dist/C_Guide.js.map +0 -1
  546. package/dist/C_Guide2.js.map +0 -1
  547. package/dist/C_Icon.js.map +0 -1
  548. package/dist/C_Icon2.js.map +0 -1
  549. package/dist/C_ImageCropper-CdTX2nxU.css.map +0 -1
  550. package/dist/C_ImageCropper-ilOqPklJ.css.map +0 -1
  551. package/dist/C_ImageCropper.js.map +0 -1
  552. package/dist/C_ImageCropper2.js.map +0 -1
  553. package/dist/C_Language.js.map +0 -1
  554. package/dist/C_Language2.js.map +0 -1
  555. package/dist/C_Login-B3qYkLrN.css.map +0 -1
  556. package/dist/C_Login-xMI1_ojE.css.map +0 -1
  557. package/dist/C_Login.js.map +0 -1
  558. package/dist/C_Login2.js.map +0 -1
  559. package/dist/C_Map-CWMMN58_.css.map +0 -1
  560. package/dist/C_Map-xSR2H-9o.css.map +0 -1
  561. package/dist/C_Map.js.map +0 -1
  562. package/dist/C_Map2.js.map +0 -1
  563. package/dist/C_Markdown-C7lTVJ1S.css.map +0 -1
  564. package/dist/C_Markdown-CZDm_baQ.css.map +0 -1
  565. package/dist/C_Markdown.js.map +0 -1
  566. package/dist/C_Markdown2.js.map +0 -1
  567. package/dist/C_Menu.js.map +0 -1
  568. package/dist/C_Menu2.js.map +0 -1
  569. package/dist/C_NotificationCenter-D7GGGWg7.css.map +0 -1
  570. package/dist/C_NotificationCenter-SSmeHA45.css.map +0 -1
  571. package/dist/C_NotificationCenter.js.map +0 -1
  572. package/dist/C_NotificationCenter2.js.map +0 -1
  573. package/dist/C_OrgChart-ChZu346B.css.map +0 -1
  574. package/dist/C_OrgChart-DqBufOv5.css.map +0 -1
  575. package/dist/C_OrgChart.js.map +0 -1
  576. package/dist/C_OrgChart2.js.map +0 -1
  577. package/dist/C_Progress.js.map +0 -1
  578. package/dist/C_Progress2.js.map +0 -1
  579. package/dist/C_QRCode-B_1lHUdx.css.map +0 -1
  580. package/dist/C_QRCode-CuQRYu0s.css.map +0 -1
  581. package/dist/C_QRCode.js.map +0 -1
  582. package/dist/C_QRCode2.js.map +0 -1
  583. package/dist/C_Signature-Bp-RBpAl.css.map +0 -1
  584. package/dist/C_Signature-Cb2VW1ok.css.map +0 -1
  585. package/dist/C_Signature.js.map +0 -1
  586. package/dist/C_Signature2.js.map +0 -1
  587. package/dist/C_Skeleton-BNPbaut7.css.map +0 -1
  588. package/dist/C_Skeleton-Djsjw8XY.css.map +0 -1
  589. package/dist/C_Skeleton.js.map +0 -1
  590. package/dist/C_Skeleton2.js.map +0 -1
  591. package/dist/C_SplitPane-CgGWYsRE.css.map +0 -1
  592. package/dist/C_SplitPane-DGf6WEeR.css.map +0 -1
  593. package/dist/C_SplitPane.js.map +0 -1
  594. package/dist/C_SplitPane2.js.map +0 -1
  595. package/dist/C_Steps-27Exh7PM.css.map +0 -1
  596. package/dist/C_Steps-DU9ZsFrs.css.map +0 -1
  597. package/dist/C_Steps.js.map +0 -1
  598. package/dist/C_Steps2.js.map +0 -1
  599. package/dist/C_Table--kbQaaBv.css.map +0 -1
  600. package/dist/C_Table-D631kdXC.css.map +0 -1
  601. package/dist/C_Table.js.map +0 -1
  602. package/dist/C_Table2.js +0 -4
  603. package/dist/C_Table2.js.map +0 -1
  604. package/dist/C_TagsView-BN8vMRsY.css.map +0 -1
  605. package/dist/C_TagsView-s1dnSJAV.css.map +0 -1
  606. package/dist/C_TagsView.js.map +0 -1
  607. package/dist/C_TagsView2.js.map +0 -1
  608. package/dist/C_Theme.js.map +0 -1
  609. package/dist/C_Theme2.js.map +0 -1
  610. package/dist/C_Time-BQ9PGy8B.css.map +0 -1
  611. package/dist/C_Time-CO73krC6.css.map +0 -1
  612. package/dist/C_Time.js.map +0 -1
  613. package/dist/C_Time2.js.map +0 -1
  614. package/dist/C_Timeline-4rk0Dzgn.css.map +0 -1
  615. package/dist/C_Timeline-DdESmqwL.css.map +0 -1
  616. package/dist/C_Timeline.js.map +0 -1
  617. package/dist/C_Timeline2.js.map +0 -1
  618. package/dist/C_Transfer-B-vjvhjI.css.map +0 -1
  619. package/dist/C_Transfer-EzdHzZNv.css.map +0 -1
  620. package/dist/C_Transfer.js.map +0 -1
  621. package/dist/C_Transfer2.js.map +0 -1
  622. package/dist/C_Tree-CsXgGfhn.css.map +0 -1
  623. package/dist/C_Tree-P7eRpnOa.css.map +0 -1
  624. package/dist/C_Tree.js.map +0 -1
  625. package/dist/C_Tree2.js.map +0 -1
  626. package/dist/C_Upload-CHjiVVh7.css.map +0 -1
  627. package/dist/C_Upload-DE3OLsZD.css.map +0 -1
  628. package/dist/C_Upload.js.map +0 -1
  629. package/dist/C_Upload2.js.map +0 -1
  630. package/dist/C_VideoPlayer-CnaNOFtW.css.map +0 -1
  631. package/dist/C_VideoPlayer-cnP88zNV.css.map +0 -1
  632. package/dist/C_VideoPlayer.js.map +0 -1
  633. package/dist/C_VideoPlayer2.js.map +0 -1
  634. package/dist/C_VtableGantt-CZlJgvpC.css.map +0 -1
  635. package/dist/C_VtableGantt-DKfQkql0.css.map +0 -1
  636. package/dist/C_VtableGantt.js.map +0 -1
  637. package/dist/C_VtableGantt2.js.map +0 -1
  638. package/dist/C_WaterFall-BJ_39ext.css.map +0 -1
  639. package/dist/C_WaterFall-cYc1vntE.css.map +0 -1
  640. package/dist/C_WaterFall.js.map +0 -1
  641. package/dist/C_WaterFall2.js.map +0 -1
  642. package/dist/C_WorkFlow-BFzRGGhJ.css.map +0 -1
  643. package/dist/C_WorkFlow-DSyCOvRp.css.map +0 -1
  644. package/dist/C_WorkFlow.js.map +0 -1
  645. package/dist/C_WorkFlow2.js.map +0 -1
  646. package/dist/_shared.cjs +0 -1
  647. package/dist/_shared.d.cts +0 -2
  648. package/dist/_shared.d.ts +0 -2
  649. package/dist/_shared.js +0 -1
  650. package/dist/city.js.map +0 -1
  651. package/dist/index.cjs.map +0 -1
  652. package/dist/index.js.map +0 -1
  653. package/dist/menuAdapter.js +0 -2
  654. package/dist/menuAdapter.js.map +0 -1
  655. package/dist/resolver.cjs.map +0 -1
  656. package/dist/resolver.js.map +0 -1
  657. package/dist/storage.js.map +0 -1
  658. /package/dist/{chunk.js → chunk.cjs} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"file":"C_Form2.js","names":["formItems","formItems","formItems","formItems","formItems","formItems","formItems","$attrs"],"sources":["../src/components/C_Form/composables/useFormConfig.ts","../src/components/C_Form/composables/useFormDirty.ts","../src/components/C_Form/composables/useFormState.ts","../src/components/C_Form/composables/useFormRenderer.ts","../src/components/C_Form/layouts/Default/index.vue","../src/components/C_Form/layouts/Default/index.vue","../src/components/C_Form/layouts/Inline/index.vue","../src/components/C_Form/layouts/Inline/index.vue","../src/components/C_Form/layouts/Grid/index.vue","../src/components/C_Form/layouts/Grid/index.vue","../src/components/C_Form/layouts/Card/index.vue","../src/components/C_Form/layouts/Card/index.vue","../src/components/C_Form/layouts/Tabs/index.vue","../src/components/C_Form/layouts/Tabs/index.vue","../src/components/C_Form/layouts/Steps/index.vue","../src/components/C_Form/layouts/Steps/index.vue","../src/components/C_Form/composables/useDynamicFormState.ts","../src/components/C_Form/layouts/Dynamic/index.vue","../src/components/C_Form/layouts/Dynamic/index.vue","../src/components/C_Form/layouts/Custom/index.vue","../src/components/C_Form/layouts/Custom/index.vue","../src/components/C_Form/index.vue","../src/components/C_Form/index.vue"],"sourcesContent":["/*\n * @Author: ChenYu ycyplus@gmail.com\n * @Description: C_Form 配置解析 Composable — 统一 FormConfig 接口与默认值\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n */\n\nimport type {\n LayoutType,\n LabelPlacement,\n FormMode,\n GridLayoutConfig,\n InlineLayoutConfig,\n CardLayoutConfig,\n TabsLayoutConfig,\n StepsLayoutConfig,\n DynamicLayoutConfig,\n CustomLayoutConfig,\n DynamicFieldConfig,\n RenderMode,\n FormOption,\n} from '../types'\n\n/* =================== FormConfig 类型定义 =================== */\n\n/** 布局回调事件 — 替代原先 16 个 emit 中的纯透传事件 */\nexport interface LayoutCallbacks {\n /* tabs 布局回调 */\n onTabChange?: (tabKey: string, tabIndex: number) => void\n onTabValidate?: (tabKey: string) => void\n\n /* steps 布局回调 */\n onStepChange?: (stepIndex: number, stepKey: string) => void\n onStepBeforeChange?: (currentStep: number, targetStep: number) => void\n onStepValidate?: (stepIndex: number) => void\n\n /* dynamic 布局回调 */\n onFieldAdd?: (fieldConfig: DynamicFieldConfig) => void\n onFieldRemove?: (fieldId: string) => void\n onFieldToggle?: (fieldId: string, visible: boolean) => void\n onFieldsClear?: () => void\n\n /* custom 布局回调 */\n onRenderModeChange?: (mode: RenderMode) => void\n onGroupToggle?: (groupKey: string, collapsed: boolean) => void\n onGroupReset?: (groupKey: string) => void\n onFieldsChange?: (fields: FormOption[]) => void\n}\n\n/**\n * C_Form 统一配置接口\n * @description 收拢原先 13 个分散 Props 为 1 个 config 对象\n * 默认值均在 FORM_DEFAULTS 中集中管理\n */\nexport interface FormConfig extends LayoutCallbacks {\n /** 布局类型,默认 'default' */\n layout?: LayoutType\n /** 标签位置,默认 'left' */\n labelPlacement?: LabelPlacement\n /** 标签宽度,默认 'auto' */\n labelWidth?: string | number\n /** 尺寸,默认 'medium' */\n size?: 'small' | 'medium' | 'large'\n /** 禁用整个表单,默认 false */\n disabled?: boolean\n /** 只读,默认 false */\n readonly?: boolean\n /** 显示默认提交/重置按钮,默认 true */\n showActions?: boolean\n /** 值变化时自动校验,默认 false */\n validateOnChange?: boolean\n\n /* ===== v0.8.0 新增 ===== */\n\n /** 表单模式:create = 新建(默认),edit = 编辑(配合 initialValues 实现回填 + 脏检查) */\n mode?: FormMode\n /** 编辑模式初始值:设置后自动作为脏检查基准 */\n initialValues?: Record<string, any>\n\n /* ===== 布局级配置 ===== */\n grid?: GridLayoutConfig\n inline?: InlineLayoutConfig\n card?: CardLayoutConfig\n tabs?: TabsLayoutConfig\n steps?: StepsLayoutConfig\n dynamic?: DynamicLayoutConfig\n custom?: CustomLayoutConfig\n}\n\n/** 解析后的配置(所有必填字段均已设置默认值) */\nexport interface ResolvedFormConfig extends Required<\n Omit<\n FormConfig,\n | keyof LayoutCallbacks\n | 'grid'\n | 'inline'\n | 'card'\n | 'tabs'\n | 'steps'\n | 'dynamic'\n | 'custom'\n | 'initialValues'\n >\n> {\n /* 布局配置保留可选,因为只有对应 layout 时才有值 */\n grid?: GridLayoutConfig\n inline?: InlineLayoutConfig\n card?: CardLayoutConfig\n tabs?: TabsLayoutConfig\n steps?: StepsLayoutConfig\n dynamic?: DynamicLayoutConfig\n custom?: CustomLayoutConfig\n /* 回调保留可选 */\n onTabChange?: LayoutCallbacks['onTabChange']\n onTabValidate?: LayoutCallbacks['onTabValidate']\n onStepChange?: LayoutCallbacks['onStepChange']\n onStepBeforeChange?: LayoutCallbacks['onStepBeforeChange']\n onStepValidate?: LayoutCallbacks['onStepValidate']\n onFieldAdd?: LayoutCallbacks['onFieldAdd']\n onFieldRemove?: LayoutCallbacks['onFieldRemove']\n onFieldToggle?: LayoutCallbacks['onFieldToggle']\n onFieldsClear?: LayoutCallbacks['onFieldsClear']\n onRenderModeChange?: LayoutCallbacks['onRenderModeChange']\n onGroupToggle?: LayoutCallbacks['onGroupToggle']\n onGroupReset?: LayoutCallbacks['onGroupReset']\n onFieldsChange?: LayoutCallbacks['onFieldsChange']\n /* v0.8.0 */\n initialValues?: Record<string, any>\n}\n\n/* =================== 默认值常量 =================== */\n\nexport const FORM_DEFAULTS: ResolvedFormConfig = {\n layout: 'default',\n labelPlacement: 'left',\n labelWidth: 'auto',\n size: 'medium',\n disabled: false,\n readonly: false,\n showActions: true,\n validateOnChange: false,\n mode: 'create',\n} as const\n\n/** 拥有自身控制按钮的布局(不显示默认操作按钮) */\nexport const LAYOUTS_WITH_OWN_CONTROLS: readonly LayoutType[] = [\n 'steps',\n 'custom',\n] as const\n\n/* =================== 核心函数 =================== */\n\n/**\n * 解析 FormConfig,合并默认值\n * @param config - 用户传入的配置(可选)\n * @returns 具有完整默认值的 ResolvedFormConfig\n */\nexport function resolveFormConfig(config?: FormConfig): ResolvedFormConfig {\n return { ...FORM_DEFAULTS, ...config }\n}\n\n/**\n * 计算是否显示默认操作按钮\n * @param resolved - 已解析的配置\n */\nexport function shouldShowActions(resolved: ResolvedFormConfig): boolean {\n if (resolved.showActions === false) return false\n if (LAYOUTS_WITH_OWN_CONTROLS.includes(resolved.layout)) return false\n return true\n}\n","/*\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2026-03-13 00:22:28\n * @LastEditors: ChenYu ycyplus@gmail.com\n * @LastEditTime: 2026-03-13 00:26:33\n * @FilePath: \\robot\\naive-ui-components\\src\\components\\C_Form\\composables\\useFormDirty.ts\n * @Description: 表单脏检查引擎 — 追踪初始快照与当前值的差异\n * Copyright (c) 2026 by CHENY, All Rights Reserved 😎.\n */\n\nimport { ref, computed, type Ref } from 'vue'\nimport type { FormModel } from '../types'\n\n/**\n * 深度比较两个值是否相等(支持基本类型、数组、普通对象)\n */\nfunction deepEqual(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) return true\n if (a == null || b == null) return a === b\n if (typeof a !== typeof b) return false\n\n if (Array.isArray(a)) {\n if (!Array.isArray(b) || a.length !== b.length) return false\n return a.every((v, i) => deepEqual(v, b[i]))\n }\n\n if (typeof a === 'object') {\n const keysA = Object.keys(a as Record<string, unknown>)\n const keysB = Object.keys(b as Record<string, unknown>)\n if (keysA.length !== keysB.length) return false\n return keysA.every(key =>\n deepEqual(\n (a as Record<string, unknown>)[key],\n (b as Record<string, unknown>)[key]\n )\n )\n }\n\n return false\n}\n\n/**\n * 深拷贝(去除响应式引用)\n */\nfunction snapshot(obj: Record<string, unknown>): Record<string, unknown> {\n return JSON.parse(JSON.stringify(obj))\n}\n\nexport interface UseFormDirtyReturn {\n /** 表单是否已修改 */\n isDirty: Ref<boolean>\n /** 获取发生变化的字段名列表 */\n getChangedFields: () => string[]\n /** 检查指定字段是否脏 */\n isFieldDirty: (field: string) => boolean\n /** 保存当前值为干净快照 */\n markAsClean: () => void\n}\n\n/**\n * 脏检查 Composable — 追踪 formModel 相对于初始快照的变化\n * @param formModel 响应式表单数据对象(reactive)\n */\nexport function useFormDirty(formModel: FormModel): UseFormDirtyReturn {\n const initialSnapshot: Ref<Record<string, unknown>> = ref({})\n\n const isDirty = computed(() => getChangedFields().length > 0)\n\n /** 获取与初始快照相比发生变化的字段名列表 */\n function getChangedFields(): string[] {\n const snap = initialSnapshot.value\n const allKeys = new Set([...Object.keys(snap), ...Object.keys(formModel)])\n const changed: string[] = []\n for (const key of allKeys) {\n if (!deepEqual(snap[key], (formModel as Record<string, unknown>)[key])) {\n changed.push(key)\n }\n }\n return changed\n }\n\n /** 检查指定字段是否相对于初始快照已修改 */\n function isFieldDirty(field: string): boolean {\n return !deepEqual(\n initialSnapshot.value[field],\n (formModel as Record<string, unknown>)[field]\n )\n }\n\n /** 将当前 formModel 保存为干净快照 */\n function markAsClean(): void {\n initialSnapshot.value = snapshot(formModel as Record<string, unknown>)\n }\n\n return {\n isDirty,\n getChangedFields,\n isFieldDirty,\n markAsClean,\n }\n}\n","/*\n * @Description: C_Form 状态引擎 Composable — 表单数据、校验规则、验证 API、脏检查、联动\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n */\n\nimport {\n reactive,\n ref,\n computed,\n watch,\n nextTick,\n onMounted,\n type ComputedRef,\n type Ref,\n} from 'vue'\nimport type { FormInst, FormRules } from 'naive-ui/es/form'\nimport { mergeRules } from '@robot-admin/form-validate'\nimport type {\n FormOption,\n FormModel,\n ComponentType,\n SubmitEventPayload,\n OptionItem,\n} from '../types'\nimport type { ResolvedFormConfig } from './useFormConfig'\nimport { useFormDirty } from './useFormDirty'\n\n/* =================== 默认值映射 =================== */\n\nconst DEFAULT_VALUES: Record<ComponentType, unknown> = {\n input: '',\n textarea: '',\n editor: '',\n select: null,\n datePicker: null,\n daterange: null,\n timePicker: null,\n cascader: null,\n colorPicker: null,\n checkbox: null,\n upload: [],\n radio: '',\n inputNumber: null,\n slider: null,\n rate: null,\n switch: null,\n} as const\n\nconst getDefaultValue = (type: ComponentType): unknown => {\n return DEFAULT_VALUES[type] ?? null\n}\n\n/* =================== Composable =================== */\n\n/**\n * C_Form 状态引擎 — 管理表单数据模型、校验规则、验证 API、字段操作、脏检查、联动\n */\nexport function useFormState(\n options: ComputedRef<FormOption[]>,\n config: ComputedRef<ResolvedFormConfig>,\n formRef: Ref<FormInst | null>,\n emit: {\n (e: 'update:modelValue', model: FormModel): void\n (e: 'validate-success', model: FormModel): void\n (e: 'validate-error', errors: unknown): void\n (e: 'submit', payload: SubmitEventPayload): void\n }\n) {\n /* ===== 响应式状态 ===== */\n const formModel = reactive<FormModel>({})\n const formRules = reactive<FormRules>({})\n\n /** 异步选项缓存:prop → OptionItem[] */\n const asyncOptionsCache = ref<Record<string, OptionItem[]>>({})\n /** 异步选项 loading 状态:prop → boolean */\n const asyncLoadingMap = ref<Record<string, boolean>>({})\n\n /* ===== 脏检查引擎 ===== */\n const { isDirty, getChangedFields, isFieldDirty, markAsClean } =\n useFormDirty(formModel)\n\n /* ===== 可见字段 ===== */\n const visibleOptions = computed(() =>\n options.value.filter(item => {\n if (item.show === false) return false\n if (item.showWhen) return item.showWhen(formModel)\n return true\n })\n )\n\n /* ===== 初始化 ===== */\n const initialize = (): void => {\n try {\n Object.keys(formRules).forEach(key => delete formRules[key])\n\n options.value.forEach(item => {\n if (!(item.prop in formModel)) {\n formModel[item.prop] =\n item.value !== undefined\n ? item.value\n : getDefaultValue(item.type as ComponentType)\n }\n\n syncRulesForField(item)\n })\n\n /* 初始化结束后保存干净快照 */\n nextTick(() => markAsClean())\n\n /* 加载所有异步选项 */\n loadAllAsyncOptions()\n } catch (error) {\n console.error('[C_Form] 初始化失败:', error)\n }\n }\n\n /* ===== 校验规则同步 ===== */\n\n /**\n * 同步单个字段的校验规则(支持静态 rules + 动态 rulesWhen + crossFieldValidator)\n */\n function syncRulesForField(item: FormOption): void {\n const staticRules = item.rulesWhen\n ? item.rulesWhen(formModel)\n : (item.rules ?? [])\n\n const allRules = [...staticRules]\n\n /* 跨字段校验转化为 naive-ui validator */\n if (item.crossFieldValidator) {\n const crossFn = item.crossFieldValidator\n allRules.push({\n validator: () => {\n const errMsg = crossFn(formModel)\n return errMsg ? Promise.reject(new Error(errMsg)) : Promise.resolve()\n },\n trigger: ['change', 'blur'],\n } as any)\n }\n\n if (allRules.length === 0) {\n delete formRules[item.prop]\n return\n }\n\n const allHaveValidator = allRules.every(\n r => typeof (r as Record<string, unknown>).validator === 'function'\n )\n formRules[item.prop] = allHaveValidator ? mergeRules(allRules) : allRules\n }\n\n /**\n * 刷新所有字段的动态规则(当 formModel 变化时调用)\n */\n function refreshDynamicRules(): void {\n const itemsWithDynamicRules = options.value.filter(\n item => item.rulesWhen || item.crossFieldValidator\n )\n for (const item of itemsWithDynamicRules) {\n syncRulesForField(item)\n }\n }\n\n /* ===== 异步选项加载 ===== */\n\n /** 加载单个字段的异步选项数据 */\n async function loadAsyncOptions(item: FormOption): Promise<void> {\n if (!item.asyncOptions) return\n const { prop } = item\n asyncLoadingMap.value[prop] = true\n try {\n const result = await item.asyncOptions(formModel)\n asyncOptionsCache.value[prop] = result\n } catch (error) {\n console.warn(`[C_Form] asyncOptions 加载失败 (${prop}):`, error)\n asyncOptionsCache.value[prop] = []\n } finally {\n asyncLoadingMap.value[prop] = false\n }\n }\n\n /** 加载所有带 asyncOptions 的字段选项 */\n function loadAllAsyncOptions(): void {\n options.value\n .filter(item => item.asyncOptions)\n .forEach(item => loadAsyncOptions(item))\n }\n\n /* ===== 联动赋值引擎 ===== */\n\n /** 执行联动赋值 — 根据 valueWhen 计算并写入对应字段值 */\n function applyValueWhen(): void {\n const itemsWithValueWhen = options.value.filter(item => item.valueWhen)\n for (const item of itemsWithValueWhen) {\n const computed = item.valueWhen!(formModel)\n if (computed !== undefined && formModel[item.prop] !== computed) {\n formModel[item.prop] = computed\n }\n }\n }\n\n /* ===== 字段变化处理 ===== */\n const handleFieldChange = (field: string): void => {\n /* 联动赋值 */\n applyValueWhen()\n\n /* 刷新动态规则 */\n refreshDynamicRules()\n\n /* 触发依赖本字段的异步选项重载 */\n options.value\n .filter(item => {\n if (!item.asyncOptions) return false\n const deps = item.dependsOn\n if (!deps) return false\n return Array.isArray(deps) ? deps.includes(field) : deps === field\n })\n .forEach(item => loadAsyncOptions(item))\n\n /* 变化时校验 */\n if (config.value.validateOnChange) {\n nextTick(() => {\n validateField(field).catch(() => {})\n })\n }\n }\n\n /* ===== 验证 API ===== */\n const validate = async (): Promise<void> => {\n if (!formRef.value) {\n throw new Error('[C_Form] 表单引用不存在')\n }\n\n try {\n await formRef.value.validate()\n emit('validate-success', getModel())\n } catch (errors) {\n emit('validate-error', errors)\n throw errors\n }\n }\n\n const validateField = async (field: string | string[]): Promise<void> => {\n if (!formRef.value) {\n throw new Error('[C_Form] 表单引用不存在')\n }\n\n const fields = Array.isArray(field) ? field : [field]\n\n try {\n await formRef.value.validate()\n } catch (allErrors: unknown) {\n if (!Array.isArray(allErrors)) throw allErrors\n\n const targetErrors = allErrors.filter((errorGroup: unknown[]) =>\n errorGroup?.some(err => {\n const e = err as Record<string, unknown>\n return typeof e.field === 'string' && fields.includes(e.field)\n })\n )\n\n if (targetErrors.length > 0) {\n throw targetErrors\n }\n }\n }\n\n const clearValidation = (field?: string | string[]): void => {\n if (!formRef.value) return\n\n if (field) {\n const fields = Array.isArray(field) ? field : [field]\n fields.forEach(fieldName => {\n if (formModel[fieldName] !== undefined) {\n const currentValue = formModel[fieldName]\n formModel[fieldName] = currentValue\n }\n })\n } else {\n formRef.value.restoreValidation()\n }\n }\n\n const validateByFilter = async (\n filterFn: (option: FormOption) => boolean,\n context: string\n ): Promise<boolean> => {\n try {\n const fields = options.value.filter(filterFn).map(option => option.prop)\n if (fields.length === 0) return true\n await validateField(fields)\n return true\n } catch (error) {\n console.warn(`[C_Form] ${context}验证失败:`, error)\n return false\n }\n }\n\n const validateStep = async (stepIndex: number): Promise<boolean> => {\n const stepKey = config.value.steps?.steps?.[stepIndex]?.key\n if (!stepKey) return true\n return validateByFilter(\n option => option.layout?.step === stepKey,\n `步骤 ${stepIndex} `\n )\n }\n\n const validateTab = async (tabKey: string): Promise<boolean> => {\n return validateByFilter(\n option => option.layout?.tab === tabKey,\n `标签页 ${tabKey} `\n )\n }\n\n const validateDynamicFields = async (): Promise<boolean> => {\n return validateByFilter(\n option => Boolean(option.layout?.dynamic),\n '动态字段 '\n )\n }\n\n const validateCustomGroup = async (groupKey: string): Promise<boolean> => {\n return validateByFilter(\n option => option.layout?.group === groupKey,\n `自定义分组 ${groupKey} `\n )\n }\n\n /* ===== 数据 API ===== */\n const getModel = (): FormModel => ({ ...formModel })\n\n const setFields = (fields: FormModel): void => {\n Object.assign(formModel, fields)\n }\n\n const resetFields = (): void => {\n try {\n clearValidation()\n\n options.value.forEach(item => {\n const defaultValue =\n item.value !== undefined\n ? item.value\n : getDefaultValue(item.type as ComponentType)\n\n formModel[item.prop] = defaultValue\n })\n\n nextTick(() => markAsClean())\n } catch (error) {\n console.error('[C_Form] 重置表单失败:', error)\n }\n }\n\n const setFieldValue = async (\n field: string,\n value: unknown,\n shouldValidate: boolean = false\n ): Promise<void> => {\n formModel[field] = value\n if (shouldValidate) {\n await validateField(field)\n }\n }\n\n const getFieldValue = (field: string): unknown => formModel[field]\n\n const setFieldsValue = async (\n fields: FormModel,\n shouldValidate: boolean = false\n ): Promise<void> => {\n Object.assign(formModel, fields)\n if (shouldValidate) {\n await validate()\n }\n }\n\n /* ===== 提交 & 重置 ===== */\n const handleSubmit = async (): Promise<void> => {\n try {\n await validate()\n emit('submit', { model: getModel(), form: formRef.value! })\n } catch (error) {\n console.warn('[C_Form] 表单验证失败:', error)\n }\n }\n\n /* ===== 生命周期 ===== */\n onMounted(() => {\n initialize()\n\n watch(\n () => options.value,\n () => initialize(),\n { deep: true }\n )\n\n watch(\n () => formModel,\n val => emit('update:modelValue', { ...val }),\n { deep: true }\n )\n })\n\n return {\n formModel,\n formRules,\n visibleOptions,\n initialize,\n handleFieldChange,\n /* 验证 API */\n validate,\n validateField,\n validateStep,\n validateTab,\n validateDynamicFields,\n validateCustomGroup,\n clearValidation,\n /* 数据 API */\n getModel,\n setFields,\n resetFields,\n setFieldValue,\n getFieldValue,\n setFieldsValue,\n /* 操作 */\n handleSubmit,\n handleReset: resetFields,\n /* v0.8.0 新增 */\n isDirty,\n getChangedFields,\n isFieldDirty,\n markAsClean,\n asyncOptionsCache,\n asyncLoadingMap,\n }\n}\n","/*\n * @Description: C_Form 渲染引擎 Composable — 统一组件注册表 + formItems 生成\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n */\n\nimport {\n computed,\n h,\n type VNode,\n type ComputedRef,\n type Component,\n type Ref,\n} from 'vue'\n\nimport type { FormOption, FormModel, OptionItem } from '../types'\nimport type { ResolvedFormConfig } from './useFormConfig'\n\n/* =================== 组件映射类型 =================== */\n\nexport type ComponentMap = Record<string, Component>\n\n/* =================== 渲染器类型 =================== */\n\nexport type FormRenderer = (\n baseProps: Record<string, any>,\n item: FormOption,\n config: ResolvedFormConfig,\n ctx?: { slots?: Record<string, any>; components?: ComponentMap }\n) => VNode | null\n\n/* =================== 渲染器参数 =================== */\n\nexport interface UseFormRendererOptions {\n formModel: FormModel\n visibleOptions: ComputedRef<FormOption[]>\n config: ComputedRef<ResolvedFormConfig>\n handleFieldChange: (field: string) => void\n componentMap: ComponentMap\n instanceSlots?: Record<string, any>\n asyncOptionsCache: Ref<Record<string, OptionItem[]>>\n asyncLoadingMap: Ref<Record<string, boolean>>\n}\n\n/* =================== 帮助工具 =================== */\n\n/** 解析字段级 disabled/readonly(字段级 > 全局级) */\nfunction resolveFieldFlag(\n flag: boolean | ((model: Record<string, any>) => boolean) | undefined,\n globalFlag: boolean,\n formModel: FormModel\n): boolean {\n if (flag === undefined) return globalFlag\n return typeof flag === 'function' ? flag(formModel) : flag\n}\n\n/* =================== 渲染器工厂 =================== */\n\n/** 根据组件映射表構建内置渲染器集合 */\nfunction buildRenderers(C: ComponentMap): Record<string, FormRenderer> {\n return {\n input: props => h(C.NInput, { ...props }),\n textarea: props => h(C.NInput, { ...props, type: 'textarea' }),\n inputNumber: props => h(C.NInputNumber, { ...props }),\n switch: props => h(C.NSwitch, { ...props }),\n slider: props => h(C.NSlider, { ...props }),\n rate: props => h(C.NRate, { ...props }),\n datePicker: props => h(C.NDatePicker, { ...props }),\n daterange: props => h(C.NDatePicker, { ...props, type: 'daterange' }),\n timePicker: props => h(C.NTimePicker, { ...props }),\n cascader: props => h(C.NCascader, { ...props }),\n colorPicker: props => h(C.NColorPicker, { ...props }),\n\n select: (baseProps, item) =>\n h(C.NSelect, {\n ...baseProps,\n options:\n item.children?.map((child: OptionItem) => ({\n value: child.value,\n label: child.label,\n disabled: child.disabled,\n })) || [],\n }),\n\n checkbox: (baseProps, item) =>\n h(\n C.NCheckboxGroup,\n { ...baseProps },\n {\n default: () =>\n h(\n C.NSpace,\n {},\n {\n default: () =>\n item.children?.map((child: OptionItem) =>\n h(C.NCheckbox, {\n value: child.value,\n label: child.label,\n disabled: child.disabled,\n key: String(child.value),\n })\n ) || [],\n }\n ),\n }\n ),\n\n radio: (baseProps, item) =>\n h(\n C.NRadioGroup,\n { ...baseProps },\n {\n default: () =>\n h(\n C.NSpace,\n {},\n {\n default: () =>\n item.children?.map((child: OptionItem) =>\n h(\n C.NRadio,\n {\n value: child.value,\n disabled: child.disabled,\n key: String(child.value),\n },\n { default: () => child.label }\n )\n ) || [],\n }\n ),\n }\n ),\n\n upload: (baseProps, item, _config, ctx) =>\n h(\n C.NUpload,\n {\n fileList: baseProps.value || [],\n 'onUpdate:fileList': (fileList: unknown[]) => {\n baseProps['onUpdate:value']?.(fileList)\n },\n ...item.attrs,\n },\n {\n trigger: () =>\n ctx?.slots?.['uploadClick']?.() ||\n h(C.NButton, { type: 'primary' }, { default: () => '选择文件' }),\n tip: () => ctx?.slots?.['uploadTip']?.() || null,\n }\n ),\n\n editor: (baseProps, item, config) =>\n h(C.C_Editor, {\n editorId: `editor-${item.prop}`,\n modelValue: baseProps.value || '',\n placeholder: item.placeholder,\n disabled: config.disabled,\n readonly: config.readonly,\n 'onUpdate:modelValue': (value: string) => {\n baseProps['onUpdate:value']?.(value)\n },\n ...item.attrs,\n }),\n }\n}\n\n/** 自定义渲染器扩展存储 */\nconst customRenderers: Record<string, FormRenderer> = {}\n\n/**\n * 运行时注册自定义渲染器 — 开闭原则\n */\nexport function registerRenderer(type: string, renderer: FormRenderer) {\n customRenderers[type] = renderer\n}\n\n/* =================== 带选项类型集合 =================== */\n\nconst OPTION_TYPES = new Set(['select', 'checkbox', 'radio', 'cascader'])\n\n/* =================== Composable =================== */\n\n/**\n * 渲染引擎 Composable — 生成 formItems VNode 数组\n *\n * v0.8.0 增强:\n * - 字段级 disabled / readonly\n * - help / tooltip label 渲染\n * - asyncOptions 远程选项合并\n * - loading 占位\n */\nexport function useFormRenderer(opts: UseFormRendererOptions) {\n const {\n formModel,\n visibleOptions,\n config,\n handleFieldChange,\n componentMap,\n instanceSlots,\n asyncOptionsCache,\n asyncLoadingMap,\n } = opts\n\n const C = componentMap\n const renderers = { ...buildRenderers(C), ...customRenderers }\n\n /* ===== 基础 Props 生成 ===== */\n\n const getBaseProps = (item: FormOption): Record<string, unknown> => {\n const baseProps: Record<string, unknown> = {\n value: formModel[item.prop],\n 'onUpdate:value': (value: unknown) => {\n formModel[item.prop] = value\n handleFieldChange(item.prop)\n },\n disabled: resolveFieldFlag(\n item.disabled,\n config.value.disabled,\n formModel\n ),\n readonly: resolveFieldFlag(\n item.readonly,\n config.value.readonly,\n formModel\n ),\n }\n\n if (item.type === 'textarea') {\n baseProps.type = 'textarea'\n }\n\n if (item.placeholder) {\n baseProps.placeholder = item.placeholder\n }\n\n return baseProps\n }\n\n /* ===== 选项合并(静态 children + asyncOptions 缓存) ===== */\n\n /** 合并静态 children 与 asyncOptions 缓存 */\n function resolveChildren(item: FormOption): OptionItem[] {\n const staticChildren = item.children ?? []\n const asyncChildren = asyncOptionsCache.value[item.prop] ?? []\n return asyncChildren.length > 0 ? asyncChildren : staticChildren\n }\n\n /* ===== 表单项控件渲染 ===== */\n\n const renderFormItem = (item: FormOption): VNode | null => {\n try {\n /* 对带选项的控件,合并异步/静态选项 */\n const isOptionType = OPTION_TYPES.has(item.type)\n const isLoading = asyncLoadingMap.value[item.prop]\n\n const effectiveItem = isOptionType\n ? { ...item, children: resolveChildren(item) }\n : item\n\n const renderer = renderers[effectiveItem.type]\n if (!renderer) {\n console.warn(`[C_Form] 未支持的组件类型: ${effectiveItem.type}`)\n return null\n }\n\n const baseProps = getBaseProps(effectiveItem)\n\n /* 异步加载中:select 显示 loading */\n if (isLoading && effectiveItem.type === 'select') {\n baseProps.loading = true\n }\n\n return renderer(\n { ...baseProps, ...effectiveItem.attrs },\n effectiveItem,\n config.value,\n { slots: instanceSlots, components: C }\n )\n } catch (error) {\n console.error(`[C_Form] 渲染表单项失败:`, error, item)\n return null\n }\n }\n\n /* ===== Label 渲染(支持 help tooltip) ===== */\n\n /** 渲染带 help tooltip 的 label,若无 help 则返回纯文本 */\n function renderLabel(item: FormOption): VNode | string | undefined {\n if (!item.label) return undefined\n\n if (!item.help) return item.label\n\n return h(\n 'span',\n { style: 'display:inline-flex;align-items:center;gap:4px' },\n [\n item.label,\n h(\n C.NTooltip,\n { trigger: 'hover' },\n {\n trigger: () =>\n h('span', {\n style: 'cursor:help;opacity:0.5;font-size:14px',\n innerHTML: '&#9432;', // ℹ\n }),\n default: () => item.help,\n }\n ),\n ]\n )\n }\n\n /* ===== formItems VNode[] ===== */\n\n const formItems = computed(() =>\n visibleOptions.value.map(item => {\n const hasRules = !!(\n item.rules?.length ||\n item.rulesWhen ||\n item.crossFieldValidator\n )\n const label = renderLabel(item)\n\n return h(\n C.NFormItem,\n {\n label: typeof label === 'string' ? label : undefined,\n path: item.prop,\n key: item.prop,\n required: hasRules,\n },\n {\n ...(typeof label !== 'string' && label ? { label: () => label } : {}),\n default: () => renderFormItem(item),\n }\n )\n })\n )\n\n return { renderFormItem, formItems, getBaseProps }\n}\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-01\r\n * @Description: 卡片布局 - 基础默认布局\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"c-form-default\">\r\n <template v-for=\"item in formItems\" :key=\"item.key\">\r\n <component :is=\"item\" />\r\n </template>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { type VNode } from \"vue\";\r\n\r\ninterface Props {\r\n formItems: VNode[];\r\n layoutConfig?: any;\r\n options?: any[];\r\n}\r\n\r\ndefineProps<Props>();\r\n</script>\r\n\r\n<style scoped>\r\n.c-form-default {\r\n width: 100%;\r\n}\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-01\r\n * @Description: 卡片布局 - 基础默认布局\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"c-form-default\">\r\n <template v-for=\"item in formItems\" :key=\"item.key\">\r\n <component :is=\"item\" />\r\n </template>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { type VNode } from \"vue\";\r\n\r\ninterface Props {\r\n formItems: VNode[];\r\n layoutConfig?: any;\r\n options?: any[];\r\n}\r\n\r\ndefineProps<Props>();\r\n</script>\r\n\r\n<style scoped>\r\n.c-form-default {\r\n width: 100%;\r\n}\r\n</style>\r\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-01\n * @Description: 表单组件 - 内联布局组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n\n<template>\n <div class=\"c-form-inline\" :style=\"containerStyle\">\n <div\n v-for=\"(item, index) in formItems\"\n :key=\"getItemKey(item, index)\"\n class=\"c-form-inline-item\"\n :style=\"getItemStyle(index)\"\n >\n <component :is=\"item\" />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from \"vue\";\nimport type { VNode, CSSProperties } from \"vue\";\nimport type { LayoutProps, FormOption, ItemLayoutConfig } from \"../../types\";\n\n/* ================= 组件属性 ================= */\n\nconst props = withDefaults(defineProps<LayoutProps>(), {\n layoutConfig: () => ({}),\n options: () => [],\n});\n\n/* ================= 计算属性 ================= */\n\n/**\n * 获取统一项目宽度\n */\nconst itemWidth = computed((): number => 280);\n\n/**\n * 获取项目间距\n */\nconst gap = computed((): number => {\n return props.layoutConfig?.inline?.gap ?? 16;\n});\n\n/**\n * 获取行间距\n */\nconst rowGap = computed((): number => 16);\n\n/**\n * 获取对齐方式 - 既控制垂直对齐也控制水平对齐\n */\nconst align = computed((): \"start\" | \"center\" | \"end\" => {\n const alignValue = props.layoutConfig?.inline?.align;\n return alignValue === \"start\" || alignValue === \"end\" ? alignValue : \"center\";\n});\n\n/**\n * 获取垂直对齐样式\n */\nconst alignItems = computed((): string => {\n switch (align.value) {\n case \"start\":\n return \"flex-start\";\n case \"end\":\n return \"flex-end\";\n default:\n return \"center\";\n }\n});\n\n/**\n * 获取水平对齐样式\n */\nconst justifyContent = computed((): string => {\n switch (align.value) {\n case \"start\":\n return \"flex-start\";\n case \"end\":\n return \"flex-end\";\n case \"center\":\n return \"center\";\n default:\n return \"flex-start\";\n }\n});\n\n/**\n * 容器样式计算\n */\nconst containerStyle = computed((): CSSProperties => {\n return {\n display: \"flex\",\n flexWrap: \"wrap\",\n alignItems: alignItems.value,\n justifyContent: justifyContent.value,\n gap: `${rowGap.value}px ${gap.value}px`,\n width: \"100%\",\n };\n});\n\n/* ================= 方法 ================= */\n\n/**\n * 获取表单项的唯一key\n */\nconst getItemKey = (item: VNode, index: number): string => {\n if (item.key != null) {\n return String(item.key);\n }\n\n const itemProps = item.props as any;\n if (itemProps?.path) {\n return itemProps.path;\n }\n\n return `form-item-${index}`;\n};\n\n/**\n * 获取表单项样式\n */\nconst getItemStyle = (index: number): CSSProperties => {\n const option: FormOption | undefined = props.options?.[index];\n const layoutConfig: ItemLayoutConfig | undefined = option?.layout;\n\n /* 基础样式,统一宽度 */\n const baseStyle: CSSProperties = {\n width: `${itemWidth.value}px`,\n flexShrink: 0,\n display: \"flex\",\n flexDirection: \"column\",\n };\n\n /* 如果单独设置了宽度,则覆盖统一宽度 */\n if (layoutConfig?.width !== undefined) {\n baseStyle.width =\n typeof layoutConfig.width === \"number\"\n ? `${layoutConfig.width}px`\n : layoutConfig.width;\n }\n\n /* 合并自定义样式 */\n if (layoutConfig?.style) {\n Object.assign(baseStyle, layoutConfig.style);\n }\n\n return baseStyle;\n};\n</script>\n\n<style scoped lang=\"scss\">\n@use \"./index.scss\";\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-01\n * @Description: 表单组件 - 内联布局组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n\n<template>\n <div class=\"c-form-inline\" :style=\"containerStyle\">\n <div\n v-for=\"(item, index) in formItems\"\n :key=\"getItemKey(item, index)\"\n class=\"c-form-inline-item\"\n :style=\"getItemStyle(index)\"\n >\n <component :is=\"item\" />\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from \"vue\";\nimport type { VNode, CSSProperties } from \"vue\";\nimport type { LayoutProps, FormOption, ItemLayoutConfig } from \"../../types\";\n\n/* ================= 组件属性 ================= */\n\nconst props = withDefaults(defineProps<LayoutProps>(), {\n layoutConfig: () => ({}),\n options: () => [],\n});\n\n/* ================= 计算属性 ================= */\n\n/**\n * 获取统一项目宽度\n */\nconst itemWidth = computed((): number => 280);\n\n/**\n * 获取项目间距\n */\nconst gap = computed((): number => {\n return props.layoutConfig?.inline?.gap ?? 16;\n});\n\n/**\n * 获取行间距\n */\nconst rowGap = computed((): number => 16);\n\n/**\n * 获取对齐方式 - 既控制垂直对齐也控制水平对齐\n */\nconst align = computed((): \"start\" | \"center\" | \"end\" => {\n const alignValue = props.layoutConfig?.inline?.align;\n return alignValue === \"start\" || alignValue === \"end\" ? alignValue : \"center\";\n});\n\n/**\n * 获取垂直对齐样式\n */\nconst alignItems = computed((): string => {\n switch (align.value) {\n case \"start\":\n return \"flex-start\";\n case \"end\":\n return \"flex-end\";\n default:\n return \"center\";\n }\n});\n\n/**\n * 获取水平对齐样式\n */\nconst justifyContent = computed((): string => {\n switch (align.value) {\n case \"start\":\n return \"flex-start\";\n case \"end\":\n return \"flex-end\";\n case \"center\":\n return \"center\";\n default:\n return \"flex-start\";\n }\n});\n\n/**\n * 容器样式计算\n */\nconst containerStyle = computed((): CSSProperties => {\n return {\n display: \"flex\",\n flexWrap: \"wrap\",\n alignItems: alignItems.value,\n justifyContent: justifyContent.value,\n gap: `${rowGap.value}px ${gap.value}px`,\n width: \"100%\",\n };\n});\n\n/* ================= 方法 ================= */\n\n/**\n * 获取表单项的唯一key\n */\nconst getItemKey = (item: VNode, index: number): string => {\n if (item.key != null) {\n return String(item.key);\n }\n\n const itemProps = item.props as any;\n if (itemProps?.path) {\n return itemProps.path;\n }\n\n return `form-item-${index}`;\n};\n\n/**\n * 获取表单项样式\n */\nconst getItemStyle = (index: number): CSSProperties => {\n const option: FormOption | undefined = props.options?.[index];\n const layoutConfig: ItemLayoutConfig | undefined = option?.layout;\n\n /* 基础样式,统一宽度 */\n const baseStyle: CSSProperties = {\n width: `${itemWidth.value}px`,\n flexShrink: 0,\n display: \"flex\",\n flexDirection: \"column\",\n };\n\n /* 如果单独设置了宽度,则覆盖统一宽度 */\n if (layoutConfig?.width !== undefined) {\n baseStyle.width =\n typeof layoutConfig.width === \"number\"\n ? `${layoutConfig.width}px`\n : layoutConfig.width;\n }\n\n /* 合并自定义样式 */\n if (layoutConfig?.style) {\n Object.assign(baseStyle, layoutConfig.style);\n }\n\n return baseStyle;\n};\n</script>\n\n<style scoped lang=\"scss\">\n@use \"./index.scss\";\n</style>\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-01\r\n * @Description: 表单组件 - 网格表单组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"c-grid-layout\">\r\n <!-- 配置面板 -->\r\n <NCard\r\n v-if=\"showConfigPanel\"\r\n size=\"small\"\r\n :bordered=\"false\"\r\n class=\"config-panel\"\r\n >\r\n <template #header>\r\n <div class=\"config-header\">\r\n <C_Icon\r\n :name=\"'mdi:view-grid'\"\r\n :size=\"18\"\r\n />\r\n <span>网格配置</span>\r\n </div>\r\n </template>\r\n\r\n <div class=\"config-controls\">\r\n <div\r\n v-for=\"control in configControls\"\r\n :key=\"control.key\"\r\n class=\"config-item\"\r\n >\r\n <span class=\"config-label\">{{ control.label }}:</span>\r\n <component\r\n :is=\"control.component\"\r\n v-model:value=\"control.value\"\r\n v-bind=\"control.props\"\r\n />\r\n </div>\r\n </div>\r\n </NCard>\r\n\r\n <!-- 网格容器 -->\r\n <NGrid\r\n v-bind=\"gridProps\"\r\n class=\"grid-container\"\r\n >\r\n <NGridItem\r\n v-for=\"(item, index) in formItems\"\r\n :key=\"getItemKey(item, index)\"\r\n v-bind=\"getItemProps(index)\"\r\n class=\"grid-item\"\r\n >\r\n <div class=\"item-wrapper\">\r\n <component :is=\"item\" />\r\n </div>\r\n </NGridItem>\r\n </NGrid>\r\n\r\n <!-- 统计信息 -->\r\n <NAlert\r\n v-if=\"showStats\"\r\n type=\"info\"\r\n :show-icon=\"false\"\r\n size=\"small\"\r\n class=\"grid-stats\"\r\n >\r\n <template #header>\r\n <C_Icon\r\n :name=\"'mdi:information-outline'\"\r\n :size=\"16\"\r\n />\r\n 网格信息\r\n </template>\r\n {{ statsText }}\r\n </NAlert>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { reactive, computed, watch, type VNode } from 'vue'\r\n import C_Icon from '../../../C_Icon/index.vue'\r\n\r\n /* ================= 类型定义 ================= */\r\n\r\n interface GridConfig {\r\n cols?: number\r\n gutter?: number\r\n responsive?: boolean\r\n showConfigPanel?: boolean\r\n showStats?: boolean\r\n }\r\n\r\n interface FormOption {\r\n type: string\r\n prop: string\r\n label?: string\r\n layout?: {\r\n span?: number\r\n offset?: number\r\n suffix?: boolean\r\n grid?: {\r\n span?: number\r\n offset?: number\r\n suffix?: boolean\r\n }\r\n }\r\n }\r\n\r\n interface Props {\r\n formItems: VNode[]\r\n layoutConfig?: { grid?: GridConfig }\r\n options?: FormOption[]\r\n }\r\n\r\n /* ================= 组件属性 ================= */\r\n\r\n const props = withDefaults(defineProps<Props>(), {\r\n layoutConfig: () => ({}),\r\n options: () => [],\r\n })\r\n\r\n /* ================= 响应式状态 ================= */\r\n\r\n const internalConfig = reactive({\r\n cols: 24,\r\n gutter: 16,\r\n responsive: true,\r\n })\r\n\r\n /* ================= 计算属性 ================= */\r\n\r\n const gridConfig = computed(() => props.layoutConfig?.grid || {})\r\n const showConfigPanel = computed(() => gridConfig.value.showConfigPanel)\r\n const showStats = computed(() => gridConfig.value.showStats)\r\n\r\n /* 生效的配置(内部配置优先) */\r\n const effectiveConfig = computed(() => ({\r\n cols: showConfigPanel.value\r\n ? internalConfig.cols\r\n : (gridConfig.value.cols ?? 24),\r\n gutter: showConfigPanel.value\r\n ? internalConfig.gutter\r\n : (gridConfig.value.gutter ?? 16),\r\n responsive: showConfigPanel.value\r\n ? internalConfig.responsive\r\n : (gridConfig.value.responsive ?? true),\r\n }))\r\n\r\n /* 网格属性 */\r\n const gridProps = computed(() => ({\r\n cols: effectiveConfig.value.cols,\r\n xGap: effectiveConfig.value.gutter,\r\n yGap: effectiveConfig.value.gutter,\r\n responsive: effectiveConfig.value.responsive ? 'screen' : 'self',\r\n }))\r\n\r\n /* 配置控件定义 */\r\n const configControls = computed(() => [\r\n {\r\n key: 'cols',\r\n label: '列数',\r\n component: 'NInputNumber',\r\n value: computed({\r\n get: () => internalConfig.cols,\r\n set: (val: number) => (internalConfig.cols = val),\r\n }),\r\n props: { min: 1, max: 48, size: 'small' },\r\n },\r\n {\r\n key: 'gutter',\r\n label: '间距',\r\n component: 'NInputNumber',\r\n value: computed({\r\n get: () => internalConfig.gutter,\r\n set: (val: number) => (internalConfig.gutter = val),\r\n }),\r\n props: { min: 0, max: 48, size: 'small' },\r\n },\r\n {\r\n key: 'responsive',\r\n label: '响应式',\r\n component: 'NSwitch',\r\n value: computed({\r\n get: () => internalConfig.responsive,\r\n set: (val: boolean) => (internalConfig.responsive = val),\r\n }),\r\n props: { size: 'small' },\r\n },\r\n ])\r\n\r\n /* 统计文本 */\r\n const statsText = computed(\r\n () =>\r\n `列数: ${effectiveConfig.value.cols} | 间距: ${effectiveConfig.value.gutter}px | 项目: ${props.formItems.length}个`\r\n )\r\n\r\n /* ================= 核心方法 ================= */\r\n\r\n /**\r\n * 获取表单项key\r\n */\r\n const getItemKey = (item: VNode, index: number): string =>\r\n String(item.key) || (item.props as any)?.path || `grid-item-${index}`\r\n\r\n /**\r\n * 获取布局属性值\r\n */\r\n const getLayoutValue = (index: number, key: 'span' | 'offset' | 'suffix') => {\r\n const option = props.options?.[index]?.layout\r\n return option?.[key] ?? option?.grid?.[key]\r\n }\r\n\r\n /**\r\n * 获取默认span值\r\n */\r\n const getDefaultSpan = (): number => {\r\n const { cols } = effectiveConfig.value\r\n return cols <= 12 ? cols : cols <= 24 ? 12 : 8\r\n }\r\n\r\n /**\r\n * 获取网格项属性\r\n */\r\n const getItemProps = (index: number) => {\r\n const span = getLayoutValue(index, 'span')\r\n const offset = getLayoutValue(index, 'offset')\r\n const suffix = getLayoutValue(index, 'suffix')\r\n\r\n return {\r\n span:\r\n typeof span === 'number' &&\r\n span > 0 &&\r\n span <= effectiveConfig.value.cols\r\n ? span\r\n : getDefaultSpan(),\r\n offset:\r\n typeof offset === 'number' &&\r\n offset >= 0 &&\r\n offset < effectiveConfig.value.cols\r\n ? offset\r\n : 0,\r\n suffix: Boolean(suffix),\r\n }\r\n }\r\n\r\n /* ================= 监听器 ================= */\r\n\r\n /* 同步外部配置 */\r\n watch(\r\n gridConfig,\r\n config => {\r\n if (config.cols !== undefined) internalConfig.cols = config.cols\r\n if (config.gutter !== undefined) internalConfig.gutter = config.gutter\r\n if (config.responsive !== undefined)\r\n internalConfig.responsive = config.responsive\r\n },\r\n { immediate: true }\r\n )\r\n\r\n /* ================= 暴露接口 ================= */\r\n\r\n defineExpose({\r\n updateGridConfig: (config: Partial<GridConfig>) =>\r\n Object.assign(internalConfig, config),\r\n getCurrentConfig: () => ({ ...effectiveConfig.value }),\r\n getGridInfo: () => ({\r\n ...effectiveConfig.value,\r\n itemCount: props.formItems.length,\r\n }),\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-01\r\n * @Description: 表单组件 - 网格表单组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"c-grid-layout\">\r\n <!-- 配置面板 -->\r\n <NCard\r\n v-if=\"showConfigPanel\"\r\n size=\"small\"\r\n :bordered=\"false\"\r\n class=\"config-panel\"\r\n >\r\n <template #header>\r\n <div class=\"config-header\">\r\n <C_Icon\r\n :name=\"'mdi:view-grid'\"\r\n :size=\"18\"\r\n />\r\n <span>网格配置</span>\r\n </div>\r\n </template>\r\n\r\n <div class=\"config-controls\">\r\n <div\r\n v-for=\"control in configControls\"\r\n :key=\"control.key\"\r\n class=\"config-item\"\r\n >\r\n <span class=\"config-label\">{{ control.label }}:</span>\r\n <component\r\n :is=\"control.component\"\r\n v-model:value=\"control.value\"\r\n v-bind=\"control.props\"\r\n />\r\n </div>\r\n </div>\r\n </NCard>\r\n\r\n <!-- 网格容器 -->\r\n <NGrid\r\n v-bind=\"gridProps\"\r\n class=\"grid-container\"\r\n >\r\n <NGridItem\r\n v-for=\"(item, index) in formItems\"\r\n :key=\"getItemKey(item, index)\"\r\n v-bind=\"getItemProps(index)\"\r\n class=\"grid-item\"\r\n >\r\n <div class=\"item-wrapper\">\r\n <component :is=\"item\" />\r\n </div>\r\n </NGridItem>\r\n </NGrid>\r\n\r\n <!-- 统计信息 -->\r\n <NAlert\r\n v-if=\"showStats\"\r\n type=\"info\"\r\n :show-icon=\"false\"\r\n size=\"small\"\r\n class=\"grid-stats\"\r\n >\r\n <template #header>\r\n <C_Icon\r\n :name=\"'mdi:information-outline'\"\r\n :size=\"16\"\r\n />\r\n 网格信息\r\n </template>\r\n {{ statsText }}\r\n </NAlert>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { reactive, computed, watch, type VNode } from 'vue'\r\n import C_Icon from '../../../C_Icon/index.vue'\r\n\r\n /* ================= 类型定义 ================= */\r\n\r\n interface GridConfig {\r\n cols?: number\r\n gutter?: number\r\n responsive?: boolean\r\n showConfigPanel?: boolean\r\n showStats?: boolean\r\n }\r\n\r\n interface FormOption {\r\n type: string\r\n prop: string\r\n label?: string\r\n layout?: {\r\n span?: number\r\n offset?: number\r\n suffix?: boolean\r\n grid?: {\r\n span?: number\r\n offset?: number\r\n suffix?: boolean\r\n }\r\n }\r\n }\r\n\r\n interface Props {\r\n formItems: VNode[]\r\n layoutConfig?: { grid?: GridConfig }\r\n options?: FormOption[]\r\n }\r\n\r\n /* ================= 组件属性 ================= */\r\n\r\n const props = withDefaults(defineProps<Props>(), {\r\n layoutConfig: () => ({}),\r\n options: () => [],\r\n })\r\n\r\n /* ================= 响应式状态 ================= */\r\n\r\n const internalConfig = reactive({\r\n cols: 24,\r\n gutter: 16,\r\n responsive: true,\r\n })\r\n\r\n /* ================= 计算属性 ================= */\r\n\r\n const gridConfig = computed(() => props.layoutConfig?.grid || {})\r\n const showConfigPanel = computed(() => gridConfig.value.showConfigPanel)\r\n const showStats = computed(() => gridConfig.value.showStats)\r\n\r\n /* 生效的配置(内部配置优先) */\r\n const effectiveConfig = computed(() => ({\r\n cols: showConfigPanel.value\r\n ? internalConfig.cols\r\n : (gridConfig.value.cols ?? 24),\r\n gutter: showConfigPanel.value\r\n ? internalConfig.gutter\r\n : (gridConfig.value.gutter ?? 16),\r\n responsive: showConfigPanel.value\r\n ? internalConfig.responsive\r\n : (gridConfig.value.responsive ?? true),\r\n }))\r\n\r\n /* 网格属性 */\r\n const gridProps = computed(() => ({\r\n cols: effectiveConfig.value.cols,\r\n xGap: effectiveConfig.value.gutter,\r\n yGap: effectiveConfig.value.gutter,\r\n responsive: effectiveConfig.value.responsive ? 'screen' : 'self',\r\n }))\r\n\r\n /* 配置控件定义 */\r\n const configControls = computed(() => [\r\n {\r\n key: 'cols',\r\n label: '列数',\r\n component: 'NInputNumber',\r\n value: computed({\r\n get: () => internalConfig.cols,\r\n set: (val: number) => (internalConfig.cols = val),\r\n }),\r\n props: { min: 1, max: 48, size: 'small' },\r\n },\r\n {\r\n key: 'gutter',\r\n label: '间距',\r\n component: 'NInputNumber',\r\n value: computed({\r\n get: () => internalConfig.gutter,\r\n set: (val: number) => (internalConfig.gutter = val),\r\n }),\r\n props: { min: 0, max: 48, size: 'small' },\r\n },\r\n {\r\n key: 'responsive',\r\n label: '响应式',\r\n component: 'NSwitch',\r\n value: computed({\r\n get: () => internalConfig.responsive,\r\n set: (val: boolean) => (internalConfig.responsive = val),\r\n }),\r\n props: { size: 'small' },\r\n },\r\n ])\r\n\r\n /* 统计文本 */\r\n const statsText = computed(\r\n () =>\r\n `列数: ${effectiveConfig.value.cols} | 间距: ${effectiveConfig.value.gutter}px | 项目: ${props.formItems.length}个`\r\n )\r\n\r\n /* ================= 核心方法 ================= */\r\n\r\n /**\r\n * 获取表单项key\r\n */\r\n const getItemKey = (item: VNode, index: number): string =>\r\n String(item.key) || (item.props as any)?.path || `grid-item-${index}`\r\n\r\n /**\r\n * 获取布局属性值\r\n */\r\n const getLayoutValue = (index: number, key: 'span' | 'offset' | 'suffix') => {\r\n const option = props.options?.[index]?.layout\r\n return option?.[key] ?? option?.grid?.[key]\r\n }\r\n\r\n /**\r\n * 获取默认span值\r\n */\r\n const getDefaultSpan = (): number => {\r\n const { cols } = effectiveConfig.value\r\n return cols <= 12 ? cols : cols <= 24 ? 12 : 8\r\n }\r\n\r\n /**\r\n * 获取网格项属性\r\n */\r\n const getItemProps = (index: number) => {\r\n const span = getLayoutValue(index, 'span')\r\n const offset = getLayoutValue(index, 'offset')\r\n const suffix = getLayoutValue(index, 'suffix')\r\n\r\n return {\r\n span:\r\n typeof span === 'number' &&\r\n span > 0 &&\r\n span <= effectiveConfig.value.cols\r\n ? span\r\n : getDefaultSpan(),\r\n offset:\r\n typeof offset === 'number' &&\r\n offset >= 0 &&\r\n offset < effectiveConfig.value.cols\r\n ? offset\r\n : 0,\r\n suffix: Boolean(suffix),\r\n }\r\n }\r\n\r\n /* ================= 监听器 ================= */\r\n\r\n /* 同步外部配置 */\r\n watch(\r\n gridConfig,\r\n config => {\r\n if (config.cols !== undefined) internalConfig.cols = config.cols\r\n if (config.gutter !== undefined) internalConfig.gutter = config.gutter\r\n if (config.responsive !== undefined)\r\n internalConfig.responsive = config.responsive\r\n },\r\n { immediate: true }\r\n )\r\n\r\n /* ================= 暴露接口 ================= */\r\n\r\n defineExpose({\r\n updateGridConfig: (config: Partial<GridConfig>) =>\r\n Object.assign(internalConfig, config),\r\n getCurrentConfig: () => ({ ...effectiveConfig.value }),\r\n getGridInfo: () => ({\r\n ...effectiveConfig.value,\r\n itemCount: props.formItems.length,\r\n }),\r\n })\r\n</script>\r\n\r\n<style lang=\"scss\" scoped>\r\n @use './index.scss';\r\n</style>\r\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-01\n * @Description: 表单组件 - 卡片组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n\n<template>\n <div class=\"c-form-card\">\n <!-- 布局配置面板 -->\n <NCard\n v-if=\"hasGroups && showLayoutConfig\"\n class=\"layout-config-panel\"\n :bordered=\"false\"\n >\n <template #header>\n <div class=\"flex items-center gap-2\">\n <C_Icon :name=\"'mdi:cog'\" :size=\"18\" />\n <span>布局配置</span>\n </div>\n </template>\n\n <div class=\"config-controls\">\n <div class=\"config-item\">\n <span>卡片间距</span>\n <div class=\"flex items-center gap-2\">\n <NSlider\n v-model:value=\"cardGap\"\n :min=\"12\"\n :max=\"32\"\n :step=\"4\"\n class=\"w-24\"\n />\n <span class=\"text-xs min-w-12\">{{ cardGap }}px</span>\n </div>\n </div>\n\n <div class=\"config-item\">\n <span>显示图标</span>\n <NSwitch v-model:value=\"showIcons\" size=\"small\" />\n </div>\n\n <div class=\"config-item\">\n <span>可折叠</span>\n <NSwitch v-model:value=\"collapsible\" size=\"small\" />\n </div>\n\n <div class=\"config-item\">\n <span>布局方向</span>\n <NRadioGroup v-model:value=\"currentDirection\" size=\"small\">\n <NRadio value=\"vertical\">垂直</NRadio>\n <NRadio value=\"horizontal\">水平</NRadio>\n </NRadioGroup>\n </div>\n </div>\n </NCard>\n\n <!-- 表单内容区域 -->\n <div\n class=\"form-content\"\n :class=\"layoutClass\"\n :style=\"{ gap: `${cardGap}px` }\"\n >\n <!-- 无分组时的单卡片模式 -->\n <NCard v-if=\"!hasGroups\" class=\"single-card\" hoverable>\n <template #header>\n <div class=\"flex items-center gap-3\">\n <C_Icon\n v-if=\"showIcons\"\n :name=\"'mdi:form-select'\"\n :size=\"18\"\n style=\"color: #3b82f6\"\n />\n <span>表单信息</span>\n </div>\n </template>\n\n <template v-for=\"item in formItems\" :key=\"item.key\">\n <component :is=\"item\" />\n </template>\n </NCard>\n\n <!-- 有分组时的多卡片模式 -->\n <template v-else>\n <NCard\n v-for=\"group in groupsWithItems\"\n :key=\"group.config.key\"\n class=\"group-card\"\n :class=\"[\n `${group.config.key}-card`,\n { collapsed: collapsible && collapsedGroups[group.config.key] },\n ]\"\n hoverable\n >\n <template #header>\n <div class=\"card-header\">\n <div class=\"header-info\">\n <C_Icon\n v-if=\"showIcons && group.config.icon\"\n :name=\"group.config.icon\"\n :size=\"20\"\n class=\"card-icon\"\n />\n <C_Icon\n v-else-if=\"showIcons\"\n :name=\"getDefaultIcon(group.config.key)\"\n :size=\"20\"\n class=\"card-icon\"\n />\n\n <div class=\"header-text\">\n <h3>{{ group.config.title }}</h3>\n <p v-if=\"group.config.description\">\n {{ group.config.description }}\n </p>\n </div>\n </div>\n\n <div class=\"header-actions\">\n <!-- 统计信息 -->\n <div class=\"field-stats\">\n <NBadge :value=\"group.items.length\" type=\"info\" show-zero />\n <NBadge\n :value=\"`${getFilledCount(group)}/${group.items.length}`\"\n :type=\"\n getFilledCount(group) === group.items.length\n ? 'success'\n : 'warning'\n \"\n />\n </div>\n\n <!-- 折叠按钮 -->\n <NButton\n v-if=\"collapsible\"\n quaternary\n circle\n size=\"small\"\n @click=\"toggleGroup(group.config.key)\"\n >\n <template #icon>\n <C_Icon\n :name=\"\n collapsedGroups[group.config.key]\n ? 'mdi:chevron-down'\n : 'mdi:chevron-up'\n \"\n :size=\"18\"\n />\n </template>\n </NButton>\n </div>\n </div>\n </template>\n\n <div v-show=\"!collapsedGroups[group.config.key]\" class=\"card-content\">\n <!-- 进度指示器 -->\n <div v-if=\"showProgress\" class=\"progress-section\">\n <NProgress\n :percentage=\"getGroupProgress(group)\"\n :color=\"getGroupProgress(group) === 100 ? '#52c41a' : '#1890ff'\"\n :show-indicator=\"false\"\n class=\"mb-4\"\n />\n </div>\n\n <!-- 表单项 -->\n <template v-for=\"item in group.items\" :key=\"item.key\">\n <component :is=\"item\" />\n </template>\n </div>\n </NCard>\n </template>\n </div>\n\n <!-- 统一操作面板 -->\n <NCard\n v-if=\"hasGroups && showActionPanel\"\n class=\"action-panel\"\n :bordered=\"false\"\n >\n <div class=\"action-content\">\n <div class=\"status-summary\">\n <div class=\"status-item\">\n <span class=\"label\">完成进度:</span>\n <div class=\"progress-display\">\n <NProgress\n :percentage=\"totalProgress\"\n :show-indicator=\"false\"\n :color=\"totalProgress === 100 ? '#52c41a' : '#1890ff'\"\n class=\"flex-1\"\n />\n <span class=\"text-sm min-w-12\">{{ totalProgress }}%</span>\n </div>\n </div>\n </div>\n\n <div class=\"action-buttons\">\n <NButton v-if=\"collapsible\" @click=\"toggleAllGroups\">\n <template #icon>\n <C_Icon\n :name=\"\n allCollapsed\n ? 'mdi:unfold-more-horizontal'\n : 'mdi:unfold-less-horizontal'\n \"\n :size=\"18\"\n />\n </template>\n {{ allCollapsed ? \"展开全部\" : \"折叠全部\" }}\n </NButton>\n </div>\n </div>\n </NCard>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, onMounted } from \"vue\";\nimport type { VNode } from \"vue\";\nimport C_Icon from \"../../../C_Icon/index.vue\";\n\n/**\n * 分组配置接口\n */\ninterface GroupConfig {\n key: string;\n title: string;\n description?: string;\n icon?: string;\n}\n\n/**\n * 分组数据接口\n */\ninterface GroupWithItems {\n config: GroupConfig;\n items: VNode[];\n}\n\n/**\n * 组件属性接口\n */\ninterface Props {\n formItems: VNode[];\n layoutConfig?: {\n card?: {\n groups?: GroupConfig[];\n direction?: \"vertical\" | \"horizontal\";\n showLayoutConfig?: boolean;\n showActionPanel?: boolean;\n showProgress?: boolean;\n };\n };\n options?: Array<{\n layout?: {\n group?: string;\n };\n prop?: string;\n }>;\n formData?: Record<string, any>;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n layoutConfig: () => ({}),\n options: () => [],\n formData: () => ({}),\n});\n\n/* ================= 响应式状态 ================= */\nconst cardGap = ref(20);\nconst showIcons = ref(true);\nconst collapsible = ref(true);\nconst showProgress = ref(true);\nconst currentDirection = ref<\"vertical\" | \"horizontal\">(\"vertical\");\nconst collapsedGroups = ref<Record<string, boolean>>({});\n\n/* ================= 计算属性 ================= */\nconst groups = computed((): GroupConfig[] => {\n return props.layoutConfig?.card?.groups || [];\n});\n\nconst hasGroups = computed((): boolean => {\n return groups.value.length > 0;\n});\n\nconst showLayoutConfig = computed((): boolean => {\n return props.layoutConfig?.card?.showLayoutConfig ?? true;\n});\n\nconst showActionPanel = computed((): boolean => {\n return props.layoutConfig?.card?.showActionPanel ?? true;\n});\n\nconst layoutClass = computed((): string => {\n if (!hasGroups.value) return \"layout-single\";\n return `layout-${currentDirection.value}`;\n});\n\nconst groupsWithItems = computed((): GroupWithItems[] => {\n if (!hasGroups.value) return [];\n\n const groupMap = new Map<string, VNode[]>();\n\n /* 初始化分组映射 */\n groups.value.forEach((group) => {\n groupMap.set(group.key, []);\n });\n\n /* 将表单项分配到对应分组 */\n props.formItems.forEach((item, index) => {\n const option = props.options?.[index];\n const groupKey = option?.layout?.group || groups.value[0]?.key || \"default\";\n\n if (!groupMap.has(groupKey)) {\n groupMap.set(groupKey, []);\n }\n groupMap.get(groupKey)!.push(item);\n });\n\n /* 只返回有表单项的分组 */\n return groups.value\n .map((groupConfig) => ({\n config: groupConfig,\n items: groupMap.get(groupConfig.key) || [],\n }))\n .filter((group) => group.items.length > 0);\n});\n\nconst allCollapsed = computed(() => {\n const groupKeys = Object.keys(collapsedGroups.value);\n return (\n groupKeys.length > 0 && groupKeys.every((key) => collapsedGroups.value[key])\n );\n});\n\nconst totalProgress = computed(() => {\n if (!props.options || props.options.length === 0) return 0;\n\n const filledCount = props.options.filter((option) => {\n const value = props.formData?.[option.prop || \"\"];\n return isFieldFilled(value);\n }).length;\n\n return Math.round((filledCount / props.options.length) * 100);\n});\n\n/* ================= 工具函数 ================= */\nconst isFieldFilled = (value: any): boolean => {\n if (value === null || value === undefined) return false;\n if (Array.isArray(value)) return value.length > 0;\n if (typeof value === \"string\") return value.trim() !== \"\";\n return true;\n};\n\nconst getFilledCount = (group: GroupWithItems): number => {\n if (!props.options) return 0;\n\n const groupFields = props.options.filter(\n (option) => option.layout?.group === group.config.key,\n );\n\n return groupFields.filter((option) => {\n const value = props.formData?.[option.prop || \"\"];\n return isFieldFilled(value);\n }).length;\n};\n\nconst getGroupProgress = (group: GroupWithItems): number => {\n if (group.items.length === 0) return 0;\n const filledCount = getFilledCount(group);\n return Math.round((filledCount / group.items.length) * 100);\n};\n\nconst getDefaultIcon = (groupKey: string): string => {\n const iconMap: Record<string, string> = {\n basic: \"mdi:account\",\n contact: \"mdi:phone\",\n preferences: \"mdi:cog\",\n settings: \"mdi:cog\",\n info: \"mdi:information\",\n default: \"mdi:form-select\",\n };\n return iconMap[groupKey] || iconMap.default;\n};\n\n/* ================= 操作方法 ================= */\nconst toggleGroup = (groupKey: string): void => {\n collapsedGroups.value[groupKey] = !collapsedGroups.value[groupKey];\n};\n\nconst toggleAllGroups = (): void => {\n const shouldCollapse = !allCollapsed.value;\n groups.value.forEach((group) => {\n collapsedGroups.value[group.key] = shouldCollapse;\n });\n};\n\n/* ================= 生命周期 ================= */\nonMounted(() => {\n /* 初始化配置 */\n const config = props.layoutConfig?.card;\n if (config?.direction) {\n currentDirection.value = config.direction;\n }\n\n if (config?.showProgress !== undefined) {\n showProgress.value = config.showProgress;\n }\n\n /* 初始化折叠状态 */\n groups.value.forEach((group) => {\n collapsedGroups.value[group.key] = false;\n });\n});\n</script>\n\n<style scoped lang=\"scss\">\n@use \"./index.scss\";\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-01\n * @Description: 表单组件 - 卡片组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n\n<template>\n <div class=\"c-form-card\">\n <!-- 布局配置面板 -->\n <NCard\n v-if=\"hasGroups && showLayoutConfig\"\n class=\"layout-config-panel\"\n :bordered=\"false\"\n >\n <template #header>\n <div class=\"flex items-center gap-2\">\n <C_Icon :name=\"'mdi:cog'\" :size=\"18\" />\n <span>布局配置</span>\n </div>\n </template>\n\n <div class=\"config-controls\">\n <div class=\"config-item\">\n <span>卡片间距</span>\n <div class=\"flex items-center gap-2\">\n <NSlider\n v-model:value=\"cardGap\"\n :min=\"12\"\n :max=\"32\"\n :step=\"4\"\n class=\"w-24\"\n />\n <span class=\"text-xs min-w-12\">{{ cardGap }}px</span>\n </div>\n </div>\n\n <div class=\"config-item\">\n <span>显示图标</span>\n <NSwitch v-model:value=\"showIcons\" size=\"small\" />\n </div>\n\n <div class=\"config-item\">\n <span>可折叠</span>\n <NSwitch v-model:value=\"collapsible\" size=\"small\" />\n </div>\n\n <div class=\"config-item\">\n <span>布局方向</span>\n <NRadioGroup v-model:value=\"currentDirection\" size=\"small\">\n <NRadio value=\"vertical\">垂直</NRadio>\n <NRadio value=\"horizontal\">水平</NRadio>\n </NRadioGroup>\n </div>\n </div>\n </NCard>\n\n <!-- 表单内容区域 -->\n <div\n class=\"form-content\"\n :class=\"layoutClass\"\n :style=\"{ gap: `${cardGap}px` }\"\n >\n <!-- 无分组时的单卡片模式 -->\n <NCard v-if=\"!hasGroups\" class=\"single-card\" hoverable>\n <template #header>\n <div class=\"flex items-center gap-3\">\n <C_Icon\n v-if=\"showIcons\"\n :name=\"'mdi:form-select'\"\n :size=\"18\"\n style=\"color: #3b82f6\"\n />\n <span>表单信息</span>\n </div>\n </template>\n\n <template v-for=\"item in formItems\" :key=\"item.key\">\n <component :is=\"item\" />\n </template>\n </NCard>\n\n <!-- 有分组时的多卡片模式 -->\n <template v-else>\n <NCard\n v-for=\"group in groupsWithItems\"\n :key=\"group.config.key\"\n class=\"group-card\"\n :class=\"[\n `${group.config.key}-card`,\n { collapsed: collapsible && collapsedGroups[group.config.key] },\n ]\"\n hoverable\n >\n <template #header>\n <div class=\"card-header\">\n <div class=\"header-info\">\n <C_Icon\n v-if=\"showIcons && group.config.icon\"\n :name=\"group.config.icon\"\n :size=\"20\"\n class=\"card-icon\"\n />\n <C_Icon\n v-else-if=\"showIcons\"\n :name=\"getDefaultIcon(group.config.key)\"\n :size=\"20\"\n class=\"card-icon\"\n />\n\n <div class=\"header-text\">\n <h3>{{ group.config.title }}</h3>\n <p v-if=\"group.config.description\">\n {{ group.config.description }}\n </p>\n </div>\n </div>\n\n <div class=\"header-actions\">\n <!-- 统计信息 -->\n <div class=\"field-stats\">\n <NBadge :value=\"group.items.length\" type=\"info\" show-zero />\n <NBadge\n :value=\"`${getFilledCount(group)}/${group.items.length}`\"\n :type=\"\n getFilledCount(group) === group.items.length\n ? 'success'\n : 'warning'\n \"\n />\n </div>\n\n <!-- 折叠按钮 -->\n <NButton\n v-if=\"collapsible\"\n quaternary\n circle\n size=\"small\"\n @click=\"toggleGroup(group.config.key)\"\n >\n <template #icon>\n <C_Icon\n :name=\"\n collapsedGroups[group.config.key]\n ? 'mdi:chevron-down'\n : 'mdi:chevron-up'\n \"\n :size=\"18\"\n />\n </template>\n </NButton>\n </div>\n </div>\n </template>\n\n <div v-show=\"!collapsedGroups[group.config.key]\" class=\"card-content\">\n <!-- 进度指示器 -->\n <div v-if=\"showProgress\" class=\"progress-section\">\n <NProgress\n :percentage=\"getGroupProgress(group)\"\n :color=\"getGroupProgress(group) === 100 ? '#52c41a' : '#1890ff'\"\n :show-indicator=\"false\"\n class=\"mb-4\"\n />\n </div>\n\n <!-- 表单项 -->\n <template v-for=\"item in group.items\" :key=\"item.key\">\n <component :is=\"item\" />\n </template>\n </div>\n </NCard>\n </template>\n </div>\n\n <!-- 统一操作面板 -->\n <NCard\n v-if=\"hasGroups && showActionPanel\"\n class=\"action-panel\"\n :bordered=\"false\"\n >\n <div class=\"action-content\">\n <div class=\"status-summary\">\n <div class=\"status-item\">\n <span class=\"label\">完成进度:</span>\n <div class=\"progress-display\">\n <NProgress\n :percentage=\"totalProgress\"\n :show-indicator=\"false\"\n :color=\"totalProgress === 100 ? '#52c41a' : '#1890ff'\"\n class=\"flex-1\"\n />\n <span class=\"text-sm min-w-12\">{{ totalProgress }}%</span>\n </div>\n </div>\n </div>\n\n <div class=\"action-buttons\">\n <NButton v-if=\"collapsible\" @click=\"toggleAllGroups\">\n <template #icon>\n <C_Icon\n :name=\"\n allCollapsed\n ? 'mdi:unfold-more-horizontal'\n : 'mdi:unfold-less-horizontal'\n \"\n :size=\"18\"\n />\n </template>\n {{ allCollapsed ? \"展开全部\" : \"折叠全部\" }}\n </NButton>\n </div>\n </div>\n </NCard>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, computed, onMounted } from \"vue\";\nimport type { VNode } from \"vue\";\nimport C_Icon from \"../../../C_Icon/index.vue\";\n\n/**\n * 分组配置接口\n */\ninterface GroupConfig {\n key: string;\n title: string;\n description?: string;\n icon?: string;\n}\n\n/**\n * 分组数据接口\n */\ninterface GroupWithItems {\n config: GroupConfig;\n items: VNode[];\n}\n\n/**\n * 组件属性接口\n */\ninterface Props {\n formItems: VNode[];\n layoutConfig?: {\n card?: {\n groups?: GroupConfig[];\n direction?: \"vertical\" | \"horizontal\";\n showLayoutConfig?: boolean;\n showActionPanel?: boolean;\n showProgress?: boolean;\n };\n };\n options?: Array<{\n layout?: {\n group?: string;\n };\n prop?: string;\n }>;\n formData?: Record<string, any>;\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n layoutConfig: () => ({}),\n options: () => [],\n formData: () => ({}),\n});\n\n/* ================= 响应式状态 ================= */\nconst cardGap = ref(20);\nconst showIcons = ref(true);\nconst collapsible = ref(true);\nconst showProgress = ref(true);\nconst currentDirection = ref<\"vertical\" | \"horizontal\">(\"vertical\");\nconst collapsedGroups = ref<Record<string, boolean>>({});\n\n/* ================= 计算属性 ================= */\nconst groups = computed((): GroupConfig[] => {\n return props.layoutConfig?.card?.groups || [];\n});\n\nconst hasGroups = computed((): boolean => {\n return groups.value.length > 0;\n});\n\nconst showLayoutConfig = computed((): boolean => {\n return props.layoutConfig?.card?.showLayoutConfig ?? true;\n});\n\nconst showActionPanel = computed((): boolean => {\n return props.layoutConfig?.card?.showActionPanel ?? true;\n});\n\nconst layoutClass = computed((): string => {\n if (!hasGroups.value) return \"layout-single\";\n return `layout-${currentDirection.value}`;\n});\n\nconst groupsWithItems = computed((): GroupWithItems[] => {\n if (!hasGroups.value) return [];\n\n const groupMap = new Map<string, VNode[]>();\n\n /* 初始化分组映射 */\n groups.value.forEach((group) => {\n groupMap.set(group.key, []);\n });\n\n /* 将表单项分配到对应分组 */\n props.formItems.forEach((item, index) => {\n const option = props.options?.[index];\n const groupKey = option?.layout?.group || groups.value[0]?.key || \"default\";\n\n if (!groupMap.has(groupKey)) {\n groupMap.set(groupKey, []);\n }\n groupMap.get(groupKey)!.push(item);\n });\n\n /* 只返回有表单项的分组 */\n return groups.value\n .map((groupConfig) => ({\n config: groupConfig,\n items: groupMap.get(groupConfig.key) || [],\n }))\n .filter((group) => group.items.length > 0);\n});\n\nconst allCollapsed = computed(() => {\n const groupKeys = Object.keys(collapsedGroups.value);\n return (\n groupKeys.length > 0 && groupKeys.every((key) => collapsedGroups.value[key])\n );\n});\n\nconst totalProgress = computed(() => {\n if (!props.options || props.options.length === 0) return 0;\n\n const filledCount = props.options.filter((option) => {\n const value = props.formData?.[option.prop || \"\"];\n return isFieldFilled(value);\n }).length;\n\n return Math.round((filledCount / props.options.length) * 100);\n});\n\n/* ================= 工具函数 ================= */\nconst isFieldFilled = (value: any): boolean => {\n if (value === null || value === undefined) return false;\n if (Array.isArray(value)) return value.length > 0;\n if (typeof value === \"string\") return value.trim() !== \"\";\n return true;\n};\n\nconst getFilledCount = (group: GroupWithItems): number => {\n if (!props.options) return 0;\n\n const groupFields = props.options.filter(\n (option) => option.layout?.group === group.config.key,\n );\n\n return groupFields.filter((option) => {\n const value = props.formData?.[option.prop || \"\"];\n return isFieldFilled(value);\n }).length;\n};\n\nconst getGroupProgress = (group: GroupWithItems): number => {\n if (group.items.length === 0) return 0;\n const filledCount = getFilledCount(group);\n return Math.round((filledCount / group.items.length) * 100);\n};\n\nconst getDefaultIcon = (groupKey: string): string => {\n const iconMap: Record<string, string> = {\n basic: \"mdi:account\",\n contact: \"mdi:phone\",\n preferences: \"mdi:cog\",\n settings: \"mdi:cog\",\n info: \"mdi:information\",\n default: \"mdi:form-select\",\n };\n return iconMap[groupKey] || iconMap.default;\n};\n\n/* ================= 操作方法 ================= */\nconst toggleGroup = (groupKey: string): void => {\n collapsedGroups.value[groupKey] = !collapsedGroups.value[groupKey];\n};\n\nconst toggleAllGroups = (): void => {\n const shouldCollapse = !allCollapsed.value;\n groups.value.forEach((group) => {\n collapsedGroups.value[group.key] = shouldCollapse;\n });\n};\n\n/* ================= 生命周期 ================= */\nonMounted(() => {\n /* 初始化配置 */\n const config = props.layoutConfig?.card;\n if (config?.direction) {\n currentDirection.value = config.direction;\n }\n\n if (config?.showProgress !== undefined) {\n showProgress.value = config.showProgress;\n }\n\n /* 初始化折叠状态 */\n groups.value.forEach((group) => {\n collapsedGroups.value[group.key] = false;\n });\n});\n</script>\n\n<style scoped lang=\"scss\">\n@use \"./index.scss\";\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-01\n * @Description: 表单组件 - 标签布局组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n\n<template>\n <div class=\"c-form-tabs\">\n <!-- 无标签配置时的单一面板模式 -->\n <div v-if=\"!hasTabs\" class=\"single-panel\">\n <component\n v-for=\"(item, index) in formItems\"\n :key=\"getItemKey(item, index)\"\n :is=\"item\"\n />\n </div>\n\n <!-- 有标签配置时的分标签模式 -->\n <div v-else class=\"tabs-container\">\n <NTabs\n v-model:value=\"currentTab\"\n :type=\"tabsConfig.type\"\n :size=\"tabsConfig.size\"\n :placement=\"tabsConfig.placement\"\n :animated=\"tabsConfig.animated\"\n :closable=\"tabsConfig.closable\"\n :addable=\"tabsConfig.addable\"\n class=\"form-tabs\"\n @update:value=\"handleTabChange\"\n @close=\"handleTabClose\"\n @add=\"handleTabAdd\"\n >\n <NTabPane\n v-for=\"tab in tabsWithItems\"\n :key=\"tab.config.key\"\n :name=\"tab.config.key\"\n :tab=\"tab.config.title\"\n :disabled=\"tab.config.disabled\"\n :closable=\"tab.config.closable\"\n >\n <template #tab>\n <NSpace align=\"center\" :size=\"8\">\n <C_Icon\n v-if=\"tab.config.icon\"\n :name=\"tab.config.icon\"\n :size=\"16\"\n class=\"tab-icon\"\n />\n <span>{{ tab.config.title }}</span>\n <NBadge\n v-if=\"tabsConfig.showCount\"\n :value=\"tab.items.length\"\n :max=\"99\"\n :show=\"tab.items.length > 0\"\n type=\"info\"\n />\n </NSpace>\n </template>\n\n <!-- 标签页头部信息 -->\n <div\n v-if=\"tabsConfig.showTabHeader && tab.config.description\"\n class=\"tab-header\"\n >\n <p class=\"tab-description\">{{ tab.config.description }}</p>\n </div>\n\n <!-- 标签页内的表单项 -->\n <div class=\"tab-form-items\">\n <component\n v-for=\"(item, itemIndex) in tab.items\"\n :key=\"getItemKey(item, itemIndex)\"\n :is=\"item\"\n />\n </div>\n\n <!-- 空状态 -->\n <NEmpty\n v-if=\"tab.items.length === 0\"\n description=\"暂无表单项\"\n class=\"tab-empty\"\n />\n </NTabPane>\n </NTabs>\n\n <!-- 标签页操作按钮 -->\n <div v-if=\"tabsConfig.showActions\" class=\"tabs-actions\">\n <NSpace justify=\"space-between\">\n <NSpace>\n <NButton\n v-if=\"tabsConfig.validateBeforeSwitch\"\n type=\"primary\"\n size=\"small\"\n @click=\"validateCurrentTab\"\n >\n <C_Icon\n :name=\"'carbon:star-check'\"\n :size=\"14\"\n style=\"margin-right: 4px\"\n />\n 验证当前标签\n </NButton>\n </NSpace>\n\n <NSpace>\n <slot\n name=\"tab-actions\"\n :current-tab=\"currentTab\"\n :total-tabs=\"tabsWithItems.length\"\n :validate-tab=\"validateCurrentTab\"\n :switch-to-tab=\"switchToTab\"\n />\n </NSpace>\n </NSpace>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport {\n ref,\n reactive,\n computed,\n watch,\n nextTick,\n onMounted,\n readonly,\n} from \"vue\";\nimport type { VNode } from \"vue\";\nimport C_Icon from \"../../../C_Icon/index.vue\";\n\n/* ================= 类型定义 ================= */\ninterface TabConfig {\n key: string;\n title: string;\n description?: string;\n icon?: string;\n disabled?: boolean;\n closable?: boolean;\n}\n\ninterface TabsLayoutConfig {\n tabs: TabConfig[];\n type?: \"line\" | \"card\" | \"segment\";\n size?: \"small\" | \"medium\" | \"large\";\n placement?: \"top\" | \"right\" | \"bottom\" | \"left\";\n animated?: boolean;\n closable?: boolean;\n addable?: boolean;\n showTabHeader?: boolean;\n showActions?: boolean;\n showCount?: boolean;\n validateBeforeSwitch?: boolean;\n defaultTab?: string;\n}\n\ninterface TabWithItems {\n config: TabConfig;\n items: VNode[];\n}\n\ninterface Props {\n formItems: VNode[];\n layoutConfig?: {\n tabs?: TabsLayoutConfig;\n };\n options?: Array<{\n layout?: {\n tab?: string;\n };\n }>;\n}\n\n/* ================= 组件属性和事件 ================= */\nconst props = withDefaults(defineProps<Props>(), {\n layoutConfig: () => ({}),\n options: () => [],\n});\n\nconst emit = defineEmits<{\n \"tab-change\": [tabKey: string, tabIndex: number];\n \"tab-before-change\": [currentTab: string, targetTab: string];\n \"tab-validate\": [tabKey: string];\n \"tab-close\": [tabKey: string];\n \"tab-add\": [];\n}>();\n\n/* ================= 响应式状态 ================= */\nconst currentTab = ref<string>(\"\");\nconst tabValidationStatus = reactive<Record<string, boolean>>({});\n\n/* ================= 默认配置 ================= */\nconst getDefaultTabsConfig = (): Required<TabsLayoutConfig> => ({\n tabs: [],\n type: \"line\",\n size: \"medium\",\n placement: \"top\",\n animated: true,\n closable: false,\n addable: false,\n showTabHeader: true,\n showActions: false,\n showCount: false,\n validateBeforeSwitch: false,\n defaultTab: \"\",\n});\n\n/* ================= 计算属性 ================= */\nconst tabsConfig = computed(() => {\n const defaultConfig = getDefaultTabsConfig();\n const userConfig = props.layoutConfig?.tabs || {};\n\n return {\n ...defaultConfig,\n ...userConfig,\n };\n});\n\nconst hasTabs = computed((): boolean => {\n return tabsConfig.value.tabs.length > 0;\n});\n\nconst tabsWithItems = computed((): TabWithItems[] => {\n if (!hasTabs.value) return [];\n\n const tabMap = new Map<string, VNode[]>();\n\n /* 初始化标签映射 */\n tabsConfig.value.tabs.forEach((tab) => {\n tabMap.set(tab.key, []);\n });\n\n /* 分配表单项到对应标签 */\n props.formItems.forEach((item, index) => {\n const option = props.options?.[index];\n const tabKey =\n option?.layout?.tab || tabsConfig.value.tabs[0]?.key || \"default\";\n\n if (!tabMap.has(tabKey)) {\n tabMap.set(tabKey, []);\n }\n tabMap.get(tabKey)!.push(item);\n });\n\n /* 返回所有标签(包括空标签) */\n return tabsConfig.value.tabs.map((tabConfig) => ({\n config: tabConfig,\n items: tabMap.get(tabConfig.key) || [],\n }));\n});\n\n/* ================= 工具方法 ================= */\nconst getItemKey = (item: VNode, index: number): string => {\n if (item.key != null) {\n return String(item.key);\n }\n\n const itemProps = item.props as Record<string, any> | null;\n if (itemProps?.path) {\n return itemProps.path;\n }\n\n return `tab-item-${index}`;\n};\n\nconst validateCurrentTab = async (): Promise<boolean> => {\n if (!currentTab.value) return true;\n\n try {\n emit(\"tab-validate\", currentTab.value);\n const valid = true;\n tabValidationStatus[currentTab.value] = valid;\n return valid;\n } catch (error) {\n console.error(\"[Tabs Layout] 标签验证失败:\", error);\n tabValidationStatus[currentTab.value] = false;\n return false;\n }\n};\n\nconst switchToTab = async (targetTab: string): Promise<boolean> => {\n if (!targetTab || targetTab === currentTab.value) {\n return true;\n }\n\n const targetTabExists = tabsWithItems.value.some(\n (tab) => tab.config.key === targetTab,\n );\n if (!targetTabExists) {\n return false;\n }\n\n try {\n /* 验证当前标签(如果需要) */\n if (tabsConfig.value.validateBeforeSwitch && currentTab.value) {\n const isValid = await validateCurrentTab();\n if (!isValid) {\n return false;\n }\n }\n\n /* 触发标签切换前事件 */\n if (currentTab.value) {\n emit(\"tab-before-change\", currentTab.value, targetTab);\n }\n\n currentTab.value = targetTab;\n const tabIndex = tabsWithItems.value.findIndex(\n (tab) => tab.config.key === targetTab,\n );\n emit(\"tab-change\", targetTab, tabIndex);\n return true;\n } catch (error) {\n console.error(\"[Tabs Layout] 标签切换失败:\", error);\n return false;\n }\n};\n\n/* ================= 事件处理方法 ================= */\nconst handleTabChange = (tabKey: string): void => {\n switchToTab(tabKey);\n};\n\nconst handleTabClose = (tabKey: string): void => {\n emit(\"tab-close\", tabKey);\n};\n\nconst handleTabAdd = (): void => {\n emit(\"tab-add\");\n};\n\nconst initializeCurrentTab = (): void => {\n if (!hasTabs.value || tabsWithItems.value.length === 0) {\n return;\n }\n\n const { defaultTab } = tabsConfig.value;\n const targetTab = defaultTab || tabsWithItems.value[0]?.config.key;\n\n if (targetTab && targetTab !== currentTab.value) {\n currentTab.value = targetTab;\n nextTick(() => {\n const tabIndex = tabsWithItems.value.findIndex(\n (tab) => tab.config.key === targetTab,\n );\n if (tabIndex >= 0) {\n emit(\"tab-change\", targetTab, tabIndex);\n }\n });\n }\n};\n\n/* ================= 生命周期 ================= */\nonMounted(() => {\n initializeCurrentTab();\n});\n\n/* 只监听标签结构变化(key / 数量),不监听表单项内容变化 */\nconst tabStructureKey = computed(() =>\n tabsConfig.value.tabs.map((t) => t.key).join(\",\"),\n);\n\nwatch(tabStructureKey, () => {\n if (\n currentTab.value &&\n !tabsConfig.value.tabs.some((tab) => tab.key === currentTab.value)\n ) {\n initializeCurrentTab();\n }\n});\n\n/* 监听配置变化 */\nwatch(\n () => tabsConfig.value.defaultTab,\n (newDefaultTab) => {\n if (newDefaultTab && newDefaultTab !== currentTab.value) {\n switchToTab(newDefaultTab);\n }\n },\n);\n\n/* ================= 对外暴露 ================= */\ndefineExpose({\n switchToTab,\n validateCurrentTab,\n currentTab: readonly(currentTab),\n totalTabs: computed(() => tabsWithItems.value.length),\n tabsWithItems: readonly(tabsWithItems),\n});\n</script>\n\n<style scoped lang=\"scss\">\n@use \"./index.scss\";\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-01\n * @Description: 表单组件 - 标签布局组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n\n<template>\n <div class=\"c-form-tabs\">\n <!-- 无标签配置时的单一面板模式 -->\n <div v-if=\"!hasTabs\" class=\"single-panel\">\n <component\n v-for=\"(item, index) in formItems\"\n :key=\"getItemKey(item, index)\"\n :is=\"item\"\n />\n </div>\n\n <!-- 有标签配置时的分标签模式 -->\n <div v-else class=\"tabs-container\">\n <NTabs\n v-model:value=\"currentTab\"\n :type=\"tabsConfig.type\"\n :size=\"tabsConfig.size\"\n :placement=\"tabsConfig.placement\"\n :animated=\"tabsConfig.animated\"\n :closable=\"tabsConfig.closable\"\n :addable=\"tabsConfig.addable\"\n class=\"form-tabs\"\n @update:value=\"handleTabChange\"\n @close=\"handleTabClose\"\n @add=\"handleTabAdd\"\n >\n <NTabPane\n v-for=\"tab in tabsWithItems\"\n :key=\"tab.config.key\"\n :name=\"tab.config.key\"\n :tab=\"tab.config.title\"\n :disabled=\"tab.config.disabled\"\n :closable=\"tab.config.closable\"\n >\n <template #tab>\n <NSpace align=\"center\" :size=\"8\">\n <C_Icon\n v-if=\"tab.config.icon\"\n :name=\"tab.config.icon\"\n :size=\"16\"\n class=\"tab-icon\"\n />\n <span>{{ tab.config.title }}</span>\n <NBadge\n v-if=\"tabsConfig.showCount\"\n :value=\"tab.items.length\"\n :max=\"99\"\n :show=\"tab.items.length > 0\"\n type=\"info\"\n />\n </NSpace>\n </template>\n\n <!-- 标签页头部信息 -->\n <div\n v-if=\"tabsConfig.showTabHeader && tab.config.description\"\n class=\"tab-header\"\n >\n <p class=\"tab-description\">{{ tab.config.description }}</p>\n </div>\n\n <!-- 标签页内的表单项 -->\n <div class=\"tab-form-items\">\n <component\n v-for=\"(item, itemIndex) in tab.items\"\n :key=\"getItemKey(item, itemIndex)\"\n :is=\"item\"\n />\n </div>\n\n <!-- 空状态 -->\n <NEmpty\n v-if=\"tab.items.length === 0\"\n description=\"暂无表单项\"\n class=\"tab-empty\"\n />\n </NTabPane>\n </NTabs>\n\n <!-- 标签页操作按钮 -->\n <div v-if=\"tabsConfig.showActions\" class=\"tabs-actions\">\n <NSpace justify=\"space-between\">\n <NSpace>\n <NButton\n v-if=\"tabsConfig.validateBeforeSwitch\"\n type=\"primary\"\n size=\"small\"\n @click=\"validateCurrentTab\"\n >\n <C_Icon\n :name=\"'carbon:star-check'\"\n :size=\"14\"\n style=\"margin-right: 4px\"\n />\n 验证当前标签\n </NButton>\n </NSpace>\n\n <NSpace>\n <slot\n name=\"tab-actions\"\n :current-tab=\"currentTab\"\n :total-tabs=\"tabsWithItems.length\"\n :validate-tab=\"validateCurrentTab\"\n :switch-to-tab=\"switchToTab\"\n />\n </NSpace>\n </NSpace>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport {\n ref,\n reactive,\n computed,\n watch,\n nextTick,\n onMounted,\n readonly,\n} from \"vue\";\nimport type { VNode } from \"vue\";\nimport C_Icon from \"../../../C_Icon/index.vue\";\n\n/* ================= 类型定义 ================= */\ninterface TabConfig {\n key: string;\n title: string;\n description?: string;\n icon?: string;\n disabled?: boolean;\n closable?: boolean;\n}\n\ninterface TabsLayoutConfig {\n tabs: TabConfig[];\n type?: \"line\" | \"card\" | \"segment\";\n size?: \"small\" | \"medium\" | \"large\";\n placement?: \"top\" | \"right\" | \"bottom\" | \"left\";\n animated?: boolean;\n closable?: boolean;\n addable?: boolean;\n showTabHeader?: boolean;\n showActions?: boolean;\n showCount?: boolean;\n validateBeforeSwitch?: boolean;\n defaultTab?: string;\n}\n\ninterface TabWithItems {\n config: TabConfig;\n items: VNode[];\n}\n\ninterface Props {\n formItems: VNode[];\n layoutConfig?: {\n tabs?: TabsLayoutConfig;\n };\n options?: Array<{\n layout?: {\n tab?: string;\n };\n }>;\n}\n\n/* ================= 组件属性和事件 ================= */\nconst props = withDefaults(defineProps<Props>(), {\n layoutConfig: () => ({}),\n options: () => [],\n});\n\nconst emit = defineEmits<{\n \"tab-change\": [tabKey: string, tabIndex: number];\n \"tab-before-change\": [currentTab: string, targetTab: string];\n \"tab-validate\": [tabKey: string];\n \"tab-close\": [tabKey: string];\n \"tab-add\": [];\n}>();\n\n/* ================= 响应式状态 ================= */\nconst currentTab = ref<string>(\"\");\nconst tabValidationStatus = reactive<Record<string, boolean>>({});\n\n/* ================= 默认配置 ================= */\nconst getDefaultTabsConfig = (): Required<TabsLayoutConfig> => ({\n tabs: [],\n type: \"line\",\n size: \"medium\",\n placement: \"top\",\n animated: true,\n closable: false,\n addable: false,\n showTabHeader: true,\n showActions: false,\n showCount: false,\n validateBeforeSwitch: false,\n defaultTab: \"\",\n});\n\n/* ================= 计算属性 ================= */\nconst tabsConfig = computed(() => {\n const defaultConfig = getDefaultTabsConfig();\n const userConfig = props.layoutConfig?.tabs || {};\n\n return {\n ...defaultConfig,\n ...userConfig,\n };\n});\n\nconst hasTabs = computed((): boolean => {\n return tabsConfig.value.tabs.length > 0;\n});\n\nconst tabsWithItems = computed((): TabWithItems[] => {\n if (!hasTabs.value) return [];\n\n const tabMap = new Map<string, VNode[]>();\n\n /* 初始化标签映射 */\n tabsConfig.value.tabs.forEach((tab) => {\n tabMap.set(tab.key, []);\n });\n\n /* 分配表单项到对应标签 */\n props.formItems.forEach((item, index) => {\n const option = props.options?.[index];\n const tabKey =\n option?.layout?.tab || tabsConfig.value.tabs[0]?.key || \"default\";\n\n if (!tabMap.has(tabKey)) {\n tabMap.set(tabKey, []);\n }\n tabMap.get(tabKey)!.push(item);\n });\n\n /* 返回所有标签(包括空标签) */\n return tabsConfig.value.tabs.map((tabConfig) => ({\n config: tabConfig,\n items: tabMap.get(tabConfig.key) || [],\n }));\n});\n\n/* ================= 工具方法 ================= */\nconst getItemKey = (item: VNode, index: number): string => {\n if (item.key != null) {\n return String(item.key);\n }\n\n const itemProps = item.props as Record<string, any> | null;\n if (itemProps?.path) {\n return itemProps.path;\n }\n\n return `tab-item-${index}`;\n};\n\nconst validateCurrentTab = async (): Promise<boolean> => {\n if (!currentTab.value) return true;\n\n try {\n emit(\"tab-validate\", currentTab.value);\n const valid = true;\n tabValidationStatus[currentTab.value] = valid;\n return valid;\n } catch (error) {\n console.error(\"[Tabs Layout] 标签验证失败:\", error);\n tabValidationStatus[currentTab.value] = false;\n return false;\n }\n};\n\nconst switchToTab = async (targetTab: string): Promise<boolean> => {\n if (!targetTab || targetTab === currentTab.value) {\n return true;\n }\n\n const targetTabExists = tabsWithItems.value.some(\n (tab) => tab.config.key === targetTab,\n );\n if (!targetTabExists) {\n return false;\n }\n\n try {\n /* 验证当前标签(如果需要) */\n if (tabsConfig.value.validateBeforeSwitch && currentTab.value) {\n const isValid = await validateCurrentTab();\n if (!isValid) {\n return false;\n }\n }\n\n /* 触发标签切换前事件 */\n if (currentTab.value) {\n emit(\"tab-before-change\", currentTab.value, targetTab);\n }\n\n currentTab.value = targetTab;\n const tabIndex = tabsWithItems.value.findIndex(\n (tab) => tab.config.key === targetTab,\n );\n emit(\"tab-change\", targetTab, tabIndex);\n return true;\n } catch (error) {\n console.error(\"[Tabs Layout] 标签切换失败:\", error);\n return false;\n }\n};\n\n/* ================= 事件处理方法 ================= */\nconst handleTabChange = (tabKey: string): void => {\n switchToTab(tabKey);\n};\n\nconst handleTabClose = (tabKey: string): void => {\n emit(\"tab-close\", tabKey);\n};\n\nconst handleTabAdd = (): void => {\n emit(\"tab-add\");\n};\n\nconst initializeCurrentTab = (): void => {\n if (!hasTabs.value || tabsWithItems.value.length === 0) {\n return;\n }\n\n const { defaultTab } = tabsConfig.value;\n const targetTab = defaultTab || tabsWithItems.value[0]?.config.key;\n\n if (targetTab && targetTab !== currentTab.value) {\n currentTab.value = targetTab;\n nextTick(() => {\n const tabIndex = tabsWithItems.value.findIndex(\n (tab) => tab.config.key === targetTab,\n );\n if (tabIndex >= 0) {\n emit(\"tab-change\", targetTab, tabIndex);\n }\n });\n }\n};\n\n/* ================= 生命周期 ================= */\nonMounted(() => {\n initializeCurrentTab();\n});\n\n/* 只监听标签结构变化(key / 数量),不监听表单项内容变化 */\nconst tabStructureKey = computed(() =>\n tabsConfig.value.tabs.map((t) => t.key).join(\",\"),\n);\n\nwatch(tabStructureKey, () => {\n if (\n currentTab.value &&\n !tabsConfig.value.tabs.some((tab) => tab.key === currentTab.value)\n ) {\n initializeCurrentTab();\n }\n});\n\n/* 监听配置变化 */\nwatch(\n () => tabsConfig.value.defaultTab,\n (newDefaultTab) => {\n if (newDefaultTab && newDefaultTab !== currentTab.value) {\n switchToTab(newDefaultTab);\n }\n },\n);\n\n/* ================= 对外暴露 ================= */\ndefineExpose({\n switchToTab,\n validateCurrentTab,\n currentTab: readonly(currentTab),\n totalTabs: computed(() => tabsWithItems.value.length),\n tabsWithItems: readonly(tabsWithItems),\n});\n</script>\n\n<style scoped lang=\"scss\">\n@use \"./index.scss\";\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-01\n * @Description: 表单组件 - 步骤表单组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n\n<template>\n <div class=\"c-form-steps\">\n <!-- 无步骤配置时的单一面板模式 -->\n <div v-if=\"!hasSteps\" class=\"single-panel\">\n <component\n v-for=\"(item, index) in formItems\"\n :key=\"getItemKey(item, index)\"\n :is=\"item\"\n />\n </div>\n\n <!-- 有步骤配置时的分步骤模式 -->\n <div v-else class=\"steps-container\">\n <!-- 步骤指示器 -->\n <NSteps\n :current=\"currentStep + 1\"\n :status=\"stepStatus\"\n :size=\"stepsConfig.size\"\n :vertical=\"stepsConfig.vertical\"\n class=\"steps-indicator\"\n >\n <NStep\n v-for=\"step in stepsWithItems\"\n :key=\"step.config.key\"\n :title=\"step.config.title\"\n :description=\"step.config.description\"\n :disabled=\"step.config.disabled\"\n />\n </NSteps>\n\n <!-- 步骤内容区域 -->\n <NCard class=\"steps-content\" :bordered=\"false\">\n <div\n v-for=\"(step, index) in stepsWithItems\"\n v-show=\"currentStep === index\"\n :key=\"step.config.key\"\n class=\"step-panel\"\n >\n <!-- 步骤标题和描述 -->\n <div v-if=\"stepsConfig.showStepHeader\" class=\"step-header\">\n <h3 class=\"step-title\">{{ step.config.title }}</h3>\n <p v-if=\"step.config.description\" class=\"step-description\">\n {{ step.config.description }}\n </p>\n </div>\n\n <!-- 步骤内的表单项 -->\n <div class=\"step-form-items\">\n <component\n v-for=\"(item, itemIndex) in step.items\"\n :key=\"getItemKey(item, itemIndex)\"\n :is=\"item\"\n />\n </div>\n </div>\n </NCard>\n\n <!-- 步骤操作按钮 -->\n <div class=\"steps-actions\">\n <NSpace justify=\"space-between\">\n <NButton\n v-if=\"currentStep > 0\"\n :disabled=\"loading\"\n @click=\"handlePreviousStep\"\n >\n <C_Icon\n :name=\"'mdi:chevron-left-first'\"\n :size=\"16\"\n style=\"margin-right: 4px\"\n />\n {{ stepsConfig.prevButtonText }}\n </NButton>\n\n <div></div>\n\n <NSpace>\n <NButton\n v-if=\"currentStep < stepsWithItems.length - 1\"\n type=\"primary\"\n :loading=\"loading\"\n @click=\"handleNextStep\"\n >\n {{ stepsConfig.nextButtonText }}\n <C_Icon\n :name=\"'mdi:chevron-right-last'\"\n :size=\"16\"\n style=\"margin-left: 4px\"\n />\n </NButton>\n\n <slot\n name=\"step-actions\"\n :current-step=\"currentStep\"\n :total-steps=\"stepsWithItems.length\"\n :is-first-step=\"isFirstStep\"\n :is-last-step=\"isLastStep\"\n :next-step=\"handleNextStep\"\n :previous-step=\"handlePreviousStep\"\n :go-to-step=\"goToStep\"\n />\n </NSpace>\n </NSpace>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, computed, watch, onMounted, readonly } from \"vue\";\nimport type { VNode } from \"vue\";\nimport type { StepConfig, StepsLayoutConfig } from \"../../types\";\nimport C_Icon from \"../../../C_Icon/index.vue\";\n\n/* ================= 类型定义 ================= */\ninterface StepWithItems {\n config: StepConfig;\n items: VNode[];\n}\n\ninterface Props {\n formItems: VNode[];\n layoutConfig?: {\n steps?: StepsLayoutConfig;\n };\n options?: Array<{\n layout?: {\n step?: string;\n };\n }>;\n}\n\n/* ================= 组件属性和事件 ================= */\nconst props = withDefaults(defineProps<Props>(), {\n layoutConfig: () => ({}),\n options: () => [],\n});\n\nconst emit = defineEmits<{\n \"step-change\": [stepIndex: number, stepKey: string];\n \"step-before-change\": [currentStep: number, targetStep: number];\n \"step-validate\": [stepIndex: number];\n}>();\n\n/* ================= 响应式状态 ================= */\nconst currentStep = ref<number>(0);\nconst loading = ref<boolean>(false);\nconst stepValidationStatus = reactive<Record<number, boolean>>({});\n\n/* ================= 计算属性 ================= */\nconst stepsConfig = computed(() => {\n const config = props.layoutConfig?.steps || {};\n return {\n steps: config.steps || [],\n vertical: config.vertical || false,\n size: config.size || \"medium\",\n showStepHeader: config.showStepHeader !== false,\n validateBeforeNext: config.validateBeforeNext || false,\n prevButtonText: config.prevButtonText || \"上一步\",\n nextButtonText: config.nextButtonText || \"下一步\",\n defaultStep: config.defaultStep || 0,\n };\n});\n\nconst hasSteps = computed((): boolean => {\n return stepsConfig.value.steps.length > 0;\n});\n\nconst stepsWithItems = computed((): StepWithItems[] => {\n if (!hasSteps.value) return [];\n\n const stepMap = new Map<string, VNode[]>();\n\n /* 初始化步骤映射 */\n stepsConfig.value.steps.forEach((step) => {\n stepMap.set(step.key, []);\n });\n\n /* 分配表单项到对应步骤 */\n props.formItems.forEach((item, index) => {\n const option = props.options?.[index];\n const stepKey =\n option?.layout?.step || stepsConfig.value.steps[0]?.key || \"default\";\n\n if (!stepMap.has(stepKey)) {\n stepMap.set(stepKey, []);\n }\n stepMap.get(stepKey)!.push(item);\n });\n\n /* 只返回有表单项的步骤 */\n return stepsConfig.value.steps\n .map((stepConfig) => ({\n config: stepConfig,\n items: stepMap.get(stepConfig.key) || [],\n }))\n .filter((step) => step.items.length > 0);\n});\n\nconst stepStatus = computed(() => {\n for (let i = 0; i <= currentStep.value; i++) {\n if (stepValidationStatus[i] === false) {\n return \"error\";\n }\n }\n return \"process\";\n});\n\nconst isFirstStep = computed((): boolean => {\n return currentStep.value === 0;\n});\n\nconst isLastStep = computed((): boolean => {\n return currentStep.value === stepsWithItems.value.length - 1;\n});\n\n/* ================= 工具方法 ================= */\nconst getItemKey = (item: VNode, index: number): string => {\n if (item.key != null) {\n return String(item.key);\n }\n\n const itemProps = item.props as Record<string, any> | null;\n if (itemProps?.path) {\n return itemProps.path;\n }\n\n return `step-item-${index}`;\n};\n\nconst validateCurrentStep = async (): Promise<boolean> => {\n try {\n const result = await Promise.resolve(\n emit(\"step-validate\", currentStep.value) as unknown as\n | boolean\n | Promise<boolean>,\n );\n const valid = result !== false;\n stepValidationStatus[currentStep.value] = valid;\n return valid;\n } catch (error) {\n console.error(\"[Steps Layout] 步骤验证失败:\", error);\n stepValidationStatus[currentStep.value] = false;\n return false;\n }\n};\n\nconst switchToStep = async (\n targetStep: number,\n needValidation = false,\n): Promise<boolean> => {\n if (targetStep < 0 || targetStep >= stepsWithItems.value.length) {\n return false;\n }\n\n if (targetStep === currentStep.value) {\n return true;\n }\n\n try {\n loading.value = true;\n\n /* 验证步骤(如果需要) */\n if (needValidation && stepsConfig.value.validateBeforeNext) {\n const isValid = await validateCurrentStep();\n if (!isValid) {\n return false;\n }\n }\n\n /* 触发步骤切换前事件 */\n await emit(\"step-before-change\", currentStep.value, targetStep);\n\n currentStep.value = targetStep;\n emit(\n \"step-change\",\n currentStep.value,\n stepsWithItems.value[currentStep.value].config.key,\n );\n return true;\n } catch (error) {\n console.error(\"[Steps Layout] 步骤切换失败:\", error);\n return false;\n } finally {\n loading.value = false;\n }\n};\n\n/* ================= 事件处理方法 ================= */\nconst handleNextStep = async (): Promise<void> => {\n await switchToStep(currentStep.value + 1, true);\n};\n\nconst handlePreviousStep = (): void => {\n switchToStep(currentStep.value - 1);\n};\n\nconst goToStep = async (stepIndex: number): Promise<void> => {\n if (stepsWithItems.value[stepIndex]?.config.disabled) {\n return;\n }\n\n const needValidation = stepIndex > currentStep.value;\n await switchToStep(stepIndex, needValidation);\n};\n\nconst initializeCurrentStep = (): void => {\n if (!hasSteps.value || stepsWithItems.value.length === 0) {\n return;\n }\n\n const { defaultStep } = stepsConfig.value;\n const isValidDefaultStep =\n defaultStep >= 0 &&\n defaultStep < stepsWithItems.value.length &&\n !stepsWithItems.value[defaultStep]?.config.disabled;\n\n currentStep.value = isValidDefaultStep ? defaultStep : 0;\n};\n\n/* ================= 生命周期 ================= */\n\n/* 只监听步骤结构变化(key / 数量),不监听表单项内容变化 */\nconst stepStructureKey = computed(() =>\n stepsConfig.value.steps.map((s) => s.key).join(\",\"),\n);\n\nwatch(stepStructureKey, () => {\n initializeCurrentStep();\n});\n\nonMounted(() => {\n initializeCurrentStep();\n});\n\n/* ================= 对外暴露 ================= */\ndefineExpose({\n nextStep: handleNextStep,\n previousStep: handlePreviousStep,\n goToStep,\n validateCurrentStep,\n currentStep: readonly(currentStep),\n totalSteps: computed(() => stepsWithItems.value.length),\n});\n</script>\n\n<style scoped lang=\"scss\">\n@use \"./index.scss\";\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-01\n * @Description: 表单组件 - 步骤表单组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n\n<template>\n <div class=\"c-form-steps\">\n <!-- 无步骤配置时的单一面板模式 -->\n <div v-if=\"!hasSteps\" class=\"single-panel\">\n <component\n v-for=\"(item, index) in formItems\"\n :key=\"getItemKey(item, index)\"\n :is=\"item\"\n />\n </div>\n\n <!-- 有步骤配置时的分步骤模式 -->\n <div v-else class=\"steps-container\">\n <!-- 步骤指示器 -->\n <NSteps\n :current=\"currentStep + 1\"\n :status=\"stepStatus\"\n :size=\"stepsConfig.size\"\n :vertical=\"stepsConfig.vertical\"\n class=\"steps-indicator\"\n >\n <NStep\n v-for=\"step in stepsWithItems\"\n :key=\"step.config.key\"\n :title=\"step.config.title\"\n :description=\"step.config.description\"\n :disabled=\"step.config.disabled\"\n />\n </NSteps>\n\n <!-- 步骤内容区域 -->\n <NCard class=\"steps-content\" :bordered=\"false\">\n <div\n v-for=\"(step, index) in stepsWithItems\"\n v-show=\"currentStep === index\"\n :key=\"step.config.key\"\n class=\"step-panel\"\n >\n <!-- 步骤标题和描述 -->\n <div v-if=\"stepsConfig.showStepHeader\" class=\"step-header\">\n <h3 class=\"step-title\">{{ step.config.title }}</h3>\n <p v-if=\"step.config.description\" class=\"step-description\">\n {{ step.config.description }}\n </p>\n </div>\n\n <!-- 步骤内的表单项 -->\n <div class=\"step-form-items\">\n <component\n v-for=\"(item, itemIndex) in step.items\"\n :key=\"getItemKey(item, itemIndex)\"\n :is=\"item\"\n />\n </div>\n </div>\n </NCard>\n\n <!-- 步骤操作按钮 -->\n <div class=\"steps-actions\">\n <NSpace justify=\"space-between\">\n <NButton\n v-if=\"currentStep > 0\"\n :disabled=\"loading\"\n @click=\"handlePreviousStep\"\n >\n <C_Icon\n :name=\"'mdi:chevron-left-first'\"\n :size=\"16\"\n style=\"margin-right: 4px\"\n />\n {{ stepsConfig.prevButtonText }}\n </NButton>\n\n <div></div>\n\n <NSpace>\n <NButton\n v-if=\"currentStep < stepsWithItems.length - 1\"\n type=\"primary\"\n :loading=\"loading\"\n @click=\"handleNextStep\"\n >\n {{ stepsConfig.nextButtonText }}\n <C_Icon\n :name=\"'mdi:chevron-right-last'\"\n :size=\"16\"\n style=\"margin-left: 4px\"\n />\n </NButton>\n\n <slot\n name=\"step-actions\"\n :current-step=\"currentStep\"\n :total-steps=\"stepsWithItems.length\"\n :is-first-step=\"isFirstStep\"\n :is-last-step=\"isLastStep\"\n :next-step=\"handleNextStep\"\n :previous-step=\"handlePreviousStep\"\n :go-to-step=\"goToStep\"\n />\n </NSpace>\n </NSpace>\n </div>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, reactive, computed, watch, onMounted, readonly } from \"vue\";\nimport type { VNode } from \"vue\";\nimport type { StepConfig, StepsLayoutConfig } from \"../../types\";\nimport C_Icon from \"../../../C_Icon/index.vue\";\n\n/* ================= 类型定义 ================= */\ninterface StepWithItems {\n config: StepConfig;\n items: VNode[];\n}\n\ninterface Props {\n formItems: VNode[];\n layoutConfig?: {\n steps?: StepsLayoutConfig;\n };\n options?: Array<{\n layout?: {\n step?: string;\n };\n }>;\n}\n\n/* ================= 组件属性和事件 ================= */\nconst props = withDefaults(defineProps<Props>(), {\n layoutConfig: () => ({}),\n options: () => [],\n});\n\nconst emit = defineEmits<{\n \"step-change\": [stepIndex: number, stepKey: string];\n \"step-before-change\": [currentStep: number, targetStep: number];\n \"step-validate\": [stepIndex: number];\n}>();\n\n/* ================= 响应式状态 ================= */\nconst currentStep = ref<number>(0);\nconst loading = ref<boolean>(false);\nconst stepValidationStatus = reactive<Record<number, boolean>>({});\n\n/* ================= 计算属性 ================= */\nconst stepsConfig = computed(() => {\n const config = props.layoutConfig?.steps || {};\n return {\n steps: config.steps || [],\n vertical: config.vertical || false,\n size: config.size || \"medium\",\n showStepHeader: config.showStepHeader !== false,\n validateBeforeNext: config.validateBeforeNext || false,\n prevButtonText: config.prevButtonText || \"上一步\",\n nextButtonText: config.nextButtonText || \"下一步\",\n defaultStep: config.defaultStep || 0,\n };\n});\n\nconst hasSteps = computed((): boolean => {\n return stepsConfig.value.steps.length > 0;\n});\n\nconst stepsWithItems = computed((): StepWithItems[] => {\n if (!hasSteps.value) return [];\n\n const stepMap = new Map<string, VNode[]>();\n\n /* 初始化步骤映射 */\n stepsConfig.value.steps.forEach((step) => {\n stepMap.set(step.key, []);\n });\n\n /* 分配表单项到对应步骤 */\n props.formItems.forEach((item, index) => {\n const option = props.options?.[index];\n const stepKey =\n option?.layout?.step || stepsConfig.value.steps[0]?.key || \"default\";\n\n if (!stepMap.has(stepKey)) {\n stepMap.set(stepKey, []);\n }\n stepMap.get(stepKey)!.push(item);\n });\n\n /* 只返回有表单项的步骤 */\n return stepsConfig.value.steps\n .map((stepConfig) => ({\n config: stepConfig,\n items: stepMap.get(stepConfig.key) || [],\n }))\n .filter((step) => step.items.length > 0);\n});\n\nconst stepStatus = computed(() => {\n for (let i = 0; i <= currentStep.value; i++) {\n if (stepValidationStatus[i] === false) {\n return \"error\";\n }\n }\n return \"process\";\n});\n\nconst isFirstStep = computed((): boolean => {\n return currentStep.value === 0;\n});\n\nconst isLastStep = computed((): boolean => {\n return currentStep.value === stepsWithItems.value.length - 1;\n});\n\n/* ================= 工具方法 ================= */\nconst getItemKey = (item: VNode, index: number): string => {\n if (item.key != null) {\n return String(item.key);\n }\n\n const itemProps = item.props as Record<string, any> | null;\n if (itemProps?.path) {\n return itemProps.path;\n }\n\n return `step-item-${index}`;\n};\n\nconst validateCurrentStep = async (): Promise<boolean> => {\n try {\n const result = await Promise.resolve(\n emit(\"step-validate\", currentStep.value) as unknown as\n | boolean\n | Promise<boolean>,\n );\n const valid = result !== false;\n stepValidationStatus[currentStep.value] = valid;\n return valid;\n } catch (error) {\n console.error(\"[Steps Layout] 步骤验证失败:\", error);\n stepValidationStatus[currentStep.value] = false;\n return false;\n }\n};\n\nconst switchToStep = async (\n targetStep: number,\n needValidation = false,\n): Promise<boolean> => {\n if (targetStep < 0 || targetStep >= stepsWithItems.value.length) {\n return false;\n }\n\n if (targetStep === currentStep.value) {\n return true;\n }\n\n try {\n loading.value = true;\n\n /* 验证步骤(如果需要) */\n if (needValidation && stepsConfig.value.validateBeforeNext) {\n const isValid = await validateCurrentStep();\n if (!isValid) {\n return false;\n }\n }\n\n /* 触发步骤切换前事件 */\n await emit(\"step-before-change\", currentStep.value, targetStep);\n\n currentStep.value = targetStep;\n emit(\n \"step-change\",\n currentStep.value,\n stepsWithItems.value[currentStep.value].config.key,\n );\n return true;\n } catch (error) {\n console.error(\"[Steps Layout] 步骤切换失败:\", error);\n return false;\n } finally {\n loading.value = false;\n }\n};\n\n/* ================= 事件处理方法 ================= */\nconst handleNextStep = async (): Promise<void> => {\n await switchToStep(currentStep.value + 1, true);\n};\n\nconst handlePreviousStep = (): void => {\n switchToStep(currentStep.value - 1);\n};\n\nconst goToStep = async (stepIndex: number): Promise<void> => {\n if (stepsWithItems.value[stepIndex]?.config.disabled) {\n return;\n }\n\n const needValidation = stepIndex > currentStep.value;\n await switchToStep(stepIndex, needValidation);\n};\n\nconst initializeCurrentStep = (): void => {\n if (!hasSteps.value || stepsWithItems.value.length === 0) {\n return;\n }\n\n const { defaultStep } = stepsConfig.value;\n const isValidDefaultStep =\n defaultStep >= 0 &&\n defaultStep < stepsWithItems.value.length &&\n !stepsWithItems.value[defaultStep]?.config.disabled;\n\n currentStep.value = isValidDefaultStep ? defaultStep : 0;\n};\n\n/* ================= 生命周期 ================= */\n\n/* 只监听步骤结构变化(key / 数量),不监听表单项内容变化 */\nconst stepStructureKey = computed(() =>\n stepsConfig.value.steps.map((s) => s.key).join(\",\"),\n);\n\nwatch(stepStructureKey, () => {\n initializeCurrentStep();\n});\n\nonMounted(() => {\n initializeCurrentStep();\n});\n\n/* ================= 对外暴露 ================= */\ndefineExpose({\n nextStep: handleNextStep,\n previousStep: handlePreviousStep,\n goToStep,\n validateCurrentStep,\n currentStep: readonly(currentStep),\n totalSteps: computed(() => stepsWithItems.value.length),\n});\n</script>\n\n<style scoped lang=\"scss\">\n@use \"./index.scss\";\n</style>\n","/**\r\n * @description 动态表单状态管理组合式函数\r\n * @module useDynamicFormState\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * @returns 包含动态表单状态和操作方法的对象\r\n */\r\n\r\nimport { reactive, computed, readonly } from 'vue'\r\nimport type {\r\n FormOption,\r\n ComponentType,\r\n DynamicFieldConfig,\r\n DynamicFormConfig,\r\n DynamicFormController,\r\n DynamicFormState,\r\n} from '../types'\r\n\r\n/**\r\n * @description 默认表单配置\r\n */\r\nconst DEFAULT_CONFIG: DynamicFormConfig = {\r\n maxFields: 20,\r\n autoSave: false,\r\n enableSort: true,\r\n showControls: true,\r\n showItemControls: true,\r\n}\r\n\r\n/**\r\n * @description 可用的字段类型选项\r\n */\r\nexport const FIELD_TYPE_OPTIONS = [\r\n { label: '文本输入', value: 'input' as ComponentType },\r\n { label: '数字输入', value: 'inputNumber' as ComponentType },\r\n { label: '多行文本', value: 'textarea' as ComponentType },\r\n { label: '下拉选择', value: 'select' as ComponentType },\r\n { label: '开关切换', value: 'switch' as ComponentType },\r\n { label: '评分组件', value: 'rate' as ComponentType },\r\n]\r\n\r\n/**\r\n * @description 创建和管理动态表单状态\r\n * @returns 包含状态和方法的对象\r\n */\r\nexport const useDynamicFormState = (): DynamicFormController => {\r\n /**\r\n * @description 响应式表单状态\r\n */\r\n const state = reactive<DynamicFormState>({\r\n config: { ...DEFAULT_CONFIG },\r\n baseFields: [],\r\n dynamicFields: [],\r\n hiddenFieldIds: new Set<string>(),\r\n fieldCounter: 0,\r\n isInitialized: false,\r\n })\r\n\r\n /**\r\n * @description 计算所有字段(基础字段+动态字段)\r\n */\r\n const allFields = computed<FormOption[]>(() => [\r\n ...state.baseFields,\r\n ...state.dynamicFields.map(field => ({\r\n ...field,\r\n show: !state.hiddenFieldIds.has(field.prop),\r\n })),\r\n ])\r\n\r\n /**\r\n * @description 计算可见字段\r\n */\r\n const visibleFields = computed<FormOption[]>(() =>\r\n allFields.value.filter(field => field.show !== false)\r\n )\r\n\r\n /**\r\n * @description 计算动态字段数量\r\n */\r\n const dynamicFieldsCount = computed(() => state.dynamicFields.length)\r\n\r\n /**\r\n * @description 计算隐藏字段数量\r\n */\r\n const hiddenFieldsCount = computed(() => state.hiddenFieldIds.size)\r\n\r\n /**\r\n * @description 是否可以添加更多字段\r\n */\r\n const canAddMoreFields = computed(\r\n () => state.dynamicFields.length < state.config.maxFields\r\n )\r\n\r\n /**\r\n * @description 是否所有字段都可见\r\n */\r\n const allVisible = computed(() => state.hiddenFieldIds.size === 0)\r\n\r\n /**\r\n * @description 添加动态字段\r\n * @param config - 字段配置\r\n */\r\n const addField = (config: Partial<DynamicFieldConfig> = {}) => {\r\n if (!canAddMoreFields.value) {\r\n console.warn('[useDynamicFormState] 已达到最大字段数量限制')\r\n return\r\n }\r\n\r\n state.fieldCounter++\r\n\r\n const defaultType =\r\n config.type ||\r\n FIELD_TYPE_OPTIONS[Math.floor(Math.random() * FIELD_TYPE_OPTIONS.length)]\r\n .value\r\n\r\n const newField: DynamicFieldConfig = {\r\n id: `dynamic_field_${state.fieldCounter}`,\r\n type: defaultType,\r\n prop: config.prop || `dynamic_${state.fieldCounter}`,\r\n label: config.label || `动态字段 ${state.fieldCounter}`,\r\n placeholder: config.placeholder || `请输入${config.label || '内容'}`,\r\n visible: true,\r\n removable: true,\r\n created: Date.now(),\r\n layout: config.layout || { span: 12 },\r\n ...config,\r\n }\r\n\r\n state.dynamicFields.push(newField)\r\n\r\n console.log('[useDynamicFormState] 添加字段:', newField)\r\n }\r\n\r\n /**\r\n * @description 移除动态字段\r\n * @param index - 可选,要移除的字段索引,默认移除最后一个\r\n */\r\n const removeField = (index?: number) => {\r\n if (state.dynamicFields.length === 0) {\r\n console.warn('[useDynamicFormState] 没有可移除的动态字段')\r\n return\r\n }\r\n\r\n const targetIndex = index ?? state.dynamicFields.length - 1\r\n\r\n if (targetIndex < 0 || targetIndex >= state.dynamicFields.length) {\r\n console.warn('[useDynamicFormState] 字段索引超出范围')\r\n return\r\n }\r\n\r\n const removed = state.dynamicFields.splice(targetIndex, 1)[0]\r\n if (removed) {\r\n state.hiddenFieldIds.delete(removed.prop)\r\n console.log('[useDynamicFormState] 移除字段:', removed.prop)\r\n }\r\n }\r\n\r\n /**\r\n * @description 清空所有动态字段\r\n */\r\n const clearDynamicFields = () => {\r\n console.log(\r\n '[useDynamicFormState] 清空动态字段:',\r\n state.dynamicFields.length\r\n )\r\n state.dynamicFields.forEach(field =>\r\n state.hiddenFieldIds.delete(field.prop)\r\n )\r\n state.dynamicFields.length = 0\r\n state.fieldCounter = 0\r\n }\r\n\r\n /**\r\n * @description 切换字段可见性\r\n * @param fieldId - 字段ID\r\n */\r\n const toggleFieldVisibility = (fieldId: string) => {\r\n if (state.hiddenFieldIds.has(fieldId)) {\r\n state.hiddenFieldIds.delete(fieldId)\r\n console.log('[useDynamicFormState] 显示字段:', fieldId)\r\n } else {\r\n state.hiddenFieldIds.add(fieldId)\r\n console.log('[useDynamicFormState] 隐藏字段:', fieldId)\r\n }\r\n }\r\n\r\n /**\r\n * @description 切换所有字段可见性\r\n */\r\n const toggleAllVisibility = () => {\r\n if (allVisible.value) {\r\n state.dynamicFields.forEach(field => {\r\n state.hiddenFieldIds.add(field.prop)\r\n })\r\n console.log('[useDynamicFormState] 隐藏所有动态字段')\r\n } else {\r\n state.hiddenFieldIds.clear()\r\n console.log('[useDynamicFormState] 显示所有字段')\r\n }\r\n }\r\n\r\n /**\r\n * @description 更新表单配置\r\n * @param newConfig - 新的配置对象\r\n */\r\n const updateConfig = (newConfig: Partial<DynamicFormConfig>) => {\r\n Object.assign(state.config, newConfig)\r\n console.log('[useDynamicFormState] 更新配置:', newConfig)\r\n }\r\n\r\n /**\r\n * @description 导出当前表单配置\r\n * @returns JSON格式的配置字符串\r\n */\r\n const exportConfig = () => {\r\n const config = {\r\n baseFields: state.baseFields,\r\n dynamicFields: state.dynamicFields,\r\n config: state.config,\r\n hiddenFields: Array.from(state.hiddenFieldIds),\r\n timestamp: Date.now(),\r\n }\r\n return JSON.stringify(config, null, 2)\r\n }\r\n\r\n /**\r\n * @description 初始化表单状态\r\n * @param baseFields - 基础字段配置\r\n * @param config - 可选,表单配置\r\n */\r\n const initialize = (\r\n baseFields: FormOption[],\r\n config: Partial<DynamicFormConfig> = {}\r\n ) => {\r\n console.log('[useDynamicFormState] 初始化状态:', {\r\n baseFieldsCount: baseFields.length,\r\n config,\r\n })\r\n\r\n state.baseFields = [...baseFields]\r\n Object.assign(state.config, config)\r\n state.isInitialized = true\r\n\r\n console.log('[useDynamicFormState] 初始化完成')\r\n }\r\n\r\n return {\r\n state: readonly(state),\r\n allFields,\r\n visibleFields,\r\n dynamicFieldsCount,\r\n hiddenFieldsCount,\r\n canAddMoreFields,\r\n allVisible,\r\n FIELD_TYPE_OPTIONS,\r\n addField,\r\n removeField,\r\n clearDynamicFields,\r\n toggleFieldVisibility,\r\n toggleAllVisibility,\r\n updateConfig,\r\n exportConfig,\r\n initialize,\r\n }\r\n}\r\n\r\n/**\r\n * @description 动态表单状态类型\r\n */\r\nexport type DynamicFormStateType = DynamicFormController\r\n\r\n/**\r\n * @description 动态表单状态注入键\r\n */\r\nexport const DYNAMIC_FORM_STATE_KEY = Symbol('dynamicFormState')\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-01\r\n * @Description: 表单组件 - 动态表单组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"c-form-dynamic\">\r\n <!-- 动态控制面板 -->\r\n <div\r\n v-if=\"showControls && isDynamicStateAvailable\"\r\n class=\"dynamic-controls\"\r\n >\r\n <NCard\r\n size=\"small\"\r\n title=\"动态表单控制\"\r\n :bordered=\"false\"\r\n >\r\n <template #header-extra>\r\n <NBadge\r\n :value=\"dynamicFieldsCount\"\r\n type=\"warning\"\r\n >\r\n <C_Icon\r\n :name=\"'mdi:layers'\"\r\n :size=\"16\"\r\n />\r\n </NBadge>\r\n </template>\r\n\r\n <NSpace\r\n justify=\"space-between\"\r\n align=\"center\"\r\n >\r\n <NSpace>\r\n <NButton\r\n size=\"small\"\r\n type=\"primary\"\r\n :disabled=\"!canAddMoreFields\"\r\n @click=\"dynamicState!.addField()\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"'mdi:plus'\"\r\n :size=\"14\"\r\n />\r\n </template>\r\n 添加字段 ({{ dynamicFieldsCount }}/{{ maxFields }})\r\n </NButton>\r\n\r\n <NButton\r\n size=\"small\"\r\n type=\"warning\"\r\n :disabled=\"dynamicFieldsCount === 0\"\r\n @click=\"dynamicState!.removeField()\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"'mdi:minus'\"\r\n :size=\"14\"\r\n />\r\n </template>\r\n 移除字段\r\n </NButton>\r\n\r\n <NButton\r\n size=\"small\"\r\n type=\"error\"\r\n :disabled=\"dynamicFieldsCount === 0\"\r\n @click=\"dynamicState!.clearDynamicFields()\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"'mdi:delete-sweep'\"\r\n :size=\"14\"\r\n />\r\n </template>\r\n 清空动态\r\n </NButton>\r\n </NSpace>\r\n\r\n <!-- 最大字段数配置 -->\r\n <div class=\"max-fields-config\">\r\n <span>最大字段数:</span>\r\n <NInputNumber\r\n :value=\"maxFields\"\r\n @update:value=\"\r\n (v: any) => v && dynamicState!.updateConfig({ maxFields: v })\r\n \"\r\n :min=\"5\"\r\n :max=\"50\"\r\n size=\"small\"\r\n style=\"width: 100px\"\r\n />\r\n </div>\r\n </NSpace>\r\n\r\n <!-- 状态信息 -->\r\n <div class=\"dynamic-stats\">\r\n <NSpace>\r\n <NTag type=\"info\">总字段: {{ totalFieldsCount }}</NTag>\r\n <NTag type=\"warning\">动态: {{ dynamicFieldsCount }}</NTag>\r\n </NSpace>\r\n </div>\r\n </NCard>\r\n </div>\r\n\r\n <!-- 状态不可用时的提示 -->\r\n <div\r\n v-else-if=\"showControls && !isDynamicStateAvailable\"\r\n class=\"dynamic-controls-fallback\"\r\n >\r\n <NCard\r\n size=\"small\"\r\n title=\"动态表单控制 (静态模式)\"\r\n :bordered=\"false\"\r\n >\r\n <NAlert\r\n type=\"info\"\r\n show-icon\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"'mdi:information-outline'\"\r\n :size=\"16\"\r\n />\r\n </template>\r\n 当前为静态模式,如需动态功能请在父组件中提供动态表单状态。\r\n </NAlert>\r\n </NCard>\r\n </div>\r\n\r\n <!-- 表单项渲染区域 -->\r\n <div class=\"dynamic-form-items\">\r\n <NGrid\r\n :cols=\"gridCols\"\r\n :x-gap=\"gridGutter\"\r\n :y-gap=\"gridGutter\"\r\n >\r\n <NGridItem\r\n v-for=\"(item, index) in formItems\"\r\n :key=\"getItemKey(item, index)\"\r\n :span=\"getItemSpan(index)\"\r\n >\r\n <div\r\n class=\"dynamic-item-wrapper\"\r\n :class=\"{ 'is-dynamic-field': isDynamicField(item) }\"\r\n >\r\n <component :is=\"item\" />\r\n </div>\r\n </NGridItem>\r\n </NGrid>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { computed, inject, type VNode } from 'vue'\r\n import type {\r\n DynamicFieldConfig,\r\n LayoutConfig,\r\n FormOption,\r\n } from '../../types'\r\n import {\r\n DYNAMIC_FORM_STATE_KEY,\r\n type DynamicFormStateType,\r\n } from '../../composables/useDynamicFormState'\r\n import C_Icon from '../../../C_Icon/index.vue'\r\n\r\n /* ================= 接口定义 ================= */\r\n interface Props {\r\n formItems: VNode[]\r\n layoutConfig?: LayoutConfig\r\n options?: FormOption[]\r\n dynamicFormState?: DynamicFormStateType | null\r\n }\r\n\r\n /* ================= 组件配置 ================= */\r\n const props = withDefaults(defineProps<Props>(), {\r\n layoutConfig: () => ({}),\r\n options: () => [],\r\n dynamicFormState: null,\r\n })\r\n\r\n defineEmits<{\r\n 'field-add': [fieldConfig: DynamicFieldConfig]\r\n 'field-remove': [fieldId: string]\r\n 'fields-clear': []\r\n }>()\r\n\r\n /* ================= 状态管理 ================= */\r\n const injectedDynamicState = inject<DynamicFormStateType | null>(\r\n DYNAMIC_FORM_STATE_KEY,\r\n null\r\n )\r\n\r\n const dynamicState = computed(\r\n () => props.dynamicFormState || injectedDynamicState\r\n )\r\n const isDynamicStateAvailable = computed(() => !!dynamicState.value)\r\n\r\n /* ================= 计算属性 ================= */\r\n const gridCols = computed(() => props.layoutConfig?.dynamic?.grid?.cols ?? 24)\r\n const gridGutter = computed(\r\n () => props.layoutConfig?.dynamic?.grid?.gutter ?? 16\r\n )\r\n const showControls = computed(\r\n () => props.layoutConfig?.dynamic?.controls?.showControls !== false\r\n )\r\n\r\n const maxFields = computed(() => {\r\n return (\r\n dynamicState.value?.state.config.maxFields ??\r\n props.layoutConfig?.dynamic?.dynamic?.maxFields ??\r\n 50\r\n )\r\n })\r\n\r\n const dynamicFieldsCount = computed(\r\n () => dynamicState.value?.dynamicFieldsCount.value ?? 0\r\n )\r\n const canAddMoreFields = computed(\r\n () => dynamicState.value?.canAddMoreFields.value ?? false\r\n )\r\n const totalFieldsCount = computed(() => props.formItems.length)\r\n\r\n /* ================= 工具方法 ================= */\r\n const getItemKey = (item: VNode, index: number): string => {\r\n return (\r\n item.key?.toString() ||\r\n (item.props as any)?.path ||\r\n `dynamic-item-${index}`\r\n )\r\n }\r\n\r\n const getItemSpan = (index: number): number => {\r\n const span = props.options?.[index]?.layout?.span\r\n return typeof span === 'number' && span > 0 && span <= gridCols.value\r\n ? span\r\n : Math.min(12, gridCols.value)\r\n }\r\n\r\n const isDynamicField = (item: VNode): boolean => {\r\n if (!dynamicState.value) return false\r\n const fieldId = (item.props as any)?.path || item.key?.toString() || ''\r\n return dynamicState.value.state.dynamicFields.some(\r\n (field: any) => field.prop === fieldId\r\n )\r\n }\r\n\r\n /* ================= 对外暴露 ================= */\r\n defineExpose({\r\n addField: () => dynamicState.value?.addField(),\r\n removeField: () => dynamicState.value?.removeField(),\r\n clearAllDynamic: () => dynamicState.value?.clearDynamicFields(),\r\n isDynamicStateAvailable,\r\n dynamicState,\r\n })\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n @use './index.scss';\r\n</style>\r\n","<!--\r\n * @Author: ChenYu ycyplus@gmail.com\r\n * @Date: 2025-06-01\r\n * @Description: 表单组件 - 动态表单组件\r\n * @Migration: naive-ui-components 组件库迁移版本\r\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\r\n-->\r\n\r\n<template>\r\n <div class=\"c-form-dynamic\">\r\n <!-- 动态控制面板 -->\r\n <div\r\n v-if=\"showControls && isDynamicStateAvailable\"\r\n class=\"dynamic-controls\"\r\n >\r\n <NCard\r\n size=\"small\"\r\n title=\"动态表单控制\"\r\n :bordered=\"false\"\r\n >\r\n <template #header-extra>\r\n <NBadge\r\n :value=\"dynamicFieldsCount\"\r\n type=\"warning\"\r\n >\r\n <C_Icon\r\n :name=\"'mdi:layers'\"\r\n :size=\"16\"\r\n />\r\n </NBadge>\r\n </template>\r\n\r\n <NSpace\r\n justify=\"space-between\"\r\n align=\"center\"\r\n >\r\n <NSpace>\r\n <NButton\r\n size=\"small\"\r\n type=\"primary\"\r\n :disabled=\"!canAddMoreFields\"\r\n @click=\"dynamicState!.addField()\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"'mdi:plus'\"\r\n :size=\"14\"\r\n />\r\n </template>\r\n 添加字段 ({{ dynamicFieldsCount }}/{{ maxFields }})\r\n </NButton>\r\n\r\n <NButton\r\n size=\"small\"\r\n type=\"warning\"\r\n :disabled=\"dynamicFieldsCount === 0\"\r\n @click=\"dynamicState!.removeField()\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"'mdi:minus'\"\r\n :size=\"14\"\r\n />\r\n </template>\r\n 移除字段\r\n </NButton>\r\n\r\n <NButton\r\n size=\"small\"\r\n type=\"error\"\r\n :disabled=\"dynamicFieldsCount === 0\"\r\n @click=\"dynamicState!.clearDynamicFields()\"\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"'mdi:delete-sweep'\"\r\n :size=\"14\"\r\n />\r\n </template>\r\n 清空动态\r\n </NButton>\r\n </NSpace>\r\n\r\n <!-- 最大字段数配置 -->\r\n <div class=\"max-fields-config\">\r\n <span>最大字段数:</span>\r\n <NInputNumber\r\n :value=\"maxFields\"\r\n @update:value=\"\r\n (v: any) => v && dynamicState!.updateConfig({ maxFields: v })\r\n \"\r\n :min=\"5\"\r\n :max=\"50\"\r\n size=\"small\"\r\n style=\"width: 100px\"\r\n />\r\n </div>\r\n </NSpace>\r\n\r\n <!-- 状态信息 -->\r\n <div class=\"dynamic-stats\">\r\n <NSpace>\r\n <NTag type=\"info\">总字段: {{ totalFieldsCount }}</NTag>\r\n <NTag type=\"warning\">动态: {{ dynamicFieldsCount }}</NTag>\r\n </NSpace>\r\n </div>\r\n </NCard>\r\n </div>\r\n\r\n <!-- 状态不可用时的提示 -->\r\n <div\r\n v-else-if=\"showControls && !isDynamicStateAvailable\"\r\n class=\"dynamic-controls-fallback\"\r\n >\r\n <NCard\r\n size=\"small\"\r\n title=\"动态表单控制 (静态模式)\"\r\n :bordered=\"false\"\r\n >\r\n <NAlert\r\n type=\"info\"\r\n show-icon\r\n >\r\n <template #icon>\r\n <C_Icon\r\n :name=\"'mdi:information-outline'\"\r\n :size=\"16\"\r\n />\r\n </template>\r\n 当前为静态模式,如需动态功能请在父组件中提供动态表单状态。\r\n </NAlert>\r\n </NCard>\r\n </div>\r\n\r\n <!-- 表单项渲染区域 -->\r\n <div class=\"dynamic-form-items\">\r\n <NGrid\r\n :cols=\"gridCols\"\r\n :x-gap=\"gridGutter\"\r\n :y-gap=\"gridGutter\"\r\n >\r\n <NGridItem\r\n v-for=\"(item, index) in formItems\"\r\n :key=\"getItemKey(item, index)\"\r\n :span=\"getItemSpan(index)\"\r\n >\r\n <div\r\n class=\"dynamic-item-wrapper\"\r\n :class=\"{ 'is-dynamic-field': isDynamicField(item) }\"\r\n >\r\n <component :is=\"item\" />\r\n </div>\r\n </NGridItem>\r\n </NGrid>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\n import { computed, inject, type VNode } from 'vue'\r\n import type {\r\n DynamicFieldConfig,\r\n LayoutConfig,\r\n FormOption,\r\n } from '../../types'\r\n import {\r\n DYNAMIC_FORM_STATE_KEY,\r\n type DynamicFormStateType,\r\n } from '../../composables/useDynamicFormState'\r\n import C_Icon from '../../../C_Icon/index.vue'\r\n\r\n /* ================= 接口定义 ================= */\r\n interface Props {\r\n formItems: VNode[]\r\n layoutConfig?: LayoutConfig\r\n options?: FormOption[]\r\n dynamicFormState?: DynamicFormStateType | null\r\n }\r\n\r\n /* ================= 组件配置 ================= */\r\n const props = withDefaults(defineProps<Props>(), {\r\n layoutConfig: () => ({}),\r\n options: () => [],\r\n dynamicFormState: null,\r\n })\r\n\r\n defineEmits<{\r\n 'field-add': [fieldConfig: DynamicFieldConfig]\r\n 'field-remove': [fieldId: string]\r\n 'fields-clear': []\r\n }>()\r\n\r\n /* ================= 状态管理 ================= */\r\n const injectedDynamicState = inject<DynamicFormStateType | null>(\r\n DYNAMIC_FORM_STATE_KEY,\r\n null\r\n )\r\n\r\n const dynamicState = computed(\r\n () => props.dynamicFormState || injectedDynamicState\r\n )\r\n const isDynamicStateAvailable = computed(() => !!dynamicState.value)\r\n\r\n /* ================= 计算属性 ================= */\r\n const gridCols = computed(() => props.layoutConfig?.dynamic?.grid?.cols ?? 24)\r\n const gridGutter = computed(\r\n () => props.layoutConfig?.dynamic?.grid?.gutter ?? 16\r\n )\r\n const showControls = computed(\r\n () => props.layoutConfig?.dynamic?.controls?.showControls !== false\r\n )\r\n\r\n const maxFields = computed(() => {\r\n return (\r\n dynamicState.value?.state.config.maxFields ??\r\n props.layoutConfig?.dynamic?.dynamic?.maxFields ??\r\n 50\r\n )\r\n })\r\n\r\n const dynamicFieldsCount = computed(\r\n () => dynamicState.value?.dynamicFieldsCount.value ?? 0\r\n )\r\n const canAddMoreFields = computed(\r\n () => dynamicState.value?.canAddMoreFields.value ?? false\r\n )\r\n const totalFieldsCount = computed(() => props.formItems.length)\r\n\r\n /* ================= 工具方法 ================= */\r\n const getItemKey = (item: VNode, index: number): string => {\r\n return (\r\n item.key?.toString() ||\r\n (item.props as any)?.path ||\r\n `dynamic-item-${index}`\r\n )\r\n }\r\n\r\n const getItemSpan = (index: number): number => {\r\n const span = props.options?.[index]?.layout?.span\r\n return typeof span === 'number' && span > 0 && span <= gridCols.value\r\n ? span\r\n : Math.min(12, gridCols.value)\r\n }\r\n\r\n const isDynamicField = (item: VNode): boolean => {\r\n if (!dynamicState.value) return false\r\n const fieldId = (item.props as any)?.path || item.key?.toString() || ''\r\n return dynamicState.value.state.dynamicFields.some(\r\n (field: any) => field.prop === fieldId\r\n )\r\n }\r\n\r\n /* ================= 对外暴露 ================= */\r\n defineExpose({\r\n addField: () => dynamicState.value?.addField(),\r\n removeField: () => dynamicState.value?.removeField(),\r\n clearAllDynamic: () => dynamicState.value?.clearDynamicFields(),\r\n isDynamicStateAvailable,\r\n dynamicState,\r\n })\r\n</script>\r\n\r\n<style scoped lang=\"scss\">\r\n @use './index.scss';\r\n</style>\r\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-01\n * @Description: 表单组件 - 自定义布局组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n\n<template>\n <div class=\"custom-layout\">\n <!-- 顶部工具栏 -->\n <NCard\n :bordered=\"false\"\n class=\"toolbar-card\"\n >\n <div class=\"toolbar-content\">\n <!-- 模式切换 -->\n <div class=\"mode-section\">\n <span class=\"section-label\">自定义模式:</span>\n <NButtonGroup>\n <NButton\n :type=\"isDesignMode ? 'primary' : 'default'\"\n @click=\"isDesignMode = true\"\n size=\"small\"\n >\n 🎨 设计模式\n </NButton>\n <NButton\n :type=\"!isDesignMode ? 'primary' : 'default'\"\n @click=\"isDesignMode = false\"\n size=\"small\"\n >\n 📝 填写模式\n </NButton>\n </NButtonGroup>\n </div>\n\n <!-- 统计信息 -->\n <div class=\"stats-section\">\n <div class=\"stat-item\">\n <div class=\"stat-value\">{{ customAreas.length }}</div>\n <div class=\"stat-label\">自定义区域</div>\n </div>\n <div class=\"stat-item\">\n <div class=\"stat-value\">{{ totalFieldsCount }}</div>\n <div class=\"stat-label\">字段总数</div>\n </div>\n </div>\n\n <!-- 操作按钮 -->\n <div class=\"actions-section\">\n <template v-if=\"isDesignMode\">\n <NButton\n secondary\n @click=\"handleSaveLayout\"\n size=\"small\"\n >\n 💾 保存布局\n </NButton>\n <NButton\n secondary\n @click=\"handleResetLayout\"\n size=\"small\"\n >\n 🔄 重置布局\n </NButton>\n </template>\n <template v-else>\n <NButton\n secondary\n @click=\"handleExportData\"\n size=\"small\"\n >\n 📊 导出数据\n </NButton>\n </template>\n </div>\n </div>\n </NCard>\n\n <!-- 设计模式工具面板 -->\n <NCard\n v-if=\"isDesignMode\"\n class=\"design-panel\"\n title=\"🎨 设计工具\"\n >\n <div class=\"design-tools\">\n <div class=\"tool-group\">\n <span class=\"group-label\">添加区域:</span>\n <NButton\n @click=\"addArea('horizontal')\"\n size=\"small\"\n >\n ➡️ 水平区域\n </NButton>\n <NButton\n @click=\"addArea('vertical')\"\n size=\"small\"\n >\n ⬇️ 垂直区域\n </NButton>\n <NButton\n @click=\"addArea('grid')\"\n size=\"small\"\n >\n ⚏ 网格区域\n </NButton>\n </div>\n </div>\n </NCard>\n\n <!-- 主画布区域 -->\n <div\n class=\"layout-canvas\"\n :class=\"{ 'design-mode': isDesignMode }\"\n >\n <!-- 设计模式 -->\n <template v-if=\"isDesignMode\">\n <div\n class=\"canvas-hint\"\n v-if=\"customAreas.length === 0\"\n >\n <div class=\"hint-content\">\n <h3>🎨 开始自定义你的布局</h3>\n <p>点击上方按钮添加区域</p>\n </div>\n </div>\n\n <!-- 区域列表 -->\n <div\n v-else\n class=\"areas-container\"\n >\n <div\n v-for=\"area in customAreas\"\n :key=\"area.id\"\n class=\"custom-area\"\n :class=\"`area-${area.type}`\"\n >\n <div class=\"area-header\">\n <div class=\"area-info\">\n <NInput\n v-if=\"editingTitleId === area.id\"\n v-model:value=\"area.title\"\n size=\"small\"\n @blur=\"editingTitleId = ''\"\n @keyup.enter=\"editingTitleId = ''\"\n class=\"title-input\"\n />\n <span\n v-else\n class=\"area-title\"\n @click=\"editingTitleId = area.id\"\n >\n {{ area.title }}\n </span>\n <NTag size=\"small\">{{ area.fields.length }} 字段</NTag>\n </div>\n <div class=\"area-controls\">\n <NButton\n text\n @click=\"deleteArea(area.id)\"\n size=\"tiny\"\n type=\"error\"\n title=\"删除区域\"\n >\n 🗑️\n </NButton>\n </div>\n </div>\n\n <!-- 字段容器(可拖入) -->\n <VueDraggable\n v-model=\"area.fields\"\n class=\"area-fields\"\n :group=\"{ name: 'form-fields', pull: true, put: true }\"\n :animation=\"200\"\n ghost-class=\"field-ghost\"\n item-key=\"id\"\n >\n <div\n v-for=\"field in area.fields\"\n :key=\"field.id\"\n class=\"field-item\"\n >\n <div class=\"field-preview\">\n <span class=\"drag-handle\">⠿</span>\n <span class=\"field-label\">{{\n field.label || field.prop\n }}</span>\n <span class=\"field-type\">{{\n getFieldTypeName(field.type)\n }}</span>\n <NButton\n text\n size=\"tiny\"\n type=\"error\"\n @click=\"removeFieldFromArea(area.id, field.id)\"\n title=\"移出字段\"\n >\n ✕\n </NButton>\n </div>\n </div>\n </VueDraggable>\n\n <div\n class=\"area-drop-zone\"\n v-if=\"area.fields.length === 0\"\n >\n 从下方字段池拖拽字段到这里\n </div>\n </div>\n </div>\n\n <!-- 字段池(可拖出) -->\n <NCard\n class=\"field-pool\"\n title=\"📦 可用字段\"\n >\n <VueDraggable\n v-model=\"availableFields\"\n class=\"pool-fields-grid\"\n :group=\"{ name: 'form-fields', pull: 'clone', put: true }\"\n :animation=\"200\"\n :sort=\"false\"\n ghost-class=\"field-ghost\"\n item-key=\"id\"\n :clone=\"cloneField\"\n >\n <div\n v-for=\"field in availableFields\"\n :key=\"field.id\"\n class=\"pool-field\"\n >\n <span class=\"drag-handle\">⠿</span>\n <span class=\"field-name\">{{ field.label || field.prop }}</span>\n <span class=\"field-type-tag\">{{\n getFieldTypeName(field.type)\n }}</span>\n </div>\n </VueDraggable>\n </NCard>\n </template>\n\n <!-- 填写模式 -->\n <template v-else>\n <div\n v-if=\"customAreas.length === 0\"\n class=\"empty-layout\"\n >\n <NEmpty description=\"尚未设计布局\">\n <template #extra>\n <NButton\n @click=\"isDesignMode = true\"\n type=\"primary\"\n >\n 🎨 开始设计\n </NButton>\n </template>\n </NEmpty>\n </div>\n\n <div\n v-else\n class=\"form-container\"\n >\n <div class=\"form-areas\">\n <div\n v-for=\"area in customAreas\"\n :key=\"area.id\"\n class=\"form-area\"\n :class=\"`area-${area.type}`\"\n >\n <NCard\n v-if=\"area.fields.length > 0\"\n :title=\"area.title\"\n >\n <div\n class=\"area-form-items\"\n :class=\"`layout-${area.type}`\"\n >\n <component\n v-for=\"field in area.fields\"\n :key=\"field.prop\"\n :is=\"getFormItemForField(field)\"\n />\n </div>\n </NCard>\n <NEmpty\n v-else\n description=\"此区域暂无字段\"\n size=\"small\"\n >\n <template #extra>\n <NButton\n @click=\"isDesignMode = true\"\n size=\"small\"\n secondary\n >\n 🎨 添加字段\n </NButton>\n </template>\n </NEmpty>\n </div>\n </div>\n </div>\n </template>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, watchEffect, type VNode } from 'vue'\n import { VueDraggable } from 'vue-draggable-plus'\n import type { FormOption } from '../../types'\n\n /* 接口定义 */\n interface CustomArea {\n id: string\n title: string\n type: 'horizontal' | 'vertical' | 'grid'\n fields: DraggableFormOption[]\n }\n\n interface DraggableFormOption extends FormOption {\n id: string\n }\n\n interface Props {\n options?: FormOption[]\n formItems?: VNode[]\n formData?: Record<string, any>\n }\n\n const props = withDefaults(defineProps<Props>(), {\n options: () => [],\n formItems: () => [],\n formData: () => ({}),\n })\n\n const emit = defineEmits<{\n 'fields-change': [fields: FormOption[]]\n 'export-data': [data: any]\n }>()\n\n /* 响应式状态 */\n const isDesignMode = ref(true)\n const customAreas = ref<CustomArea[]>([])\n const availableFields = ref<DraggableFormOption[]>([])\n const editingTitleId = ref<string | number>('')\n\n /* 计算属性 */\n const allFormOptions = computed(() => {\n if (props.options?.length > 0) {\n return props.options\n }\n\n return (\n props.formItems\n ?.map((item: VNode) => {\n const itemProps = item.props as any\n return {\n prop: itemProps?.path || '',\n label: itemProps?.label || itemProps?.path || '',\n type: 'input',\n show: true,\n } as FormOption\n })\n .filter(option => option.prop) || []\n )\n })\n\n const totalFieldsCount = computed(() =>\n customAreas.value.reduce((total, area) => total + area.fields.length, 0)\n )\n\n /* 工具函数 */\n const generateId = () =>\n `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`\n\n const getFieldTypeName = (type: string) => {\n const typeMap: Record<string, string> = {\n input: '输入框',\n select: '下拉框',\n radio: '单选框',\n checkbox: '复选框',\n textarea: '文本域',\n date: '日期',\n number: '数字',\n }\n return typeMap[type] || type\n }\n\n const getFormItemForField = (field: FormOption) => {\n return (\n props.formItems?.find((item: VNode) => {\n const itemProps = item.props as any\n return itemProps?.path === field.prop\n }) || null\n )\n }\n\n /* 布局操作 */\n const addArea = (type: 'horizontal' | 'vertical' | 'grid') => {\n const area: CustomArea = {\n id: generateId(),\n title: `${type === 'horizontal' ? '水平' : type === 'vertical' ? '垂直' : '网格'}区域`,\n type,\n fields: [],\n }\n customAreas.value.push(area)\n }\n\n const deleteArea = (areaId: string | number) => {\n const index = customAreas.value.findIndex(area => area.id === areaId)\n if (index !== -1) {\n customAreas.value.splice(index, 1)\n }\n }\n\n /** 克隆字段(从字段池拖出时使用副本,保证字段池不丢数据) */\n const cloneField = (field: DraggableFormOption) => ({\n ...field,\n id: `${field.prop}-${generateId()}`,\n })\n\n /** 从指定区域移除字段 */\n const removeFieldFromArea = (\n areaId: string | number,\n fieldId: string | number\n ) => {\n const area = customAreas.value.find(a => a.id === areaId)\n if (area) {\n const idx = area.fields.findIndex(f => f.id === fieldId)\n if (idx !== -1) area.fields.splice(idx, 1)\n }\n }\n\n const handleSaveLayout = () => {\n const config = JSON.stringify(customAreas.value, null, 2)\n const blob = new Blob([config], { type: 'application/json' })\n const url = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = `layout-config-${Date.now()}.json`\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n URL.revokeObjectURL(url)\n }\n\n const handleResetLayout = () => {\n customAreas.value = []\n }\n\n const handleExportData = () => {\n const exportData = {\n layout: customAreas.value,\n formData: props.formData,\n timestamp: new Date().toISOString(),\n }\n emit('export-data', exportData)\n }\n\n /* 监听器 */\n watchEffect(() => {\n const usedProps = new Set(\n customAreas.value.flatMap(area => area.fields.map(field => field.prop))\n )\n\n availableFields.value = allFormOptions.value\n .filter(field => !usedProps.has(field.prop))\n .map(field => ({\n ...field,\n id: field.prop,\n }))\n })\n\n watch(\n () => customAreas.value,\n () => {\n const allFields = customAreas.value.flatMap(area =>\n area.fields.map(field => ({\n ...field,\n id: undefined,\n }))\n )\n emit('fields-change', allFields)\n },\n { deep: true }\n )\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Date: 2025-06-01\n * @Description: 表单组件 - 自定义布局组件\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n\n<template>\n <div class=\"custom-layout\">\n <!-- 顶部工具栏 -->\n <NCard\n :bordered=\"false\"\n class=\"toolbar-card\"\n >\n <div class=\"toolbar-content\">\n <!-- 模式切换 -->\n <div class=\"mode-section\">\n <span class=\"section-label\">自定义模式:</span>\n <NButtonGroup>\n <NButton\n :type=\"isDesignMode ? 'primary' : 'default'\"\n @click=\"isDesignMode = true\"\n size=\"small\"\n >\n 🎨 设计模式\n </NButton>\n <NButton\n :type=\"!isDesignMode ? 'primary' : 'default'\"\n @click=\"isDesignMode = false\"\n size=\"small\"\n >\n 📝 填写模式\n </NButton>\n </NButtonGroup>\n </div>\n\n <!-- 统计信息 -->\n <div class=\"stats-section\">\n <div class=\"stat-item\">\n <div class=\"stat-value\">{{ customAreas.length }}</div>\n <div class=\"stat-label\">自定义区域</div>\n </div>\n <div class=\"stat-item\">\n <div class=\"stat-value\">{{ totalFieldsCount }}</div>\n <div class=\"stat-label\">字段总数</div>\n </div>\n </div>\n\n <!-- 操作按钮 -->\n <div class=\"actions-section\">\n <template v-if=\"isDesignMode\">\n <NButton\n secondary\n @click=\"handleSaveLayout\"\n size=\"small\"\n >\n 💾 保存布局\n </NButton>\n <NButton\n secondary\n @click=\"handleResetLayout\"\n size=\"small\"\n >\n 🔄 重置布局\n </NButton>\n </template>\n <template v-else>\n <NButton\n secondary\n @click=\"handleExportData\"\n size=\"small\"\n >\n 📊 导出数据\n </NButton>\n </template>\n </div>\n </div>\n </NCard>\n\n <!-- 设计模式工具面板 -->\n <NCard\n v-if=\"isDesignMode\"\n class=\"design-panel\"\n title=\"🎨 设计工具\"\n >\n <div class=\"design-tools\">\n <div class=\"tool-group\">\n <span class=\"group-label\">添加区域:</span>\n <NButton\n @click=\"addArea('horizontal')\"\n size=\"small\"\n >\n ➡️ 水平区域\n </NButton>\n <NButton\n @click=\"addArea('vertical')\"\n size=\"small\"\n >\n ⬇️ 垂直区域\n </NButton>\n <NButton\n @click=\"addArea('grid')\"\n size=\"small\"\n >\n ⚏ 网格区域\n </NButton>\n </div>\n </div>\n </NCard>\n\n <!-- 主画布区域 -->\n <div\n class=\"layout-canvas\"\n :class=\"{ 'design-mode': isDesignMode }\"\n >\n <!-- 设计模式 -->\n <template v-if=\"isDesignMode\">\n <div\n class=\"canvas-hint\"\n v-if=\"customAreas.length === 0\"\n >\n <div class=\"hint-content\">\n <h3>🎨 开始自定义你的布局</h3>\n <p>点击上方按钮添加区域</p>\n </div>\n </div>\n\n <!-- 区域列表 -->\n <div\n v-else\n class=\"areas-container\"\n >\n <div\n v-for=\"area in customAreas\"\n :key=\"area.id\"\n class=\"custom-area\"\n :class=\"`area-${area.type}`\"\n >\n <div class=\"area-header\">\n <div class=\"area-info\">\n <NInput\n v-if=\"editingTitleId === area.id\"\n v-model:value=\"area.title\"\n size=\"small\"\n @blur=\"editingTitleId = ''\"\n @keyup.enter=\"editingTitleId = ''\"\n class=\"title-input\"\n />\n <span\n v-else\n class=\"area-title\"\n @click=\"editingTitleId = area.id\"\n >\n {{ area.title }}\n </span>\n <NTag size=\"small\">{{ area.fields.length }} 字段</NTag>\n </div>\n <div class=\"area-controls\">\n <NButton\n text\n @click=\"deleteArea(area.id)\"\n size=\"tiny\"\n type=\"error\"\n title=\"删除区域\"\n >\n 🗑️\n </NButton>\n </div>\n </div>\n\n <!-- 字段容器(可拖入) -->\n <VueDraggable\n v-model=\"area.fields\"\n class=\"area-fields\"\n :group=\"{ name: 'form-fields', pull: true, put: true }\"\n :animation=\"200\"\n ghost-class=\"field-ghost\"\n item-key=\"id\"\n >\n <div\n v-for=\"field in area.fields\"\n :key=\"field.id\"\n class=\"field-item\"\n >\n <div class=\"field-preview\">\n <span class=\"drag-handle\">⠿</span>\n <span class=\"field-label\">{{\n field.label || field.prop\n }}</span>\n <span class=\"field-type\">{{\n getFieldTypeName(field.type)\n }}</span>\n <NButton\n text\n size=\"tiny\"\n type=\"error\"\n @click=\"removeFieldFromArea(area.id, field.id)\"\n title=\"移出字段\"\n >\n ✕\n </NButton>\n </div>\n </div>\n </VueDraggable>\n\n <div\n class=\"area-drop-zone\"\n v-if=\"area.fields.length === 0\"\n >\n 从下方字段池拖拽字段到这里\n </div>\n </div>\n </div>\n\n <!-- 字段池(可拖出) -->\n <NCard\n class=\"field-pool\"\n title=\"📦 可用字段\"\n >\n <VueDraggable\n v-model=\"availableFields\"\n class=\"pool-fields-grid\"\n :group=\"{ name: 'form-fields', pull: 'clone', put: true }\"\n :animation=\"200\"\n :sort=\"false\"\n ghost-class=\"field-ghost\"\n item-key=\"id\"\n :clone=\"cloneField\"\n >\n <div\n v-for=\"field in availableFields\"\n :key=\"field.id\"\n class=\"pool-field\"\n >\n <span class=\"drag-handle\">⠿</span>\n <span class=\"field-name\">{{ field.label || field.prop }}</span>\n <span class=\"field-type-tag\">{{\n getFieldTypeName(field.type)\n }}</span>\n </div>\n </VueDraggable>\n </NCard>\n </template>\n\n <!-- 填写模式 -->\n <template v-else>\n <div\n v-if=\"customAreas.length === 0\"\n class=\"empty-layout\"\n >\n <NEmpty description=\"尚未设计布局\">\n <template #extra>\n <NButton\n @click=\"isDesignMode = true\"\n type=\"primary\"\n >\n 🎨 开始设计\n </NButton>\n </template>\n </NEmpty>\n </div>\n\n <div\n v-else\n class=\"form-container\"\n >\n <div class=\"form-areas\">\n <div\n v-for=\"area in customAreas\"\n :key=\"area.id\"\n class=\"form-area\"\n :class=\"`area-${area.type}`\"\n >\n <NCard\n v-if=\"area.fields.length > 0\"\n :title=\"area.title\"\n >\n <div\n class=\"area-form-items\"\n :class=\"`layout-${area.type}`\"\n >\n <component\n v-for=\"field in area.fields\"\n :key=\"field.prop\"\n :is=\"getFormItemForField(field)\"\n />\n </div>\n </NCard>\n <NEmpty\n v-else\n description=\"此区域暂无字段\"\n size=\"small\"\n >\n <template #extra>\n <NButton\n @click=\"isDesignMode = true\"\n size=\"small\"\n secondary\n >\n 🎨 添加字段\n </NButton>\n </template>\n </NEmpty>\n </div>\n </div>\n </div>\n </template>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\n import { ref, computed, watch, watchEffect, type VNode } from 'vue'\n import { VueDraggable } from 'vue-draggable-plus'\n import type { FormOption } from '../../types'\n\n /* 接口定义 */\n interface CustomArea {\n id: string\n title: string\n type: 'horizontal' | 'vertical' | 'grid'\n fields: DraggableFormOption[]\n }\n\n interface DraggableFormOption extends FormOption {\n id: string\n }\n\n interface Props {\n options?: FormOption[]\n formItems?: VNode[]\n formData?: Record<string, any>\n }\n\n const props = withDefaults(defineProps<Props>(), {\n options: () => [],\n formItems: () => [],\n formData: () => ({}),\n })\n\n const emit = defineEmits<{\n 'fields-change': [fields: FormOption[]]\n 'export-data': [data: any]\n }>()\n\n /* 响应式状态 */\n const isDesignMode = ref(true)\n const customAreas = ref<CustomArea[]>([])\n const availableFields = ref<DraggableFormOption[]>([])\n const editingTitleId = ref<string | number>('')\n\n /* 计算属性 */\n const allFormOptions = computed(() => {\n if (props.options?.length > 0) {\n return props.options\n }\n\n return (\n props.formItems\n ?.map((item: VNode) => {\n const itemProps = item.props as any\n return {\n prop: itemProps?.path || '',\n label: itemProps?.label || itemProps?.path || '',\n type: 'input',\n show: true,\n } as FormOption\n })\n .filter(option => option.prop) || []\n )\n })\n\n const totalFieldsCount = computed(() =>\n customAreas.value.reduce((total, area) => total + area.fields.length, 0)\n )\n\n /* 工具函数 */\n const generateId = () =>\n `${Date.now()}-${Math.random().toString(36).substring(2, 11)}`\n\n const getFieldTypeName = (type: string) => {\n const typeMap: Record<string, string> = {\n input: '输入框',\n select: '下拉框',\n radio: '单选框',\n checkbox: '复选框',\n textarea: '文本域',\n date: '日期',\n number: '数字',\n }\n return typeMap[type] || type\n }\n\n const getFormItemForField = (field: FormOption) => {\n return (\n props.formItems?.find((item: VNode) => {\n const itemProps = item.props as any\n return itemProps?.path === field.prop\n }) || null\n )\n }\n\n /* 布局操作 */\n const addArea = (type: 'horizontal' | 'vertical' | 'grid') => {\n const area: CustomArea = {\n id: generateId(),\n title: `${type === 'horizontal' ? '水平' : type === 'vertical' ? '垂直' : '网格'}区域`,\n type,\n fields: [],\n }\n customAreas.value.push(area)\n }\n\n const deleteArea = (areaId: string | number) => {\n const index = customAreas.value.findIndex(area => area.id === areaId)\n if (index !== -1) {\n customAreas.value.splice(index, 1)\n }\n }\n\n /** 克隆字段(从字段池拖出时使用副本,保证字段池不丢数据) */\n const cloneField = (field: DraggableFormOption) => ({\n ...field,\n id: `${field.prop}-${generateId()}`,\n })\n\n /** 从指定区域移除字段 */\n const removeFieldFromArea = (\n areaId: string | number,\n fieldId: string | number\n ) => {\n const area = customAreas.value.find(a => a.id === areaId)\n if (area) {\n const idx = area.fields.findIndex(f => f.id === fieldId)\n if (idx !== -1) area.fields.splice(idx, 1)\n }\n }\n\n const handleSaveLayout = () => {\n const config = JSON.stringify(customAreas.value, null, 2)\n const blob = new Blob([config], { type: 'application/json' })\n const url = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = `layout-config-${Date.now()}.json`\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n URL.revokeObjectURL(url)\n }\n\n const handleResetLayout = () => {\n customAreas.value = []\n }\n\n const handleExportData = () => {\n const exportData = {\n layout: customAreas.value,\n formData: props.formData,\n timestamp: new Date().toISOString(),\n }\n emit('export-data', exportData)\n }\n\n /* 监听器 */\n watchEffect(() => {\n const usedProps = new Set(\n customAreas.value.flatMap(area => area.fields.map(field => field.prop))\n )\n\n availableFields.value = allFormOptions.value\n .filter(field => !usedProps.has(field.prop))\n .map(field => ({\n ...field,\n id: field.prop,\n }))\n })\n\n watch(\n () => customAreas.value,\n () => {\n const allFields = customAreas.value.flatMap(area =>\n area.fields.map(field => ({\n ...field,\n id: undefined,\n }))\n )\n emit('fields-change', allFields)\n },\n { deep: true }\n )\n</script>\n\n<style lang=\"scss\" scoped>\n @use './index.scss';\n</style>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Description: 表单组件 — 薄 UI 壳 + 厚 Composable 引擎\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n\n<template>\n <NForm\n ref=\"formRef\"\n :model=\"formModel\"\n :rules=\"formRules\"\n :validate-on-rule-change=\"false\"\n :label-placement=\"resolved.labelPlacement\"\n :label-width=\"resolved.labelWidth\"\n :size=\"resolved.size\"\n :disabled=\"resolved.disabled\"\n :readonly=\"resolved.readonly\"\n v-bind=\"$attrs\"\n >\n <!-- 布局组件渲染 -->\n <component\n :is=\"layoutComponent\"\n :form-items=\"formItems\"\n :layout-config=\"mergedLayoutConfig\"\n :options=\"visibleOptions\"\n :form-data=\"formModel\"\n @tab-change=\"handleLayoutEvent('onTabChange', $event)\"\n @tab-validate=\"handleLayoutEvent('onTabValidate', $event)\"\n @step-change=\"handleStepChange\"\n @step-before-change=\"handleStepBeforeChange\"\n @step-validate=\"handleStepValidate\"\n @field-add=\"handleLayoutEvent('onFieldAdd', $event)\"\n @field-remove=\"handleLayoutEvent('onFieldRemove', $event)\"\n @field-toggle=\"\n (id: string, visible: boolean) => resolved.onFieldToggle?.(id, visible)\n \"\n @fields-clear=\"handleLayoutEvent('onFieldsClear')\"\n @render-mode-change=\"handleLayoutEvent('onRenderModeChange', $event)\"\n @group-toggle=\"\n (key: string, collapsed: boolean) =>\n resolved.onGroupToggle?.(key, collapsed)\n \"\n @group-reset=\"handleLayoutEvent('onGroupReset', $event)\"\n @validate-success=\"(model: FormModel) => emit('validate-success', model)\"\n @validate-error=\"(errors: unknown) => emit('validate-error', errors)\"\n @fields-change=\"handleFieldsChange\"\n />\n\n <!-- 表单操作按钮区域(只在特定布局中显示) -->\n <NFormItem\n v-if=\"showActions\"\n style=\"margin-top: 20px\"\n >\n <slot\n name=\"action\"\n :form=\"formRef\"\n :model=\"formModel\"\n :validate=\"validate\"\n :validateField=\"validateField\"\n :reset=\"resetFields\"\n :setFields=\"setFields\"\n :getModel=\"getModel\"\n :clearValidation=\"clearValidation\"\n >\n <NSpace>\n <NButton\n type=\"primary\"\n @click=\"handleSubmit\"\n >提交</NButton\n >\n <NButton @click=\"handleReset\">重置</NButton>\n </NSpace>\n </slot>\n </NFormItem>\n </NForm>\n</template>\n\n<script lang=\"ts\" setup>\n import { computed, ref, watch, getCurrentInstance, nextTick } from 'vue'\n import type { FormInst } from 'naive-ui/es/form'\n import {\n NForm,\n NFormItem,\n NButton,\n NSpace,\n NInput,\n NInputNumber,\n NSwitch,\n NSlider,\n NRate,\n NDatePicker,\n NTimePicker,\n NCascader,\n NColorPicker,\n NSelect,\n NCheckboxGroup,\n NCheckbox,\n NRadioGroup,\n NRadio,\n NUpload,\n NTooltip,\n } from 'naive-ui'\n import { C_Editor } from '../C_Editor'\n import type {\n FormOption,\n LayoutType,\n LayoutConfig,\n SubmitEventPayload,\n FormModel,\n } from './types'\n import {\n type FormConfig,\n resolveFormConfig,\n shouldShowActions as calcShowActions,\n } from './composables/useFormConfig'\n import { useFormState } from './composables/useFormState'\n import {\n useFormRenderer,\n type ComponentMap,\n } from './composables/useFormRenderer'\n\n /* ===== 布局组件静态映射(取代 DynamicComponent) ===== */\n import DefaultLayout from './layouts/Default/index.vue'\n import InlineLayout from './layouts/Inline/index.vue'\n import GridLayout from './layouts/Grid/index.vue'\n import CardLayout from './layouts/Card/index.vue'\n import TabsLayout from './layouts/Tabs/index.vue'\n import StepsLayout from './layouts/Steps/index.vue'\n import DynamicLayout from './layouts/Dynamic/index.vue'\n import CustomLayout from './layouts/Custom/index.vue'\n\n defineOptions({ name: 'C_Form' })\n\n const LAYOUT_MAP: Record<LayoutType, any> = {\n default: DefaultLayout,\n inline: InlineLayout,\n grid: GridLayout,\n card: CardLayout,\n tabs: TabsLayout,\n steps: StepsLayout,\n dynamic: DynamicLayout,\n custom: CustomLayout,\n } as const\n\n /* ===== Naive UI 组件映射 ===== */\n /*\n * 库代码是预构建产物,resolveComponent 无法在运行时解析未全局注册的组件。\n * 直接 import 即可。naive-ui 作为 peerDependency,与消费项目共享同一份实例。\n */\n const COMPONENT_MAP: ComponentMap = {\n NFormItem,\n NInput,\n NInputNumber,\n NSwitch,\n NSlider,\n NRate,\n NDatePicker,\n NTimePicker,\n NCascader,\n NColorPicker,\n NSelect,\n NCheckboxGroup,\n NCheckbox,\n NRadioGroup,\n NRadio,\n NUpload,\n NButton,\n NSpace,\n NTooltip,\n C_Editor,\n } as ComponentMap\n\n /* ================= 组件属性定义 ================= */\n\n interface CFormProps {\n /** 字段配置数组 */\n options: FormOption[]\n /** 双向绑定表单数据 */\n modelValue?: FormModel\n /** 统一配置对象(收拢原先 13 个分散 Props) */\n config?: FormConfig\n }\n\n const props = withDefaults(defineProps<CFormProps>(), {\n config: () => ({}),\n })\n\n /* ================= 组件事件定义(从 16 个精简到 4 个) ================= */\n\n const emit = defineEmits<{\n submit: [payload: SubmitEventPayload]\n 'update:modelValue': [model: FormModel]\n 'validate-success': [model: FormModel]\n 'validate-error': [errors: unknown]\n }>()\n\n /* ================= 配置解析 ================= */\n\n const resolved = computed(() => resolveFormConfig(props.config))\n\n /* ================= 响应式状态 ================= */\n\n const formRef = ref<FormInst | null>(null)\n const optionsRef = computed(() => props.options)\n\n /* ===== 状态引擎 ===== */\n const {\n formModel,\n formRules,\n visibleOptions,\n initialize,\n handleFieldChange,\n validate,\n validateField,\n validateStep,\n validateTab,\n validateDynamicFields,\n validateCustomGroup,\n clearValidation,\n getModel,\n setFields,\n resetFields,\n setFieldValue,\n getFieldValue,\n setFieldsValue,\n handleSubmit,\n handleReset,\n /* v0.8.0 新增 */\n isDirty,\n getChangedFields,\n isFieldDirty,\n markAsClean,\n asyncOptionsCache,\n asyncLoadingMap,\n } = useFormState(optionsRef, resolved, formRef, emit)\n\n /* ===== 渲染引擎 ===== */\n const currentInstance = getCurrentInstance()\n const { formItems } = useFormRenderer({\n formModel,\n visibleOptions,\n config: resolved,\n handleFieldChange,\n componentMap: COMPONENT_MAP,\n instanceSlots: currentInstance?.slots,\n asyncOptionsCache,\n asyncLoadingMap,\n })\n\n /* ===== 编辑模式:自动回填 initialValues ===== */\n watch(\n () => resolved.value.initialValues,\n val => {\n if (val && resolved.value.mode === 'edit') {\n Object.assign(formModel, val)\n nextTick(() => markAsClean())\n }\n },\n { immediate: true }\n )\n\n /* ================= 计算属性 ================= */\n\n const layoutComponent = computed(\n () => LAYOUT_MAP[resolved.value.layout] || LAYOUT_MAP.default\n )\n\n const mergedLayoutConfig = computed<LayoutConfig>(() => ({\n type: resolved.value.layout,\n grid: resolved.value.grid,\n inline: resolved.value.inline,\n card: resolved.value.card,\n tabs: resolved.value.tabs,\n steps: resolved.value.steps,\n dynamic: resolved.value.dynamic,\n custom: resolved.value.custom,\n }))\n\n const showActions = computed(() => calcShowActions(resolved.value))\n\n /* ================= 布局事件 → config 回调桥接 ================= */\n\n /** 通用布局事件桥接 */\n const handleLayoutEvent = (callbackName: string, ...args: any[]) => {\n const callback = (resolved.value as any)[callbackName]\n callback?.(...args)\n }\n\n /** 字段变化事件(保留回调通道) */\n const handleFieldsChange = (fields: FormOption[]): void => {\n resolved.value.onFieldsChange?.(fields)\n }\n\n /** Steps 布局事件 — 需要多参数特殊处理 */\n const handleStepChange = (stepIndex: number, stepKey: string): void => {\n resolved.value.onStepChange?.(stepIndex, stepKey)\n }\n\n const handleStepBeforeChange = async (\n currentStep: number,\n targetStep: number\n ): Promise<boolean> => {\n resolved.value.onStepBeforeChange?.(currentStep, targetStep)\n return true\n }\n\n const handleStepValidate = async (stepIndex: number): Promise<boolean> => {\n try {\n const currentStepKey = resolved.value.steps?.steps?.[stepIndex]?.key\n if (!currentStepKey) return true\n\n const stepFields = props.options\n .filter(option => option.layout?.step === currentStepKey)\n .map(option => option.prop)\n\n if (stepFields.length === 0) return true\n\n await validateField(stepFields)\n resolved.value.onStepValidate?.(stepIndex)\n return true\n } catch (error) {\n console.warn(`[C_Form] 步骤 ${stepIndex} 验证失败:`, error)\n return false\n }\n }\n\n /* ================= modelValue 双向同步 ================= */\n\n watch(\n () => props.modelValue,\n val => {\n if (val) Object.assign(formModel, val)\n },\n { immediate: true, deep: true }\n )\n\n /* ================= 组件暴露 ================= */\n\n defineExpose({\n validate,\n validateField,\n validateStep,\n validateTab,\n validateDynamicFields,\n validateCustomGroup,\n clearValidation,\n getModel,\n setFields,\n resetFields,\n setFieldValue,\n getFieldValue,\n setFieldsValue,\n formRef,\n formModel,\n initialize,\n layoutType: computed(() => resolved.value.layout),\n shouldShowDefaultActions: showActions,\n /* v0.8.0 脏检查 API */\n isDirty,\n getChangedFields,\n isFieldDirty,\n markAsClean,\n asyncLoadingMap,\n })\n</script>\n","<!--\n * @Author: ChenYu ycyplus@gmail.com\n * @Description: 表单组件 — 薄 UI 壳 + 厚 Composable 引擎\n * @Migration: naive-ui-components 组件库迁移版本\n * Copyright (c) 2025 by CHENY, All Rights Reserved.\n-->\n\n<template>\n <NForm\n ref=\"formRef\"\n :model=\"formModel\"\n :rules=\"formRules\"\n :validate-on-rule-change=\"false\"\n :label-placement=\"resolved.labelPlacement\"\n :label-width=\"resolved.labelWidth\"\n :size=\"resolved.size\"\n :disabled=\"resolved.disabled\"\n :readonly=\"resolved.readonly\"\n v-bind=\"$attrs\"\n >\n <!-- 布局组件渲染 -->\n <component\n :is=\"layoutComponent\"\n :form-items=\"formItems\"\n :layout-config=\"mergedLayoutConfig\"\n :options=\"visibleOptions\"\n :form-data=\"formModel\"\n @tab-change=\"handleLayoutEvent('onTabChange', $event)\"\n @tab-validate=\"handleLayoutEvent('onTabValidate', $event)\"\n @step-change=\"handleStepChange\"\n @step-before-change=\"handleStepBeforeChange\"\n @step-validate=\"handleStepValidate\"\n @field-add=\"handleLayoutEvent('onFieldAdd', $event)\"\n @field-remove=\"handleLayoutEvent('onFieldRemove', $event)\"\n @field-toggle=\"\n (id: string, visible: boolean) => resolved.onFieldToggle?.(id, visible)\n \"\n @fields-clear=\"handleLayoutEvent('onFieldsClear')\"\n @render-mode-change=\"handleLayoutEvent('onRenderModeChange', $event)\"\n @group-toggle=\"\n (key: string, collapsed: boolean) =>\n resolved.onGroupToggle?.(key, collapsed)\n \"\n @group-reset=\"handleLayoutEvent('onGroupReset', $event)\"\n @validate-success=\"(model: FormModel) => emit('validate-success', model)\"\n @validate-error=\"(errors: unknown) => emit('validate-error', errors)\"\n @fields-change=\"handleFieldsChange\"\n />\n\n <!-- 表单操作按钮区域(只在特定布局中显示) -->\n <NFormItem\n v-if=\"showActions\"\n style=\"margin-top: 20px\"\n >\n <slot\n name=\"action\"\n :form=\"formRef\"\n :model=\"formModel\"\n :validate=\"validate\"\n :validateField=\"validateField\"\n :reset=\"resetFields\"\n :setFields=\"setFields\"\n :getModel=\"getModel\"\n :clearValidation=\"clearValidation\"\n >\n <NSpace>\n <NButton\n type=\"primary\"\n @click=\"handleSubmit\"\n >提交</NButton\n >\n <NButton @click=\"handleReset\">重置</NButton>\n </NSpace>\n </slot>\n </NFormItem>\n </NForm>\n</template>\n\n<script lang=\"ts\" setup>\n import { computed, ref, watch, getCurrentInstance, nextTick } from 'vue'\n import type { FormInst } from 'naive-ui/es/form'\n import {\n NForm,\n NFormItem,\n NButton,\n NSpace,\n NInput,\n NInputNumber,\n NSwitch,\n NSlider,\n NRate,\n NDatePicker,\n NTimePicker,\n NCascader,\n NColorPicker,\n NSelect,\n NCheckboxGroup,\n NCheckbox,\n NRadioGroup,\n NRadio,\n NUpload,\n NTooltip,\n } from 'naive-ui'\n import { C_Editor } from '../C_Editor'\n import type {\n FormOption,\n LayoutType,\n LayoutConfig,\n SubmitEventPayload,\n FormModel,\n } from './types'\n import {\n type FormConfig,\n resolveFormConfig,\n shouldShowActions as calcShowActions,\n } from './composables/useFormConfig'\n import { useFormState } from './composables/useFormState'\n import {\n useFormRenderer,\n type ComponentMap,\n } from './composables/useFormRenderer'\n\n /* ===== 布局组件静态映射(取代 DynamicComponent) ===== */\n import DefaultLayout from './layouts/Default/index.vue'\n import InlineLayout from './layouts/Inline/index.vue'\n import GridLayout from './layouts/Grid/index.vue'\n import CardLayout from './layouts/Card/index.vue'\n import TabsLayout from './layouts/Tabs/index.vue'\n import StepsLayout from './layouts/Steps/index.vue'\n import DynamicLayout from './layouts/Dynamic/index.vue'\n import CustomLayout from './layouts/Custom/index.vue'\n\n defineOptions({ name: 'C_Form' })\n\n const LAYOUT_MAP: Record<LayoutType, any> = {\n default: DefaultLayout,\n inline: InlineLayout,\n grid: GridLayout,\n card: CardLayout,\n tabs: TabsLayout,\n steps: StepsLayout,\n dynamic: DynamicLayout,\n custom: CustomLayout,\n } as const\n\n /* ===== Naive UI 组件映射 ===== */\n /*\n * 库代码是预构建产物,resolveComponent 无法在运行时解析未全局注册的组件。\n * 直接 import 即可。naive-ui 作为 peerDependency,与消费项目共享同一份实例。\n */\n const COMPONENT_MAP: ComponentMap = {\n NFormItem,\n NInput,\n NInputNumber,\n NSwitch,\n NSlider,\n NRate,\n NDatePicker,\n NTimePicker,\n NCascader,\n NColorPicker,\n NSelect,\n NCheckboxGroup,\n NCheckbox,\n NRadioGroup,\n NRadio,\n NUpload,\n NButton,\n NSpace,\n NTooltip,\n C_Editor,\n } as ComponentMap\n\n /* ================= 组件属性定义 ================= */\n\n interface CFormProps {\n /** 字段配置数组 */\n options: FormOption[]\n /** 双向绑定表单数据 */\n modelValue?: FormModel\n /** 统一配置对象(收拢原先 13 个分散 Props) */\n config?: FormConfig\n }\n\n const props = withDefaults(defineProps<CFormProps>(), {\n config: () => ({}),\n })\n\n /* ================= 组件事件定义(从 16 个精简到 4 个) ================= */\n\n const emit = defineEmits<{\n submit: [payload: SubmitEventPayload]\n 'update:modelValue': [model: FormModel]\n 'validate-success': [model: FormModel]\n 'validate-error': [errors: unknown]\n }>()\n\n /* ================= 配置解析 ================= */\n\n const resolved = computed(() => resolveFormConfig(props.config))\n\n /* ================= 响应式状态 ================= */\n\n const formRef = ref<FormInst | null>(null)\n const optionsRef = computed(() => props.options)\n\n /* ===== 状态引擎 ===== */\n const {\n formModel,\n formRules,\n visibleOptions,\n initialize,\n handleFieldChange,\n validate,\n validateField,\n validateStep,\n validateTab,\n validateDynamicFields,\n validateCustomGroup,\n clearValidation,\n getModel,\n setFields,\n resetFields,\n setFieldValue,\n getFieldValue,\n setFieldsValue,\n handleSubmit,\n handleReset,\n /* v0.8.0 新增 */\n isDirty,\n getChangedFields,\n isFieldDirty,\n markAsClean,\n asyncOptionsCache,\n asyncLoadingMap,\n } = useFormState(optionsRef, resolved, formRef, emit)\n\n /* ===== 渲染引擎 ===== */\n const currentInstance = getCurrentInstance()\n const { formItems } = useFormRenderer({\n formModel,\n visibleOptions,\n config: resolved,\n handleFieldChange,\n componentMap: COMPONENT_MAP,\n instanceSlots: currentInstance?.slots,\n asyncOptionsCache,\n asyncLoadingMap,\n })\n\n /* ===== 编辑模式:自动回填 initialValues ===== */\n watch(\n () => resolved.value.initialValues,\n val => {\n if (val && resolved.value.mode === 'edit') {\n Object.assign(formModel, val)\n nextTick(() => markAsClean())\n }\n },\n { immediate: true }\n )\n\n /* ================= 计算属性 ================= */\n\n const layoutComponent = computed(\n () => LAYOUT_MAP[resolved.value.layout] || LAYOUT_MAP.default\n )\n\n const mergedLayoutConfig = computed<LayoutConfig>(() => ({\n type: resolved.value.layout,\n grid: resolved.value.grid,\n inline: resolved.value.inline,\n card: resolved.value.card,\n tabs: resolved.value.tabs,\n steps: resolved.value.steps,\n dynamic: resolved.value.dynamic,\n custom: resolved.value.custom,\n }))\n\n const showActions = computed(() => calcShowActions(resolved.value))\n\n /* ================= 布局事件 → config 回调桥接 ================= */\n\n /** 通用布局事件桥接 */\n const handleLayoutEvent = (callbackName: string, ...args: any[]) => {\n const callback = (resolved.value as any)[callbackName]\n callback?.(...args)\n }\n\n /** 字段变化事件(保留回调通道) */\n const handleFieldsChange = (fields: FormOption[]): void => {\n resolved.value.onFieldsChange?.(fields)\n }\n\n /** Steps 布局事件 — 需要多参数特殊处理 */\n const handleStepChange = (stepIndex: number, stepKey: string): void => {\n resolved.value.onStepChange?.(stepIndex, stepKey)\n }\n\n const handleStepBeforeChange = async (\n currentStep: number,\n targetStep: number\n ): Promise<boolean> => {\n resolved.value.onStepBeforeChange?.(currentStep, targetStep)\n return true\n }\n\n const handleStepValidate = async (stepIndex: number): Promise<boolean> => {\n try {\n const currentStepKey = resolved.value.steps?.steps?.[stepIndex]?.key\n if (!currentStepKey) return true\n\n const stepFields = props.options\n .filter(option => option.layout?.step === currentStepKey)\n .map(option => option.prop)\n\n if (stepFields.length === 0) return true\n\n await validateField(stepFields)\n resolved.value.onStepValidate?.(stepIndex)\n return true\n } catch (error) {\n console.warn(`[C_Form] 步骤 ${stepIndex} 验证失败:`, error)\n return false\n }\n }\n\n /* ================= modelValue 双向同步 ================= */\n\n watch(\n () => props.modelValue,\n val => {\n if (val) Object.assign(formModel, val)\n },\n { immediate: true, deep: true }\n )\n\n /* ================= 组件暴露 ================= */\n\n defineExpose({\n validate,\n validateField,\n validateStep,\n validateTab,\n validateDynamicFields,\n validateCustomGroup,\n clearValidation,\n getModel,\n setFields,\n resetFields,\n setFieldValue,\n getFieldValue,\n setFieldsValue,\n formRef,\n formModel,\n initialize,\n layoutType: computed(() => resolved.value.layout),\n shouldShowDefaultActions: showActions,\n /* v0.8.0 脏检查 API */\n isDirty,\n getChangedFields,\n isFieldDirty,\n markAsClean,\n asyncLoadingMap,\n })\n</script>\n"],"mappings":"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"}