@qynpm/ui 1.0.40 → 1.0.41

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 (422) hide show
  1. package/README.md +1797 -1797
  2. package/dist/index.cjs +19 -19
  3. package/dist/index.mjs +21 -21
  4. package/dist/qy-action-bar/index.cjs +1 -1
  5. package/dist/qy-action-bar/index.mjs +1 -1
  6. package/dist/qy-alert/index.cjs +1 -1
  7. package/dist/qy-alert/index.mjs +4 -4
  8. package/dist/qy-aside/index.cjs +1 -1
  9. package/dist/qy-aside/index.mjs +4 -4
  10. package/dist/qy-autocomplete/index.cjs +1 -1
  11. package/dist/qy-autocomplete/index.mjs +3 -3
  12. package/dist/qy-avatar/index.cjs +1 -1
  13. package/dist/qy-avatar/index.mjs +1 -1
  14. package/dist/qy-badge/index.cjs +1 -1
  15. package/dist/qy-badge/index.mjs +4 -4
  16. package/dist/qy-button/index.cjs +2 -2
  17. package/dist/qy-button/index.mjs +2 -2
  18. package/dist/qy-card/index.cjs +1 -1
  19. package/dist/qy-card/index.mjs +1 -1
  20. package/dist/qy-cascader/index.cjs +1 -1
  21. package/dist/qy-cascader/index.mjs +3 -3
  22. package/dist/qy-checkbox/index.cjs +1 -1
  23. package/dist/qy-checkbox/index.mjs +1 -1
  24. package/dist/qy-checkbox-group/index.cjs +1 -1
  25. package/dist/qy-checkbox-group/index.mjs +4 -4
  26. package/dist/qy-col/index.cjs +1 -1
  27. package/dist/qy-col/index.mjs +4 -4
  28. package/dist/qy-collapse/index.cjs +1 -1
  29. package/dist/qy-collapse/index.mjs +2 -2
  30. package/dist/qy-collapse-item/index.cjs +1 -1
  31. package/dist/qy-collapse-item/index.mjs +5 -5
  32. package/dist/qy-color-picker/index.cjs +1 -1
  33. package/dist/qy-color-picker/index.mjs +4 -4
  34. package/dist/qy-container/index.cjs +1 -1
  35. package/dist/qy-container/index.mjs +3 -3
  36. package/dist/qy-date-picker/index.cjs +1 -1
  37. package/dist/qy-date-picker/index.mjs +1 -1
  38. package/dist/qy-descriptions/index.cjs +1 -1
  39. package/dist/qy-descriptions/index.mjs +1 -1
  40. package/dist/qy-descriptions-item/index.cjs +1 -1
  41. package/dist/qy-descriptions-item/index.mjs +4 -4
  42. package/dist/qy-dialog/index.cjs +1 -1
  43. package/dist/qy-dialog/index.mjs +4 -4
  44. package/dist/qy-divider/index.cjs +1 -1
  45. package/dist/qy-divider/index.mjs +4 -4
  46. package/dist/qy-drawer/index.cjs +1 -1
  47. package/dist/qy-drawer/index.mjs +2 -2
  48. package/dist/qy-dropdown/index.cjs +2 -2
  49. package/dist/qy-dropdown/index.mjs +2 -2
  50. package/dist/qy-empty/index.cjs +1 -1
  51. package/dist/qy-empty/index.mjs +4 -4
  52. package/dist/qy-file-picker/index.cjs +1 -1
  53. package/dist/qy-file-picker/index.mjs +1 -1
  54. package/dist/qy-form-section/index.cjs +1 -1
  55. package/dist/qy-form-section/index.mjs +1 -1
  56. package/dist/qy-fullscreen/index.cjs +1 -1
  57. package/dist/qy-fullscreen/index.mjs +1 -1
  58. package/dist/qy-icon/index.cjs +1 -1
  59. package/dist/qy-icon/index.mjs +2 -2
  60. package/dist/qy-icon-picker/index.cjs +2 -2
  61. package/dist/qy-icon-picker/index.mjs +5 -5
  62. package/dist/qy-iframe/index.cjs +1 -1
  63. package/dist/qy-iframe/index.mjs +1 -1
  64. package/dist/qy-image/index.cjs +1 -1
  65. package/dist/qy-image/index.mjs +1 -1
  66. package/dist/qy-image-preview/index.cjs +1 -1
  67. package/dist/qy-image-preview/index.mjs +1 -1
  68. package/dist/qy-image-upload/index.cjs +1 -1
  69. package/dist/qy-image-upload/index.mjs +1 -1
  70. package/dist/qy-input/index.cjs +1 -1
  71. package/dist/qy-input/index.mjs +1 -1
  72. package/dist/qy-input-number/index.cjs +1 -1
  73. package/dist/qy-input-number/index.mjs +2 -2
  74. package/dist/qy-input-tag/index.cjs +1 -1
  75. package/dist/qy-input-tag/index.mjs +4 -4
  76. package/dist/qy-legacy-selection-dialog/index.cjs +1 -1
  77. package/dist/qy-legacy-selection-dialog/index.mjs +1 -1
  78. package/dist/qy-link/index.cjs +1 -1
  79. package/dist/qy-link/index.mjs +5 -5
  80. package/dist/qy-main/index.cjs +1 -1
  81. package/dist/qy-main/index.mjs +4 -4
  82. package/dist/qy-menu-actions/index.cjs +1 -1
  83. package/dist/qy-menu-actions/index.mjs +1 -1
  84. package/dist/qy-money-input/index.cjs +1 -1
  85. package/dist/qy-money-input/index.mjs +4 -4
  86. package/dist/qy-pagination/index.cjs +1 -1
  87. package/dist/qy-pagination/index.mjs +1 -1
  88. package/dist/qy-popconfirm/index.cjs +1 -1
  89. package/dist/qy-popconfirm/index.mjs +5 -5
  90. package/dist/qy-popover/index.cjs +1 -1
  91. package/dist/qy-popover/index.mjs +4 -4
  92. package/dist/qy-progress/index.cjs +1 -1
  93. package/dist/qy-progress/index.mjs +3 -3
  94. package/dist/qy-radio/index.cjs +1 -1
  95. package/dist/qy-radio/index.mjs +1 -1
  96. package/dist/qy-radio-group/index.cjs +1 -1
  97. package/dist/qy-radio-group/index.mjs +1 -1
  98. package/dist/qy-record-quote-search/index.cjs +1 -1
  99. package/dist/qy-record-quote-search/index.mjs +1 -1
  100. package/dist/qy-remark-image/index.cjs +1 -1
  101. package/dist/qy-remark-image/index.mjs +1 -1
  102. package/dist/qy-remote-select/index.cjs +1 -1
  103. package/dist/qy-remote-select/index.mjs +1 -1
  104. package/dist/qy-result/index.cjs +1 -1
  105. package/dist/qy-result/index.mjs +4 -4
  106. package/dist/qy-row/index.cjs +1 -1
  107. package/dist/qy-row/index.mjs +4 -4
  108. package/dist/qy-scrollbar/index.cjs +1 -1
  109. package/dist/qy-scrollbar/index.mjs +3 -3
  110. package/dist/qy-search-input/index.cjs +1 -1
  111. package/dist/qy-search-input/index.mjs +1 -1
  112. package/dist/qy-select/index.cjs +1 -1
  113. package/dist/qy-select/index.mjs +1 -1
  114. package/dist/qy-selection-dialog/index.cjs +1 -1
  115. package/dist/qy-selection-dialog/index.mjs +1 -1
  116. package/dist/qy-skeleton/index.cjs +1 -1
  117. package/dist/qy-skeleton/index.mjs +4 -4
  118. package/dist/qy-skeleton-item/index.cjs +1 -1
  119. package/dist/qy-skeleton-item/index.mjs +4 -4
  120. package/dist/qy-statistic/index.cjs +1 -1
  121. package/dist/qy-statistic/index.mjs +3 -3
  122. package/dist/qy-step/index.cjs +1 -1
  123. package/dist/qy-step/index.mjs +5 -5
  124. package/dist/qy-steps/index.cjs +1 -1
  125. package/dist/qy-steps/index.mjs +4 -4
  126. package/dist/qy-switch/index.cjs +1 -1
  127. package/dist/qy-switch/index.mjs +1 -1
  128. package/dist/qy-tab-pane/index.cjs +1 -1
  129. package/dist/qy-tab-pane/index.mjs +4 -4
  130. package/dist/qy-table-column-settings/index.cjs +1 -1
  131. package/dist/qy-table-column-settings/index.mjs +1 -1
  132. package/dist/qy-tabs/index.cjs +1 -1
  133. package/dist/qy-tabs/index.mjs +4 -4
  134. package/dist/qy-tag/index.cjs +1 -1
  135. package/dist/qy-tag/index.mjs +1 -1
  136. package/dist/qy-tooltip/index.cjs +1 -1
  137. package/dist/qy-tooltip/index.mjs +4 -4
  138. package/dist/qy-tree/index.cjs +1 -1
  139. package/dist/qy-tree/index.mjs +5 -5
  140. package/dist/qy-tree-select/index.cjs +1 -1
  141. package/dist/qy-tree-select/index.mjs +1 -1
  142. package/dist/qy-upload/index.cjs +1 -1
  143. package/dist/qy-upload/index.mjs +1 -1
  144. package/dist/qy-watermark/index.cjs +1 -1
  145. package/dist/qy-watermark/index.mjs +1 -1
  146. package/dist/shared/{index-CBhrdEIf.mjs → index-2D5AFexl.mjs} +1 -1
  147. package/dist/shared/index-8Iwma3ls.mjs +222 -0
  148. package/dist/shared/index-B25yA5j-.mjs +71 -0
  149. package/dist/shared/index-B3GsIwhf.mjs +142 -0
  150. package/dist/shared/index-B3XwO-Lc.mjs +127 -0
  151. package/dist/shared/index-B3YHS3Aa.mjs +54 -0
  152. package/dist/shared/index-BEcS8y8g.mjs +68 -0
  153. package/dist/shared/index-BNssRW4d.mjs +90 -0
  154. package/dist/shared/index-BSTMCPDj.mjs +72 -0
  155. package/dist/shared/index-BhvOSOfi.mjs +766 -0
  156. package/dist/shared/index-BjqJCq-6.mjs +293 -0
  157. package/dist/shared/index-Bq9quq2D.cjs +1 -0
  158. package/dist/shared/index-ByQyMTPg.mjs +285 -0
  159. package/dist/shared/index-CGq7Q_hV.mjs +119 -0
  160. package/dist/shared/{index-D97QYFZw.cjs → index-CUlhX6fW.cjs} +1 -1
  161. package/dist/shared/index-CVWru9T3.cjs +1 -0
  162. package/dist/shared/index-CVYNG8Fc.cjs +1 -0
  163. package/dist/shared/index-CiE6qJCJ.mjs +377 -0
  164. package/dist/shared/index-CnVhquq5.cjs +1 -0
  165. package/dist/shared/index-Co84fsS5.mjs +225 -0
  166. package/dist/shared/index-D27mwR57.cjs +1 -0
  167. package/dist/shared/index-DAztNKSp.cjs +1 -0
  168. package/dist/shared/index-DKw-seoh.cjs +1 -0
  169. package/dist/shared/index-DRIoLeFE.mjs +162 -0
  170. package/dist/shared/index-DRugp8x0.cjs +1 -0
  171. package/dist/shared/index-DTbGlDqr.cjs +1 -0
  172. package/dist/shared/index-DXZ6Y6wd.mjs +107 -0
  173. package/dist/shared/index-DiEag4sK.cjs +1 -0
  174. package/dist/shared/index-DuP-b_eY.cjs +1 -0
  175. package/dist/shared/index-DvFMgAcu.mjs +149 -0
  176. package/dist/shared/index-E3zI0Ugj.mjs +2362 -0
  177. package/dist/shared/index-EIFVul2W.cjs +1 -0
  178. package/dist/shared/index-HNFq7v-A.cjs +1 -0
  179. package/dist/shared/index-Mj7JZt7y.cjs +1 -0
  180. package/dist/shared/index-MyDDX-zj.cjs +1 -0
  181. package/dist/shared/index-R_hSPemR.cjs +1 -0
  182. package/dist/shared/index-d76Z3yrB.cjs +1 -0
  183. package/dist/shared/index-gMrQlV5n.cjs +1 -0
  184. package/dist/shared/index-rSrDnOpu.cjs +1 -0
  185. package/dist/shared/index-zo5J-y0C.mjs +157 -0
  186. package/dist/shared/{index-CCVlab6d.mjs → index.vue_vue_type_script_lang-69zSOotQ.mjs} +10 -11
  187. package/dist/shared/index.vue_vue_type_script_lang-8AT3-xU-.cjs +1 -0
  188. package/dist/shared/{index-EPcAlzgc.mjs → index.vue_vue_type_script_lang-BGAdXWIL.mjs} +11 -12
  189. package/dist/shared/index.vue_vue_type_script_lang-BO9Ju_i0.cjs +1 -0
  190. package/dist/shared/{index-1Vw54aYL.mjs → index.vue_vue_type_script_lang-BaIOvoQn.mjs} +5 -6
  191. package/dist/shared/index.vue_vue_type_script_lang-Bc3tktk9.cjs +1 -0
  192. package/dist/shared/index.vue_vue_type_script_lang-BgapsQjI.cjs +1 -0
  193. package/dist/shared/{index-BG3XKumS.mjs → index.vue_vue_type_script_lang-Bk0kLg5l.mjs} +8 -9
  194. package/dist/shared/index.vue_vue_type_script_lang-BkoqbceR.cjs +1 -0
  195. package/dist/shared/index.vue_vue_type_script_lang-BnmY1ndj.mjs +77 -0
  196. package/dist/shared/index.vue_vue_type_script_lang-By3jd4gw.cjs +1 -0
  197. package/dist/shared/{index-Se0xx6vl.mjs → index.vue_vue_type_script_lang-C4JHCuXz.mjs} +13 -14
  198. package/dist/shared/{index-D_Imq4-m.mjs → index.vue_vue_type_script_lang-C9X0V5AK.mjs} +12 -13
  199. package/dist/shared/index.vue_vue_type_script_lang-CCL57H5c.cjs +1 -0
  200. package/dist/shared/index.vue_vue_type_script_lang-CIOi2ahp.cjs +1 -0
  201. package/dist/shared/index.vue_vue_type_script_lang-CKZUcaZ5.cjs +1 -0
  202. package/dist/shared/index.vue_vue_type_script_lang-CWnNQBPN.mjs +31 -0
  203. package/dist/shared/{index-CrlLsoRF.mjs → index.vue_vue_type_script_lang-CZK0hDYa.mjs} +20 -21
  204. package/dist/shared/index.vue_vue_type_script_lang-CfjfZCT3.cjs +1 -0
  205. package/dist/shared/index.vue_vue_type_script_lang-ChS-3_vl.mjs +43 -0
  206. package/dist/shared/index.vue_vue_type_script_lang-Cv4Pf58E.cjs +1 -0
  207. package/dist/shared/index.vue_vue_type_script_lang-CwrbII5c.cjs +1 -0
  208. package/dist/shared/index.vue_vue_type_script_lang-D42aRlO2.cjs +1 -0
  209. package/dist/shared/{index-BPXJkcM1.mjs → index.vue_vue_type_script_lang-D7b9ABei.mjs} +19 -20
  210. package/dist/shared/{index-LDtOVxCE.mjs → index.vue_vue_type_script_lang-D7nzeBUR.mjs} +7 -8
  211. package/dist/shared/index.vue_vue_type_script_lang-DIKHRo0o.mjs +72 -0
  212. package/dist/shared/index.vue_vue_type_script_lang-DLmUPDR5.cjs +1 -0
  213. package/dist/shared/index.vue_vue_type_script_lang-DMrpLmWN.cjs +1 -0
  214. package/dist/shared/{index-TVUj4Yp4.mjs → index.vue_vue_type_script_lang-DOOT2grg.mjs} +10 -11
  215. package/dist/shared/index.vue_vue_type_script_lang-DRvk4-_O.mjs +43 -0
  216. package/dist/shared/{index-BQzQcTgt.mjs → index.vue_vue_type_script_lang-Dfq7D3mJ.mjs} +3 -4
  217. package/dist/shared/index.vue_vue_type_script_lang-DpSaB5eg.cjs +1 -0
  218. package/dist/shared/index.vue_vue_type_script_lang-WJ63_A7F.cjs +1 -0
  219. package/dist/shared/{index-B1I7mCIm.mjs → index.vue_vue_type_script_lang-chBiq2cG.mjs} +3 -4
  220. package/dist/shared/index.vue_vue_type_script_setup_true_lang-4KZSABSM.cjs +1 -0
  221. package/dist/shared/index.vue_vue_type_script_setup_true_lang-B4JrNUDc.mjs +43 -0
  222. package/dist/shared/index.vue_vue_type_script_setup_true_lang-BJe7Uo6S.mjs +42 -0
  223. package/dist/shared/index.vue_vue_type_script_setup_true_lang-BWi3g3mb.cjs +1 -0
  224. package/dist/shared/index.vue_vue_type_script_setup_true_lang-BXnZt9UT.mjs +63 -0
  225. package/dist/shared/index.vue_vue_type_script_setup_true_lang-Bdz9oDDW.mjs +62 -0
  226. package/dist/shared/index.vue_vue_type_script_setup_true_lang-BiIgNax-.cjs +1 -0
  227. package/dist/shared/index.vue_vue_type_script_setup_true_lang-BnIolx5s.cjs +1 -0
  228. package/dist/shared/index.vue_vue_type_script_setup_true_lang-C96ZaggL.cjs +1 -0
  229. package/dist/shared/index.vue_vue_type_script_setup_true_lang-CKp87br2.cjs +1 -0
  230. package/dist/shared/index.vue_vue_type_script_setup_true_lang-COAUEujY.mjs +48 -0
  231. package/dist/shared/index.vue_vue_type_script_setup_true_lang-CqSJ_8hG.cjs +1 -0
  232. package/dist/shared/index.vue_vue_type_script_setup_true_lang-Cr9PdvyR.cjs +1 -0
  233. package/dist/shared/index.vue_vue_type_script_setup_true_lang-D7BlbHN5.cjs +1 -0
  234. package/dist/shared/index.vue_vue_type_script_setup_true_lang-DIWWHODS.mjs +197 -0
  235. package/dist/shared/index.vue_vue_type_script_setup_true_lang-DUEhuwGQ.cjs +1 -0
  236. package/dist/shared/index.vue_vue_type_script_setup_true_lang-DbLp1kvW.cjs +1 -0
  237. package/dist/shared/index.vue_vue_type_script_setup_true_lang-Dd_nKJvH.mjs +19 -0
  238. package/dist/shared/index.vue_vue_type_script_setup_true_lang-Dn29lZTs.mjs +106 -0
  239. package/dist/shared/index.vue_vue_type_script_setup_true_lang-DwFGEW4B.mjs +143 -0
  240. package/dist/shared/index.vue_vue_type_script_setup_true_lang-EiHoQBXt.mjs +94 -0
  241. package/dist/shared/index.vue_vue_type_script_setup_true_lang-IyZesuKm.mjs +48 -0
  242. package/dist/shared/index.vue_vue_type_script_setup_true_lang-UBQQ6Z03.cjs +1 -0
  243. package/dist/shared/index.vue_vue_type_script_setup_true_lang-ccFLNRry.cjs +1 -0
  244. package/dist/shared/index.vue_vue_type_script_setup_true_lang-r7iyZzDS.mjs +61 -0
  245. package/dist/shared/index.vue_vue_type_script_setup_true_lang-wG7OTsWa.mjs +331 -0
  246. package/dist/shared/index.vue_vue_type_style_index_0_lang-1cTut9Ql.cjs +1 -0
  247. package/dist/shared/index.vue_vue_type_style_index_0_lang-B1FgJZbw.mjs +148 -0
  248. package/dist/shared/index.vue_vue_type_style_index_0_lang-B2thgQml.cjs +1 -0
  249. package/dist/shared/index.vue_vue_type_style_index_0_lang-B6cv-Ra3.mjs +404 -0
  250. package/dist/shared/index.vue_vue_type_style_index_0_lang-BMZqMPZb.mjs +215 -0
  251. package/dist/shared/index.vue_vue_type_style_index_0_lang-BXTkWo5P.cjs +1 -0
  252. package/dist/shared/index.vue_vue_type_style_index_0_lang-BnPRHCwR.cjs +1 -0
  253. package/dist/shared/index.vue_vue_type_style_index_0_lang-BoaO6MKl.cjs +1 -0
  254. package/dist/shared/index.vue_vue_type_style_index_0_lang-C1n-zAZh.mjs +67 -0
  255. package/dist/shared/index.vue_vue_type_style_index_0_lang-C4Yk-UdJ.mjs +172 -0
  256. package/dist/shared/index.vue_vue_type_style_index_0_lang-CPxbKjvY.mjs +286 -0
  257. package/dist/shared/index.vue_vue_type_style_index_0_lang-CU9gg9t5.cjs +1 -0
  258. package/dist/shared/index.vue_vue_type_style_index_0_lang-CVdFZeHK.mjs +98 -0
  259. package/dist/shared/index.vue_vue_type_style_index_0_lang-CcVf5MXE.mjs +166 -0
  260. package/dist/shared/index.vue_vue_type_style_index_0_lang-D9DraThL.cjs +1 -0
  261. package/dist/shared/index.vue_vue_type_style_index_0_lang-DFAaBzkW.cjs +1 -0
  262. package/dist/shared/index.vue_vue_type_style_index_0_lang-DHK86rdP.cjs +1 -0
  263. package/dist/shared/index.vue_vue_type_style_index_0_lang-DSur831A.mjs +68 -0
  264. package/dist/shared/index.vue_vue_type_style_index_0_lang-DVXf-yUs.cjs +1 -0
  265. package/dist/shared/index.vue_vue_type_style_index_0_lang-DbQkbvgb.mjs +317 -0
  266. package/dist/shared/index.vue_vue_type_style_index_0_lang-DsOg_Rum.mjs +128 -0
  267. package/dist/shared/index.vue_vue_type_style_index_0_lang-KHk9wRYT.mjs +298 -0
  268. package/dist/shared/index.vue_vue_type_style_index_0_lang-OHPkiKBo.cjs +1 -0
  269. package/dist/shared/index.vue_vue_type_style_index_0_lang-RiwA2WPO.cjs +1 -0
  270. package/dist/shared/{index-DZU3jXf9.mjs → index.vue_vue_type_style_index_0_lang-Tzo8o6M8.mjs} +9 -10
  271. package/dist/shared/index.vue_vue_type_style_index_0_lang-WGzoSatU.cjs +1 -0
  272. package/dist/shared/{index-GRwpbz1m.mjs → index.vue_vue_type_style_index_0_lang-gs0YJI91.mjs} +17 -18
  273. package/dist/shared/index.vue_vue_type_style_index_0_lang-hbNK_h45.cjs +1 -0
  274. package/index.d.ts +592 -592
  275. package/package.json +14 -10
  276. package/qy-action-bar/index.d.ts +5 -5
  277. package/qy-aside/index.d.ts +47 -47
  278. package/qy-button/index.d.ts +34 -34
  279. package/qy-checkbox/index.d.ts +45 -45
  280. package/qy-checkbox-group/index.d.ts +48 -48
  281. package/qy-col/index.d.ts +65 -65
  282. package/qy-color-picker/index.d.ts +36 -36
  283. package/qy-container/index.d.ts +49 -49
  284. package/qy-date-picker/index.d.ts +140 -140
  285. package/qy-dropdown/index.d.ts +40 -40
  286. package/qy-file-picker/index.d.ts +48 -48
  287. package/qy-form-section/index.d.ts +5 -5
  288. package/qy-fullscreen/index.d.ts +72 -72
  289. package/qy-icon/index.d.ts +99 -99
  290. package/qy-icon-picker/index.d.ts +56 -56
  291. package/qy-input/index.d.ts +32 -32
  292. package/qy-input-number/index.d.ts +15 -15
  293. package/qy-legacy-selection-dialog/index.d.ts +5 -5
  294. package/qy-main/index.d.ts +45 -45
  295. package/qy-popconfirm/index.d.ts +55 -55
  296. package/qy-popover/index.d.ts +63 -63
  297. package/qy-radio/index.d.ts +44 -44
  298. package/qy-radio-group/index.d.ts +60 -60
  299. package/qy-record-quote-search/index.d.ts +5 -5
  300. package/qy-remark-image/index.d.ts +5 -5
  301. package/qy-remote-select/index.d.ts +12 -12
  302. package/qy-row/index.d.ts +59 -59
  303. package/qy-search-input/index.d.ts +5 -5
  304. package/qy-select/index.d.ts +67 -67
  305. package/qy-selection-dialog/index.d.ts +5 -5
  306. package/qy-statistic/index.d.ts +61 -61
  307. package/qy-switch/index.d.ts +46 -46
  308. package/qy-tag/index.d.ts +44 -44
  309. package/qy-tooltip/index.d.ts +54 -54
  310. package/qy-watermark/index.d.ts +72 -72
  311. package/dist/shared/index-5vWL_IJI.mjs +0 -150
  312. package/dist/shared/index-7fIb2Tqw.mjs +0 -129
  313. package/dist/shared/index-9T0p3USM.cjs +0 -1
  314. package/dist/shared/index-B-zfoMbw.cjs +0 -1
  315. package/dist/shared/index-B1aU9mew.mjs +0 -77
  316. package/dist/shared/index-B26-GlFX.cjs +0 -1
  317. package/dist/shared/index-B63vgrS4.mjs +0 -73
  318. package/dist/shared/index-B97hTd-h.cjs +0 -1
  319. package/dist/shared/index-B9zEH5Yq.cjs +0 -1
  320. package/dist/shared/index-BA_tJgLE.cjs +0 -1
  321. package/dist/shared/index-BBIPQa5N.mjs +0 -76
  322. package/dist/shared/index-BCWvMvRL.cjs +0 -1
  323. package/dist/shared/index-BDJIWxaw.cjs +0 -1
  324. package/dist/shared/index-BFbAB8UH.mjs +0 -307
  325. package/dist/shared/index-BHGDbXoK.mjs +0 -82
  326. package/dist/shared/index-BInkt-Al.cjs +0 -1
  327. package/dist/shared/index-BKEw_9fh.mjs +0 -2660
  328. package/dist/shared/index-BNfu2YgX.mjs +0 -47
  329. package/dist/shared/index-BUSdZ-x8.cjs +0 -1
  330. package/dist/shared/index-BZDbBD41.cjs +0 -1
  331. package/dist/shared/index-Bc1ny9GC.cjs +0 -1
  332. package/dist/shared/index-BcscC86C.mjs +0 -206
  333. package/dist/shared/index-BiowqiSD.cjs +0 -1
  334. package/dist/shared/index-Bpl6Jh4H.cjs +0 -1
  335. package/dist/shared/index-BqojE7aF.cjs +0 -1
  336. package/dist/shared/index-BrZzYI8x.cjs +0 -1
  337. package/dist/shared/index-BsXys36-.cjs +0 -1
  338. package/dist/shared/index-BvmXE8aK.cjs +0 -1
  339. package/dist/shared/index-Bw3nETeY.cjs +0 -1
  340. package/dist/shared/index-BxxuaQGJ.cjs +0 -1
  341. package/dist/shared/index-BxymsnW0.cjs +0 -1
  342. package/dist/shared/index-BzpgGytE.mjs +0 -52
  343. package/dist/shared/index-BzzZmppN.mjs +0 -63
  344. package/dist/shared/index-C0rOcDsc.cjs +0 -1
  345. package/dist/shared/index-C1hAuubZ.mjs +0 -157
  346. package/dist/shared/index-C2BQtQPa.mjs +0 -61
  347. package/dist/shared/index-C62Loq0f.cjs +0 -1
  348. package/dist/shared/index-C7N8x3DK.mjs +0 -206
  349. package/dist/shared/index-C8aLbb8l.cjs +0 -1
  350. package/dist/shared/index-CA279UZp.mjs +0 -87
  351. package/dist/shared/index-CDjAMIpe.cjs +0 -1
  352. package/dist/shared/index-CDleTMJj.mjs +0 -395
  353. package/dist/shared/index-CG4I3nRK.cjs +0 -1
  354. package/dist/shared/index-CHt1R1WD.cjs +0 -1
  355. package/dist/shared/index-CZIsLBLq.cjs +0 -1
  356. package/dist/shared/index-CcEXTVYA.mjs +0 -69
  357. package/dist/shared/index-CedTjtZr.cjs +0 -1
  358. package/dist/shared/index-CgXuleV-.mjs +0 -205
  359. package/dist/shared/index-CkfWS0Ba.cjs +0 -1
  360. package/dist/shared/index-Cm7k9j8a.cjs +0 -1
  361. package/dist/shared/index-CmgT_pgc.mjs +0 -154
  362. package/dist/shared/index-CngdcQWi.cjs +0 -1
  363. package/dist/shared/index-CqdhLbMe.cjs +0 -1
  364. package/dist/shared/index-CsI1WBRp.cjs +0 -1
  365. package/dist/shared/index-CsXA7Qfy.mjs +0 -105
  366. package/dist/shared/index-CsaDF9d4.mjs +0 -175
  367. package/dist/shared/index-CvdUJpAu.mjs +0 -365
  368. package/dist/shared/index-CvfLEIFE.mjs +0 -526
  369. package/dist/shared/index-CwcD7q4B.mjs +0 -446
  370. package/dist/shared/index-D0kCG3Ov.mjs +0 -278
  371. package/dist/shared/index-D1-QYDXi.cjs +0 -1
  372. package/dist/shared/index-D1BK66mG.cjs +0 -1
  373. package/dist/shared/index-D3IHte_d.cjs +0 -1
  374. package/dist/shared/index-D3VO2Ccd.mjs +0 -73
  375. package/dist/shared/index-D5spJ8nj.cjs +0 -1
  376. package/dist/shared/index-D7uPizqd.cjs +0 -1
  377. package/dist/shared/index-D8OJx-hy.mjs +0 -104
  378. package/dist/shared/index-DAiFZxwY.mjs +0 -51
  379. package/dist/shared/index-DBz3lz62.mjs +0 -53
  380. package/dist/shared/index-DCKEecrx.mjs +0 -138
  381. package/dist/shared/index-DCneRuMf.mjs +0 -78
  382. package/dist/shared/index-DD-zKgrO.cjs +0 -1
  383. package/dist/shared/index-DEHvfBYQ.mjs +0 -295
  384. package/dist/shared/index-DF_Q6c4g.mjs +0 -27
  385. package/dist/shared/index-DFeV2CL8.cjs +0 -1
  386. package/dist/shared/index-DIckpqrH.cjs +0 -1
  387. package/dist/shared/index-DKKMSKqm.cjs +0 -1
  388. package/dist/shared/index-DPhYSn9g.mjs +0 -130
  389. package/dist/shared/index-DSq7WIiO.cjs +0 -1
  390. package/dist/shared/index-DTHRZ-aL.mjs +0 -74
  391. package/dist/shared/index-DTqCwGN_.cjs +0 -1
  392. package/dist/shared/index-DVwCIrin.mjs +0 -100
  393. package/dist/shared/index-DbxSDJ7e.mjs +0 -81
  394. package/dist/shared/index-Dc4A_1-H.mjs +0 -53
  395. package/dist/shared/index-Dchy1DNn.mjs +0 -197
  396. package/dist/shared/index-DdKCUobQ.mjs +0 -311
  397. package/dist/shared/index-DdX40CzJ.cjs +0 -1
  398. package/dist/shared/index-DfP6txWq.mjs +0 -198
  399. package/dist/shared/index-Dh_dh3TS.cjs +0 -1
  400. package/dist/shared/index-DjRDV62n.mjs +0 -153
  401. package/dist/shared/index-DpGlBnUl.cjs +0 -1
  402. package/dist/shared/index-DsDUAk2R.cjs +0 -1
  403. package/dist/shared/index-DxUzSONj.cjs +0 -1
  404. package/dist/shared/index-DypZJHmM.cjs +0 -1
  405. package/dist/shared/index-DzCwEfCQ.cjs +0 -1
  406. package/dist/shared/index-Gyu5R4Gn.cjs +0 -1
  407. package/dist/shared/index-IJJI2ylC.mjs +0 -234
  408. package/dist/shared/index-OaA2R7Ur.mjs +0 -369
  409. package/dist/shared/index-S2TDFo5d.cjs +0 -1
  410. package/dist/shared/index-U3c1apvC.cjs +0 -1
  411. package/dist/shared/index-VExJFRrd.mjs +0 -156
  412. package/dist/shared/index-Xw2_Py_V.mjs +0 -63
  413. package/dist/shared/index-ZbSETCxZ.cjs +0 -1
  414. package/dist/shared/index-ZkHMbIv4.cjs +0 -1
  415. package/dist/shared/index-aveXATNw.cjs +0 -1
  416. package/dist/shared/index-byOl9Vtk.cjs +0 -1
  417. package/dist/shared/index-fiuhurmv.cjs +0 -1
  418. package/dist/shared/index-pqwrEshN.cjs +0 -1
  419. package/dist/shared/index-rowlxa3p.mjs +0 -245
  420. package/dist/shared/index-trf8Dvbk.cjs +0 -1
  421. package/dist/shared/index-tsfRa5ze.cjs +0 -1
  422. package/dist/shared/index-uRVIiLjP.mjs +0 -892
package/README.md CHANGED
@@ -1,1605 +1,1605 @@
1
- # @qynpm/ui
2
-
3
- ## QyPagination
4
-
5
- `QyPagination` 是受控分页门面,可从 `@qynpm/ui` 或 `@qynpm/ui/qy-pagination` 导入。它公开 `total`、`page`、`pageSize`、`pageSizeOptions`、`hideOnSinglePage`、`disabled`、`loading`、可选 `binding`,以及 `page-change` / `page-size-change` 事件;请求、URL 和业务回第一页逻辑由消费者负责。
6
-
7
- 起印体系内抽离出来的 Vue 3 UI 组件包,当前主要包含基础输入组件、选择器组件、区块容器、底部操作栏,以及上传、弹窗、备注图文等通用能力。
8
-
9
- 录单拆包的 transform 实际代码盘点见 [录单拆包迁移总览](../record-order-migration.md)。其中记录了 `QyImagePreview`、凭证上传模式、设计文件管理等后续 UI 缺口。`QyRichTextEditor` 属于录单追加信息的独立业务组件,不进入当前全局 UI 基础包。
10
-
11
- ## 安装
12
-
13
- ```bash
14
- pnpm add @qynpm/ui
15
- ```
16
-
17
- Peer Dependencies:
18
-
19
- - `vue >= 3.4`
1
+ # @qynpm/ui
2
+
3
+ ## QyPagination
4
+
5
+ `QyPagination` 是受控分页门面,可从 `@qynpm/ui` 或 `@qynpm/ui/qy-pagination` 导入。它公开 `total`、`page`、`pageSize`、`pageSizeOptions`、`hideOnSinglePage`、`disabled`、`loading`、可选 `binding`,以及 `page-change` / `page-size-change` 事件;请求、URL 和业务回第一页逻辑由消费者负责。
6
+
7
+ 起印体系内抽离出来的 Vue 3 UI 组件包,当前主要包含基础输入组件、选择器组件、区块容器、底部操作栏,以及上传、弹窗、备注图文等通用能力。
8
+
9
+ 录单拆包的 transform 实际代码盘点见 [录单拆包迁移总览](../record-order-migration.md)。其中记录了 `QyImagePreview`、凭证上传模式、设计文件管理等后续 UI 缺口。`QyRichTextEditor` 属于录单追加信息的独立业务组件,不进入当前全局 UI 基础包。
10
+
11
+ ## 安装
12
+
13
+ ```bash
14
+ pnpm add @qynpm/ui
15
+ ```
16
+
17
+ Peer Dependencies:
18
+
19
+ - `vue >= 3.4`
20
20
  - `element-plus >= 2.9`
21
- - `@element-plus/icons-vue >= 2.0`
22
- - `@vueuse/core >= 10.0`
23
- - `clsx >= 2.0`
24
-
25
- ## 注册
26
-
27
- ```ts
28
- import { createApp } from 'vue'
29
- import ElementPlus from 'element-plus'
30
- import QyUI from '@qynpm/ui'
31
-
32
- const app = createApp(App)
33
-
34
- app.use(ElementPlus)
35
- app.use(QyUI)
36
- ```
37
-
38
- 也可以按需引入:
39
-
40
- ```ts
41
- import {
42
- QyUpload,
43
- QyFilePicker,
44
- QySwitch,
45
- QyTag,
46
- QyBadge,
47
- QyCascader,
48
- QyTooltip,
49
- QyPopover,
50
- QyPopconfirm,
51
- QySkeleton,
52
- QySkeletonItem,
53
- QyLoading,
54
- QyTabs,
55
- QyTabPane,
56
- QySteps,
57
- QyStep,
58
- QyIcon,
59
- QyIconPicker,
60
- QyColorPicker,
21
+ - `@element-plus/icons-vue >= 2.0`
22
+ - `@vueuse/core >= 10.0`
23
+ - `clsx >= 2.0`
24
+
25
+ ## 注册
26
+
27
+ ```ts
28
+ import { createApp } from 'vue'
29
+ import ElementPlus from 'element-plus'
30
+ import QyUI from '@qynpm/ui'
31
+
32
+ const app = createApp(App)
33
+
34
+ app.use(ElementPlus)
35
+ app.use(QyUI)
36
+ ```
37
+
38
+ 也可以按需引入:
39
+
40
+ ```ts
41
+ import {
42
+ QyUpload,
43
+ QyFilePicker,
44
+ QySwitch,
45
+ QyTag,
46
+ QyBadge,
47
+ QyCascader,
48
+ QyTooltip,
49
+ QyPopover,
50
+ QyPopconfirm,
51
+ QySkeleton,
52
+ QySkeletonItem,
53
+ QyLoading,
54
+ QyTabs,
55
+ QyTabPane,
56
+ QySteps,
57
+ QyStep,
58
+ QyIcon,
59
+ QyIconPicker,
60
+ QyColorPicker,
61
61
  QyWatermark,
62
62
  QyLink,
63
63
  QyIframe,
64
64
  QyDivider,
65
- QyEmpty,
66
- QyScrollbar,
67
- QyProgress,
68
- QyImage,
69
- QyImagePreview,
70
- QyImageUpload,
71
- QyDialog,
72
- QyButton,
73
- QyDropdown,
65
+ QyEmpty,
66
+ QyScrollbar,
67
+ QyProgress,
68
+ QyImage,
69
+ QyImagePreview,
70
+ QyImageUpload,
71
+ QyDialog,
72
+ QyButton,
73
+ QyDropdown,
74
74
  QyRemarkImage,
75
75
  QyInput,
76
76
  QyInputTag,
77
77
  QyInputNumber,
78
- QyMoneyInput,
79
- QyDatePicker,
80
- QyCheckbox,
81
- QyRadio,
82
- QyAutocomplete,
83
- QyMenuActions,
84
- QyTableColumnSettings,
85
- QyRadioGroup,
86
- QySelect,
87
- QyTreeSelect,
88
- QyRemoteSelect,
89
- QySelectionDialog,
90
- QyFormSection,
91
- QyActionBar,
92
- QySearchInput,
93
- QyRecordQuoteSearch
94
- } from '@qynpm/ui'
95
- ```
96
-
97
- 也可以按需引入单个组件入口:
98
-
99
- ```ts
78
+ QyMoneyInput,
79
+ QyDatePicker,
80
+ QyCheckbox,
81
+ QyRadio,
82
+ QyAutocomplete,
83
+ QyMenuActions,
84
+ QyTableColumnSettings,
85
+ QyRadioGroup,
86
+ QySelect,
87
+ QyTreeSelect,
88
+ QyRemoteSelect,
89
+ QySelectionDialog,
90
+ QyFormSection,
91
+ QyActionBar,
92
+ QySearchInput,
93
+ QyRecordQuoteSearch
94
+ } from '@qynpm/ui'
95
+ ```
96
+
97
+ 也可以按需引入单个组件入口:
98
+
99
+ ```ts
100
100
  import QyInput from '@qynpm/ui/qy-input'
101
101
  import QyInputTag from '@qynpm/ui/qy-input-tag'
102
102
  import QyMoneyInput from '@qynpm/ui/qy-money-input'
103
- import QyRadioGroup from '@qynpm/ui/qy-radio-group'
104
- import QySelect from '@qynpm/ui/qy-select'
105
- import QyTreeSelect from '@qynpm/ui/qy-tree-select'
106
- import QyRemoteSelect from '@qynpm/ui/qy-remote-select'
107
- import QySelectionDialog from '@qynpm/ui/qy-selection-dialog'
108
- import QyFormSection from '@qynpm/ui/qy-form-section'
109
- import QyActionBar from '@qynpm/ui/qy-action-bar'
110
- import QyButton from '@qynpm/ui/qy-button'
111
- import QyDropdown from '@qynpm/ui/qy-dropdown'
112
- import QyIconPicker from '@qynpm/ui/qy-icon-picker'
113
- import QyColorPicker from '@qynpm/ui/qy-color-picker'
114
- import QySearchInput from '@qynpm/ui/qy-search-input'
115
- import QyRecordQuoteSearch from '@qynpm/ui/qy-record-quote-search'
116
- import QyDialog from '@qynpm/ui/qy-dialog'
117
- import QyUpload from '@qynpm/ui/qy-upload'
118
- import QyFilePicker from '@qynpm/ui/qy-file-picker'
119
- import QySwitch from '@qynpm/ui/qy-switch'
120
- import QyTag from '@qynpm/ui/qy-tag'
121
- import QyBadge from '@qynpm/ui/qy-badge'
122
- import QyCascader from '@qynpm/ui/qy-cascader'
123
- import QyTree from '@qynpm/ui/qy-tree'
124
- import QyTooltip from '@qynpm/ui/qy-tooltip'
125
- import QyPopover from '@qynpm/ui/qy-popover'
126
- import QyPopconfirm from '@qynpm/ui/qy-popconfirm'
127
- import QyWatermark from '@qynpm/ui/qy-watermark'
128
- import QySkeleton from '@qynpm/ui/qy-skeleton'
129
- import QySkeletonItem from '@qynpm/ui/qy-skeleton-item'
130
- import QyLoading, { openQyLoading } from '@qynpm/ui/qy-loading'
131
- import QyTabs from '@qynpm/ui/qy-tabs'
132
- import QyTabPane from '@qynpm/ui/qy-tab-pane'
133
- import QySteps from '@qynpm/ui/qy-steps'
134
- import QyStep from '@qynpm/ui/qy-step'
103
+ import QyRadioGroup from '@qynpm/ui/qy-radio-group'
104
+ import QySelect from '@qynpm/ui/qy-select'
105
+ import QyTreeSelect from '@qynpm/ui/qy-tree-select'
106
+ import QyRemoteSelect from '@qynpm/ui/qy-remote-select'
107
+ import QySelectionDialog from '@qynpm/ui/qy-selection-dialog'
108
+ import QyFormSection from '@qynpm/ui/qy-form-section'
109
+ import QyActionBar from '@qynpm/ui/qy-action-bar'
110
+ import QyButton from '@qynpm/ui/qy-button'
111
+ import QyDropdown from '@qynpm/ui/qy-dropdown'
112
+ import QyIconPicker from '@qynpm/ui/qy-icon-picker'
113
+ import QyColorPicker from '@qynpm/ui/qy-color-picker'
114
+ import QySearchInput from '@qynpm/ui/qy-search-input'
115
+ import QyRecordQuoteSearch from '@qynpm/ui/qy-record-quote-search'
116
+ import QyDialog from '@qynpm/ui/qy-dialog'
117
+ import QyUpload from '@qynpm/ui/qy-upload'
118
+ import QyFilePicker from '@qynpm/ui/qy-file-picker'
119
+ import QySwitch from '@qynpm/ui/qy-switch'
120
+ import QyTag from '@qynpm/ui/qy-tag'
121
+ import QyBadge from '@qynpm/ui/qy-badge'
122
+ import QyCascader from '@qynpm/ui/qy-cascader'
123
+ import QyTree from '@qynpm/ui/qy-tree'
124
+ import QyTooltip from '@qynpm/ui/qy-tooltip'
125
+ import QyPopover from '@qynpm/ui/qy-popover'
126
+ import QyPopconfirm from '@qynpm/ui/qy-popconfirm'
127
+ import QyWatermark from '@qynpm/ui/qy-watermark'
128
+ import QySkeleton from '@qynpm/ui/qy-skeleton'
129
+ import QySkeletonItem from '@qynpm/ui/qy-skeleton-item'
130
+ import QyLoading, { openQyLoading } from '@qynpm/ui/qy-loading'
131
+ import QyTabs from '@qynpm/ui/qy-tabs'
132
+ import QyTabPane from '@qynpm/ui/qy-tab-pane'
133
+ import QySteps from '@qynpm/ui/qy-steps'
134
+ import QyStep from '@qynpm/ui/qy-step'
135
135
  import QyLink from '@qynpm/ui/qy-link'
136
136
  import QyIframe from '@qynpm/ui/qy-iframe'
137
137
  import QyEmpty from '@qynpm/ui/qy-empty'
138
- import QyScrollbar from '@qynpm/ui/qy-scrollbar'
139
- import QyProgress from '@qynpm/ui/qy-progress'
140
- import QyImage from '@qynpm/ui/qy-image'
141
- import QyImagePreview from '@qynpm/ui/qy-image-preview'
142
- import QyImageUpload from '@qynpm/ui/qy-image-upload'
143
- import QyRemarkImage from '@qynpm/ui/qy-remark-image'
144
- import QyInputNumber from '@qynpm/ui/qy-input-number'
145
- import QyDatePicker from '@qynpm/ui/qy-date-picker'
146
- import QyCheckbox from '@qynpm/ui/qy-checkbox'
147
- import QyRadio from '@qynpm/ui/qy-radio'
148
- import QyAutocomplete from '@qynpm/ui/qy-autocomplete'
149
- import QyMenuActions from '@qynpm/ui/qy-menu-actions'
150
- import QyTableColumnSettings from '@qynpm/ui/qy-table-column-settings'
151
- ```
152
-
153
- 后台公共包必须通过 `@qynpm/ui/<子组件>` 使用 UI 能力。每个被后台公共包消费的子入口必须是自包含入口,直接组装对应组件并保留该子入口的命名导出,禁止再转发到 `../index.js` 加载 UI 根入口。这样可以保证发布包按需加载,也能让本地源码联调稳定解析到唯一物理模块。
154
-
155
- 本地 file 依赖联调说明:单组件入口的 `package.json exports` 指向 `dist/qy-*/index.mjs` 和 `dist/qy-*/index.cjs`,而 `dist` 不提交到仓库。消费项目如果通过 `file:../qy-components/packages/ui` 引用本包,必须先在 `qy-components` 执行:
156
-
157
- ```bash
158
- pnpm --filter @qynpm/ui build
159
- ```
160
-
161
- 然后在消费项目刷新 file 依赖安装视图,例如:
162
-
163
- ```bash
164
- pnpm install --frozen-lockfile --ignore-scripts
165
- ```
166
-
167
- 不要依赖本机残留的 `packages/ui/dist`。如果后续希望免 build 联调,应在消费项目显式配置源码 alias,而不是把包 export 指向未发布源码。
168
-
169
- ## 组件说明
170
-
171
- ### `QyEmpty`
172
-
173
- `QyEmpty` 使用 Element Plus `ElEmpty` 渲染只读空状态,支持 `image`、`imageSize` 和 `description` 属性,以及 `image`、`description`、默认三个原生插槽。组件不判断数据,不内置加载、错误、重试或按钮点击逻辑。
174
-
175
- ```vue
176
- <QyEmpty description="暂无记录">
177
- <template #image><img src="/empty.svg" alt="暂无记录" /></template>
178
- <template #default>
179
- <QyButton @click="createRecord">新建记录</QyButton>
180
- </template>
181
- </QyEmpty>
182
- ```
183
-
184
- `imageSize` 直接沿用 Element Plus 的数值语义;`image` / `description` 插槽遵循 Element Plus 的属性优先级。`class`、`style`、`id`、`title`、`role`、`data-*` 和 `aria-*` 安全透传到根节点,消费者传入的宽度、高度、margin、padding 均可覆盖,事件监听器和底层实例不对外暴露。
185
-
186
- ### `QyScrollbar`
187
-
188
- `QyScrollbar` 以 Element Plus 2.14.3 的 `ElScrollbar` 作为唯一滚动实现。默认插槽直接承载滚动内容,支持固定高度、最大高度、纵向/横向滚动、原生/自定义滚动模式、`always`、滚动层样式与类名,以及 `tabindex`、`id`、`role`、`ariaLabel` 和 `ariaOrientation`。
189
-
190
- ```vue
191
- <QyScrollbar height="240px" max-height="360px" always aria-label="消息列表">
192
- <div v-for="message in messages" :key="message.id">{{ message.text }}</div>
193
- </QyScrollbar>
194
-
195
- <QyScrollbar
196
- height="160px"
197
- :distance="12"
198
- @scroll="handleScroll"
199
- @end-reached="loadMore"
200
- >
201
- <div class="wide-content">横向内容由局部容器滚动</div>
202
- </QyScrollbar>
203
- ```
204
-
205
- `scroll` 只返回只读快照 `{ scrollTop, scrollLeft }`;`end-reached` 返回 `top`、`bottom`、`left` 或 `right`,阈值由 Element Plus 的 `distance` 处理。实例只公开 `scrollTo(x, y)`、`scrollTo(options)`、`setScrollTop(value)`、`setScrollLeft(value)` 和 `update()`,挂载前或卸载后调用均为空操作。不显式暴露内部 `ElScrollbar` 实例、`wrapRef`、`handleScroll` 或 DOM ref;Vue 公共实例自带的 `$el` 不属于适配器承诺的稳定 API,消费者不得依赖。
206
-
207
- 根节点仅安全透传 `class`、`style`、`title`、`data-*` 和不冲突的 `aria-*`;旧的 `width`、`vertical` 属性及未知 `on*` 监听器会被过滤。自定义模式只映射 `--el-scrollbar-bg-color` / `--el-scrollbar-hover-bg-color` 到 admin-theme 的 `--qy-scrollbar-thumb` / `--qy-scrollbar-thumb-hover`,不覆盖 Element Plus 滑块尺寸、定位、圆角、显隐或动画;原生模式继续使用 admin-theme 的全局原生滚动条规则。
208
-
209
- ### `QyCascader`
210
-
211
- `QyCascader` 是 Element Plus Cascader 的受控适配器,保留单值、路径值和多选值的原始形状,不自动改写业务 options。支持 `expandTrigger`、`multiple`、`checkStrictly`、`emitPath`、`lazyLoad`、过滤、折叠标签、浮层定位、虚拟滚动及键盘操作。
212
-
213
- 节点默认插槽、`suggestion-item`、过滤、懒加载以及 `disabled` / `leaf` 回调接收只读的 `QyCascaderNodeSnapshot`,不会泄漏 Element Plus Node 或组件实例。组件仅暴露 `focus()`、`blur()`、`open()`、`close()` 四个方法。
214
-
215
- ```vue
216
- <QyCascader
217
- v-model="value"
218
- :options="options"
219
- :props="{ emitPath: true, checkStrictly: true }"
220
- filterable
221
- placeholder="选择地区"
222
- />
223
- ```
224
-
225
- 完整交互 playground 覆盖基础/路径、严格检查、多选折叠、过滤、懒加载、禁用、插槽、键盘、浮层和移动端 40px 触控目标。
226
-
227
- ### `QyTree`
228
-
229
- `QyTree` 以 Element Plus `ElTree` 作为唯一的树结构、勾选/半选、键盘、懒加载和拖拽实现。`data` 始终是业务唯一数据权威;节点回调、事件、默认插槽和 `QyTreeRef.getNode()` 都返回当前只读 Qy 快照,不泄漏 Element Node、Store、组件实例或私有 DOM。
230
-
231
- ```vue
232
- <QyTree
233
- ref="treeRef"
234
- :data="departments"
235
- node-key="id"
236
- show-checkbox
237
- default-expand-all
238
- :filter-node-method="(value, data, node) => node.label.includes(value)"
239
- @check="(_, info) => console.log(info.checkedKeys, info.halfCheckedKeys)"
240
- />
241
- ```
242
-
243
- 支持字段映射、展开/当前节点、联动和严格勾选、筛选、懒加载、拖拽、自定义节点插槽及本地键盘导航。公开引用仅包含筛选、当前节点、节点路径、勾选/半选读取与设置方法;不提供 `append`、`remove`、`insert` 或 `updateKeyChildren` 等内部数据修改方法。键值方法需要 `nodeKey`;未提供筛选函数时调用 `filter()` 会抛出 QyTree 自有错误。
244
-
138
+ import QyScrollbar from '@qynpm/ui/qy-scrollbar'
139
+ import QyProgress from '@qynpm/ui/qy-progress'
140
+ import QyImage from '@qynpm/ui/qy-image'
141
+ import QyImagePreview from '@qynpm/ui/qy-image-preview'
142
+ import QyImageUpload from '@qynpm/ui/qy-image-upload'
143
+ import QyRemarkImage from '@qynpm/ui/qy-remark-image'
144
+ import QyInputNumber from '@qynpm/ui/qy-input-number'
145
+ import QyDatePicker from '@qynpm/ui/qy-date-picker'
146
+ import QyCheckbox from '@qynpm/ui/qy-checkbox'
147
+ import QyRadio from '@qynpm/ui/qy-radio'
148
+ import QyAutocomplete from '@qynpm/ui/qy-autocomplete'
149
+ import QyMenuActions from '@qynpm/ui/qy-menu-actions'
150
+ import QyTableColumnSettings from '@qynpm/ui/qy-table-column-settings'
151
+ ```
152
+
153
+ 后台公共包必须通过 `@qynpm/ui/<子组件>` 使用 UI 能力。每个被后台公共包消费的子入口必须是自包含入口,直接组装对应组件并保留该子入口的命名导出,禁止再转发到 `../index.js` 加载 UI 根入口。这样可以保证发布包按需加载,也能让本地源码联调稳定解析到唯一物理模块。
154
+
155
+ 本地 file 依赖联调说明:单组件入口的 `package.json exports` 指向 `dist/qy-*/index.mjs` 和 `dist/qy-*/index.cjs`,而 `dist` 不提交到仓库。消费项目如果通过 `file:../qy-components/packages/ui` 引用本包,必须先在 `qy-components` 执行:
156
+
157
+ ```bash
158
+ pnpm --filter @qynpm/ui build
159
+ ```
160
+
161
+ 然后在消费项目刷新 file 依赖安装视图,例如:
162
+
163
+ ```bash
164
+ pnpm install --frozen-lockfile --ignore-scripts
165
+ ```
166
+
167
+ 不要依赖本机残留的 `packages/ui/dist`。如果后续希望免 build 联调,应在消费项目显式配置源码 alias,而不是把包 export 指向未发布源码。
168
+
169
+ ## 组件说明
170
+
171
+ ### `QyEmpty`
172
+
173
+ `QyEmpty` 使用 Element Plus `ElEmpty` 渲染只读空状态,支持 `image`、`imageSize` 和 `description` 属性,以及 `image`、`description`、默认三个原生插槽。组件不判断数据,不内置加载、错误、重试或按钮点击逻辑。
174
+
175
+ ```vue
176
+ <QyEmpty description="暂无记录">
177
+ <template #image><img src="/empty.svg" alt="暂无记录" /></template>
178
+ <template #default>
179
+ <QyButton @click="createRecord">新建记录</QyButton>
180
+ </template>
181
+ </QyEmpty>
182
+ ```
183
+
184
+ `imageSize` 直接沿用 Element Plus 的数值语义;`image` / `description` 插槽遵循 Element Plus 的属性优先级。`class`、`style`、`id`、`title`、`role`、`data-*` 和 `aria-*` 安全透传到根节点,消费者传入的宽度、高度、margin、padding 均可覆盖,事件监听器和底层实例不对外暴露。
185
+
186
+ ### `QyScrollbar`
187
+
188
+ `QyScrollbar` 以 Element Plus 2.14.3 的 `ElScrollbar` 作为唯一滚动实现。默认插槽直接承载滚动内容,支持固定高度、最大高度、纵向/横向滚动、原生/自定义滚动模式、`always`、滚动层样式与类名,以及 `tabindex`、`id`、`role`、`ariaLabel` 和 `ariaOrientation`。
189
+
190
+ ```vue
191
+ <QyScrollbar height="240px" max-height="360px" always aria-label="消息列表">
192
+ <div v-for="message in messages" :key="message.id">{{ message.text }}</div>
193
+ </QyScrollbar>
194
+
195
+ <QyScrollbar
196
+ height="160px"
197
+ :distance="12"
198
+ @scroll="handleScroll"
199
+ @end-reached="loadMore"
200
+ >
201
+ <div class="wide-content">横向内容由局部容器滚动</div>
202
+ </QyScrollbar>
203
+ ```
204
+
205
+ `scroll` 只返回只读快照 `{ scrollTop, scrollLeft }`;`end-reached` 返回 `top`、`bottom`、`left` 或 `right`,阈值由 Element Plus 的 `distance` 处理。实例只公开 `scrollTo(x, y)`、`scrollTo(options)`、`setScrollTop(value)`、`setScrollLeft(value)` 和 `update()`,挂载前或卸载后调用均为空操作。不显式暴露内部 `ElScrollbar` 实例、`wrapRef`、`handleScroll` 或 DOM ref;Vue 公共实例自带的 `$el` 不属于适配器承诺的稳定 API,消费者不得依赖。
206
+
207
+ 根节点仅安全透传 `class`、`style`、`title`、`data-*` 和不冲突的 `aria-*`;旧的 `width`、`vertical` 属性及未知 `on*` 监听器会被过滤。自定义模式只映射 `--el-scrollbar-bg-color` / `--el-scrollbar-hover-bg-color` 到 admin-theme 的 `--qy-scrollbar-thumb` / `--qy-scrollbar-thumb-hover`,不覆盖 Element Plus 滑块尺寸、定位、圆角、显隐或动画;原生模式继续使用 admin-theme 的全局原生滚动条规则。
208
+
209
+ ### `QyCascader`
210
+
211
+ `QyCascader` 是 Element Plus Cascader 的受控适配器,保留单值、路径值和多选值的原始形状,不自动改写业务 options。支持 `expandTrigger`、`multiple`、`checkStrictly`、`emitPath`、`lazyLoad`、过滤、折叠标签、浮层定位、虚拟滚动及键盘操作。
212
+
213
+ 节点默认插槽、`suggestion-item`、过滤、懒加载以及 `disabled` / `leaf` 回调接收只读的 `QyCascaderNodeSnapshot`,不会泄漏 Element Plus Node 或组件实例。组件仅暴露 `focus()`、`blur()`、`open()`、`close()` 四个方法。
214
+
215
+ ```vue
216
+ <QyCascader
217
+ v-model="value"
218
+ :options="options"
219
+ :props="{ emitPath: true, checkStrictly: true }"
220
+ filterable
221
+ placeholder="选择地区"
222
+ />
223
+ ```
224
+
225
+ 完整交互 playground 覆盖基础/路径、严格检查、多选折叠、过滤、懒加载、禁用、插槽、键盘、浮层和移动端 40px 触控目标。
226
+
227
+ ### `QyTree`
228
+
229
+ `QyTree` 以 Element Plus `ElTree` 作为唯一的树结构、勾选/半选、键盘、懒加载和拖拽实现。`data` 始终是业务唯一数据权威;节点回调、事件、默认插槽和 `QyTreeRef.getNode()` 都返回当前只读 Qy 快照,不泄漏 Element Node、Store、组件实例或私有 DOM。
230
+
231
+ ```vue
232
+ <QyTree
233
+ ref="treeRef"
234
+ :data="departments"
235
+ node-key="id"
236
+ show-checkbox
237
+ default-expand-all
238
+ :filter-node-method="(value, data, node) => node.label.includes(value)"
239
+ @check="(_, info) => console.log(info.checkedKeys, info.halfCheckedKeys)"
240
+ />
241
+ ```
242
+
243
+ 支持字段映射、展开/当前节点、联动和严格勾选、筛选、懒加载、拖拽、自定义节点插槽及本地键盘导航。公开引用仅包含筛选、当前节点、节点路径、勾选/半选读取与设置方法;不提供 `append`、`remove`、`insert` 或 `updateKeyChildren` 等内部数据修改方法。键值方法需要 `nodeKey`;未提供筛选函数时调用 `filter()` 会抛出 QyTree 自有错误。
244
+
245
245
  ### `QyFilePicker`
246
246
 
247
- > Deprecated:新代码请使用 `QyUpload variant="file-list" :auto-upload="false"`。当前入口仅用于兼容,后续 major 版本移除。
247
+ > Deprecated:新代码请使用 `QyUpload variant="file-list" :auto-upload="false"`。当前入口仅用于兼容,后续 major 版本移除。
248
+
249
+ 单文件选择兼容组件,支持点击选择、拖拽、替换、清空以及后缀和大小校验;内部复用 `QyUpload` 的本地选择模式。
250
+
251
+ - `v-model` 只输出浏览器原始 `File | null`。
252
+ - `extensions` 忽略大小写,可传 `xls` 或 `.xlsx`。
253
+ - `maxSizeMb` 的边界值允许,默认 20MB。
254
+ - 校验失败触发 `invalid`,并保留原有 `modelValue`。
255
+ - 组件只选择本地文件,不发送请求、不读取 token、不生成或保存 URL,也不复用 `QyUpload` 的业务上传协议。
256
+
257
+ ```vue
258
+ <QyFilePicker
259
+ v-model="file"
260
+ :extensions="['xls', 'xlsx']"
261
+ :max-size-mb="20"
262
+ placeholder="选择或拖拽 Excel 文件"
263
+ @invalid="handleInvalid"
264
+ />
265
+ ```
266
+
267
+ ### `QySwitch`
268
+
269
+ 受控开关组件,`modelValue`、`activeValue`、`inactiveValue` 和 `update:modelValue` / `change` payload 均为 `boolean | string | number`,不进行隐式布尔化。
270
+
271
+ ```vue
272
+ <QySwitch
273
+ v-model="enabled"
274
+ active-text="启用"
275
+ inactive-text="停用"
276
+ @change="handleChange"
277
+ />
278
+ ```
279
+
280
+ 支持 `disabled`、`loading`、`size`、`inlinePrompt`、`name`、`id`、`tabindex` 和 `ariaLabel`,以及 `class`、`style`、`role`、`title`、`data-*`、其它 `aria-*` 安全属性。只发出 `update:modelValue`、`change`、`focus`、`blur`;不提供 `beforeChange`、`input`、图标/slot 或底层实例、focus/blur 等命令式方法。
281
+
282
+ ### `QyTag`
283
+
284
+ 通用紧凑标签,内部使用 `ElTag`,公开 `tone`、`size`、`effect`、`closable`、`round`、`disabled` 和默认 slot。`tone` 支持 `neutral`、`primary`、`success`、`warning`、`danger`、`info`;`size` 为 `sm`、`md`、`lg`,默认分别映射为 Element Plus 的 `small`、`default`、`large`。
285
+
286
+ ```vue
287
+ <QyTag tone="success" size="sm" closable @close="removeTag">
288
+ 已完成
289
+ </QyTag>
290
+ ```
291
+
292
+ `disabled` 会设置 `aria-disabled="true"`、隐藏关闭按钮并抑制 `click` / `close`;非禁用状态下这两个事件各发出一次 `MouseEvent`。支持 `class`、`style`、`title`、`role`、`data-*`、`aria-*` 安全属性,不公开 `color`、`hit`、`disableTransitions` 或底层 Element Plus 实例。QyTag 不是按钮,不新增键盘按钮语义;需要动作语义时使用 `QyButton`。
293
+
294
+ ### `QyBadge`
295
+
296
+ `QyBadge` 基于 Element Plus `ElBadge` 渲染只读徽标,不管理未读状态、通知或点击逻辑。支持数字与文字、数字上限、圆点、隐藏、零值策略、五种语义类型、自定义颜色、偏移以及徽标内部样式和类名。
297
+
298
+ ```vue
299
+ <QyBadge :value="unreadCount" :max="99" type="danger">
300
+ <QyButton>消息</QyButton>
301
+ </QyBadge>
302
+
303
+ <QyBadge value="!" is-dot>
304
+ <span>待处理</span>
305
+ <template #content="{ value }">数量:{{ value }}</template>
306
+ </QyBadge>
307
+ ```
308
+
309
+ `value` 默认为空字符串,`max` 默认为 `99`,`type` 默认为 `danger`,`showZero` 默认为 `true`,`offset` 默认为 `[0, 0]`。上限只作用于数字,字符串原样显示;`content` 插槽收到经过圆点和上限规则处理后的只读 `{ value: string }`,组件公开的 `content` 也只有最终显示内容,不暴露 Element Plus 实例。根节点安全透传 `class`、`style`、`id`、`role`、`title`、`data-*` 和 `aria-*`,不声明事件、`v-model` 或尺寸参数。
310
+
311
+ ### `QyTooltip`
312
+
313
+ 只读提示组件。默认插槽是唯一触发内容,不增加触发元素包装 DOM;`content` 插槽(content slot)优先于 `content` 属性。组件支持 hover / focus、完整 `placement`、`light` / `dark` effect、延迟、偏移和可收缩的 `maxWidth`。
314
+
315
+ ```vue
316
+ <QyTooltip content="说明文字" placement="top-start">
317
+ <button type="button">查看提示</button>
318
+ </QyTooltip>
319
+
320
+ <QyTooltip content="属性内容">
321
+ <button type="button">插槽内容</button>
322
+ <template #content>只读插槽内容</template>
323
+ </QyTooltip>
324
+ ```
325
+
326
+ 默认值为 `placement="top"`、`effect="dark"`、`disabled=false`、`showDelay=0`、`hideDelay=200`、`offset=12`、`maxWidth=320`。事件只有 `open` / `close`,且只在实际可见状态转换时各发一次;不公开 `trigger`、受控 `open`、raw HTML、交互内容、Element Plus attrs/listeners 或实例方法。
327
+
328
+ ### `QyPopover`
329
+
330
+ 交互浮层组件。`reference` 插槽是触发元素,默认插槽是可交互面板内容,不增加触发元素包装 DOM;支持 `click`、`hover`、`focus`、`contextmenu`、完整 `placement`、`light` / `dark` effect、数字或 CSS 字符串 `width`、延迟、偏移、箭头和窄视口收缩。
331
+
332
+ ```vue
333
+ <QyPopover placement="bottom-start" :width="280" @open-change="onOpenChange">
334
+ <template #reference><button type="button">打开操作</button></template>
335
+ <button type="button" @click="submit">确认</button>
336
+ </QyPopover>
337
+
338
+ <QyPopover v-model:open="open" trigger="contextmenu">
339
+ <template #reference><div>右键区域</div></template>
340
+ <div>受控交互内容</div>
341
+ </QyPopover>
342
+ ```
343
+
344
+ 默认值为 `trigger="click"`、`placement="bottom"`、`effect="light"`、`width=240`、`offset=12`、`showDelay=0`、`hideDelay=200`、`showArrow=true`、`disabled=false`。`open` 未传时组件内部管理状态,传入时通过 `v-model:open` 由父级回传决定状态;`update:open` 是状态意图,`open-change` / `open` / `close` 只在实际显隐转换时发出。唯一暴露的方法是 `close()`,不公开 Element Plus 实例、定位更新、`teleported`、`appendTo` 或 `popperOptions`。
345
+
346
+ ### `QyPopconfirm`
347
+
348
+ 二次确认浮层,提供 Qy-owned 的确认、取消、加载锁、关闭原因和焦点恢复语义。支持 `reference`、`title`、`icon` 插槽;`open` 可选受控,确认成功后的父级关闭会以 `close('external')` 记录,异步失败保持打开并允许重试。
349
+
350
+ ```vue
351
+ <QyPopconfirm
352
+ title="确认删除?"
353
+ variant="danger"
354
+ confirm-type="danger"
355
+ :confirm-loading="saving"
356
+ :close-on-confirm="false"
357
+ @confirm="save"
358
+ @close="onClose"
359
+ >
360
+ <template #reference><button type="button">删除</button></template>
361
+ </QyPopconfirm>
362
+ ```
363
+
364
+ 事件为 `update:open`、`open-change`、`confirm`、`cancel` 和 `close(reason)`;关闭原因是 `confirm`、`cancel`、`outside`、`escape`、`trigger`、`external` 或 `disabled`。不公开 Element Plus 类型、实例、teleport 或 popper 参数。
365
+
366
+ ### `QySkeleton` 与 `QySkeletonItem`
367
+
368
+ 加载骨架组件基于 Element Plus 的 `ElSkeleton` / `ElSkeletonItem` 渲染。`loading` 由业务受控,加载期间使用 `template` 插槽,加载完成后使用默认插槽;支持 `animated`、`count`、`rows` 及数字或对象形式的 `throttle`。
369
+
370
+ ```vue
371
+ <QySkeleton :loading="loading" animated :count="2">
372
+ <template #template>
373
+ <QySkeletonItem variant="rect" style="height: 120px" />
374
+ </template>
375
+ <div>真实内容</div>
376
+ </QySkeleton>
377
+ ```
378
+
379
+ `QySkeletonItem` 的 `variant` 支持 `p`、`text`、`h1`、`h3`、`caption`、`button`、`image`、`circle`、`rect`,默认值为 `text`。两者均支持 `class`、`style`、`role`、`title`、`data-*` 和 `aria-*`,不公开 Element Plus 实例。
380
+
381
+ ### `QyLoading`
382
+
383
+ `QyLoading` 安装后注册 `v-qy-loading` 指令,并配置命令式 `openQyLoading` 服务。指令支持布尔值或 `{ active, text, maskColor, lockScroll }` 对象;服务未传 `target` 时覆盖 body,传入 HTMLElement 时只覆盖该容器。同一目标的多个句柄共享一个遮罩,最后一个句柄调用 `close()` 后才移除。
384
+
385
+ ```vue
386
+ <script setup>
387
+ import { ref } from 'vue'
388
+ import { openQyLoading } from '@qynpm/ui/qy-loading'
389
+
390
+ const loading = ref(false)
391
+ const target = ref(null)
392
+
393
+ function load() {
394
+ const handle = openQyLoading({ target: target.value, text: '加载中' })
395
+ // 请求完成后调用一次即可,重复 close 不会影响后续 loading。
396
+ handle.close()
397
+ }
398
+ </script>
399
+
400
+ <template>
401
+ <div ref="target" v-qy-loading="{ active: loading, lockScroll: true }">
402
+ 容器内容
403
+ </div>
404
+ </template>
405
+ ```
406
+
407
+ ### `QyDrawer`
408
+
409
+ `QyDrawer` 使用 Qy-owned props、事件和插槽封装抽屉容器,支持四方向、数字尺寸、遮罩/Escape 关闭原因、指定 `teleportTo` 容器、焦点恢复和重叠抽屉顶层响应。`header`、默认内容和 `footer` 插槽均接收 Qy-owned `close()`。
410
+
411
+ ```vue
412
+ <script setup>
413
+ import { ref } from 'vue'
414
+ import QyDrawer from '@qynpm/ui/qy-drawer'
415
+
416
+ const open = ref(false)
417
+ </script>
418
+
419
+ <template>
420
+ <button type="button" @click="open = true">查看订单</button>
421
+ <QyDrawer v-model="open" title="订单详情" placement="right" @close="open = false">
422
+ <p>抽屉内容</p>
423
+ <template #footer="{ close }">
424
+ <button type="button" @click="close">关闭</button>
425
+ </template>
426
+ </QyDrawer>
427
+ </template>
428
+ ```
429
+
430
+ ### `QyResult`
431
+
432
+ `QyResult` 统一展示成功、警告、信息、错误和 401/403/404/500 结果。它只负责结果视觉、标题、说明、图片和操作区,不负责路由、返回、刷新、重试、请求或状态管理;业务动作由消费者放入 `actions` 插槽。
433
+
434
+ ```vue
435
+ <script setup>
436
+ import QyResult from '@qynpm/ui/qy-result'
437
+ </script>
438
+
439
+ <template>
440
+ <QyResult status="404" title="页面不存在" description="请检查地址">
441
+ <template #actions>
442
+ <button type="button" @click="goHome">返回首页</button>
443
+ </template>
444
+ </QyResult>
445
+ </template>
446
+ ```
447
+
448
+ `visual` 插槽优先于 `image`,`image` 优先于状态内置视觉;`title` 同时作为结果标题和根节点原生 `title`,`description` 与 `actions` 也支持同名插槽覆盖属性内容。根入口与 `@qynpm/ui/qy-result` 均提供 Qy-owned 类型,不公开 Element Plus 类型、实例或事件。
449
+
450
+ ### `QyWatermark`
451
+
452
+ `QyWatermark` 在容器内提供 Qy-owned 的平铺文字或图片水印,图片优先且加载失败回退到 `content`;`content` 支持多行文字,`font`、`rotate`、`width`、`height`、`gap` 和 `offset` 控制水印单元。水印覆盖层不接收指针事件,默认插槽中的按钮、图片和选择操作仍由消费者处理。
453
+
454
+ ```vue
455
+ <script setup>
456
+ import QyWatermark from '@qynpm/ui/qy-watermark'
457
+ </script>
458
+
459
+ <template>
460
+ <QyWatermark :content="['客户名称', '订单编号']" :rotate="-18">
461
+ <div>订单内容</div>
462
+ </QyWatermark>
463
+ </template>
464
+ ```
465
+
466
+ 公开 interface 只包含 `content`、`image`、`zIndex`、`rotate`、`width`、`height`、`gap`、`offset` 和 Qy-owned `font`,以及安全容器属性 `class`、`style`、`id`、`title`、`role`、`data-*`、`aria-*`;不公开 Element Plus props、实例、DOM、事件或 expose。完整演示位于 `src/docs/QyWatermarkDoc.vue`,入口为 `@qynpm/ui/qy-watermark`。
467
+
468
+ ### `QyTabs` 与 `QyTabPane`
469
+
470
+ `QyTabs` 使用 Element Plus 的 `ElTabs` / `ElTabPane` 处理渲染、焦点与键盘行为。`modelValue` 传入时保持受控;`defaultValue` 仅提供初始选择。`tab-change`、`tab-remove`、`tab-add` 与 `edit` 都是意图事件,不会改写业务页签数组、路由或 AdminShell 运行时。
471
+
472
+ ```vue
473
+ <QyTabs v-model="current" editable @tab-add="addTab" @tab-remove="removeTab">
474
+ <QyTabPane label="概览" name="overview">概览内容</QyTabPane>
475
+ <QyTabPane label="详情" :name="2" lazy closable>详情内容</QyTabPane>
476
+ </QyTabs>
477
+ ```
478
+
479
+ 支持 `type`(`'' | 'card' | 'border-card')、`tabPosition`、`stretch`、`closable`、`addable`、`editable`、`beforeLeave` 和 `tabindex`。`QyTabPane` 支持 `label`、字符串或数字 `name`、`closable`、`disabled`、`lazy` 与 `label` 插槽。`tab-click` 的首个参数是冻结的 `QyTabPaneSnapshot`,只包含 `name`、`label`、`disabled`、`closable`、`lazy`、`active`、`index`,不会泄漏 Element Plus 页签上下文或实例。
480
+
481
+ ### `QyDescriptions` 与 `QyDescriptionsItem`
482
+
483
+ `QyDescriptions` 使用 Element Plus 的 `ElDescriptions` / `ElDescriptionsItem` 处理描述列表的行列和单元格渲染。`QyDescriptionsItem` 是无 DOM 声明节点,父组件会递归处理直接子项、`v-if`、`v-for` 和 `template`/Fragment,再交给 Element Plus 完成 `span`、`rowspan`、宽度和对齐计算。
484
+
485
+ ```vue
486
+ <QyDescriptions border :column="3" title="订单详情">
487
+ <template #extra><QyLink href="/orders">查看全部</QyLink></template>
488
+ <QyDescriptionsItem label="编号">SO-2026-001</QyDescriptionsItem>
489
+ <QyDescriptionsItem label="摘要" :span="2" :rowspan="2">复杂内容也可放入默认插槽。</QyDescriptionsItem>
490
+ <QyDescriptionsItem label="金额" align="right">¥12,800.00</QyDescriptionsItem>
491
+ </QyDescriptions>
492
+ ```
493
+
494
+ 父级支持 `border`、`column`、`direction`、`size`(`'' | 'large' | 'default' | 'small'`)、`title`、`extra`、`labelWidth` 以及默认、`title`、`extra` 插槽;插槽优先于同名文本属性。描述项支持 `label`、`span`、`rowspan`、`width`、`minWidth`、`labelWidth`、`align`、`labelAlign`、`className`、`labelClassName` 以及默认和 `label` 插槽。组件只安全透传根节点的 `class`、`style`、`id`、`title`、`role`、`data-*`、`aria-*`,不公开事件、状态或 Element Plus 实例。
495
+
496
+ ### `QyUpload`
497
+
498
+ 上传组件,支持:
499
+
500
+ - 图片上传
501
+ - 视频上传
502
+ - 粘贴上传
503
+ - 拖拽上传
504
+ - 文本备注
505
+ - 预览
506
+ - `v-model`
507
+ - `valueFormat`
508
+ - 纯图片模式
509
+ - 普通文件列表模式
510
+ - 只选择本地文件而不上传
511
+
512
+ 当前可配置项里,和宿主耦合最强的是上传配置:
513
+
514
+ - `api`
515
+ - `tokenKey`
516
+ - `name`
517
+ - `uploadRequest`
518
+
519
+ 其中:
520
+
521
+ - `api` 为必填
522
+ - `tokenKey` 不传时默认使用 `Admin-Token`
523
+ - `name` 不传时默认使用 `file`
524
+ - `uploadRequest` 可接入宿主项目自己的 request、baseURL、鉴权和错误处理;不传时使用组件默认 XHR 上传
525
+ - 新代码应由宿主 `uploadRequest` adapter 返回已经完成 baseURL 归一化的完整 URL;组件不拼接消费者的相对文件地址
526
+
527
+ 值协议:
528
+
529
+ - 默认 `valueFormat="object"`,`v-model` 输出 `{ files: string[], text: string }`
530
+ - `valueFormat="array"`,`v-model` 输出 `string[]`
531
+ - `valueFormat="string"`,`v-model` 输出逗号分隔 URL
532
+ - `showText=false` 可隐藏文字备注区;如仍需粘贴入口,可开启 `showPasteInput`
533
+ - `defaultValue` 仍保留给老页面做非受控初始化;新页面建议优先使用 `v-model`
534
+ - `variant="file-list"` 使用普通文件列表;默认 `media-card` 行为保持不变
535
+ - `autoUpload=false` 时不调用 transport,使用 `v-model:selected-files` 读写浏览器原始 `File[]`
536
+
537
+ ### `QyImageUpload`
538
+
539
+ 图片/文件字段上传组件,基于 `QyUpload` 的薄封装,适合商品图、设计图、成本附图、凭证图片集合、单视频字段等场景。
540
+
541
+ 固定协议:
542
+
543
+ - 默认 `multiple=false`,`v-model` 为单个 URL 字符串
544
+ - `multiple=true` 时,`v-model` 为 URL 数组
545
+ - 单图默认 `limit=1`,多图默认 `limit=9`
546
+ - 默认 `name="files"`
547
+ - 默认 `showText=false`
548
+ - 默认开启纯粘贴输入条
549
+ - 默认 `size="128px"`
550
+ - 支持 `supportVideo`、`fileType`、`fileSize`
551
+ - 支持透传 `uploadRequest`,用于接入宿主项目上传请求
552
+
553
+ 凭证上传模式:
554
+
555
+ - `mode="voucher"` 或 `voucher` 可启用凭证图片场景。
556
+ - 默认允许 `jpg / jpeg / png / gif / bmp / webp`。
557
+ - 默认 `limit=30`,保留纯粘贴入口,适合收款凭证、成本附图等旧 `CopyImgUpload` 使用点。
558
+ - 暴露 `getFullPathList()` 和 `fullPathList`,兼容旧页面 `ref.fullPathList.join(',')` 的读值方式。
559
+ - 上传成功时额外触发 `updateImg(url)`,兼容旧 `CopyImgUpload` 的成功通知语义。
560
+
561
+ `QyImageUpload` 不保留旧 `imageUpload` 的 `successUpload(fileList)` 回调。旧页面迁移时优先改为 `v-model`;确实依赖旧 `CopyImgUpload` 读值方式的页面,可先用凭证模式的 `fullPathList / getFullPathList()` 过渡。
562
+
563
+ ### `QyImage`
564
+
565
+ 图片展示组件,计划承接旧 `packages/qiyin/components/Image`,并作为 `@qynpm/table-schema` 的 `image` 列渲染底座。
566
+
567
+ 这是后续替代旧 `useCol` 的前置组件。旧 `useCol/render/imageRender.vue` 的表格列渲染不应该在 `@qynpm/table-schema` 内重复维护一套通用图片组件,而应组合 `QyImage`。
568
+
569
+ 必须完整覆盖旧能力:
570
+
571
+ - `src` 图片地址。
572
+ - `width / height / size` 缩略图尺寸。
573
+ - `fit` 图片填充方式,透传 `ElImage`。
574
+ - 加载中状态。
575
+ - 加载失败状态。
576
+ - `error` 事件。
577
+ - `placeholder` 空图占位。
578
+ - `compressor` 压缩缩略图参数。
579
+ - 旧域名兼容:`ys.diansan.com` 地址迁移为 `https://admin.qiyinbz.com`。
580
+ - 旧缩略图参数:点三域名使用 `?small=true&style=image/resize,h_{h},w_{w}`,其他域名使用 `?w={w}`。
581
+ - 失败兜底:缩略图请求失败后请求原图 blob,并用浏览器 canvas 压缩成 dataURL 展示。
582
+ - `preview / previewList / initialIndex` 图片预览。
583
+
584
+ 失败兜底属于旧公共图片组件能力,不是录单业务逻辑。当前实现不新增 `compressorjs`,使用浏览器原生 `fetch + blob + canvas` 完成压缩;如果后续发现必须完全等价旧 `compressorjs` 的压缩细节,再单独评估是否新增依赖。
585
+
586
+ 建议新组件 API:
587
+
588
+ ```ts
589
+ type QyImageProps = {
590
+ src?: string
591
+ width?: number | string
592
+ height?: number | string
593
+ size?: number
594
+ fit?: 'fill' | 'contain' | 'cover' | 'none' | 'scale-down'
595
+ placeholder?: boolean
596
+ compressor?: boolean | {
597
+ w?: number
598
+ h?: number
599
+ q?: number
600
+ }
601
+ preview?: boolean
602
+ previewList?: string[]
603
+ initialIndex?: number
604
+ }
605
+ ```
606
+
607
+ 表格 image 列后续直接组合 `QyImage` 和 `QyImagePreview`,不要在 `@qynpm/table-schema` 里复制一份通用图片组件。
608
+
609
+ 已完成:
610
+
611
+ - 创建 `@qiyin/UI/qy-image` 入口。
612
+ - 创建 `src/docs/QyImageDoc.vue` playground 文档。
613
+ - 补 `index.js / index.d.ts / package.json exports / files`。
614
+ - 补构建入口,确保 `@qynpm/ui/qy-image` 可按需引入。
615
+ - 补失败压缩兜底,不新增 `compressorjs`。
616
+ - 补 `preview` 接入,可点击打开 `QyImagePreview`。
617
+
618
+ ### `QyImagePreview`
619
+
620
+ 图片预览组件,承接旧 `useCol/render/imageRender.vue` 中动态创建 `ElImageViewer` 的逻辑。
621
+
622
+ 需要支持:
623
+
624
+ - `urlList` 图片列表。
625
+ - `initialIndex` 初始预览索引。
626
+ - 打开时控制 `body.style.overflow = 'hidden'`。
627
+ - 关闭时恢复 body 滚动并销毁实例。
628
+ - 支持直接作为组件使用,也支持函数式调用,例如 `openQyImagePreview({ urlList, initialIndex })`。
629
+
630
+ 该能力是 `@qynpm/table-schema` 完整迁移 image 列的前置能力。table-schema 不应该长期维护一份独立图片预览逻辑。
631
+
632
+ ### `QyCheckbox`
633
+
634
+ 受控复选框基础组件,基于 `ElCheckbox` 做隔离适配,`modelValue`、`trueValue`、`falseValue` 和事件 payload 均保持 `boolean | string | number` 原始类型,不做隐式布尔转换。
635
+
636
+ 支持 `value`(为后续 `QyCheckboxGroup` 保留的选项值)、只读展示状态 `indeterminate`、`disabled`、`size` 和默认 slot。事件只有 `update:modelValue`、`change`、`focus`、`blur`;禁用状态不产生值变更意图,也不公开 Element Plus 实例或命令式方法。
637
+
638
+ ```vue
639
+ <QyCheckbox
640
+ v-model="ticketValue"
641
+ true-value="Y"
642
+ false-value="N"
643
+ aria-label="开票"
644
+ @change="handleChange"
645
+ >
646
+ 开票
647
+ </QyCheckbox>
648
+ ```
649
+
650
+ `class`、`style`、`id`、`name`、`role`、`title`、`data-*` 和 `aria-*` 会安全透传;桌面交互区域保持紧凑,窄屏下提升到至少 40px。`QyCheckboxGroup`、全选/级联和 `CheckboxButton` 不属于 V1。
651
+
652
+ ### `QyRadio`
653
+
654
+ 受控单选框基础组件,基于 `ElRadio` 做隔离适配。`value` 表示选中值,`label` 只负责展示;默认 slot 优先。`modelValue` 与事件 payload 保持 `boolean | string | number` 原始类型,父级不回写时组件不会自行改变状态,也不会通过再次点击取消选中。
655
+
656
+ 支持 `disabled`、`size`、`name`、`border` 以及 `update:modelValue`、`change`、`focus`、`blur` 事件;安全透传 `class`、`style`、`role`、`title`、`data-*` 和 `aria-*`,不公开 Element Plus 实例或命令式方法。
657
+
658
+ ```vue
659
+ <QyRadio
660
+ v-model="ticketType"
661
+ value="invoice"
662
+ label="开票"
663
+ name="ticket-type"
664
+ border
665
+ @change="handleChange"
666
+ />
667
+ ```
668
+
669
+ ### `QyCheckboxGroup`
670
+
671
+ 受控复选框组,统一管理 `QyCheckboxValue[]`。支持默认 slot 或 `options`(两者同时存在时 slot 优先),并透传 `disabled`、`min`、`max`、`size`。事件只有 `update:modelValue` 和 `change`,每次更新都返回新数组。
672
+
673
+ ```vue
674
+ <QyCheckboxGroup v-model="selected" :options="[
675
+ { label: '阅读', value: 'read' },
676
+ { label: '写作', value: 'write', disabled: true }
677
+ ]" />
678
+ ```
679
+
680
+ options 模式物理复用 `QyCheckbox`;不提供 CheckboxButton、全选、indeterminate 推导、树形/层级选择、布局 props 或 Element Plus 实例。
681
+
682
+ ### `QyAutocomplete`
683
+
684
+ 自动完成输入基础组件,基于 `ElAutocomplete` 做薄封装,支持本地 `options` 过滤和 Element Plus 原生 `fetchSuggestions` 透传。
685
+
686
+ 默认协议:
687
+
688
+ - `v-model` 绑定输入值。
689
+ - `options` 支持 `{ value }` 列表,也支持通过 `valueKey` 映射其它字段。
690
+ - 默认按 `option.value.includes(query)` 过滤。
691
+ - 支持 `select / change / input / clear / focus / blur` 事件。
692
+
693
+ 该组件作为 `@qynpm/table-schema` 的 `edit-autocomplete` 渲染器底座,表格 row 写回逻辑仍留在 table-schema。
694
+
695
+ ### `QyMenuActions`
696
+
697
+ 表格行操作 UI 底座,承接旧 `useCol/render/menu.vue` 的通用展示能力。
698
+
699
+ 支持:
700
+
701
+ - `inline` 横向操作模式。
702
+ - `popover` 更多操作模式。
703
+ - `actions` 列表。
704
+ - `hidden / disabled / loading` 支持布尔值或按行上下文计算。
705
+ - `type` 控制默认、主色、成功、警告、危险操作色。
706
+ - `confirmMethod(action, context)` 由宿主注入确认逻辑。
707
+ - `action(action, context)` 只在可执行且确认通过后触发。
708
+
709
+ `QyMenuActions` 不内置权限、路由、缓存、弹窗实例、消息提示,也不直接执行业务方法。权限过滤和业务执行应留在 `@qynpm/table-schema` adapter 或宿主页面。
710
+
711
+ ### `QyTableColumnSettings`
712
+
713
+ 表格列设置 UI 底座,承接旧 `useCol/render/setup.vue` 的通用 UI 能力。
714
+
715
+ 支持:
716
+
717
+ - 列列表展示。
718
+ - 当前选中列。
719
+ - 置顶、置底、上移、下移。
720
+ - 固定左侧、固定右侧、取消固定。
721
+ - 列宽编辑。
722
+ - 显隐开关。
723
+ - 恢复默认。
724
+ - 删除缓存。
725
+
726
+ 业务缓存读写仍由 `@qynpm/table-schema` 的 settings adapter 或宿主 adapter 负责,UI 组件只负责展示和编辑 settings。
727
+
728
+ ### 编辑类基础组件(待评估)
729
+
730
+ 旧 `useCol` 的 `edit-input / edit-autocomplete` 有一套“展示态 -> 点击编辑 -> blur/enter 写回”的通用交互。后续有两种选择:
731
+
732
+ - 如果表格外也需要该交互,补 `QyInlineEditInput` 和 `QyAutocompleteInput`。
733
+ - 如果只服务表格列,先放在 `@qynpm/table-schema` renderer 内部,避免 UI 包过早扩大。
734
+
735
+ ### `QyDialog`
736
+
737
+ QyDialog 是受控弹窗组件,使用 Qy-owned 协议:
738
+
739
+ - `open` / `update:open` / `open-change` 管理显隐
740
+ - `confirm`、`cancel` 和 `close(reason)` 表达关闭意图;`reason` 为 `confirm | cancel | header | escape | overlay | external`
741
+ - `confirm-loading` 在宿主异步业务期间锁定确认动作,业务成功后由宿主关闭
742
+ - 默认 footer 由 `show-footer`、`show-confirm`、`show-cancel`、`confirm-text` 和 `cancel-text` 控制;自定义 `footer` 时不渲染默认按钮
743
+ - 支持全屏切换、最小化、焦点恢复和顶层弹窗 Escape/遮罩仲裁
744
+
745
+ ```vue
746
+ <QyDialog
747
+ :open="open"
748
+ title="订单确认"
749
+ :confirm-loading="saving"
750
+ :close-on-confirm="false"
751
+ @update:open="open = $event"
752
+ @confirm="save"
753
+ >
754
+ 内容区域
755
+ </QyDialog>
756
+ ```
757
+
758
+ 旧 `modelValue`、`layout`、`confirmProps`、`ok` 和 Element Plus attrs 不属于 QyDialog 公共面;过渡场景使用独立的 `@qynpm/qy-dialog-legacy` adapter,禁止新业务采用。
759
+
760
+ ### `QyButton`
761
+
762
+ 后台按钮统一入口,后续 AdminShell 和业务页按钮迁移时优先使用该组件,而不是直接写原生 `button` 或分散使用 `ElButton`。
763
+
764
+ 核心能力:
765
+
766
+ - `type="default | primary | success | warning | danger | text | ghost | link"` 控制视觉类型。
767
+ - `size="sm | md | lg"` 控制高度、padding、gap、字号和图标尺寸,默认 `md`。
768
+ - `disabled` 和 `loading` 都会阻止 `click` 事件;`loading` 会展示内置 loading 状态。
769
+ - `active` 用于顶部当前系统、tabs 当前操作等选中态。
770
+ - `block` 撑满父容器,`round` 显式开启胶囊圆角;默认后台圆角保持紧凑。
771
+ - `native-type="button | submit | reset"` 控制原生按钮类型,默认 `button`。
772
+ - `prefix-icon / suffix-icon` 只支持 Vue 组件图标;也可以通过 `prefix / suffix` 插槽传入前后图标;`icon-only` 必须提供 `aria-label` 或 `title`。
773
+
774
+ 样式 token:
775
+
776
+ - 尺寸类:`--qy-button-sm-height`、`--qy-button-md-height`、`--qy-button-lg-height`、`--qy-button-*-padding-x`、`--qy-button-*-gap`、`--qy-button-*-font-size`、`--qy-button-*-icon-size`。
777
+ - 状态类:`--qy-button-default-*`、`--qy-button-primary-*`、`--qy-button-success-*`、`--qy-button-warning-*`、`--qy-button-danger-*`、`--qy-button-disabled-*`、`--qy-button-focus-ring`。
778
+ - token 默认从 Element Plus 的 `--el-*` 设计变量取值,宿主可覆盖 `--qy-button-*` 做主题适配。
779
+
780
+ ### `QyDropdown`
781
+
782
+ 后台下拉菜单统一入口,后续 AdminShell、工具栏和更多操作菜单迁移时优先使用该组件,而不是在业务页面散落手写原生 dropdown DOM。
783
+
784
+ 核心能力:
785
+
786
+ - `items` 支持 `{ key, label, icon, disabled, danger, hidden, divided, active, title }`。
787
+ - `hidden` 项不渲染,`disabled` 项不触发 `select`。
788
+ - `danger` 和 `active` 项会输出稳定的 `is-danger` / `is-active` class,以及 `data-danger` / `data-active` 标记。
789
+ - `trigger="click"` 为默认触发方式,预留 `contextmenu`。
790
+ - `v-model` / `model-value` 支持受控打开状态;受控模式下只触发 `update:modelValue` 和 `open-change`,不私自决定最终打开状态。
791
+ - `close-on-select=false` 可在选择后保持面板打开。
792
+ - `panel-width` / `width` 和 `max-height` 控制面板尺寸。
793
+ - `trigger`、`item`、`header`、`footer`、`empty` 插槽用于业务定制展示;`trigger` 插槽应把 `attrs` 绑定到实际触发按钮上。
794
+
795
+ ### `QySelectionDialog`
796
+
797
+ 数据选择弹窗底座,参考老 `@qiyin/components/Dialog` 的核心能力迁移,但不内置任何 ERP 接口或权限逻辑。
798
+
799
+ 适合业务 wrapper 组合:
800
+
801
+ - 店铺选择
802
+ - 人员选择
803
+ - 商品选择
804
+ - 物料/工艺/属性选择
805
+
806
+ 核心能力:
807
+
808
+ - `QyDialog` 弹窗容器
809
+ - `fetchMethod(query)` 或兼容老 `query(query)` 加载表格数据
810
+ - `selectionMode="single | multiple | none"`,兼容老 `selection="single | multi | none"`
811
+ - `modelValue` 管理确认后的已选行,`selected` 兼容老 `Dialog` 初始已选行
812
+ - `rowKey` 控制唯一键
813
+ - `labelKey` 控制已选标签展示
814
+ - `searchKey`、分类、类型筛选
815
+ - 类型筛选内部使用 `QySelect`,可通过 `typeSelectProps` 透传下拉属性
816
+ - `columns` / `cols` 插槽渲染业务列
817
+ - `side`、`search`、`toolbar` 插槽扩展业务区域
818
+ - Element Plus 原生分页
819
+
820
+ `QySelectionDialog` 只解决“怎么选”,不解决“选什么”。业务接口、字段映射、权限判断应放在宿主项目 wrapper 中。
821
+
822
+ 迁移业务选择器前,建议先阅读:
823
+
824
+ - [选择弹窗迁移规范](./选择弹窗迁移规范.md)
825
+
826
+ 选择状态采用“弹窗草稿 + 确认提交”协议:
827
+
828
+ - 行点击、勾选、删除标签、粘贴只修改弹窗内部草稿,并触发 `selection-change(rows)`。
829
+ - 点击确认后才触发 `update:modelValue(rows)`、`confirm(rows)` 和兼容老 `Dialog` 的 `submit({ selection, rows, query })`。
830
+ - 点击取消或关闭会丢弃草稿选择,不会污染宿主表单中的 `v-model`。
831
+ - `search` / `handleQuerySearch` 会重置到第一页并查询;分页切换会按当前条件查询。
832
+
833
+ 主要扩展点:
834
+
835
+ - `columns` / `cols`:表格列,`cols` 用于兼容老 `Dialog`。
836
+ - `side`:左侧业务区域,例如分类树、部门树。
837
+ - `search`:完全自定义查询区,插槽参数为 `{ query, search, reset }`。
838
+ - `toolbar`:搜索区右侧操作区,插槽参数为 `{ query, search }`。
839
+ - `getTableRef`、`getTableData`、`getSelection`:用于业务 wrapper 做必要的桥接。
840
+
841
+ ### `QyRemarkImage`
842
+
843
+ 备注图片组件,承接旧 `@qiyin/components/remarkImage` 的“备注文本 + 单图”协议。
844
+
845
+ 支持:
846
+
847
+ - `defaultValue` 解析 `[url:图片地址]备注文本`
848
+ - `defaultImage` 独立图片默认值
849
+ - `change(value, imageUrl)` 输出完整备注值和图片地址
850
+ - 粘贴图片上传
851
+ - 悬浮预览和删除图片
852
+ - `uploadRequest` 自定义上传请求
853
+ - `layout="select-prefix"` 可把一个基础下拉值合并成输入前缀,用于“下拉值 + 图文备注”这类旧协议字段
854
+ - `deleteImage()` / `clearContent()` / `getValue()` 暴露方法,兼容旧表单重置和读取协议值
855
+
856
+ 默认上传会使用:
857
+
858
+ - `api`,默认 `/permission-api/common/uploads`
859
+ - `tokenKey`,默认 `Admin-Token`
860
+ - `uploadName`,默认 `files`
861
+
862
+ 如果宿主项目有统一 request、baseURL、鉴权、错误处理或登录失效处理,应优先传入 `uploadRequest`,不要在组件内部写死项目请求实现。
863
+
864
+ 组合下拉输入:
865
+
866
+ ```vue
867
+ <QyRemarkImage
868
+ layout="select-prefix"
869
+ :select-value="postageValue"
870
+ :select-options="[
871
+ { label: '包邮', value: '包邮' },
872
+ { label: '不包邮', value: '不包邮' }
873
+ ]"
874
+ placeholder="备注 / 粘贴图片"
875
+ type="text"
876
+ @update:select-value="postageValue = $event"
877
+ @change="handleRemarkChange"
878
+ />
879
+ ```
880
+
881
+ ### `QyInput`
882
+
883
+ 输入组件,第一版定位为 `ElInput` 的轻量包装层,重点支持:
884
+
885
+ - 保持和 `ElInput` 接近的使用方式
886
+ - `removeSpace`
887
+ - `trimMode`
888
+ - `enter`
889
+ - `textarea`
890
+ - `modelValue` 支持 `string | number | null | undefined`,用户编辑事件统一输出 `string`
891
+ - 兼容 `text`、`textarea`、`password`、`search` 和 Element Plus 常用属性
892
+ - 兼容 `prefix`、`suffix`、`prepend`、`append` slots
893
+ - 类型出口包含 `QyInputValue`、`QyInputModelValue`、`QyInputType`、`QyInputSize`、`QyInputAutoSize`、`QyInputIcon`、`QyInputInputMode`、`QyInputModelModifiers`、`QyInputStyle`、`QyInputProps`、`QyInputEmits` 和 `QyInputExposed`
894
+ - 只公开 `focus`、`blur`、`select`、`clear`、`resizeTextarea` 方法
895
+
896
+ ### `QyMoneyInput`
897
+
898
+ 金额输入组件,第一版定位为 `ElInput` 的金额录入包装层,公开类型包含 `QyMoneyInputValue`、`QyMoneyInputFormatTrigger`、`QyMoneyInputSize`、`QyMoneyInputProps`、`QyMoneyInputEmits`、`QyMoneyInputSlots` 和 `QyMoneyInputExposed`。重点支持:
899
+
900
+ - 输入过程清洗非法字符
901
+ - 默认失焦格式化为固定小数位
902
+ - `precision`
903
+ - `min / max`
904
+ - `allowNegative`
905
+ - `formatTrigger` 与 `emptyValue`
906
+ - `placeholder`、`clearable`、`disabled`、`readonly`、`size`、`name`、`id`、`autocomplete`、`autofocus`、`maxlength`、`minlength`、`tabindex` 和 `ariaLabel`
907
+ - `prefix`、`suffix`、`prepend`、`append` slots
908
+ - `update:modelValue`、`input`、`change`、`focus`、`blur`、`clear`、`enter` 显式事件
909
+ - 只公开 `focus()`、`blur()`、`select()`、`clear()` 方法
910
+
911
+ 运行时暂保留 `getNativeInput()` 兼容方法,但其原生 DOM 返回值不属于 Qy 稳定类型契约,新消费者不应依赖。
912
+
913
+ ### `QyInputTag`
914
+
915
+ 受控标签输入组件,内部使用 Element Plus 2.9 起提供的 `ElInputTag`。`modelValue` 始终为 `string[]`;`trigger` 支持 `enter` 和 `space`,`tagTone` / `tagEffect` 使用 Qy 标签语义,新增、删除、清空分别发出 `add`、`remove(value, index)`、`clear`,每次接受的变更只发出一次 `change`。仅公开 `focus()` 和 `blur()`。
916
+
917
+ ```vue
918
+ <QyInputTag
919
+ v-model="tags"
920
+ clearable
921
+ placeholder="输入标签后按 Enter"
922
+ @add="handleAdd"
923
+ @remove="handleRemove"
924
+ @change="handleChange"
925
+ />
926
+ ```
927
+
928
+ 支持 `max`、`size`、`disabled`、`readonly`、`autofocus`、`validateEvent`、`id`、`tabindex`、`maxlength`、`minlength`、`autocomplete`、`ariaLabel` 和 `tag`、`prefix`、`suffix` 插槽;不提供 delimiter、Tab 提交、拖拽、折叠标签或 `v-model:value` / `removeTag` 旧版兼容。
929
+
930
+ ### `QyInputNumber`
931
+
932
+ 数字输入组件,第一版定位为 `ElInputNumber` 的轻量包装层,公开契约由 Qy 自有类型定义;使用该组件时 Element Plus peer 保持 `^2.9.0` 或更高版本。
933
+
934
+ 重点支持:
935
+
936
+ - 保持 `number / null` 值语义
937
+ - `min / max`
938
+ - `step`
939
+ - `step-strictly`
940
+ - `precision`
941
+ - `controls / controls-position`
942
+ - `valueOnClear`(默认 `null`,也支持 `min / max / number`)
943
+ - `readonly / disabled / size / validateEvent`
944
+ - `id / name / placeholder / ariaLabel`
945
+ - `prefix / suffix / increase-icon / decrease-icon` slots
946
+ - `update:modelValue / input / change / focus / blur` 显式事件
947
+ - 兼容 `focus / blur` expose 方法
948
+
949
+ 金额、费用、税费等财务录入场景请优先使用 `QyMoneyInput`,不要用 `QyInputNumber` 做金额格式化。
950
+
951
+ ### `QyDatePicker`
952
+
953
+ 日期选择组件,第一版定位为 `ElDatePicker` 的轻量包装层,重点支持:
954
+
955
+ - 保持和 `ElDatePicker` 接近的使用方式
956
+ - `date / datetime / daterange / datetimerange` 等常见类型
957
+ - `format / value-format`
958
+ - `default-time`
959
+ - `shortcuts`
960
+ - `disabled-date`
961
+ - `year / month / date / dates / datetime / week / daterange / datetimerange / monthrange`
962
+ - `clearable / disabled / readonly / teleported / append-to / popper-class`
963
+ - `update:modelValue / change / clear / calendar-change / panel-change / visible-change / focus / blur`
964
+ - `default / range-separator / prev-month / next-month / prev-year / next-year` slots
965
+ - 仅公开 `focus() / blur() / open() / close()` expose 方法
966
+
967
+ `normalize-range-end-time` 默认关闭。开启后只处理范围第二项:精确 `00:00:00.000` 的 `Date` 克隆为 `23:59:59.000`,带明确午夜时间的普通/ISO 字符串只替换时间并保留格式及 zone suffix;date-only 字符串、number、非午夜和非范围值保持原引用,不修改父数组或父 `Date`。
968
+
969
+ ### `QyRadioGroup`
970
+
971
+ 单选组组件,第一版定位为 `ElRadioGroup` 的轻量包装层,重点支持:
972
+
973
+ - `options` 直出
974
+ - `labelKey / valueKey / disabledKey` 映射
975
+ - 普通单选 / 按钮式单选
976
+ - 选项禁用
977
+ - `option` 插槽自定义选项文案
978
+ - 事件保持 `update:modelValue`、`change`
979
+
980
+ `option` 插槽由外部传入,组件会透出当前选项的:
981
+
982
+ - `option`:原始选项对象
983
+ - `label`:映射后的展示文案
984
+ - `value`:映射后的选项值
985
+ - `disabled`:是否禁用
986
+
987
+ 普通 `options` 模式物理复用 `QyRadio`;`type="button"` 继续使用内部 Element Plus button adapter。已发布的 `getRadioGroupInstance()` 仅为兼容保留并标记为 deprecated,不新增实例能力。
988
+
989
+ ### `QySelect`
990
+
991
+ 受控选择器组件。string、number、boolean、对象值和多选数组会原样通过 `update:modelValue` / `change` 返回;组件不会排序、克隆或隐式转换,父级 `modelValue` 始终是最终状态权威。
992
+
993
+ - `options` 支持 `labelKey / valueKey / disabledKey` 字段映射;默认 slot 有实际内容时优先。
994
+ - `valueKey` 只决定 option 的值字段;对象值需要稳定回显时,使用 `objectIdentityKey` 指定对象身份字段。
995
+ - 支持单选、多选、disabled、clearable、filterable、loading、collapse tags、弹层挂载和 popper class。
996
+ - `autoSelectSingle` 只在 options 模式、当前值为空且唯一 option 未禁用时触发一次 `update:modelValue` 后再触发一次 `change`;父值变为非空后再次清空可重新触发。
997
+ - 保留 prefix、empty、loading、tag 和 default slots,以及 clear、visible-change、focus、blur 事件。
998
+ - 只公开 `focus()` / `blur()`,不公开 Element Plus 实例或 DOM 引用。
999
+
1000
+ ```vue
1001
+ <QySelect
1002
+ v-model="selectedUser"
1003
+ :options="userOptions"
1004
+ label-key="name"
1005
+ value-key="user"
1006
+ object-identity-key="id"
1007
+ />
1008
+ ```
1009
+
1010
+ 远程请求、防抖和已选项缓存仍由 `QyRemoteSelect` 负责;`QySelect` 不承接业务字典或请求状态编排。
1011
+
1012
+ ### `QyTreeSelect`
1013
+
1014
+ 树选择组件以 `ElTreeSelect` 作为唯一树、勾选、过滤、键盘和浮层实现,重点支持:
1015
+
1016
+ - `data` 树数据直出,`options` 作为兼容入口;同时传入时 `data` 优先,节点与数组保持原始引用
1017
+ - `labelKey / valueKey / childrenKey / disabledKey` 快捷字段与 `props` 映射(显式 `props` 优先)
1018
+ - string、number、boolean、对象和多选数组的受控值;对象值必须配置稳定的 `nodeKey`
1019
+ - 单选 / 多选
1020
+ - `check-strictly`
1021
+ - `collapse-tags`
1022
+ - 默认弹层挂载策略
1023
+ - 保留原始节点字段,便于业务 slot 和后续透传使用
1024
+
1025
+ `QyTreeSelect` 只处理树选择器的通用 UI 协议,不内置远程请求、权限过滤或业务接口格式化。节点插槽、回调和事件只提供原始数据与安全快照;公开实例只有 `focus()` 和 `blur()`,不会暴露 Element Node、Store 或组件实例。
1026
+
1027
+ 为降低迁移成本,`QyTreeSelect` 的 `clearable`、`filterable`、`check-strictly`、`render-after-expand`、`fit-input-width` 等默认行为尽量跟随 `ElTreeSelect`。业务需要搜索、清空、父子不联动时应显式传参。
1028
+
1029
+ ### `QyRemoteSelect`
1030
+
1031
+ 远程选择器组件,基于 `QySelect` 组合实现,重点支持:
1032
+
1033
+ - `fetchMethod(keyword)` 远程请求
1034
+ - `debounce`
1035
+ - `minLength`
1036
+ - `defaultOptions`
1037
+ - `remoteOnFocus`
1038
+ - 内部请求 `loading`
1039
+ - `error`
1040
+ - `options-change`
1041
+ - 已选项缓存,避免远程 options 清空后回显丢 label
1042
+ - 继承 `QySelect` 的字段映射、多选、折叠标签、唯一选项自动选中能力
1043
+
1044
+ 如果只是本地 options 下拉,应优先使用 `QySelect`;只有需要远程请求、搜索和回显保留时再使用 `QyRemoteSelect`。
1045
+
1046
+ ### `QyFormSection`
1047
+
1048
+ 区块容器组件,适合录单页面的表单区块外壳,重点支持:
1049
+
1050
+ - 标题
1051
+ - 描述
1052
+ - 操作区 slot
1053
+ - 提示区
1054
+ - 简单折叠
1055
+ - 统一边框、背景和间距
1056
+
1057
+ ### `QyActionBar`
1058
+
1059
+ 底部操作栏组件,适合录单页面底部按钮区,重点支持:
1060
+
1061
+ - sticky 吸底
1062
+ - 左右分区
1063
+ - 窄屏换行
1064
+ - 边框 / 阴影
1065
+ - 底部安全区适配
1066
+
1067
+ ### `QySearchInput`
1068
+
1069
+ 搜索输入组件,支持:
1070
+
1071
+ - 基于 `ElAutocomplete` 的等价封装
1072
+ - 搜索按钮
1073
+ - 回车搜索
1074
+ - 本地建议项
1075
+ - 远程建议项
1076
+ - 兼容 `fetch-suggestions(queryString, cb)` 回调风格
1077
+ - 高亮匹配词
1078
+ - 默认使用 Element Plus 弹层挂载策略,避免被父级裁剪
1079
+ - 平铺项和分组项两种建议结构
1080
+
1081
+ ### `QyRecordQuoteSearch`
1082
+
1083
+ 录单报价单号搜索组件,支持:
1084
+
1085
+ - 报价单号输入
1086
+ - 报价单号提取与规范化
1087
+ - 搜索触发
1088
+ - 建议项选择
1089
+ - 局部状态提示
1090
+ - `loading-change / success / error` 事件
1091
+
1092
+ ## 样式说明
1093
+
1094
+ - 包内样式会跟随构建产物一起注入
1095
+ - 宿主仍然需要自行引入 `element-plus/dist/index.css`
1096
+ - 当前组件内部仍然依赖宿主提供的 Tailwind / Iconify 体系能力
1097
+
1098
+ ## 使用示例
1099
+
1100
+ ### QyUpload
1101
+
1102
+ ```vue
1103
+ <template>
1104
+ <QyUpload
1105
+ v-model="uploadValue"
1106
+ api="/permission-api/common/uploads"
1107
+ token-key="Admin-Token"
1108
+ @change="handleChange"
1109
+ />
1110
+ </template>
1111
+ ```
1112
+
1113
+ 纯图片上传:
1114
+
1115
+ ```vue
1116
+ <template>
1117
+ <QyUpload
1118
+ v-model="payImgs"
1119
+ api="/permission-api/common/uploads"
1120
+ name="files"
1121
+ value-format="array"
1122
+ :show-text="false"
1123
+ :show-paste-input="true"
1124
+ paste-placeholder="粘贴图片上传"
1125
+ size="90px"
1126
+ />
1127
+ </template>
1128
+ ```
1129
+
1130
+ ### QyImageUpload
1131
+
1132
+ 单图字段:
1133
+
1134
+ ```vue
1135
+ <template>
1136
+ <QyImageUpload
1137
+ v-model="imageUrl"
1138
+ api="/permission-api/common/uploads"
1139
+ :file-size="5"
1140
+ />
1141
+ </template>
1142
+ ```
1143
+
1144
+ ### QyImage
1145
+
1146
+ ```vue
1147
+ <template>
1148
+ <QyImage
1149
+ src="https://img.example.com/a.jpg"
1150
+ :size="48"
1151
+ fit="cover"
1152
+ preview
1153
+ :compressor="{ w: 200, h: 200, q: 50 }"
1154
+ />
1155
+ </template>
1156
+ ```
1157
+
1158
+ 函数式预览:
1159
+
1160
+ ```ts
1161
+ import { openQyImagePreview } from '@qynpm/ui'
1162
+
1163
+ openQyImagePreview({
1164
+ urlList: ['https://img.example.com/a.jpg'],
1165
+ initialIndex: 0
1166
+ })
1167
+ ```
1168
+
1169
+ 多图字段:
1170
+
1171
+ ```vue
1172
+ <template>
1173
+ <QyImageUpload
1174
+ v-model="payImages"
1175
+ api="/permission-api/common/uploads"
1176
+ multiple
1177
+ :limit="9"
1178
+ />
1179
+ </template>
1180
+ ```
1181
+
1182
+ 凭证上传模式,迁移旧 `CopyImgUpload`:
1183
+
1184
+ ```vue
1185
+ <template>
1186
+ <QyImageUpload
1187
+ ref="payImgRef"
1188
+ v-model="payImages"
1189
+ mode="voucher"
1190
+ api="/permission-api/common/uploads"
1191
+ :multiple="false"
1192
+ size="100px"
1193
+ />
1194
+ </template>
1195
+
1196
+ <script setup>
1197
+ import { ref } from 'vue'
1198
+
1199
+ const payImages = ref('')
1200
+ const payImgRef = ref(null)
1201
+
1202
+ function getForms() {
1203
+ return {
1204
+ erpOrderPayImg: payImgRef.value.getFullPathList().join(',')
1205
+ }
1206
+ }
1207
+ </script>
1208
+ ```
1209
+
1210
+ 接入宿主项目上传请求:
1211
+
1212
+ ```vue
1213
+ <template>
1214
+ <QyImageUpload
1215
+ v-model="payImgs"
1216
+ name="files"
1217
+ multiple
1218
+ :upload-request="uploadFile"
1219
+ />
1220
+ </template>
1221
+
1222
+ <script setup lang="ts">
1223
+ import { request } from '@qiyin/utils'
1224
+
1225
+ async function uploadFile({ formData }) {
1226
+ return request({
1227
+ url: '/permission-api/common/uploads',
1228
+ method: 'POST',
1229
+ data: formData
1230
+ })
1231
+ }
1232
+ </script>
1233
+ ```
1234
+
1235
+ ### QyRemarkImage
248
1236
 
249
- 单文件选择兼容组件,支持点击选择、拖拽、替换、清空以及后缀和大小校验;内部复用 `QyUpload` 的本地选择模式。
250
-
251
- - `v-model` 只输出浏览器原始 `File | null`。
252
- - `extensions` 忽略大小写,可传 `xls` 或 `.xlsx`。
253
- - `maxSizeMb` 的边界值允许,默认 20MB。
254
- - 校验失败触发 `invalid`,并保留原有 `modelValue`。
255
- - 组件只选择本地文件,不发送请求、不读取 token、不生成或保存 URL,也不复用 `QyUpload` 的业务上传协议。
256
-
257
- ```vue
258
- <QyFilePicker
259
- v-model="file"
260
- :extensions="['xls', 'xlsx']"
261
- :max-size-mb="20"
262
- placeholder="选择或拖拽 Excel 文件"
263
- @invalid="handleInvalid"
264
- />
265
- ```
266
-
267
- ### `QySwitch`
268
-
269
- 受控开关组件,`modelValue`、`activeValue`、`inactiveValue` 和 `update:modelValue` / `change` payload 均为 `boolean | string | number`,不进行隐式布尔化。
270
-
271
- ```vue
272
- <QySwitch
273
- v-model="enabled"
274
- active-text="启用"
275
- inactive-text="停用"
276
- @change="handleChange"
277
- />
278
- ```
279
-
280
- 支持 `disabled`、`loading`、`size`、`inlinePrompt`、`name`、`id`、`tabindex` 和 `ariaLabel`,以及 `class`、`style`、`role`、`title`、`data-*`、其它 `aria-*` 安全属性。只发出 `update:modelValue`、`change`、`focus`、`blur`;不提供 `beforeChange`、`input`、图标/slot 或底层实例、focus/blur 等命令式方法。
281
-
282
- ### `QyTag`
283
-
284
- 通用紧凑标签,内部使用 `ElTag`,公开 `tone`、`size`、`effect`、`closable`、`round`、`disabled` 和默认 slot。`tone` 支持 `neutral`、`primary`、`success`、`warning`、`danger`、`info`;`size` 为 `sm`、`md`、`lg`,默认分别映射为 Element Plus 的 `small`、`default`、`large`。
285
-
286
- ```vue
287
- <QyTag tone="success" size="sm" closable @close="removeTag">
288
- 已完成
289
- </QyTag>
290
- ```
291
-
292
- `disabled` 会设置 `aria-disabled="true"`、隐藏关闭按钮并抑制 `click` / `close`;非禁用状态下这两个事件各发出一次 `MouseEvent`。支持 `class`、`style`、`title`、`role`、`data-*`、`aria-*` 安全属性,不公开 `color`、`hit`、`disableTransitions` 或底层 Element Plus 实例。QyTag 不是按钮,不新增键盘按钮语义;需要动作语义时使用 `QyButton`。
293
-
294
- ### `QyBadge`
295
-
296
- `QyBadge` 基于 Element Plus `ElBadge` 渲染只读徽标,不管理未读状态、通知或点击逻辑。支持数字与文字、数字上限、圆点、隐藏、零值策略、五种语义类型、自定义颜色、偏移以及徽标内部样式和类名。
297
-
298
- ```vue
299
- <QyBadge :value="unreadCount" :max="99" type="danger">
300
- <QyButton>消息</QyButton>
301
- </QyBadge>
302
-
303
- <QyBadge value="!" is-dot>
304
- <span>待处理</span>
305
- <template #content="{ value }">数量:{{ value }}</template>
306
- </QyBadge>
307
- ```
308
-
309
- `value` 默认为空字符串,`max` 默认为 `99`,`type` 默认为 `danger`,`showZero` 默认为 `true`,`offset` 默认为 `[0, 0]`。上限只作用于数字,字符串原样显示;`content` 插槽收到经过圆点和上限规则处理后的只读 `{ value: string }`,组件公开的 `content` 也只有最终显示内容,不暴露 Element Plus 实例。根节点安全透传 `class`、`style`、`id`、`role`、`title`、`data-*` 和 `aria-*`,不声明事件、`v-model` 或尺寸参数。
310
-
311
- ### `QyTooltip`
312
-
313
- 只读提示组件。默认插槽是唯一触发内容,不增加触发元素包装 DOM;`content` 插槽(content slot)优先于 `content` 属性。组件支持 hover / focus、完整 `placement`、`light` / `dark` effect、延迟、偏移和可收缩的 `maxWidth`。
314
-
315
- ```vue
316
- <QyTooltip content="说明文字" placement="top-start">
317
- <button type="button">查看提示</button>
318
- </QyTooltip>
319
-
320
- <QyTooltip content="属性内容">
321
- <button type="button">插槽内容</button>
322
- <template #content>只读插槽内容</template>
323
- </QyTooltip>
324
- ```
325
-
326
- 默认值为 `placement="top"`、`effect="dark"`、`disabled=false`、`showDelay=0`、`hideDelay=200`、`offset=12`、`maxWidth=320`。事件只有 `open` / `close`,且只在实际可见状态转换时各发一次;不公开 `trigger`、受控 `open`、raw HTML、交互内容、Element Plus attrs/listeners 或实例方法。
327
-
328
- ### `QyPopover`
329
-
330
- 交互浮层组件。`reference` 插槽是触发元素,默认插槽是可交互面板内容,不增加触发元素包装 DOM;支持 `click`、`hover`、`focus`、`contextmenu`、完整 `placement`、`light` / `dark` effect、数字或 CSS 字符串 `width`、延迟、偏移、箭头和窄视口收缩。
331
-
332
- ```vue
333
- <QyPopover placement="bottom-start" :width="280" @open-change="onOpenChange">
334
- <template #reference><button type="button">打开操作</button></template>
335
- <button type="button" @click="submit">确认</button>
336
- </QyPopover>
337
-
338
- <QyPopover v-model:open="open" trigger="contextmenu">
339
- <template #reference><div>右键区域</div></template>
340
- <div>受控交互内容</div>
341
- </QyPopover>
342
- ```
343
-
344
- 默认值为 `trigger="click"`、`placement="bottom"`、`effect="light"`、`width=240`、`offset=12`、`showDelay=0`、`hideDelay=200`、`showArrow=true`、`disabled=false`。`open` 未传时组件内部管理状态,传入时通过 `v-model:open` 由父级回传决定状态;`update:open` 是状态意图,`open-change` / `open` / `close` 只在实际显隐转换时发出。唯一暴露的方法是 `close()`,不公开 Element Plus 实例、定位更新、`teleported`、`appendTo` 或 `popperOptions`。
345
-
346
- ### `QyPopconfirm`
347
-
348
- 二次确认浮层,提供 Qy-owned 的确认、取消、加载锁、关闭原因和焦点恢复语义。支持 `reference`、`title`、`icon` 插槽;`open` 可选受控,确认成功后的父级关闭会以 `close('external')` 记录,异步失败保持打开并允许重试。
349
-
350
- ```vue
351
- <QyPopconfirm
352
- title="确认删除?"
353
- variant="danger"
354
- confirm-type="danger"
355
- :confirm-loading="saving"
356
- :close-on-confirm="false"
357
- @confirm="save"
358
- @close="onClose"
359
- >
360
- <template #reference><button type="button">删除</button></template>
361
- </QyPopconfirm>
362
- ```
363
-
364
- 事件为 `update:open`、`open-change`、`confirm`、`cancel` 和 `close(reason)`;关闭原因是 `confirm`、`cancel`、`outside`、`escape`、`trigger`、`external` 或 `disabled`。不公开 Element Plus 类型、实例、teleport 或 popper 参数。
365
-
366
- ### `QySkeleton` 与 `QySkeletonItem`
367
-
368
- 加载骨架组件基于 Element Plus 的 `ElSkeleton` / `ElSkeletonItem` 渲染。`loading` 由业务受控,加载期间使用 `template` 插槽,加载完成后使用默认插槽;支持 `animated`、`count`、`rows` 及数字或对象形式的 `throttle`。
369
-
370
- ```vue
371
- <QySkeleton :loading="loading" animated :count="2">
372
- <template #template>
373
- <QySkeletonItem variant="rect" style="height: 120px" />
374
- </template>
375
- <div>真实内容</div>
376
- </QySkeleton>
377
- ```
378
-
379
- `QySkeletonItem` 的 `variant` 支持 `p`、`text`、`h1`、`h3`、`caption`、`button`、`image`、`circle`、`rect`,默认值为 `text`。两者均支持 `class`、`style`、`role`、`title`、`data-*` 和 `aria-*`,不公开 Element Plus 实例。
380
-
381
- ### `QyLoading`
382
-
383
- `QyLoading` 安装后注册 `v-qy-loading` 指令,并配置命令式 `openQyLoading` 服务。指令支持布尔值或 `{ active, text, maskColor, lockScroll }` 对象;服务未传 `target` 时覆盖 body,传入 HTMLElement 时只覆盖该容器。同一目标的多个句柄共享一个遮罩,最后一个句柄调用 `close()` 后才移除。
384
-
385
- ```vue
386
- <script setup>
387
- import { ref } from 'vue'
388
- import { openQyLoading } from '@qynpm/ui/qy-loading'
389
-
390
- const loading = ref(false)
391
- const target = ref(null)
392
-
393
- function load() {
394
- const handle = openQyLoading({ target: target.value, text: '加载中' })
395
- // 请求完成后调用一次即可,重复 close 不会影响后续 loading。
396
- handle.close()
397
- }
398
- </script>
399
-
400
- <template>
401
- <div ref="target" v-qy-loading="{ active: loading, lockScroll: true }">
402
- 容器内容
403
- </div>
404
- </template>
405
- ```
406
-
407
- ### `QyDrawer`
408
-
409
- `QyDrawer` 使用 Qy-owned props、事件和插槽封装抽屉容器,支持四方向、数字尺寸、遮罩/Escape 关闭原因、指定 `teleportTo` 容器、焦点恢复和重叠抽屉顶层响应。`header`、默认内容和 `footer` 插槽均接收 Qy-owned `close()`。
410
-
411
- ```vue
412
- <script setup>
413
- import { ref } from 'vue'
414
- import QyDrawer from '@qynpm/ui/qy-drawer'
415
-
416
- const open = ref(false)
417
- </script>
418
-
419
- <template>
420
- <button type="button" @click="open = true">查看订单</button>
421
- <QyDrawer v-model="open" title="订单详情" placement="right" @close="open = false">
422
- <p>抽屉内容</p>
423
- <template #footer="{ close }">
424
- <button type="button" @click="close">关闭</button>
425
- </template>
426
- </QyDrawer>
427
- </template>
428
- ```
429
-
430
- ### `QyResult`
431
-
432
- `QyResult` 统一展示成功、警告、信息、错误和 401/403/404/500 结果。它只负责结果视觉、标题、说明、图片和操作区,不负责路由、返回、刷新、重试、请求或状态管理;业务动作由消费者放入 `actions` 插槽。
433
-
434
- ```vue
435
- <script setup>
436
- import QyResult from '@qynpm/ui/qy-result'
437
- </script>
438
-
439
- <template>
440
- <QyResult status="404" title="页面不存在" description="请检查地址">
441
- <template #actions>
442
- <button type="button" @click="goHome">返回首页</button>
443
- </template>
444
- </QyResult>
445
- </template>
446
- ```
447
-
448
- `visual` 插槽优先于 `image`,`image` 优先于状态内置视觉;`title` 同时作为结果标题和根节点原生 `title`,`description` 与 `actions` 也支持同名插槽覆盖属性内容。根入口与 `@qynpm/ui/qy-result` 均提供 Qy-owned 类型,不公开 Element Plus 类型、实例或事件。
449
-
450
- ### `QyWatermark`
451
-
452
- `QyWatermark` 在容器内提供 Qy-owned 的平铺文字或图片水印,图片优先且加载失败回退到 `content`;`content` 支持多行文字,`font`、`rotate`、`width`、`height`、`gap` 和 `offset` 控制水印单元。水印覆盖层不接收指针事件,默认插槽中的按钮、图片和选择操作仍由消费者处理。
453
-
454
- ```vue
455
- <script setup>
456
- import QyWatermark from '@qynpm/ui/qy-watermark'
457
- </script>
458
-
459
- <template>
460
- <QyWatermark :content="['客户名称', '订单编号']" :rotate="-18">
461
- <div>订单内容</div>
462
- </QyWatermark>
463
- </template>
464
- ```
465
-
466
- 公开 interface 只包含 `content`、`image`、`zIndex`、`rotate`、`width`、`height`、`gap`、`offset` 和 Qy-owned `font`,以及安全容器属性 `class`、`style`、`id`、`title`、`role`、`data-*`、`aria-*`;不公开 Element Plus props、实例、DOM、事件或 expose。完整演示位于 `src/docs/QyWatermarkDoc.vue`,入口为 `@qynpm/ui/qy-watermark`。
467
-
468
- ### `QyTabs` 与 `QyTabPane`
469
-
470
- `QyTabs` 使用 Element Plus 的 `ElTabs` / `ElTabPane` 处理渲染、焦点与键盘行为。`modelValue` 传入时保持受控;`defaultValue` 仅提供初始选择。`tab-change`、`tab-remove`、`tab-add` 与 `edit` 都是意图事件,不会改写业务页签数组、路由或 AdminShell 运行时。
471
-
472
- ```vue
473
- <QyTabs v-model="current" editable @tab-add="addTab" @tab-remove="removeTab">
474
- <QyTabPane label="概览" name="overview">概览内容</QyTabPane>
475
- <QyTabPane label="详情" :name="2" lazy closable>详情内容</QyTabPane>
476
- </QyTabs>
477
- ```
478
-
479
- 支持 `type`(`'' | 'card' | 'border-card')、`tabPosition`、`stretch`、`closable`、`addable`、`editable`、`beforeLeave` 和 `tabindex`。`QyTabPane` 支持 `label`、字符串或数字 `name`、`closable`、`disabled`、`lazy` 与 `label` 插槽。`tab-click` 的首个参数是冻结的 `QyTabPaneSnapshot`,只包含 `name`、`label`、`disabled`、`closable`、`lazy`、`active`、`index`,不会泄漏 Element Plus 页签上下文或实例。
480
-
481
- ### `QyDescriptions` 与 `QyDescriptionsItem`
482
-
483
- `QyDescriptions` 使用 Element Plus 的 `ElDescriptions` / `ElDescriptionsItem` 处理描述列表的行列和单元格渲染。`QyDescriptionsItem` 是无 DOM 声明节点,父组件会递归处理直接子项、`v-if`、`v-for` 和 `template`/Fragment,再交给 Element Plus 完成 `span`、`rowspan`、宽度和对齐计算。
484
-
485
- ```vue
486
- <QyDescriptions border :column="3" title="订单详情">
487
- <template #extra><QyLink href="/orders">查看全部</QyLink></template>
488
- <QyDescriptionsItem label="编号">SO-2026-001</QyDescriptionsItem>
489
- <QyDescriptionsItem label="摘要" :span="2" :rowspan="2">复杂内容也可放入默认插槽。</QyDescriptionsItem>
490
- <QyDescriptionsItem label="金额" align="right">¥12,800.00</QyDescriptionsItem>
491
- </QyDescriptions>
492
- ```
493
-
494
- 父级支持 `border`、`column`、`direction`、`size`(`'' | 'large' | 'default' | 'small'`)、`title`、`extra`、`labelWidth` 以及默认、`title`、`extra` 插槽;插槽优先于同名文本属性。描述项支持 `label`、`span`、`rowspan`、`width`、`minWidth`、`labelWidth`、`align`、`labelAlign`、`className`、`labelClassName` 以及默认和 `label` 插槽。组件只安全透传根节点的 `class`、`style`、`id`、`title`、`role`、`data-*`、`aria-*`,不公开事件、状态或 Element Plus 实例。
495
-
496
- ### `QyUpload`
497
-
498
- 上传组件,支持:
499
-
500
- - 图片上传
501
- - 视频上传
502
- - 粘贴上传
503
- - 拖拽上传
504
- - 文本备注
505
- - 预览
506
- - `v-model`
507
- - `valueFormat`
508
- - 纯图片模式
509
- - 普通文件列表模式
510
- - 只选择本地文件而不上传
511
-
512
- 当前可配置项里,和宿主耦合最强的是上传配置:
513
-
514
- - `api`
515
- - `tokenKey`
516
- - `name`
517
- - `uploadRequest`
518
-
519
- 其中:
520
-
521
- - `api` 为必填
522
- - `tokenKey` 不传时默认使用 `Admin-Token`
523
- - `name` 不传时默认使用 `file`
524
- - `uploadRequest` 可接入宿主项目自己的 request、baseURL、鉴权和错误处理;不传时使用组件默认 XHR 上传
525
- - 新代码应由宿主 `uploadRequest` adapter 返回已经完成 baseURL 归一化的完整 URL;组件不拼接消费者的相对文件地址
526
-
527
- 值协议:
528
-
529
- - 默认 `valueFormat="object"`,`v-model` 输出 `{ files: string[], text: string }`
530
- - `valueFormat="array"`,`v-model` 输出 `string[]`
531
- - `valueFormat="string"`,`v-model` 输出逗号分隔 URL
532
- - `showText=false` 可隐藏文字备注区;如仍需粘贴入口,可开启 `showPasteInput`
533
- - `defaultValue` 仍保留给老页面做非受控初始化;新页面建议优先使用 `v-model`
534
- - `variant="file-list"` 使用普通文件列表;默认 `media-card` 行为保持不变
535
- - `autoUpload=false` 时不调用 transport,使用 `v-model:selected-files` 读写浏览器原始 `File[]`
536
-
537
- ### `QyImageUpload`
538
-
539
- 图片/文件字段上传组件,基于 `QyUpload` 的薄封装,适合商品图、设计图、成本附图、凭证图片集合、单视频字段等场景。
540
-
541
- 固定协议:
542
-
543
- - 默认 `multiple=false`,`v-model` 为单个 URL 字符串
544
- - `multiple=true` 时,`v-model` 为 URL 数组
545
- - 单图默认 `limit=1`,多图默认 `limit=9`
546
- - 默认 `name="files"`
547
- - 默认 `showText=false`
548
- - 默认开启纯粘贴输入条
549
- - 默认 `size="128px"`
550
- - 支持 `supportVideo`、`fileType`、`fileSize`
551
- - 支持透传 `uploadRequest`,用于接入宿主项目上传请求
552
-
553
- 凭证上传模式:
554
-
555
- - `mode="voucher"` 或 `voucher` 可启用凭证图片场景。
556
- - 默认允许 `jpg / jpeg / png / gif / bmp / webp`。
557
- - 默认 `limit=30`,保留纯粘贴入口,适合收款凭证、成本附图等旧 `CopyImgUpload` 使用点。
558
- - 暴露 `getFullPathList()` 和 `fullPathList`,兼容旧页面 `ref.fullPathList.join(',')` 的读值方式。
559
- - 上传成功时额外触发 `updateImg(url)`,兼容旧 `CopyImgUpload` 的成功通知语义。
560
-
561
- `QyImageUpload` 不保留旧 `imageUpload` 的 `successUpload(fileList)` 回调。旧页面迁移时优先改为 `v-model`;确实依赖旧 `CopyImgUpload` 读值方式的页面,可先用凭证模式的 `fullPathList / getFullPathList()` 过渡。
562
-
563
- ### `QyImage`
564
-
565
- 图片展示组件,计划承接旧 `packages/qiyin/components/Image`,并作为 `@qynpm/table-schema` 的 `image` 列渲染底座。
566
-
567
- 这是后续替代旧 `useCol` 的前置组件。旧 `useCol/render/imageRender.vue` 的表格列渲染不应该在 `@qynpm/table-schema` 内重复维护一套通用图片组件,而应组合 `QyImage`。
568
-
569
- 必须完整覆盖旧能力:
570
-
571
- - `src` 图片地址。
572
- - `width / height / size` 缩略图尺寸。
573
- - `fit` 图片填充方式,透传 `ElImage`。
574
- - 加载中状态。
575
- - 加载失败状态。
576
- - `error` 事件。
577
- - `placeholder` 空图占位。
578
- - `compressor` 压缩缩略图参数。
579
- - 旧域名兼容:`ys.diansan.com` 地址迁移为 `https://admin.qiyinbz.com`。
580
- - 旧缩略图参数:点三域名使用 `?small=true&style=image/resize,h_{h},w_{w}`,其他域名使用 `?w={w}`。
581
- - 失败兜底:缩略图请求失败后请求原图 blob,并用浏览器 canvas 压缩成 dataURL 展示。
582
- - `preview / previewList / initialIndex` 图片预览。
583
-
584
- 失败兜底属于旧公共图片组件能力,不是录单业务逻辑。当前实现不新增 `compressorjs`,使用浏览器原生 `fetch + blob + canvas` 完成压缩;如果后续发现必须完全等价旧 `compressorjs` 的压缩细节,再单独评估是否新增依赖。
585
-
586
- 建议新组件 API:
587
-
588
- ```ts
589
- type QyImageProps = {
590
- src?: string
591
- width?: number | string
592
- height?: number | string
593
- size?: number
594
- fit?: 'fill' | 'contain' | 'cover' | 'none' | 'scale-down'
595
- placeholder?: boolean
596
- compressor?: boolean | {
597
- w?: number
598
- h?: number
599
- q?: number
600
- }
601
- preview?: boolean
602
- previewList?: string[]
603
- initialIndex?: number
604
- }
605
- ```
606
-
607
- 表格 image 列后续直接组合 `QyImage` 和 `QyImagePreview`,不要在 `@qynpm/table-schema` 里复制一份通用图片组件。
608
-
609
- 已完成:
610
-
611
- - 创建 `@qiyin/UI/qy-image` 入口。
612
- - 创建 `src/docs/QyImageDoc.vue` playground 文档。
613
- - 补 `index.js / index.d.ts / package.json exports / files`。
614
- - 补构建入口,确保 `@qynpm/ui/qy-image` 可按需引入。
615
- - 补失败压缩兜底,不新增 `compressorjs`。
616
- - 补 `preview` 接入,可点击打开 `QyImagePreview`。
617
-
618
- ### `QyImagePreview`
619
-
620
- 图片预览组件,承接旧 `useCol/render/imageRender.vue` 中动态创建 `ElImageViewer` 的逻辑。
621
-
622
- 需要支持:
623
-
624
- - `urlList` 图片列表。
625
- - `initialIndex` 初始预览索引。
626
- - 打开时控制 `body.style.overflow = 'hidden'`。
627
- - 关闭时恢复 body 滚动并销毁实例。
628
- - 支持直接作为组件使用,也支持函数式调用,例如 `openQyImagePreview({ urlList, initialIndex })`。
629
-
630
- 该能力是 `@qynpm/table-schema` 完整迁移 image 列的前置能力。table-schema 不应该长期维护一份独立图片预览逻辑。
631
-
632
- ### `QyCheckbox`
633
-
634
- 受控复选框基础组件,基于 `ElCheckbox` 做隔离适配,`modelValue`、`trueValue`、`falseValue` 和事件 payload 均保持 `boolean | string | number` 原始类型,不做隐式布尔转换。
635
-
636
- 支持 `value`(为后续 `QyCheckboxGroup` 保留的选项值)、只读展示状态 `indeterminate`、`disabled`、`size` 和默认 slot。事件只有 `update:modelValue`、`change`、`focus`、`blur`;禁用状态不产生值变更意图,也不公开 Element Plus 实例或命令式方法。
637
-
638
- ```vue
639
- <QyCheckbox
640
- v-model="ticketValue"
641
- true-value="Y"
642
- false-value="N"
643
- aria-label="开票"
644
- @change="handleChange"
645
- >
646
- 开票
647
- </QyCheckbox>
648
- ```
649
-
650
- `class`、`style`、`id`、`name`、`role`、`title`、`data-*` 和 `aria-*` 会安全透传;桌面交互区域保持紧凑,窄屏下提升到至少 40px。`QyCheckboxGroup`、全选/级联和 `CheckboxButton` 不属于 V1。
651
-
652
- ### `QyRadio`
653
-
654
- 受控单选框基础组件,基于 `ElRadio` 做隔离适配。`value` 表示选中值,`label` 只负责展示;默认 slot 优先。`modelValue` 与事件 payload 保持 `boolean | string | number` 原始类型,父级不回写时组件不会自行改变状态,也不会通过再次点击取消选中。
655
-
656
- 支持 `disabled`、`size`、`name`、`border` 以及 `update:modelValue`、`change`、`focus`、`blur` 事件;安全透传 `class`、`style`、`role`、`title`、`data-*` 和 `aria-*`,不公开 Element Plus 实例或命令式方法。
657
-
658
- ```vue
659
- <QyRadio
660
- v-model="ticketType"
661
- value="invoice"
662
- label="开票"
663
- name="ticket-type"
664
- border
665
- @change="handleChange"
666
- />
667
- ```
668
-
669
- ### `QyCheckboxGroup`
670
-
671
- 受控复选框组,统一管理 `QyCheckboxValue[]`。支持默认 slot 或 `options`(两者同时存在时 slot 优先),并透传 `disabled`、`min`、`max`、`size`。事件只有 `update:modelValue` 和 `change`,每次更新都返回新数组。
672
-
673
- ```vue
674
- <QyCheckboxGroup v-model="selected" :options="[
675
- { label: '阅读', value: 'read' },
676
- { label: '写作', value: 'write', disabled: true }
677
- ]" />
678
- ```
679
-
680
- options 模式物理复用 `QyCheckbox`;不提供 CheckboxButton、全选、indeterminate 推导、树形/层级选择、布局 props 或 Element Plus 实例。
681
-
682
- ### `QyAutocomplete`
683
-
684
- 自动完成输入基础组件,基于 `ElAutocomplete` 做薄封装,支持本地 `options` 过滤和 Element Plus 原生 `fetchSuggestions` 透传。
685
-
686
- 默认协议:
687
-
688
- - `v-model` 绑定输入值。
689
- - `options` 支持 `{ value }` 列表,也支持通过 `valueKey` 映射其它字段。
690
- - 默认按 `option.value.includes(query)` 过滤。
691
- - 支持 `select / change / input / clear / focus / blur` 事件。
692
-
693
- 该组件作为 `@qynpm/table-schema` 的 `edit-autocomplete` 渲染器底座,表格 row 写回逻辑仍留在 table-schema。
694
-
695
- ### `QyMenuActions`
696
-
697
- 表格行操作 UI 底座,承接旧 `useCol/render/menu.vue` 的通用展示能力。
698
-
699
- 支持:
700
-
701
- - `inline` 横向操作模式。
702
- - `popover` 更多操作模式。
703
- - `actions` 列表。
704
- - `hidden / disabled / loading` 支持布尔值或按行上下文计算。
705
- - `type` 控制默认、主色、成功、警告、危险操作色。
706
- - `confirmMethod(action, context)` 由宿主注入确认逻辑。
707
- - `action(action, context)` 只在可执行且确认通过后触发。
708
-
709
- `QyMenuActions` 不内置权限、路由、缓存、弹窗实例、消息提示,也不直接执行业务方法。权限过滤和业务执行应留在 `@qynpm/table-schema` adapter 或宿主页面。
710
-
711
- ### `QyTableColumnSettings`
712
-
713
- 表格列设置 UI 底座,承接旧 `useCol/render/setup.vue` 的通用 UI 能力。
714
-
715
- 支持:
716
-
717
- - 列列表展示。
718
- - 当前选中列。
719
- - 置顶、置底、上移、下移。
720
- - 固定左侧、固定右侧、取消固定。
721
- - 列宽编辑。
722
- - 显隐开关。
723
- - 恢复默认。
724
- - 删除缓存。
725
-
726
- 业务缓存读写仍由 `@qynpm/table-schema` 的 settings adapter 或宿主 adapter 负责,UI 组件只负责展示和编辑 settings。
727
-
728
- ### 编辑类基础组件(待评估)
729
-
730
- 旧 `useCol` 的 `edit-input / edit-autocomplete` 有一套“展示态 -> 点击编辑 -> blur/enter 写回”的通用交互。后续有两种选择:
731
-
732
- - 如果表格外也需要该交互,补 `QyInlineEditInput` 和 `QyAutocompleteInput`。
733
- - 如果只服务表格列,先放在 `@qynpm/table-schema` renderer 内部,避免 UI 包过早扩大。
734
-
735
- ### `QyDialog`
736
-
737
- QyDialog 是受控弹窗组件,使用 Qy-owned 协议:
738
-
739
- - `open` / `update:open` / `open-change` 管理显隐
740
- - `confirm`、`cancel` 和 `close(reason)` 表达关闭意图;`reason` 为 `confirm | cancel | header | escape | overlay | external`
741
- - `confirm-loading` 在宿主异步业务期间锁定确认动作,业务成功后由宿主关闭
742
- - 默认 footer 由 `show-footer`、`show-confirm`、`show-cancel`、`confirm-text` 和 `cancel-text` 控制;自定义 `footer` 时不渲染默认按钮
743
- - 支持全屏切换、最小化、焦点恢复和顶层弹窗 Escape/遮罩仲裁
744
-
745
- ```vue
746
- <QyDialog
747
- :open="open"
748
- title="订单确认"
749
- :confirm-loading="saving"
750
- :close-on-confirm="false"
751
- @update:open="open = $event"
752
- @confirm="save"
753
- >
754
- 内容区域
755
- </QyDialog>
756
- ```
757
-
758
- 旧 `modelValue`、`layout`、`confirmProps`、`ok` 和 Element Plus attrs 不属于 QyDialog 公共面;过渡场景使用独立的 `@qynpm/qy-dialog-legacy` adapter,禁止新业务采用。
759
-
760
- ### `QyButton`
761
-
762
- 后台按钮统一入口,后续 AdminShell 和业务页按钮迁移时优先使用该组件,而不是直接写原生 `button` 或分散使用 `ElButton`。
763
-
764
- 核心能力:
765
-
766
- - `type="default | primary | success | warning | danger | text | ghost | link"` 控制视觉类型。
767
- - `size="sm | md | lg"` 控制高度、padding、gap、字号和图标尺寸,默认 `md`。
768
- - `disabled` 和 `loading` 都会阻止 `click` 事件;`loading` 会展示内置 loading 状态。
769
- - `active` 用于顶部当前系统、tabs 当前操作等选中态。
770
- - `block` 撑满父容器,`round` 显式开启胶囊圆角;默认后台圆角保持紧凑。
771
- - `native-type="button | submit | reset"` 控制原生按钮类型,默认 `button`。
772
- - `prefix-icon / suffix-icon` 只支持 Vue 组件图标;也可以通过 `prefix / suffix` 插槽传入前后图标;`icon-only` 必须提供 `aria-label` 或 `title`。
773
-
774
- 样式 token:
775
-
776
- - 尺寸类:`--qy-button-sm-height`、`--qy-button-md-height`、`--qy-button-lg-height`、`--qy-button-*-padding-x`、`--qy-button-*-gap`、`--qy-button-*-font-size`、`--qy-button-*-icon-size`。
777
- - 状态类:`--qy-button-default-*`、`--qy-button-primary-*`、`--qy-button-success-*`、`--qy-button-warning-*`、`--qy-button-danger-*`、`--qy-button-disabled-*`、`--qy-button-focus-ring`。
778
- - token 默认从 Element Plus 的 `--el-*` 设计变量取值,宿主可覆盖 `--qy-button-*` 做主题适配。
779
-
780
- ### `QyDropdown`
781
-
782
- 后台下拉菜单统一入口,后续 AdminShell、工具栏和更多操作菜单迁移时优先使用该组件,而不是在业务页面散落手写原生 dropdown DOM。
783
-
784
- 核心能力:
785
-
786
- - `items` 支持 `{ key, label, icon, disabled, danger, hidden, divided, active, title }`。
787
- - `hidden` 项不渲染,`disabled` 项不触发 `select`。
788
- - `danger` 和 `active` 项会输出稳定的 `is-danger` / `is-active` class,以及 `data-danger` / `data-active` 标记。
789
- - `trigger="click"` 为默认触发方式,预留 `contextmenu`。
790
- - `v-model` / `model-value` 支持受控打开状态;受控模式下只触发 `update:modelValue` 和 `open-change`,不私自决定最终打开状态。
791
- - `close-on-select=false` 可在选择后保持面板打开。
792
- - `panel-width` / `width` 和 `max-height` 控制面板尺寸。
793
- - `trigger`、`item`、`header`、`footer`、`empty` 插槽用于业务定制展示;`trigger` 插槽应把 `attrs` 绑定到实际触发按钮上。
794
-
795
- ### `QySelectionDialog`
796
-
797
- 数据选择弹窗底座,参考老 `@qiyin/components/Dialog` 的核心能力迁移,但不内置任何 ERP 接口或权限逻辑。
798
-
799
- 适合业务 wrapper 组合:
800
-
801
- - 店铺选择
802
- - 人员选择
803
- - 商品选择
804
- - 物料/工艺/属性选择
805
-
806
- 核心能力:
807
-
808
- - `QyDialog` 弹窗容器
809
- - `fetchMethod(query)` 或兼容老 `query(query)` 加载表格数据
810
- - `selectionMode="single | multiple | none"`,兼容老 `selection="single | multi | none"`
811
- - `modelValue` 管理确认后的已选行,`selected` 兼容老 `Dialog` 初始已选行
812
- - `rowKey` 控制唯一键
813
- - `labelKey` 控制已选标签展示
814
- - `searchKey`、分类、类型筛选
815
- - 类型筛选内部使用 `QySelect`,可通过 `typeSelectProps` 透传下拉属性
816
- - `columns` / `cols` 插槽渲染业务列
817
- - `side`、`search`、`toolbar` 插槽扩展业务区域
818
- - Element Plus 原生分页
819
-
820
- `QySelectionDialog` 只解决“怎么选”,不解决“选什么”。业务接口、字段映射、权限判断应放在宿主项目 wrapper 中。
821
-
822
- 迁移业务选择器前,建议先阅读:
823
-
824
- - [选择弹窗迁移规范](./选择弹窗迁移规范.md)
825
-
826
- 选择状态采用“弹窗草稿 + 确认提交”协议:
827
-
828
- - 行点击、勾选、删除标签、粘贴只修改弹窗内部草稿,并触发 `selection-change(rows)`。
829
- - 点击确认后才触发 `update:modelValue(rows)`、`confirm(rows)` 和兼容老 `Dialog` 的 `submit({ selection, rows, query })`。
830
- - 点击取消或关闭会丢弃草稿选择,不会污染宿主表单中的 `v-model`。
831
- - `search` / `handleQuerySearch` 会重置到第一页并查询;分页切换会按当前条件查询。
832
-
833
- 主要扩展点:
834
-
835
- - `columns` / `cols`:表格列,`cols` 用于兼容老 `Dialog`。
836
- - `side`:左侧业务区域,例如分类树、部门树。
837
- - `search`:完全自定义查询区,插槽参数为 `{ query, search, reset }`。
838
- - `toolbar`:搜索区右侧操作区,插槽参数为 `{ query, search }`。
839
- - `getTableRef`、`getTableData`、`getSelection`:用于业务 wrapper 做必要的桥接。
840
-
841
- ### `QyRemarkImage`
842
-
843
- 备注图片组件,承接旧 `@qiyin/components/remarkImage` 的“备注文本 + 单图”协议。
844
-
845
- 支持:
846
-
847
- - `defaultValue` 解析 `[url:图片地址]备注文本`
848
- - `defaultImage` 独立图片默认值
849
- - `change(value, imageUrl)` 输出完整备注值和图片地址
850
- - 粘贴图片上传
851
- - 悬浮预览和删除图片
852
- - `uploadRequest` 自定义上传请求
853
- - `layout="select-prefix"` 可把一个基础下拉值合并成输入前缀,用于“下拉值 + 图文备注”这类旧协议字段
854
- - `deleteImage()` / `clearContent()` / `getValue()` 暴露方法,兼容旧表单重置和读取协议值
855
-
856
- 默认上传会使用:
857
-
858
- - `api`,默认 `/permission-api/common/uploads`
859
- - `tokenKey`,默认 `Admin-Token`
860
- - `uploadName`,默认 `files`
861
-
862
- 如果宿主项目有统一 request、baseURL、鉴权、错误处理或登录失效处理,应优先传入 `uploadRequest`,不要在组件内部写死项目请求实现。
863
-
864
- 组合下拉输入:
865
-
866
- ```vue
867
- <QyRemarkImage
868
- layout="select-prefix"
869
- :select-value="postageValue"
870
- :select-options="[
871
- { label: '包邮', value: '包邮' },
872
- { label: '不包邮', value: '不包邮' }
873
- ]"
874
- placeholder="备注 / 粘贴图片"
875
- type="text"
876
- @update:select-value="postageValue = $event"
877
- @change="handleRemarkChange"
878
- />
879
- ```
880
-
881
- ### `QyInput`
882
-
883
- 输入组件,第一版定位为 `ElInput` 的轻量包装层,重点支持:
884
-
885
- - 保持和 `ElInput` 接近的使用方式
886
- - `removeSpace`
887
- - `trimMode`
888
- - `enter`
889
- - `textarea`
890
- - `modelValue` 支持 `string | number | null | undefined`,用户编辑事件统一输出 `string`
891
- - 兼容 `text`、`textarea`、`password`、`search` 和 Element Plus 常用属性
892
- - 兼容 `prefix`、`suffix`、`prepend`、`append` slots
893
- - 类型出口包含 `QyInputValue`、`QyInputModelValue`、`QyInputType`、`QyInputSize`、`QyInputAutoSize`、`QyInputIcon`、`QyInputInputMode`、`QyInputModelModifiers`、`QyInputStyle`、`QyInputProps`、`QyInputEmits` 和 `QyInputExposed`
894
- - 只公开 `focus`、`blur`、`select`、`clear`、`resizeTextarea` 方法
895
-
896
- ### `QyMoneyInput`
1237
+ 默认上传:
897
1238
 
898
- 金额输入组件,第一版定位为 `ElInput` 的金额录入包装层,公开类型包含 `QyMoneyInputValue`、`QyMoneyInputFormatTrigger`、`QyMoneyInputSize`、`QyMoneyInputProps`、`QyMoneyInputEmits`、`QyMoneyInputSlots` 和 `QyMoneyInputExposed`。重点支持:
899
-
900
- - 输入过程清洗非法字符
901
- - 默认失焦格式化为固定小数位
902
- - `precision`
903
- - `min / max`
904
- - `allowNegative`
905
- - `formatTrigger` 与 `emptyValue`
906
- - `placeholder`、`clearable`、`disabled`、`readonly`、`size`、`name`、`id`、`autocomplete`、`autofocus`、`maxlength`、`minlength`、`tabindex` 和 `ariaLabel`
907
- - `prefix`、`suffix`、`prepend`、`append` slots
908
- - `update:modelValue`、`input`、`change`、`focus`、`blur`、`clear`、`enter` 显式事件
909
- - 只公开 `focus()`、`blur()`、`select()`、`clear()` 方法
1239
+ ```vue
1240
+ <template>
1241
+ <QyRemarkImage
1242
+ :default-value="remark"
1243
+ api="/permission-api/common/uploads"
1244
+ upload-name="files"
1245
+ @change="handleRemarkChange"
1246
+ />
1247
+ </template>
910
1248
 
911
- 运行时暂保留 `getNativeInput()` 兼容方法,但其原生 DOM 返回值不属于 Qy 稳定类型契约,新消费者不应依赖。
1249
+ <script setup lang="ts">
1250
+ function handleRemarkChange(value: string, imageUrl?: string) {
1251
+ remark.value = value
1252
+ remarkImage.value = imageUrl || ''
1253
+ }
1254
+ </script>
1255
+ ```
912
1256
 
913
- ### `QyInputTag`
1257
+ 接入宿主项目上传请求:
914
1258
 
915
- 受控标签输入组件,内部使用 Element Plus 2.9 起提供的 `ElInputTag`。`modelValue` 始终为 `string[]`;`trigger` 支持 `enter` 和 `space`,`tagTone` / `tagEffect` 使用 Qy 标签语义,新增、删除、清空分别发出 `add`、`remove(value, index)`、`clear`,每次接受的变更只发出一次 `change`。仅公开 `focus()` 和 `blur()`。
1259
+ ```vue
1260
+ <template>
1261
+ <QyRemarkImage
1262
+ :default-value="remark"
1263
+ :upload-request="uploadRemarkImage"
1264
+ @change="handleRemarkChange"
1265
+ />
1266
+ </template>
1267
+
1268
+ <script setup lang="ts">
1269
+ import { request } from '@qiyin/utils'
1270
+
1271
+ async function uploadRemarkImage({ formData }) {
1272
+ return request({
1273
+ url: '/permission-api/common/uploads',
1274
+ method: 'POST',
1275
+ data: formData
1276
+ })
1277
+ }
1278
+
1279
+ function handleRemarkChange(value: string, imageUrl?: string) {
1280
+ remark.value = value
1281
+ remarkImage.value = imageUrl || ''
1282
+ }
1283
+ </script>
1284
+ ```
1285
+
1286
+ ### QyMenuActions
916
1287
 
917
1288
  ```vue
918
- <QyInputTag
919
- v-model="tags"
920
- clearable
921
- placeholder="输入标签后按 Enter"
922
- @add="handleAdd"
923
- @remove="handleRemove"
924
- @change="handleChange"
925
- />
1289
+ <template>
1290
+ <QyMenuActions
1291
+ :row="row"
1292
+ :row-index="0"
1293
+ :actions="actions"
1294
+ :confirm-method="confirmAction"
1295
+ @action="handleAction"
1296
+ />
1297
+ </template>
1298
+
1299
+ <script setup lang="ts">
1300
+ const row = { id: 1, status: 'draft' }
1301
+ const actions = [
1302
+ { key: 'edit', label: '编辑' },
1303
+ { key: 'delete', label: '删除', type: 'danger', confirm: true }
1304
+ ]
1305
+
1306
+ function confirmAction(action, context) {
1307
+ return window.confirm(`确认${action.label}?`)
1308
+ }
1309
+
1310
+ function handleAction(action, context) {
1311
+ // 业务执行、消息提示和权限判断留在宿主或 table-schema adapter。
1312
+ }
1313
+ </script>
926
1314
  ```
927
1315
 
928
- 支持 `max`、`size`、`disabled`、`readonly`、`autofocus`、`validateEvent`、`id`、`tabindex`、`maxlength`、`minlength`、`autocomplete`、`ariaLabel` 和 `tag`、`prefix`、`suffix` 插槽;不提供 delimiter、Tab 提交、拖拽、折叠标签或 `v-model:value` / `removeTag` 旧版兼容。
1316
+ ### QyTableColumnSettings
929
1317
 
930
- ### `QyInputNumber`
1318
+ ```vue
1319
+ <template>
1320
+ <QyTableColumnSettings
1321
+ v-model="visible"
1322
+ :settings="settings"
1323
+ :default-settings="defaultSettings"
1324
+ @confirm="saveSettings"
1325
+ @delete-cache="removeSettingsCache"
1326
+ />
1327
+ </template>
1328
+ ```
931
1329
 
932
- 数字输入组件,第一版定位为 `ElInputNumber` 的轻量包装层,公开契约由 Qy 自有类型定义;使用该组件时 Element Plus peer 保持 `^2.9.0` 或更高版本。
1330
+ ### QyButton
1331
+
1332
+ ```vue
1333
+ <template>
1334
+ <QyButton type="primary" :prefix-icon="Search" @click="handleSearch">
1335
+ 查询
1336
+ </QyButton>
1337
+ <QyButton loading>保存中</QyButton>
1338
+ <QyButton icon-only :prefix-icon="Refresh" aria-label="刷新当前页" />
1339
+ </template>
1340
+ ```
1341
+
1342
+ ### QyDropdown
1343
+
1344
+ ```vue
1345
+ <template>
1346
+ <QyDropdown
1347
+ :items="items"
1348
+ panel-width="168px"
1349
+ @select="handleSelect"
1350
+ >
1351
+ <template #trigger="{ attrs }">
1352
+ <QyButton v-bind="attrs">
1353
+ 更多
1354
+ </QyButton>
1355
+ </template>
1356
+ </QyDropdown>
1357
+ </template>
1358
+
1359
+ <script setup lang="ts">
1360
+ import QyButton from '@qynpm/ui/qy-button'
1361
+ import QyDropdown from '@qynpm/ui/qy-dropdown'
1362
+
1363
+ const items = [
1364
+ { key: 'profile', label: '个人信息' },
1365
+ { key: 'logout', label: '退出登录', danger: true, divided: true }
1366
+ ]
1367
+
1368
+ function handleSelect(item) {
1369
+ // 业务执行、路由跳转和权限判断留在宿主项目。
1370
+ }
1371
+ </script>
1372
+ ```
1373
+
1374
+ ### QyDialog
1375
+
1376
+ ```vue
1377
+ <template>
1378
+ <QyDialog :open="open" title="标题" close-on-confirm @update:open="open = $event">
1379
+ 内容区域
1380
+ </QyDialog>
1381
+ </template>
1382
+ ```
1383
+
1384
+ ### QyInput
1385
+
1386
+ ```vue
1387
+ <template>
1388
+ <QyInput
1389
+ v-model="quoteOrderCode"
1390
+ remove-space
1391
+ trim-mode="blur"
1392
+ placeholder="填写报价单,回车搜索"
1393
+ @enter="handleSearch"
1394
+ />
1395
+ </template>
1396
+ ```
1397
+
1398
+ ### QyMoneyInput
1399
+
1400
+ ```vue
1401
+ <template>
1402
+ <QyMoneyInput
1403
+ v-model="totalPay"
1404
+ :precision="2"
1405
+ :min="0"
1406
+ placeholder="请输入总金额"
1407
+ />
1408
+ </template>
1409
+ ```
1410
+
1411
+ ### QyInputNumber
1412
+
1413
+ ```vue
1414
+ <template>
1415
+ <QyInputNumber
1416
+ v-model="productNum"
1417
+ :min="0"
1418
+ :step="1"
1419
+ :precision="0"
1420
+ controls-position="right"
1421
+ placeholder="请输入数量"
1422
+ />
1423
+ </template>
1424
+ ```
1425
+
1426
+ ### QyDatePicker
1427
+
1428
+ ```vue
1429
+ <template>
1430
+ <QyDatePicker
1431
+ v-model="dateRange"
1432
+ type="datetimerange"
1433
+ value-format="YYYY-MM-DD HH:mm:ss"
1434
+ format="YYYY-MM-DD HH:mm:ss"
1435
+ :default-time="defaultTime"
1436
+ normalize-range-end-time
1437
+ />
1438
+ </template>
1439
+ ```
1440
+
1441
+ ### QyRadio
1442
+
1443
+ ```vue
1444
+ <template>
1445
+ <QyRadio
1446
+ v-model="ticketType"
1447
+ value="invoice"
1448
+ label="开票"
1449
+ />
1450
+ </template>
1451
+ ```
1452
+
1453
+ ### QyRadioGroup
1454
+
1455
+ ```vue
1456
+ <template>
1457
+ <QyRadioGroup
1458
+ v-model="openTicket"
1459
+ :options="ticketOptions"
1460
+ />
1461
+ </template>
1462
+ ```
1463
+
1464
+ 自定义选项展示:
1465
+
1466
+ ```vue
1467
+ <template>
1468
+ <QyRadioGroup v-model="openTicket" :options="ticketOptions">
1469
+ <template #option="{ option, label }">
1470
+ <span>{{ label }}</span>
1471
+ <span v-if="option.fee" style="margin-left: 6px; color: #f56c6c">
1472
+ {{ option.fee }}
1473
+ </span>
1474
+ </template>
1475
+ </QyRadioGroup>
1476
+ </template>
1477
+ ```
1478
+
1479
+ ### QySelect
1480
+
1481
+ ```vue
1482
+ <template>
1483
+ <QySelect
1484
+ v-model="shopCode"
1485
+ :options="shopOptions"
1486
+ placeholder="请选择店铺"
1487
+ />
1488
+ </template>
1489
+ ```
1490
+
1491
+ ### QyRemoteSelect
1492
+
1493
+ ```vue
1494
+ <template>
1495
+ <QyRemoteSelect
1496
+ v-model="recvAccount"
1497
+ :fetch-method="fetchFinanceAccounts"
1498
+ :default-options="accountDefaultOptions"
1499
+ label-key="accountName"
1500
+ value-key="accountId"
1501
+ placeholder="请选择收款账户"
1502
+ remote-on-focus
1503
+ @error="handleAccountError"
1504
+ />
1505
+ </template>
1506
+ ```
1507
+
1508
+ ### QyFormSection
1509
+
1510
+ ```vue
1511
+ <template>
1512
+ <QyFormSection title="订单信息" description="这里放订单表单区块">
1513
+ <el-form>...</el-form>
1514
+ </QyFormSection>
1515
+ </template>
1516
+ ```
1517
+
1518
+ ### QyActionBar
1519
+
1520
+ ```vue
1521
+ <template>
1522
+ <QyActionBar>
1523
+ <template #left>
1524
+ <el-button plain>开票</el-button>
1525
+ </template>
1526
+ <template #right>
1527
+ <el-button>保存</el-button>
1528
+ <el-button type="primary">提交</el-button>
1529
+ </template>
1530
+ </QyActionBar>
1531
+ </template>
1532
+ ```
1533
+
1534
+ ### QySearchInput
1535
+
1536
+ ```vue
1537
+ <template>
1538
+ <QySearchInput
1539
+ v-model="keyword"
1540
+ :fetch-suggestions-method="querySearch"
1541
+ :show-button="false"
1542
+ />
1543
+ </template>
1544
+ ```
1545
+
1546
+ ### QyRecordQuoteSearch
1547
+
1548
+ ```vue
1549
+ <template>
1550
+ <QyRecordQuoteSearch
1551
+ v-model="quoteOrderCode"
1552
+ :fetch-suggestions="fetchQuoteSuggestions"
1553
+ :search-method="handleQuoteSearch"
1554
+ @search="handleSearch"
1555
+ />
1556
+ </template>
1557
+ ```
1558
+
1559
+ ### QyCollapse
1560
+
1561
+ `QyCollapse` 与 `QyCollapseItem` 是 Element Plus 折叠面板的受控适配器。普通模式使用数组值,手风琴模式使用单个字符串或数字;`beforeCollapse` 同时拦截展开和收起。
1562
+
1563
+ ```vue
1564
+ <template>
1565
+ <QyCollapse v-model="activeNames" :before-collapse="beforeCollapse">
1566
+ <QyCollapseItem title="基本信息" name="base">内容</QyCollapseItem>
1567
+ <QyCollapseItem title="数字名称" :name="2" />
1568
+ </QyCollapse>
1569
+ </template>
1570
+
1571
+ <script setup>
1572
+ import { ref } from 'vue'
1573
+ import { QyCollapse, QyCollapseItem } from '@qynpm/ui'
1574
+
1575
+ const activeNames = ref(['base'])
1576
+ function beforeCollapse(name) {
1577
+ return name !== 'locked'
1578
+ }
1579
+ </script>
1580
+ ```
1581
+
1582
+ 通过 `ref` 可读取只读的 `activeNames`,并调用 `setActiveNames(value)` 设置完整公共值;标题和图标插槽都接收 `{ isActive }`。
1583
+
1584
+ ### QyLink
1585
+
1586
+ `QyLink` 基于 Element Plus `ElLink`,保留真实 `<a href>` 的浏览器焦点、Enter 激活和默认导航语义。支持六种语义类型、`always` / `never` / `hover` 下划线策略、禁用、原生链接地址和属性、图标属性及默认/图标插槽。
1587
+
1588
+ ```vue
1589
+ <QyLink
1590
+ href="https://example.com"
1591
+ target="_blank"
1592
+ rel="noopener noreferrer"
1593
+ type="primary"
1594
+ underline="hover"
1595
+ >
1596
+ 打开外部文档
1597
+ <template #icon>↗</template>
1598
+ </QyLink>
1599
+ ```
1600
+
1601
+ `disabled` 会移除有效 `href` 与 `target` 并抑制 `click`;非禁用点击只转发一次原生 `MouseEvent`。`type` 和 `underline` 未传时可继承 Element Plus ConfigProvider;布尔下划线仅作兼容,`true` 等同 `hover`、`false` 等同 `never`。不自动改写 `target` 或 `rel`,外部新窗口链接请显式提供 `rel="noopener noreferrer"`。无 href、只监听 `click` 的旧用法可以兼容,但新业务动作应使用 `QyButton`,路由导航应使用 RouterLink。
933
1602
 
934
- 重点支持:
935
-
936
- - 保持 `number / null` 值语义
937
- - `min / max`
938
- - `step`
939
- - `step-strictly`
940
- - `precision`
941
- - `controls / controls-position`
942
- - `valueOnClear`(默认 `null`,也支持 `min / max / number`)
943
- - `readonly / disabled / size / validateEvent`
944
- - `id / name / placeholder / ariaLabel`
945
- - `prefix / suffix / increase-icon / decrease-icon` slots
946
- - `update:modelValue / input / change / focus / blur` 显式事件
947
- - 兼容 `focus / blur` expose 方法
948
-
949
- 金额、费用、税费等财务录入场景请优先使用 `QyMoneyInput`,不要用 `QyInputNumber` 做金额格式化。
950
-
951
- ### `QyDatePicker`
952
-
953
- 日期选择组件,第一版定位为 `ElDatePicker` 的轻量包装层,重点支持:
954
-
955
- - 保持和 `ElDatePicker` 接近的使用方式
956
- - `date / datetime / daterange / datetimerange` 等常见类型
957
- - `format / value-format`
958
- - `default-time`
959
- - `shortcuts`
960
- - `disabled-date`
961
- - `year / month / date / dates / datetime / week / daterange / datetimerange / monthrange`
962
- - `clearable / disabled / readonly / teleported / append-to / popper-class`
963
- - `update:modelValue / change / clear / calendar-change / panel-change / visible-change / focus / blur`
964
- - `default / range-separator / prev-month / next-month / prev-year / next-year` slots
965
- - 仅公开 `focus() / blur() / open() / close()` expose 方法
966
-
967
- `normalize-range-end-time` 默认关闭。开启后只处理范围第二项:精确 `00:00:00.000` 的 `Date` 克隆为 `23:59:59.000`,带明确午夜时间的普通/ISO 字符串只替换时间并保留格式及 zone suffix;date-only 字符串、number、非午夜和非范围值保持原引用,不修改父数组或父 `Date`。
968
-
969
- ### `QyRadioGroup`
970
-
971
- 单选组组件,第一版定位为 `ElRadioGroup` 的轻量包装层,重点支持:
972
-
973
- - `options` 直出
974
- - `labelKey / valueKey / disabledKey` 映射
975
- - 普通单选 / 按钮式单选
976
- - 选项禁用
977
- - `option` 插槽自定义选项文案
978
- - 事件保持 `update:modelValue`、`change`
979
-
980
- `option` 插槽由外部传入,组件会透出当前选项的:
981
-
982
- - `option`:原始选项对象
983
- - `label`:映射后的展示文案
984
- - `value`:映射后的选项值
985
- - `disabled`:是否禁用
986
-
987
- 普通 `options` 模式物理复用 `QyRadio`;`type="button"` 继续使用内部 Element Plus button adapter。已发布的 `getRadioGroupInstance()` 仅为兼容保留并标记为 deprecated,不新增实例能力。
988
-
989
- ### `QySelect`
990
-
991
- 受控选择器组件。string、number、boolean、对象值和多选数组会原样通过 `update:modelValue` / `change` 返回;组件不会排序、克隆或隐式转换,父级 `modelValue` 始终是最终状态权威。
992
-
993
- - `options` 支持 `labelKey / valueKey / disabledKey` 字段映射;默认 slot 有实际内容时优先。
994
- - `valueKey` 只决定 option 的值字段;对象值需要稳定回显时,使用 `objectIdentityKey` 指定对象身份字段。
995
- - 支持单选、多选、disabled、clearable、filterable、loading、collapse tags、弹层挂载和 popper class。
996
- - `autoSelectSingle` 只在 options 模式、当前值为空且唯一 option 未禁用时触发一次 `update:modelValue` 后再触发一次 `change`;父值变为非空后再次清空可重新触发。
997
- - 保留 prefix、empty、loading、tag 和 default slots,以及 clear、visible-change、focus、blur 事件。
998
- - 只公开 `focus()` / `blur()`,不公开 Element Plus 实例或 DOM 引用。
999
-
1000
- ```vue
1001
- <QySelect
1002
- v-model="selectedUser"
1003
- :options="userOptions"
1004
- label-key="name"
1005
- value-key="user"
1006
- object-identity-key="id"
1007
- />
1008
- ```
1009
-
1010
- 远程请求、防抖和已选项缓存仍由 `QyRemoteSelect` 负责;`QySelect` 不承接业务字典或请求状态编排。
1011
-
1012
- ### `QyTreeSelect`
1013
-
1014
- 树选择组件以 `ElTreeSelect` 作为唯一树、勾选、过滤、键盘和浮层实现,重点支持:
1015
-
1016
- - `data` 树数据直出,`options` 作为兼容入口;同时传入时 `data` 优先,节点与数组保持原始引用
1017
- - `labelKey / valueKey / childrenKey / disabledKey` 快捷字段与 `props` 映射(显式 `props` 优先)
1018
- - string、number、boolean、对象和多选数组的受控值;对象值必须配置稳定的 `nodeKey`
1019
- - 单选 / 多选
1020
- - `check-strictly`
1021
- - `collapse-tags`
1022
- - 默认弹层挂载策略
1023
- - 保留原始节点字段,便于业务 slot 和后续透传使用
1024
-
1025
- `QyTreeSelect` 只处理树选择器的通用 UI 协议,不内置远程请求、权限过滤或业务接口格式化。节点插槽、回调和事件只提供原始数据与安全快照;公开实例只有 `focus()` 和 `blur()`,不会暴露 Element Node、Store 或组件实例。
1026
-
1027
- 为降低迁移成本,`QyTreeSelect` 的 `clearable`、`filterable`、`check-strictly`、`render-after-expand`、`fit-input-width` 等默认行为尽量跟随 `ElTreeSelect`。业务需要搜索、清空、父子不联动时应显式传参。
1028
-
1029
- ### `QyRemoteSelect`
1030
-
1031
- 远程选择器组件,基于 `QySelect` 组合实现,重点支持:
1032
-
1033
- - `fetchMethod(keyword)` 远程请求
1034
- - `debounce`
1035
- - `minLength`
1036
- - `defaultOptions`
1037
- - `remoteOnFocus`
1038
- - 内部请求 `loading`
1039
- - `error`
1040
- - `options-change`
1041
- - 已选项缓存,避免远程 options 清空后回显丢 label
1042
- - 继承 `QySelect` 的字段映射、多选、折叠标签、唯一选项自动选中能力
1043
-
1044
- 如果只是本地 options 下拉,应优先使用 `QySelect`;只有需要远程请求、搜索和回显保留时再使用 `QyRemoteSelect`。
1045
-
1046
- ### `QyFormSection`
1047
-
1048
- 区块容器组件,适合录单页面的表单区块外壳,重点支持:
1049
-
1050
- - 标题
1051
- - 描述
1052
- - 操作区 slot
1053
- - 提示区
1054
- - 简单折叠
1055
- - 统一边框、背景和间距
1056
-
1057
- ### `QyActionBar`
1058
-
1059
- 底部操作栏组件,适合录单页面底部按钮区,重点支持:
1060
-
1061
- - sticky 吸底
1062
- - 左右分区
1063
- - 窄屏换行
1064
- - 边框 / 阴影
1065
- - 底部安全区适配
1066
-
1067
- ### `QySearchInput`
1068
-
1069
- 搜索输入组件,支持:
1070
-
1071
- - 基于 `ElAutocomplete` 的等价封装
1072
- - 搜索按钮
1073
- - 回车搜索
1074
- - 本地建议项
1075
- - 远程建议项
1076
- - 兼容 `fetch-suggestions(queryString, cb)` 回调风格
1077
- - 高亮匹配词
1078
- - 默认使用 Element Plus 弹层挂载策略,避免被父级裁剪
1079
- - 平铺项和分组项两种建议结构
1080
-
1081
- ### `QyRecordQuoteSearch`
1082
-
1083
- 录单报价单号搜索组件,支持:
1084
-
1085
- - 报价单号输入
1086
- - 报价单号提取与规范化
1087
- - 搜索触发
1088
- - 建议项选择
1089
- - 局部状态提示
1090
- - `loading-change / success / error` 事件
1091
-
1092
- ## 样式说明
1093
-
1094
- - 包内样式会跟随构建产物一起注入
1095
- - 宿主仍然需要自行引入 `element-plus/dist/index.css`
1096
- - 当前组件内部仍然依赖宿主提供的 Tailwind / Iconify 体系能力
1097
-
1098
- ## 使用示例
1099
-
1100
- ### QyUpload
1101
-
1102
- ```vue
1103
- <template>
1104
- <QyUpload
1105
- v-model="uploadValue"
1106
- api="/permission-api/common/uploads"
1107
- token-key="Admin-Token"
1108
- @change="handleChange"
1109
- />
1110
- </template>
1111
- ```
1112
-
1113
- 纯图片上传:
1114
-
1115
- ```vue
1116
- <template>
1117
- <QyUpload
1118
- v-model="payImgs"
1119
- api="/permission-api/common/uploads"
1120
- name="files"
1121
- value-format="array"
1122
- :show-text="false"
1123
- :show-paste-input="true"
1124
- paste-placeholder="粘贴图片上传"
1125
- size="90px"
1126
- />
1127
- </template>
1128
- ```
1129
-
1130
- ### QyImageUpload
1131
-
1132
- 单图字段:
1133
-
1134
- ```vue
1135
- <template>
1136
- <QyImageUpload
1137
- v-model="imageUrl"
1138
- api="/permission-api/common/uploads"
1139
- :file-size="5"
1140
- />
1141
- </template>
1142
- ```
1143
-
1144
- ### QyImage
1145
-
1146
- ```vue
1147
- <template>
1148
- <QyImage
1149
- src="https://img.example.com/a.jpg"
1150
- :size="48"
1151
- fit="cover"
1152
- preview
1153
- :compressor="{ w: 200, h: 200, q: 50 }"
1154
- />
1155
- </template>
1156
- ```
1157
-
1158
- 函数式预览:
1159
-
1160
- ```ts
1161
- import { openQyImagePreview } from '@qynpm/ui'
1162
-
1163
- openQyImagePreview({
1164
- urlList: ['https://img.example.com/a.jpg'],
1165
- initialIndex: 0
1166
- })
1167
- ```
1168
-
1169
- 多图字段:
1170
-
1171
- ```vue
1172
- <template>
1173
- <QyImageUpload
1174
- v-model="payImages"
1175
- api="/permission-api/common/uploads"
1176
- multiple
1177
- :limit="9"
1178
- />
1179
- </template>
1180
- ```
1181
-
1182
- 凭证上传模式,迁移旧 `CopyImgUpload`:
1183
-
1184
- ```vue
1185
- <template>
1186
- <QyImageUpload
1187
- ref="payImgRef"
1188
- v-model="payImages"
1189
- mode="voucher"
1190
- api="/permission-api/common/uploads"
1191
- :multiple="false"
1192
- size="100px"
1193
- />
1194
- </template>
1195
-
1196
- <script setup>
1197
- import { ref } from 'vue'
1198
-
1199
- const payImages = ref('')
1200
- const payImgRef = ref(null)
1201
-
1202
- function getForms() {
1203
- return {
1204
- erpOrderPayImg: payImgRef.value.getFullPathList().join(',')
1205
- }
1206
- }
1207
- </script>
1208
- ```
1209
-
1210
- 接入宿主项目上传请求:
1211
-
1212
- ```vue
1213
- <template>
1214
- <QyImageUpload
1215
- v-model="payImgs"
1216
- name="files"
1217
- multiple
1218
- :upload-request="uploadFile"
1219
- />
1220
- </template>
1221
-
1222
- <script setup lang="ts">
1223
- import { request } from '@qiyin/utils'
1224
-
1225
- async function uploadFile({ formData }) {
1226
- return request({
1227
- url: '/permission-api/common/uploads',
1228
- method: 'POST',
1229
- data: formData
1230
- })
1231
- }
1232
- </script>
1233
- ```
1234
-
1235
- ### QyRemarkImage
1236
-
1237
- 默认上传:
1238
-
1239
- ```vue
1240
- <template>
1241
- <QyRemarkImage
1242
- :default-value="remark"
1243
- api="/permission-api/common/uploads"
1244
- upload-name="files"
1245
- @change="handleRemarkChange"
1246
- />
1247
- </template>
1248
-
1249
- <script setup lang="ts">
1250
- function handleRemarkChange(value: string, imageUrl?: string) {
1251
- remark.value = value
1252
- remarkImage.value = imageUrl || ''
1253
- }
1254
- </script>
1255
- ```
1256
-
1257
- 接入宿主项目上传请求:
1258
-
1259
- ```vue
1260
- <template>
1261
- <QyRemarkImage
1262
- :default-value="remark"
1263
- :upload-request="uploadRemarkImage"
1264
- @change="handleRemarkChange"
1265
- />
1266
- </template>
1267
-
1268
- <script setup lang="ts">
1269
- import { request } from '@qiyin/utils'
1270
-
1271
- async function uploadRemarkImage({ formData }) {
1272
- return request({
1273
- url: '/permission-api/common/uploads',
1274
- method: 'POST',
1275
- data: formData
1276
- })
1277
- }
1278
-
1279
- function handleRemarkChange(value: string, imageUrl?: string) {
1280
- remark.value = value
1281
- remarkImage.value = imageUrl || ''
1282
- }
1283
- </script>
1284
- ```
1285
-
1286
- ### QyMenuActions
1287
-
1288
- ```vue
1289
- <template>
1290
- <QyMenuActions
1291
- :row="row"
1292
- :row-index="0"
1293
- :actions="actions"
1294
- :confirm-method="confirmAction"
1295
- @action="handleAction"
1296
- />
1297
- </template>
1298
-
1299
- <script setup lang="ts">
1300
- const row = { id: 1, status: 'draft' }
1301
- const actions = [
1302
- { key: 'edit', label: '编辑' },
1303
- { key: 'delete', label: '删除', type: 'danger', confirm: true }
1304
- ]
1305
-
1306
- function confirmAction(action, context) {
1307
- return window.confirm(`确认${action.label}?`)
1308
- }
1309
-
1310
- function handleAction(action, context) {
1311
- // 业务执行、消息提示和权限判断留在宿主或 table-schema adapter。
1312
- }
1313
- </script>
1314
- ```
1315
-
1316
- ### QyTableColumnSettings
1317
-
1318
- ```vue
1319
- <template>
1320
- <QyTableColumnSettings
1321
- v-model="visible"
1322
- :settings="settings"
1323
- :default-settings="defaultSettings"
1324
- @confirm="saveSettings"
1325
- @delete-cache="removeSettingsCache"
1326
- />
1327
- </template>
1328
- ```
1329
-
1330
- ### QyButton
1331
-
1332
- ```vue
1333
- <template>
1334
- <QyButton type="primary" :prefix-icon="Search" @click="handleSearch">
1335
- 查询
1336
- </QyButton>
1337
- <QyButton loading>保存中</QyButton>
1338
- <QyButton icon-only :prefix-icon="Refresh" aria-label="刷新当前页" />
1339
- </template>
1340
- ```
1341
-
1342
- ### QyDropdown
1343
-
1344
- ```vue
1345
- <template>
1346
- <QyDropdown
1347
- :items="items"
1348
- panel-width="168px"
1349
- @select="handleSelect"
1350
- >
1351
- <template #trigger="{ attrs }">
1352
- <QyButton v-bind="attrs">
1353
- 更多
1354
- </QyButton>
1355
- </template>
1356
- </QyDropdown>
1357
- </template>
1358
-
1359
- <script setup lang="ts">
1360
- import QyButton from '@qynpm/ui/qy-button'
1361
- import QyDropdown from '@qynpm/ui/qy-dropdown'
1362
-
1363
- const items = [
1364
- { key: 'profile', label: '个人信息' },
1365
- { key: 'logout', label: '退出登录', danger: true, divided: true }
1366
- ]
1367
-
1368
- function handleSelect(item) {
1369
- // 业务执行、路由跳转和权限判断留在宿主项目。
1370
- }
1371
- </script>
1372
- ```
1373
-
1374
- ### QyDialog
1375
-
1376
- ```vue
1377
- <template>
1378
- <QyDialog :open="open" title="标题" close-on-confirm @update:open="open = $event">
1379
- 内容区域
1380
- </QyDialog>
1381
- </template>
1382
- ```
1383
-
1384
- ### QyInput
1385
-
1386
- ```vue
1387
- <template>
1388
- <QyInput
1389
- v-model="quoteOrderCode"
1390
- remove-space
1391
- trim-mode="blur"
1392
- placeholder="填写报价单,回车搜索"
1393
- @enter="handleSearch"
1394
- />
1395
- </template>
1396
- ```
1397
-
1398
- ### QyMoneyInput
1399
-
1400
- ```vue
1401
- <template>
1402
- <QyMoneyInput
1403
- v-model="totalPay"
1404
- :precision="2"
1405
- :min="0"
1406
- placeholder="请输入总金额"
1407
- />
1408
- </template>
1409
- ```
1410
-
1411
- ### QyInputNumber
1412
-
1413
- ```vue
1414
- <template>
1415
- <QyInputNumber
1416
- v-model="productNum"
1417
- :min="0"
1418
- :step="1"
1419
- :precision="0"
1420
- controls-position="right"
1421
- placeholder="请输入数量"
1422
- />
1423
- </template>
1424
- ```
1425
-
1426
- ### QyDatePicker
1427
-
1428
- ```vue
1429
- <template>
1430
- <QyDatePicker
1431
- v-model="dateRange"
1432
- type="datetimerange"
1433
- value-format="YYYY-MM-DD HH:mm:ss"
1434
- format="YYYY-MM-DD HH:mm:ss"
1435
- :default-time="defaultTime"
1436
- normalize-range-end-time
1437
- />
1438
- </template>
1439
- ```
1440
-
1441
- ### QyRadio
1442
-
1443
- ```vue
1444
- <template>
1445
- <QyRadio
1446
- v-model="ticketType"
1447
- value="invoice"
1448
- label="开票"
1449
- />
1450
- </template>
1451
- ```
1452
-
1453
- ### QyRadioGroup
1454
-
1455
- ```vue
1456
- <template>
1457
- <QyRadioGroup
1458
- v-model="openTicket"
1459
- :options="ticketOptions"
1460
- />
1461
- </template>
1462
- ```
1463
-
1464
- 自定义选项展示:
1465
-
1466
- ```vue
1467
- <template>
1468
- <QyRadioGroup v-model="openTicket" :options="ticketOptions">
1469
- <template #option="{ option, label }">
1470
- <span>{{ label }}</span>
1471
- <span v-if="option.fee" style="margin-left: 6px; color: #f56c6c">
1472
- {{ option.fee }}
1473
- </span>
1474
- </template>
1475
- </QyRadioGroup>
1476
- </template>
1477
- ```
1478
-
1479
- ### QySelect
1480
-
1481
- ```vue
1482
- <template>
1483
- <QySelect
1484
- v-model="shopCode"
1485
- :options="shopOptions"
1486
- placeholder="请选择店铺"
1487
- />
1488
- </template>
1489
- ```
1490
-
1491
- ### QyRemoteSelect
1492
-
1493
- ```vue
1494
- <template>
1495
- <QyRemoteSelect
1496
- v-model="recvAccount"
1497
- :fetch-method="fetchFinanceAccounts"
1498
- :default-options="accountDefaultOptions"
1499
- label-key="accountName"
1500
- value-key="accountId"
1501
- placeholder="请选择收款账户"
1502
- remote-on-focus
1503
- @error="handleAccountError"
1504
- />
1505
- </template>
1506
- ```
1507
-
1508
- ### QyFormSection
1509
-
1510
- ```vue
1511
- <template>
1512
- <QyFormSection title="订单信息" description="这里放订单表单区块">
1513
- <el-form>...</el-form>
1514
- </QyFormSection>
1515
- </template>
1516
- ```
1517
-
1518
- ### QyActionBar
1519
-
1520
- ```vue
1521
- <template>
1522
- <QyActionBar>
1523
- <template #left>
1524
- <el-button plain>开票</el-button>
1525
- </template>
1526
- <template #right>
1527
- <el-button>保存</el-button>
1528
- <el-button type="primary">提交</el-button>
1529
- </template>
1530
- </QyActionBar>
1531
- </template>
1532
- ```
1533
-
1534
- ### QySearchInput
1535
-
1536
- ```vue
1537
- <template>
1538
- <QySearchInput
1539
- v-model="keyword"
1540
- :fetch-suggestions-method="querySearch"
1541
- :show-button="false"
1542
- />
1543
- </template>
1544
- ```
1545
-
1546
- ### QyRecordQuoteSearch
1547
-
1548
- ```vue
1549
- <template>
1550
- <QyRecordQuoteSearch
1551
- v-model="quoteOrderCode"
1552
- :fetch-suggestions="fetchQuoteSuggestions"
1553
- :search-method="handleQuoteSearch"
1554
- @search="handleSearch"
1555
- />
1556
- </template>
1557
- ```
1558
-
1559
- ### QyCollapse
1560
-
1561
- `QyCollapse` 与 `QyCollapseItem` 是 Element Plus 折叠面板的受控适配器。普通模式使用数组值,手风琴模式使用单个字符串或数字;`beforeCollapse` 同时拦截展开和收起。
1562
-
1563
- ```vue
1564
- <template>
1565
- <QyCollapse v-model="activeNames" :before-collapse="beforeCollapse">
1566
- <QyCollapseItem title="基本信息" name="base">内容</QyCollapseItem>
1567
- <QyCollapseItem title="数字名称" :name="2" />
1568
- </QyCollapse>
1569
- </template>
1570
-
1571
- <script setup>
1572
- import { ref } from 'vue'
1573
- import { QyCollapse, QyCollapseItem } from '@qynpm/ui'
1574
-
1575
- const activeNames = ref(['base'])
1576
- function beforeCollapse(name) {
1577
- return name !== 'locked'
1578
- }
1579
- </script>
1580
- ```
1581
-
1582
- 通过 `ref` 可读取只读的 `activeNames`,并调用 `setActiveNames(value)` 设置完整公共值;标题和图标插槽都接收 `{ isActive }`。
1583
-
1584
- ### QyLink
1585
-
1586
- `QyLink` 基于 Element Plus `ElLink`,保留真实 `<a href>` 的浏览器焦点、Enter 激活和默认导航语义。支持六种语义类型、`always` / `never` / `hover` 下划线策略、禁用、原生链接地址和属性、图标属性及默认/图标插槽。
1587
-
1588
- ```vue
1589
- <QyLink
1590
- href="https://example.com"
1591
- target="_blank"
1592
- rel="noopener noreferrer"
1593
- type="primary"
1594
- underline="hover"
1595
- >
1596
- 打开外部文档
1597
- <template #icon>↗</template>
1598
- </QyLink>
1599
- ```
1600
-
1601
- `disabled` 会移除有效 `href` 与 `target` 并抑制 `click`;非禁用点击只转发一次原生 `MouseEvent`。`type` 和 `underline` 未传时可继承 Element Plus ConfigProvider;布尔下划线仅作兼容,`true` 等同 `hover`、`false` 等同 `never`。不自动改写 `target` 或 `rel`,外部新窗口链接请显式提供 `rel="noopener noreferrer"`。无 href、只监听 `click` 的旧用法可以兼容,但新业务动作应使用 `QyButton`,路由导航应使用 RouterLink。
1602
-
1603
1603
  ### QyIframe
1604
1604
 
1605
1605
  `QyIframe` 用于在当前页面容器中嵌入受信任的独立页面。`src` 和无障碍 `title` 必填且去除首尾空白后必须非空;任一为空时不渲染 iframe。支持原生 `loading`、`sandbox`、`allow`、`referrerPolicy`、`allowFullscreen`,并发出无参数的 `load` 和 `error` 通知,不暴露原生 DOM Event。
@@ -1621,184 +1621,184 @@ function beforeCollapse(name) {
1621
1621
  `src` 变化时更新当前 iframe 地址;即使 `src` 相同,改变 `reloadKey`(`string | number`)也会重建 iframe 以触发受控 reload。组件默认填满父容器,不计算应用头部、标签栏或面包屑高度;宿主必须为容器提供明确高度。根节点只安全透传 `class`、`style`、`id`、`role`、`tabindex`、`data-*` 和 `aria-*`,未知属性及未声明监听器不对外透传。组件不模拟加载时长、不覆盖全局 resize 监听,也不负责登录会话、地址白名单或跨域通信。
1622
1622
 
1623
1623
  ### QyDivider
1624
-
1625
- `QyDivider` 基于 Element Plus `ElDivider`,支持水平/垂直方向、左中右标题位置和标准 CSS `border-style` 值。水平模式渲染默认插槽,垂直模式即使传入插槽也保持 Element Plus 行为而不渲染;消费者传入的 `width`、`height`、`margin` 等根样式会与 Element Plus 的边框 CSS 变量合并。
1626
-
1627
- ```vue
1628
- <QyDivider content-position="left" border-style="dashed">
1629
- 分组标题
1630
- </QyDivider>
1631
- <QyDivider direction="vertical" :style="{ height: '130px', margin: '0 8px' }" />
1632
- ```
1633
-
1634
- 根节点保留 `role="separator"`,只安全透传 `class`、`style`、`id`、`title`、`role`、`data-*` 和 `aria-*`;组件没有事件、尺寸参数、公开实例或额外布局规则。
1635
-
1636
- ### QyProgress
1637
-
1638
- `QyProgress` 基于 Element Plus `ElProgress`,用于文件上传、批处理和任务进度的受控展示。支持 line / circle / dashboard 三种形态、percentage、四种 status、显示/隐藏/内部/自定义文字、固定/分段/函数颜色、线宽、端点、圆形画布宽度、不确定动画、条纹、流动条纹和默认插槽;不接管上传、轮询、暂停、恢复、重试或任务状态映射。
1639
-
1640
- ```vue
1641
- <QyProgress :percentage="progress" status="success" />
1642
- <QyProgress type="circle" :percentage="progress" :color="colorStops" />
1643
- <QyProgress :percentage="progress" :style="{ width: '720px', margin: '8px auto' }">
1644
- <template #default="{ percentage }">已完成 {{ percentage }}%</template>
1645
- </QyProgress>
1646
- ```
1647
-
1648
- 颜色、文字优先级、合法 percentage、图形和动画全部沿用 Element Plus;根级只安全透传 `class`、`style`、`id`、`role`、`title`、`data-*` 和 `aria-*`,未知属性、事件监听器、实例、DOM ref 和方法不对外暴露。文档演示位于 `src/docs/QyProgressDoc.vue`,API 表使用局部横向滚动,不产生页面级横向溢出。
1649
-
1650
- ### QyStatistic
1651
-
1652
- `QyStatistic` 基于 Element Plus `ElStatistic` 展示数值。`value`、`precision`、`decimalSeparator`、`groupSeparator`、`formatter`、`valueStyle` 以及 `title`、`prefix`、`suffix` 属性和同名插槽均沿用 Element Plus;插槽优先级不变。
1653
-
1654
- ```vue
1655
- <QyStatistic title="成交额" :value="123456.78" :precision="2" prefix="¥" suffix="元" />
1656
- <QyStatistic :value="target" animated :duration="800" :start-value="100" />
1657
- ```
1658
-
1659
- 动画首次从 `startValue` 过渡,目标变化时从当前显示值平滑衔接;`animated=false`、`duration<=0` 和 `prefers-reduced-motion: reduce` 时立即显示目标值。根级只安全透传 `class`、`style`、`id`、`role`、`data-*` 和 `aria-*`,未知属性与事件监听器不会透传,也不暴露 Element Plus 实例、DOM ref 或方法。
1660
-
1661
- ### QyAvatar
1662
-
1663
- `QyAvatar` 基于 Element Plus `ElAvatar`,用于用户头像及自定义头像内容展示。支持数字尺寸、`small` / `default` / `large` 命名尺寸、圆形和方形、图片 `src` / `srcSet` / `alt` / `fit`、图标、默认插槽和图片加载失败后的原生回退。
1664
-
1665
- ```vue
1666
- <QyAvatar :size="80" src="/avatar.png" alt="用户头像" />
1667
- <QyAvatar size="large" shape="square" :icon="UserFilled" />
1668
- <QyAvatar src="/missing.png" @error="handleAvatarError">
1669
- 张三
1670
- </QyAvatar>
1671
- ```
1672
-
1673
- 图片加载、失败回退、图标与默认插槽优先级全部沿用 Element Plus;`error` 只转发标准图片 `Event`。根级只安全透传 `class`、`style`、`id`、`role`、`title`、`tabindex`、`data-*` 和 `aria-*`,未知属性、未声明事件、实例、DOM ref 和方法不对外暴露。QyAvatar 不接管上传、裁剪、预览、缓存、用户资料保存或头像组;文档演示位于 `src/docs/QyAvatarDoc.vue`,API 表使用局部横向滚动。
1674
-
1675
- ### QyAlert
1676
-
1677
- `QyAlert` 基于 Element Plus `ElAlert`,用于页面模板中的常驻成功、警告、信息和错误提示。支持 `title`、`description`、五种 `type`、关闭入口、图标、居中和明暗效果,以及 `icon`、`title`、默认三个插槽;关闭时只触发无参数 `close` 事件,隐藏状态由 Element Plus 管理。
1678
-
1679
- ```vue
1680
- <QyAlert type="warning" title="请检查填写内容" description="修改后即可继续提交" @close="handleClose" />
1681
- ```
1682
-
1683
- 根级只安全透传 `class`、`style`、`id`、`role`、`data-*` 和 `aria-*`;不透传原生 `title`、未知属性、原始鼠标事件或 Element Plus 实例。`QyAlert` 只负责常驻提示,不替代 `@qynpm/hooks` feedback runtime,也不改动 `QyFormSection` 的现有 tip 协议。
1684
-
1685
- ### QyCard
1686
-
1687
- `QyCard` 基于 Element Plus `ElCard`,用于页面内部可独立识别的小型内容面板。支持 `header`、`footer`、`shadow`、`bodyStyle` 以及三个区域类名入口,原生转发 `header`、默认和 `footer` 插槽;插槽存在时由 Element Plus 优先于同名文本属性渲染。
1688
-
1689
- ```vue
1690
- <QyCard header="订单概览" shadow="hover" @click="handleCardClick">
1691
- <template #footer>更新于刚刚</template>
1692
- 面板正文
1693
- </QyCard>
1694
- ```
1695
-
1696
- 根级只安全透传 `class`、`style`、`id`、`role`、`title`、`tabindex`、`data-*` 和 `aria-*`;`click` 只转发一次原生 `MouseEvent`,不把普通卡片自动改成按钮或链接。`QyCard` 不替代 `QyPage` 的页面语义根和页面节奏,也不替代 `QyFormSection` 的表单标题、说明、动作或折叠;标准列表页和完整页面不要再套一层卡片 workspace。
1697
-
1698
- ## 说明
1699
-
1700
- - 当前版本更适合体系内拆包复用
1701
- - 上传默认值仍然保留了现有项目约定,后续如果完全独立对外,可以再继续抽离
1702
- - `QyInput` 第一版优先兼容 `ElInput`,后续再逐步补统一输入规则
1703
- - `QyInputNumber` 第一版优先兼容 `ElInputNumber`,保持数字输入语义,不承接金额格式化
1704
- - `QyRadioGroup` 第一版优先兼容 `ElRadioGroup`,不内置字典请求或复杂表单联动
1705
- - `QySelect` 第一版优先兼容 `ElSelect`,不内置远程字典或复杂请求能力
1706
- - `QyDatePicker` 第一版优先兼容 `ElDatePicker`,查询结束时间归一化需要显式开启
1707
- - `QyRemoteSelect` 负责远程请求状态和回显保留,不承接具体业务接口协议转换
1708
- - `QyFormSection` 只负责区块壳,不替代 `@qiyin/form` 的 schema / 校验能力
1709
- - `QyActionBar` 只负责底部布局壳,不负责编排按钮业务逻辑
1710
- - `QySearchInput` 第一版已经覆盖建议搜索场景,可通过 `show-button=false` 关闭默认搜索按钮,但仍然不承接页面级副作用
1711
- - `QyRecordQuoteSearch` 只承接报价单搜索入口逻辑,不直接改整页录单状态
1712
- - `QyImage` 负责通用图片显示,不负责表格列取值、formatter、水印和列设置;这些由 `@qynpm/table-schema` 组合
1713
-
1714
- ## 当前联调说明
1715
-
1716
- 当前 workspace 联调由顶层 Vite 开关统一控制,不再要求在 `UI` 或 `form` 内手动切换 import。
1717
-
1718
- 开关位置:
1719
-
1720
- - `qy-workspace` 顶层 `vite.config.ts`
1721
-
1722
- 当前配置:
1723
-
1724
- ```ts
1725
- const ENABLE_LOCAL_QIYIN_DEBUG = true
1726
- ```
1727
-
1728
- 规则如下:
1729
-
1730
- 1. 当值为 `true` 时
1731
- - `@qynpm/ui` 映射到本地 [lib/index.js](./lib/index.js)
1732
- - `@qynpm/form` / `@qiyin/form` 映射到本地 [../form/index.ts](../form/index.ts)
1733
- - 消费项目开发时可以直接联调 `UI` 与 `form`
1734
-
1735
- 2. 当值为 `false` 时
1736
- - 走各自包的正常入口
1737
- - 行为更接近线上
1738
-
1739
- 如果切换开关后页面报 `Outdated Optimize Dep`:
1740
-
1741
- 1. 停掉当前 dev 服务
1742
- 2. 清理消费项目的 `node_modules/.vite`
1743
- 3. 重新启动
1744
-
1745
- ### QySteps 与 QyStep
1746
-
1747
- `QySteps` 和 `QyStep` 是 Element Plus `ElSteps` / `ElStep` 的安全公共入口。布局、父子注册、排序、状态计算和过渡全部由 Element Plus 负责;Qy 层只隔离公共属性、插槽、根级安全属性和 `change(newValue, oldValue)` 事件。
1748
-
1749
- ```vue
1750
- <QySteps :active="active" direction="horizontal" @change="handleChange">
1751
- <QyStep title="创建订单" description="填写订单信息" />
1752
- <QyStep title="确认信息">
1753
- <template #title><button type="button" @click="openOrder">查看订单</button></template>
1754
- </QyStep>
1755
- <QyStep title="完成" status="success" />
1756
- </QySteps>
1757
- ```
1758
-
1759
- 支持自动、像素和百分比 `space`,横向/纵向、居中、简洁模式、五种步骤状态以及受控 `active`。`QyStep` 支持 `title`、`description`、`icon`、显式 `status` 和 `icon` / `title` / `description` 插槽;插槽内容优先于同名属性。组件不提供 `update:active`、自动导航或步骤点击事件,业务跳转应在插槽中放置真实按钮或链接并自行处理。
1760
-
1761
- 两个入口分别为 `@qynpm/ui/qy-steps` 与 `@qynpm/ui/qy-step`;根入口也导出 `QySteps`、`QyStep` 及其 Qy 自有类型。根级只安全透传 `class`、`style`、`id`、`role`、`title`、`data-*` 和 `aria-*`,未知属性、未声明事件、Element Plus 实例、内部注册对象和 DOM 方法不对外暴露。文档演示位于 `src/docs/QyStepsDoc.vue`,宽步骤条和 API 表使用局部横向滚动。
1762
-
1763
- ### QyRow 与 QyCol
1764
-
1765
- `QyRow` 与 `QyCol` 是 Element Plus `ElRow` / `ElCol` 的安全公共入口。栅格、gutter、对齐、位移、嵌套和五档响应式全部沿用 Element Plus;Qy 层不手写 24 栅格、断点、负边距或列 padding。
1766
-
1767
- ```vue
1768
- <QyRow :gutter="16" justify="space-between" align="middle">
1769
- <QyCol :span="12" :xs="24" :md="12">左侧内容</QyCol>
1770
- <QyCol :span="12" :offset="1">右侧内容</QyCol>
1771
- </QyRow>
1772
- ```
1773
-
1774
- 两个入口分别为 `@qynpm/ui/qy-row` 与 `@qynpm/ui/qy-col`;根入口也导出 `QyRow`、`QyCol` 及其 Qy 自有类型。`QyRow` 支持 `tag`、`gutter`、`justify`、`align` 和默认插槽;`QyCol` 支持 `tag`、`span`、`offset`、`push`、`pull`、`xs`、`sm`、`md`、`lg`、`xl` 和默认插槽。数值合法性和异常值表现交由 Element Plus 负责,不对旧项目非法值做兼容映射。
1775
-
1776
- 两者根级只安全透传 `class`、`style`、`id`、`role`、`title`、`data-*` 和 `aria-*`;未知属性、监听器、Element Plus 实例、DOM ref 和方法不对外暴露。完整演示位于 `src/docs/QyGridDoc.vue`,包含等分列、gutter、justify/align、offset/push/pull、嵌套、自定义 tag、五档响应式和局部横向滚动 API 表。
1777
-
1778
- ### QyFullscreen
1779
-
1780
- `QyFullscreen` 统一承接整页或指定局部 `HTMLElement` 的浏览器全屏进入、退出和状态同步。它使用 QyButton 保留按钮、loading、尺寸和可访问语义,使用 QyIcon 渲染图标;图标未在当前 registry 注册时显示当前 label 文字,不会产生空白按钮。
1781
-
1782
- ```vue
1783
- <QyFullscreen @change="isFullscreen = $event" @error="handleFullscreenError" />
1784
- <QyFullscreen :target="previewElement" enter-label="进入局部全屏" />
1785
- ```
1786
-
1787
- `target` 未传时使用 `document.documentElement`,显式传入 `null` 表示目标暂不可用。全屏期间 target 变化不会自动退出或切换,退出后下一次进入才使用新目标。`enter()`、`exit()`、`toggle()` 通过模板 ref 命令式调用并返回 `Promise<boolean>`;`change` 只在浏览器确认实际状态变化后触发,`error` 返回不含原始 `DOMException` 的只读快照。完整示例位于 `src/docs/QyFullscreenDoc.vue`,入口为 `@qynpm/ui/qy-fullscreen`。
1788
-
1789
- ### QyIcon 与应用图标注册表
1790
-
1624
+
1625
+ `QyDivider` 基于 Element Plus `ElDivider`,支持水平/垂直方向、左中右标题位置和标准 CSS `border-style` 值。水平模式渲染默认插槽,垂直模式即使传入插槽也保持 Element Plus 行为而不渲染;消费者传入的 `width`、`height`、`margin` 等根样式会与 Element Plus 的边框 CSS 变量合并。
1626
+
1627
+ ```vue
1628
+ <QyDivider content-position="left" border-style="dashed">
1629
+ 分组标题
1630
+ </QyDivider>
1631
+ <QyDivider direction="vertical" :style="{ height: '130px', margin: '0 8px' }" />
1632
+ ```
1633
+
1634
+ 根节点保留 `role="separator"`,只安全透传 `class`、`style`、`id`、`title`、`role`、`data-*` 和 `aria-*`;组件没有事件、尺寸参数、公开实例或额外布局规则。
1635
+
1636
+ ### QyProgress
1637
+
1638
+ `QyProgress` 基于 Element Plus `ElProgress`,用于文件上传、批处理和任务进度的受控展示。支持 line / circle / dashboard 三种形态、percentage、四种 status、显示/隐藏/内部/自定义文字、固定/分段/函数颜色、线宽、端点、圆形画布宽度、不确定动画、条纹、流动条纹和默认插槽;不接管上传、轮询、暂停、恢复、重试或任务状态映射。
1639
+
1640
+ ```vue
1641
+ <QyProgress :percentage="progress" status="success" />
1642
+ <QyProgress type="circle" :percentage="progress" :color="colorStops" />
1643
+ <QyProgress :percentage="progress" :style="{ width: '720px', margin: '8px auto' }">
1644
+ <template #default="{ percentage }">已完成 {{ percentage }}%</template>
1645
+ </QyProgress>
1646
+ ```
1647
+
1648
+ 颜色、文字优先级、合法 percentage、图形和动画全部沿用 Element Plus;根级只安全透传 `class`、`style`、`id`、`role`、`title`、`data-*` 和 `aria-*`,未知属性、事件监听器、实例、DOM ref 和方法不对外暴露。文档演示位于 `src/docs/QyProgressDoc.vue`,API 表使用局部横向滚动,不产生页面级横向溢出。
1649
+
1650
+ ### QyStatistic
1651
+
1652
+ `QyStatistic` 基于 Element Plus `ElStatistic` 展示数值。`value`、`precision`、`decimalSeparator`、`groupSeparator`、`formatter`、`valueStyle` 以及 `title`、`prefix`、`suffix` 属性和同名插槽均沿用 Element Plus;插槽优先级不变。
1653
+
1654
+ ```vue
1655
+ <QyStatistic title="成交额" :value="123456.78" :precision="2" prefix="¥" suffix="元" />
1656
+ <QyStatistic :value="target" animated :duration="800" :start-value="100" />
1657
+ ```
1658
+
1659
+ 动画首次从 `startValue` 过渡,目标变化时从当前显示值平滑衔接;`animated=false`、`duration<=0` 和 `prefers-reduced-motion: reduce` 时立即显示目标值。根级只安全透传 `class`、`style`、`id`、`role`、`data-*` 和 `aria-*`,未知属性与事件监听器不会透传,也不暴露 Element Plus 实例、DOM ref 或方法。
1660
+
1661
+ ### QyAvatar
1662
+
1663
+ `QyAvatar` 基于 Element Plus `ElAvatar`,用于用户头像及自定义头像内容展示。支持数字尺寸、`small` / `default` / `large` 命名尺寸、圆形和方形、图片 `src` / `srcSet` / `alt` / `fit`、图标、默认插槽和图片加载失败后的原生回退。
1664
+
1665
+ ```vue
1666
+ <QyAvatar :size="80" src="/avatar.png" alt="用户头像" />
1667
+ <QyAvatar size="large" shape="square" :icon="UserFilled" />
1668
+ <QyAvatar src="/missing.png" @error="handleAvatarError">
1669
+ 张三
1670
+ </QyAvatar>
1671
+ ```
1672
+
1673
+ 图片加载、失败回退、图标与默认插槽优先级全部沿用 Element Plus;`error` 只转发标准图片 `Event`。根级只安全透传 `class`、`style`、`id`、`role`、`title`、`tabindex`、`data-*` 和 `aria-*`,未知属性、未声明事件、实例、DOM ref 和方法不对外暴露。QyAvatar 不接管上传、裁剪、预览、缓存、用户资料保存或头像组;文档演示位于 `src/docs/QyAvatarDoc.vue`,API 表使用局部横向滚动。
1674
+
1675
+ ### QyAlert
1676
+
1677
+ `QyAlert` 基于 Element Plus `ElAlert`,用于页面模板中的常驻成功、警告、信息和错误提示。支持 `title`、`description`、五种 `type`、关闭入口、图标、居中和明暗效果,以及 `icon`、`title`、默认三个插槽;关闭时只触发无参数 `close` 事件,隐藏状态由 Element Plus 管理。
1678
+
1679
+ ```vue
1680
+ <QyAlert type="warning" title="请检查填写内容" description="修改后即可继续提交" @close="handleClose" />
1681
+ ```
1682
+
1683
+ 根级只安全透传 `class`、`style`、`id`、`role`、`data-*` 和 `aria-*`;不透传原生 `title`、未知属性、原始鼠标事件或 Element Plus 实例。`QyAlert` 只负责常驻提示,不替代 `@qynpm/hooks` feedback runtime,也不改动 `QyFormSection` 的现有 tip 协议。
1684
+
1685
+ ### QyCard
1686
+
1687
+ `QyCard` 基于 Element Plus `ElCard`,用于页面内部可独立识别的小型内容面板。支持 `header`、`footer`、`shadow`、`bodyStyle` 以及三个区域类名入口,原生转发 `header`、默认和 `footer` 插槽;插槽存在时由 Element Plus 优先于同名文本属性渲染。
1688
+
1689
+ ```vue
1690
+ <QyCard header="订单概览" shadow="hover" @click="handleCardClick">
1691
+ <template #footer>更新于刚刚</template>
1692
+ 面板正文
1693
+ </QyCard>
1694
+ ```
1695
+
1696
+ 根级只安全透传 `class`、`style`、`id`、`role`、`title`、`tabindex`、`data-*` 和 `aria-*`;`click` 只转发一次原生 `MouseEvent`,不把普通卡片自动改成按钮或链接。`QyCard` 不替代 `QyPage` 的页面语义根和页面节奏,也不替代 `QyFormSection` 的表单标题、说明、动作或折叠;标准列表页和完整页面不要再套一层卡片 workspace。
1697
+
1698
+ ## 说明
1699
+
1700
+ - 当前版本更适合体系内拆包复用
1701
+ - 上传默认值仍然保留了现有项目约定,后续如果完全独立对外,可以再继续抽离
1702
+ - `QyInput` 第一版优先兼容 `ElInput`,后续再逐步补统一输入规则
1703
+ - `QyInputNumber` 第一版优先兼容 `ElInputNumber`,保持数字输入语义,不承接金额格式化
1704
+ - `QyRadioGroup` 第一版优先兼容 `ElRadioGroup`,不内置字典请求或复杂表单联动
1705
+ - `QySelect` 第一版优先兼容 `ElSelect`,不内置远程字典或复杂请求能力
1706
+ - `QyDatePicker` 第一版优先兼容 `ElDatePicker`,查询结束时间归一化需要显式开启
1707
+ - `QyRemoteSelect` 负责远程请求状态和回显保留,不承接具体业务接口协议转换
1708
+ - `QyFormSection` 只负责区块壳,不替代 `@qiyin/form` 的 schema / 校验能力
1709
+ - `QyActionBar` 只负责底部布局壳,不负责编排按钮业务逻辑
1710
+ - `QySearchInput` 第一版已经覆盖建议搜索场景,可通过 `show-button=false` 关闭默认搜索按钮,但仍然不承接页面级副作用
1711
+ - `QyRecordQuoteSearch` 只承接报价单搜索入口逻辑,不直接改整页录单状态
1712
+ - `QyImage` 负责通用图片显示,不负责表格列取值、formatter、水印和列设置;这些由 `@qynpm/table-schema` 组合
1713
+
1714
+ ## 当前联调说明
1715
+
1716
+ 当前 workspace 联调由顶层 Vite 开关统一控制,不再要求在 `UI` 或 `form` 内手动切换 import。
1717
+
1718
+ 开关位置:
1719
+
1720
+ - `qy-workspace` 顶层 `vite.config.ts`
1721
+
1722
+ 当前配置:
1723
+
1724
+ ```ts
1725
+ const ENABLE_LOCAL_QIYIN_DEBUG = true
1726
+ ```
1727
+
1728
+ 规则如下:
1729
+
1730
+ 1. 当值为 `true` 时
1731
+ - `@qynpm/ui` 映射到本地 [lib/index.js](./lib/index.js)
1732
+ - `@qynpm/form` / `@qiyin/form` 映射到本地 [../form/index.ts](../form/index.ts)
1733
+ - 消费项目开发时可以直接联调 `UI` 与 `form`
1734
+
1735
+ 2. 当值为 `false` 时
1736
+ - 走各自包的正常入口
1737
+ - 行为更接近线上
1738
+
1739
+ 如果切换开关后页面报 `Outdated Optimize Dep`:
1740
+
1741
+ 1. 停掉当前 dev 服务
1742
+ 2. 清理消费项目的 `node_modules/.vite`
1743
+ 3. 重新启动
1744
+
1745
+ ### QySteps 与 QyStep
1746
+
1747
+ `QySteps` 和 `QyStep` 是 Element Plus `ElSteps` / `ElStep` 的安全公共入口。布局、父子注册、排序、状态计算和过渡全部由 Element Plus 负责;Qy 层只隔离公共属性、插槽、根级安全属性和 `change(newValue, oldValue)` 事件。
1748
+
1749
+ ```vue
1750
+ <QySteps :active="active" direction="horizontal" @change="handleChange">
1751
+ <QyStep title="创建订单" description="填写订单信息" />
1752
+ <QyStep title="确认信息">
1753
+ <template #title><button type="button" @click="openOrder">查看订单</button></template>
1754
+ </QyStep>
1755
+ <QyStep title="完成" status="success" />
1756
+ </QySteps>
1757
+ ```
1758
+
1759
+ 支持自动、像素和百分比 `space`,横向/纵向、居中、简洁模式、五种步骤状态以及受控 `active`。`QyStep` 支持 `title`、`description`、`icon`、显式 `status` 和 `icon` / `title` / `description` 插槽;插槽内容优先于同名属性。组件不提供 `update:active`、自动导航或步骤点击事件,业务跳转应在插槽中放置真实按钮或链接并自行处理。
1760
+
1761
+ 两个入口分别为 `@qynpm/ui/qy-steps` 与 `@qynpm/ui/qy-step`;根入口也导出 `QySteps`、`QyStep` 及其 Qy 自有类型。根级只安全透传 `class`、`style`、`id`、`role`、`title`、`data-*` 和 `aria-*`,未知属性、未声明事件、Element Plus 实例、内部注册对象和 DOM 方法不对外暴露。文档演示位于 `src/docs/QyStepsDoc.vue`,宽步骤条和 API 表使用局部横向滚动。
1762
+
1763
+ ### QyRow 与 QyCol
1764
+
1765
+ `QyRow` 与 `QyCol` 是 Element Plus `ElRow` / `ElCol` 的安全公共入口。栅格、gutter、对齐、位移、嵌套和五档响应式全部沿用 Element Plus;Qy 层不手写 24 栅格、断点、负边距或列 padding。
1766
+
1767
+ ```vue
1768
+ <QyRow :gutter="16" justify="space-between" align="middle">
1769
+ <QyCol :span="12" :xs="24" :md="12">左侧内容</QyCol>
1770
+ <QyCol :span="12" :offset="1">右侧内容</QyCol>
1771
+ </QyRow>
1772
+ ```
1773
+
1774
+ 两个入口分别为 `@qynpm/ui/qy-row` 与 `@qynpm/ui/qy-col`;根入口也导出 `QyRow`、`QyCol` 及其 Qy 自有类型。`QyRow` 支持 `tag`、`gutter`、`justify`、`align` 和默认插槽;`QyCol` 支持 `tag`、`span`、`offset`、`push`、`pull`、`xs`、`sm`、`md`、`lg`、`xl` 和默认插槽。数值合法性和异常值表现交由 Element Plus 负责,不对旧项目非法值做兼容映射。
1775
+
1776
+ 两者根级只安全透传 `class`、`style`、`id`、`role`、`title`、`data-*` 和 `aria-*`;未知属性、监听器、Element Plus 实例、DOM ref 和方法不对外暴露。完整演示位于 `src/docs/QyGridDoc.vue`,包含等分列、gutter、justify/align、offset/push/pull、嵌套、自定义 tag、五档响应式和局部横向滚动 API 表。
1777
+
1778
+ ### QyFullscreen
1779
+
1780
+ `QyFullscreen` 统一承接整页或指定局部 `HTMLElement` 的浏览器全屏进入、退出和状态同步。它使用 QyButton 保留按钮、loading、尺寸和可访问语义,使用 QyIcon 渲染图标;图标未在当前 registry 注册时显示当前 label 文字,不会产生空白按钮。
1781
+
1782
+ ```vue
1783
+ <QyFullscreen @change="isFullscreen = $event" @error="handleFullscreenError" />
1784
+ <QyFullscreen :target="previewElement" enter-label="进入局部全屏" />
1785
+ ```
1786
+
1787
+ `target` 未传时使用 `document.documentElement`,显式传入 `null` 表示目标暂不可用。全屏期间 target 变化不会自动退出或切换,退出后下一次进入才使用新目标。`enter()`、`exit()`、`toggle()` 通过模板 ref 命令式调用并返回 `Promise<boolean>`;`change` 只在浏览器确认实际状态变化后触发,`error` 返回不含原始 `DOMException` 的只读快照。完整示例位于 `src/docs/QyFullscreenDoc.vue`,入口为 `@qynpm/ui/qy-fullscreen`。
1788
+
1789
+ ### QyIcon 与应用图标注册表
1790
+
1791
1791
  `QyIcon` 是应用级统一图标入口。每个 Vue app 通过 `createQyIconRegistry` 与 `createQyIconPlugin` 提供自己的 registry,支持同文档 SVG symbol、直接 Vue component 和宿主已经生成样式的静态 class;包本身不依赖 Element Plus/Iconify renderer,也不进行远程加载或 `v-html`。宿主可选传入 `loader` 延迟补充完整目录;`load()` 复用进行中或成功的结果,失败后由 `retry()` 显式重试。
1792
-
1793
- ```ts
1794
- import { createQyIconPlugin, createQyIconRegistry } from '@qynpm/ui/qy-icon'
1795
-
1792
+
1793
+ ```ts
1794
+ import { createQyIconPlugin, createQyIconRegistry } from '@qynpm/ui/qy-icon'
1795
+
1796
1796
  const registry = createQyIconRegistry({
1797
- icons: [
1798
- { name: 'system', source: 'symbol', value: '#icon-system' },
1799
- { name: 'close', source: 'class', value: 'icon-[mdi--close]' }
1800
- ],
1801
- aliases: { 'el-icon-s-home': 'system' }
1797
+ icons: [
1798
+ { name: 'system', source: 'symbol', value: '#icon-system' },
1799
+ { name: 'close', source: 'class', value: 'icon-[mdi--close]' }
1800
+ ],
1801
+ aliases: { 'el-icon-s-home': 'system' }
1802
1802
  })
1803
1803
 
1804
1804
  const lazyRegistry = createQyIconRegistry({
@@ -1818,52 +1818,52 @@ export async function loadElementPlusIconCatalog() {
1818
1818
  return { icons: Object.entries(catalog).map(([name, value]) => ({ name, source: 'component', value })) }
1819
1819
  }
1820
1820
  ```
1821
-
1822
- 名称大小写不敏感;`#icon-system` 规范为 `system`,`icon-[mdi--close]` 规范为 `iconify:mdi:close`。冲突、未注册 alias 目标和不安全 symbol/class 值会在注册或合并时抛出错误。QyIcon 默认尺寸为 `1em`、颜色为 `currentColor`;提供 `label` 或消费方 `aria-label` 时作为 `role="img"`,否则为装饰图标。完整演示位于 `src/docs/QyIconDoc.vue`,入口为 `@qynpm/ui/qy-icon`。
1823
-
1824
- ### QyIconPicker
1825
-
1821
+
1822
+ 名称大小写不敏感;`#icon-system` 规范为 `system`,`icon-[mdi--close]` 规范为 `iconify:mdi:close`。冲突、未注册 alias 目标和不安全 symbol/class 值会在注册或合并时抛出错误。QyIcon 默认尺寸为 `1em`、颜色为 `currentColor`;提供 `label` 或消费方 `aria-label` 时作为 `role="img"`,否则为装饰图标。完整演示位于 `src/docs/QyIconDoc.vue`,入口为 `@qynpm/ui/qy-icon`。
1823
+
1824
+ ### QyIconPicker
1825
+
1826
1826
  `QyIconPicker` 从当前 Vue app 注入的 `QyIconRegistry` 读取允许图标,统一支持 symbol、Vue component 和静态 class 三种来源。它在首次打开时调用 registry `load()`,展示可访问的加载、失败、重试和空状态,失败后重新打开不会自动重试。它是单值受控选择器:默认展示 registry 全量,也可以通过 `allowedNames` 白名单限制;搜索匹配名称、label 和 keywords,旧 alias 当前值只用于解析 active 图标,不会静默改写 modelValue,未知当前值也会保留到消费者主动选择或清空。
1827
-
1828
- ```vue
1829
- <QyIconPicker
1830
- v-model="menuIcon"
1831
- :allowed-names="['system', 'settings']"
1832
- clearable
1833
- aria-label="菜单图标"
1834
- />
1835
- ```
1836
-
1837
- 公开事件为 `update:modelValue`、`change`、`clear`、`update:open` 和 `open-change`;实例只暴露 `focus()`、`blur()`、`open()`、`close()`。面板使用 listbox/option 语义,支持 Enter/Space 打开、方向键移动、Enter 选择和 Escape 回焦;触摸窄屏网格为两列且每个选项至少 40px。完整演示位于 `src/docs/QyIconPickerDoc.vue`,入口为 `@qynpm/ui/qy-icon-picker`。
1838
-
1839
- ### QyColorPicker
1840
-
1841
- `QyColorPicker` 是受控颜色选择器。`format` 只接受 `hex` 或 `rgb`;未指定时,关闭透明度输出 hex,开启透明度输出 rgb/rgba。拖动和输入只触发 `active-change`,确认或清空才按 `update:modelValue`、`change`、`visible-change(false)` 顺序提交;Escape、点击外部和失焦会回滚到当前父级值且不发提交事件。
1842
-
1843
- ```vue
1844
- <QyColorPicker
1845
- v-model="brandColor"
1846
- format="rgb"
1847
- show-alpha
1848
- :predefine="['#409eff', '#67c23a']"
1849
- clearable
1850
- @active-change="previewColor = $event"
1851
- />
1852
- ```
1853
-
1854
- 事件为 `update:modelValue`、`active-change`、`change` 和 `visible-change`,颜色 payload 为 `string | null`;组件不公开 Element Plus 类型、实例或 expose。完整演示位于 `src/docs/QyColorPickerDoc.vue`,入口为 `@qynpm/ui/qy-color-picker`。
1855
-
1856
- ### QyContainer、QyAside 与 QyMain
1857
-
1858
- 三个组件是通用布局原语,入口分别为 `@qynpm/ui/qy-container`、`@qynpm/ui/qy-aside` 与 `@qynpm/ui/qy-main`;根入口也导出 `QyContainer`、`QyAside`、`QyMain` 及其 Qy 自有类型。V1 使用内部 Element Plus renderer,公共 wrapper 和声明文件不要求消费者感知 Element Plus。
1859
-
1860
- ```vue
1861
- <QyContainer>
1862
- <QyAside width="240px">侧栏</QyAside>
1863
- <QyMain>主内容</QyMain>
1864
- </QyContainer>
1865
- ```
1866
-
1867
- `QyContainer` 的 `direction` 默认是 `horizontal`,只有显式传入 `vertical` 才进入纵向布局;`QyAside` 的 `width` 是默认 `300px` 的原样字符串,支持合法 CSS 宽度值;`QyMain` 是语义 `main`,填充剩余空间、内容溢出时局部滚动并使用默认 `20px` padding。三者只提供默认插槽,不提供 emits、expose、ref 或实例能力,并且只安全透传 `class`、`style`、`id`、`role`、`title`、`data-*`、`aria-*`。
1868
-
1869
- 完整演示位于 `src/docs/QyContainerDoc.vue`,覆盖默认横向、自定义侧栏宽度、显式纵向、嵌套组合、安全属性和局部横向滚动 API 表。它们不替代 `QyAdminContent`:后者仍负责后台页面级内容编排、workspace 和相关页面语义。
1827
+
1828
+ ```vue
1829
+ <QyIconPicker
1830
+ v-model="menuIcon"
1831
+ :allowed-names="['system', 'settings']"
1832
+ clearable
1833
+ aria-label="菜单图标"
1834
+ />
1835
+ ```
1836
+
1837
+ 公开事件为 `update:modelValue`、`change`、`clear`、`update:open` 和 `open-change`;实例只暴露 `focus()`、`blur()`、`open()`、`close()`。面板使用 listbox/option 语义,支持 Enter/Space 打开、方向键移动、Enter 选择和 Escape 回焦;触摸窄屏网格为两列且每个选项至少 40px。完整演示位于 `src/docs/QyIconPickerDoc.vue`,入口为 `@qynpm/ui/qy-icon-picker`。
1838
+
1839
+ ### QyColorPicker
1840
+
1841
+ `QyColorPicker` 是受控颜色选择器。`format` 只接受 `hex` 或 `rgb`;未指定时,关闭透明度输出 hex,开启透明度输出 rgb/rgba。拖动和输入只触发 `active-change`,确认或清空才按 `update:modelValue`、`change`、`visible-change(false)` 顺序提交;Escape、点击外部和失焦会回滚到当前父级值且不发提交事件。
1842
+
1843
+ ```vue
1844
+ <QyColorPicker
1845
+ v-model="brandColor"
1846
+ format="rgb"
1847
+ show-alpha
1848
+ :predefine="['#409eff', '#67c23a']"
1849
+ clearable
1850
+ @active-change="previewColor = $event"
1851
+ />
1852
+ ```
1853
+
1854
+ 事件为 `update:modelValue`、`active-change`、`change` 和 `visible-change`,颜色 payload 为 `string | null`;组件不公开 Element Plus 类型、实例或 expose。完整演示位于 `src/docs/QyColorPickerDoc.vue`,入口为 `@qynpm/ui/qy-color-picker`。
1855
+
1856
+ ### QyContainer、QyAside 与 QyMain
1857
+
1858
+ 三个组件是通用布局原语,入口分别为 `@qynpm/ui/qy-container`、`@qynpm/ui/qy-aside` 与 `@qynpm/ui/qy-main`;根入口也导出 `QyContainer`、`QyAside`、`QyMain` 及其 Qy 自有类型。V1 使用内部 Element Plus renderer,公共 wrapper 和声明文件不要求消费者感知 Element Plus。
1859
+
1860
+ ```vue
1861
+ <QyContainer>
1862
+ <QyAside width="240px">侧栏</QyAside>
1863
+ <QyMain>主内容</QyMain>
1864
+ </QyContainer>
1865
+ ```
1866
+
1867
+ `QyContainer` 的 `direction` 默认是 `horizontal`,只有显式传入 `vertical` 才进入纵向布局;`QyAside` 的 `width` 是默认 `300px` 的原样字符串,支持合法 CSS 宽度值;`QyMain` 是语义 `main`,填充剩余空间、内容溢出时局部滚动并使用默认 `20px` padding。三者只提供默认插槽,不提供 emits、expose、ref 或实例能力,并且只安全透传 `class`、`style`、`id`、`role`、`title`、`data-*`、`aria-*`。
1868
+
1869
+ 完整演示位于 `src/docs/QyContainerDoc.vue`,覆盖默认横向、自定义侧栏宽度、显式纵向、嵌套组合、安全属性和局部横向滚动 API 表。它们不替代 `QyAdminContent`:后者仍负责后台页面级内容编排、workspace 和相关页面语义。