@xmszm/core 0.0.2 → 0.0.4

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 (71) hide show
  1. package/README.md +10 -1
  2. package/dist/index.cjs +2 -2
  3. package/dist/index.mjs +1296 -1285
  4. package/dist/plugin/vite/initRouteMeta.cjs +1 -0
  5. package/dist/plugin/vite/initRouteMeta.mjs +13 -0
  6. package/dist/style.css +1 -1
  7. package/docs/.vitepress/config.mjs +10 -1
  8. package/docs/components/config-options.md +125 -0
  9. package/docs/components/dataform.md +175 -22
  10. package/docs/components/datatable.md +21 -39
  11. package/docs/components/dialog.md +155 -16
  12. package/docs/components/options.md +43 -14
  13. package/docs/components/query.md +20 -12
  14. package/docs/components/utils.md +118 -10
  15. package/docs/guide/changelog.md +81 -0
  16. package/docs/guide/config.md +241 -4
  17. package/docs/guide/quickstart.md +27 -2
  18. package/docs/index.md +1 -1
  19. package/docs/usage.md +16 -3
  20. package/examples/README.md +46 -0
  21. package/examples/index.html +14 -0
  22. package/examples/package.json +25 -0
  23. package/examples/pnpm-lock.yaml +1568 -0
  24. package/examples/pnpm-workspace.yaml +2 -0
  25. package/examples/src/AdminSystem.vue +870 -0
  26. package/examples/src/App.vue +330 -0
  27. package/examples/src/Introduction.vue +307 -0
  28. package/examples/src/main.js +22 -0
  29. package/examples/src/utils/permission.js +16 -0
  30. package/examples/src/utils/request.js +10 -0
  31. package/examples/vite.config.js +41 -0
  32. package/package.json +10 -4
  33. package/src/dialog/commonDialog.tsx +286 -0
  34. package/src/dialog/utils/{dialog.js → dialog.ts} +2 -0
  35. package/src/enum/sort.tsx +45 -0
  36. package/src/form/DataForm.vue +26 -52
  37. package/src/{index.js → index.ts} +7 -6
  38. package/src/list/{useList.jsx → useList.tsx} +49 -14
  39. package/src/options/{Options.jsx → Options.tsx} +37 -36
  40. package/src/options/defaultOptions.tsx +656 -0
  41. package/src/query/CommonQuery.vue +57 -89
  42. package/src/table/DataTable.vue +60 -94
  43. package/src/table/opr/{DataColumnCollet.jsx → DataColumnCollet.tsx} +18 -8
  44. package/src/table/opr/{useDataColumn.jsx → useDataColumn.tsx} +43 -48
  45. package/src/table/opr/{useDataColumnButton.jsx → useDataColumnButton.tsx} +13 -6
  46. package/src/table/opr/{useDataColumnPop.jsx → useDataColumnPop.tsx} +13 -5
  47. package/src/utils/{array.js → array.ts} +4 -6
  48. package/src/utils/{config.js → config.ts} +16 -2
  49. package/src/utils/{dialog.js → dialog.ts} +2 -2
  50. package/src/utils/{object.js → object.ts} +1 -0
  51. package/src/utils/{upload.js → upload.ts} +3 -3
  52. package/types/components.d.ts +402 -0
  53. package/types/index.d.ts +145 -7
  54. package/types/plugin/vite/initRouteMeta.d.ts +23 -0
  55. package/types/src.d.ts +55 -0
  56. package/types/vue-shim.d.ts +9 -0
  57. package/examples/demo.vue +0 -224
  58. package/src/dialog/commonDialog.jsx +0 -262
  59. package/src/enum/sort.jsx +0 -31
  60. package/src/options/defaultOptions.jsx +0 -580
  61. /package/src/dialog/{useCommonDialog.js → useCommonDialog.ts} +0 -0
  62. /package/src/directives/{auto-register.js → auto-register.ts} +0 -0
  63. /package/src/directives/{permission.js → permission.ts} +0 -0
  64. /package/src/enum/{options.js → options.ts} +0 -0
  65. /package/src/plugin/{index.js → index.ts} +0 -0
  66. /package/src/plugin/vite/{initRouteMeta.js → initRouteMeta.ts} +0 -0
  67. /package/src/store/utils/{index.js → index.ts} +0 -0
  68. /package/src/table/opr/{useQRCode.js → useQRCode.ts} +0 -0
  69. /package/src/table/utils/{ellipsis.js → ellipsis.ts} +0 -0
  70. /package/src/utils/{auth.js → auth.ts} +0 -0
  71. /package/src/utils/{time.js → time.ts} +0 -0
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function h(a,s=""){return a.length?(a.forEach(e=>{var m;e.children&&h(e.children,e==null?void 0:e.path),e.path&&(e.sourceFullPath=`${s?`${s}/`.replace(/^\/\//,"/"):""}${e.path}`),e.meta||(e.meta={});const n=(e==null?void 0:e.title)??((m=e==null?void 0:e.meta)==null?void 0:m.title)??"未命名页面";e!=null&&e.api&&(e.meta.api=e.api),n&&(e.meta.title=n,e.title=n),e!=null&&e.hidden&&(e.meta.hidden=e.hidden);let t=[];e!=null&&e.auth&&(e.meta.auth=e.auth,t=Object.keys(e.auth).reduce((r,i)=>(typeof e.auth[i]=="string"?r.push(e.auth[i]):typeof e.auth[i]=="boolean"&&r.push(i),r),[])),e!=null&&e.permission&&(e.meta.permission=e.permission),e.meta.permission&&Array.isArray(e.meta.permission)?e.meta.permission=e.meta.permission.concat(t):t.length&&(e.meta.permission=t)}),a):[]}exports.initRouteMeta=h;
@@ -0,0 +1,13 @@
1
+ function m(a, r = "") {
2
+ return a.length ? (a.forEach((e) => {
3
+ var h;
4
+ e.children && m(e.children, e == null ? void 0 : e.path), e.path && (e.sourceFullPath = `${r ? `${r}/`.replace(/^\/\//, "/") : ""}${e.path}`), e.meta || (e.meta = {});
5
+ const n = (e == null ? void 0 : e.title) ?? ((h = e == null ? void 0 : e.meta) == null ? void 0 : h.title) ?? "未命名页面";
6
+ e != null && e.api && (e.meta.api = e.api), n && (e.meta.title = n, e.title = n), e != null && e.hidden && (e.meta.hidden = e.hidden);
7
+ let i = [];
8
+ e != null && e.auth && (e.meta.auth = e.auth, i = Object.keys(e.auth).reduce((s, t) => (typeof e.auth[t] == "string" ? s.push(e.auth[t]) : typeof e.auth[t] == "boolean" && s.push(t), s), [])), e != null && e.permission && (e.meta.permission = e.permission), e.meta.permission && Array.isArray(e.meta.permission) ? e.meta.permission = e.meta.permission.concat(i) : i.length && (e.meta.permission = i);
9
+ }), a) : [];
10
+ }
11
+ export {
12
+ m as initRouteMeta
13
+ };
package/dist/style.css CHANGED
@@ -1 +1 @@
1
- .filter-box[data-v-2aba8b9e]{padding:20px;margin:-16px -28px -20px;box-sizing:border-box}.filter-main[data-v-2aba8b9e]{display:flex;align-content:flex-start;flex-wrap:wrap;min-height:500px;max-height:700px;overflow-y:auto;row-gap:20px;padding:0 0 15px;box-sizing:border-box}.filter-main .filter-item[data-v-2aba8b9e]{--info-color: var(--e0ecc754);--n-border-checked: 1px solid var(--info-color) !important;--n-border-focus: 1px solid var(--info-color) !important;--n-color-checked: var(--info-color) !important;--n-box-shadow-focus: 0 0 0 2px #6a1f7403 !important;width:calc(100% / 3)}.filter-footer[data-v-2aba8b9e]{display:flex;justify-content:space-between;align-items:center}.filter-footer .submit-btn[data-v-2aba8b9e]{width:80px}[data-v-d6710561] .n-data-table-tr--summary{position:sticky;bottom:0;left:0;right:0;z-index:2}[data-v-d6710561] .n-data-table-tr--summary .n-data-table-td--summary{border-top:1px solid var(--n-merged-border-color)}.upload-box[data-v-54e2cc87]{width:auto}.upload-box[data-v-54e2cc87] .n-upload-file-list.n-upload-file-list--grid{display:flex;flex-wrap:wrap}.upload-box[data-v-54e2cc87] .n-upload-file.n-upload-file--image-card-type{width:var(--image-w);height:var(--image-h)}.upload-box[data-v-54e2cc87] .n-upload-file.n-upload-file--image-card-type .n-image img{object-fit:var(--image-mode)!important}.upload-box[data-v-54e2cc87] .n-upload-trigger--image-card{width:var(--image-w);height:var(--image-h)}.upload-box[data-v-54e2cc87] .n-upload-file--error-status:not(:hover) .n-upload-file-info,.upload-box[data-v-54e2cc87] .n-upload-file--info-status:not(:hover) .n-upload-file-info{position:relative}.upload-box[data-v-54e2cc87] .n-upload-file--error-status:not(:hover) .n-upload-file-info:after,.upload-box[data-v-54e2cc87] .n-upload-file--info-status:not(:hover) .n-upload-file-info:after{content:"";position:absolute;top:0;left:0;right:0;bottom:0;z-index:5;display:block;background-color:#0006}.upload-box[data-v-54e2cc87] .n-upload-file--error-status:not(:hover):after{font-size:12px;white-space:nowrap;content:"上传失败~";position:absolute;color:#ffffffbf;top:50%;left:50%;transform:translate(-50%,-50%);z-index:5;display:block}.upload-box[data-v-54e2cc87] .n-upload-file--info-status:not(:hover):after{font-size:12px;white-space:nowrap;content:"加载中~";position:absolute;color:#ffffffbf;top:50%;left:50%;transform:translate(-50%,-50%);z-index:5;display:block}.svg-icon[data-v-9dbe5f10]{width:inherit;height:inherit;fill:currentColor;vertical-align:middle}.core-dialog-main,.core-dialog-content{box-sizing:border-box;display:flex;align-items:flex-start}.core-dialog-main{min-height:300px}.core-dialog .n-dialog__content{overflow-y:auto;margin:10px -28px 0;box-sizing:border-box;flex:1;border-top:1px solid #91919147;border-bottom:1px solid #91919147;padding:28px}.core-dialog .n-dialog__action{padding:20px 0 0;box-sizing:border-box}.core-dialog-read .n-dialog__content{border-bottom:unset}.select-text[data-v-6ef17b7a]{min-width:100px;max-width:240px;text-align:center}.select-line-text[data-v-6ef17b7a]{text-align:center;white-space:nowrap;display:inline}
1
+ .filter-box[data-v-2aba8b9e]{padding:20px;margin:-16px -28px -20px;box-sizing:border-box}.filter-main[data-v-2aba8b9e]{display:flex;align-content:flex-start;flex-wrap:wrap;min-height:500px;max-height:700px;overflow-y:auto;row-gap:20px;padding:0 0 15px;box-sizing:border-box}.filter-main .filter-item[data-v-2aba8b9e]{--info-color: var(--e0ecc754);--n-border-checked: 1px solid var(--info-color) !important;--n-border-focus: 1px solid var(--info-color) !important;--n-color-checked: var(--info-color) !important;--n-box-shadow-focus: 0 0 0 2px #6a1f7403 !important;width:calc(100% / 3)}.filter-footer[data-v-2aba8b9e]{display:flex;justify-content:space-between;align-items:center}.filter-footer .submit-btn[data-v-2aba8b9e]{width:80px}[data-v-9de17e68] .n-data-table-tr--summary{position:sticky;bottom:0;left:0;right:0;z-index:2}[data-v-9de17e68] .n-data-table-tr--summary .n-data-table-td--summary{border-top:1px solid var(--n-merged-border-color)}.upload-box[data-v-54e2cc87]{width:auto}.upload-box[data-v-54e2cc87] .n-upload-file-list.n-upload-file-list--grid{display:flex;flex-wrap:wrap}.upload-box[data-v-54e2cc87] .n-upload-file.n-upload-file--image-card-type{width:var(--image-w);height:var(--image-h)}.upload-box[data-v-54e2cc87] .n-upload-file.n-upload-file--image-card-type .n-image img{object-fit:var(--image-mode)!important}.upload-box[data-v-54e2cc87] .n-upload-trigger--image-card{width:var(--image-w);height:var(--image-h)}.upload-box[data-v-54e2cc87] .n-upload-file--error-status:not(:hover) .n-upload-file-info,.upload-box[data-v-54e2cc87] .n-upload-file--info-status:not(:hover) .n-upload-file-info{position:relative}.upload-box[data-v-54e2cc87] .n-upload-file--error-status:not(:hover) .n-upload-file-info:after,.upload-box[data-v-54e2cc87] .n-upload-file--info-status:not(:hover) .n-upload-file-info:after{content:"";position:absolute;top:0;left:0;right:0;bottom:0;z-index:5;display:block;background-color:#0006}.upload-box[data-v-54e2cc87] .n-upload-file--error-status:not(:hover):after{font-size:12px;white-space:nowrap;content:"上传失败~";position:absolute;color:#ffffffbf;top:50%;left:50%;transform:translate(-50%,-50%);z-index:5;display:block}.upload-box[data-v-54e2cc87] .n-upload-file--info-status:not(:hover):after{font-size:12px;white-space:nowrap;content:"加载中~";position:absolute;color:#ffffffbf;top:50%;left:50%;transform:translate(-50%,-50%);z-index:5;display:block}.svg-icon[data-v-9dbe5f10]{width:inherit;height:inherit;fill:currentColor;vertical-align:middle}.core-dialog-main,.core-dialog-content{box-sizing:border-box;display:flex;align-items:flex-start}.core-dialog-main{min-height:300px}.core-dialog .n-dialog__content{overflow-y:auto;margin:10px -28px 0;box-sizing:border-box;flex:1;border-top:1px solid #91919147;border-bottom:1px solid #91919147;padding:28px}.core-dialog .n-dialog__action{padding:20px 0 0;box-sizing:border-box}.core-dialog-read .n-dialog__content{border-bottom:unset}.select-text[data-v-643f6214]{min-width:100px;max-width:240px;text-align:center}.select-line-text[data-v-643f6214]{text-align:center;white-space:nowrap;display:inline}
@@ -16,7 +16,9 @@ export default defineConfig({
16
16
  { text: '指南', link: '/guide/quickstart' },
17
17
  { text: '组件', link: '/components/dataform' },
18
18
  { text: '工具', link: '/components/utils' },
19
+ { text: '版本历史', link: '/guide/changelog' },
19
20
  { text: '示例 Demo', link: '/guide/demo' },
21
+ { text: '在线示例', link: '/examples/', target: '_self' },
20
22
  ],
21
23
  sidebar: {
22
24
  '/guide/': [
@@ -24,8 +26,9 @@ export default defineConfig({
24
26
  text: '指南',
25
27
  items: [
26
28
  { text: '快速开始', link: '/guide/quickstart' },
27
- { text: '配置指南', link: '/guide/config' },
29
+ { text: '初始化配置', link: '/guide/config' },
28
30
  { text: '本地开发', link: '/guide/local-development' },
31
+ { text: '版本历史', link: '/guide/changelog' },
29
32
  { text: '示例 Demo 说明', link: '/guide/demo' },
30
33
  ],
31
34
  },
@@ -55,6 +58,12 @@ export default defineConfig({
55
58
  { text: '权限与路由', link: '/components/utils#权限与路由' },
56
59
  ],
57
60
  },
61
+ {
62
+ text: '配置项',
63
+ items: [
64
+ { text: '配置项说明', link: '/components/config-options' },
65
+ ],
66
+ },
58
67
  ],
59
68
  },
60
69
  socialLinks: [
@@ -0,0 +1,125 @@
1
+ ---
2
+ title: 配置项说明
3
+ ---
4
+
5
+ 本文档包含所有组件中使用的通用配置项说明。
6
+
7
+ ## Options 配置字段
8
+
9
+ `Options` 配置字段用于 `DataForm`、`CommonQuery`、`Options` 等组件的表单项配置。
10
+
11
+ | 字段名 | 必填 | 类型 | 说明 |
12
+ |--------|------|------|------|
13
+ | `key` | 是 | `string \| string[]` | 字段键名,支持数组键用于区间 |
14
+ | `label` | 否 | `string` | 显示文本 |
15
+ | `way` | 否 | `string` | 控件类型,默认 `'input'`。支持的枚举值见下方 [way 字段类型说明](#way-字段类型说明) |
16
+ | `options` | 否 | `Array` | 选择类数据,数组项默认使用 `name` 和 `id` 字段(可通过 `labelField`、`valueField` 配置) |
17
+ | `enum` | 否 | `Object` | 对象形式的枚举,会通过 `ObjectToArray` 转数组 |
18
+ | `props` | 否 | `Object \| Function` | 透传到具体控件(如 `NInput`、`NSelect`),支持函数,入参包含 `formRef`、`setValue` |
19
+ | `formItemProps` | 否 | `Object` | 透传到 `NFormItem`,可控制 label、样式、校验反馈等 |
20
+ | `required` | 否 | `boolean` | 是否必填,影响自动校验 |
21
+ | `rule` | 否 | `Function \| Array` | 自定义校验规则 |
22
+ | `message` | 否 | `string` | 校验失败时的提示信息 |
23
+ | `render` | 否 | `Function` | 完全自定义渲染,优先级最高 |
24
+ | `isRender` | 否 | `boolean \| Function` | 控制是否渲染该项 |
25
+ | `default` | 否 | `any \| Function` | 默认值,支持函数 |
26
+ | `prefix` | 否 | `Function \| Object` | 前缀内容,支持函数或对象 |
27
+ | `suffix` | 否 | `Function \| Object` | 后缀内容,支持函数或对象 |
28
+ | `labelSuffix` | 否 | `string \| Function` | label 后缀,支持图标或函数 |
29
+ | `labelSuffixProps` | 否 | `Object` | label 后缀的属性配置 |
30
+ | `noLabel` | 否 | `boolean` | 是否隐藏 label |
31
+ | `labelClass` | 否 | `string` | label 的 class |
32
+ | `permission` | 否 | `string` | 权限标识,用于权限指令控制显示 |
33
+
34
+ ### way 字段类型说明
35
+
36
+ | 类型值 | 说明 | 对应组件 |
37
+ |--------|------|----------|
38
+ | `input` | 文本输入框 | `NInput` |
39
+ | `select` | 选择器 | `NSelect` |
40
+ | `date` | 日期选择器 | `NDatePicker` |
41
+ | `dateRange` | 日期范围选择器 | `NDatePicker` |
42
+ | `time` | 时间选择器 | `NTimePicker` |
43
+ | `radio` | 单选框 | `NRadioGroup` |
44
+ | `switch` | 开关 | `NSwitch` |
45
+ | `uploadFile` | 文件上传 | 自定义上传组件 |
46
+ | `image` | 图片上传 | 自定义图片组件 |
47
+ | `dataTable` | 表格选择 | `DataTable` |
48
+ | `button` | 按钮 | `NButton` |
49
+
50
+ ## commonDialogMethod Mode 枚举
51
+
52
+ `commonDialogMethod` 的 `mode` 参数用于指定弹窗模式。
53
+
54
+ | 枚举值 | 说明 | 是否只读 |
55
+ |--------|------|----------|
56
+ | `none` | 无模式,不显示模式前缀 | 否 |
57
+ | `create` | 创建模式,标题前缀为"创建" | 否 |
58
+ | `add` | 添加模式,标题前缀为"添加",默认值 | 否 |
59
+ | `edit` | 编辑模式,标题前缀为"编辑" | 否 |
60
+ | `view` | 查看模式,标题前缀为"查看",自动设置为只读 | 是 |
61
+ | `export` | 导出模式,标题前缀为"导出" | 否 |
62
+ | `import` | 导入模式,标题前缀为"导入" | 否 |
63
+ | `delete` | 删除模式,标题前缀为"删除" | 否 |
64
+ | `copy` | 复制模式,标题前缀为"复制" | 否 |
65
+
66
+ > 注意:`view` 模式会自动设置 `read: true`,使表单变为只读状态。
67
+
68
+ ## commonDialogMethod Action 配置
69
+
70
+ `commonDialogMethod` 的 `action` 参数用于自定义弹窗底部按钮。
71
+
72
+ | 字段名 | 必填 | 类型 | 说明 |
73
+ |--------|------|------|------|
74
+ | `label` | 否 | `string` | 按钮文本 |
75
+ | `mode` | 否 | `string` | 按钮模式,`'cancel'` 表示取消按钮 |
76
+ | `valid` | 否 | `boolean` | 是否执行 DataForm 校验,默认 `false` |
77
+ | `loading` | 否 | `boolean` | 是否自动切换 loading 状态,默认 `false` |
78
+ | `onClick` | 否 | `Function` | 点击事件,入参 `{ model, cancel, validate, showLoading, hideLoading }` |
79
+ | `render` | 否 | `Function` | 自定义渲染函数,优先级高于 `label` |
80
+ | `props` | 否 | `Object` | 透传给 `NButton` 的属性 |
81
+ | `style` | 否 | `Object` | 按钮样式 |
82
+
83
+ ## createActionColumnJsx 配置
84
+
85
+ `createActionColumnJsx` 用于生成表格操作列配置。
86
+
87
+ | 字段名 | 必填 | 类型 | 说明 |
88
+ |--------|------|------|------|
89
+ | `label` | 否 | `string` | 按钮文本 |
90
+ | `type` | 否 | `string` | 按钮类型,默认 `'primary'`。支持的枚举值见下方 [按钮类型枚举](#按钮类型枚举) |
91
+ | `mode` | 否 | `string` | 操作模式,`'pop'` 表示需要二次确认,其他值或不设置则直接执行 |
92
+ | `onClick` | 否 | `Function` | 点击事件,入参为当前行数据 `row` |
93
+ | `permission` | 否 | `string` | 权限标识,用于权限控制 |
94
+ | `render` | 否 | `Function` | 自定义渲染函数 |
95
+ | `props` | 否 | `Object` | 透传给按钮的属性 |
96
+
97
+ ### 按钮类型枚举
98
+
99
+ | 类型值 | 说明 |
100
+ |--------|------|
101
+ | `default` | 默认按钮 |
102
+ | `primary` | 主要按钮(默认值) |
103
+ | `success` | 成功按钮 |
104
+ | `info` | 信息按钮 |
105
+ | `warning` | 警告按钮 |
106
+ | `error` | 错误按钮 |
107
+ | `tertiary` | 第三级按钮 |
108
+ | `quaternary` | 第四级按钮 |
109
+
110
+ ## CommonQuery queryType 说明
111
+
112
+ `CommonQuery` 组件中,`options` 配置项的 `queryType` 字段用于指定查询参数的类型。
113
+
114
+ | queryType 值 | 说明 | 示例 |
115
+ |--------------|------|------|
116
+ | `likeQuery` | 模糊查询,值会放入 `query.likeQuery[key]` | `{ key: 'name', queryType: 'likeQuery' }` |
117
+ | 不设置或空字符串 | 直接放入 `query[key]` | `{ key: 'status' }` |
118
+
119
+ ## 相关链接
120
+
121
+ - [DataForm 组件](/components/dataform)
122
+ - [Options 组件](/components/options)
123
+ - [CommonQuery 组件](/components/query)
124
+ - [commonDialogMethod](/components/dialog)
125
+
@@ -29,33 +29,186 @@ const options = [
29
29
  ```
30
30
 
31
31
  ## Props
32
- - `options: Array` 表单项配置,透传给 `Options`。
33
- - `value (v-model:value): Object` 表单数据。
34
- - `read: boolean` 只读模式。
35
- - `labelField: string` 默认 `label`,决定 label 字段名。
36
- - `formProps: Object` 透传给 `naive-ui` `NForm`。
37
- - `formItemProps: Object` 透传给每个 `NFormItem`。
38
- - `dialog: boolean` 在弹窗场景下使用时自动附加样式。
39
- - `rules: Object` 自定义校验规则;不传则根据 `options` 自动生成。
40
-
41
- ## Options 关键字段
42
- - `key` 必填,字段键名。支持数组键用于区间。
43
- - `label` 显示文本。
44
- - `way` 字段类型,默认 `input`。常用:`select`、`date`、`dateRange`、`time`、`radio`、`switch`、`uploadFile`、`image`、`dataTable` 等。
45
- - `options / enum` 选择类数据。`enum` 会通过 `ObjectToArray` 转数组。
46
- - `props` 透传到具体控件(如 `NInput`、`NSelect`)。
47
- - `formItemProps` 透传到 `NFormItem`,可控制 label、样式、校验反馈等。
48
- - `required / rule / message` 影响自动校验。
49
- - `render` 自定义渲染,优先级最高。
32
+
33
+ | 字段名 | 必填 | 类型 | 说明 |
34
+ |--------|------|------|------|
35
+ | `options` | 否 | `Array` | 表单项配置,透传给 `Options` |
36
+ | `value` / `v-model:value` | 否 | `Object` | 表单数据,支持 v-model 双向绑定 |
37
+ | `read` | 否 | `boolean` | 只读模式,默认 `false` |
38
+ | `labelField` | 否 | `string` | 决定 label 字段名,默认 `'label'` |
39
+ | `formProps` | 否 | `Object` | 透传给 `naive-ui` `NForm` 的属性 |
40
+ | `formItemProps` | 否 | `Object` | 透传给每个 `NFormItem` 的属性 |
41
+ | `dialog` | 否 | `boolean` | 在弹窗场景下使用时自动附加样式,默认 `false` |
42
+ | `rules` | 否 | `Object` | 自定义校验规则;不传则根据 `options` 自动生成 |
43
+ | `isNo` | 否 | `boolean` | 内容最小高度控制,默认 `true` |
44
+ | `contentStyle` | 否 | `Object` | 内容区域样式,默认 `{}` |
45
+
46
+ ## Options 配置字段
47
+
48
+ `options` 配置项使用 [Options 配置字段](/components/config-options#options-配置字段),详见配置项说明文档。
50
49
 
51
50
  ## 方法(defineExpose)
52
- - `formRef` Naive UI `NForm` 实例引用。
53
- - `getRule()` 获取自动生成的 rules。
54
- - `valid(keyCode?: string[])` 返回 Promise,支持按键位校验。
55
- - `confirm(fn)` 触发校验后执行回调。
51
+
52
+ | 方法名 | 类型 | 说明 |
53
+ |--------|------|------|
54
+ | `formRef` | `Ref<FormInstance>` | Naive UI `NForm` 实例引用 |
55
+ | `getRule()` | `() => Object` | 获取自动生成的 rules |
56
+ | `valid(keyCode?)` | `(keyCode?: string[]) => Promise<void>` | 表单校验,返回 Promise,支持按键位校验 |
57
+ | `confirm(fn)` | `(fn?: Function) => Promise<Object>` | 触发校验后执行回调,返回 Promise |
58
+
59
+ ## initRules
60
+
61
+ `initRules` 用于根据 `options` 配置自动生成表单校验规则。规则处理基于 [async-validator](https://github.com/yiminghe/async-validator) 库。
62
+
63
+ ```javascript
64
+ import { initRules } from '@xmszm/core'
65
+
66
+ const options = [
67
+ { key: 'name', label: '名称', way: 'input', required: true },
68
+ { key: 'email', label: '邮箱', way: 'input', rule: /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/ },
69
+ ]
70
+
71
+ const rules = initRules(options)
72
+ // => {
73
+ // name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
74
+ // email: [{ pattern: /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/, message: '请输入正确的邮箱', trigger: 'blur' }]
75
+ // }
76
+ ```
77
+
78
+ ### 规则生成逻辑
79
+
80
+ #### required
81
+
82
+ - `required: true`:自动生成必填校验
83
+ - 默认情况下,只需要 `required: true` 即可满足大部分校验需求
84
+
85
+ ```javascript
86
+ const options = [
87
+ { key: 'name', label: '名称', way: 'input', required: true },
88
+ // 自动生成:{ required: true, message: '请输入名称', trigger: 'blur' }
89
+ ]
90
+ ```
91
+
92
+ #### rule(自定义校验规则)
93
+
94
+ `rule` 支持以下形式:
95
+
96
+ 1. **对象形式**:直接传入校验规则对象
97
+
98
+ ```javascript
99
+ const options = [
100
+ {
101
+ key: 'age',
102
+ label: '年龄',
103
+ way: 'input',
104
+ rule: {
105
+ type: 'number',
106
+ min: 18,
107
+ max: 100,
108
+ message: '年龄必须在 18-100 之间',
109
+ },
110
+ },
111
+ ]
112
+ ```
113
+
114
+ 2. **函数形式**:函数返回校验规则对象,可以根据当前值和表单数据动态生成规则
115
+
116
+ ```javascript
117
+ const options = [
118
+ {
119
+ key: 'password',
120
+ label: '密码',
121
+ way: 'input',
122
+ rule: (value, formData) => {
123
+ // 函数返回的是规则配置对象,可以根据 value 和 formData 动态生成规则
124
+ if (value && value.length < 8) {
125
+ return {
126
+ required: true,
127
+ message: '密码长度不能少于 8 位',
128
+ }
129
+ }
130
+ // 返回规则对象,用于动态校验
131
+ return {
132
+ required: true,
133
+ min: 8,
134
+ message: '密码长度不能少于 8 位',
135
+ }
136
+ },
137
+ },
138
+ {
139
+ key: 'confirmPassword',
140
+ label: '确认密码',
141
+ way: 'input',
142
+ rule: (value, formData) => {
143
+ // 可以根据其他字段的值动态生成规则
144
+ return {
145
+ required: true,
146
+ validator: (rule, val) => {
147
+ if (val !== formData.password) {
148
+ return Promise.reject('两次输入的密码不一致')
149
+ }
150
+ return Promise.resolve()
151
+ },
152
+ }
153
+ },
154
+ },
155
+ ]
156
+ ```
157
+
158
+ ::: tip 函数形式的优势
159
+ 函数形式的 `rule` 可以根据当前字段的值(`value`)和整个表单数据(`formData`)动态生成校验规则,从而实现:
160
+ - 动态必填校验(根据其他字段的值决定是否必填)
161
+ - 联动校验(如确认密码需要与密码一致)
162
+ - 条件校验(根据表单状态动态调整校验规则)
163
+ :::
164
+
165
+ ::: warning 重要提示
166
+ 当使用 `rule` 自定义校验规则时,**外部的 `required` 配置将无效**。如果需要在自定义规则中包含必填校验,请在 `rule` 对象中显式设置 `required: true`。
167
+
168
+ ```javascript
169
+ // ❌ 错误:rule 存在时,外部的 required 无效
170
+ {
171
+ key: 'name',
172
+ required: true,
173
+ rule: { type: 'string', min: 2 },
174
+ }
175
+
176
+ // ✅ 正确:在 rule 中包含 required
177
+ {
178
+ key: 'name',
179
+ rule: {
180
+ type: 'string',
181
+ required: true,
182
+ min: 2,
183
+ message: '名称至少需要 2 个字符',
184
+ },
185
+ }
186
+ ```
187
+ :::
188
+
189
+ #### message
190
+
191
+ 自定义错误提示信息。
192
+
193
+ ```javascript
194
+ const options = [
195
+ {
196
+ key: 'name',
197
+ label: '名称',
198
+ way: 'input',
199
+ required: true,
200
+ message: '请输入您的姓名', // 自定义错误提示
201
+ },
202
+ ]
203
+ ```
204
+
205
+ ### 参考文档
206
+
207
+ 更多关于校验规则的详细说明,请参考 [async-validator](https://github.com/yiminghe/async-validator) 官方文档。
56
208
 
57
209
  ## 场景提示
58
210
  - 自动校验逻辑由 `initRules` 提供,`required`/`rule`/`message` 会影响生成结果。
59
211
  - 若需要动态选项,可在 `options` 内传入函数或 `ref`,组件内部会自动解包。
60
212
  - 弹窗模式结合 `commonDialogMethod` 使用最少代码完成「表单 + 弹窗 + 校验 + 提交」。
213
+ - `options` 中的 `way` 字段支持自定义控件类型,可通过 `setupOptions` 注册,详见 [初始化配置 - Options 注册](/guide/config#options-注册)。
61
214
 
@@ -2,7 +2,7 @@
2
2
  title: DataTable
3
3
  ---
4
4
 
5
- 基于 `naive-ui` `n-data-table` 的增强组件,提供列筛选、操作列、排序、虚拟滚动与省略。
5
+ 基于 `naive-ui` `n-data-table` 的增强组件,提供列筛选、操作列、虚拟滚动与省略。
6
6
 
7
7
  ## 基础用法
8
8
  ```vue
@@ -25,44 +25,26 @@ const data = ref([
25
25
  </template>
26
26
  ```
27
27
 
28
- ## Props(常用)
29
- - `data: Array` 数据源。
30
- - `columns: Array` 列定义,支持 `label`/`title`、`key`、`width`、`ellipsis`、`sorter` 等。
31
- - `pagination: Object | null` 透传 `n-data-table` 分页。
32
- - `oprColumns: Object | null` 右侧操作列配置(模板中使用 `opr-columns`)。
33
- - `selectColumns: Object | null` 选择列(模板中使用 `select-columns`)。
34
- - `defaultColumns: Array` 默认可见列键(模板中使用 `default-columns`)。
35
- - `summaryColumns: Function` 汇总行(模板中使用 `summary-columns`)。
36
- - `isFilter: boolean` 是否启用列筛选。
37
- - `isEllipsis: boolean` 默认开启省略,使用内置 `ellipsis` tooltip。
38
- - `virtual: boolean` 虚拟滚动,默认数据量大时自动开启。
39
- - `rowKey: Function | String` 行键,用于标识每一行数据。
40
-
41
- ## 排序(orderEnum 内置工具)
42
- `orderEnum` 专为 `DataTable` 列排序提供,离开表格场景单独调用无意义。
43
-
44
- 用法示例(结合后端查询参数与分页刷新):
45
- ```javascript
46
- import { orderEnum } from '@xmszm/core'
47
-
48
- const listQuery = reactive({ sortFieldName: '', desc: false })
49
- const pageState = {
50
- fetchData: () => loadTableData(listQuery),
51
- }
52
-
53
- const columns = [
54
- {
55
- title: '创建时间',
56
- key: 'createdAt',
57
- width: 180,
58
- sorter: (listQueryParam, pageStateParam, key) => {
59
- // 选择升序/降序/默认时会进入这里
60
- orderEnum.ascend.fn(listQueryParam, key) // 设置排序字段与方向
61
- pageStateParam.fetchData() // 重新拉取数据
62
- },
63
- },
64
- ]
65
- ```
28
+ ## Props
29
+
30
+ | 字段名 | 必填 | 类型 | 说明 |
31
+ |--------|------|------|------|
32
+ | `data` | | `Array` | 数据源,默认 `[]` |
33
+ | `columns` | | `Array` | 列定义,支持 `label`/`title`、`key`、`width`、`ellipsis` 等 |
34
+ | `pagination` | 否 | `Object \| null` | 透传 `n-data-table` 分页配置 |
35
+ | `oprColumns` | 否 | `Object \| null` | 右侧操作列配置(模板中使用 `opr-columns`) |
36
+ | `selectColumns` | 否 | `Object \| null` | 选择列配置(模板中使用 `select-columns`) |
37
+ | `defaultColumns` | 否 | `Array` | 默认可见列键(模板中使用 `default-columns`),默认 `[]` |
38
+ | `summaryColumns` | 否 | `Function \| null` | 汇总行函数(模板中使用 `summary-columns`) |
39
+ | `isFilter` | | `boolean` | 是否启用列筛选,默认 `false` |
40
+ | `isEllipsis` | 否 | `boolean` | 是否开启省略,使用内置 `ellipsis` tooltip,默认 `true` |
41
+ | `virtual` | 否 | `boolean \| Object` | 虚拟滚动配置,默认数据量大时自动开启 |
42
+ | `rowKey` | 否 | `Function \| String` | 行键,用于标识每一行数据 |
43
+ | `emptyText` | 否 | `string` | 空数据提示文本,默认 `'没有数据'` |
44
+ | `emptyIcon` | 否 | `string` | 空数据图标,默认 `''` |
45
+ | `singleColumn` | 否 | `boolean` | 单列模式,默认 `false` |
46
+
47
+ ## 事件
66
48
 
67
49
  ## 列筛选弹窗
68
50
  - 设定 `isFilter=true` 时,右上角会出现“筛选字段”按钮。
@@ -34,26 +34,42 @@ function openEditDialog(row) {
34
34
  openEditDialog(currentRow)
35
35
  ```
36
36
 
37
- ## 参数(主要)
38
- - `title / noTitle / titleFull`:标题配置。
39
- - `options: Array` 表单项,直接传给 `DataForm`。
40
- - `mode` 与 `modeEnum`:内置 `create/add/edit/view/import/export/delete/copy/none`,`view` 会自动只读。
41
- - `labelField`:默认 `label`。
42
- - `isNo`:内容最小高度控制。
43
- - `formProps`、`contentStyle`:透传 `DataForm`。
44
- - `action`:自定义底部按钮数组或函数;不传则使用默认“取消 / 确定”。
45
- - `actionProps`:NSpace/按钮样式补充。
46
- - `interfaceFn`:点击默认“确定”时执行,入参 `(model, { close, hideLoading })`。
47
- - `interfaceFnCancel`:点击默认“取消”时执行。
48
- - `read / isRead`:只读模式。
37
+ ## 参数
38
+
39
+ | 字段名 | 必填 | 类型 | 说明 |
40
+ |--------|------|------|------|
41
+ | `title` | 否 | `string` | 弹窗标题,默认 `''` |
42
+ | `noTitle` | 否 | `boolean` | 是否隐藏标题,默认 `false` |
43
+ | `titleFull` | 否 | `Function \| string` | 自定义标题渲染函数或完整标题 |
44
+ | `options` | 否 | `Array` | 表单项配置,直接传给 `DataForm`,默认 `[]` |
45
+ | `mode` | 否 | `string` | 模式,默认 `'add'`。支持的枚举值见 [commonDialogMethod Mode 枚举](/components/config-options#commondialogmethod-mode-枚举) |
46
+ | `modeEnum` | 否 | `Object` | 自定义模式枚举,会与默认模式合并 |
47
+ | `labelField` | 否 | `string` | label 字段名,默认 `'label'` |
48
+ | `isNo` | 否 | `boolean` | 内容最小高度控制,默认 `true` |
49
+ | `formProps` | 否 | `Object` | 透传给 `DataForm` 的 `formProps`,默认 `{}` |
50
+ | `contentStyle` | 否 | `Object` | 透传给 `DataForm` 的 `contentStyle`,默认 `{}` |
51
+ | `action` | 否 | `Array \| Function` | 自定义底部按钮数组或函数;不传则使用默认“取消 / 确定” |
52
+ | `actionProps` | 否 | `Object` | NSpace/按钮样式补充,默认 `{}` |
53
+ | `interfaceFn` | 否 | `Function` | 点击默认“确定”时执行,入参 `(model, { close, hideLoading })` |
54
+ | `interfaceFnCancel` | 否 | `Function` | 点击默认“取消”时执行,入参 `(model, { close })` |
55
+ | `read` | 否 | `boolean` | 只读模式,默认 `false` |
56
+ | `isRead` | 否 | `boolean` | 只读模式(与 `read` 同义),默认 `false` |
57
+ | `valueData` | 否 | `Object` | 表单初始数据,默认 `{}` |
58
+ | `dialogProps` | 否 | `Object` | 透传给 `n-dialog` 的属性(第二个参数) |
49
59
 
50
60
  ## 返回值
51
- - `cancel()` 关闭弹窗。
52
- - `setValue(v, key?)` 设置表单数据。
53
- - `model` 响应式数据快照。
54
- - `modeEnum` 默认模式枚举。
61
+
62
+ | 字段名 | 类型 | 说明 |
63
+ |--------|------|------|
64
+ | `cancel` | `() => void` | 关闭弹窗的方法 |
65
+ | `setValue` | `(v: any, key?: string) => void` | 设置表单数据,`key` 为空时更新整个表单对象 |
66
+ | `model` | `Ref<Object>` | 响应式表单数据快照 |
67
+ | `modeEnum` | `Object` | 默认模式枚举对象 |
55
68
 
56
69
  ## 自定义动作
70
+
71
+ `action` 参数支持数组或函数,数组项配置详见 [commonDialogMethod Action 配置](/components/config-options#commondialogmethod-action-配置)。
72
+
57
73
  ```javascript
58
74
  commonDialogMethod({
59
75
  action: [
@@ -71,8 +87,131 @@ commonDialogMethod({
71
87
  })
72
88
  ```
73
89
 
90
+ ## useCommonDialog Hook
91
+
92
+ 在组件中使用 `commonDialogMethod` 的便捷方式,自动注册 Dialog 实例。
93
+
94
+ ### 基础用法
95
+
96
+ ```javascript
97
+ import { useCommonDialog } from '@xmszm/core'
98
+
99
+ export default {
100
+ setup() {
101
+ const openDialog = useCommonDialog()
102
+
103
+ const handleEdit = (row) => {
104
+ openDialog({
105
+ title: '编辑',
106
+ options: [
107
+ { key: 'name', label: '名称', way: 'input', required: true },
108
+ ],
109
+ valueData: row,
110
+ interfaceFn: async (data, { close }) => {
111
+ await save(data)
112
+ close()
113
+ },
114
+ })
115
+ }
116
+
117
+ return { handleEdit }
118
+ },
119
+ }
120
+ ```
121
+
122
+ ### 在 Composition API 中使用
123
+
124
+ ```javascript
125
+ import { useCommonDialog } from '@xmszm/core'
126
+
127
+ const openDialog = useCommonDialog()
128
+
129
+ function handleAdd() {
130
+ openDialog({
131
+ title: '新增',
132
+ options: formOptions,
133
+ interfaceFn: async (data, { close }) => {
134
+ await create(data)
135
+ close()
136
+ },
137
+ })
138
+ }
139
+ ```
140
+
141
+ ## Dialog 工具函数
142
+
143
+ ### createDialog
144
+
145
+ 使用 dialog 的工具函数,需要手动传入 dialog 实例。
146
+
147
+ ```javascript
148
+ import { useDialog } from 'naive-ui'
149
+ import { createDialog } from '@xmszm/core'
150
+
151
+ const dialog = useDialog()
152
+
153
+ // 创建自定义弹窗
154
+ const { destroy } = createDialog(dialog, {
155
+ title: '提示',
156
+ content: '这是一个自定义弹窗',
157
+ })
158
+ ```
159
+
160
+ ### createDialogMethods
161
+
162
+ 创建 Dialog 快捷方法(info、success、warning、error、create)。
163
+
164
+ ```javascript
165
+ import { useDialog } from 'naive-ui'
166
+ import { createDialogMethods } from '@xmszm/core'
167
+
168
+ const dialog = useDialog()
169
+ const dialogMethods = createDialogMethods(dialog)
170
+
171
+ // 使用快捷方法
172
+ dialogMethods.info({
173
+ title: '信息',
174
+ content: '这是一条信息',
175
+ })
176
+
177
+ dialogMethods.success({
178
+ title: '成功',
179
+ content: '操作成功',
180
+ })
181
+
182
+ dialogMethods.warning({
183
+ title: '警告',
184
+ content: '请注意',
185
+ })
186
+
187
+ dialogMethods.error({
188
+ title: '错误',
189
+ content: '操作失败',
190
+ })
191
+ ```
192
+
193
+ ### createDialogOptions
194
+
195
+ 创建 dialog 配置,应用主题色继承设置。通常用于自定义 Dialog 主题。
196
+
197
+ ```javascript
198
+ import { useDialog } from 'naive-ui'
199
+ import { createDialogOptions } from '@xmszm/core'
200
+
201
+ const dialog = useDialog()
202
+
203
+ const options = createDialogOptions({
204
+ title: '自定义主题',
205
+ content: '内容',
206
+ })
207
+
208
+ dialog.create(options)
209
+ ```
210
+
74
211
  ## 小贴士
75
212
  - 表单校验委托给 `DataForm`,`valid: true` 时自动调用 `formRef.valid()`。
76
213
  - 只读场景可用 `mode: 'view'`,或直接传 `read: true`。
77
214
  - 若需要自定义 header,可传 `titleFull` 为渲染函数。
215
+ - 在组件中推荐使用 `useCommonDialog` Hook,它会自动处理 Dialog 实例注册。
216
+ - `createDialog`、`createDialogMethods`、`createDialogOptions` 适用于需要更细粒度控制的场景。
78
217