vome-core 0.3.64 → 0.3.66

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 (345) hide show
  1. package/dist/admin/api/client.js +7 -2
  2. package/dist/admin/components/ui/avatar/Avatar.vue +18 -18
  3. package/dist/admin/components/ui/avatar/AvatarFallback.vue +21 -21
  4. package/dist/admin/components/ui/avatar/AvatarImage.vue +16 -16
  5. package/dist/admin/components/ui/avatar/index.js +1 -1
  6. package/dist/admin/components/ui/badge/Badge.vue +26 -26
  7. package/dist/admin/components/ui/button/Button.vue +31 -31
  8. package/dist/admin/components/ui/checkbox/Checkbox.vue +35 -35
  9. package/dist/admin/components/ui/checkbox/index.js +1 -1
  10. package/dist/admin/components/ui/dialog/Dialog.vue +19 -19
  11. package/dist/admin/components/ui/dialog/DialogClose.vue +15 -15
  12. package/dist/admin/components/ui/dialog/DialogContent.vue +267 -267
  13. package/dist/admin/components/ui/dialog/DialogDescription.vue +23 -23
  14. package/dist/admin/components/ui/dialog/DialogFooter.vue +27 -27
  15. package/dist/admin/components/ui/dialog/DialogHeader.vue +17 -17
  16. package/dist/admin/components/ui/dialog/DialogOverlay.vue +21 -21
  17. package/dist/admin/components/ui/dialog/DialogScrollContent.vue +60 -60
  18. package/dist/admin/components/ui/dialog/DialogTitle.vue +23 -23
  19. package/dist/admin/components/ui/dialog/DialogTrigger.vue +15 -15
  20. package/dist/admin/components/ui/dialog/index.js +1 -1
  21. package/dist/admin/components/ui/dropdown-menu/DropdownMenu.vue +19 -19
  22. package/dist/admin/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +39 -39
  23. package/dist/admin/components/ui/dropdown-menu/DropdownMenuContent.vue +39 -39
  24. package/dist/admin/components/ui/dropdown-menu/DropdownMenuGroup.vue +15 -15
  25. package/dist/admin/components/ui/dropdown-menu/DropdownMenuItem.vue +31 -31
  26. package/dist/admin/components/ui/dropdown-menu/DropdownMenuLabel.vue +23 -23
  27. package/dist/admin/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +21 -21
  28. package/dist/admin/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +40 -40
  29. package/dist/admin/components/ui/dropdown-menu/DropdownMenuSeparator.vue +23 -23
  30. package/dist/admin/components/ui/dropdown-menu/DropdownMenuShortcut.vue +17 -17
  31. package/dist/admin/components/ui/dropdown-menu/DropdownMenuSub.vue +18 -18
  32. package/dist/admin/components/ui/dropdown-menu/DropdownMenuSubContent.vue +27 -27
  33. package/dist/admin/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +31 -31
  34. package/dist/admin/components/ui/dropdown-menu/DropdownMenuTrigger.vue +17 -17
  35. package/dist/admin/components/ui/dropdown-menu/index.js +1 -1
  36. package/dist/admin/components/ui/input/Input.vue +183 -183
  37. package/dist/admin/components/ui/input/index.js +1 -1
  38. package/dist/admin/components/ui/label/Label.vue +26 -26
  39. package/dist/admin/components/ui/label/index.js +1 -1
  40. package/dist/admin/components/ui/scroll-area/ScrollArea.vue +33 -33
  41. package/dist/admin/components/ui/scroll-area/ScrollBar.vue +32 -32
  42. package/dist/admin/components/ui/scroll-area/index.js +1 -1
  43. package/dist/admin/components/ui/select/Select.vue +19 -19
  44. package/dist/admin/components/ui/select/SelectContent.vue +51 -51
  45. package/dist/admin/components/ui/select/SelectGroup.vue +15 -15
  46. package/dist/admin/components/ui/select/SelectItem.vue +53 -53
  47. package/dist/admin/components/ui/select/SelectItemText.vue +15 -15
  48. package/dist/admin/components/ui/select/SelectLabel.vue +17 -17
  49. package/dist/admin/components/ui/select/SelectScrollDownButton.vue +26 -26
  50. package/dist/admin/components/ui/select/SelectScrollUpButton.vue +26 -26
  51. package/dist/admin/components/ui/select/SelectSeparator.vue +19 -19
  52. package/dist/admin/components/ui/select/SelectTrigger.vue +44 -44
  53. package/dist/admin/components/ui/select/SelectValue.vue +15 -15
  54. package/dist/admin/components/ui/select/index.js +1 -1
  55. package/dist/admin/components/ui/separator/Separator.vue +29 -29
  56. package/dist/admin/components/ui/separator/index.js +1 -1
  57. package/dist/admin/components/ui/sheet/Sheet.vue +19 -19
  58. package/dist/admin/components/ui/sheet/SheetClose.vue +15 -15
  59. package/dist/admin/components/ui/sheet/SheetContent.vue +63 -63
  60. package/dist/admin/components/ui/sheet/SheetDescription.vue +21 -21
  61. package/dist/admin/components/ui/sheet/SheetFooter.vue +16 -16
  62. package/dist/admin/components/ui/sheet/SheetHeader.vue +15 -15
  63. package/dist/admin/components/ui/sheet/SheetOverlay.vue +21 -21
  64. package/dist/admin/components/ui/sheet/SheetTitle.vue +21 -21
  65. package/dist/admin/components/ui/sheet/SheetTrigger.vue +15 -15
  66. package/dist/admin/components/ui/sheet/index.js +1 -1
  67. package/dist/admin/components/ui/sonner/Toaster.vue +117 -117
  68. package/dist/admin/components/ui/sonner/index.js +1 -1
  69. package/dist/admin/components/ui/table/Table.vue +16 -16
  70. package/dist/admin/components/ui/table/TableBody.vue +17 -17
  71. package/dist/admin/components/ui/table/TableCaption.vue +17 -17
  72. package/dist/admin/components/ui/table/TableCell.vue +22 -22
  73. package/dist/admin/components/ui/table/TableEmpty.vue +34 -34
  74. package/dist/admin/components/ui/table/TableFooter.vue +17 -17
  75. package/dist/admin/components/ui/table/TableHead.vue +17 -17
  76. package/dist/admin/components/ui/table/TableHeader.vue +17 -17
  77. package/dist/admin/components/ui/table/TableRow.vue +17 -17
  78. package/dist/admin/components/ui/table/index.js +1 -1
  79. package/dist/admin/components/ui/tabs/Tabs.vue +24 -24
  80. package/dist/admin/components/ui/tabs/TabsContent.vue +21 -21
  81. package/dist/admin/components/ui/tabs/TabsList.vue +24 -24
  82. package/dist/admin/components/ui/tabs/TabsTrigger.vue +26 -26
  83. package/dist/admin/components/ui/tabs/index.js +1 -1
  84. package/dist/admin/components/ui/tooltip/Tooltip.vue +19 -19
  85. package/dist/admin/components/ui/tooltip/TooltipContent.vue +34 -34
  86. package/dist/admin/components/ui/tooltip/TooltipProvider.vue +14 -14
  87. package/dist/admin/components/ui/tooltip/TooltipTrigger.vue +15 -15
  88. package/dist/admin/components/ui/tooltip/index.js +1 -1
  89. package/dist/admin/components/vm-action-btn.vue +136 -136
  90. package/dist/admin/components/vm-aside-list-item.vue +136 -136
  91. package/dist/admin/components/vm-aside.vue +229 -229
  92. package/dist/admin/components/vm-auto-perm-dialog.vue +371 -371
  93. package/dist/admin/components/vm-card-grid.vue +37 -37
  94. package/dist/admin/components/vm-card-head.vue +45 -45
  95. package/dist/admin/components/vm-card-meta.vue +22 -22
  96. package/dist/admin/components/vm-card-title.vue +56 -56
  97. package/dist/admin/components/vm-card.vue +176 -176
  98. package/dist/admin/components/vm-check-tree.vue +340 -340
  99. package/dist/admin/components/vm-clamp-text.vue +39 -39
  100. package/dist/admin/components/vm-dept-tree.vue +497 -497
  101. package/dist/admin/components/vm-empty.vue +68 -68
  102. package/dist/admin/components/vm-eps-perm-picker.vue +123 -123
  103. package/dist/admin/components/vm-form-dialog.vue +632 -632
  104. package/dist/admin/components/vm-group-cascader.vue +560 -560
  105. package/dist/admin/components/vm-icon-btn.vue +88 -88
  106. package/dist/admin/components/vm-icon-picker.vue +647 -647
  107. package/dist/admin/components/vm-inline-search.vue +61 -61
  108. package/dist/admin/components/vm-loading.vue +114 -114
  109. package/dist/admin/components/vm-markdown.vue +405 -405
  110. package/dist/admin/components/vm-marquee.vue +265 -265
  111. package/dist/admin/components/vm-page-tabs.vue +94 -94
  112. package/dist/admin/components/vm-perm-section.vue +57 -57
  113. package/dist/admin/components/vm-ri-icon.vue +23 -23
  114. package/dist/admin/components/vm-role-picker.vue +314 -314
  115. package/dist/admin/components/vm-split-layout.vue +106 -106
  116. package/dist/admin/components/vm-thumb.vue +49 -49
  117. package/dist/admin/components/vm-view-path-picker.vue +59 -59
  118. package/dist/admin/crud/auto-fields.js +1 -1
  119. package/dist/admin/crud/components/vm-avatar.vue +104 -104
  120. package/dist/admin/crud/components/vm-color-picker.vue +1626 -1626
  121. package/dist/admin/crud/components/vm-column-custom.vue +193 -193
  122. package/dist/admin/crud/components/vm-context-menu.vue +105 -105
  123. package/dist/admin/crud/components/vm-copy-btn.vue +102 -102
  124. package/dist/admin/crud/components/vm-date-calendar-panel.vue +537 -537
  125. package/dist/admin/crud/components/vm-date-picker.vue +75 -75
  126. package/dist/admin/crud/components/vm-date-range.vue +88 -88
  127. package/dist/admin/crud/components/vm-date-text.vue +42 -42
  128. package/dist/admin/crud/components/vm-datetime-field.vue +215 -215
  129. package/dist/admin/crud/components/vm-datetime-picker.vue +9 -9
  130. package/dist/admin/crud/components/vm-dict-tag.vue +112 -112
  131. package/dist/admin/crud/components/vm-ellipsis-text.vue +34 -34
  132. package/dist/admin/crud/components/vm-form-hint.vue +81 -81
  133. package/dist/admin/crud/components/vm-json-code.vue +41 -41
  134. package/dist/admin/crud/components/vm-json-editor.vue +161 -161
  135. package/dist/admin/crud/components/vm-json-kv-editor.vue +318 -318
  136. package/dist/admin/crud/components/vm-kv-row.vue +51 -51
  137. package/dist/admin/crud/components/vm-multi-select.vue +279 -279
  138. package/dist/admin/crud/components/vm-number-range.vue +204 -204
  139. package/dist/admin/crud/components/vm-preview-viewer.vue +894 -894
  140. package/dist/admin/crud/components/vm-radio.vue +87 -87
  141. package/dist/admin/crud/components/vm-richtext.vue +313 -313
  142. package/dist/admin/crud/components/vm-select.vue +570 -570
  143. package/dist/admin/crud/components/vm-status-tag.vue +158 -158
  144. package/dist/admin/crud/components/vm-switch.vue +158 -158
  145. package/dist/admin/crud/components/vm-tag-list.vue +108 -108
  146. package/dist/admin/crud/components/vm-text-link.vue +52 -52
  147. package/dist/admin/crud/components/vm-toggle-switch.vue +84 -84
  148. package/dist/admin/crud/components/vm-tree-select.vue +450 -450
  149. package/dist/admin/crud/components/vm-upload-item.vue +298 -298
  150. package/dist/admin/crud/components/vm-upload.vue +436 -436
  151. package/dist/admin/crud/config.js +1 -1
  152. package/dist/admin/crud/confirm.js +1 -1
  153. package/dist/admin/crud/crud-page-request.js +1 -1
  154. package/dist/admin/crud/data-i18n.js +1 -1
  155. package/dist/admin/crud/dict.js +1 -1
  156. package/dist/admin/crud/export-fetch.js +1 -1
  157. package/dist/admin/crud/index.js +1 -0
  158. package/dist/admin/crud/key.js +1 -1
  159. package/dist/admin/crud/plugins.js +1 -1
  160. package/dist/admin/crud/span.js +1 -1
  161. package/dist/admin/crud/style.js +1 -1
  162. package/dist/admin/crud/useCrud.js +3 -0
  163. package/dist/admin/crud/validate.js +1 -1
  164. package/dist/admin/crud/vm-add-btn.vue +70 -70
  165. package/dist/admin/crud/vm-adv-search.vue +83 -83
  166. package/dist/admin/crud/vm-crud.vue +711 -711
  167. package/dist/admin/crud/vm-data-i18n-btn.vue +456 -456
  168. package/dist/admin/crud/vm-data-i18n-lang.vue +183 -183
  169. package/dist/admin/crud/vm-export-btn.vue +183 -183
  170. package/dist/admin/crud/vm-flex.vue +14 -14
  171. package/dist/admin/crud/vm-form.vue +33 -15
  172. package/dist/admin/crud/vm-import-btn.vue +747 -747
  173. package/dist/admin/crud/vm-multi-delete-btn.vue +49 -49
  174. package/dist/admin/crud/vm-pagination.vue +212 -212
  175. package/dist/admin/crud/vm-refresh-btn.vue +35 -35
  176. package/dist/admin/crud/vm-row.vue +55 -55
  177. package/dist/admin/crud/vm-search-key.vue +78 -78
  178. package/dist/admin/crud/vm-search.vue +466 -466
  179. package/dist/admin/crud/vm-table.vue +1390 -1390
  180. package/dist/admin/crud/vm-tabs.vue +94 -94
  181. package/dist/admin/crud/vm-toolbar.vue +357 -357
  182. package/dist/admin/crud/vm-upsert.vue +765 -765
  183. package/dist/admin/directives/perm.js +1 -1
  184. package/dist/admin/env.d.ts +1 -1
  185. package/dist/admin/hooks/useUpload.js +1 -1
  186. package/dist/admin/index.d.ts +1 -31
  187. package/dist/admin/lib/browser.js +1 -1
  188. package/dist/admin/lib/cn.js +1 -1
  189. package/dist/admin/lib/dialog-float.js +1 -1
  190. package/dist/admin/lib/export-excel.js +1 -1
  191. package/dist/admin/lib/import-excel.js +1 -1
  192. package/dist/admin/lib/json.js +1 -1
  193. package/dist/admin/lib/menu.js +1 -1
  194. package/dist/admin/lib/micro-locale.js +1 -1
  195. package/dist/admin/lib/micro-theme.js +1 -1
  196. package/dist/admin/lib/shell.js +1 -1
  197. package/dist/admin/lib/theme-color-options.js +1 -1
  198. package/dist/admin/lib/tree.js +1 -1
  199. package/dist/admin/lib/upload.js +1 -1
  200. package/dist/admin/lib/video-frame.js +1 -1
  201. package/dist/admin/router/create.js +1 -1
  202. package/dist/admin/router/guards.js +1 -1
  203. package/dist/admin/router/index.d.ts +1 -5
  204. package/dist/admin/service/index.d.ts +1 -11
  205. package/dist/admin/styles/base.css +121 -121
  206. package/dist/admin/vendor/browser-image-compression.js +1144 -1144
  207. package/dist/admin/vendor/decimal-js.js +12 -12
  208. package/dist/admin/vendor/xlsx.js +263 -263
  209. package/dist/ai/index.js +1 -1
  210. package/dist/client/admin-vendor.d.ts +1 -13
  211. package/dist/client/ai-model-registry.js +1 -1
  212. package/dist/client/base.js +1 -1
  213. package/dist/client/configure.js +1 -1
  214. package/dist/client/dict.js +1 -1
  215. package/dist/client/eps-payload.js +1 -1
  216. package/dist/client/eps.js +1 -1
  217. package/dist/client/index.d.ts +1 -7
  218. package/dist/client/index.js +1 -1
  219. package/dist/client/locale-change.js +1 -1
  220. package/dist/client/locale-store.js +1 -1
  221. package/dist/client/service.js +1 -1
  222. package/dist/client/vite-admin.d.ts +1 -40
  223. package/dist/client/vite-admin.js +1 -1
  224. package/dist/client/vite-auto-import.d.ts +1 -2
  225. package/dist/client/vite-auto-import.js +1 -1
  226. package/dist/client/vite-micro-proxy.d.ts +1 -20
  227. package/dist/client/vite-micro-proxy.js +1 -1
  228. package/dist/client/vite-plugin-eps.d.ts +1 -20
  229. package/dist/client/vite-plugin-eps.js +1 -1
  230. package/dist/client/vite-resolve.d.ts +1 -16
  231. package/dist/client/vite-resolve.js +1 -1
  232. package/dist/config/index.js +1 -1
  233. package/dist/core/index.d.ts +1 -1
  234. package/dist/index.js +1 -1
  235. package/dist/ioc/index.d.ts +1 -1
  236. package/dist/server/index.d.ts +1 -1
  237. package/dist/server/index.js +1 -1
  238. package/dist/shared/datetime-picker.js +1 -1
  239. package/dist/shared/decimal.js +1 -1
  240. package/dist/shared/excel.js +1 -1
  241. package/dist/shared/index.js +1 -1
  242. package/dist/shared/locale-json.js +1 -1
  243. package/dist/shared/tree.js +1 -1
  244. package/package.json +1 -1
  245. package/typings/admin/base/auth.ts +24 -24
  246. package/typings/admin/base/permission.ts +19 -19
  247. package/typings/admin/comm/cascader.ts +7 -7
  248. package/typings/admin/comm/check-tree.ts +7 -7
  249. package/typings/admin/comm/crud.ts +427 -427
  250. package/typings/admin/comm/eps.ts +86 -86
  251. package/typings/admin/comm/request.ts +16 -16
  252. package/typings/admin/comm/service.ts +43 -43
  253. package/typings/admin/comm/upload.ts +39 -39
  254. package/typings/admin/theme.ts +10 -10
  255. package/typings/admin/vome/browser.ts +11 -11
  256. package/typings/admin/vome/module.ts +13 -13
  257. package/typings/admin/vome/tags.ts +9 -9
  258. package/typings/comm/crud.ts +83 -83
  259. package/typings/comm/page.ts +18 -18
  260. package/typings/comm/scan.ts +6 -6
  261. package/typings/common.ts +4 -4
  262. package/typings/context/data.ts +10 -10
  263. package/typings/ext/market-seat.ts +42 -42
  264. package/typings/ext/market.ts +55 -55
  265. package/typings/ext/module.ts +64 -64
  266. package/typings/ext/plugin.ts +38 -38
  267. package/typings/ioc/metadata.ts +34 -34
  268. package/typings/logger/config.ts +6 -6
  269. package/typings/routing/crud.ts +199 -199
  270. package/typings/routing/eps.ts +88 -88
  271. package/typings/routing/meta.ts +63 -63
  272. package/typings/routing/register.ts +21 -21
  273. package/typings/routing/scan-context.ts +7 -7
  274. package/dist/admin/api/client.d.ts +0 -50
  275. package/dist/admin/components/ui/avatar/index.d.ts +0 -3
  276. package/dist/admin/components/ui/badge/index.d.ts +0 -6
  277. package/dist/admin/components/ui/button/index.d.ts +0 -7
  278. package/dist/admin/components/ui/checkbox/index.d.ts +0 -1
  279. package/dist/admin/components/ui/dialog/index.d.ts +0 -10
  280. package/dist/admin/components/ui/dropdown-menu/index.d.ts +0 -15
  281. package/dist/admin/components/ui/input/index.d.ts +0 -1
  282. package/dist/admin/components/ui/label/index.d.ts +0 -1
  283. package/dist/admin/components/ui/scroll-area/index.d.ts +0 -2
  284. package/dist/admin/components/ui/select/index.d.ts +0 -11
  285. package/dist/admin/components/ui/separator/index.d.ts +0 -1
  286. package/dist/admin/components/ui/sheet/index.d.ts +0 -8
  287. package/dist/admin/components/ui/sonner/index.d.ts +0 -1
  288. package/dist/admin/components/ui/table/index.d.ts +0 -9
  289. package/dist/admin/components/ui/tabs/index.d.ts +0 -4
  290. package/dist/admin/components/ui/tooltip/index.d.ts +0 -4
  291. package/dist/admin/crud/auto-fields.d.ts +0 -68
  292. package/dist/admin/crud/config.d.ts +0 -5
  293. package/dist/admin/crud/confirm.d.ts +0 -19
  294. package/dist/admin/crud/crud-page-request.d.ts +0 -21
  295. package/dist/admin/crud/data-i18n.d.ts +0 -62
  296. package/dist/admin/crud/dict.d.ts +0 -4
  297. package/dist/admin/crud/export-fetch.d.ts +0 -22
  298. package/dist/admin/crud/index.d.ts +0 -60
  299. package/dist/admin/crud/json-kv.d.ts +0 -9
  300. package/dist/admin/crud/key.d.ts +0 -22
  301. package/dist/admin/crud/paging.d.ts +0 -2
  302. package/dist/admin/crud/plugins.d.ts +0 -63
  303. package/dist/admin/crud/registry.d.ts +0 -3
  304. package/dist/admin/crud/span.d.ts +0 -17
  305. package/dist/admin/crud/style.d.ts +0 -82
  306. package/dist/admin/crud/useCrud.d.ts +0 -21
  307. package/dist/admin/crud/validate.d.ts +0 -7
  308. package/dist/admin/directives/perm.d.ts +0 -3
  309. package/dist/admin/hooks/useBrowser.d.ts +0 -6
  310. package/dist/admin/hooks/useUpload.d.ts +0 -8
  311. package/dist/admin/hooks/useVome.d.ts +0 -10
  312. package/dist/admin/lib/browser.d.ts +0 -3
  313. package/dist/admin/lib/cn.d.ts +0 -2
  314. package/dist/admin/lib/compress-image.d.ts +0 -12
  315. package/dist/admin/lib/dialog-float.d.ts +0 -8
  316. package/dist/admin/lib/eps.d.ts +0 -2
  317. package/dist/admin/lib/export-excel.d.ts +0 -9
  318. package/dist/admin/lib/file-preview.d.ts +0 -9
  319. package/dist/admin/lib/import-excel.d.ts +0 -21
  320. package/dist/admin/lib/json.d.ts +0 -11
  321. package/dist/admin/lib/menu.d.ts +0 -3
  322. package/dist/admin/lib/micro-locale.d.ts +0 -5
  323. package/dist/admin/lib/micro-theme.d.ts +0 -14
  324. package/dist/admin/lib/module.d.ts +0 -21
  325. package/dist/admin/lib/scarce-assets.d.ts +0 -5
  326. package/dist/admin/lib/shell.d.ts +0 -8
  327. package/dist/admin/lib/theme-color-options.d.ts +0 -15
  328. package/dist/admin/lib/tree.d.ts +0 -2
  329. package/dist/admin/lib/upload.d.ts +0 -17
  330. package/dist/admin/lib/video-frame.d.ts +0 -6
  331. package/dist/admin/router/create.d.ts +0 -16
  332. package/dist/admin/router/guards.d.ts +0 -6
  333. package/dist/admin/router/menu-routes.d.ts +0 -13
  334. package/dist/admin/stores/app.d.ts +0 -13
  335. package/dist/admin/stores/tags.d.ts +0 -14
  336. package/dist/admin/stores/user.d.ts +0 -48
  337. package/dist/client/ai-model-registry.d.ts +0 -16
  338. package/dist/client/base.d.ts +0 -28
  339. package/dist/client/configure.d.ts +0 -33
  340. package/dist/client/dict.d.ts +0 -31
  341. package/dist/client/eps-payload.d.ts +0 -3
  342. package/dist/client/eps.d.ts +0 -17
  343. package/dist/client/locale-change.d.ts +0 -16
  344. package/dist/client/locale-store.d.ts +0 -105
  345. package/dist/client/service.d.ts +0 -29
@@ -1,466 +1,466 @@
1
- <template>
2
- <div v-if="items.length" class="vm-crud-search">
3
- <div class="vm-crud-search__filters">
4
- <template v-for="(item, idx) in items" :key="`${item.prop}-${idx}`">
5
- <component
6
- :is="resolveField(item)"
7
- v-if="resolveField(item)"
8
- class="vm-crud-search__control"
9
- :class="{ 'is-range': isRange(item) }"
10
- v-bind="fieldProps(item)"
11
- :model-value="form[item.prop]"
12
- @update:model-value="(v: unknown) => (form[item.prop] = v)"
13
- />
14
- <Select
15
- v-else-if="item.type === 'select' && !item.multiple"
16
- :model-value="String(form[item.prop] ?? '')"
17
- @update:model-value="(v) => (form[item.prop] = coerceSelect(item, v))"
18
- >
19
- <SelectTrigger class="vm-crud-search__control">
20
- <SelectValue :placeholder="itemPlaceholder(item)" />
21
- </SelectTrigger>
22
- <SelectContent>
23
- <SelectItem
24
- v-for="opt in optionsOf(item)"
25
- :key="String(opt.value)"
26
- :value="String(opt.value)"
27
- >
28
- {{ opt.label }}
29
- </SelectItem>
30
- </SelectContent>
31
- </Select>
32
- <Input
33
- v-else
34
- class="vm-crud-search__control"
35
- :model-value="String(form[item.prop] ?? '')"
36
- :placeholder="itemPlaceholder(item)"
37
- @update:model-value="(v) => (form[item.prop] = v)"
38
- @keydown.enter.prevent="search"
39
- />
40
- </template>
41
- </div>
42
- <div v-if="inlineActions" class="vm-crud-search__actions">
43
- <button type="button" class="vm-crud-search__btn is-primary" @click="search">
44
- {{ crudLabel('search', crud.dict.label) }}
45
- </button>
46
- <button type="button" class="vm-crud-search__btn is-ghost" @click="reset">
47
- {{ crudLabel('reset', crud.dict.label) }}
48
- </button>
49
- <slot />
50
- </div>
51
- </div>
52
- </template>
53
-
54
- <script setup lang="ts">
55
- import { ref, computed, watch, reactive, onMounted, toValue } from 'vue'
56
- import { onBeforeUnmount } from 'vue'
57
- import { useCrud } from './useCrud'
58
- import { injectSearchOptions } from './key'
59
- import { buildAutoSearchItems, type TablePlugin } from './plugins'
60
- import {
61
- getCrudStyle,
62
- crudLocaleRev,
63
- crudLabel,
64
- resolveSearchPlaceholder,
65
- resolveRangePlaceholders,
66
- } from './style'
67
- import { resolveCrudComponent } from './registry'
68
- import { mapDictOptions } from './auto-fields'
69
- import type { CrudSearchItem } from '../../../typings/admin/comm/crud'
70
- defineOptions({ name: 'vm-search' })
71
-
72
- const props = withDefaults(
73
- defineProps<{
74
- items?: CrudSearchItem[]
75
- /** 为 true 时在筛选器同行显示搜索/重置(默认由 vm-toolbar 展示) */
76
- inlineActions?: boolean
77
- }>(),
78
- { inlineActions: false },
79
- )
80
-
81
- const crud = useCrud()
82
- const searchOpts = injectSearchOptions()
83
- const autoItems = ref<CrudSearchItem[]>([])
84
-
85
- const manualItems = computed(
86
- () => props.items?.length ? props.items : searchOpts?.items?.length ? searchOpts.items : [],
87
- )
88
-
89
- /** 自动项在前;手写项同 prop 覆盖自动项,避免多控件共绑 form[prop] */
90
- function mergeSearchItems(auto: CrudSearchItem[], manual: CrudSearchItem[]) {
91
- const manualProps = new Set(manual.map((i) => i.prop).filter(Boolean))
92
- const merged = [
93
- ...auto.filter((i) => i.prop && !manualProps.has(i.prop)),
94
- ...manual.filter((i) => i.prop),
95
- ]
96
- return merged
97
- }
98
-
99
- const items = computed(() => {
100
- void crudLocaleRev.value
101
- return mergeSearchItems(autoItems.value, manualItems.value)
102
- })
103
-
104
- function itemPlaceholder(item: CrudSearchItem) {
105
- return resolveSearchPlaceholder(item)
106
- }
107
-
108
- const form = reactive<Record<string, unknown>>({})
109
-
110
- function isRange(item: CrudSearchItem) {
111
- return item.type === 'number-range' || item.type === 'daterange' || Boolean(item.range)
112
- }
113
-
114
- /** 多选:explicit multiple,或组件声明为 vm-multi-select(宿主常漏写 multiple) */
115
- function isMultiValue(item: CrudSearchItem) {
116
- if (item.multiple) return true
117
- const name = item.component?.name
118
- return typeof name === 'string' && /multi-select/i.test(name)
119
- }
120
-
121
- function emptyValue(item: CrudSearchItem) {
122
- if (isRange(item)) return [null, null]
123
- if (isMultiValue(item)) return []
124
- return ''
125
- }
126
-
127
- /** 浅拷贝初始化值(数组避免共用引用) */
128
- function cloneInit(v: unknown) {
129
- if (Array.isArray(v)) return [...v]
130
- return v
131
- }
132
-
133
- /** item.value 优先;未设则 emptyValue。重置也走此规则。 */
134
- function initialValue(item: CrudSearchItem) {
135
- if (item.value !== undefined) {
136
- const v = cloneInit(item.value)
137
- if (isMultiValue(item) && !Array.isArray(v)) {
138
- return v == null || v === '' ? [] : [v]
139
- }
140
- if (isRange(item) && !Array.isArray(v)) return [null, null]
141
- return v
142
- }
143
- return emptyValue(item)
144
- }
145
-
146
- /** 已有 form 值与控件类型不一致时纠正(避免 '' 绑到 multi-select) */
147
- function coerceFormValue(item: CrudSearchItem, current: unknown) {
148
- if (isMultiValue(item)) {
149
- if (Array.isArray(current)) return current
150
- if (current == null || current === '') return []
151
- return [current]
152
- }
153
- if (isRange(item)) {
154
- if (Array.isArray(current) && current.length >= 2) return current
155
- return [null, null]
156
- }
157
- return current
158
- }
159
-
160
- function coerceSelect(item: CrudSearchItem, v: unknown) {
161
- const s = v == null ? '' : String(v)
162
- if (!s) return ''
163
- const hit = optionsOf(item).find((o) => String(o.value) === s)
164
- return hit ? hit.value : s
165
- }
166
-
167
- /** options 支持 Ref / ComputedRef / getter(与 vm-upsert 一致) */
168
- function resolveOptions(
169
- options: CrudSearchItem['options'],
170
- ): Array<{ label: string; value: string | number | boolean }> {
171
- const list = options == null ? [] : toValue(options)
172
- return Array.isArray(list) ? list : []
173
- }
174
-
175
- /** 筛选项 options:优先 EPS 本地一级字典,禁止请求 /data */
176
- function optionsOf(item: CrudSearchItem) {
177
- if (item.dict) return mapDictOptions(item.dict)
178
- return resolveOptions(item.options)
179
- }
180
-
181
- function rebuildAutoItems() {
182
- const plugins = getCrudStyle().search.plugins as TablePlugin[]
183
- const auto = plugins?.find((p) => p?.__plugin === 'setAuto')
184
- if (!auto) {
185
- autoItems.value = []
186
- return
187
- }
188
- const svc = crud.service as { namespace?: string; search?: Record<string, unknown> }
189
- autoItems.value = buildAutoSearchItems(svc, {
190
- hideLabel: auto.hideLabel !== false,
191
- ignoreFields: auto.ignoreFields as string[] | undefined,
192
- })
193
- }
194
-
195
- onMounted(rebuildAutoItems)
196
-
197
- // EPS 热更 / createEps 重建 leaf 后补一次(仅 onMounted 会漏)
198
- watch(
199
- () => {
200
- const svc = crud.service as { namespace?: string; search?: unknown }
201
- return [svc?.namespace, svc?.search, getCrudStyle().search.plugins]
202
- },
203
- rebuildAutoItems,
204
- { deep: true },
205
- )
206
-
207
- watch(
208
- items,
209
- (list) => {
210
- for (const it of list) {
211
- if (!(it.prop in form)) {
212
- form[it.prop] = initialValue(it)
213
- } else {
214
- form[it.prop] = coerceFormValue(it, form[it.prop])
215
- }
216
- }
217
- const active = list.length > 0
218
- crud.hasSearchFilters.value = active
219
- crud.searchActions.value = active ? { search, reset } : null
220
- // 先写入 form + params(有 value 则带条件,无则不带),不在这里 refresh;
221
- // 等页面 useCrud 回调 / immediate 只拉一次,避免空参无效请求。
222
- if (active) applyFormToParams(false)
223
- },
224
- { immediate: true, deep: true },
225
- )
226
-
227
- function resolveField(item: CrudSearchItem) {
228
- const name = item.component?.name
229
- if (typeof name === 'string') {
230
- const comp = resolveCrudComponent(name)
231
- if (comp) return comp
232
- } else if (name) {
233
- return name
234
- }
235
- if (item.type === 'select' && item.multiple) {
236
- return resolveCrudComponent('vm-multi-select')
237
- }
238
- if (item.type === 'select' && isMultiValue(item)) {
239
- return resolveCrudComponent('vm-multi-select')
240
- }
241
- if (item.type === 'daterange') {
242
- return resolveCrudComponent('vm-date-range')
243
- }
244
- if (item.type === 'date') {
245
- return resolveCrudComponent('vm-date-picker')
246
- }
247
- if (item.type === 'number-range') {
248
- return resolveCrudComponent('vm-number-range')
249
- }
250
- if (item.type === 'select') return undefined
251
- return undefined
252
- }
253
-
254
- function fieldProps(item: CrudSearchItem) {
255
- const ph = itemPlaceholder(item)
256
- const rangePlaceholders =
257
- item.type === 'number-range' || item.type === 'daterange' || item.phMode === 'range'
258
- ? resolveRangePlaceholders(item)
259
- : {}
260
- return {
261
- options: optionsOf(item),
262
- refreshOnChange: false,
263
- precision: item.range?.rangeType,
264
- mode:
265
- item.range?.rangeType === 'float' || item.range?.rangeType === 'int'
266
- ? item.range.rangeType
267
- : undefined,
268
- ...(item.component?.props || {}),
269
- placeholder: ph,
270
- ...rangePlaceholders,
271
- }
272
- }
273
-
274
- function buildSearchPayload() {
275
- const payload: Record<string, unknown> = {}
276
- for (const it of items.value) {
277
- const v = form[it.prop]
278
- if (it.range) {
279
- const pair = Array.isArray(v) ? v : [null, null]
280
- if (pair[0] != null && pair[0] !== '') payload[it.range.min] = pair[0]
281
- if (pair[1] != null && pair[1] !== '') payload[it.range.max] = pair[1]
282
- continue
283
- }
284
- if (it.multiple || isMultiValue(it)) {
285
- if (Array.isArray(v) && v.length) payload[it.prop] = v
286
- continue
287
- }
288
- if (v !== '' && v != null) payload[it.prop] = v
289
- }
290
- return payload
291
- }
292
-
293
- /** 用当前 form 覆盖本组筛选项对应 params;doRefresh=false 仅赋值供首屏一次查询 */
294
- function applyFormToParams(doRefresh = true) {
295
- const payload = buildSearchPayload()
296
- const next = { ...crud.getParams() }
297
- for (const it of items.value) {
298
- delete next[it.prop]
299
- if (it.range) {
300
- delete next[it.range.min]
301
- delete next[it.range.max]
302
- }
303
- }
304
- Object.assign(next, payload)
305
- crud.params.value = next
306
- if (!doRefresh) return
307
- crud.pagination.value = { ...crud.pagination.value, page: 1 }
308
- void crud.refresh()
309
- }
310
-
311
- function search() {
312
- applyFormToParams(true)
313
- }
314
-
315
- function reset() {
316
- for (const it of items.value) {
317
- form[it.prop] = initialValue(it)
318
- }
319
- // 回到 props.params 底稿后,再按当前 form(含 value 初始)提交一次
320
- crud.resetParams(false)
321
- search()
322
- }
323
-
324
- onBeforeUnmount(() => {
325
- crud.hasSearchFilters.value = false
326
- if (crud.searchActions.value?.search === search) {
327
- crud.searchActions.value = null
328
- }
329
- })
330
-
331
- defineExpose({ form, search, reset })
332
- </script>
333
-
334
- <style lang="scss" scoped>
335
- .vm-crud-search {
336
- --vm-search-gap: 12px;
337
- container-type: inline-size;
338
- container-name: vm-crud-search;
339
-
340
- display: flex;
341
- width: 100%;
342
- min-width: 0;
343
- flex-wrap: wrap;
344
- align-items: flex-start;
345
- gap: var(--vm-search-gap);
346
- margin-bottom: 6px;
347
- }
348
-
349
- .vm-crud-search__filters {
350
- display: grid;
351
- flex: 1 1 auto;
352
- /* 默认 2 列;随容器变宽升到 8 列,单列始终 ≥140 */
353
- grid-template-columns: repeat(2, minmax(0, 1fr));
354
- gap: var(--vm-search-gap);
355
- min-width: 0;
356
- align-items: center;
357
- }
358
-
359
- /* n * 140 + (n-1) * 12 = 152n - 12 */
360
- @container vm-crud-search (min-width: 444px) {
361
- .vm-crud-search__filters {
362
- grid-template-columns: repeat(3, minmax(0, 1fr));
363
- }
364
- }
365
-
366
- @container vm-crud-search (min-width: 596px) {
367
- .vm-crud-search__filters {
368
- grid-template-columns: repeat(4, minmax(0, 1fr));
369
- }
370
- }
371
-
372
- @container vm-crud-search (min-width: 748px) {
373
- .vm-crud-search__filters {
374
- grid-template-columns: repeat(5, minmax(0, 1fr));
375
- }
376
- }
377
-
378
- @container vm-crud-search (min-width: 900px) {
379
- .vm-crud-search__filters {
380
- grid-template-columns: repeat(6, minmax(0, 1fr));
381
- }
382
- }
383
-
384
- @container vm-crud-search (min-width: 1052px) {
385
- .vm-crud-search__filters {
386
- grid-template-columns: repeat(7, minmax(0, 1fr));
387
- }
388
- }
389
-
390
- @container vm-crud-search (min-width: 1204px) {
391
- .vm-crud-search__filters {
392
- grid-template-columns: repeat(8, minmax(0, 1fr));
393
- }
394
- }
395
-
396
- .vm-crud-search__actions {
397
- display: flex;
398
- flex: 0 0 auto;
399
- flex-wrap: wrap;
400
- align-items: center;
401
- gap: var(--vm-search-gap);
402
- }
403
-
404
- :deep(.vm-crud-search__control) {
405
- box-sizing: border-box;
406
- width: 100% !important;
407
- min-width: 0 !important;
408
- max-width: none !important;
409
- height: var(--vm-control-height) !important;
410
- border-radius: 12px !important;
411
- box-shadow: none !important;
412
-
413
- &:not(.is-range) {
414
- border: 1px solid transparent !important;
415
- background: var(--muted) !important;
416
-
417
- &:focus,
418
- &:focus-visible {
419
- border-color: var(--focus-border) !important;
420
- box-shadow: none !important;
421
- }
422
- }
423
-
424
- /* 区间占两列:2 * 列宽 + 12px */
425
- &.is-range {
426
- width: 100% !important;
427
- min-width: 0 !important;
428
- max-width: none !important;
429
- height: var(--vm-control-height) !important;
430
- grid-column: span 2;
431
- padding: 0 10px !important;
432
- border: 1px solid transparent !important;
433
- border-radius: 12px !important;
434
- background: var(--muted) !important;
435
- }
436
- }
437
-
438
- .vm-crud-search__btn {
439
- height: var(--vm-control-height);
440
- padding: 0 14px;
441
- border: none;
442
- border-radius: 12px;
443
- font-size: 13px;
444
- font-weight: 600;
445
- cursor: pointer;
446
- transition: background 0.15s ease, color 0.15s ease, opacity 0.15s ease;
447
-
448
- &.is-primary {
449
- background: var(--brand);
450
- color: #fff;
451
-
452
- &:hover {
453
- background: var(--brand-deep);
454
- }
455
- }
456
-
457
- &.is-ghost {
458
- background: var(--muted);
459
- color: var(--foreground);
460
-
461
- &:hover {
462
- background: color-mix(in srgb, var(--muted) 70%, var(--foreground) 8%);
463
- }
464
- }
465
- }
466
- </style>
1
+ <template>
2
+ <div v-if="items.length" class="vm-crud-search">
3
+ <div class="vm-crud-search__filters">
4
+ <template v-for="(item, idx) in items" :key="`${item.prop}-${idx}`">
5
+ <component
6
+ :is="resolveField(item)"
7
+ v-if="resolveField(item)"
8
+ class="vm-crud-search__control"
9
+ :class="{ 'is-range': isRange(item) }"
10
+ v-bind="fieldProps(item)"
11
+ :model-value="form[item.prop]"
12
+ @update:model-value="(v: unknown) => (form[item.prop] = v)"
13
+ />
14
+ <Select
15
+ v-else-if="item.type === 'select' && !item.multiple"
16
+ :model-value="String(form[item.prop] ?? '')"
17
+ @update:model-value="(v) => (form[item.prop] = coerceSelect(item, v))"
18
+ >
19
+ <SelectTrigger class="vm-crud-search__control">
20
+ <SelectValue :placeholder="itemPlaceholder(item)" />
21
+ </SelectTrigger>
22
+ <SelectContent>
23
+ <SelectItem
24
+ v-for="opt in optionsOf(item)"
25
+ :key="String(opt.value)"
26
+ :value="String(opt.value)"
27
+ >
28
+ {{ opt.label }}
29
+ </SelectItem>
30
+ </SelectContent>
31
+ </Select>
32
+ <Input
33
+ v-else
34
+ class="vm-crud-search__control"
35
+ :model-value="String(form[item.prop] ?? '')"
36
+ :placeholder="itemPlaceholder(item)"
37
+ @update:model-value="(v) => (form[item.prop] = v)"
38
+ @keydown.enter.prevent="search"
39
+ />
40
+ </template>
41
+ </div>
42
+ <div v-if="inlineActions" class="vm-crud-search__actions">
43
+ <button type="button" class="vm-crud-search__btn is-primary" @click="search">
44
+ {{ crudLabel('search', crud.dict.label) }}
45
+ </button>
46
+ <button type="button" class="vm-crud-search__btn is-ghost" @click="reset">
47
+ {{ crudLabel('reset', crud.dict.label) }}
48
+ </button>
49
+ <slot />
50
+ </div>
51
+ </div>
52
+ </template>
53
+
54
+ <script setup lang="ts">
55
+ import { ref, computed, watch, reactive, onMounted, toValue } from 'vue'
56
+ import { onBeforeUnmount } from 'vue'
57
+ import { useCrud } from './useCrud'
58
+ import { injectSearchOptions } from './key'
59
+ import { buildAutoSearchItems, type TablePlugin } from './plugins'
60
+ import {
61
+ getCrudStyle,
62
+ crudLocaleRev,
63
+ crudLabel,
64
+ resolveSearchPlaceholder,
65
+ resolveRangePlaceholders,
66
+ } from './style'
67
+ import { resolveCrudComponent } from './registry'
68
+ import { mapDictOptions } from './auto-fields'
69
+ import type { CrudSearchItem } from '../../../typings/admin/comm/crud'
70
+ defineOptions({ name: 'vm-search' })
71
+
72
+ const props = withDefaults(
73
+ defineProps<{
74
+ items?: CrudSearchItem[]
75
+ /** 为 true 时在筛选器同行显示搜索/重置(默认由 vm-toolbar 展示) */
76
+ inlineActions?: boolean
77
+ }>(),
78
+ { inlineActions: false },
79
+ )
80
+
81
+ const crud = useCrud()
82
+ const searchOpts = injectSearchOptions()
83
+ const autoItems = ref<CrudSearchItem[]>([])
84
+
85
+ const manualItems = computed(
86
+ () => props.items?.length ? props.items : searchOpts?.items?.length ? searchOpts.items : [],
87
+ )
88
+
89
+ /** 自动项在前;手写项同 prop 覆盖自动项,避免多控件共绑 form[prop] */
90
+ function mergeSearchItems(auto: CrudSearchItem[], manual: CrudSearchItem[]) {
91
+ const manualProps = new Set(manual.map((i) => i.prop).filter(Boolean))
92
+ const merged = [
93
+ ...auto.filter((i) => i.prop && !manualProps.has(i.prop)),
94
+ ...manual.filter((i) => i.prop),
95
+ ]
96
+ return merged
97
+ }
98
+
99
+ const items = computed(() => {
100
+ void crudLocaleRev.value
101
+ return mergeSearchItems(autoItems.value, manualItems.value)
102
+ })
103
+
104
+ function itemPlaceholder(item: CrudSearchItem) {
105
+ return resolveSearchPlaceholder(item)
106
+ }
107
+
108
+ const form = reactive<Record<string, unknown>>({})
109
+
110
+ function isRange(item: CrudSearchItem) {
111
+ return item.type === 'number-range' || item.type === 'daterange' || Boolean(item.range)
112
+ }
113
+
114
+ /** 多选:explicit multiple,或组件声明为 vm-multi-select(宿主常漏写 multiple) */
115
+ function isMultiValue(item: CrudSearchItem) {
116
+ if (item.multiple) return true
117
+ const name = item.component?.name
118
+ return typeof name === 'string' && /multi-select/i.test(name)
119
+ }
120
+
121
+ function emptyValue(item: CrudSearchItem) {
122
+ if (isRange(item)) return [null, null]
123
+ if (isMultiValue(item)) return []
124
+ return ''
125
+ }
126
+
127
+ /** 浅拷贝初始化值(数组避免共用引用) */
128
+ function cloneInit(v: unknown) {
129
+ if (Array.isArray(v)) return [...v]
130
+ return v
131
+ }
132
+
133
+ /** item.value 优先;未设则 emptyValue。重置也走此规则。 */
134
+ function initialValue(item: CrudSearchItem) {
135
+ if (item.value !== undefined) {
136
+ const v = cloneInit(item.value)
137
+ if (isMultiValue(item) && !Array.isArray(v)) {
138
+ return v == null || v === '' ? [] : [v]
139
+ }
140
+ if (isRange(item) && !Array.isArray(v)) return [null, null]
141
+ return v
142
+ }
143
+ return emptyValue(item)
144
+ }
145
+
146
+ /** 已有 form 值与控件类型不一致时纠正(避免 '' 绑到 multi-select) */
147
+ function coerceFormValue(item: CrudSearchItem, current: unknown) {
148
+ if (isMultiValue(item)) {
149
+ if (Array.isArray(current)) return current
150
+ if (current == null || current === '') return []
151
+ return [current]
152
+ }
153
+ if (isRange(item)) {
154
+ if (Array.isArray(current) && current.length >= 2) return current
155
+ return [null, null]
156
+ }
157
+ return current
158
+ }
159
+
160
+ function coerceSelect(item: CrudSearchItem, v: unknown) {
161
+ const s = v == null ? '' : String(v)
162
+ if (!s) return ''
163
+ const hit = optionsOf(item).find((o) => String(o.value) === s)
164
+ return hit ? hit.value : s
165
+ }
166
+
167
+ /** options 支持 Ref / ComputedRef / getter(与 vm-upsert 一致) */
168
+ function resolveOptions(
169
+ options: CrudSearchItem['options'],
170
+ ): Array<{ label: string; value: string | number | boolean }> {
171
+ const list = options == null ? [] : toValue(options)
172
+ return Array.isArray(list) ? list : []
173
+ }
174
+
175
+ /** 筛选项 options:优先 EPS 本地一级字典,禁止请求 /data */
176
+ function optionsOf(item: CrudSearchItem) {
177
+ if (item.dict) return mapDictOptions(item.dict)
178
+ return resolveOptions(item.options)
179
+ }
180
+
181
+ function rebuildAutoItems() {
182
+ const plugins = getCrudStyle().search.plugins as TablePlugin[]
183
+ const auto = plugins?.find((p) => p?.__plugin === 'setAuto')
184
+ if (!auto) {
185
+ autoItems.value = []
186
+ return
187
+ }
188
+ const svc = crud.service as { namespace?: string; search?: Record<string, unknown> }
189
+ autoItems.value = buildAutoSearchItems(svc, {
190
+ hideLabel: auto.hideLabel !== false,
191
+ ignoreFields: auto.ignoreFields as string[] | undefined,
192
+ })
193
+ }
194
+
195
+ onMounted(rebuildAutoItems)
196
+
197
+ // EPS 热更 / createEps 重建 leaf 后补一次(仅 onMounted 会漏)
198
+ watch(
199
+ () => {
200
+ const svc = crud.service as { namespace?: string; search?: unknown }
201
+ return [svc?.namespace, svc?.search, getCrudStyle().search.plugins]
202
+ },
203
+ rebuildAutoItems,
204
+ { deep: true },
205
+ )
206
+
207
+ watch(
208
+ items,
209
+ (list) => {
210
+ for (const it of list) {
211
+ if (!(it.prop in form)) {
212
+ form[it.prop] = initialValue(it)
213
+ } else {
214
+ form[it.prop] = coerceFormValue(it, form[it.prop])
215
+ }
216
+ }
217
+ const active = list.length > 0
218
+ crud.hasSearchFilters.value = active
219
+ crud.searchActions.value = active ? { search, reset } : null
220
+ // 先写入 form + params(有 value 则带条件,无则不带),不在这里 refresh;
221
+ // 等页面 useCrud 回调 / immediate 只拉一次,避免空参无效请求。
222
+ if (active) applyFormToParams(false)
223
+ },
224
+ { immediate: true, deep: true },
225
+ )
226
+
227
+ function resolveField(item: CrudSearchItem) {
228
+ const name = item.component?.name
229
+ if (typeof name === 'string') {
230
+ const comp = resolveCrudComponent(name)
231
+ if (comp) return comp
232
+ } else if (name) {
233
+ return name
234
+ }
235
+ if (item.type === 'select' && item.multiple) {
236
+ return resolveCrudComponent('vm-multi-select')
237
+ }
238
+ if (item.type === 'select' && isMultiValue(item)) {
239
+ return resolveCrudComponent('vm-multi-select')
240
+ }
241
+ if (item.type === 'daterange') {
242
+ return resolveCrudComponent('vm-date-range')
243
+ }
244
+ if (item.type === 'date') {
245
+ return resolveCrudComponent('vm-date-picker')
246
+ }
247
+ if (item.type === 'number-range') {
248
+ return resolveCrudComponent('vm-number-range')
249
+ }
250
+ if (item.type === 'select') return undefined
251
+ return undefined
252
+ }
253
+
254
+ function fieldProps(item: CrudSearchItem) {
255
+ const ph = itemPlaceholder(item)
256
+ const rangePlaceholders =
257
+ item.type === 'number-range' || item.type === 'daterange' || item.phMode === 'range'
258
+ ? resolveRangePlaceholders(item)
259
+ : {}
260
+ return {
261
+ options: optionsOf(item),
262
+ refreshOnChange: false,
263
+ precision: item.range?.rangeType,
264
+ mode:
265
+ item.range?.rangeType === 'float' || item.range?.rangeType === 'int'
266
+ ? item.range.rangeType
267
+ : undefined,
268
+ ...(item.component?.props || {}),
269
+ placeholder: ph,
270
+ ...rangePlaceholders,
271
+ }
272
+ }
273
+
274
+ function buildSearchPayload() {
275
+ const payload: Record<string, unknown> = {}
276
+ for (const it of items.value) {
277
+ const v = form[it.prop]
278
+ if (it.range) {
279
+ const pair = Array.isArray(v) ? v : [null, null]
280
+ if (pair[0] != null && pair[0] !== '') payload[it.range.min] = pair[0]
281
+ if (pair[1] != null && pair[1] !== '') payload[it.range.max] = pair[1]
282
+ continue
283
+ }
284
+ if (it.multiple || isMultiValue(it)) {
285
+ if (Array.isArray(v) && v.length) payload[it.prop] = v
286
+ continue
287
+ }
288
+ if (v !== '' && v != null) payload[it.prop] = v
289
+ }
290
+ return payload
291
+ }
292
+
293
+ /** 用当前 form 覆盖本组筛选项对应 params;doRefresh=false 仅赋值供首屏一次查询 */
294
+ function applyFormToParams(doRefresh = true) {
295
+ const payload = buildSearchPayload()
296
+ const next = { ...crud.getParams() }
297
+ for (const it of items.value) {
298
+ delete next[it.prop]
299
+ if (it.range) {
300
+ delete next[it.range.min]
301
+ delete next[it.range.max]
302
+ }
303
+ }
304
+ Object.assign(next, payload)
305
+ crud.params.value = next
306
+ if (!doRefresh) return
307
+ crud.pagination.value = { ...crud.pagination.value, page: 1 }
308
+ void crud.refresh()
309
+ }
310
+
311
+ function search() {
312
+ applyFormToParams(true)
313
+ }
314
+
315
+ function reset() {
316
+ for (const it of items.value) {
317
+ form[it.prop] = initialValue(it)
318
+ }
319
+ // 回到 props.params 底稿后,再按当前 form(含 value 初始)提交一次
320
+ crud.resetParams(false)
321
+ search()
322
+ }
323
+
324
+ onBeforeUnmount(() => {
325
+ crud.hasSearchFilters.value = false
326
+ if (crud.searchActions.value?.search === search) {
327
+ crud.searchActions.value = null
328
+ }
329
+ })
330
+
331
+ defineExpose({ form, search, reset })
332
+ </script>
333
+
334
+ <style lang="scss" scoped>
335
+ .vm-crud-search {
336
+ --vm-search-gap: 12px;
337
+ container-type: inline-size;
338
+ container-name: vm-crud-search;
339
+
340
+ display: flex;
341
+ width: 100%;
342
+ min-width: 0;
343
+ flex-wrap: wrap;
344
+ align-items: flex-start;
345
+ gap: var(--vm-search-gap);
346
+ margin-bottom: 6px;
347
+ }
348
+
349
+ .vm-crud-search__filters {
350
+ display: grid;
351
+ flex: 1 1 auto;
352
+ /* 默认 2 列;随容器变宽升到 8 列,单列始终 ≥140 */
353
+ grid-template-columns: repeat(2, minmax(0, 1fr));
354
+ gap: var(--vm-search-gap);
355
+ min-width: 0;
356
+ align-items: center;
357
+ }
358
+
359
+ /* n * 140 + (n-1) * 12 = 152n - 12 */
360
+ @container vm-crud-search (min-width: 444px) {
361
+ .vm-crud-search__filters {
362
+ grid-template-columns: repeat(3, minmax(0, 1fr));
363
+ }
364
+ }
365
+
366
+ @container vm-crud-search (min-width: 596px) {
367
+ .vm-crud-search__filters {
368
+ grid-template-columns: repeat(4, minmax(0, 1fr));
369
+ }
370
+ }
371
+
372
+ @container vm-crud-search (min-width: 748px) {
373
+ .vm-crud-search__filters {
374
+ grid-template-columns: repeat(5, minmax(0, 1fr));
375
+ }
376
+ }
377
+
378
+ @container vm-crud-search (min-width: 900px) {
379
+ .vm-crud-search__filters {
380
+ grid-template-columns: repeat(6, minmax(0, 1fr));
381
+ }
382
+ }
383
+
384
+ @container vm-crud-search (min-width: 1052px) {
385
+ .vm-crud-search__filters {
386
+ grid-template-columns: repeat(7, minmax(0, 1fr));
387
+ }
388
+ }
389
+
390
+ @container vm-crud-search (min-width: 1204px) {
391
+ .vm-crud-search__filters {
392
+ grid-template-columns: repeat(8, minmax(0, 1fr));
393
+ }
394
+ }
395
+
396
+ .vm-crud-search__actions {
397
+ display: flex;
398
+ flex: 0 0 auto;
399
+ flex-wrap: wrap;
400
+ align-items: center;
401
+ gap: var(--vm-search-gap);
402
+ }
403
+
404
+ :deep(.vm-crud-search__control) {
405
+ box-sizing: border-box;
406
+ width: 100% !important;
407
+ min-width: 0 !important;
408
+ max-width: none !important;
409
+ height: var(--vm-control-height) !important;
410
+ border-radius: 12px !important;
411
+ box-shadow: none !important;
412
+
413
+ &:not(.is-range) {
414
+ border: 1px solid transparent !important;
415
+ background: var(--muted) !important;
416
+
417
+ &:focus,
418
+ &:focus-visible {
419
+ border-color: var(--focus-border) !important;
420
+ box-shadow: none !important;
421
+ }
422
+ }
423
+
424
+ /* 区间占两列:2 * 列宽 + 12px */
425
+ &.is-range {
426
+ width: 100% !important;
427
+ min-width: 0 !important;
428
+ max-width: none !important;
429
+ height: var(--vm-control-height) !important;
430
+ grid-column: span 2;
431
+ padding: 0 10px !important;
432
+ border: 1px solid transparent !important;
433
+ border-radius: 12px !important;
434
+ background: var(--muted) !important;
435
+ }
436
+ }
437
+
438
+ .vm-crud-search__btn {
439
+ height: var(--vm-control-height);
440
+ padding: 0 14px;
441
+ border: none;
442
+ border-radius: 12px;
443
+ font-size: 13px;
444
+ font-weight: 600;
445
+ cursor: pointer;
446
+ transition: background 0.15s ease, color 0.15s ease, opacity 0.15s ease;
447
+
448
+ &.is-primary {
449
+ background: var(--brand);
450
+ color: #fff;
451
+
452
+ &:hover {
453
+ background: var(--brand-deep);
454
+ }
455
+ }
456
+
457
+ &.is-ghost {
458
+ background: var(--muted);
459
+ color: var(--foreground);
460
+
461
+ &:hover {
462
+ background: color-mix(in srgb, var(--muted) 70%, var(--foreground) 8%);
463
+ }
464
+ }
465
+ }
466
+ </style>