@robot-admin/naive-ui-components 0.14.3 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/README.md +130 -741
- package/README_EN.md +137 -678
- package/dist/C_ActionBar.css +57 -58
- package/dist/C_ActionBar2.cjs +1 -1
- package/dist/C_ActionBar2.js +1 -1
- package/dist/C_AntV.css +232 -238
- package/dist/C_AntV2.cjs +2 -2
- package/dist/C_AntV2.js +2 -2
- package/dist/C_AudioPlayer.css +9 -9
- package/dist/C_AvatarGroup.css +5 -6
- package/dist/C_Barcode.css +1 -1
- package/dist/C_Breadcrumb.css +15 -18
- package/dist/C_Breadcrumb2.cjs +1 -1
- package/dist/C_Breadcrumb2.js +1 -1
- package/dist/C_Captcha.css +46 -49
- package/dist/C_Captcha2.cjs +1 -1
- package/dist/C_Captcha2.js +1 -1
- package/dist/C_Cascade.css +5 -6
- package/dist/C_Chat.css +8 -8
- package/dist/C_City.css +2 -2
- package/dist/C_Code.css +9 -9
- package/dist/C_CollapsePanel.css +9 -9
- package/dist/C_ContextMenu.css +31 -31
- package/dist/C_Cron.css +271 -274
- package/dist/C_Date.css +1 -1
- package/dist/C_Draggable.css +10 -11
- package/dist/C_Editor.css +2 -2
- package/dist/C_FilePreview.css +423 -423
- package/dist/C_Form.base.css +608 -602
- package/dist/C_Form.cjs +1 -1
- package/dist/C_Form.css +610 -604
- package/dist/C_Form.d.cts +2 -2
- package/dist/C_Form.d.ts +2 -2
- package/dist/C_Form.js +1 -1
- package/dist/C_FormModal.cjs +1 -1
- package/dist/C_FormModal.css +12 -17
- package/dist/C_FormModal.js +1 -1
- package/dist/C_FormModal2.cjs +1 -1
- package/dist/C_FormModal2.js +1 -1
- package/dist/C_FormSearch.css +53 -55
- package/dist/C_FormSearch2.cjs +1 -1
- package/dist/C_FormSearch2.js +1 -1
- package/dist/C_FormulaEditor.css +204 -205
- package/dist/C_FullCalendar.css +13 -15
- package/dist/C_FullCalendar2.cjs +1 -1
- package/dist/C_FullCalendar2.js +1 -1
- package/dist/C_GlobalSearch.css +11 -12
- package/dist/C_Guide.css +10 -10
- package/dist/C_Icon.css +7 -8
- package/dist/C_ImageCropper.css +69 -69
- package/dist/C_Language.css +8 -8
- package/dist/C_Loading.css +22 -25
- package/dist/C_Loading2.cjs +1 -1
- package/dist/C_Loading2.js +1 -1
- package/dist/C_Login.css +130 -135
- package/dist/C_Login2.cjs +1 -1
- package/dist/C_Login2.js +1 -1
- package/dist/C_Map.css +22 -23
- package/dist/C_Markdown.css +6 -7
- package/dist/C_Menu.css +2 -5
- package/dist/C_Menu2.cjs +1 -1
- package/dist/C_Menu2.js +1 -1
- package/dist/C_NotificationCenter.css +316 -281
- package/dist/C_NotificationCenter.d.cts +2 -2
- package/dist/C_NotificationCenter.d.ts +2 -2
- package/dist/C_NotificationCenter2.cjs +1 -1
- package/dist/C_NotificationCenter2.js +1 -1
- package/dist/C_OrgChart.css +8 -8
- package/dist/C_PageLoading.css +34 -39
- package/dist/C_QRCode.css +5 -6
- package/dist/C_Signature.css +5 -6
- package/dist/C_Skeleton.css +2 -2
- package/dist/C_SplitPane.css +2 -2
- package/dist/C_Steps.css +5 -6
- package/dist/C_Table.base.css +1090 -879
- package/dist/C_Table.cjs +1 -1
- package/dist/C_Table.css +1096 -885
- package/dist/C_Table.d.cts +1 -1
- package/dist/C_Table.d.ts +1 -1
- package/dist/C_Table.js +1 -1
- package/dist/C_Tabs.css +5 -6
- package/dist/C_TagsView.css +60 -63
- package/dist/C_TagsView2.cjs +1 -1
- package/dist/C_TagsView2.js +1 -1
- package/dist/C_Theme.css +7 -8
- package/dist/C_Time.css +1 -1
- package/dist/C_Timeline.css +8 -8
- package/dist/C_Transfer.css +10 -11
- package/dist/C_Tree.css +16 -17
- package/dist/C_Upload.css +156 -157
- package/dist/C_VideoPlayer.css +267 -267
- package/dist/C_VtableGantt.css +2 -2
- package/dist/C_WaterFall.css +2 -2
- package/dist/C_WorkFlow.css +466 -470
- package/dist/C_WorkFlow2.cjs +1 -1
- package/dist/C_WorkFlow2.js +1 -1
- package/dist/Card.cjs +1 -0
- package/dist/Card.js +1 -0
- package/dist/Custom.cjs +1 -0
- package/dist/Custom.js +1 -0
- package/dist/Dynamic.cjs +1 -0
- package/dist/Dynamic.js +1 -0
- package/dist/Steps.cjs +1 -0
- package/dist/Steps.js +1 -0
- package/dist/Tabs.cjs +1 -0
- package/dist/Tabs.js +1 -0
- package/dist/cascader.cjs +1 -0
- package/dist/cascader.js +1 -0
- package/dist/color-picker.cjs +1 -0
- package/dist/color-picker.js +1 -0
- package/dist/constants3.d.cts +71 -117
- package/dist/constants3.d.ts +71 -117
- package/dist/constants4.d.cts +3 -3
- package/dist/constants4.d.ts +3 -3
- package/dist/constants5.d.cts +2 -2
- package/dist/constants5.d.ts +2 -2
- package/dist/context.cjs +1 -0
- package/dist/context.js +1 -0
- package/dist/contracts.d.cts +24 -0
- package/dist/contracts.d.ts +24 -0
- package/dist/createPageLoading.cjs +1 -1
- package/dist/createPageLoading.js +1 -1
- package/dist/data.cjs +1 -1
- package/dist/data.d.cts +9 -9
- package/dist/data.d.ts +9 -9
- package/dist/data.js +1 -1
- package/dist/date-picker.cjs +1 -0
- package/dist/date-picker.js +1 -0
- package/dist/feedback.cjs +1 -0
- package/dist/feedback.js +1 -0
- package/dist/helpers.cjs +1 -1
- package/dist/helpers.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.js +1 -1
- package/dist/index.vue.d.cts +5 -5
- package/dist/index.vue.d.ts +5 -5
- package/dist/index10.vue.d.cts +5 -5
- package/dist/index10.vue.d.ts +3 -3
- package/dist/index11.vue.d.cts +3 -3
- package/dist/index11.vue.d.ts +2 -2
- package/dist/index12.vue.d.cts +2 -2
- package/dist/index12.vue.d.ts +1 -1
- package/dist/index13.vue.d.cts +1 -1
- package/dist/index14.vue.d.ts +9 -9
- package/dist/index15.vue.d.cts +9 -9
- package/dist/index15.vue.d.ts +1 -1
- package/dist/index16.vue.d.cts +1 -1
- package/dist/index18.vue.d.ts +4 -4
- package/dist/index19.vue.d.cts +4 -4
- package/dist/index19.vue.d.ts +2 -9
- package/dist/index2.vue.d.cts +2 -2
- package/dist/index2.vue.d.ts +2 -2
- package/dist/index20.vue.d.cts +1 -1
- package/dist/index20.vue.d.ts +1 -1
- package/dist/index21.vue.d.cts +2 -2
- package/dist/index21.vue.d.ts +2 -2
- package/dist/index22.vue.d.cts +1 -1
- package/dist/index22.vue.d.ts +1 -1
- package/dist/index23.vue.d.cts +1 -1
- package/dist/index23.vue.d.ts +1 -1
- package/dist/index25.vue.d.cts +4 -4
- package/dist/index25.vue.d.ts +4 -4
- package/dist/index26.vue.d.cts +1 -1
- package/dist/index26.vue.d.ts +1 -1
- package/dist/index27.vue.d.cts +5 -5
- package/dist/index27.vue.d.ts +5 -5
- package/dist/index28.vue.d.cts +3 -3
- package/dist/index28.vue.d.ts +3 -3
- package/dist/index3.vue.d.cts +3 -3
- package/dist/index3.vue.d.ts +3 -3
- package/dist/index4.vue.d.cts +2 -9
- package/dist/index6.vue.d.ts +4 -4
- package/dist/index7.vue.d.cts +4 -4
- package/dist/index8.vue.d.ts +3 -3
- package/dist/index9.vue.d.cts +3 -3
- package/dist/index9.vue.d.ts +5 -5
- package/dist/mapUtils.d.cts +5 -5
- package/dist/mapUtils.d.ts +5 -5
- package/dist/presets.d.cts +8 -2
- package/dist/presets.d.ts +8 -2
- package/dist/rate.cjs +1 -0
- package/dist/rate.js +1 -0
- package/dist/slider.cjs +1 -0
- package/dist/slider.js +1 -0
- package/dist/style.css +10725 -10722
- package/dist/time-picker.cjs +1 -0
- package/dist/time-picker.js +1 -0
- package/dist/upload.cjs +1 -0
- package/dist/upload.js +1 -0
- package/dist/useActionTask.cjs +1 -0
- package/dist/useActionTask.js +1 -0
- package/dist/useCalendarEvents.d.cts +2 -2
- package/dist/useCalendarEvents.d.ts +2 -2
- package/dist/useCollapsePanel.d.cts +5 -5
- package/dist/useCollapsePanel.d.ts +5 -5
- package/dist/useComponentLocale.cjs +1 -0
- package/dist/useComponentLocale.js +1 -0
- package/dist/useCropperCore.d.cts +8 -8
- package/dist/useCropperCore.d.ts +8 -8
- package/dist/useDraggableLayout.d.cts +9 -9
- package/dist/useDraggableLayout.d.ts +9 -9
- package/dist/useDynamicFormState.cjs +1 -0
- package/dist/useDynamicFormState.d.cts +64 -40
- package/dist/useDynamicFormState.d.ts +64 -40
- package/dist/useDynamicFormState.js +1 -0
- package/dist/useEdgeInteraction.d.cts +2 -2
- package/dist/useEdgeInteraction.d.ts +2 -2
- package/dist/useQRCode.d.cts +2 -2
- package/dist/useQRCode.d.ts +2 -2
- package/dist/useSearchState.d.cts +14 -724
- package/dist/useSearchState.d.ts +14 -833
- package/dist/useSignatureHistory.d.cts +3 -3
- package/dist/useSignatureHistory.d.ts +3 -3
- package/dist/useSplitResize.d.cts +5 -5
- package/dist/useSplitResize.d.ts +5 -5
- package/dist/useTableQuery.cjs +3 -3
- package/dist/useTableQuery.d.cts +66 -33
- package/dist/useTableQuery.d.ts +66 -33
- package/dist/useTableQuery.js +3 -3
- package/dist/useTimeSelection.d.cts +2 -2
- package/dist/useTimeSelection.d.ts +2 -2
- package/dist/useTreeOperations.d.cts +7 -7
- package/dist/useTreeOperations.d.ts +7 -7
- package/dist/useWorkflowValidation.d.cts +5 -5
- package/dist/useWorkflowValidation.d.ts +5 -5
- package/dist/verification.d.cts +1 -1
- package/dist/verification.d.ts +1 -1
- package/docs/architecture.en.md +83 -0
- package/docs/architecture.md +83 -0
- package/docs/assets/README.md +47 -0
- package/docs/assets/naive-ui-components-banner.png +0 -0
- package/docs/assets/naive-ui-components-banner.svg +69 -0
- package/docs/assets/naive-ui-components-logo.png +0 -0
- package/docs/assets/naive-ui-components-logo.svg +22 -0
- package/docs/components.en.md +118 -0
- package/docs/components.md +118 -0
- package/docs/engineering.en.md +132 -0
- package/docs/engineering.md +133 -0
- package/docs/guides/notification-center.md +95 -0
- package/docs/guides/usage.en.md +638 -0
- package/docs/guides/usage.md +699 -0
- package/docs/performance-0.15.0.md +20 -0
- package/docs/security-scan-2026-10-06.md +11 -0
- package/docs/security-scan-2026-10-18.md +16 -0
- package/package.json +29 -11
- package/dist/C_Form2.cjs +0 -1
- package/dist/C_Form2.js +0 -1
- package/dist/config.cjs +0 -1
- package/dist/config.d.cts +0 -33
- package/dist/config.d.ts +0 -33
- package/dist/config.js +0 -1
|
@@ -0,0 +1,699 @@
|
|
|
1
|
+
[← 项目首页](../../README.md) · [English](./usage.en.md)
|
|
2
|
+
|
|
3
|
+
# 使用指南
|
|
4
|
+
|
|
5
|
+
按需导入、组件配置与业务场景的详细接入示例。
|
|
6
|
+
|
|
7
|
+
## 本页导航
|
|
8
|
+
|
|
9
|
+
- [导入方式](#导入方式)
|
|
10
|
+
- [Cron 与公式工作区](#cron-与公式工作区)
|
|
11
|
+
- [C_Guide 配置引导](#c_guide-配置引导)
|
|
12
|
+
- [C_Form / C_Table 推荐用法](#c_form--c_table-推荐用法)
|
|
13
|
+
- [常用组件约定](#常用组件约定)
|
|
14
|
+
- [C_Map 推荐用法](#c_map-推荐用法)
|
|
15
|
+
- [C_Captcha 服务端校验](#c_captcha-服务端校验)
|
|
16
|
+
- [表格加载态](#表格加载态)
|
|
17
|
+
- [C_Login 扩展表单](#c_login-扩展表单)
|
|
18
|
+
- [页面切换加载](#页面切换加载)
|
|
19
|
+
- [应用级扩展与迁移](#应用级扩展与迁移)
|
|
20
|
+
|
|
21
|
+
## 导入方式
|
|
22
|
+
|
|
23
|
+
### 全局注册
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { createApp } from 'vue'
|
|
27
|
+
import App from './App.vue'
|
|
28
|
+
import NaiveUIComponents from '@robot-admin/naive-ui-components'
|
|
29
|
+
import '@robot-admin/naive-ui-components/style.css'
|
|
30
|
+
|
|
31
|
+
const app = createApp(App)
|
|
32
|
+
app.use(NaiveUIComponents)
|
|
33
|
+
app.mount('#app')
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
根入口聚合全部组件,运行时需要 `vue-router`;无需导航能力时请选择组件子路径。
|
|
37
|
+
|
|
38
|
+
### 按需导入(主入口 Tree-Shaking)
|
|
39
|
+
|
|
40
|
+
```vue
|
|
41
|
+
<script setup lang="ts">
|
|
42
|
+
import { C_Icon, C_Table, C_Form } from '@robot-admin/naive-ui-components'
|
|
43
|
+
import '@robot-admin/naive-ui-components/style.css'
|
|
44
|
+
</script>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 子路径独立导入(推荐,最小打包体积)
|
|
48
|
+
|
|
49
|
+
每个组件都提供独立的子路径入口,仅加载目标组件的代码和类型:
|
|
50
|
+
|
|
51
|
+
```vue
|
|
52
|
+
<script setup lang="ts">
|
|
53
|
+
import { C_Form } from '@robot-admin/naive-ui-components/C_Form'
|
|
54
|
+
import { C_Table } from '@robot-admin/naive-ui-components/C_Table'
|
|
55
|
+
import { C_Icon } from '@robot-admin/naive-ui-components/C_Icon'
|
|
56
|
+
import { createMenuOptions } from '@robot-admin/naive-ui-components/C_Menu'
|
|
57
|
+
import '@robot-admin/naive-ui-components/C_Form/base.css'
|
|
58
|
+
import '@robot-admin/naive-ui-components/C_Table/base.css'
|
|
59
|
+
import '@robot-admin/naive-ui-components/C_Icon/style.css'
|
|
60
|
+
</script>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
> 子路径导入提供完整的 TypeScript 类型支持(`.d.ts`),IDE 可自动补全 props / emits / slots。组件相关工具函数(如 `createMenuOptions`)也从对应组件子路径导出,避免为了单个工具加载组件库根入口。
|
|
64
|
+
|
|
65
|
+
### Composables 单独使用
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { useTableManager } from '@robot-admin/naive-ui-components/C_Table'
|
|
69
|
+
import { useFormState } from '@robot-admin/naive-ui-components/C_Form'
|
|
70
|
+
import { usePlayerCore } from '@robot-admin/naive-ui-components/C_VideoPlayer'
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 自动按需导入(推荐)
|
|
74
|
+
|
|
75
|
+
Resolver 默认从组件子路径加载,避免只使用少量组件时把整个组件库及重型运行依赖带入首屏:
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
import Components from 'unplugin-vue-components/vite'
|
|
79
|
+
import { RobotNaiveUiResolver } from '@robot-admin/naive-ui-components/resolver'
|
|
80
|
+
|
|
81
|
+
Components({
|
|
82
|
+
resolvers: [RobotNaiveUiResolver({ importStyle: true })],
|
|
83
|
+
})
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
`importStyle: true`(等价于 `'full'`)保持原有完整样式行为。只使用 C_Form/C_Table 基础字段、不使用内置富文本编辑器时,可设置 `importStyle: 'base'`,避免带入编辑器样式;其他组件会安全回退到标准样式入口。如需兼容旧项目的主入口导入,可显式设置 `importOnDemand: false`。
|
|
87
|
+
|
|
88
|
+
每个 `C_*/style.css` 都是可独立消费的完整组件样式入口:如果组件内部组合了 `C_Icon`、`C_Captcha` 等其他公共组件,对应依赖样式会自动包含,无需使用侧重复导入,也不会依赖全量 `style.css` 兜底。
|
|
89
|
+
|
|
90
|
+
`C_Menu` 会在鼠标进入或键盘聚焦叶子菜单时触发 `intent` 事件;宿主可将其绑定到路由预取函数,点击与 `select` 行为保持不变。
|
|
91
|
+
|
|
92
|
+
也可以手动选择样式层级:
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import '@robot-admin/naive-ui-components/C_Form/base.css'
|
|
96
|
+
import '@robot-admin/naive-ui-components/C_Table/base.css'
|
|
97
|
+
// 完整模式也可显式使用 C_Form/full.css、C_Table/full.css
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Cron 与公式工作区
|
|
101
|
+
|
|
102
|
+
一个模型加一份扁平配置即可。原有独立属性继续兼容,组件内部统一处理模板、校验、预览与初始状态重置。
|
|
103
|
+
|
|
104
|
+
```vue
|
|
105
|
+
<script setup lang="ts">
|
|
106
|
+
import { ref } from 'vue'
|
|
107
|
+
import {
|
|
108
|
+
C_Cron,
|
|
109
|
+
type CronConfig,
|
|
110
|
+
} from '@robot-admin/naive-ui-components/C_Cron'
|
|
111
|
+
import {
|
|
112
|
+
C_FormulaEditor,
|
|
113
|
+
type FormulaEditorConfig,
|
|
114
|
+
} from '@robot-admin/naive-ui-components/C_FormulaEditor'
|
|
115
|
+
import '@robot-admin/naive-ui-components/C_Cron/style.css'
|
|
116
|
+
import '@robot-admin/naive-ui-components/C_FormulaEditor/style.css'
|
|
117
|
+
|
|
118
|
+
const expression = ref('0 30 8 * * ?')
|
|
119
|
+
const cronConfig: CronConfig = { previewCount: 5 }
|
|
120
|
+
const formula = ref('IF([完成值] > 0, 100 / [完成值], 0)')
|
|
121
|
+
const formulaConfig: FormulaEditorConfig = {
|
|
122
|
+
variables: [{ name: '完成值', field: 'completed', type: 'number' }],
|
|
123
|
+
sampleData: { completed: 5 },
|
|
124
|
+
editableSampleData: true,
|
|
125
|
+
}
|
|
126
|
+
</script>
|
|
127
|
+
<template>
|
|
128
|
+
<C_Cron
|
|
129
|
+
v-model="expression"
|
|
130
|
+
:config="cronConfig"
|
|
131
|
+
/>
|
|
132
|
+
<C_FormulaEditor
|
|
133
|
+
v-model="formula"
|
|
134
|
+
:config="formulaConfig"
|
|
135
|
+
/>
|
|
136
|
+
</template>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Cron 支持秒到星期的六个数字字段、范围、间隔、列表及日/星期 `?` 互斥,不实现 L/W/# 扩展;预览按浏览器本地时区计算,不会调度任务。公式试算只在本地进行,不修改传入的 `sampleData`;校验和计算复用有界解析器,条件分支按需执行。通过 `showPreview`、`showKeyboard`、`showVariablePanel` 控制嵌入布局,`disabled` 同时保护试算输入。重置恢复初始模型及数据;切换独立记录时使用新 key 重新挂载。
|
|
140
|
+
|
|
141
|
+
公式键盘默认展开,可手动收起。数字、运算、比较与条件按键直接插入当前光标位置;选中文字会被替换,退格可整体删除变量,清空后继续输入。函数快捷键复用 `functions` 配置及签名说明,不需要项目额外配置;隐藏键盘仍使用 `showKeyboard: false`。
|
|
142
|
+
|
|
143
|
+
## C_Guide 配置引导
|
|
144
|
+
|
|
145
|
+
项目只需要提供目标和步骤,组件内置主题、可选 SVG 示意图及退出清理,不依赖项目的路由或 Store:
|
|
146
|
+
|
|
147
|
+
```vue
|
|
148
|
+
<script setup lang="ts">
|
|
149
|
+
import {
|
|
150
|
+
C_Guide,
|
|
151
|
+
type GuideStep,
|
|
152
|
+
} from '@robot-admin/naive-ui-components/C_Guide'
|
|
153
|
+
import '@robot-admin/naive-ui-components/C_Guide/style.css'
|
|
154
|
+
|
|
155
|
+
const steps: GuideStep[] = [
|
|
156
|
+
{
|
|
157
|
+
element: '[data-guide="search"]',
|
|
158
|
+
popover: {
|
|
159
|
+
title: '搜索',
|
|
160
|
+
description: '快速查找功能。',
|
|
161
|
+
illustration: 'search',
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
]
|
|
165
|
+
</script>
|
|
166
|
+
|
|
167
|
+
<template>
|
|
168
|
+
<C_Guide :steps="steps" />
|
|
169
|
+
</template>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
在 `NConfigProvider` 内会自动跟随亮暗主题和主色。目标支持选择器、元素或解析函数;默认跳过不可见目标,不传目标可展示居中步骤。引擎在打开时加载。启用 `persistence` 后,只有完成引导才记住状态;点击入口仍可重看。每一步默认显示“跳过引导”,跳过会发出 `skip` 和 `close` 事件,不记录为完成;可用 `showSkipButton` 和 `skipBtnText` 控制入口与文案。通过 `GuideExpose` 可调用 `startGuide(force?)`、`stopGuide()`、`isCompleted()` 和 `resetCompleted()`,宿主可在路由切换时主动停止。
|
|
173
|
+
|
|
174
|
+
## C_Form / C_Table 推荐用法
|
|
175
|
+
|
|
176
|
+
推荐使用类型助手和绑定助手:业务模型只声明一次,字段路径、字段值、列 key、保存回调和实例方法即可保持同一套类型推导。字段支持 `profile.name`、`contacts.0.email` 这类嵌套路径。
|
|
177
|
+
|
|
178
|
+
```vue
|
|
179
|
+
<script setup lang="ts">
|
|
180
|
+
import {
|
|
181
|
+
C_Form,
|
|
182
|
+
defineFormConfig,
|
|
183
|
+
defineFormOptions,
|
|
184
|
+
useCForm,
|
|
185
|
+
} from '@robot-admin/naive-ui-components/C_Form'
|
|
186
|
+
|
|
187
|
+
interface UserForm {
|
|
188
|
+
name: string
|
|
189
|
+
departmentId: number | null
|
|
190
|
+
profile: { email: string }
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const fields = defineFormOptions<UserForm>([
|
|
194
|
+
{
|
|
195
|
+
type: 'input',
|
|
196
|
+
prop: 'name',
|
|
197
|
+
label: '名称',
|
|
198
|
+
required: true,
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
type: 'select',
|
|
202
|
+
prop: 'departmentId',
|
|
203
|
+
label: '部门',
|
|
204
|
+
asyncOptions: async (_model, context) =>
|
|
205
|
+
fetch('/api/departments', { signal: context?.signal }).then(response =>
|
|
206
|
+
response.json()
|
|
207
|
+
),
|
|
208
|
+
},
|
|
209
|
+
{ type: 'input', prop: 'profile.email', label: '邮箱' },
|
|
210
|
+
])
|
|
211
|
+
const config = defineFormConfig<UserForm>({
|
|
212
|
+
mode: 'edit',
|
|
213
|
+
validateOnChange: true,
|
|
214
|
+
onSubmit: async ({ model: validatedModel }) => save(validatedModel),
|
|
215
|
+
onError: (error, context) => reportError(error, context),
|
|
216
|
+
})
|
|
217
|
+
const { model, formRef, bindings } = useCForm<UserForm>({
|
|
218
|
+
initialValues: {
|
|
219
|
+
name: '',
|
|
220
|
+
departmentId: null,
|
|
221
|
+
profile: { email: '' },
|
|
222
|
+
},
|
|
223
|
+
options: fields,
|
|
224
|
+
config,
|
|
225
|
+
})
|
|
226
|
+
</script>
|
|
227
|
+
|
|
228
|
+
<template>
|
|
229
|
+
<C_Form
|
|
230
|
+
ref="formRef"
|
|
231
|
+
v-bind="bindings"
|
|
232
|
+
/>
|
|
233
|
+
</template>
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
表单已内置 `@robot-admin/form-validate`,使用侧无需另写类型适配,也不用重复安装验证依赖。`rules` / `rulesWhen` 直接接受 Naive UI 原生规则、验证库的 `NaiveRule` 和框架无关的 `RuleSpec`,可以混用;`required: true` 同样复用验证库的空值判断,`0` 和 `false` 不会被误判为空。
|
|
237
|
+
|
|
238
|
+
```ts
|
|
239
|
+
import {
|
|
240
|
+
defineFormOptions,
|
|
241
|
+
PRESET_RULES,
|
|
242
|
+
NAIVE_COMBOS,
|
|
243
|
+
SPEC_RULES,
|
|
244
|
+
} from '@robot-admin/naive-ui-components/C_Form'
|
|
245
|
+
|
|
246
|
+
const fields = defineFormOptions([
|
|
247
|
+
{
|
|
248
|
+
type: 'input',
|
|
249
|
+
prop: 'name',
|
|
250
|
+
label: '名称',
|
|
251
|
+
required: true,
|
|
252
|
+
rules: [SPEC_RULES.length('名称', 2, 20)],
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
type: 'input',
|
|
256
|
+
prop: 'email',
|
|
257
|
+
label: '邮箱',
|
|
258
|
+
rules: NAIVE_COMBOS.email('邮箱'),
|
|
259
|
+
},
|
|
260
|
+
{
|
|
261
|
+
type: 'input',
|
|
262
|
+
prop: 'mobile',
|
|
263
|
+
label: '手机号',
|
|
264
|
+
rules: [PRESET_RULES.mobile('手机号')],
|
|
265
|
+
},
|
|
266
|
+
])
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
普通表单默认提供提交与重置,步骤表单最后一步默认提供提交按钮。只需配置 `submitText`、`resetText` 和 `onSubmit`;要增加预览等业务操作,使用 `action-extra` 插槽即可保留默认按钮和加载管理。需要完全定制时仍可覆盖 `action` / `step-actions`,并调用插槽的 `submit()`,不要用 `validate()` 代替提交。
|
|
270
|
+
|
|
271
|
+
异步保存放在 `config.onSubmit` 中并等待完成;`@submit` 是完成后的通知事件,不等待监听器返回的 Promise。第二参数提供 `context?.signal`,可直接传给支持取消的请求;组件卸载会发出取消信号,并停止晚到的提交事件和提示。`submitSuccessText` / `resetSuccessText` 为可选反馈文案,默认不显示成功提示,也不代表数据已持久化。
|
|
272
|
+
|
|
273
|
+
新增/编辑场景推荐用 `C_FormModal` 直接消费 Headless CRUD 的结构化 `editor`。字段、校验和布局继续由 `C_Form` 配置驱动,页面不再重复编写 Modal、按钮、loading 和草稿状态;默认采用紧凑小尺寸表单和右下角带图标操作按钮,宽度、表单尺寸与动作文案仍可覆盖:
|
|
274
|
+
|
|
275
|
+
```vue
|
|
276
|
+
<script setup lang="ts">
|
|
277
|
+
import { C_FormModal } from '@robot-admin/naive-ui-components/C_FormModal'
|
|
278
|
+
import type { FormModalEditor } from '@robot-admin/naive-ui-components/C_FormModal'
|
|
279
|
+
import {
|
|
280
|
+
defineFormConfig,
|
|
281
|
+
defineFormOptions,
|
|
282
|
+
} from '@robot-admin/naive-ui-components/C_Form'
|
|
283
|
+
|
|
284
|
+
interface UserForm {
|
|
285
|
+
name: string
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
defineProps<{ editor: FormModalEditor<UserForm> }>()
|
|
289
|
+
|
|
290
|
+
const fields = defineFormOptions<UserForm>([
|
|
291
|
+
{ type: 'input', prop: 'name', label: '名称', required: true },
|
|
292
|
+
])
|
|
293
|
+
const formConfig = defineFormConfig<UserForm>({ labelPlacement: 'top' })
|
|
294
|
+
</script>
|
|
295
|
+
|
|
296
|
+
<template>
|
|
297
|
+
<C_FormModal
|
|
298
|
+
:editor="editor"
|
|
299
|
+
:options="fields"
|
|
300
|
+
:config="formConfig"
|
|
301
|
+
/>
|
|
302
|
+
</template>
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
`editor` 采用结构类型,不要求组件库依赖某个请求库;任何提供 `visible/mode/model/title/loading/setModel/close/submit` 的 Headless 控制器都可接入。弹窗默认保留关闭按钮、遮罩关闭和 Esc 行为,也可按高风险表单显式关闭。
|
|
306
|
+
|
|
307
|
+
远程表格推荐交给 `useTableQuery` 管理请求取消、竞态、分页和 loading;只需把 `bindings` 绑定给组件。`rowKey` 必须稳定且唯一,默认会检测缺失和重复键。
|
|
308
|
+
|
|
309
|
+
```vue
|
|
310
|
+
<script setup lang="ts">
|
|
311
|
+
import {
|
|
312
|
+
C_Table,
|
|
313
|
+
defineTableColumns,
|
|
314
|
+
defineTableConfig,
|
|
315
|
+
useTableQuery,
|
|
316
|
+
} from '@robot-admin/naive-ui-components/C_Table'
|
|
317
|
+
|
|
318
|
+
interface UserRow {
|
|
319
|
+
id: string
|
|
320
|
+
name: string
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
const columns = defineTableColumns<UserRow>([
|
|
324
|
+
{ key: 'name', title: '名称', editable: true },
|
|
325
|
+
])
|
|
326
|
+
const config = defineTableConfig<UserRow>({
|
|
327
|
+
selection: { enabled: true },
|
|
328
|
+
edit: {
|
|
329
|
+
enabled: true,
|
|
330
|
+
mode: 'row',
|
|
331
|
+
onSave: row => saveRow(row),
|
|
332
|
+
onError: error => reportError(error),
|
|
333
|
+
},
|
|
334
|
+
})
|
|
335
|
+
const { bindings } = useTableQuery<UserRow, { keyword: string }>({
|
|
336
|
+
initialQuery: { keyword: '' },
|
|
337
|
+
columns,
|
|
338
|
+
config,
|
|
339
|
+
rowKey: 'id',
|
|
340
|
+
request: async ({ page, pageSize, query, signal }) => {
|
|
341
|
+
const response = await fetch('/api/users', {
|
|
342
|
+
method: 'POST',
|
|
343
|
+
body: JSON.stringify({ page, pageSize, ...query }),
|
|
344
|
+
signal,
|
|
345
|
+
})
|
|
346
|
+
return response.json() as Promise<{ data: UserRow[]; total: number }>
|
|
347
|
+
},
|
|
348
|
+
})
|
|
349
|
+
</script>
|
|
350
|
+
|
|
351
|
+
<template>
|
|
352
|
+
<C_Table v-bind="bindings" />
|
|
353
|
+
</template>
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
将 Headless CRUD 绑定到 `:crud` 时,表格会识别操作结果中的 `{ error }`:失败不会触发删除成功事件,也不会重复展示 CRUD 控制器已经展示的反馈。自定义 `actions.delete` 可返回 Promise,或返回 `{ data, error }` 结构。
|
|
357
|
+
|
|
358
|
+
树形数据可直接使用 `<C_Table :data="rows" :columns="columns" :config="{ tree: { defaultExpandAll: true }, pagination: false }" />`;`children` 是默认子节点字段,也可通过 `tree.childrenKey` 指定。默认展开会初始化所有父节点,并在异步追加新父节点时展开新节点,不会重新展开用户手动收起的旧节点。
|
|
359
|
+
|
|
360
|
+
`C_Tabs` 是面向页面场景切换的统一数据驱动标签页,名称与全局 `C_*` 体系保持一致。默认使用紧凑
|
|
361
|
+
`small` 尺寸、延迟呈现面板并支持受控/非受控状态;只做筛选或视图切换时启用 `tabsOnly`,组件
|
|
362
|
+
不会执行面板内容,避免隐藏内容产生渲染开销或副作用。常规场景只维护数组,复杂内容可以按需使用 `render`、`pane` 或
|
|
363
|
+
`pane-{key}` 插槽:
|
|
364
|
+
|
|
365
|
+
```vue
|
|
366
|
+
<script setup lang="ts">
|
|
367
|
+
import { ref } from 'vue'
|
|
368
|
+
import { C_Tabs, defineTabs } from '@robot-admin/naive-ui-components/C_Tabs'
|
|
369
|
+
|
|
370
|
+
const activeView = ref('basic')
|
|
371
|
+
const views = defineTabs([
|
|
372
|
+
{ key: 'basic', label: '基础表格', icon: 'mdi:table' },
|
|
373
|
+
{ key: 'tree', label: '树形表格', icon: 'mdi:file-tree-outline' },
|
|
374
|
+
])
|
|
375
|
+
</script>
|
|
376
|
+
|
|
377
|
+
<template>
|
|
378
|
+
<C_Tabs
|
|
379
|
+
v-model="activeView"
|
|
380
|
+
:items="views"
|
|
381
|
+
type="segment"
|
|
382
|
+
tabs-only
|
|
383
|
+
/>
|
|
384
|
+
</template>
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
| API | 说明 |
|
|
388
|
+
| ----------------------------- | ------------------------------------------------------------------------- |
|
|
389
|
+
| `items` | `key/label` 为必填,支持 `icon`、`badge`、禁用、关闭及 `renderTab/render` |
|
|
390
|
+
| `modelValue` / `defaultValue` | 同时支持受控和非受控状态 |
|
|
391
|
+
| `type` / `size` / `placement` | `line/card/bar/segment` 与常用尺寸、方向;默认 `line/small/top` |
|
|
392
|
+
| `tabsOnly` | 只呈现标签导航,适合表格场景和查询条件切换 |
|
|
393
|
+
| `beforeChange` | 支持同步或异步切换守卫;返回 `false` 或抛错均保留当前页 |
|
|
394
|
+
| 插槽 | `tab`、`pane` 和 `pane-{key}`,均提供当前 item 与 active 状态 |
|
|
395
|
+
| 事件 | `change`、`close`、`add` 及标准 `update:modelValue` |
|
|
396
|
+
|
|
397
|
+
页面级和表格级按钮统一使用 `C_ActionBar`,无需再维护另一套 Toolbar。操作栏默认采用带图标的 `tiny` 紧凑按钮和 `6px` 间距;`add`、`refresh`、`export`、`columns`、`settings` 等语义 key 会自动补齐一致的文案、图标与按钮类型,自定义动作未传图标时使用中性操作图标。`show`、`disabled`、`loading` 可直接传布尔值、`Ref` 或 getter,异步操作默认防重复点击并自动展示 loading。`C_Table` 可在 `toolbar.actions` / `toolbar.rightActions` 中直接复用同一份动作配置,同时保留原有左右插槽;需要更大按钮时,通过 `actionBar.size` 或单个动作的 `size` 覆盖:
|
|
398
|
+
|
|
399
|
+
```ts
|
|
400
|
+
import { defineActions } from '@robot-admin/naive-ui-components/C_ActionBar'
|
|
401
|
+
import { defineTableConfig } from '@robot-admin/naive-ui-components/C_Table'
|
|
402
|
+
|
|
403
|
+
const actions = defineActions([
|
|
404
|
+
{ key: 'add', onClick: openCreate },
|
|
405
|
+
{ key: 'refresh', disabled: () => loading.value, onClick: refresh },
|
|
406
|
+
{ key: 'settings', group: 'right', onClick: openSettings },
|
|
407
|
+
])
|
|
408
|
+
|
|
409
|
+
const config = defineTableConfig({
|
|
410
|
+
toolbar: {
|
|
411
|
+
actions,
|
|
412
|
+
actionBar: { size: 'small' }, // 可选;默认是 tiny
|
|
413
|
+
},
|
|
414
|
+
})
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
固定高度场景使用 `flex-height + wrapper-class`,根容器负责工具栏、表格与分页的高度分配。根容器自身或父容器必须有确定高度;组件不猜测页面可用高度。`wrapper-class` 支持 Vue 字符串、数组和对象 class 绑定,应用 scoped 样式可直接命中根容器,无需引用内部 CSS 类。普通 `class` / `style` 与其他原生表格属性保持原行为,继续传给内部 `NDataTable`。
|
|
418
|
+
|
|
419
|
+
```vue
|
|
420
|
+
<template>
|
|
421
|
+
<C_Table
|
|
422
|
+
wrapper-class="inventory-table"
|
|
423
|
+
flex-height
|
|
424
|
+
:columns="columns"
|
|
425
|
+
:data="rows"
|
|
426
|
+
/>
|
|
427
|
+
</template>
|
|
428
|
+
<style scoped>
|
|
429
|
+
.inventory-table {
|
|
430
|
+
height: 480px;
|
|
431
|
+
}
|
|
432
|
+
</style>
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
选择列须显式配置 `{ type: 'selection' }`,通过 `@selection-change="(keys, rows) => ..."` 接收结果;主动清空时使用公开实例方法 `clearSelection()`,不观察内部 manager 状态。
|
|
436
|
+
|
|
437
|
+
`C_Table` 继续由当前 Naive UI 表格实现负责;需要 MachTable 时应由业务入口完整渲染 MachTable 及其原生配置,避免在两套列定义、事件和实例 API 之间做隐式转换。二者只共享 `C_ActionBar` 这类框架无关的页面动作模型,不互相污染。
|
|
438
|
+
|
|
439
|
+
## 常用组件约定
|
|
440
|
+
|
|
441
|
+
### 表单读写与校验
|
|
442
|
+
|
|
443
|
+
延续上例的 `useCForm()`,优先使用助手读写模型,减少手写双向同步和等待渲染的代码:
|
|
444
|
+
|
|
445
|
+
```ts
|
|
446
|
+
const { formRef, bindings, setValues, getValues, reset, submit } =
|
|
447
|
+
useCForm<UserForm>({
|
|
448
|
+
initialValues: { name: '', departmentId: null, profile: { email: '' } },
|
|
449
|
+
options: fields,
|
|
450
|
+
config,
|
|
451
|
+
})
|
|
452
|
+
|
|
453
|
+
async function loadUser(user: UserForm) {
|
|
454
|
+
await setValues(user)
|
|
455
|
+
formRef.value?.markAsClean() // 将已加载记录设为重置基线
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
function preview() {
|
|
459
|
+
return getValues() // 独立快照;刚编辑的值无需等待父模型下一轮更新
|
|
460
|
+
}
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
`setValues(values, shouldValidate = false)` 在挂载后直接调用表单实例,挂载前更新绑定模型;`getValues()` 返回副本。`reset()` 恢复当前干净快照,`markAsClean()` 可更新该基线。设置嵌套对象时传完整对象,或使用实例的 `setFieldValue('profile.email', value)` 修改单个路径。
|
|
464
|
+
|
|
465
|
+
组件模板 ref 的公开状态已由 Vue 解包:脚本中读取 `formRef.value?.isSubmitting`、`formRef.value?.isDirty` 和 `formRef.value?.formModel`,无需再取一层 `.value`。助手返回的 `model`、`formRef`、`bindings` 本身仍是 Vue ref。
|
|
466
|
+
|
|
467
|
+
普通、行内、网格布局同步提供;卡片、标签、步骤、动态和自定义布局按需加载。异步布局尚未挂载时,`submit()` 返回 `false`,`validate()` 拒绝执行,避免把未呈现的字段当成通过校验。标签和步骤布局就绪后会挂载各面板字段,整表提交也校验未访问的面板;异步选项请求按字段隔离,更新请求后晚到的旧结果不会覆盖新选项。
|
|
468
|
+
|
|
469
|
+
### 表格分页、选择与导出
|
|
470
|
+
|
|
471
|
+
新页面统一通过 `config.pagination` 配置分页;远程表格直接使用上例 `useTableQuery().bindings`,分页、总数、loading 与请求只维护一份状态。兼容路径 `:pagination="..."` 由 Naive 原生分页负责;只要显式传入该 prop(包括 `false`),它就优先于 `config.pagination`,组件不会再显示第二个分页器。原生远程模式同时传 `remote` 并自行管理请求及原生更新事件。
|
|
472
|
+
|
|
473
|
+
本地数据先筛选、排序,再分页;远程模式显示服务器返回的这一页,不再次切片。`crossPageSelection: true` 保留已访问远程页中选中的行对象;`selectAll()` 只追加当前加载页,不能代表选中尚未获取的全部服务器记录。批量操作用 `getSelectedRows()`/`@selection-change` 的行对象;需要服务器“全部命中”操作时由业务提供查询条件或服务端任务。
|
|
474
|
+
|
|
475
|
+
导出范围应显式选择:
|
|
476
|
+
|
|
477
|
+
| `config.export` 配置 | 数据来源 |
|
|
478
|
+
| ------------------------- | ---------------------------------------------------------- |
|
|
479
|
+
| `scope: 'source'`(默认) | 当前传入的完整数据源;远程模式通常只有当前加载页 |
|
|
480
|
+
| `scope: 'page'` | 当前呈现页,本地模式包含当前筛选、排序及分页结果 |
|
|
481
|
+
| `scope: 'selected'` | 当前选中的可用行对象,包含跨页保留的已访问记录 |
|
|
482
|
+
| `requestData` | 点击导出时显式请求数据,优先于 `scope`,适合服务器全量导出 |
|
|
483
|
+
|
|
484
|
+
```ts
|
|
485
|
+
const config = defineTableConfig({
|
|
486
|
+
export: {
|
|
487
|
+
scope: 'page',
|
|
488
|
+
filename: 'users',
|
|
489
|
+
format: 'csv',
|
|
490
|
+
},
|
|
491
|
+
})
|
|
492
|
+
|
|
493
|
+
// 全量数据由业务显式提供;表格不会在导出时自动遍历服务器分页。
|
|
494
|
+
const fullExport = defineTableConfig({
|
|
495
|
+
export: { requestData: () => fetchAllUsers(), filename: 'all-users' },
|
|
496
|
+
})
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
异步展开失败后保留错误状态,默认展开内容提供重试入口。也可使用公开实例方法 `retryExpand(key)` 重新加载;`invalidateExpand(key?)` 清除指定行或全部缓存及错误状态,本身不发请求。同一行并发加载复用一次请求;替换数据行后旧缓存失效,晚到的旧结果不会重新写入。
|
|
500
|
+
|
|
501
|
+
动态行新增、复制必须生成与表格一致的唯一键。优先传字符串 `row-key="uuid"`;若表格必须传函数 `:row-key="row => row.uuid"`,同时指定 `config.dynamicRows.rowKey: 'uuid'`,让新增和复制知道应生成哪个字段。组件不推断任意复合键;键缺失或重复时拒绝插入,关闭动态行后相关实例方法不修改数据。
|
|
502
|
+
|
|
503
|
+
### 搜索与远程表格连接
|
|
504
|
+
|
|
505
|
+
搜索表单使用 `C_FormSearch`,推荐 `v-model`;旧 `formParams` 继续兼容。业务请求放在 `config.onSearch`,`@search` 用于通知;两处同时发请求会由业务执行两次。下面将请求、分页和 loading 交给一份表格控制器:
|
|
506
|
+
|
|
507
|
+
```vue
|
|
508
|
+
<script setup lang="ts">
|
|
509
|
+
import { ref } from 'vue'
|
|
510
|
+
import {
|
|
511
|
+
C_FormSearch,
|
|
512
|
+
type SearchConfig,
|
|
513
|
+
type SearchFormItem,
|
|
514
|
+
type SearchFormParams,
|
|
515
|
+
} from '@robot-admin/naive-ui-components/C_FormSearch'
|
|
516
|
+
import {
|
|
517
|
+
C_Table,
|
|
518
|
+
useTableQuery,
|
|
519
|
+
} from '@robot-admin/naive-ui-components/C_Table'
|
|
520
|
+
import '@robot-admin/naive-ui-components/C_FormSearch/style.css'
|
|
521
|
+
import '@robot-admin/naive-ui-components/C_Table/base.css'
|
|
522
|
+
|
|
523
|
+
const filters = ref<SearchFormParams>({ keyword: '' })
|
|
524
|
+
const searchFields: SearchFormItem[] = [
|
|
525
|
+
{ type: 'input', prop: 'keyword', placeholder: '关键词' },
|
|
526
|
+
]
|
|
527
|
+
const { bindings, loading, setQuery } = useTableQuery({
|
|
528
|
+
initialQuery: { keyword: '' },
|
|
529
|
+
columns,
|
|
530
|
+
rowKey: 'id',
|
|
531
|
+
request: loadUsers,
|
|
532
|
+
})
|
|
533
|
+
const applyQuery = async (params: SearchFormParams) => {
|
|
534
|
+
await setQuery({ keyword: String(params.keyword ?? '') })
|
|
535
|
+
}
|
|
536
|
+
const searchConfig: SearchConfig = {
|
|
537
|
+
requireValue: false,
|
|
538
|
+
onSearch: applyQuery,
|
|
539
|
+
}
|
|
540
|
+
</script>
|
|
541
|
+
|
|
542
|
+
<template>
|
|
543
|
+
<C_FormSearch
|
|
544
|
+
v-model="filters"
|
|
545
|
+
:form-item-list="searchFields"
|
|
546
|
+
:config="searchConfig"
|
|
547
|
+
:loading="loading"
|
|
548
|
+
@reset="applyQuery"
|
|
549
|
+
/>
|
|
550
|
+
<C_Table v-bind="bindings" />
|
|
551
|
+
</template>
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
搜索按钮、原生表单提交(含输入框 Enter)和实例 `searchFn()` 走同一校验与防重路径;仅当前挂载的搜索控件参与 Naive 表单校验。异步校验期间条件改变、外部 loading 开启或组件卸载,会取消本次派发,成功校验的快照才进入请求。默认要求至少一个非分页条件;需要空条件查询时设置 `requireValue: false`。
|
|
555
|
+
|
|
556
|
+
`reset(params)` 事件先同步更新 v-model,再通知重置后的完整快照;不带参数的旧回调继续可用。默认仅恢复字段默认值并保留 `pageNum/pageSize`,不自动查询、不添加 debounce。上例通过显式 `@reset="applyQuery"` 刷新,并由 `setQuery()` 将表格页码归一;不要在重置回调里读取一份另行维护的旧查询对象。
|
|
557
|
+
|
|
558
|
+
### 动作配置与异步执行
|
|
559
|
+
|
|
560
|
+
保留稳定语义 key 和 Promise 回调即可获得文案、图标与互斥执行,不必为每个按钮维护 loading:
|
|
561
|
+
|
|
562
|
+
```ts
|
|
563
|
+
const actions = defineActions([
|
|
564
|
+
{ key: 'save', onClick: () => saveCurrentUser() },
|
|
565
|
+
{ key: 'refresh', disabled: () => loading.value, onClick: reload },
|
|
566
|
+
{
|
|
567
|
+
key: 'more',
|
|
568
|
+
dropdown: [{ key: 'export', label: '导出', onClick: exportUsers }],
|
|
569
|
+
},
|
|
570
|
+
])
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
同一 ActionBar 中重复 key 共享执行锁;重建动作对象、切换左右分组都保留该 key 的 busy 状态。未提供 key 时按分组和位置识别,因此动态列表应显式提供 key。更多菜单与普通按钮遵守相同的 disabled、loading 和异步互斥规则;`autoLoading: false` 只关闭自动 spinner,执行期间继续阻止重复触发。
|
|
574
|
+
|
|
575
|
+
`action-click`/`dropdown-click` 是通知,不等待事件监听器的 Promise;异步命令应放在动作 `onClick`。失败发出 `action-error(error, action, item?)`,原始错误继续交给 Vue `errorHandler`/错误捕获边界。`buttonProps.disabled/loading` 与动作状态合并,不能关闭内部 busy 保护;`buttonProps.onClick` 保留为原生点击观察者,不覆盖动作执行器。表格行操作复用轻量执行锁,无需为每行再包一层完整操作栏。
|
|
576
|
+
|
|
577
|
+
## C_Map 推荐用法
|
|
578
|
+
|
|
579
|
+
`C_Map` 统一以 `[纬度, 经度]` 接收中心点和标记坐标;切换高德地图时会在组件内部转换为其要求的 `[经度, 纬度]`,使用侧无需维护两套数据。非法标记会被隔离,组件只清理自己创建的 Marker,不会误删通过 `ready` 事件添加的业务图层。
|
|
580
|
+
|
|
581
|
+
```vue
|
|
582
|
+
<script setup lang="ts">
|
|
583
|
+
import { ref } from 'vue'
|
|
584
|
+
import {
|
|
585
|
+
C_Map,
|
|
586
|
+
type MapExpose,
|
|
587
|
+
type MapMarker,
|
|
588
|
+
} from '@robot-admin/naive-ui-components/C_Map'
|
|
589
|
+
import '@robot-admin/naive-ui-components/C_Map/style.css'
|
|
590
|
+
|
|
591
|
+
const mapRef = ref<MapExpose>()
|
|
592
|
+
const markers: MapMarker[] = [
|
|
593
|
+
{ id: 'beijing', lat: 39.9042, lng: 116.4074, popup: '北京' },
|
|
594
|
+
]
|
|
595
|
+
</script>
|
|
596
|
+
|
|
597
|
+
<template>
|
|
598
|
+
<C_Map
|
|
599
|
+
ref="mapRef"
|
|
600
|
+
:markers="markers"
|
|
601
|
+
fit-markers-on-init
|
|
602
|
+
:tile-config="{ maxZoom: 18 }"
|
|
603
|
+
@error="reportError"
|
|
604
|
+
/>
|
|
605
|
+
<button @click="mapRef?.fitToMarkers({ maxZoom: 14 })">定位全部标记</button>
|
|
606
|
+
</template>
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
组件实例提供 `getMap()`、`refresh()` 和 `fitToMarkers()`,适合标签页显示、容器尺寸变化和业务图层扩展。OpenStreetMap 模式会在组件内部兼容 Leaflet 的 ESM 命名空间和 CommonJS `default` 形态,宿主无需为正确性配置整包预构建。使用 `map-type="amap"` 时必须提供 `amap-key`;2021-12-02 之后申请的 Key 还必须按[高德官方安全密钥说明](https://lbs.amap.com/api/javascript-api-v2/guide/abc/jscode)配置 `:amap-security-config="{ serviceHost: '/_AMapService' }"`(生产推荐,由服务端代理保管安全密钥),或仅在开发环境传 `{ securityJsCode: '...' }`。安全配置会在 SDK 脚本加载前写入,并拒绝同页混用不同 Key。宿主应用还需在 CSP 的 `script-src` 中允许 `https://webapi.amap.com`,同时在高德控制台配置域名白名单和配额限制。
|
|
610
|
+
|
|
611
|
+
`C_Date`、`C_Time`、`C_Menu`、`C_FormSearch` 均支持标准 `v-model`。组件可直接放在没有 `NMessageProvider` / `NDialogProvider` 的页面;如需统一提示、确认和文案,可在安装时传入 `feedback`、`locale`、`form` 与 `table.defaults`。
|
|
612
|
+
|
|
613
|
+
## C_Captcha 服务端校验
|
|
614
|
+
|
|
615
|
+
验证码入口使用组件库内置 SVG 状态图标,不依赖操作系统 Emoji 或在线图标服务;默认、校验中、成功和失败状态均保持一致的尺寸与语义颜色。`C_Login` 会把验证入口放在提交按钮之前并显示明确操作文案,同时透传 `captcha-visible-change`,宿主可在拼图交互期间暂停高开销背景动画。品牌接入可在外层通过 `--cc-height`、`--cc-radius`、`--cc-color`、`--cc-icon-color`、`--cc-bg`、`--cc-bg-hover`、`--cc-border`、`--cc-border-hover` 和 `--cc-focus` 调整外观,无需穿透组件内部 DOM。
|
|
616
|
+
|
|
617
|
+
默认本地模式仅证明浏览器内的拼图交互已经完成,不能作为登录、支付等敏感操作的安全凭证。生产场景应传入 `verifier`,并开启 `require-server-verification`;组件会处理超时、取消和竞态,只在独立的服务端/验证码提供商确认后发出 `success`。请求中的 `token`、`timestamp` 都由客户端生成,只能用于关联和日志,服务端绝不能把它们本身当作可信证明。
|
|
618
|
+
|
|
619
|
+
需要国内网络可用且长期免费的方案时,可显式选择开源 MIT 的 ALTCHA 自托管模式。该模式仅在使用时懒加载,不增加默认拼图入口的首屏执行成本;组件会强制服务端校验,缺少 `challenge-url` 或 `verifier` 时失败关闭。应用后端必须签发新鲜的一次性挑战、验证 PoW payload、阻止重放并限流;密钥只存于服务端。
|
|
620
|
+
|
|
621
|
+
```vue
|
|
622
|
+
<C_Captcha
|
|
623
|
+
provider="altcha"
|
|
624
|
+
challenge-url="/api/auth/captcha/challenge"
|
|
625
|
+
:verifier="
|
|
626
|
+
async ({ token, signal }) => {
|
|
627
|
+
const response = await fetch('/api/auth/captcha/verify', {
|
|
628
|
+
method: 'POST',
|
|
629
|
+
headers: { 'content-type': 'application/json' },
|
|
630
|
+
body: JSON.stringify({ payload: token }),
|
|
631
|
+
signal,
|
|
632
|
+
})
|
|
633
|
+
return response.json() // { valid: boolean, token: '服务端一次性登录令牌' }
|
|
634
|
+
}
|
|
635
|
+
"
|
|
636
|
+
/>
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
```vue
|
|
640
|
+
<C_Captcha
|
|
641
|
+
require-server-verification
|
|
642
|
+
:verification-timeout="8000"
|
|
643
|
+
:verifier="
|
|
644
|
+
async ({ signal }) => {
|
|
645
|
+
// providerProof 必须来自服务端或可信验证码提供商,不能由本地拼图结果伪造。
|
|
646
|
+
const providerProof = await obtainTrustedCaptchaProof({ signal })
|
|
647
|
+
const response = await fetch('/api/captcha/verify', {
|
|
648
|
+
method: 'POST',
|
|
649
|
+
headers: { 'content-type': 'application/json' },
|
|
650
|
+
body: JSON.stringify({ providerProof }),
|
|
651
|
+
signal,
|
|
652
|
+
})
|
|
653
|
+
return response.json() // { valid: boolean, token: 'server-issued-token' }
|
|
654
|
+
}
|
|
655
|
+
"
|
|
656
|
+
@verify-error="reportError"
|
|
657
|
+
/>
|
|
658
|
+
```
|
|
659
|
+
|
|
660
|
+
开启 `require-server-verification` 后,成功响应必须包含服务端 token。该 token 应短期、一次性使用,并绑定当前会话或业务请求。`C_Login` 可通过 `captchaProvider`、`captchaChallengeUrl`、`captchaVerifier`、`requireCaptchaServerVerification` 和 `captchaVerificationTimeout` 透传同一安全策略,并在 `submit` 数据中通过 `captchaType` 与 `captchaVerifiedBy` 标识验证类型和来源。更多边界说明见 [SECURITY.md](../../SECURITY.md)。
|
|
661
|
+
|
|
662
|
+
`C_Login` 的“记住我”只保存用户名,不保存密码。短信验证码仅对格式正确的手机号触发事件;组件会立即开始本地倒计时,发送结果和服务端限流仍由宿主处理。`C_City` 在首次打开时才加载城市索引,字母跳转只作用于当前实例;默认触发器、字母和城市项均可用键盘操作。
|
|
663
|
+
|
|
664
|
+
## 表格加载态
|
|
665
|
+
|
|
666
|
+
`C_Table` 默认显示跟随主题主色的数据光环 SVG 加载动画:环形轨道、数据行和细光束提示等待状态,保留已有数据,并遵循系统减少动态效果设置,无需页面配置。内置异步展开行同样复用 `C_Loading`;自定义展开内容仍由使用侧决定展示。可通过 `loading` 插槽替换默认内容。独立的 `C_Loading` 支持 `size`(16–120,默认 48)、`label`(可选说明)和 `color`(可选颜色);原生 `NSpin` 使用时请关闭旋转,避免 SVG 整体转动:
|
|
667
|
+
|
|
668
|
+
```vue
|
|
669
|
+
<NSpin :show="loading" :size="48" :rotate="false">
|
|
670
|
+
<template #icon><C_Loading /></template>
|
|
671
|
+
<section>页面内容</section>
|
|
672
|
+
</NSpin>
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
## C_Login 扩展表单
|
|
676
|
+
|
|
677
|
+
`password-fields` 插槽位于密码输入框下方,提供 `username`、`loading`,可配置工作空间或其他业务字段。`username-change` 在初始预填、恢复记住的账号和输入变化时同步触发。宿主通过 `submitDisabled` 阻止扩展字段尚未就绪时的按钮与回车提交;`loading` 期间凭据输入禁用。公司查询、成员关系和权限始终由宿主认证服务处理,组件不保存业务上下文。
|
|
678
|
+
|
|
679
|
+
## 页面切换加载
|
|
680
|
+
|
|
681
|
+
路由生命周期只需要关联 `start()` / `finish(id)`;动画、主题和减少动态效果由组件库处理。默认延迟 160ms 显示,快速切换不闪烁,旧任务完成不会关闭新任务。
|
|
682
|
+
|
|
683
|
+
```vue
|
|
684
|
+
<C_PageLoading :show="loading.visible.value" />
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
```ts
|
|
688
|
+
import { createPageLoading } from '@robot-admin/naive-ui-components/C_PageLoading'
|
|
689
|
+
const loading = createPageLoading({ delay: 160 })
|
|
690
|
+
const id = loading.start()
|
|
691
|
+
// 路由完成、取消或失败后
|
|
692
|
+
loading.finish(id)
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
## 应用级扩展与迁移
|
|
696
|
+
|
|
697
|
+
`createHighlight()`、`setupHighlight()` 各自持有独立高亮实例;组件中的 `useHighlight()` 读取应用注入,独立调用创建新的 API。默认不写入 `window.hljs`,只有兼容旧窗口用法时显式开启 `exposeToWindow: true`。
|
|
698
|
+
|
|
699
|
+
全量插件为每个应用持有独立表单 registry。已有全局 `registerRenderer()` 用法应迁移到 `createFormRendererRegistry()` 与插件的 `formRenderers` 选项;子路径接入可以显式提供 `FORM_RENDERER_REGISTRY_KEY`。示例、优先级和所有权规则见[架构与隔离](../architecture.md)。
|