@qynpm/ui 1.0.21 → 1.0.23

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 (123) hide show
  1. package/README.md +451 -352
  2. package/dist/index.cjs +8 -2
  3. package/dist/index.mjs +36 -27
  4. package/dist/qy-action-bar/index.cjs +1 -1
  5. package/dist/qy-action-bar/index.mjs +1 -1
  6. package/dist/qy-autocomplete/index.cjs +1 -1
  7. package/dist/qy-autocomplete/index.mjs +4 -2
  8. package/dist/qy-button/index.cjs +2 -0
  9. package/dist/qy-button/index.mjs +5 -0
  10. package/dist/qy-checkbox/index.cjs +1 -1
  11. package/dist/qy-checkbox/index.mjs +4 -2
  12. package/dist/qy-date-picker/index.cjs +1 -1
  13. package/dist/qy-date-picker/index.mjs +4 -2
  14. package/dist/qy-dialog/index.cjs +1 -1
  15. package/dist/qy-dialog/index.mjs +2 -2
  16. package/dist/qy-dropdown/index.cjs +2 -0
  17. package/dist/qy-dropdown/index.mjs +5 -0
  18. package/dist/qy-form-section/index.cjs +1 -1
  19. package/dist/qy-form-section/index.mjs +1 -1
  20. package/dist/qy-image/index.cjs +1 -1
  21. package/dist/qy-image/index.mjs +3 -1
  22. package/dist/qy-image-preview/index.cjs +1 -1
  23. package/dist/qy-image-preview/index.mjs +6 -3
  24. package/dist/qy-image-upload/index.cjs +1 -1
  25. package/dist/qy-image-upload/index.mjs +1 -1
  26. package/dist/qy-input/index.cjs +2 -1
  27. package/dist/qy-input/index.mjs +2 -1
  28. package/dist/qy-input-number/index.cjs +1 -1
  29. package/dist/qy-input-number/index.mjs +4 -2
  30. package/dist/qy-legacy-selection-dialog/index.cjs +1 -1
  31. package/dist/qy-legacy-selection-dialog/index.mjs +1 -1
  32. package/dist/qy-menu-actions/index.cjs +1 -1
  33. package/dist/qy-menu-actions/index.mjs +2 -2
  34. package/dist/qy-money-input/index.cjs +1 -1
  35. package/dist/qy-money-input/index.mjs +2 -2
  36. package/dist/qy-radio-group/index.cjs +1 -1
  37. package/dist/qy-radio-group/index.mjs +1 -1
  38. package/dist/qy-record-quote-search/index.cjs +1 -1
  39. package/dist/qy-record-quote-search/index.mjs +2 -2
  40. package/dist/qy-remark-image/index.cjs +1 -1
  41. package/dist/qy-remark-image/index.mjs +2 -2
  42. package/dist/qy-remote-select/index.cjs +1 -1
  43. package/dist/qy-remote-select/index.mjs +1 -1
  44. package/dist/qy-search-input/index.cjs +1 -1
  45. package/dist/qy-search-input/index.mjs +1 -1
  46. package/dist/qy-select/index.cjs +1 -1
  47. package/dist/qy-select/index.mjs +4 -2
  48. package/dist/qy-selection-dialog/index.cjs +1 -1
  49. package/dist/qy-selection-dialog/index.mjs +2 -2
  50. package/dist/qy-table-column-settings/index.cjs +1 -1
  51. package/dist/qy-table-column-settings/index.mjs +2 -2
  52. package/dist/qy-tree-select/index.cjs +1 -1
  53. package/dist/qy-tree-select/index.mjs +4 -2
  54. package/dist/qy-upload/index.cjs +1 -1
  55. package/dist/qy-upload/index.mjs +1 -1
  56. package/dist/shared/_plugin-vue_export-helper-BHFhmbuH.cjs +1 -0
  57. package/dist/shared/_plugin-vue_export-helper-CHgC5LLL.mjs +9 -0
  58. package/dist/shared/index-B3U7dqMt.cjs +1 -0
  59. package/dist/shared/index-BO5aWk3f.cjs +1 -0
  60. package/dist/shared/index-BXlQSIWX.mjs +119 -0
  61. package/dist/shared/index-BbpD7hM0.cjs +1 -0
  62. package/dist/shared/index-CRZsiNVW.cjs +1 -0
  63. package/dist/shared/index-CSxCewXP.mjs +127 -0
  64. package/dist/shared/index-CagHZ25z.mjs +162 -0
  65. package/dist/shared/index-D3l7tLgw.cjs +1 -0
  66. package/dist/shared/{index-BWIOoRpy.mjs → index-D7lMppIb.mjs} +1 -1
  67. package/dist/shared/index-DyK6vf5h.cjs +1 -0
  68. package/dist/shared/{index-B4JNbDHG.mjs → index-NCpeoBUZ.mjs} +1 -1
  69. package/dist/shared/index-ZLoAI88M.mjs +3418 -0
  70. package/dist/shared/index.vue_vue_type_script_setup_true_lang-5gku7Zwv.cjs +1 -0
  71. package/dist/shared/index.vue_vue_type_script_setup_true_lang-BJakDlgd.mjs +70 -0
  72. package/dist/shared/index.vue_vue_type_script_setup_true_lang-C-Pf9TJ0.mjs +152 -0
  73. package/dist/shared/index.vue_vue_type_script_setup_true_lang-CKp87br2.cjs +1 -0
  74. package/dist/shared/index.vue_vue_type_script_setup_true_lang-CelW13DE.cjs +1 -0
  75. package/dist/shared/index.vue_vue_type_script_setup_true_lang-DA1Nh7U1.mjs +130 -0
  76. package/dist/shared/index.vue_vue_type_script_setup_true_lang-DEpXmMj5.mjs +162 -0
  77. package/dist/shared/index.vue_vue_type_script_setup_true_lang-DNEVwqm7.cjs +1 -0
  78. package/dist/shared/index.vue_vue_type_script_setup_true_lang-DWS8bsiP.cjs +1 -0
  79. package/dist/shared/index.vue_vue_type_script_setup_true_lang-DfKTEci_.cjs +1 -0
  80. package/dist/shared/index.vue_vue_type_script_setup_true_lang-DoL8xnpo.mjs +48 -0
  81. package/dist/shared/index.vue_vue_type_script_setup_true_lang-EiHoQBXt.mjs +94 -0
  82. package/dist/shared/index.vue_vue_type_script_setup_true_lang-gTkP1LWg.mjs +61 -0
  83. package/dist/shared/index.vue_vue_type_script_setup_true_lang-svvSFv2K.cjs +1 -0
  84. package/dist/shared/index.vue_vue_type_style_index_0_lang-B_A4Nq6v.cjs +1 -0
  85. package/dist/shared/index.vue_vue_type_style_index_0_lang-DKFiK2fQ.mjs +152 -0
  86. package/dist/shared/install-CxBnxbuN.mjs +8 -0
  87. package/dist/shared/install-c8il9DQv.cjs +1 -0
  88. package/dist/shared/utils-D2KAQCCB.cjs +1 -0
  89. package/dist/shared/utils-DUntDntI.mjs +112 -0
  90. package/index.d.ts +45 -41
  91. package/package.json +41 -26
  92. package/qy-button/index.d.ts +34 -0
  93. package/qy-dropdown/index.d.ts +40 -0
  94. package/dist/shared/index-B7ZgDgHR.cjs +0 -1
  95. package/dist/shared/index-COjhEDRy.cjs +0 -1
  96. package/dist/shared/index-CQPIT5by.cjs +0 -1
  97. package/dist/shared/index-D6KfrXN6.mjs +0 -4429
  98. package/dist/shared/install-DMq9RQ-h.mjs +0 -15
  99. package/dist/shared/install-DNgKRKb2.cjs +0 -1
  100. package/qy-action-bar/index.js +0 -1
  101. package/qy-autocomplete/index.js +0 -1
  102. package/qy-checkbox/index.js +0 -1
  103. package/qy-date-picker/index.js +0 -1
  104. package/qy-dialog/index.js +0 -1
  105. package/qy-form-section/index.js +0 -1
  106. package/qy-image/index.js +0 -1
  107. package/qy-image-preview/index.js +0 -1
  108. package/qy-image-upload/index.js +0 -1
  109. package/qy-input/index.js +0 -1
  110. package/qy-input-number/index.js +0 -1
  111. package/qy-legacy-selection-dialog/index.js +0 -1
  112. package/qy-menu-actions/index.js +0 -7
  113. package/qy-money-input/index.js +0 -1
  114. package/qy-radio-group/index.js +0 -1
  115. package/qy-record-quote-search/index.js +0 -1
  116. package/qy-remark-image/index.js +0 -1
  117. package/qy-remote-select/index.js +0 -1
  118. package/qy-search-input/index.js +0 -1
  119. package/qy-select/index.js +0 -1
  120. package/qy-selection-dialog/index.js +0 -1
  121. package/qy-table-column-settings/index.js +0 -10
  122. package/qy-tree-select/index.js +0 -1
  123. package/qy-upload/index.js +0 -1
package/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # @qynpm/ui
2
2
 
3
- 起印体系内抽离出来的 Vue 3 UI 组件包,当前主要包含基础输入组件、选择器组件、区块容器、底部操作栏,以及上传、弹窗、备注图文等通用能力。
4
-
5
- 录单拆包的 transform 实际代码盘点见 [录单拆包迁移总览](../record-order-migration.md)。其中记录了 `QyImagePreview`、凭证上传模式、设计文件管理等后续 UI 缺口。`QyRichTextEditor` 属于录单追加信息的独立业务组件,不进入当前全局 UI 基础包。
6
-
7
- ## 安装
3
+ 起印体系内抽离出来的 Vue 3 UI 组件包,当前主要包含基础输入组件、选择器组件、区块容器、底部操作栏,以及上传、弹窗、备注图文等通用能力。
4
+
5
+ 录单拆包的 transform 实际代码盘点见 [录单拆包迁移总览](../record-order-migration.md)。其中记录了 `QyImagePreview`、凭证上传模式、设计文件管理等后续 UI 缺口。`QyRichTextEditor` 属于录单追加信息的独立业务组件,不进入当前全局 UI 基础包。
6
+
7
+ ## 安装
8
8
 
9
9
  ```bash
10
10
  pnpm add @qynpm/ui
@@ -34,25 +34,27 @@ app.use(QyUI)
34
34
  也可以按需引入:
35
35
 
36
36
  ```ts
37
- import {
38
- QyUpload,
39
- QyImage,
40
- QyImagePreview,
41
- QyImageUpload,
37
+ import {
38
+ QyUpload,
39
+ QyImage,
40
+ QyImagePreview,
41
+ QyImageUpload,
42
42
  QyDialog,
43
+ QyButton,
44
+ QyDropdown,
43
45
  QyRemarkImage,
44
46
  QyInput,
45
47
  QyInputNumber,
46
- QyMoneyInput,
47
- QyDatePicker,
48
- QyCheckbox,
49
- QyAutocomplete,
50
- QyMenuActions,
51
- QyTableColumnSettings,
52
- QyRadioGroup,
53
- QySelect,
54
- QyTreeSelect,
55
- QyRemoteSelect,
48
+ QyMoneyInput,
49
+ QyDatePicker,
50
+ QyCheckbox,
51
+ QyAutocomplete,
52
+ QyMenuActions,
53
+ QyTableColumnSettings,
54
+ QyRadioGroup,
55
+ QySelect,
56
+ QyTreeSelect,
57
+ QyRemoteSelect,
56
58
  QySelectionDialog,
57
59
  QyFormSection,
58
60
  QyActionBar,
@@ -66,30 +68,48 @@ import {
66
68
  ```ts
67
69
  import QyInput from '@qynpm/ui/qy-input'
68
70
  import QyMoneyInput from '@qynpm/ui/qy-money-input'
69
- import QyRadioGroup from '@qynpm/ui/qy-radio-group'
70
- import QySelect from '@qynpm/ui/qy-select'
71
- import QyTreeSelect from '@qynpm/ui/qy-tree-select'
72
- import QyRemoteSelect from '@qynpm/ui/qy-remote-select'
71
+ import QyRadioGroup from '@qynpm/ui/qy-radio-group'
72
+ import QySelect from '@qynpm/ui/qy-select'
73
+ import QyTreeSelect from '@qynpm/ui/qy-tree-select'
74
+ import QyRemoteSelect from '@qynpm/ui/qy-remote-select'
73
75
  import QySelectionDialog from '@qynpm/ui/qy-selection-dialog'
74
76
  import QyFormSection from '@qynpm/ui/qy-form-section'
75
77
  import QyActionBar from '@qynpm/ui/qy-action-bar'
78
+ import QyButton from '@qynpm/ui/qy-button'
79
+ import QyDropdown from '@qynpm/ui/qy-dropdown'
76
80
  import QySearchInput from '@qynpm/ui/qy-search-input'
77
81
  import QyRecordQuoteSearch from '@qynpm/ui/qy-record-quote-search'
78
- import QyDialog from '@qynpm/ui/qy-dialog'
79
- import QyUpload from '@qynpm/ui/qy-upload'
80
- import QyImage from '@qynpm/ui/qy-image'
81
- import QyImagePreview from '@qynpm/ui/qy-image-preview'
82
- import QyImageUpload from '@qynpm/ui/qy-image-upload'
82
+ import QyDialog from '@qynpm/ui/qy-dialog'
83
+ import QyUpload from '@qynpm/ui/qy-upload'
84
+ import QyImage from '@qynpm/ui/qy-image'
85
+ import QyImagePreview from '@qynpm/ui/qy-image-preview'
86
+ import QyImageUpload from '@qynpm/ui/qy-image-upload'
83
87
  import QyRemarkImage from '@qynpm/ui/qy-remark-image'
84
- import QyInputNumber from '@qynpm/ui/qy-input-number'
85
- import QyDatePicker from '@qynpm/ui/qy-date-picker'
86
- import QyCheckbox from '@qynpm/ui/qy-checkbox'
87
- import QyAutocomplete from '@qynpm/ui/qy-autocomplete'
88
- import QyMenuActions from '@qynpm/ui/qy-menu-actions'
88
+ import QyInputNumber from '@qynpm/ui/qy-input-number'
89
+ import QyDatePicker from '@qynpm/ui/qy-date-picker'
90
+ import QyCheckbox from '@qynpm/ui/qy-checkbox'
91
+ import QyAutocomplete from '@qynpm/ui/qy-autocomplete'
92
+ import QyMenuActions from '@qynpm/ui/qy-menu-actions'
89
93
  import QyTableColumnSettings from '@qynpm/ui/qy-table-column-settings'
90
94
  ```
91
95
 
92
- ## 组件说明
96
+ 后台公共包必须通过 `@qynpm/ui/<子组件>` 使用 UI 能力。每个被后台公共包消费的子入口必须是自包含入口,直接组装对应组件并保留该子入口的命名导出,禁止再转发到 `../index.js` 加载 UI 根入口。这样可以保证发布包按需加载,也能让本地源码联调稳定解析到唯一物理模块。
97
+
98
+ 本地 file 依赖联调说明:单组件入口的 `package.json exports` 指向 `dist/qy-*/index.mjs` 和 `dist/qy-*/index.cjs`,而 `dist` 不提交到仓库。消费项目如果通过 `file:../qy-components/packages/ui` 引用本包,必须先在 `qy-components` 执行:
99
+
100
+ ```bash
101
+ pnpm --filter @qynpm/ui build
102
+ ```
103
+
104
+ 然后在消费项目刷新 file 依赖安装视图,例如:
105
+
106
+ ```bash
107
+ pnpm install --frozen-lockfile --ignore-scripts
108
+ ```
109
+
110
+ 不要依赖本机残留的 `packages/ui/dist`。如果后续希望免 build 联调,应在消费项目显式配置源码 alias,而不是把包 export 指向未发布源码。
111
+
112
+ ## 组件说明
93
113
 
94
114
  ### `QyUpload`
95
115
 
@@ -127,7 +147,7 @@ import QyTableColumnSettings from '@qynpm/ui/qy-table-column-settings'
127
147
  - `showText=false` 可隐藏文字备注区;如仍需粘贴入口,可开启 `showPasteInput`
128
148
  - `defaultValue` 仍保留给老页面做非受控初始化;新页面建议优先使用 `v-model`
129
149
 
130
- ### `QyImageUpload`
150
+ ### `QyImageUpload`
131
151
 
132
152
  图片/文件字段上传组件,基于 `QyUpload` 的薄封装,适合商品图、设计图、成本附图、凭证图片集合、单视频字段等场景。
133
153
 
@@ -139,149 +159,149 @@ import QyTableColumnSettings from '@qynpm/ui/qy-table-column-settings'
139
159
  - 默认 `name="files"`
140
160
  - 默认 `showText=false`
141
161
  - 默认开启纯粘贴输入条
142
- - 默认 `size="128px"`
143
- - 支持 `supportVideo`、`fileType`、`fileSize`
144
- - 支持透传 `uploadRequest`,用于接入宿主项目上传请求
145
-
146
- 凭证上传模式:
147
-
148
- - `mode="voucher"` 或 `voucher` 可启用凭证图片场景。
149
- - 默认允许 `jpg / jpeg / png / gif / bmp / webp`。
150
- - 默认 `limit=30`,保留纯粘贴入口,适合收款凭证、成本附图等旧 `CopyImgUpload` 使用点。
151
- - 暴露 `getFullPathList()` 和 `fullPathList`,兼容旧页面 `ref.fullPathList.join(',')` 的读值方式。
152
- - 上传成功时额外触发 `updateImg(url)`,兼容旧 `CopyImgUpload` 的成功通知语义。
153
-
154
- `QyImageUpload` 不保留旧 `imageUpload` 的 `successUpload(fileList)` 回调。旧页面迁移时优先改为 `v-model`;确实依赖旧 `CopyImgUpload` 读值方式的页面,可先用凭证模式的 `fullPathList / getFullPathList()` 过渡。
155
-
156
- ### `QyImage`
157
-
158
- 图片展示组件,计划承接旧 `packages/qiyin/components/Image`,并作为 `@qynpm/table-schema` 的 `image` 列渲染底座。
159
-
160
- 这是后续替代旧 `useCol` 的前置组件。旧 `useCol/render/imageRender.vue` 的表格列渲染不应该在 `@qynpm/table-schema` 内重复维护一套通用图片组件,而应组合 `QyImage`。
161
-
162
- 必须完整覆盖旧能力:
163
-
164
- - `src` 图片地址。
165
- - `width / height / size` 缩略图尺寸。
166
- - `fit` 图片填充方式,透传 `ElImage`。
167
- - 加载中状态。
168
- - 加载失败状态。
169
- - `error` 事件。
170
- - `placeholder` 空图占位。
171
- - `compressor` 压缩缩略图参数。
172
- - 旧域名兼容:`ys.diansan.com` 地址迁移为 `https://admin.qiyinbz.com`。
173
- - 旧缩略图参数:点三域名使用 `?small=true&style=image/resize,h_{h},w_{w}`,其他域名使用 `?w={w}`。
174
- - 失败兜底:缩略图请求失败后请求原图 blob,并用浏览器 canvas 压缩成 dataURL 展示。
175
- - `preview / previewList / initialIndex` 图片预览。
176
-
177
- 失败兜底属于旧公共图片组件能力,不是录单业务逻辑。当前实现不新增 `compressorjs`,使用浏览器原生 `fetch + blob + canvas` 完成压缩;如果后续发现必须完全等价旧 `compressorjs` 的压缩细节,再单独评估是否新增依赖。
178
-
179
- 建议新组件 API:
180
-
181
- ```ts
182
- type QyImageProps = {
183
- src?: string
184
- width?: number | string
185
- height?: number | string
186
- size?: number
187
- fit?: 'fill' | 'contain' | 'cover' | 'none' | 'scale-down'
188
- placeholder?: boolean
189
- compressor?: boolean | {
190
- w?: number
191
- h?: number
192
- q?: number
193
- }
194
- preview?: boolean
195
- previewList?: string[]
196
- initialIndex?: number
197
- }
198
- ```
199
-
200
- 表格 image 列后续直接组合 `QyImage` 和 `QyImagePreview`,不要在 `@qynpm/table-schema` 里复制一份通用图片组件。
201
-
202
- 已完成:
203
-
204
- - 创建 `@qiyin/UI/qy-image` 入口。
205
- - 创建 `src/docs/QyImageDoc.vue` playground 文档。
206
- - 补 `index.js / index.d.ts / package.json exports / files`。
207
- - 补构建入口,确保 `@qynpm/ui/qy-image` 可按需引入。
208
- - 补失败压缩兜底,不新增 `compressorjs`。
209
- - 补 `preview` 接入,可点击打开 `QyImagePreview`。
210
-
211
- ### `QyImagePreview`
212
-
213
- 图片预览组件,承接旧 `useCol/render/imageRender.vue` 中动态创建 `ElImageViewer` 的逻辑。
214
-
215
- 需要支持:
216
-
217
- - `urlList` 图片列表。
218
- - `initialIndex` 初始预览索引。
219
- - 打开时控制 `body.style.overflow = 'hidden'`。
220
- - 关闭时恢复 body 滚动并销毁实例。
221
- - 支持直接作为组件使用,也支持函数式调用,例如 `openQyImagePreview({ urlList, initialIndex })`。
222
-
223
- 该能力是 `@qynpm/table-schema` 完整迁移 image 列的前置能力。table-schema 不应该长期维护一份独立图片预览逻辑。
224
-
225
- ### `QyCheckbox`
226
-
227
- 复选框基础组件,基于 `ElCheckbox` 做薄封装,统一 `v-model`、`change`、`focus`、`blur` 事件和单组件入口。
228
-
229
- 主要用于普通表单复选框,以及 `@qynpm/table-schema` 的 `edit-checkbox` 渲染器底座。
230
-
231
- ### `QyAutocomplete`
232
-
233
- 自动完成输入基础组件,基于 `ElAutocomplete` 做薄封装,支持本地 `options` 过滤和 Element Plus 原生 `fetchSuggestions` 透传。
234
-
235
- 默认协议:
236
-
237
- - `v-model` 绑定输入值。
238
- - `options` 支持 `{ value }` 列表,也支持通过 `valueKey` 映射其它字段。
239
- - 默认按 `option.value.includes(query)` 过滤。
240
- - 支持 `select / change / input / clear / focus / blur` 事件。
241
-
242
- 该组件作为 `@qynpm/table-schema` 的 `edit-autocomplete` 渲染器底座,表格 row 写回逻辑仍留在 table-schema。
243
-
244
- ### `QyMenuActions`
245
-
246
- 表格行操作 UI 底座,承接旧 `useCol/render/menu.vue` 的通用展示能力。
247
-
248
- 支持:
249
-
250
- - `inline` 横向操作模式。
251
- - `popover` 更多操作模式。
252
- - `actions` 列表。
253
- - `hidden / disabled / loading` 支持布尔值或按行上下文计算。
254
- - `type` 控制默认、主色、成功、警告、危险操作色。
255
- - `confirmMethod(action, context)` 由宿主注入确认逻辑。
256
- - `action(action, context)` 只在可执行且确认通过后触发。
257
-
258
- `QyMenuActions` 不内置权限、路由、缓存、弹窗实例、消息提示,也不直接执行业务方法。权限过滤和业务执行应留在 `@qynpm/table-schema` adapter 或宿主页面。
259
-
260
- ### `QyTableColumnSettings`
261
-
262
- 表格列设置 UI 底座,承接旧 `useCol/render/setup.vue` 的通用 UI 能力。
263
-
264
- 支持:
265
-
266
- - 列列表展示。
267
- - 当前选中列。
268
- - 置顶、置底、上移、下移。
269
- - 固定左侧、固定右侧、取消固定。
270
- - 列宽编辑。
271
- - 显隐开关。
272
- - 恢复默认。
273
- - 删除缓存。
274
-
275
- 业务缓存读写仍由 `@qynpm/table-schema` 的 settings adapter 或宿主 adapter 负责,UI 组件只负责展示和编辑 settings。
276
-
277
- ### 编辑类基础组件(待评估)
278
-
279
- 旧 `useCol` 的 `edit-input / edit-autocomplete` 有一套“展示态 -> 点击编辑 -> blur/enter 写回”的通用交互。后续有两种选择:
280
-
281
- - 如果表格外也需要该交互,补 `QyInlineEditInput` 和 `QyAutocompleteInput`。
282
- - 如果只服务表格列,先放在 `@qynpm/table-schema` renderer 内部,避免 UI 包过早扩大。
283
-
284
- ### `QyDialog`
162
+ - 默认 `size="128px"`
163
+ - 支持 `supportVideo`、`fileType`、`fileSize`
164
+ - 支持透传 `uploadRequest`,用于接入宿主项目上传请求
165
+
166
+ 凭证上传模式:
167
+
168
+ - `mode="voucher"` 或 `voucher` 可启用凭证图片场景。
169
+ - 默认允许 `jpg / jpeg / png / gif / bmp / webp`。
170
+ - 默认 `limit=30`,保留纯粘贴入口,适合收款凭证、成本附图等旧 `CopyImgUpload` 使用点。
171
+ - 暴露 `getFullPathList()` 和 `fullPathList`,兼容旧页面 `ref.fullPathList.join(',')` 的读值方式。
172
+ - 上传成功时额外触发 `updateImg(url)`,兼容旧 `CopyImgUpload` 的成功通知语义。
173
+
174
+ `QyImageUpload` 不保留旧 `imageUpload` 的 `successUpload(fileList)` 回调。旧页面迁移时优先改为 `v-model`;确实依赖旧 `CopyImgUpload` 读值方式的页面,可先用凭证模式的 `fullPathList / getFullPathList()` 过渡。
175
+
176
+ ### `QyImage`
177
+
178
+ 图片展示组件,计划承接旧 `packages/qiyin/components/Image`,并作为 `@qynpm/table-schema` 的 `image` 列渲染底座。
179
+
180
+ 这是后续替代旧 `useCol` 的前置组件。旧 `useCol/render/imageRender.vue` 的表格列渲染不应该在 `@qynpm/table-schema` 内重复维护一套通用图片组件,而应组合 `QyImage`。
181
+
182
+ 必须完整覆盖旧能力:
183
+
184
+ - `src` 图片地址。
185
+ - `width / height / size` 缩略图尺寸。
186
+ - `fit` 图片填充方式,透传 `ElImage`。
187
+ - 加载中状态。
188
+ - 加载失败状态。
189
+ - `error` 事件。
190
+ - `placeholder` 空图占位。
191
+ - `compressor` 压缩缩略图参数。
192
+ - 旧域名兼容:`ys.diansan.com` 地址迁移为 `https://admin.qiyinbz.com`。
193
+ - 旧缩略图参数:点三域名使用 `?small=true&style=image/resize,h_{h},w_{w}`,其他域名使用 `?w={w}`。
194
+ - 失败兜底:缩略图请求失败后请求原图 blob,并用浏览器 canvas 压缩成 dataURL 展示。
195
+ - `preview / previewList / initialIndex` 图片预览。
196
+
197
+ 失败兜底属于旧公共图片组件能力,不是录单业务逻辑。当前实现不新增 `compressorjs`,使用浏览器原生 `fetch + blob + canvas` 完成压缩;如果后续发现必须完全等价旧 `compressorjs` 的压缩细节,再单独评估是否新增依赖。
198
+
199
+ 建议新组件 API:
200
+
201
+ ```ts
202
+ type QyImageProps = {
203
+ src?: string
204
+ width?: number | string
205
+ height?: number | string
206
+ size?: number
207
+ fit?: 'fill' | 'contain' | 'cover' | 'none' | 'scale-down'
208
+ placeholder?: boolean
209
+ compressor?: boolean | {
210
+ w?: number
211
+ h?: number
212
+ q?: number
213
+ }
214
+ preview?: boolean
215
+ previewList?: string[]
216
+ initialIndex?: number
217
+ }
218
+ ```
219
+
220
+ 表格 image 列后续直接组合 `QyImage` 和 `QyImagePreview`,不要在 `@qynpm/table-schema` 里复制一份通用图片组件。
221
+
222
+ 已完成:
223
+
224
+ - 创建 `@qiyin/UI/qy-image` 入口。
225
+ - 创建 `src/docs/QyImageDoc.vue` playground 文档。
226
+ - 补 `index.js / index.d.ts / package.json exports / files`。
227
+ - 补构建入口,确保 `@qynpm/ui/qy-image` 可按需引入。
228
+ - 补失败压缩兜底,不新增 `compressorjs`。
229
+ - 补 `preview` 接入,可点击打开 `QyImagePreview`。
230
+
231
+ ### `QyImagePreview`
232
+
233
+ 图片预览组件,承接旧 `useCol/render/imageRender.vue` 中动态创建 `ElImageViewer` 的逻辑。
234
+
235
+ 需要支持:
236
+
237
+ - `urlList` 图片列表。
238
+ - `initialIndex` 初始预览索引。
239
+ - 打开时控制 `body.style.overflow = 'hidden'`。
240
+ - 关闭时恢复 body 滚动并销毁实例。
241
+ - 支持直接作为组件使用,也支持函数式调用,例如 `openQyImagePreview({ urlList, initialIndex })`。
242
+
243
+ 该能力是 `@qynpm/table-schema` 完整迁移 image 列的前置能力。table-schema 不应该长期维护一份独立图片预览逻辑。
244
+
245
+ ### `QyCheckbox`
246
+
247
+ 复选框基础组件,基于 `ElCheckbox` 做薄封装,统一 `v-model`、`change`、`focus`、`blur` 事件和单组件入口。
248
+
249
+ 主要用于普通表单复选框,以及 `@qynpm/table-schema` 的 `edit-checkbox` 渲染器底座。
250
+
251
+ ### `QyAutocomplete`
252
+
253
+ 自动完成输入基础组件,基于 `ElAutocomplete` 做薄封装,支持本地 `options` 过滤和 Element Plus 原生 `fetchSuggestions` 透传。
254
+
255
+ 默认协议:
256
+
257
+ - `v-model` 绑定输入值。
258
+ - `options` 支持 `{ value }` 列表,也支持通过 `valueKey` 映射其它字段。
259
+ - 默认按 `option.value.includes(query)` 过滤。
260
+ - 支持 `select / change / input / clear / focus / blur` 事件。
261
+
262
+ 该组件作为 `@qynpm/table-schema` 的 `edit-autocomplete` 渲染器底座,表格 row 写回逻辑仍留在 table-schema。
263
+
264
+ ### `QyMenuActions`
265
+
266
+ 表格行操作 UI 底座,承接旧 `useCol/render/menu.vue` 的通用展示能力。
267
+
268
+ 支持:
269
+
270
+ - `inline` 横向操作模式。
271
+ - `popover` 更多操作模式。
272
+ - `actions` 列表。
273
+ - `hidden / disabled / loading` 支持布尔值或按行上下文计算。
274
+ - `type` 控制默认、主色、成功、警告、危险操作色。
275
+ - `confirmMethod(action, context)` 由宿主注入确认逻辑。
276
+ - `action(action, context)` 只在可执行且确认通过后触发。
277
+
278
+ `QyMenuActions` 不内置权限、路由、缓存、弹窗实例、消息提示,也不直接执行业务方法。权限过滤和业务执行应留在 `@qynpm/table-schema` adapter 或宿主页面。
279
+
280
+ ### `QyTableColumnSettings`
281
+
282
+ 表格列设置 UI 底座,承接旧 `useCol/render/setup.vue` 的通用 UI 能力。
283
+
284
+ 支持:
285
+
286
+ - 列列表展示。
287
+ - 当前选中列。
288
+ - 置顶、置底、上移、下移。
289
+ - 固定左侧、固定右侧、取消固定。
290
+ - 列宽编辑。
291
+ - 显隐开关。
292
+ - 恢复默认。
293
+ - 删除缓存。
294
+
295
+ 业务缓存读写仍由 `@qynpm/table-schema` 的 settings adapter 或宿主 adapter 负责,UI 组件只负责展示和编辑 settings。
296
+
297
+ ### 编辑类基础组件(待评估)
298
+
299
+ 旧 `useCol` 的 `edit-input / edit-autocomplete` 有一套“展示态 -> 点击编辑 -> blur/enter 写回”的通用交互。后续有两种选择:
300
+
301
+ - 如果表格外也需要该交互,补 `QyInlineEditInput` 和 `QyAutocompleteInput`。
302
+ - 如果只服务表格列,先放在 `@qynpm/table-schema` renderer 内部,避免 UI 包过早扩大。
303
+
304
+ ### `QyDialog`
285
305
 
286
306
  弹窗组件,支持:
287
307
 
@@ -291,7 +311,42 @@ type QyImageProps = {
291
311
  - 自定义 footer
292
312
  - 移动端自动全屏
293
313
 
294
- ### `QySelectionDialog`
314
+ ### `QyButton`
315
+
316
+ 后台按钮统一入口,后续 AdminShell 和业务页按钮迁移时优先使用该组件,而不是直接写原生 `button` 或分散使用 `ElButton`。
317
+
318
+ 核心能力:
319
+
320
+ - `type="default | primary | success | warning | danger | text | ghost | link"` 控制视觉类型。
321
+ - `size="sm | md | lg"` 控制高度、padding、gap、字号和图标尺寸,默认 `md`。
322
+ - `disabled` 和 `loading` 都会阻止 `click` 事件;`loading` 会展示内置 loading 状态。
323
+ - `active` 用于顶部当前系统、tabs 当前操作等选中态。
324
+ - `block` 撑满父容器,`round` 显式开启胶囊圆角;默认后台圆角保持紧凑。
325
+ - `native-type="button | submit | reset"` 控制原生按钮类型,默认 `button`。
326
+ - `prefix-icon / suffix-icon` 只支持 Vue 组件图标;也可以通过 `prefix / suffix` 插槽传入前后图标;`icon-only` 必须提供 `aria-label` 或 `title`。
327
+
328
+ 样式 token:
329
+
330
+ - 尺寸类:`--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`。
331
+ - 状态类:`--qy-button-default-*`、`--qy-button-primary-*`、`--qy-button-success-*`、`--qy-button-warning-*`、`--qy-button-danger-*`、`--qy-button-disabled-*`、`--qy-button-focus-ring`。
332
+ - token 默认从 Element Plus 的 `--el-*` 设计变量取值,宿主可覆盖 `--qy-button-*` 做主题适配。
333
+
334
+ ### `QyDropdown`
335
+
336
+ 后台下拉菜单统一入口,后续 AdminShell、工具栏和更多操作菜单迁移时优先使用该组件,而不是在业务页面散落手写原生 dropdown DOM。
337
+
338
+ 核心能力:
339
+
340
+ - `items` 支持 `{ key, label, icon, disabled, danger, hidden, divided, active, title }`。
341
+ - `hidden` 项不渲染,`disabled` 项不触发 `select`。
342
+ - `danger` 和 `active` 项会输出稳定的 `is-danger` / `is-active` class,以及 `data-danger` / `data-active` 标记。
343
+ - `trigger="click"` 为默认触发方式,预留 `contextmenu`。
344
+ - `v-model` / `model-value` 支持受控打开状态;受控模式下只触发 `update:modelValue` 和 `open-change`,不私自决定最终打开状态。
345
+ - `close-on-select=false` 可在选择后保持面板打开。
346
+ - `panel-width` / `width` 和 `max-height` 控制面板尺寸。
347
+ - `trigger`、`item`、`header`、`footer`、`empty` 插槽用于业务定制展示;`trigger` 插槽应把 `attrs` 绑定到实际触发按钮上。
348
+
349
+ ### `QySelectionDialog`
295
350
 
296
351
  数据选择弹窗底座,参考老 `@qiyin/components/Dialog` 的核心能力迁移,但不内置任何 ERP 接口或权限逻辑。
297
352
 
@@ -316,11 +371,11 @@ type QyImageProps = {
316
371
  - `side`、`search`、`toolbar` 插槽扩展业务区域
317
372
  - Element Plus 原生分页
318
373
 
319
- `QySelectionDialog` 只解决“怎么选”,不解决“选什么”。业务接口、字段映射、权限判断应放在宿主项目 wrapper 中。
320
-
321
- 迁移业务选择器前,建议先阅读:
322
-
323
- - [选择弹窗迁移规范](./选择弹窗迁移规范.md)
374
+ `QySelectionDialog` 只解决“怎么选”,不解决“选什么”。业务接口、字段映射、权限判断应放在宿主项目 wrapper 中。
375
+
376
+ 迁移业务选择器前,建议先阅读:
377
+
378
+ - [选择弹窗迁移规范](./选择弹窗迁移规范.md)
324
379
 
325
380
  选择状态采用“弹窗草稿 + 确认提交”协议:
326
381
 
@@ -346,11 +401,11 @@ type QyImageProps = {
346
401
  - `defaultValue` 解析 `[url:图片地址]备注文本`
347
402
  - `defaultImage` 独立图片默认值
348
403
  - `change(value, imageUrl)` 输出完整备注值和图片地址
349
- - 粘贴图片上传
350
- - 悬浮预览和删除图片
351
- - `uploadRequest` 自定义上传请求
352
- - `layout="select-prefix"` 可把一个基础下拉值合并成输入前缀,用于“下拉值 + 图文备注”这类旧协议字段
353
- - `deleteImage()` / `clearContent()` / `getValue()` 暴露方法,兼容旧表单重置和读取协议值
404
+ - 粘贴图片上传
405
+ - 悬浮预览和删除图片
406
+ - `uploadRequest` 自定义上传请求
407
+ - `layout="select-prefix"` 可把一个基础下拉值合并成输入前缀,用于“下拉值 + 图文备注”这类旧协议字段
408
+ - `deleteImage()` / `clearContent()` / `getValue()` 暴露方法,兼容旧表单重置和读取协议值
354
409
 
355
410
  默认上传会使用:
356
411
 
@@ -358,24 +413,24 @@ type QyImageProps = {
358
413
  - `tokenKey`,默认 `Admin-Token`
359
414
  - `uploadName`,默认 `files`
360
415
 
361
- 如果宿主项目有统一 request、baseURL、鉴权、错误处理或登录失效处理,应优先传入 `uploadRequest`,不要在组件内部写死项目请求实现。
362
-
363
- 组合下拉输入:
364
-
365
- ```vue
366
- <QyRemarkImage
367
- layout="select-prefix"
368
- :select-value="postageValue"
369
- :select-options="[
370
- { label: '包邮', value: '包邮' },
371
- { label: '不包邮', value: '不包邮' }
372
- ]"
373
- placeholder="备注 / 粘贴图片"
374
- type="text"
375
- @update:select-value="postageValue = $event"
376
- @change="handleRemarkChange"
377
- />
378
- ```
416
+ 如果宿主项目有统一 request、baseURL、鉴权、错误处理或登录失效处理,应优先传入 `uploadRequest`,不要在组件内部写死项目请求实现。
417
+
418
+ 组合下拉输入:
419
+
420
+ ```vue
421
+ <QyRemarkImage
422
+ layout="select-prefix"
423
+ :select-value="postageValue"
424
+ :select-options="[
425
+ { label: '包邮', value: '包邮' },
426
+ { label: '不包邮', value: '不包邮' }
427
+ ]"
428
+ placeholder="备注 / 粘贴图片"
429
+ type="text"
430
+ @update:select-value="postageValue = $event"
431
+ @change="handleRemarkChange"
432
+ />
433
+ ```
379
434
 
380
435
  ### `QyInput`
381
436
 
@@ -447,35 +502,35 @@ type QyImageProps = {
447
502
  - `value`:映射后的选项值
448
503
  - `disabled`:是否禁用
449
504
 
450
- ### `QySelect`
451
-
452
- 选择器组件,第一版定位为 `ElSelect` 的轻量包装层,重点支持:
505
+ ### `QySelect`
506
+
507
+ 选择器组件,第一版定位为 `ElSelect` 的轻量包装层,重点支持:
453
508
 
454
509
  - `options` 直出
455
510
  - `labelKey / valueKey / disabledKey` 映射
456
511
  - 单选 / 多选
457
512
  - `collapse-tags`
458
- - 默认弹层挂载策略
459
- - 保留原生 slot 扩展
460
-
461
- ### `QyTreeSelect`
462
-
463
- 树选择组件,第一版定位为 `ElTreeSelect` 的轻量包装层,重点支持:
464
-
465
- - `options` 树数据直出
466
- - 兼容 `ElTreeSelect` 的 `data` 参数
467
- - `labelKey / valueKey / childrenKey / disabledKey` 字段映射
468
- - 单选 / 多选
469
- - `check-strictly`
470
- - `collapse-tags`
471
- - 默认弹层挂载策略
472
- - 保留原始节点字段,便于业务 slot 和后续透传使用
473
-
474
- `QyTreeSelect` 只处理树选择器的通用 UI 协议,不内置远程请求、权限过滤或业务接口格式化。业务接口返回字段不一致时,优先通过字段映射解决,避免每个页面先手写一遍 tree map。
475
-
476
- 为降低迁移成本,`QyTreeSelect` 的 `clearable`、`filterable`、`check-strictly`、`render-after-expand`、`fit-input-width` 等默认行为尽量跟随 `ElTreeSelect`。业务需要搜索、清空、父子不联动时应显式传参。
477
-
478
- ### `QyRemoteSelect`
513
+ - 默认弹层挂载策略
514
+ - 保留原生 slot 扩展
515
+
516
+ ### `QyTreeSelect`
517
+
518
+ 树选择组件,第一版定位为 `ElTreeSelect` 的轻量包装层,重点支持:
519
+
520
+ - `options` 树数据直出
521
+ - 兼容 `ElTreeSelect` 的 `data` 参数
522
+ - `labelKey / valueKey / childrenKey / disabledKey` 字段映射
523
+ - 单选 / 多选
524
+ - `check-strictly`
525
+ - `collapse-tags`
526
+ - 默认弹层挂载策略
527
+ - 保留原始节点字段,便于业务 slot 和后续透传使用
528
+
529
+ `QyTreeSelect` 只处理树选择器的通用 UI 协议,不内置远程请求、权限过滤或业务接口格式化。业务接口返回字段不一致时,优先通过字段映射解决,避免每个页面先手写一遍 tree map。
530
+
531
+ 为降低迁移成本,`QyTreeSelect` 的 `clearable`、`filterable`、`check-strictly`、`render-after-expand`、`fit-input-width` 等默认行为尽量跟随 `ElTreeSelect`。业务需要搜索、清空、父子不联动时应显式传参。
532
+
533
+ ### `QyRemoteSelect`
479
534
 
480
535
  远程选择器组件,基于 `QySelect` 组合实现,重点支持:
481
536
 
@@ -576,7 +631,7 @@ type QyImageProps = {
576
631
  </template>
577
632
  ```
578
633
 
579
- ### QyImageUpload
634
+ ### QyImageUpload
580
635
 
581
636
  单图字段:
582
637
 
@@ -587,37 +642,37 @@ type QyImageProps = {
587
642
  api="/permission-api/common/uploads"
588
643
  :file-size="5"
589
644
  />
590
- </template>
591
- ```
592
-
593
- ### QyImage
594
-
595
- ```vue
596
- <template>
597
- <QyImage
598
- src="https://img.example.com/a.jpg"
599
- :size="48"
600
- fit="cover"
601
- preview
602
- :compressor="{ w: 200, h: 200, q: 50 }"
603
- />
604
- </template>
605
- ```
606
-
607
- 函数式预览:
608
-
609
- ```ts
610
- import { openQyImagePreview } from '@qynpm/ui'
611
-
612
- openQyImagePreview({
613
- urlList: ['https://img.example.com/a.jpg'],
614
- initialIndex: 0
615
- })
616
- ```
645
+ </template>
646
+ ```
617
647
 
618
- 多图字段:
619
-
620
- ```vue
648
+ ### QyImage
649
+
650
+ ```vue
651
+ <template>
652
+ <QyImage
653
+ src="https://img.example.com/a.jpg"
654
+ :size="48"
655
+ fit="cover"
656
+ preview
657
+ :compressor="{ w: 200, h: 200, q: 50 }"
658
+ />
659
+ </template>
660
+ ```
661
+
662
+ 函数式预览:
663
+
664
+ ```ts
665
+ import { openQyImagePreview } from '@qynpm/ui'
666
+
667
+ openQyImagePreview({
668
+ urlList: ['https://img.example.com/a.jpg'],
669
+ initialIndex: 0
670
+ })
671
+ ```
672
+
673
+ 多图字段:
674
+
675
+ ```vue
621
676
  <template>
622
677
  <QyImageUpload
623
678
  v-model="payImages"
@@ -625,38 +680,38 @@ openQyImagePreview({
625
680
  multiple
626
681
  :limit="9"
627
682
  />
628
- </template>
629
- ```
630
-
631
- 凭证上传模式,迁移旧 `CopyImgUpload`:
632
-
633
- ```vue
634
- <template>
635
- <QyImageUpload
636
- ref="payImgRef"
637
- v-model="payImages"
638
- mode="voucher"
639
- api="/permission-api/common/uploads"
640
- :multiple="false"
641
- size="100px"
642
- />
643
- </template>
644
-
645
- <script setup>
646
- import { ref } from 'vue'
647
-
648
- const payImages = ref('')
649
- const payImgRef = ref(null)
650
-
651
- function getForms() {
652
- return {
653
- erpOrderPayImg: payImgRef.value.getFullPathList().join(',')
654
- }
655
- }
656
- </script>
657
- ```
658
-
659
- 接入宿主项目上传请求:
683
+ </template>
684
+ ```
685
+
686
+ 凭证上传模式,迁移旧 `CopyImgUpload`:
687
+
688
+ ```vue
689
+ <template>
690
+ <QyImageUpload
691
+ ref="payImgRef"
692
+ v-model="payImages"
693
+ mode="voucher"
694
+ api="/permission-api/common/uploads"
695
+ :multiple="false"
696
+ size="100px"
697
+ />
698
+ </template>
699
+
700
+ <script setup>
701
+ import { ref } from 'vue'
702
+
703
+ const payImages = ref('')
704
+ const payImgRef = ref(null)
705
+
706
+ function getForms() {
707
+ return {
708
+ erpOrderPayImg: payImgRef.value.getFullPathList().join(',')
709
+ }
710
+ }
711
+ </script>
712
+ ```
713
+
714
+ 接入宿主项目上传请求:
660
715
 
661
716
  ```vue
662
717
  <template>
@@ -681,9 +736,9 @@ async function uploadFile({ formData }) {
681
736
  </script>
682
737
  ```
683
738
 
684
- ### QyRemarkImage
685
-
686
- 默认上传:
739
+ ### QyRemarkImage
740
+
741
+ 默认上传:
687
742
 
688
743
  ```vue
689
744
  <template>
@@ -729,56 +784,100 @@ function handleRemarkChange(value: string, imageUrl?: string) {
729
784
  remark.value = value
730
785
  remarkImage.value = imageUrl || ''
731
786
  }
732
- </script>
733
- ```
734
-
735
- ### QyMenuActions
736
-
737
- ```vue
738
- <template>
739
- <QyMenuActions
740
- :row="row"
741
- :row-index="0"
742
- :actions="actions"
743
- :confirm-method="confirmAction"
744
- @action="handleAction"
745
- />
746
- </template>
747
-
748
- <script setup lang="ts">
749
- const row = { id: 1, status: 'draft' }
750
- const actions = [
751
- { key: 'edit', label: '编辑' },
752
- { key: 'delete', label: '删除', type: 'danger', confirm: true }
753
- ]
754
-
755
- function confirmAction(action, context) {
756
- return window.confirm(`确认${action.label}?`)
757
- }
758
-
759
- function handleAction(action, context) {
760
- // 业务执行、消息提示和权限判断留在宿主或 table-schema adapter。
761
- }
762
- </script>
763
- ```
764
-
765
- ### QyTableColumnSettings
766
-
767
- ```vue
768
- <template>
769
- <QyTableColumnSettings
770
- v-model="visible"
771
- :settings="settings"
772
- :default-settings="defaultSettings"
773
- @confirm="saveSettings"
774
- @delete-cache="removeSettingsCache"
775
- />
776
- </template>
777
- ```
778
-
779
- ### QyDialog
780
-
781
- ```vue
787
+ </script>
788
+ ```
789
+
790
+ ### QyMenuActions
791
+
792
+ ```vue
793
+ <template>
794
+ <QyMenuActions
795
+ :row="row"
796
+ :row-index="0"
797
+ :actions="actions"
798
+ :confirm-method="confirmAction"
799
+ @action="handleAction"
800
+ />
801
+ </template>
802
+
803
+ <script setup lang="ts">
804
+ const row = { id: 1, status: 'draft' }
805
+ const actions = [
806
+ { key: 'edit', label: '编辑' },
807
+ { key: 'delete', label: '删除', type: 'danger', confirm: true }
808
+ ]
809
+
810
+ function confirmAction(action, context) {
811
+ return window.confirm(`确认${action.label}?`)
812
+ }
813
+
814
+ function handleAction(action, context) {
815
+ // 业务执行、消息提示和权限判断留在宿主或 table-schema adapter。
816
+ }
817
+ </script>
818
+ ```
819
+
820
+ ### QyTableColumnSettings
821
+
822
+ ```vue
823
+ <template>
824
+ <QyTableColumnSettings
825
+ v-model="visible"
826
+ :settings="settings"
827
+ :default-settings="defaultSettings"
828
+ @confirm="saveSettings"
829
+ @delete-cache="removeSettingsCache"
830
+ />
831
+ </template>
832
+ ```
833
+
834
+ ### QyButton
835
+
836
+ ```vue
837
+ <template>
838
+ <QyButton type="primary" :prefix-icon="Search" @click="handleSearch">
839
+ 查询
840
+ </QyButton>
841
+ <QyButton loading>保存中</QyButton>
842
+ <QyButton icon-only :prefix-icon="Refresh" aria-label="刷新当前页" />
843
+ </template>
844
+ ```
845
+
846
+ ### QyDropdown
847
+
848
+ ```vue
849
+ <template>
850
+ <QyDropdown
851
+ :items="items"
852
+ panel-width="168px"
853
+ @select="handleSelect"
854
+ >
855
+ <template #trigger="{ attrs }">
856
+ <QyButton v-bind="attrs">
857
+ 更多
858
+ </QyButton>
859
+ </template>
860
+ </QyDropdown>
861
+ </template>
862
+
863
+ <script setup lang="ts">
864
+ import QyButton from '@qynpm/ui/qy-button'
865
+ import QyDropdown from '@qynpm/ui/qy-dropdown'
866
+
867
+ const items = [
868
+ { key: 'profile', label: '个人信息' },
869
+ { key: 'logout', label: '退出登录', danger: true, divided: true }
870
+ ]
871
+
872
+ function handleSelect(item) {
873
+ // 业务执行、路由跳转和权限判断留在宿主项目。
874
+ }
875
+ </script>
876
+ ```
877
+
878
+ ### QyDialog
879
+
880
+ ```vue
782
881
  <template>
783
882
  <QyDialog title="标题" @confirm="handleConfirm">
784
883
  内容区域
@@ -960,10 +1059,10 @@ function handleAction(action, context) {
960
1059
  - `QyDatePicker` 第一版优先兼容 `ElDatePicker`,查询结束时间归一化需要显式开启
961
1060
  - `QyRemoteSelect` 负责远程请求状态和回显保留,不承接具体业务接口协议转换
962
1061
  - `QyFormSection` 只负责区块壳,不替代 `@qiyin/form` 的 schema / 校验能力
963
- - `QyActionBar` 只负责底部布局壳,不负责编排按钮业务逻辑
964
- - `QySearchInput` 第一版已经覆盖建议搜索场景,可通过 `show-button=false` 关闭默认搜索按钮,但仍然不承接页面级副作用
965
- - `QyRecordQuoteSearch` 只承接报价单搜索入口逻辑,不直接改整页录单状态
966
- - `QyImage` 负责通用图片显示,不负责表格列取值、formatter、水印和列设置;这些由 `@qynpm/table-schema` 组合
1062
+ - `QyActionBar` 只负责底部布局壳,不负责编排按钮业务逻辑
1063
+ - `QySearchInput` 第一版已经覆盖建议搜索场景,可通过 `show-button=false` 关闭默认搜索按钮,但仍然不承接页面级副作用
1064
+ - `QyRecordQuoteSearch` 只承接报价单搜索入口逻辑,不直接改整页录单状态
1065
+ - `QyImage` 负责通用图片显示,不负责表格列取值、formatter、水印和列设置;这些由 `@qynpm/table-schema` 组合
967
1066
 
968
1067
  ## 当前联调说明
969
1068