@ithinkdt/ui 4.0.13 → 4.0.15

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.
package/README.md CHANGED
@@ -1 +1,526 @@
1
1
  # @ithinkdt/ui
2
+
3
+ ## 许可证
4
+
5
+ MIT
6
+
7
+ ## 安装
8
+
9
+ ```bash
10
+ npm i @ithinkdt/ui
11
+ ```
12
+
13
+ > 需要您自行安装 peer 依赖 `vue@>=3.5`、`vue-router@>=4.5` 与 `ithinkdt-ui@>=1.5`。如果使用页面渲染适配能力,需要安装 `@ithinkdt/page@>=4.0`;如果使用 UnoCSS 预设,需要安装 `unocss@>=66`。
14
+
15
+ ## 介绍
16
+
17
+ `@ithinkdt/ui` 提供 iThinkDT 应用 UI 层的组件、指令与渲染适配能力,包括:
18
+
19
+ - 应用布局、侧栏、菜单、面包屑、页签、通知、租户、账号、语言、外观切换组件
20
+ - 数据表单、查询筛选、数据表格、分页、批量选择、列自定义、详情描述组件
21
+ - 单选、多选、人员/部门选择、国际化输入、状态按钮等业务组件
22
+ - `v-spin`、`v-tooltip` 指令
23
+ - 与 `@ithinkdt/page` 对接的表单项、详情、模态框渲染器
24
+ - UnoCSS 主题色、圆角、快捷类与命名空间隔离预设
25
+ - 自动导入配置
26
+
27
+ ## 初始化
28
+
29
+ ### 注册 UI 上下文与指令 Provider
30
+
31
+ `UIProvider` 用于注入 UI 文案国际化能力;`SpinDirectiveProvider` 与 `TooltipDirectiveProvider` 用于挂载 `v-spin`、`v-tooltip` 所需的全局样式与浮层。
32
+
33
+ ```tsx
34
+ import { createApp } from 'vue'
35
+ import {
36
+ SpinDirectiveProvider,
37
+ TooltipDirectiveProvider,
38
+ UIProvider,
39
+ vSpin,
40
+ vTooltip,
41
+ } from '@ithinkdt/ui'
42
+
43
+ import App from './App.vue'
44
+
45
+ const app = createApp({
46
+ setup() {
47
+ return () => (
48
+ <UIProvider>
49
+ <SpinDirectiveProvider />
50
+ <TooltipDirectiveProvider />
51
+ <App />
52
+ </UIProvider>
53
+ )
54
+ },
55
+ })
56
+
57
+ app.directive('spin', vSpin)
58
+ app.directive('tooltip', vTooltip)
59
+ app.mount('#app')
60
+ ```
61
+
62
+ 如果项目已经使用 `@ithinkdt/vite` 的自动导入能力,可以直接使用 `@ithinkdt/ui/auto-imports`。
63
+
64
+ ```ts
65
+ import ImportsUI, { UIComponents, UIDirectives } from '@ithinkdt/ui/auto-imports'
66
+
67
+ export default {
68
+ plugins: [
69
+ presets({
70
+ components: {
71
+ resolvers: [
72
+ ...UIComponents,
73
+ ...UIDirectives,
74
+ ],
75
+ },
76
+ autoImport: {
77
+ imports: [
78
+ ...ImportsUI,
79
+ ],
80
+ },
81
+ }),
82
+ ],
83
+ }
84
+ ```
85
+
86
+ ### UnoCSS 预设
87
+
88
+ ```ts
89
+ import ithinkdt from '@ithinkdt/ui/unocss'
90
+ import { defineConfig } from 'unocss'
91
+
92
+ export default defineConfig({
93
+ presets: [
94
+ ithinkdt(),
95
+ ],
96
+ })
97
+ ```
98
+
99
+ 开启命名空间隔离时,UnoCSS 变量和选择器会被限定在指定容器内:
100
+
101
+ ```ts
102
+ export default defineConfig({
103
+ presets: [
104
+ ithinkdt({ namespace: 'my-app' }),
105
+ ],
106
+ })
107
+ ```
108
+
109
+ ## 应用布局
110
+
111
+ ### 基础布局
112
+
113
+ ```tsx
114
+ import {
115
+ AppAccount,
116
+ AppContent,
117
+ AppHeader,
118
+ AppLayout,
119
+ AppLogo,
120
+ AppMenu,
121
+ AppSidebar,
122
+ } from '@ithinkdt/ui'
123
+
124
+ const menus = [
125
+ {
126
+ type: 'view',
127
+ key: 'home',
128
+ name: '首页',
129
+ path: '/',
130
+ },
131
+ {
132
+ type: 'group',
133
+ key: 'system',
134
+ name: '系统管理',
135
+ children: [
136
+ { type: 'view', key: 'user', name: '用户管理', path: '/users' },
137
+ { type: 'view', key: 'role', name: '角色管理', path: '/roles' },
138
+ ],
139
+ },
140
+ ]
141
+
142
+ export default {
143
+ setup() {
144
+ const collapsed = ref(false)
145
+
146
+ return () => (
147
+ <AppLayout layout="left2right">
148
+ <AppSidebar v-model:collapsed={collapsed.value}>
149
+ <AppLogo name="管理后台" collapsed={collapsed.value} />
150
+ <AppMenu menus={menus} current="home" collapsed={collapsed.value} />
151
+ </AppSidebar>
152
+ <AppLayout>
153
+ <AppHeader>
154
+ <AppAccount
155
+ username="zhangsan"
156
+ nickname="张三"
157
+ onLogout={() => console.log('logout')}
158
+ />
159
+ </AppHeader>
160
+ <AppContent>
161
+ <RouterView />
162
+ </AppContent>
163
+ </AppLayout>
164
+ </AppLayout>
165
+ )
166
+ },
167
+ }
168
+ ```
169
+
170
+ ### 常用应用组件
171
+
172
+ | 组件 | 说明 |
173
+ |------|------|
174
+ | `AppLayout` | 应用布局容器,支持 `left2right` 与 `top2bottom` |
175
+ | `AppHeader` | 顶部栏 |
176
+ | `AppSidebar` | 侧边栏,支持折叠 |
177
+ | `AppContent` | 内容区,支持 `naive` / `native` 滚动条 |
178
+ | `AppFooter` | 底部栏 |
179
+ | `AppLogo` | 应用 Logo 与应用名 |
180
+ | `AppMenu` | 应用模块菜单 |
181
+ | `AppBreadcrumb` | 面包屑 |
182
+ | `AppAccount` | 用户账号下拉 |
183
+ | `AppFullscreen` | 全屏切换 |
184
+ | `AppAppearance` | 明暗主题切换 |
185
+ | `AppLanguage` | 语言切换 |
186
+ | `AppMultiTabs` | 多页签 |
187
+ | `AppNotification` | 消息通知 |
188
+ | `AppTenant` | 租户切换 |
189
+
190
+ ## 数据组件
191
+
192
+ 数据组件需要从 `@ithinkdt/ui/components` 导入。
193
+
194
+ ### 数据表单
195
+
196
+ `DataForm` 负责渲染 `@ithinkdt/page` 的表单项定义。
197
+
198
+ ```tsx
199
+ import { DataForm } from '@ithinkdt/ui/components'
200
+ import { useFormHelper } from '@ithinkdt/page'
201
+
202
+ export default {
203
+ setup() {
204
+ const { model, items, validate, reset } = useFormHelper(
205
+ ({ it }) => [
206
+ it('name', '姓名', 'input', { required: true }),
207
+ it('age', '年龄', 'number'),
208
+ it('status', '状态', 'select', {
209
+ selectProps: {
210
+ options: [
211
+ { label: '启用', value: '1' },
212
+ { label: '禁用', value: '0' },
213
+ ],
214
+ },
215
+ }),
216
+ ],
217
+ { initial: { name: '', status: '1' } },
218
+ )
219
+
220
+ async function submit() {
221
+ const [valid] = await validate()
222
+ if (valid) {
223
+ console.log(model)
224
+ }
225
+ }
226
+
227
+ return () => (
228
+ <DataForm
229
+ model={model}
230
+ items={items}
231
+ grid={{ cols: 12 }}
232
+ showColon
233
+ onSubmit={submit}
234
+ onReset={reset}
235
+ />
236
+ )
237
+ },
238
+ }
239
+ ```
240
+
241
+ ### 查询筛选
242
+
243
+ ```tsx
244
+ import { DataFilter } from '@ithinkdt/ui/components'
245
+ import { useFilterHelper } from '@ithinkdt/page'
246
+
247
+ const { model, items, reset } = useFilterHelper(({ it }) => [
248
+ it('keyword', '关键字', 'input'),
249
+ it('status', '状态', 'select', {
250
+ selectProps: {
251
+ options: statusOptions,
252
+ },
253
+ }),
254
+ ])
255
+
256
+ return () => (
257
+ <DataFilter
258
+ model={model}
259
+ items={items}
260
+ collapsible
261
+ onFilter={(filter) => ds.pull({ currentPage: 1 }, filter)}
262
+ onReset={reset}
263
+ />
264
+ )
265
+ ```
266
+
267
+ ### 数据表格与分页
268
+
269
+ ```tsx
270
+ import { DataPagination, DataTable } from '@ithinkdt/ui/components'
271
+ import { useDs, useTableHelper } from '@ithinkdt/page'
272
+
273
+ const ds = useDs(userApi.page, { pagination: 'remote' })
274
+
275
+ const { columns } = useTableHelper(({ col }) => [
276
+ col('name', '姓名', { width: 140 }),
277
+ col('email', '邮箱', { width: 220 }),
278
+ col('status', '状态', 'dict', {
279
+ dictParams: {
280
+ options: [
281
+ { label: '启用', value: '1' },
282
+ { label: '禁用', value: '0' },
283
+ ],
284
+ },
285
+ }),
286
+ ])
287
+
288
+ return () => (
289
+ <>
290
+ <DataTable
291
+ data={ds.data}
292
+ columns={columns.value}
293
+ sorter={ds.sorter}
294
+ selectedKeys={selectedKeys.value}
295
+ onSort={ds.sort}
296
+ onSelect={(keys) => selectedKeys.value = keys}
297
+ />
298
+ <DataPagination
299
+ page={ds.page}
300
+ total={ds.total}
301
+ onChange={ds.pull}
302
+ />
303
+ </>
304
+ )
305
+ ```
306
+
307
+ ### 其他数据组件
308
+
309
+ | 组件 / 方法 | 说明 |
310
+ |-------------|------|
311
+ | `DataFormActions` | 表单提交、重置、取消按钮组 |
312
+ | `DataSelection` | 批量选择状态展示,支持当前页 / 全部切换 |
313
+ | `DataCustom` | 表格列排序、隐藏、固定配置 |
314
+ | `DataActions` | 表格操作列按钮渲染 |
315
+ | `DataDescriptions` | 详情描述展示 |
316
+ | `DataLocaleInput` | 多语言输入 |
317
+ | `useLocaleEdit` | 多语言内容弹窗编辑 |
318
+ | `NStateButton` | 带成功 / 失败状态的按钮 |
319
+ | `NCheckboxes` | 字典友好的多选组 |
320
+ | `NRadios` | 字典友好的单选组 |
321
+ | `DtUserDept` | 用户 / 部门选择 |
322
+ | `DtUserRender` | 用户显示 |
323
+ | `DtDeptRender` | 部门显示 |
324
+
325
+ ## 与 `@ithinkdt/page` 集成
326
+
327
+ `@ithinkdt/ui/page` 提供 `@ithinkdt/page` 所需的渲染器,建议在 `@ithinkdt/page` 插件初始化时注册。
328
+
329
+ ```tsx
330
+ import pagePlugin from '@ithinkdt/page'
331
+ import { DataActions } from '@ithinkdt/ui/components'
332
+ import {
333
+ createDescriptionHelper,
334
+ createFormHelper,
335
+ createFormItemHelper,
336
+ createModalHelper,
337
+ } from '@ithinkdt/ui/page'
338
+
339
+ app.use(pagePlugin, {
340
+ getFormRenderer: createFormHelper(),
341
+ getModalRenderer: createModalHelper(),
342
+ getFormItemRenderer: createFormItemHelper({
343
+ uploadFile: async (file) => {
344
+ const formData = new FormData()
345
+ formData.append('file', file)
346
+ const res = await fetch('/api/files', { method: 'POST', body: formData })
347
+ return await res.text()
348
+ },
349
+ getFileInfos: async (ids) => {
350
+ return await fetch('/api/files/info', {
351
+ method: 'POST',
352
+ body: JSON.stringify(ids),
353
+ }).then(res => res.json())
354
+ },
355
+ getUserGroups: async () => [],
356
+ getUsersByGroup: async () => [],
357
+ getUsersByDept: async () => [],
358
+ getUsersByUsername: async () => [],
359
+ getDeptsByCode: async () => [],
360
+ }),
361
+ getDescriptionRenderer: createDescriptionHelper({
362
+ getFileInfos: async ids => [],
363
+ previewFileUrl: id => `/api/files/${id}/preview`,
364
+ getUsersByUsername: async usernames => [],
365
+ getDeptsByCode: async codes => [],
366
+ }),
367
+ getTableActionsRenderer: () => actions => <DataActions options={actions} />,
368
+ })
369
+ ```
370
+
371
+ ### 内置表单项类型
372
+
373
+ | 类型 | 说明 |
374
+ |------|------|
375
+ | `input` | 文本输入 |
376
+ | `number` | 数字输入,支持 `valueType` |
377
+ | `select` | 下拉选择,支持字典、远程 options、`valueType` |
378
+ | `checkbox` | 单个复选框 |
379
+ | `checkboxes` | 复选框组 |
380
+ | `radios` | 单选组 |
381
+ | `datepicker` | 日期选择 |
382
+ | `file` | 文件选择 |
383
+ | `upload` | 文件上传 |
384
+ | `user` | 用户 / 部门选择 |
385
+
386
+ ### 内置详情类型
387
+
388
+ | 类型 | 说明 |
389
+ |------|------|
390
+ | `longtext` | 长文本抽屉查看,支持复制 |
391
+ | `number` | 数字格式化,支持小数、百分比、千分位 |
392
+ | `date` | 日期格式化 |
393
+ | `datetime` | 日期时间格式化 |
394
+ | `dict` | 字典显示,支持状态色 |
395
+ | `email` | 邮箱链接 |
396
+ | `url` | URL 链接 |
397
+ | `color` | 颜色展示 |
398
+ | `file` | 文件链接 |
399
+ | `image` | 图片预览 |
400
+ | `user` | 用户展示 |
401
+ | `dept` | 部门展示 |
402
+
403
+ ## 指令
404
+
405
+ ### `v-spin`
406
+
407
+ ```vue
408
+ <template>
409
+ <section v-spin="loading" data-spin-tip="加载中...">
410
+ ...
411
+ </section>
412
+
413
+ <section v-spin.dark="submitting">
414
+ ...
415
+ </section>
416
+ </template>
417
+ ```
418
+
419
+ 支持 `light`、`dark` 修饰符;`data-spin-tip` 可设置提示文字。
420
+
421
+ ### `v-tooltip`
422
+
423
+ ```vue
424
+ <template>
425
+ <span v-tooltip.auto="'完整内容'">
426
+ 很长的内容
427
+ </span>
428
+
429
+ <p v-tooltip.auto.expandable.ell3="detail">
430
+ {{ detail }}
431
+ </p>
432
+
433
+ <button v-tooltip.bottom="'保存'">
434
+ 保存
435
+ </button>
436
+ </template>
437
+ ```
438
+
439
+ 常用修饰符:
440
+
441
+ | 修饰符 | 说明 |
442
+ |--------|------|
443
+ | `auto` | 内容溢出时才展示提示 |
444
+ | `expandable` | 内容溢出时支持点击展开 |
445
+ | `ell2` / `ell3` / `ell5` | 多行省略 |
446
+ | `top` / `right` / `bottom` / `left` | 提示位置 |
447
+ | `top-start` / `bottom-end` 等 | 细分提示位置 |
448
+
449
+ ## 组合式 API
450
+
451
+ ### `useDataTableDrag`
452
+
453
+ 用于给 `DataTable` 或其他表格 DOM 添加拖拽排序能力。
454
+
455
+ ```ts
456
+ import { useTemplateRef } from 'vue'
457
+ import { useDataTableDrag } from '@ithinkdt/ui/composables'
458
+
459
+ const tableRef = useTemplateRef<HTMLElement>('table')
460
+ const data = ref([
461
+ { id: '1', name: '张三' },
462
+ { id: '2', name: '李四' },
463
+ ])
464
+
465
+ useDataTableDrag(tableRef, {
466
+ data,
467
+ handle: '.drag-handle',
468
+ onSort({ from, to }) {
469
+ const [item] = data.value.splice(from, 1)
470
+ data.value.splice(to, 0, item)
471
+ },
472
+ })
473
+ ```
474
+
475
+ ## 样式工具
476
+
477
+ `@ithinkdt/ui/use-style` 重新导出 `ithinkdt-ui` 的 CSSR 工具,并提供常用样式对象。
478
+
479
+ ```ts
480
+ import useStyle, {
481
+ c,
482
+ cB,
483
+ cE,
484
+ cM,
485
+ flexCenter,
486
+ fullWH,
487
+ useClsPrefix,
488
+ } from '@ithinkdt/ui/use-style'
489
+ ```
490
+
491
+ 常用导出:
492
+
493
+ | 导出 | 说明 |
494
+ |------|------|
495
+ | `useStyle` | 挂载 CSSR 样式 |
496
+ | `useClsPrefix` | 获取组件 class 前缀 |
497
+ | `c` / `cB` / `cE` / `cM` | CSSR 选择器工具 |
498
+ | `fullWidth` / `fullHeight` / `fullWH` | 宽高工具对象 |
499
+ | `flex` / `flexDirCol` | Flex 基础工具对象 |
500
+ | `flexAlignCenter` / `flexJustifyCenter` / `flexCenter` | 居中工具对象 |
501
+ | `flexJustifySB` / `flexGap` | Flex 排布工具对象 |
502
+
503
+ ## 导入路径
504
+
505
+ ```ts
506
+ // 应用布局、指令 Provider、根 UIProvider
507
+ import { AppLayout, UIProvider, vSpin, vTooltip } from '@ithinkdt/ui'
508
+
509
+ // 数据组件
510
+ import { DataForm, DataTable, DataPagination } from '@ithinkdt/ui/components'
511
+
512
+ // 指令
513
+ import { vSpin, vTooltip } from '@ithinkdt/ui/directives'
514
+
515
+ // 与 @ithinkdt/page 集成的渲染器
516
+ import { createFormItemHelper } from '@ithinkdt/ui/page'
517
+
518
+ // 组合式 API
519
+ import { useDataTableDrag } from '@ithinkdt/ui/composables'
520
+
521
+ // 样式工具
522
+ import useStyle from '@ithinkdt/ui/use-style'
523
+
524
+ // UnoCSS 预设
525
+ import ithinkdt from '@ithinkdt/ui/unocss'
526
+ ```
@@ -153,6 +153,7 @@ var A = /* @__PURE__ */ u({
153
153
  let i = t.rowProps?.(e, n);
154
154
  return {
155
155
  ...i,
156
+ "data-row-key": v.value(e),
156
157
  onClick: (n) => {
157
158
  let a = v.value(e);
158
159
  t.highlight === !0 && (T.value = a), r("highlight", a), i?.onClick?.(n);