kn-cli 1.0.134 → 1.0.136

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 (113) hide show
  1. package/build/package.json +2 -1
  2. package/build/vite.config.js +1 -0
  3. package/build/webpack.config.js +16 -2
  4. package/package.json +1 -1
  5. package/src/build.js +1 -1
  6. package/templates/template_admin_antd5/package.json +3 -3
  7. package/templates/template_admin_antd5/public/src/_antd.less +4 -4
  8. package/templates/template_admin_antd5/public/src/_reset.module.less +1 -1
  9. package/templates/template_admin_antd5/public/src/_variable.module.less +5 -5
  10. package/templates/template_admin_antd5/public/src/assets/images/expand-hover.png +0 -0
  11. package/templates/template_admin_antd5/public/src/assets/images/expand.png +0 -0
  12. package/templates/template_admin_antd5/public/src/assets/images/icon-add.png +0 -0
  13. package/templates/template_admin_antd5/public/src/assets/images/icon-full-size.png +0 -0
  14. package/templates/template_admin_antd5/public/src/assets/images/icon-resize.png +0 -0
  15. package/templates/template_admin_antd5/public/src/assets/images/icon-user.png +0 -0
  16. package/templates/template_admin_antd5/public/src/assets/images/login/bg.png +0 -0
  17. package/templates/template_admin_antd5/public/src/assets/images/login/logo.png +0 -0
  18. package/templates/template_admin_antd5/public/src/assets/images/nav/slogan.png +0 -0
  19. package/templates/template_admin_antd5/public/src/assets/images/unexpand-hover.png +0 -0
  20. package/templates/template_admin_antd5/public/src/assets/images/unexpand.png +0 -0
  21. package/templates/template_admin_antd5/public/src/components/antd/antProvider.jsx +16 -4
  22. package/templates/template_admin_antd5/public/src/components/antd/drawer/README.md +336 -0
  23. package/templates/template_admin_antd5/public/src/components/antd/drawer/index.jsx +264 -0
  24. package/templates/template_admin_antd5/public/src/components/antd/index.jsx +19 -7
  25. package/templates/template_admin_antd5/public/src/components/antd/index.module.less +26 -0
  26. package/templates/template_admin_antd5/public/src/components/antd/modal/README.md +324 -0
  27. package/templates/template_admin_antd5/public/src/components/antd/modal/index.jsx +185 -0
  28. package/templates/template_admin_antd5/public/src/components/antd/select/index.jsx +1 -1
  29. package/templates/template_admin_antd5/public/src/components/antd/spin/index.jsx +92 -0
  30. package/templates/template_admin_antd5/public/src/components/antd/spin/index.module.less +58 -0
  31. package/templates/template_admin_antd5/public/src/components/antd/theme.js +19 -8
  32. package/templates/template_admin_antd5/public/src/components/antd/tooltip/detail/index.jsx +19 -56
  33. package/templates/template_admin_antd5/public/src/components/debug/index.jsx +7 -2
  34. package/templates/template_admin_antd5/public/src/components/error/index.jsx +0 -5
  35. package/templates/template_admin_antd5/public/src/components/icon/expand/index.jsx +17 -0
  36. package/templates/template_admin_antd5/public/src/components/icon/expand/index.module.less +22 -0
  37. package/templates/template_admin_antd5/public/src/components/icon/fullSize/index.jsx +13 -0
  38. package/templates/template_admin_antd5/public/src/components/icon/fullSize/index.module.less +28 -0
  39. package/templates/template_admin_antd5/public/src/components/icon/index.jsx +7 -1
  40. package/templates/template_admin_antd5/public/src/components/image/preview.jsx +7 -10
  41. package/templates/template_admin_antd5/public/src/components/layout/basic/index.module.less +1 -1
  42. package/templates/template_admin_antd5/public/src/components/leftMenu/index.jsx +1 -2
  43. package/templates/template_admin_antd5/public/src/components/link/index.module.less +2 -2
  44. package/templates/template_admin_antd5/public/src/components/menuIcon/index.module.less +3 -3
  45. package/templates/template_admin_antd5/public/src/components/popup/index.jsx +91 -50
  46. package/templates/template_admin_antd5/public/src/components/popup/index.module.less +22 -15
  47. package/templates/template_admin_antd5/public/src/components/react/index.jsx +23 -9
  48. package/templates/template_admin_antd5/public/src/components/resizeBox/index.jsx +3 -3
  49. package/templates/template_admin_antd5/public/src/components/select/defaultServicesSelect/index.jsx +151 -40
  50. package/templates/template_admin_antd5/public/src/components/select/dictSelect/index.jsx +19 -3
  51. package/templates/template_admin_antd5/public/src/components/select/useSelectList.jsx +65 -65
  52. package/templates/template_admin_antd5/public/src/components/table/index.jsx +48 -327
  53. package/templates/template_admin_antd5/public/src/components/table/index.module.less +0 -110
  54. package/templates/template_admin_antd5/public/src/components/table/table/index.jsx +242 -0
  55. package/templates/template_admin_antd5/public/src/components/table/table/index.module.less +85 -0
  56. package/templates/template_admin_antd5/public/src/components/table/withPage.jsx +53 -0
  57. package/templates/template_admin_antd5/public/src/components/topMenu/index.jsx +46 -11
  58. package/templates/template_admin_antd5/public/src/components/topMenu/index.module.less +10 -7
  59. package/templates/template_admin_antd5/public/src/components/topMenu/popmenu/index.jsx +89 -0
  60. package/templates/template_admin_antd5/public/src/components/topMenu/popmenu/index.module.less +76 -0
  61. package/templates/template_admin_antd5/public/src/components/topMenu/topBar/index.module.less +4 -3
  62. package/templates/template_admin_antd5/public/src/components/video/index.jsx +1 -1
  63. package/templates/template_admin_antd5/public/src/components/video/preview.jsx +7 -10
  64. package/templates/template_admin_antd5/public/src/config.js +3 -0
  65. package/templates/template_admin_antd5/public/src/hooks/useLoading.jsx +2 -2
  66. package/templates/template_admin_antd5/public/src/index.jsx +7 -4
  67. package/templates/template_admin_antd5/public/src/mock/demo.js +3 -3
  68. package/templates/template_admin_antd5/public/src/pages/antdComponents/button/index.jsx +22 -0
  69. package/templates/template_admin_antd5/public/src/pages/antdComponents/check/index.jsx +12 -0
  70. package/templates/template_admin_antd5/public/src/pages/antdComponents/index.jsx +57 -114
  71. package/templates/template_admin_antd5/public/src/pages/antdComponents/index.module.less +5 -0
  72. package/templates/template_admin_antd5/public/src/pages/antdComponents/input/index.jsx +14 -0
  73. package/templates/template_admin_antd5/public/src/pages/antdComponents/loading/index.jsx +31 -0
  74. package/templates/template_admin_antd5/public/src/pages/antdComponents/message/index.jsx +102 -0
  75. package/templates/template_admin_antd5/public/src/pages/antdComponents/message/index.module.less +17 -0
  76. package/templates/template_admin_antd5/public/src/pages/antdComponents/radio/index.jsx +26 -0
  77. package/templates/template_admin_antd5/public/src/pages/antdComponents/select/index.jsx +13 -0
  78. package/templates/template_admin_antd5/public/src/pages/antdComponents/switch/index.jsx +12 -0
  79. package/templates/template_admin_antd5/public/src/pages/antdComponents/tableWithPage/index.jsx +70 -0
  80. package/templates/template_admin_antd5/public/src/pages/antdComponents/text/index.jsx +21 -0
  81. package/templates/template_admin_antd5/public/src/pages/auth/user/dialog/index.jsx +48 -75
  82. package/templates/template_admin_antd5/public/src/pages/auth/user/index.jsx +17 -23
  83. package/templates/template_admin_antd5/public/src/pages/lazyLoad/index.jsx +11 -0
  84. package/templates/template_admin_antd5/public/src/pages/login/index.jsx +8 -3
  85. package/templates/template_admin_antd5/public/src/pages/login/index.module.less +18 -10
  86. package/templates/template_admin_antd5/public/src/provider/menu.jsx +5 -0
  87. package/templates/template_admin_antd5/public/src/route.jsx +14 -9
  88. package/templates/template_admin_antd5/public/src/services/demo.js +38 -2
  89. package/templates/template_admin_antd5/public/src/services/interceptor/index.js +30 -3
  90. package/templates/template_admin_antd5/public/src/types/global.d.js +306 -0
  91. package/templates/template_admin_antd5/public/src/utils/format.js +1 -1
  92. package/templates/template_admin_antd5/public/src/utils/index.js +3 -3
  93. package/templates/template_admin_antd5/public/src/utils/moment.js +15 -0
  94. package/templates/template_admin_antd5/public/static/version.json +3 -0
  95. package/templates/template_admin_antd5/public/src/components/_table/column.jsx +0 -47
  96. package/templates/template_admin_antd5/public/src/components/_table/column.module.less +0 -12
  97. package/templates/template_admin_antd5/public/src/components/_table/index.jsx +0 -71
  98. package/templates/template_admin_antd5/public/src/components/_table/index.module.less +0 -15
  99. package/templates/template_admin_antd5/public/src/components/badge/index.jsx +0 -47
  100. package/templates/template_admin_antd5/public/src/components/badge/index.module.less +0 -44
  101. package/templates/template_admin_antd5/public/src/components/page/pageLoading/index.jsx +0 -51
  102. package/templates/template_admin_antd5/public/src/components/page/pageLoading/index.module.less +0 -29
  103. package/templates/template_admin_antd5/public/src/components/table/aliTable/index.jsx +0 -250
  104. package/templates/template_admin_antd5/public/src/components/table/aliTable/index.module.less +0 -105
  105. package/templates/template_admin_antd5/public/src/components/toast/index.jsx +0 -79
  106. package/templates/template_admin_antd5/public/src/components/toast/index.module.less +0 -43
  107. package/templates/template_admin_antd5/public/src/provider/loading.jsx +0 -47
  108. package/templates/template_admin_antd5/public/src/provider/menu.module.less +0 -35
  109. package/templates/template_admin_antd5/public/src/type.js +0 -67
  110. package/templates/template_admin_antd5/renamejstojsx.js +0 -45
  111. package/templates/template_admin_antd5/renameless.js +0 -53
  112. /package/templates/template_admin_antd5/public/src/components/{button → antd/button}/index.jsx +0 -0
  113. /package/templates/template_admin_antd5/public/src/components/resizeBox/{index.module.css → index.module.less} +0 -0
@@ -0,0 +1,264 @@
1
+ import React from 'react';
2
+ import { Drawer, Button, Space } from '@/components/antd';
3
+ import Antd5Provider from '@/components/antd/antProvider';
4
+ import {ReactRender} from '@/components/react';
5
+
6
+ /**
7
+ * @typedef {Object} ShowDrawerConfig
8
+ * @property {React.ReactNode} content - Drawer 内容(必填)
9
+ * @property {string} [title] - 标题
10
+ * @property {number} [width] - 宽度(默认 480)
11
+ * @property {string} [placement] - 弹出方向:'left' | 'right' | 'top' | 'bottom'(默认 'right')
12
+ * @property {Function} [onOk] - 确定回调,返回 Promise 可以控制关闭
13
+ * @property {Function} [onCancel] - 取消回调
14
+ * @property {boolean} [maskClosable] - 点击遮罩是否关闭(默认 true)
15
+ * @property {boolean} [closable] - 是否显示关闭按钮(默认 true)
16
+ * @property {string} [okText] - 确定按钮文字
17
+ * @property {string} [cancelText] - 取消按钮文字
18
+ * @property {boolean} [footer] - 底部区域,设为 false 隐藏底部
19
+ * @property {Object} [drawerProps] - 其他 antd Drawer 属性
20
+ */
21
+
22
+ /**
23
+ * 创建一个命令式调用的 Drawer(推荐方式)
24
+ * 优点:
25
+ * - 自动继承主题配置
26
+ * - 代码更简洁
27
+ * - 符合 antd 5 最佳实践
28
+ * @param {ShowDrawerConfig} config - Drawer 配置
29
+ * @returns {Promise<boolean>} 返回 Promise,resolve(true) 表示确定,resolve(false) 表示取消
30
+ * @example
31
+ * // 基础用法
32
+ * const result = await showDrawer({
33
+ * title: '编辑用户',
34
+ * content: <MyForm />,
35
+ * width: 600,
36
+ * });
37
+ *
38
+ * // 带表单验证
39
+ * const result = await showDrawer({
40
+ * title: '编辑用户',
41
+ * content: <MyForm ref={formRef} />,
42
+ * onOk: async () => {
43
+ * await formRef.current.validateFields();
44
+ * await saveData();
45
+ * }
46
+ * });
47
+ */
48
+ export const showDrawer = (config) => {
49
+ return new Promise((resolve) => {
50
+ let root;
51
+ // 清理函数
52
+ const cleanup = () => {
53
+ setTimeout(() => {
54
+ root.unmount();
55
+ if (container.parentNode) {
56
+ container.parentNode.removeChild(container);
57
+ }
58
+ }, 300); // 等待动画结束
59
+ };
60
+
61
+ // 渲染 Drawer
62
+ const DrawerWrapper = () => {
63
+ const [open, setOpen] = React.useState(true);
64
+ const [confirmLoading, setConfirmLoading] = React.useState(false);
65
+
66
+ const handleOk = async () => {
67
+ try {
68
+ if (config.onOk) {
69
+ setConfirmLoading(true);
70
+ await config.onOk();
71
+ setConfirmLoading(false);
72
+ }
73
+ setOpen(false);
74
+ cleanup();
75
+ resolve(true);
76
+ } catch (error) {
77
+ setConfirmLoading(false);
78
+ // 如果 onOk 抛出错误,不关闭 Drawer
79
+ console.error('Drawer onOk error:', error);
80
+ }
81
+ };
82
+
83
+ const handleCancel = () => {
84
+ if (config.onCancel) {
85
+ config.onCancel();
86
+ }
87
+ setOpen(false);
88
+ cleanup();
89
+ resolve(false);
90
+ };
91
+
92
+ const handleClose = () => {
93
+ handleCancel();
94
+ };
95
+
96
+ const renderFooter = () => {
97
+ // 如果明确设置 footer 为 false,则不显示底部
98
+ if (config.footer === false) {
99
+ return null;
100
+ }
101
+
102
+ return (
103
+ <Space style={{ display: 'flex', justifyContent: 'flex-end' }}>
104
+ <Button onClick={handleCancel}>
105
+ {config.cancelText || '取消'}
106
+ </Button>
107
+ <Button type="primary" loading={confirmLoading} onClick={handleOk}>
108
+ {config.okText || '确定'}
109
+ </Button>
110
+ </Space>
111
+ );
112
+ };
113
+
114
+ return (
115
+ <Antd5Provider>
116
+ <Drawer
117
+ title={config.title}
118
+ open={open}
119
+ onClose={handleClose}
120
+ width={config.width || 480}
121
+ placement={config.placement || 'right'}
122
+ maskClosable={config.maskClosable !== undefined ? config.maskClosable : true}
123
+ closable={config.closable !== undefined ? config.closable : true}
124
+ footer={renderFooter()}
125
+ bodyStyle={{ paddingBottom: '16px' }}
126
+ {...config.drawerProps}
127
+ >
128
+ {config.content}
129
+ </Drawer>
130
+ </Antd5Provider>
131
+ );
132
+ };
133
+ // 创建容器
134
+ const container = document.createElement('div');
135
+ document.body.appendChild(container);
136
+ root = ReactRender(<DrawerWrapper />,container)
137
+ });
138
+ };
139
+
140
+ /**
141
+ * 使用 App.useApp() 的 Drawer(在组件内使用)
142
+ * 优点:
143
+ * - 自动继承主题
144
+ * - 更轻量
145
+ * - 不需要手动管理 DOM
146
+ *
147
+ * 注意:此 Hook 返回一个配置对象,需要在组件中配合 useState 使用
148
+ * @example
149
+ * function MyComponent() {
150
+ * const { DrawerComponent, openDrawer } = useDrawerHelper();
151
+ * const [form] = Form.useForm();
152
+ *
153
+ * const handleEdit = async () => {
154
+ * openDrawer({
155
+ * title: '编辑',
156
+ * content: <MyForm />,
157
+ * onOk: async () => {
158
+ * const values = await form.validateFields();
159
+ * await saveData(values);
160
+ * }
161
+ * });
162
+ * };
163
+ *
164
+ * return (
165
+ * <>
166
+ * <button onClick={handleEdit}>编辑</button>
167
+ * <DrawerComponent />
168
+ * </>
169
+ * );
170
+ * }
171
+ */
172
+ export const useDrawerHelper = () => {
173
+ const [drawerConfig, setDrawerConfig] = React.useState(null);
174
+ const [open, setOpen] = React.useState(false);
175
+ const [confirmLoading, setConfirmLoading] = React.useState(false);
176
+ const pendingPromise = React.useRef(null);
177
+
178
+ const handleOk = async () => {
179
+ if (!drawerConfig) return;
180
+ try {
181
+ if (drawerConfig.onOk) {
182
+ setConfirmLoading(true);
183
+ await drawerConfig.onOk();
184
+ setConfirmLoading(false);
185
+ }
186
+ setOpen(false);
187
+ setDrawerConfig(null);
188
+ if (pendingPromise.current) {
189
+ pendingPromise.current.resolve(true);
190
+ pendingPromise.current = null;
191
+ }
192
+ } catch (error) {
193
+ setConfirmLoading(false);
194
+ console.error('Drawer onOk error:', error);
195
+ }
196
+ };
197
+
198
+ const handleCancel = () => {
199
+ if (drawerConfig?.onCancel) {
200
+ drawerConfig.onCancel();
201
+ }
202
+ setOpen(false);
203
+ setDrawerConfig(null);
204
+ if (pendingPromise.current) {
205
+ pendingPromise.current.resolve(false);
206
+ pendingPromise.current = null;
207
+ }
208
+ };
209
+
210
+ const handleClose = () => {
211
+ handleCancel();
212
+ };
213
+
214
+ const renderFooter = () => {
215
+ if (!drawerConfig) return null;
216
+ if (drawerConfig.footer === false) {
217
+ return null;
218
+ }
219
+
220
+ return (
221
+ <Space style={{ display: 'flex', justifyContent: 'flex-end' }}>
222
+ <Button onClick={handleCancel}>
223
+ {drawerConfig?.cancelText || '取消'}
224
+ </Button>
225
+ <Button type="primary" loading={confirmLoading} onClick={handleOk}>
226
+ {drawerConfig?.okText || '确定'}
227
+ </Button>
228
+ </Space>
229
+ );
230
+ };
231
+
232
+ const openDrawer = (config) => {
233
+ return new Promise((resolve) => {
234
+ pendingPromise.current = { resolve };
235
+ setDrawerConfig(config);
236
+ setOpen(true);
237
+ });
238
+ };
239
+
240
+ const DrawerComponent = () => {
241
+ if (!drawerConfig) return null;
242
+
243
+ return (
244
+ <Drawer
245
+ title={drawerConfig.title}
246
+ open={open}
247
+ onClose={handleClose}
248
+ width={drawerConfig.width || 480}
249
+ placement={drawerConfig.placement || 'right'}
250
+ maskClosable={drawerConfig.maskClosable !== undefined ? drawerConfig.maskClosable : true}
251
+ closable={drawerConfig.closable !== undefined ? drawerConfig.closable : true}
252
+ footer={renderFooter()}
253
+ bodyStyle={{ paddingBottom: '16px' }}
254
+ {...drawerConfig.drawerProps}
255
+ >
256
+ {drawerConfig.content}
257
+ </Drawer>
258
+ );
259
+ };
260
+
261
+ return { openDrawer, DrawerComponent };
262
+ };
263
+
264
+ export default showDrawer;
@@ -14,6 +14,7 @@ import {
14
14
  Checkbox,
15
15
  Col,
16
16
  ConfigProvider,
17
+ App,
17
18
  Drawer,
18
19
  Dropdown,
19
20
  Empty,
@@ -33,7 +34,7 @@ import {
33
34
  Row,
34
35
  Select as AntdSelect,
35
36
  Space,
36
- Spin,
37
+ Spin as AntdSpin,
37
38
  Steps,
38
39
  Switch,
39
40
  Table,
@@ -50,8 +51,22 @@ import {
50
51
  import Select from './select';
51
52
  export {Select};
52
53
 
54
+ import showModal,{useModalHelper} from './modal';
55
+ export {showModal,useModalHelper};
56
+ export {Modal}
57
+
58
+
59
+ import showDrawer,{useDrawerHelper} from './drawer';
60
+ export {showDrawer,useDrawerHelper};
61
+ export {Drawer}
62
+
63
+ import Spin, { showLoading } from './spin';
64
+ export { Spin, showLoading };
65
+ export {AntdSpin}
66
+
67
+
53
68
  import Tooltip from './tooltip';
54
- import AsyncButton from '../button';
69
+ import AsyncButton from './button';
55
70
 
56
71
  export {AntdSelect}
57
72
  export { AsyncButton as Button };
@@ -62,11 +77,11 @@ export {Card}
62
77
  export {Checkbox}
63
78
  export {Col}
64
79
  export {ConfigProvider}
80
+ export {App}
65
81
 
66
82
  /**@type {*} */
67
83
  const DatePicker = _DatePicker;
68
84
  export {DatePicker}
69
- export {Drawer}
70
85
  export {Dropdown}
71
86
  export {Empty}
72
87
  export {Image}
@@ -75,7 +90,6 @@ export {Layout}
75
90
  export {List}
76
91
  export {Menu}
77
92
  export {message}
78
- export {Modal}
79
93
  export {notification}
80
94
  export {Pagination}
81
95
  export {Popconfirm}
@@ -84,7 +98,7 @@ export {Progress}
84
98
  export {Radio}
85
99
  export {Row}
86
100
  export {Space}
87
- export {Spin}
101
+
88
102
  export {Steps}
89
103
  export {Switch}
90
104
  export {Table}
@@ -95,8 +109,6 @@ export {Tooltip}
95
109
  export {TreeSelect}
96
110
  export {Upload}
97
111
  export {AutoComplete}
98
-
99
-
100
112
  export {AntdTooltip}
101
113
  export {AntdButton}
102
114
 
@@ -0,0 +1,26 @@
1
+
2
+
3
+
4
+ .antd5Theme {
5
+ position: relative;
6
+ width: 100%;
7
+ height: 100%;
8
+ overflow: hidden;
9
+
10
+ }
11
+
12
+ :global {
13
+ .ant5-btn{
14
+ }
15
+ .ant5-table-cell.ant5-table-cell-scrollbar{
16
+ padding-left: 0 !important;
17
+ padding-right: 0 !important;
18
+ }
19
+ // .ant-table-container {
20
+ // border-top: 0 !important;
21
+ // .ant-table-selection-extra{
22
+ // margin-left: 0;
23
+ // padding:0;
24
+ // }
25
+ // }
26
+ }
@@ -0,0 +1,324 @@
1
+ # Modal 组件使用指南
2
+
3
+ ## 概述
4
+
5
+ 提供了两种方式来创建 Modal:
6
+
7
+ 1. **showModal** - 函数式调用(推荐)
8
+ 2. **useModalHelper** - Hook 方式(在组件内使用)
9
+
10
+ 两种方式都自动继承 antd 5 的主题配置。
11
+
12
+ ---
13
+
14
+ ## 方式 1:showModal(推荐)
15
+
16
+ ### 特点
17
+ - ✅ 可以在任何地方调用(不限于组件内)
18
+ - ✅ 自动继承主题配置
19
+ - ✅ 支持异步操作
20
+ - ✅ 自动管理 loading 状态
21
+ - ✅ 错误时不关闭 Modal
22
+
23
+ ### 基础用法
24
+
25
+ ```jsx
26
+ import { showModal } from '@/components/modal';
27
+
28
+ // 简单的确认对话框
29
+ const result = await showModal({
30
+ title: '确认删除',
31
+ content: <div>确定要删除这条记录吗?</div>,
32
+ });
33
+
34
+ if (result) {
35
+ console.log('用户点击了确定');
36
+ } else {
37
+ console.log('用户点击了取消');
38
+ }
39
+ ```
40
+
41
+ ### 带表单的 Modal
42
+
43
+ ```jsx
44
+ import { showModal } from '@/components/modal';
45
+ import { Form, Input, message } from '@/components/antd';
46
+
47
+ const handleEdit = async (id) => {
48
+ let formRef = null;
49
+
50
+ const result = await showModal({
51
+ title: '编辑用户',
52
+ width: 600,
53
+ content: (
54
+ <Form ref={(ref) => (formRef = ref)}>
55
+ <Form.Item label="姓名" name="name" rules={[{ required: true }]}>
56
+ <Input />
57
+ </Form.Item>
58
+ </Form>
59
+ ),
60
+ onOk: async () => {
61
+ // 验证表单
62
+ const values = await formRef.validateFields();
63
+
64
+ // 提交数据
65
+ const res = await saveData(values);
66
+
67
+ if (res.code === 0) {
68
+ message.success('保存成功');
69
+ return; // 成功后关闭
70
+ } else {
71
+ throw new Error('保存失败'); // 抛出错误阻止关闭
72
+ }
73
+ },
74
+ });
75
+
76
+ return result;
77
+ };
78
+ ```
79
+
80
+ ### 完整配置项
81
+
82
+ ```jsx
83
+ showModal({
84
+ title: '标题', // Modal 标题
85
+ content: <YourComponent />, // Modal 内容(JSX)
86
+ width: 600, // 宽度(默认 520)
87
+ maskClosable: false, // 点击遮罩是否关闭(默认 false)
88
+ okText: '确定', // 确定按钮文字
89
+ cancelText: '取消', // 取消按钮文字
90
+ onOk: async () => { // 确定回调(支持异步)
91
+ // 返回 Promise 可以控制关闭
92
+ // 抛出错误会阻止关闭
93
+ },
94
+ onCancel: () => { // 取消回调
95
+ // 可选
96
+ },
97
+ modalProps: { // 其他 antd Modal 属性
98
+ footer: null,
99
+ // ...
100
+ }
101
+ });
102
+ ```
103
+
104
+ ---
105
+
106
+ ## 方式 2:useModalHelper(组件内使用)
107
+
108
+ ### 特点
109
+ - ✅ 使用 antd 5 的 App.useApp() hook
110
+ - ✅ 更轻量,不需要手动管理 DOM
111
+ - ✅ 自动继承主题
112
+ - ⚠️ 只能在组件内使用
113
+
114
+ ### 基础用法
115
+
116
+ ```jsx
117
+ import { useModalHelper } from '@/components/modal';
118
+ import { Form, Input } from '@/components/antd';
119
+
120
+ function MyComponent() {
121
+ const { showModalInApp } = useModalHelper();
122
+ const [form] = Form.useForm();
123
+
124
+ const handleEdit = async () => {
125
+ const result = await showModalInApp({
126
+ title: '编辑用户',
127
+ width: 600,
128
+ content: (
129
+ <Form form={form}>
130
+ <Form.Item label="姓名" name="name">
131
+ <Input />
132
+ </Form.Item>
133
+ </Form>
134
+ ),
135
+ onOk: async () => {
136
+ const values = await form.validateFields();
137
+ await saveData(values);
138
+ },
139
+ });
140
+
141
+ if (result) {
142
+ console.log('保存成功');
143
+ }
144
+ };
145
+
146
+ return <button onClick={handleEdit}>编辑</button>;
147
+ }
148
+ ```
149
+
150
+ ---
151
+
152
+ ## 对比:旧方式 vs 新方式
153
+
154
+ ### 旧方式(Popup + ReactRender)
155
+
156
+ ```jsx
157
+ // 需要创建单独的组件文件
158
+ const DialogEdit = (props) => {
159
+ const { destory, id } = props;
160
+ return (
161
+ <Modal open={true} onCancel={() => destory(false)}>
162
+ {/* ... */}
163
+ </Modal>
164
+ );
165
+ };
166
+
167
+ const ShowEdit = (props = {}) => {
168
+ return new Promise((resolve) => {
169
+ let popup = Popup(resolve);
170
+ ReactRender(
171
+ <DialogEdit destory={popup.destory} {...props} />,
172
+ popup.dom,
173
+ popup.root
174
+ );
175
+ });
176
+ };
177
+
178
+ // 使用
179
+ await ShowEdit({ id: 1 });
180
+ ```
181
+
182
+ **缺点:**
183
+ - 代码冗长
184
+ - 需要手动管理 destory
185
+ - 需要创建单独的组件
186
+ - 容易出错
187
+
188
+ ### 新方式(showModal)
189
+
190
+ ```jsx
191
+ // 直接调用,一行搞定
192
+ await showModal({
193
+ title: '编辑用户',
194
+ content: <MyForm />,
195
+ onOk: async () => { /* ... */ }
196
+ });
197
+ ```
198
+
199
+ **优点:**
200
+ - 代码简洁
201
+ - 自动管理生命周期
202
+ - 不需要单独的组件文件
203
+ - 更易维护
204
+
205
+ ---
206
+
207
+ ## 迁移指南
208
+
209
+ ### 从旧方式迁移到新方式
210
+
211
+ **旧代码:**
212
+ ```jsx
213
+ // dialog/index.jsx
214
+ const DialogEdit = (props) => {
215
+ const { destory, id } = props;
216
+ const [form] = Form.useForm();
217
+
218
+ return (
219
+ <Modal
220
+ open={true}
221
+ onOk={async () => {
222
+ const values = await form.validateFields();
223
+ await saveData(values);
224
+ destory(true);
225
+ }}
226
+ onCancel={() => destory(false)}
227
+ >
228
+ <Form form={form}>
229
+ {/* ... */}
230
+ </Form>
231
+ </Modal>
232
+ );
233
+ };
234
+
235
+ export default (props) => {
236
+ return new Promise((resolve) => {
237
+ let popup = Popup(resolve);
238
+ ReactRender(<DialogEdit destory={popup.destory} {...props} />, popup.dom, popup.root);
239
+ });
240
+ };
241
+ ```
242
+
243
+ **新代码:**
244
+ ```jsx
245
+ // dialog/index.jsx
246
+ import { showModal } from '@/components/modal';
247
+
248
+ export default async (id) => {
249
+ let formRef = null;
250
+
251
+ return showModal({
252
+ title: '编辑用户',
253
+ content: (
254
+ <Form ref={(ref) => (formRef = ref)}>
255
+ {/* ... */}
256
+ </Form>
257
+ ),
258
+ onOk: async () => {
259
+ const values = await formRef.validateFields();
260
+ await saveData(values);
261
+ },
262
+ });
263
+ };
264
+ ```
265
+
266
+ ---
267
+
268
+ ## 常见问题
269
+
270
+ ### Q1: 如何在 onOk 中阻止 Modal 关闭?
271
+
272
+ **A:** 抛出错误即可:
273
+
274
+ ```jsx
275
+ onOk: async () => {
276
+ const values = await form.validateFields();
277
+ const res = await saveData(values);
278
+
279
+ if (res.code !== 0) {
280
+ throw new Error('保存失败'); // 抛出错误,Modal 不会关闭
281
+ }
282
+ }
283
+ ```
284
+
285
+ ### Q2: 如何访问表单实例?
286
+
287
+ **A:** 使用 ref:
288
+
289
+ ```jsx
290
+ let formRef = null;
291
+
292
+ showModal({
293
+ content: <Form ref={(ref) => (formRef = ref)}>{/* ... */}</Form>,
294
+ onOk: async () => {
295
+ const values = await formRef.validateFields();
296
+ }
297
+ });
298
+ ```
299
+
300
+ ### Q3: 旧的 Popup 方式还能用吗?
301
+
302
+ **A:** 可以,已经修复了兼容性问题。但推荐使用新方式,代码更简洁。
303
+
304
+ ### Q4: 新方式支持自定义 footer 吗?
305
+
306
+ **A:** 支持,通过 modalProps 传递:
307
+
308
+ ```jsx
309
+ showModal({
310
+ title: '标题',
311
+ content: <div>内容</div>,
312
+ modalProps: {
313
+ footer: <CustomFooter />
314
+ }
315
+ });
316
+ ```
317
+
318
+ ---
319
+
320
+ ## 总结
321
+
322
+ - **推荐使用 showModal**:代码简洁,功能完整
323
+ - **旧方式保留**:已修复兼容性,可以继续使用
324
+ - **逐步迁移**:新功能用新方式,旧代码可以保持不变