imean-service-engine-htmx-plugin 1.2.0 → 2.0.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/dist/index.d.ts CHANGED
@@ -1,175 +1,200 @@
1
1
  import { Context } from 'hono';
2
2
  import { z } from 'zod';
3
- import { Plugin, PluginPriority, PluginModuleOptionsSchema, Microservice, ModuleMetadata } from 'imean-service-engine';
3
+ import { Plugin, PluginPriority, Microservice } from 'imean-service-engine';
4
4
  import * as hono_jsx_jsx_dev_runtime from 'hono/jsx/jsx-dev-runtime';
5
5
 
6
6
  /**
7
- * HtmxAdminPlugin 类型定义
7
+ * HtmxAdminPlugin 核心类型定义
8
8
  */
9
9
 
10
10
  /**
11
- * 导航项配置
11
+ * 操作按钮配置
12
12
  */
13
- interface NavItemConfig {
14
- /** 导航标签 */
13
+ interface ActionButton {
14
+ /** 按钮文本 */
15
15
  label: string;
16
- /** 导航图标 */
17
- icon?: string;
18
- /** 自定义路径 */
19
- href: string;
20
- /** 嵌套子路由 */
21
- children?: NavItemConfig[];
22
- }
23
- /**
24
- * 用户信息接口
25
- */
26
- interface UserInfo {
27
- name?: string;
28
- avatar?: string;
29
- email?: string;
30
- /** 用户权限列表(支持通配符,如 "users.*", "users.read", "deny:users.delete") */
31
- permissions?: string[];
32
- [key: string]: any;
33
- }
34
- /**
35
- * 权限校验结果
36
- */
37
- interface PermissionResult {
38
- /** 是否允许访问 */
39
- allowed: boolean;
40
- /** 如果拒绝访问,可选的错误消息 */
41
- message?: string;
42
- /** 如果拒绝访问,可选的重定向URL */
43
- redirectUrl?: string;
44
- /** 被拒绝的操作ID(用于显示详细信息) */
45
- operationId?: string;
46
- }
47
- /**
48
- * 认证提供者接口
49
- */
50
- interface AuthProvider {
51
- /** Cookie 中存储 token 的 key(默认 "auth_token") */
52
- cookieKey?: string;
53
- /** 登录页面 URL(当用户未登录且需要权限时重定向到此页面) */
54
- loginUrl?: string;
55
- /** 退出登录页面 URL(用于退出登录功能) */
56
- logoutUrl?: string;
57
- /** 将 token 转换为用户信息 */
58
- tokenToUser: (token: string, ctx: Context) => UserInfo | null | Promise<UserInfo | null>;
59
- /** 权限校验钩子(可选,如果不提供则使用默认实现) */
60
- checkPermission?: (user: UserInfo | null, operation: string, context: any) => PermissionResult | Promise<PermissionResult>;
16
+ /** 链接地址(页面模式使用) */
17
+ href?: string;
18
+ /** HTTP 方法 */
19
+ method?: "get" | "post" | "put" | "delete";
20
+ /** 按钮样式 */
21
+ variant?: "primary" | "secondary" | "danger" | "ghost";
22
+ /** HTMX GET 请求(弹窗模式使用) */
23
+ hxGet?: string;
24
+ /** HTMX POST 请求 */
25
+ hxPost?: string;
26
+ /** HTMX PUT 请求 */
27
+ hxPut?: string;
28
+ /** HTMX DELETE 请求 */
29
+ hxDelete?: string;
30
+ /** 确认提示 */
31
+ confirm?: string;
32
+ /** 是否关闭弹窗(设置为 true 时,点击按钮会自动关闭弹窗,无需写 Hyperscript 代码) */
33
+ close?: boolean;
34
+ /** 是否提交表单(设置为 true 时,按钮会提交指定的表单,需要配合 formId 使用) */
35
+ submit?: boolean;
36
+ /** 表单 ID(当 submit 为 true 时,指定要提交的表单 ID) */
37
+ formId?: string;
38
+ /** 自定义点击事件(如关闭弹窗,当 close 为 true 时此属性会被忽略) */
39
+ onClick?: string;
40
+ /** 自定义类名 */
41
+ className?: string;
61
42
  }
62
43
  /**
63
- * 操作类型
64
- */
65
- type OperationType = "read" | "create" | "edit" | "delete";
66
- /**
67
- * 操作信息
44
+ * 对话框大小类型
68
45
  */
69
- interface OperationInfo {
70
- /** 操作ID(格式:moduleName.operation) */
71
- operationId: string;
72
- /** 模块名 */
73
- moduleName: string;
74
- /** 操作类型 */
75
- operationType: OperationType;
76
- /** 模块类型 */
77
- moduleType: ModuleType;
78
- /** 模块标题 */
79
- moduleTitle?: string;
80
- /** 模块描述 */
81
- moduleDescription?: string;
82
- /** HTTP 方法 */
83
- httpMethod: string;
84
- /** 路由路径 */
85
- routePath: string;
86
- }
46
+ type DialogSize = "sm" | "md" | "lg" | "xl" | "full";
87
47
  /**
88
- * 模块类型信息
48
+ * 页面元数据配置
89
49
  */
90
- interface ModuleTypeInfo {
91
- /** 模块标题 */
50
+ interface PageMetadata {
51
+ /** 页面标题(必需) */
92
52
  title: string;
93
- /** 模块描述 */
94
- description: string;
95
- /** 模块基础路径 */
96
- basePath: string;
97
- /** 是否有 list 类型的模块 */
98
- hasList: boolean;
99
- /** 是否有 detail 类型的模块 */
100
- hasDetail: boolean;
101
- /** 是否有 form 类型的模块 */
102
- hasForm: boolean;
103
- /** 是否有 custom 类型的模块 */
104
- hasCustom: boolean;
53
+ /** 页面描述(可选) */
54
+ description?: string;
55
+ /** 是否使用管理后台布局(默认 true) */
56
+ useAdminLayout?: boolean;
105
57
  }
106
58
  /**
107
- * 面包屑项
59
+ * 字段元数据
108
60
  */
109
- interface BreadcrumbItem {
110
- label: string;
111
- href?: string;
61
+ interface FieldMetadata {
62
+ /** 字段标签(中文名称) */
63
+ label?: string;
64
+ /** 字段描述 */
65
+ description?: string;
66
+ /** 字段占位符 */
67
+ placeholder?: string;
68
+ /** 字段类型(覆盖自动推断) */
69
+ type?: "text" | "textarea" | "select" | "date" | "number" | "email" | "url";
70
+ /** 选项(用于 select 类型) */
71
+ options?: Array<{
72
+ value: string | number;
73
+ label: string;
74
+ }>;
75
+ /** 是否在列表中显示 */
76
+ showInList?: boolean;
77
+ /** 是否在详情中显示 */
78
+ showInDetail?: boolean;
79
+ /** 是否在表单中显示 */
80
+ showInForm?: boolean;
81
+ /** 是否可搜索 */
82
+ searchable?: boolean;
83
+ /** 是否可排序 */
84
+ sortable?: boolean;
85
+ /** 自定义渲染函数 */
86
+ render?: (value: any, item: any) => any;
112
87
  }
113
88
  /**
114
- * 站点配置选项
89
+ * Model Schema 接口
90
+ * 类型通过 schema 的 z.infer 推断,无需显式传递泛型
115
91
  */
116
- interface HtmxAdminPluginOptions {
117
- /** 站点标题 */
118
- title?: string;
119
- /** 站点 Logo URL(可选) */
120
- logo?: string;
121
- /** 管理后台路径前缀(默认 /admin) */
122
- prefix?: string;
123
- /** 首页路径(访问插件默认路径时重定向到此路径,如果未配置则使用第一个模块的路径) */
124
- homePath?: string;
125
- /** 导航配置(集中式声明导航结构,支持嵌套) */
126
- navigation?: NavItemConfig[];
127
- /** 认证提供者(用于鉴权和权限控制) */
128
- authProvider?: AuthProvider;
92
+ interface ModelSchema {
93
+ /** Zod Schema(用于数据验证和类型推断) */
94
+ schema: z.ZodObject<any>;
95
+ /** 字段元数据(可选,用于自定义字段标签、描述等) */
96
+ fields?: Record<string, FieldMetadata>;
97
+ /** 列表显示字段(可选,用于列表页显示哪些字段) */
98
+ listFields?: string[];
99
+ /** 详情显示字段(可选,用于详情页显示哪些字段) */
100
+ detailFields?: string[];
101
+ /** 表单字段(可选,用于表单页显示哪些字段,默认排除 id、createdAt、updatedAt) */
102
+ formFields?: string[];
129
103
  }
130
104
  /**
131
- * 模块类型
105
+ * Feature 类型
132
106
  */
133
- type ModuleType = "list" | "detail" | "form" | "custom";
107
+ type FeatureType = "list" | "detail" | "create" | "edit" | "delete" | "custom";
134
108
  /**
135
- * 模块配置选项
136
- * 通用配置放在这里,不同类型页面的差异配置通过类来实现
109
+ * 通知类型
137
110
  */
138
- interface HtmxAdminModuleOptions {
139
- type: ModuleType;
140
- title?: string;
141
- description?: string;
142
- /** 是否使用管理后台布局(默认 true,设置为 false 时不使用侧边栏和头部,只使用 BaseLayout) */
143
- useAdminLayout?: boolean;
144
- }
111
+ type NotificationType$1 = "error" | "warning" | "info" | "success";
145
112
  /**
146
- * 列表数据源接口(仅用于 list 类型)
113
+ * 通知接口
147
114
  */
148
- interface ListDatasource<T = any> {
149
- /** 获取列表数据 */
150
- getList(params: ListParams): Promise<ListResult<T>>;
151
- /** 删除数据(可选,如果不提供则列表页不显示删除操作) */
152
- deleteItem?(id: string | number): Promise<boolean>;
115
+ interface Notification {
116
+ type: NotificationType$1;
117
+ title: string;
118
+ message: string;
153
119
  }
154
120
  /**
155
- * 详情数据源接口(仅用于 detail 类型)
121
+ * Feature 上下文
122
+ * 类型通过 model.modelSchema.schema 的 z.infer 推断
156
123
  */
157
- interface DetailDatasource<T = any> {
158
- /** 获取单条数据 */
159
- getItem(id: string | number): Promise<T | null>;
160
- /** 删除数据(可选) */
161
- deleteItem?(id: string | number): Promise<boolean>;
124
+ interface FeatureContext {
125
+ /** PageModel 实例 */
126
+ model: any;
127
+ /** Hono Context */
128
+ ctx: Context;
129
+ /** 用户信息 */
130
+ user: UserInfo | null;
131
+ /** 路由参数(路径参数) */
132
+ params: Record<string, any>;
133
+ /** 查询参数 */
134
+ query: Record<string, any>;
135
+ /** 请求体数据(表单数据或 JSON) */
136
+ body: Record<string, any>;
137
+ /** 插件前缀路径 */
138
+ prefix?: string;
139
+ /** 当前数据项(用于 detail、edit) */
140
+ item?: any;
141
+ /** 数据列表(用于 list) */
142
+ items?: any[];
143
+ /** 通知队列 */
144
+ notifications: Notification[];
145
+ /** 发送通知 */
146
+ sendNotification(type: NotificationType$1, title: string, message: string): void;
147
+ /** 发送错误通知(便捷方法) */
148
+ sendError(title: string, message: string): void;
149
+ /** 发送警告通知(便捷方法) */
150
+ sendWarning(title: string, message: string): void;
151
+ /** 发送信息通知(便捷方法) */
152
+ sendInfo(title: string, message: string): void;
153
+ /** 发送成功通知(便捷方法) */
154
+ sendSuccess(title: string, message: string): void;
155
+ /** 是否是 HTMX 请求 */
156
+ isHtmxRequest: boolean;
157
+ /** 是否在对话框中打开 */
158
+ isDialog: boolean;
159
+ /** 重定向 URL */
160
+ redirectUrl?: string;
161
+ /** 设置重定向 URL */
162
+ redirect(url: string): void;
163
+ /** 是否需要刷新页面 */
164
+ refresh: boolean;
165
+ /** 设置需要刷新页面 */
166
+ setRefresh(refresh?: boolean): void;
162
167
  }
163
168
  /**
164
- * 表单数据源接口(仅用于 form 类型)
169
+ * Feature 接口
170
+ * 类型通过 context.model.modelSchema.schema 的 z.infer 推断
165
171
  */
166
- interface FormDatasource<T = any> {
167
- /** 获取单条数据(编辑时使用) */
168
- getItem?(id: string | number): Promise<T | null>;
169
- /** 更新数据 */
170
- updateItem?(id: string | number, data: Partial<T>): Promise<T | null>;
171
- /** 创建数据 */
172
- createItem?(data: Partial<T>): Promise<T>;
172
+ interface Feature {
173
+ /** Feature 名称 */
174
+ name: string;
175
+ /** Feature 类型 */
176
+ type: FeatureType;
177
+ /** 所需权限(格式:modelName.featureName 或自定义,null 表示开放访问) */
178
+ permission: string | null;
179
+ /** 弹窗大小(当 Feature 在弹窗中打开时使用,默认 "lg") */
180
+ dialogSize?: DialogSize;
181
+ /** 是否允许点击遮罩区域关闭弹窗(默认 true,设置为 false 时只能通过关闭按钮关闭) */
182
+ closeOnBackdropClick?: boolean;
183
+ /** 获取动态标题(可选,会覆盖 PageMetadata 的 title) */
184
+ getTitle?(context: FeatureContext): string | Promise<string>;
185
+ /** 获取动态描述(可选,会覆盖 PageMetadata 的 description) */
186
+ getDescription?(context: FeatureContext): string | Promise<string> | undefined | Promise<string | undefined>;
187
+ /** 获取操作按钮(可选,根据 isDialog 返回不同的按钮配置) */
188
+ getActions?(context: FeatureContext): ActionButton[] | Promise<ActionButton[]>;
189
+ /** 路由配置(必须实现) */
190
+ getRoutes(): Array<{
191
+ method: "get" | "post" | "put" | "delete";
192
+ path: string;
193
+ }>;
194
+ /** 处理请求 */
195
+ handle?(context: FeatureContext): any | Promise<any>;
196
+ /** 渲染页面 */
197
+ render?(context: FeatureContext): any | Promise<any>;
173
198
  }
174
199
  /**
175
200
  * 列表查询参数
@@ -201,942 +226,721 @@ interface ListResult<T> {
201
226
  /** 总页数 */
202
227
  totalPages: number;
203
228
  }
204
-
205
229
  /**
206
- * Action Helper - 简化操作按钮定义
230
+ * 用户信息接口
207
231
  */
232
+ interface UserInfo {
233
+ name?: string;
234
+ avatar?: string;
235
+ email?: string;
236
+ /** 用户权限列表(支持通配符,如 "users.*", "users.read", "deny:users.delete") */
237
+ permissions?: string[];
238
+ [key: string]: any;
239
+ }
208
240
  /**
209
- * Action Helper 类
210
- * 提供便捷的方法来定义操作按钮,隐藏路径规则的具体实现
241
+ * 权限校验结果
211
242
  */
212
- declare class PathHelper {
213
- private basePath;
214
- constructor(basePath: string);
215
- /**
216
- * 详情页动作
217
- * 生成路径: {basePath}/detail/{id}
218
- * @param label 按钮标签
219
- * @param dialog 是否在对话框中打开
220
- */
221
- detail(id: string | number, dialog?: boolean): string;
222
- /**
223
- * 编辑页动作
224
- * 生成路径: {basePath}/edit/{id}
225
- * @param dialog 是否在对话框中打开
226
- */
227
- edit(id: string | number, dialog?: boolean): string;
228
- /**
229
- * 删除动作
230
- * 生成路径: {basePath}/detail/{id},方法: DELETE
231
- */
232
- delete(id: string | number): string;
233
- /**
234
- * 新建页动作
235
- * 生成路径: {basePath}/new
236
- * @param label 按钮标签
237
- * @param dialog 是否在对话框中打开
238
- */
239
- create(dialog?: boolean): string;
240
- /**
241
- * 列表页动作
242
- * 生成路径: {basePath}/list
243
- */
244
- list(): string;
245
- base(): string;
243
+ interface PermissionResult {
244
+ /** 是否允许访问 */
245
+ allowed: boolean;
246
+ /** 如果拒绝访问,可选的错误消息 */
247
+ message?: string;
248
+ /** 如果拒绝访问,可选的重定向URL */
249
+ redirectUrl?: string;
250
+ /** 被拒绝的操作ID(用于显示详细信息) */
251
+ operationId?: string;
246
252
  }
247
-
248
253
  /**
249
- * HtmxAdmin 上下文对象
250
- * 封装请求处理过程中的状态和操作
254
+ * 认证提供者接口
251
255
  */
252
-
256
+ interface AuthProvider {
257
+ /** Cookie 中存储 token 的 key(默认 "auth_token") */
258
+ cookieKey?: string;
259
+ /** 登录页面 URL(当用户未登录且需要权限时重定向到此页面) */
260
+ loginUrl?: string;
261
+ /** 退出登录页面 URL(用于退出登录功能) */
262
+ logoutUrl?: string;
263
+ /** 将 token 转换为用户信息 */
264
+ tokenToUser: (token: string, ctx: Context) => UserInfo | null | Promise<UserInfo | null>;
265
+ /** 权限校验钩子(可选,如果不提供则使用默认实现) */
266
+ checkPermission?: (user: UserInfo | null, operation: string, context: any) => PermissionResult | Promise<PermissionResult>;
267
+ }
253
268
  /**
254
- * 通知类型
269
+ * 插件配置选项(用户输入,可选值)
255
270
  */
256
- type NotificationType = "error" | "warning" | "info" | "success";
271
+ interface HtmxAdminPluginOptions {
272
+ /** 站点标题 */
273
+ title?: string;
274
+ /** 站点 Logo URL(可选) */
275
+ logo?: string;
276
+ /** 管理后台路径前缀(默认 /admin) */
277
+ prefix?: string;
278
+ /** 首页路径(访问插件默认路径时重定向到此路径) */
279
+ homePath?: string;
280
+ /** 导航配置(集中式声明导航结构,支持嵌套) */
281
+ navigation?: NavItemConfig[];
282
+ /** 认证提供者(用于鉴权和权限控制) */
283
+ authProvider?: AuthProvider;
284
+ }
257
285
  /**
258
- * 通知项
286
+ * 导航项配置
259
287
  */
260
- interface Notification {
261
- type: NotificationType;
262
- title: string;
263
- message: string;
288
+ interface NavItemConfig {
289
+ /** 导航标签 */
290
+ label: string;
291
+ /** 导航图标 */
292
+ icon?: string;
293
+ /** 自定义路径 */
294
+ href: string;
295
+ /** 嵌套子路由 */
296
+ children?: NavItemConfig[];
264
297
  }
265
298
  /**
266
- * HtmxAdmin 上下文
267
- * 封装请求处理过程中的所有状态和操作
299
+ * 表单字段定义
268
300
  */
269
- declare class HtmxAdminContext {
270
- /** 模块元数据 */
271
- readonly moduleMetadata: ModuleTypeInfo;
272
- /** 插件选项 */
273
- readonly pluginOptions: Required<HtmxAdminPluginOptions>;
274
- /** 服务名(用于生成权限ID) */
275
- readonly serviceName: string;
276
- /** Hono Context */
277
- readonly ctx: Context;
278
- /** 之前的模块名 */
279
- readonly previousModuleName?: string;
280
- /** 是否是片段请求(HTMX 请求) */
281
- readonly isFragment: boolean;
282
- /** 是否是对话框请求 */
283
- readonly isDialog: boolean;
284
- /** 用户信息 */
285
- readonly userInfo: UserInfo | null;
286
- /** 通知队列 */
287
- readonly notifications: Notification[];
288
- /** 页面标题(用于 HX-Title 和页面展示) */
289
- title: string;
290
- /** 页面描述(用于SEO和页面展示) */
291
- description: string;
292
- /** 面包屑项 */
293
- breadcrumbs: BreadcrumbItem[];
294
- /** 主要内容 */
295
- content: any;
296
- /** 需要重定向的 URL */
297
- redirectUrl?: string;
298
- /** 是否需要刷新页面(用于 HX-Refresh) */
299
- refresh: boolean;
300
- constructor(ctx: Context, userInfo: UserInfo | null, moduleMetadata: ModuleTypeInfo, pluginOptions: Required<HtmxAdminPluginOptions>, serviceName?: string);
301
- /**
302
- * 发送通知
303
- * 通知将在响应时通过 OOB 更新到错误容器
304
- */
305
- sendNotification(type: NotificationType, title: string, message: string): void;
306
- /**
307
- * 发送错误通知(便捷方法)
308
- */
309
- sendError(title: string, message: string): void;
310
- /**
311
- * 发送警告通知(便捷方法)
301
+ interface FormField {
302
+ name: string;
303
+ label: string;
304
+ type?: "text" | "textarea" | "select" | "date" | "number" | "email" | "url" | "checkbox";
305
+ required?: boolean;
306
+ placeholder?: string;
307
+ description?: string;
308
+ options?: Array<{
309
+ value: string | number;
310
+ label: string;
311
+ }>;
312
+ }
313
+
314
+ /**
315
+ * Feature 注册表
316
+ * 类型通过 model.modelSchema.schema 的 z.infer 推断
317
+ */
318
+ declare class FeatureRegistry {
319
+ private features;
320
+ private model;
321
+ constructor(model: PageModel);
322
+ /**
323
+ * 注册 Feature
324
+ */
325
+ register(name: string, feature: Feature): void;
326
+ /**
327
+ * 快捷方法:注册列表 Feature
312
328
  */
313
- sendWarning(title: string, message: string): void;
329
+ list(feature: Feature): void;
314
330
  /**
315
- * 发送信息通知(便捷方法)
331
+ * 快捷方法:注册详情 Feature
316
332
  */
317
- sendInfo(title: string, message: string): void;
333
+ detail(feature: Feature): void;
318
334
  /**
319
- * 发送成功通知(便捷方法)
335
+ * 快捷方法:注册创建 Feature
320
336
  */
321
- sendSuccess(title: string, message: string): void;
337
+ create(feature: Feature): void;
322
338
  /**
323
- * 设置需要推送的 URL
324
- * 用于 HX-Push-Url 响应头
339
+ * 快捷方法:注册编辑 Feature
325
340
  */
326
- redirect(url: string): void;
341
+ edit(feature: Feature): void;
327
342
  /**
328
- * 设置需要刷新页面
329
- * 用于 HX-Refresh 响应头
343
+ * 快捷方法:注册删除 Feature
330
344
  */
331
- setRefresh(refresh?: boolean): void;
345
+ delete(feature: Feature): void;
332
346
  /**
333
- * 检查是否有列表页面
334
- * 封装 moduleMetadata 访问,避免直接访问内部属性
347
+ * 快捷方法:注册自定义 Feature
335
348
  */
336
- hasList(): boolean;
349
+ custom(name: string, feature: Feature): void;
337
350
  /**
338
- * 检查是否有详情页面
339
- * 封装 moduleMetadata 访问,避免直接访问内部属性
351
+ * 一键启用所有 CRUD Feature
352
+ * 类型通过 model.modelSchema.schema 的 z.infer 推断
340
353
  */
341
- hasDetail(): boolean;
354
+ crud<T extends {
355
+ id: string | number;
356
+ } = any>(options: {
357
+ /** 权限前缀 */
358
+ permissionPrefix: string;
359
+ /** 获取列表数据的函数 */
360
+ getList: (params: ListParams) => Promise<ListResult<T>>;
361
+ /** 获取单条数据的函数 */
362
+ getItem: (id: string | number) => Promise<T | null>;
363
+ /** 创建数据的函数 */
364
+ createItem: (data: Partial<T>) => Promise<T>;
365
+ /** 更新数据的函数 */
366
+ updateItem: (id: string | number, data: Partial<T>) => Promise<T | null>;
367
+ /** 删除数据的函数(可选) */
368
+ deleteItem?: (id: string | number) => Promise<boolean>;
369
+ /** 自定义权限(可选) */
370
+ permissions?: {
371
+ list?: string;
372
+ read?: string;
373
+ create?: string;
374
+ edit?: string;
375
+ delete?: string;
376
+ };
377
+ /** 是否启用某些 Feature(可选) */
378
+ features?: {
379
+ list?: boolean;
380
+ detail?: boolean;
381
+ create?: boolean;
382
+ edit?: boolean;
383
+ delete?: boolean;
384
+ };
385
+ /** 弹窗大小配置(可选) */
386
+ dialogSizes?: {
387
+ list?: DialogSize;
388
+ detail?: DialogSize;
389
+ create?: DialogSize;
390
+ edit?: DialogSize;
391
+ delete?: DialogSize;
392
+ };
393
+ /** 是否允许点击遮罩关闭配置(可选) */
394
+ closeOnBackdropClick?: {
395
+ list?: boolean;
396
+ detail?: boolean;
397
+ create?: boolean;
398
+ edit?: boolean;
399
+ delete?: boolean;
400
+ };
401
+ /** 动态标题配置(可选) */
402
+ getTitles?: {
403
+ detail?: (item: T, context: FeatureContext) => string | Promise<string>;
404
+ edit?: (item: T, context: FeatureContext) => string | Promise<string>;
405
+ create?: (context: FeatureContext) => string | Promise<string>;
406
+ };
407
+ /** 动态描述配置(可选) */
408
+ getDescriptions?: {
409
+ detail?: (item: T, context: FeatureContext) => string | Promise<string> | undefined;
410
+ edit?: (item: T, context: FeatureContext) => string | Promise<string> | undefined;
411
+ create?: (context: FeatureContext) => string | Promise<string> | undefined;
412
+ };
413
+ }): void;
342
414
  /**
343
- * 检查是否有表单页面
344
- * 封装 moduleMetadata 访问,避免直接访问内部属性
415
+ * 获取所有注册的 Feature
345
416
  */
346
- hasForm(): boolean;
417
+ getAll(): Feature[];
347
418
  /**
348
- * 检查是否有自定义页面
349
- * 封装 moduleMetadata 访问,避免直接访问内部属性
419
+ * 获取指定 Feature
350
420
  */
351
- hasCustom(): boolean;
421
+ get(name: string): Feature | undefined;
352
422
  }
353
423
 
354
424
  /**
355
- * Page 模块基类
356
- * 所有页面模块的基类,提供通用的属性和方法
425
+ * PageModel 基类
426
+ * 统一处理有数据模型和无数据模型的场景
357
427
  */
358
428
 
359
429
  /**
360
- * Page 页面模块基类
361
- * 所有页面模块都继承此类,包括 ListPageModule、DetailPageModule、FormPageModule
362
- *
363
- * 对于 custom 类型的模块,必须实现 render 方法
364
- * 对于其他类型的模块,可以重写 render 方法来自定义渲染,否则使用默认渲染逻辑
430
+ * PageModel 基类
431
+ * 类型通过 modelSchema.schema 的 z.infer 推断,无需显式传递泛型
365
432
  */
366
- declare abstract class PageModule {
367
- /** HtmxAdmin 上下文对象 */
368
- context: HtmxAdminContext;
369
- /** Action Helper 实例 */
370
- paths: PathHelper;
371
- /**
372
- * 初始化模块实例(私有方法,仅由 RouteHandler 调用)
373
- * 用于设置模块的基础属性
374
- */
375
- __init(context: HtmxAdminContext): void;
433
+ declare abstract class PageModel {
434
+ readonly modelName: string;
435
+ readonly features: FeatureRegistry;
436
+ protected modelSchema?: ModelSchema;
437
+ private metadata;
376
438
  /**
377
- * 获取页面标题
378
- * 子类可以重写此方法来返回页面标题
379
- * 默认实现:使用模块名
439
+ * 构造函数
440
+ * @param modelName 模型/页面名称(用于路由和权限)
441
+ * @param schema 模型 Schema(可选,不提供则为普通页面)
442
+ * @param metadata 页面元数据(可选,如果提供则不需要实现 getMetadata)
380
443
  */
381
- getTitle(): string;
444
+ constructor(modelName: string, schema?: ModelSchema, metadata?: PageMetadata);
382
445
  /**
383
- * 获取页面描述
384
- * 子类可以重写此方法来返回页面描述(用于SEO和页面展示)
385
- * 默认实现:返回空字符串
446
+ * 获取推断的类型(如果有 schema)
447
+ * 使用方式:type ModelType = z.infer<typeof pageModel.getSchema()!.schema>
386
448
  */
387
- getDescription(): string;
449
+ getInferredType(): z.ZodObject<any> | undefined;
388
450
  /**
389
- * 获取面包屑
390
- * 子类可以重写此方法来自定义面包屑
391
- * 默认实现:首页 => 自定义页面
451
+ * 获取页面元数据
452
+ * 如果构造函数提供了 metadata,直接返回
453
+ * 否则调用子类实现
392
454
  */
393
- getBreadcrumbs(): BreadcrumbItem[];
455
+ getMetadata(): PageMetadata;
394
456
  /**
395
- * 获取所需权限
396
- * 子类可以重写此方法来声明页面所需的权限
397
- *
398
- * 返回值说明:
399
- * - 返回空字符串 "" 或 null 或 undefined:表示开放访问(无需权限)
400
- * - 返回权限字符串:表示需要该权限,如 "users.read", "users.*"
401
- *
402
- * 默认实现:返回空字符串(开放访问)
403
- *
404
- * @param ctx Hono Context(可选,用于根据请求动态决定权限)
405
- * @returns 所需权限字符串,或空字符串/null/undefined 表示开放
457
+ * 判断是否有数据模型(有 Schema)
406
458
  */
407
- getRequiredPermission?(ctx?: any): string | null | undefined;
459
+ hasModel(): boolean;
408
460
  /**
409
- * 处理请求的统一入口(由 RouteHandler 调用)
410
- * 默认实现:直接调用 render 方法
411
- * 子类可以重写此方法来处理请求级别的逻辑(如根据 HTTP method 分发)
412
- *
413
- * @param adminContext HtmxAdmin 上下文对象(必需),包含请求状态和 helper 方法
414
- * @returns 页面内容
461
+ * 获取模型 Schema(可选)
415
462
  */
416
- __handle(): Promise<any>;
463
+ getSchema?(): ModelSchema | undefined;
417
464
  /**
418
- * 渲染页面内容
419
- *
420
- * 所有页面模块都必须提供 render 方法
421
- * - Custom 类型:必须实现此方法
422
- * - List/Detail/Form 类型:基类提供默认实现,可以重写来自定义渲染
423
- *
424
- * @param adminContext HtmxAdmin 上下文对象(必需),包含请求状态和 helper 方法
425
- * 可以通过 adminContext.ctx 访问 Hono Context
465
+ * 验证数据(仅用于有数据模型的场景)
426
466
  */
427
- abstract render(): any | Promise<any>;
428
- }
429
-
430
- /**
431
- * Detail 模块基类
432
- * 用于详情展示,继承自 PageModule
433
- */
434
-
435
- /**
436
- * Detail 页面模块基类
437
- * 继承自 PageModule,提供详情页面的默认行为
438
- *
439
- * 可以重写 render 方法来自定义渲染,否则使用默认的详情渲染逻辑
440
- */
441
- declare abstract class DetailPageModule<T = any> extends PageModule {
442
- /** ID 字段名(默认 "id") */
443
- protected readonly idField: string;
467
+ validate(data: unknown): {
468
+ success: true;
469
+ data: any;
470
+ } | {
471
+ success: false;
472
+ error: string;
473
+ };
444
474
  /**
445
- * 获取所需权限
446
- * 默认实现:返回 "{serviceName}.{moduleName}.read"
447
- * 子类可以重写此方法来自定义权限要求
448
- *
449
- * @param ctx Hono Context(可选)
450
- * @returns 所需权限字符串,或空字符串/null/undefined 表示开放
475
+ * 获取表单字段(仅用于有数据模型的场景)
451
476
  */
452
- getRequiredPermission(ctx?: any): string | null | undefined;
477
+ getFormFields(): FormField[];
453
478
  /**
454
- * 获取数据源(抽象方法,必须实现)
455
- * 子类必须实现此方法来提供数据源
479
+ * 创建表单字段
456
480
  */
457
- abstract getDatasource(): DetailDatasource<T>;
481
+ private createFormField;
458
482
  /**
459
- * 获取字段标签(可选)
460
- * 子类可以重写此方法来自定义字段的中文标签
483
+ * 从 Zod enum schema 中提取选项
461
484
  */
462
- getFieldLabel?(field: string): string;
485
+ private extractEnumOptions;
463
486
  /**
464
- * 渲染字段值(可选)
465
- * 子类可以重写此方法来自定义字段的渲染方式
487
+ * 判断字段是否为必填
466
488
  */
467
- renderField?(field: string, value: any, item: T): any;
489
+ private isRequiredField;
468
490
  /**
469
- * 获取字段分组(可选)
470
- * 子类可以重写此方法来定义字段分组
471
- * 返回 null 或 undefined 表示不分组,平铺显示
491
+ * 推断字段类型
472
492
  */
473
- getFieldGroups?(item: T): Array<{
474
- title: string;
475
- fields: string[];
476
- }> | null;
493
+ private inferFieldType;
477
494
  /**
478
- * 获取可见字段列表(可选)
479
- * 子类可以重写此方法来控制字段的显示顺序和可见性
480
- * 返回 null 或 undefined 表示显示所有字段
495
+ * 获取列表字段(仅用于有数据模型的场景)
481
496
  */
482
- getVisibleFields?(item: T): string[] | null;
497
+ getListFields(): string[];
483
498
  /**
484
- * 获取详情页操作按钮(可选)
485
- * 子类可以重写此方法来添加详情页的操作按钮
486
- * 如果不定义,则根据模块元数据智能生成默认操作按钮
499
+ * 获取详情字段(仅用于有数据模型的场景)
487
500
  */
488
- getDetailActions?(item: T): Array<{
489
- label: string;
490
- href: string | ((item: T) => string);
491
- method?: string;
492
- class?: string;
493
- }>;
501
+ getDetailFields(): string[];
494
502
  /**
495
- * 渲染详情页面(默认实现)
496
- * 子类可以重写此方法来自定义渲染
503
+ * 获取字段标签
497
504
  */
498
- render(): Promise<any>;
505
+ getFieldLabel(fieldName: string): string;
499
506
  }
500
507
 
501
508
  /**
502
- * Form 模块基类
503
- * 用于表单(新建/编辑),继承自 PageModule
509
+ * Feature 基类
510
+ * 提供所有 Feature 的公共属性和默认实现
504
511
  */
505
512
 
506
513
  /**
507
- * Form 页面模块基类
508
- * 继承自 PageModule,提供表单页面的默认行为
509
- *
510
- * 可以重写 render 方法来自定义渲染,否则使用默认的表单渲染逻辑
514
+ * Feature 基类
515
+ * 所有 Feature 都应该继承此类,而不是直接实现 Feature 接口
511
516
  */
512
- declare abstract class FormPageModule<T = any> extends PageModule {
513
- /** ID 字段名(默认 "id") */
514
- protected idField: string;
515
- /** Zod Schema(可选,如果提供则自动生成表单字段和校验) */
516
- protected schema?: z.ZodObject<any>;
517
- constructor(schema?: z.ZodObject<any>);
517
+ declare abstract class BaseFeature implements Feature {
518
+ /** Feature 名称 */
519
+ readonly name: string;
520
+ /** Feature 类型 */
521
+ readonly type: FeatureType;
522
+ /** 所需权限(格式:modelName.featureName 或自定义,null 表示开放访问) */
523
+ permission: string | null;
524
+ /** 弹窗大小(当 Feature 在弹窗中打开时使用,默认 "lg") */
525
+ dialogSize?: DialogSize;
526
+ /** 是否允许点击遮罩区域关闭弹窗(默认 true,设置为 false 时只能通过关闭按钮关闭) */
527
+ closeOnBackdropClick?: boolean;
528
+ constructor(options: {
529
+ name: string;
530
+ type: FeatureType;
531
+ permission: string | null;
532
+ dialogSize?: DialogSize;
533
+ closeOnBackdropClick?: boolean;
534
+ });
535
+ /**
536
+ * 获取动态标题(默认实现:返回 PageMetadata 的 title)
537
+ * 子类可以覆盖此方法以提供动态标题
538
+ */
539
+ getTitle(context: FeatureContext): Promise<string>;
540
+ /**
541
+ * 获取动态描述(默认实现:返回 PageMetadata 的 description)
542
+ * 子类可以覆盖此方法以提供动态描述
543
+ */
544
+ getDescription(context: FeatureContext): Promise<string | undefined>;
518
545
  /**
519
- * 获取所需权限
520
- * 根据是新建还是编辑返回不同的权限要求
521
- * - 新建:{serviceName}.{moduleName}.create
522
- * - 编辑:{serviceName}.{moduleName}.edit
523
- * 子类可以重写此方法来自定义权限要求
524
- *
525
- * @param ctx Hono Context(可选)
526
- * @returns 所需权限字符串,或空字符串/null/undefined 表示开放
546
+ * 获取操作按钮(默认实现:返回空数组)
547
+ * 子类可以覆盖此方法以提供操作按钮
527
548
  */
528
- getRequiredPermission(ctx?: any): string | null | undefined;
549
+ getActions(context: FeatureContext): Promise<ActionButton[]>;
529
550
  /**
530
- * 获取数据源(抽象方法,必须实现)
531
- * 子类必须实现此方法来提供数据源
551
+ * 获取路由配置(必须实现)
532
552
  */
533
- abstract getDatasource(): FormDatasource<T>;
553
+ abstract getRoutes(): Array<{
554
+ method: "get" | "post" | "put" | "delete";
555
+ path: string;
556
+ }>;
534
557
  /**
535
- * 获取单条数据(编辑时使用)
558
+ * 处理请求(可选,如果实现了 handle,则优先使用 handle)
536
559
  */
537
- getItem(id: string | number): Promise<T | null>;
560
+ handle?(context: FeatureContext): Promise<any>;
538
561
  /**
539
- * 获取字段标签(可选)
540
- * 子类可以重写此方法来自定义字段的中文标签
562
+ * 渲染页面(可选,如果 handle 不存在或返回 undefined,则使用 render)
541
563
  */
542
- getFieldLabel?(field: string): string;
564
+ render?(context: FeatureContext): Promise<any>;
565
+ }
566
+
567
+ /**
568
+ * 表单 Feature 基类
569
+ * 提供创建和编辑 Feature 的公共逻辑
570
+ */
571
+
572
+ /**
573
+ * 表单操作类型
574
+ */
575
+ type FormAction = "create" | "edit";
576
+ /**
577
+ * 表单 Feature 基类
578
+ * 用于创建和编辑 Feature 的共同逻辑
579
+ */
580
+ declare abstract class BaseFormFeature<T extends {
581
+ id: string | number;
582
+ } = any> extends BaseFeature {
583
+ protected titleGetter?: (context: FeatureContext, item?: T) => string | Promise<string>;
584
+ protected descriptionGetter?: (context: FeatureContext, item?: T) => string | Promise<string> | undefined;
585
+ /** 当前请求的表单 ID(用于在 render 和 getActions 之间共享) */
586
+ private currentFormId?;
543
587
  /**
544
- * 获取表单字段定义
545
- *
546
- * 如果提供了 schema,则自动从 schema 生成字段定义
547
- * 否则子类必须实现此方法来定义表单的字段
588
+ * 获取或生成表单 ID(确保在同一个请求中保持一致)
548
589
  */
549
- getFormFields(item: T | null): Array<{
590
+ private getFormId;
591
+ constructor(options: {
550
592
  name: string;
551
- label: string;
552
- type?: "text" | "email" | "number" | "textarea" | "select" | "date" | "datetime-local";
553
- required?: boolean;
554
- placeholder?: string;
555
- options?: Array<{
556
- value: string | number;
557
- label: string;
558
- }>;
559
- }>;
593
+ type: "create" | "edit";
594
+ permission: string;
595
+ dialogSize?: DialogSize;
596
+ closeOnBackdropClick?: boolean;
597
+ getTitle?: (context: FeatureContext, item?: T) => string | Promise<string>;
598
+ getDescription?: (context: FeatureContext, item?: T) => string | Promise<string> | undefined;
599
+ });
560
600
  /**
561
- * 获取字段标签映射(可选)
562
- * 用于覆盖从 schema description 提取的标签
601
+ * 获取表单操作类型
563
602
  */
564
- getFieldLabels?(): Record<string, string>;
603
+ abstract getFormAction(): FormAction;
565
604
  /**
566
- * 获取字段占位符映射(可选)
605
+ * 获取提交 URL
567
606
  */
568
- getFieldPlaceholders?(): Record<string, string>;
607
+ abstract getSubmitUrl(context: FeatureContext): string;
569
608
  /**
570
- * 获取字段选项映射(可选)
571
- * 用于覆盖从 schema enum 提取的选项
609
+ * 获取初始数据(用于编辑时加载现有数据)
572
610
  */
573
- getFieldOptions?(): Record<string, Array<{
574
- value: string | number;
575
- label: string;
576
- }>>;
611
+ abstract getInitialData(context: FeatureContext): Promise<Partial<T> | undefined>;
577
612
  /**
578
- * 获取字段类型映射(可选)
579
- * 用于覆盖自动推断的类型
613
+ * 处理表单提交
580
614
  */
581
- getFieldTypes?(): Record<string, "text" | "email" | "number" | "textarea" | "select" | "date" | "datetime-local">;
615
+ abstract handleSubmit(context: FeatureContext, validatedData: Partial<T>): Promise<T | null>;
582
616
  /**
583
- * 获取要排除的字段列表(可选)
617
+ * 获取成功后的重定向 URL
584
618
  */
585
- getExcludeFields?(): string[];
619
+ abstract getSuccessRedirectUrl(context: FeatureContext, item: T): string;
586
620
  /**
587
- * 验证表单数据
588
- *
589
- * 如果提供了 schema,则自动使用 schema 进行校验
590
- * 否则子类可以重写此方法来验证表单数据
621
+ * 获取取消按钮的跳转 URL
591
622
  */
592
- validateFormData(data: Record<string, any>, item: T | null): string | null;
623
+ abstract getCancelUrl(context: FeatureContext): string | undefined;
593
624
  /**
594
- * 处理请求的统一入口(重写基类方法)
595
- * 根据 HTTP method 处理不同请求:
596
- * - GET: 渲染表单页面(调用 render)
597
- * - POST: 创建数据
598
- * - PUT: 更新数据
599
- * - DELETE: 删除数据
600
- * 子类可以重写此方法来自定义请求处理逻辑
625
+ * 获取动态标题
601
626
  */
602
- __handle(): Promise<any>;
627
+ getTitle(context: FeatureContext): Promise<string>;
603
628
  /**
604
- * 渲染表单页面(默认实现)
605
- * 子类可以重写此方法来自定义渲染
606
- * @param formData 表单数据(用于回填验证失败时的值)
629
+ * 获取动态描述
607
630
  */
608
- render(formData?: Record<string, any>): Promise<any>;
631
+ getDescription(context: FeatureContext): Promise<string | undefined>;
609
632
  /**
610
- * 处理创建请求(POST)
633
+ * 预处理表单数据:根据 schema 类型转换数据
634
+ * 表单数据都是字符串,需要转换为正确的类型(数字、布尔等)
611
635
  */
612
- private handleCreate;
636
+ private preprocessFormData;
613
637
  /**
614
- * 处理更新请求(PUT)
638
+ * 处理请求
615
639
  */
616
- private handleUpdate;
640
+ handle(context: FeatureContext): Promise<any>;
617
641
  /**
618
- * 处理删除请求(DELETE)
619
- * 注意:FormDatasource 不包含 deleteItem,删除操作通常由 List 或 Detail 模块处理
620
- * 这里提供默认实现,子类可以重写
642
+ * 渲染表单页面
621
643
  */
622
- private handleDelete;
644
+ render(context: FeatureContext, initialData?: Partial<T>): Promise<any>;
623
645
  /**
624
- * 渲染表单页面(辅助方法)
625
- * 用于在验证失败时重新渲染表单页面
626
- * @param adminContext 上下文对象
627
- * @param item 原始数据项(编辑时)
628
- * @param isEdit 是否是编辑模式
629
- * @param formData 表单数据(用于回填验证失败时的值)
646
+ * 获取操作按钮
630
647
  */
631
- private renderFormPage;
648
+ getActions(context: FeatureContext): Promise<ActionButton[]>;
649
+ }
650
+
651
+ /**
652
+ * 自定义 Feature
653
+ * 用于处理不需要数据模型的业务逻辑
654
+ */
655
+
656
+ /**
657
+ * 自定义 Feature
658
+ */
659
+ declare class CustomFeature extends BaseFeature {
660
+ private routes;
661
+ private handlerFn?;
662
+ private renderFn?;
663
+ private titleGetter?;
664
+ private descriptionGetter?;
665
+ constructor(options: {
666
+ name: string;
667
+ routes: Array<{
668
+ method: "get" | "post" | "put" | "delete";
669
+ path: string;
670
+ }>;
671
+ handler?: (context: FeatureContext) => any | Promise<any>;
672
+ render?: (context: FeatureContext) => any | Promise<any>;
673
+ permission?: string | null;
674
+ dialogSize?: DialogSize;
675
+ closeOnBackdropClick?: boolean;
676
+ /** 获取动态标题(可选,会覆盖 PageMetadata 的 title) */
677
+ getTitle?: (context: FeatureContext) => string | Promise<string>;
678
+ /** 获取动态描述(可选,会覆盖 PageMetadata 的 description) */
679
+ getDescription?: (context: FeatureContext) => string | Promise<string> | undefined | Promise<string | undefined>;
680
+ });
681
+ getTitle(context: FeatureContext): Promise<string>;
682
+ getDescription(context: FeatureContext): Promise<string | undefined>;
683
+ getRoutes(): {
684
+ method: "get" | "post" | "put" | "delete";
685
+ path: string;
686
+ }[];
687
+ handle(context: FeatureContext): Promise<any>;
688
+ render(context: FeatureContext): Promise<any>;
632
689
  }
633
690
 
634
691
  /**
635
- * List 模块基类
636
- * 用于列表展示,继承自 PageModule
692
+ * 默认创建 Feature
637
693
  */
638
694
 
639
695
  /**
640
- * List 页面模块基类
641
- * 继承自 PageModule,提供列表页面的默认行为
642
- *
643
- * 可以重写 render 方法来自定义渲染,否则使用默认的列表渲染逻辑
696
+ * 默认创建 Feature
697
+ * 类型通过 context.model.modelSchema.schema 的 z.infer 推断
644
698
  */
645
- declare abstract class ListPageModule<T extends {
699
+ declare class DefaultCreateFeature<T extends {
646
700
  id: string | number;
647
- } = {
701
+ } = any> extends BaseFormFeature<T> {
702
+ private createItem;
703
+ constructor(options: {
704
+ createItem: (data: Partial<T>) => Promise<T>;
705
+ permissionPrefix: string;
706
+ permission?: string;
707
+ dialogSize?: DialogSize;
708
+ closeOnBackdropClick?: boolean;
709
+ /** 获取动态标题(可选,接收 context,返回标题字符串,如 "新建文章") */
710
+ getTitle?: (context: FeatureContext) => string | Promise<string>;
711
+ /** 获取动态描述(可选,接收 context,返回描述字符串) */
712
+ getDescription?: (context: FeatureContext) => string | Promise<string> | undefined;
713
+ });
714
+ getFormAction(): "create";
715
+ getRoutes(): ({
716
+ method: "get";
717
+ path: string;
718
+ } | {
719
+ method: "post";
720
+ path: string;
721
+ })[];
722
+ getSubmitUrl(context: FeatureContext): string;
723
+ getInitialData(context: FeatureContext): Promise<Partial<T> | undefined>;
724
+ handleSubmit(context: FeatureContext, validatedData: Partial<T>): Promise<T | null>;
725
+ getSuccessRedirectUrl(context: FeatureContext, item: T): string;
726
+ getCancelUrl(context: FeatureContext): string | undefined;
727
+ }
728
+
729
+ /**
730
+ * 默认删除 Feature
731
+ */
732
+
733
+ /**
734
+ * 默认删除 Feature
735
+ * 类型通过 context.model.modelSchema.schema 的 z.infer 推断
736
+ */
737
+ declare class DefaultDeleteFeature<T extends {
648
738
  id: string | number;
649
- }> extends PageModule {
650
- /** ID 字段名(默认 "id") */
651
- protected readonly idField: string;
652
- /**
653
- * 获取所需权限
654
- * 默认实现:返回 "{serviceName}.{moduleName}.read"
655
- * 子类可以重写此方法来自定义权限要求
656
- *
657
- * @param ctx Hono Context(可选)
658
- * @returns 所需权限字符串,或空字符串/null/undefined 表示开放
659
- */
660
- getRequiredPermission(ctx?: any): string | null | undefined;
661
- /**
662
- * 获取数据源(抽象方法,必须实现)
663
- * 子类必须实现此方法来提供数据源
664
- */
665
- abstract getDatasource(): ListDatasource<T>;
666
- /**
667
- * 获取列表数据
668
- */
669
- getList(params: ListParams): Promise<ListResult<T>>;
670
- /**
671
- * 删除数据(可选,如果数据源支持删除)
672
- */
673
- deleteItem(id: string | number): Promise<boolean>;
674
- /**
675
- * 获取字段标签(可选)
676
- * 子类可以重写此方法来自定义字段的中文标签
677
- */
678
- getFieldLabel?(field: string): string;
679
- /**
680
- * 自定义列渲染(可选)
681
- * 子类可以重写此方法来自定义列的渲染逻辑
682
- */
683
- renderColumn?(field: string, value: any, item: T): any;
684
- /**
685
- * 获取统计信息(可选)
686
- * 子类可以重写此方法来返回 KPI 统计卡片数据
687
- * 返回的数组将渲染为 StatCard 组件
688
- */
689
- getStats?(params: ListParams): Promise<Array<{
690
- title: string;
691
- value: string | number;
692
- change?: number;
693
- changeLabel?: string;
694
- iconColor?: "blue" | "green" | "yellow" | "purple" | "red" | "indigo";
695
- icon?: any;
696
- }>> | Array<{
697
- title: string;
698
- value: string | number;
699
- change?: number;
700
- changeLabel?: string;
701
- iconColor?: "blue" | "green" | "yellow" | "purple" | "red" | "indigo";
702
- icon?: any;
703
- }>;
704
- /**
705
- * 获取筛选器配置(可选)
706
- * 子类可以重写此方法来返回筛选器字段配置
707
- * 返回的配置将渲染为 FilterCard 组件
708
- */
709
- getFilters?(params: ListParams): Array<{
710
- name: string;
711
- label: string;
712
- options: Array<{
713
- value: string | number;
714
- label: string;
715
- disabled?: boolean;
716
- }>;
717
- value?: string | number;
718
- defaultValue?: string | number;
719
- }>;
720
- /**
721
- * 获取表格标题(可选)
722
- * 子类可以重写此方法来返回表格标题
723
- * 如果不定义,默认使用模块名
724
- */
725
- getTableTitle?(): string;
726
- /**
727
- * 获取表格操作按钮(可选)
728
- * 子类可以重写此方法来返回表格操作按钮配置(如导出、清空、刷新等)
729
- * 如果不定义,默认会生成一个刷新按钮
730
- */
731
- getTableActions?(params: ListParams, basePath: string): Array<{
732
- label: string;
733
- href?: string;
734
- hxGet?: string;
735
- hxPost?: string;
736
- hxDelete?: string;
737
- variant?: "primary" | "secondary" | "danger" | "ghost";
738
- hxConfirm?: string;
739
- }>;
740
- /**
741
- * 自定义操作按钮(可选)
742
- * 子类可以重写此方法来添加自定义操作按钮
743
- * 如果不定义,则根据模块元数据智能生成默认操作按钮
744
- */
745
- getActions?(item: T): Array<{
746
- label: string;
747
- href: string | ((item: T) => string);
748
- method?: string;
749
- class?: string;
750
- }>;
751
- /**
752
- * 渲染列表页面(默认实现)
753
- * 子类可以重写此方法来自定义渲染
754
- */
755
- render(): Promise<any>;
739
+ } = any> extends BaseFeature {
740
+ private deleteItem;
741
+ constructor(options: {
742
+ deleteItem: (id: string | number) => Promise<boolean>;
743
+ permissionPrefix: string;
744
+ permission?: string;
745
+ });
746
+ getRoutes(): {
747
+ method: "delete";
748
+ path: string;
749
+ }[];
750
+ handle(context: FeatureContext): Promise<any>;
756
751
  }
757
752
 
758
753
  /**
759
- * 数据源接口和基础实现
754
+ * 默认详情 Feature
760
755
  */
761
756
 
762
757
  /**
763
- * 内存数据源(完整实现,可用于 list、detail、form 类型)
758
+ * 默认详情 Feature
759
+ * 类型通过 context.model.modelSchema.schema 的 z.infer 推断
764
760
  */
765
- declare class MemoryListDatasource<T extends {
761
+ declare class DefaultDetailFeature<T extends {
766
762
  id: string | number;
767
- }> implements ListDatasource<T>, DetailDatasource<T>, FormDatasource<T> {
768
- private data;
769
- constructor(data?: T[]);
770
- getList(params?: ListParams): Promise<ListResult<T>>;
771
- getItem(id: string | number): Promise<T | null>;
772
- deleteItem(id: string | number): Promise<boolean>;
773
- updateItem(id: string | number, data: Partial<T>): Promise<T | null>;
774
- createItem(data: Partial<T>): Promise<T>;
775
- }
776
-
777
- /**
778
- * HtmxAdminPlugin - 管理后台插件
779
- * 使用 HTMX + Tailwind + Hyperscript + JSX 快速构建管理后台
763
+ } = any> extends BaseFeature {
764
+ private getItem;
765
+ private deleteItem?;
766
+ private titleGetter?;
767
+ private descriptionGetter?;
768
+ constructor(options: {
769
+ getItem: (id: string | number) => Promise<T | null>;
770
+ deleteItem?: (id: string | number) => Promise<boolean>;
771
+ permissionPrefix: string;
772
+ permission?: string;
773
+ dialogSize?: DialogSize;
774
+ closeOnBackdropClick?: boolean;
775
+ /** 获取动态标题(可选,接收 item context,返回标题字符串) */
776
+ getTitle?: (item: T, context: FeatureContext) => string | Promise<string>;
777
+ /** 获取动态描述(可选,接收 item 和 context,返回描述字符串) */
778
+ getDescription?: (item: T, context: FeatureContext) => string | Promise<string> | undefined;
779
+ });
780
+ getTitle(context: FeatureContext): Promise<string>;
781
+ getDescription(context: FeatureContext): Promise<string | undefined>;
782
+ getRoutes(): {
783
+ method: "get";
784
+ path: string;
785
+ }[];
786
+ render(context: FeatureContext): Promise<any>;
787
+ getActions(context: FeatureContext): Promise<ActionButton[]>;
788
+ }
789
+
790
+ /**
791
+ * 默认编辑 Feature
792
+ */
793
+
794
+ /**
795
+ * 默认编辑 Feature
796
+ * 类型通过 context.model.modelSchema.schema 的 z.infer 推断
797
+ */
798
+ declare class DefaultEditFeature<T extends {
799
+ id: string | number;
800
+ } = any> extends BaseFormFeature<T> {
801
+ private getItem;
802
+ private updateItem;
803
+ constructor(options: {
804
+ getItem: (id: string | number) => Promise<T | null>;
805
+ updateItem: (id: string | number, data: Partial<T>) => Promise<T | null>;
806
+ permissionPrefix: string;
807
+ permission?: string;
808
+ dialogSize?: DialogSize;
809
+ closeOnBackdropClick?: boolean;
810
+ /** 获取动态标题(可选,接收 item 和 context,返回标题字符串,如 "编辑 {文章标题}") */
811
+ getTitle?: (item: T, context: FeatureContext) => string | Promise<string>;
812
+ /** 获取动态描述(可选,接收 item 和 context,返回描述字符串) */
813
+ getDescription?: (item: T, context: FeatureContext) => string | Promise<string> | undefined;
814
+ });
815
+ getFormAction(): "edit";
816
+ getRoutes(): ({
817
+ method: "get";
818
+ path: string;
819
+ } | {
820
+ method: "put";
821
+ path: string;
822
+ })[];
823
+ getSubmitUrl(context: FeatureContext): string;
824
+ getInitialData(context: FeatureContext): Promise<Partial<T> | undefined>;
825
+ handleSubmit(context: FeatureContext, validatedData: Partial<T>): Promise<T | null>;
826
+ getSuccessRedirectUrl(context: FeatureContext, item: T): string;
827
+ getCancelUrl(context: FeatureContext): string | undefined;
828
+ /**
829
+ * 重写 render 方法以处理 404 情况
830
+ */
831
+ render(context: FeatureContext, initialData?: Partial<T>): Promise<any>;
832
+ }
833
+
834
+ /**
835
+ * 默认列表 Feature
836
+ */
837
+
838
+ /**
839
+ * 默认列表 Feature
840
+ * 类型通过 context.model.modelSchema.schema 的 z.infer 推断
841
+ */
842
+ declare class DefaultListFeature<T extends {
843
+ id: string | number;
844
+ } = any> extends BaseFeature {
845
+ private getList;
846
+ private deleteItem?;
847
+ constructor(options: {
848
+ /** 获取列表数据的函数 */
849
+ getList: (params: ListParams) => Promise<ListResult<T>>;
850
+ /** 删除数据的函数(可选,不提供则列表不显示删除操作) */
851
+ deleteItem?: (id: string | number) => Promise<boolean>;
852
+ /** 权限前缀(格式:modelName,最终权限为 modelName.list) */
853
+ permissionPrefix: string;
854
+ /** 自定义权限(可选,覆盖默认的 modelName.list) */
855
+ permission?: string;
856
+ /** 弹窗大小(当 Feature 在弹窗中打开时使用) */
857
+ dialogSize?: DialogSize;
858
+ /** 是否允许点击遮罩区域关闭弹窗 */
859
+ closeOnBackdropClick?: boolean;
860
+ });
861
+ getRoutes(): {
862
+ method: "get";
863
+ path: string;
864
+ }[];
865
+ render(context: FeatureContext): Promise<any>;
866
+ getActions(context: FeatureContext): Promise<ActionButton[]>;
867
+ }
868
+
869
+ /**
870
+ * HtmxAdminPlugin - 管理后台插件 v2
871
+ * 基于 PageModel 和 Feature 的简化设计
780
872
  */
781
873
 
782
874
  /**
783
875
  * HtmxAdminPlugin
784
876
  */
785
- declare class HtmxAdminPlugin implements Plugin<HtmxAdminModuleOptions> {
877
+ declare class HtmxAdminPlugin implements Plugin {
786
878
  readonly name = "htmx-admin-plugin";
787
879
  readonly priority = PluginPriority.ROUTE;
788
880
  private engine;
789
881
  private hono;
790
882
  private options;
791
883
  private serviceName;
792
- private moduleTypeMap;
793
- private registeredOperations;
884
+ private pages;
794
885
  constructor(options?: HtmxAdminPluginOptions);
795
886
  /**
796
- * 声明Module配置Schema
887
+ * 注册页面(统一接口,支持有模型和无模型)
797
888
  */
798
- getModuleOptionsSchema(): PluginModuleOptionsSchema<HtmxAdminModuleOptions>;
889
+ registerPage(page: PageModel): this;
799
890
  /**
800
- * 引擎初始化钩子
801
- */
802
- onInit(engine: Microservice): void;
803
- /**
804
- * 检查并注册模块
805
- */
806
- private checkAndRegisterModules;
807
- /**
808
- * 根据模块类型和路由信息生成操作ID
809
- */
810
- private generateOperationId;
811
- /**
812
- * 注册内置路由(权限提示页面)
813
- */
814
- private registerBuiltinRoutes;
815
- /**
816
- * 注册路由
891
+ * 批量注册页面
817
892
  */
818
- private registerRoutes;
893
+ registerPages(...pages: PageModel[]): this;
819
894
  /**
820
- * 获取所有注册的操作(权限)列表
821
- * 可用于权限管理模块作为数据源,或用于确定管理员的权限
822
- *
823
- * @returns 所有注册的操作信息列表
824
- */
825
- getRegisteredOperations(): OperationInfo[];
826
- /**
827
- * 获取指定模块的所有操作
828
- *
829
- * @param moduleName 模块名
830
- * @returns 该模块的所有操作信息列表
831
- */
832
- getModuleOperations(moduleName: string): OperationInfo[];
833
- /**
834
- * 获取所有唯一的操作ID列表(去重)
835
- *
836
- * @returns 所有唯一的操作ID列表
895
+ * 引擎初始化钩子
837
896
  */
838
- getOperationIds(): string[];
897
+ onInit(engine: Microservice): void;
839
898
  /**
840
- * 模块加载钩子:检查模块类型约束并注册路由
899
+ * 引擎启动后注册路由
841
900
  */
842
- onModuleLoad(modules: ModuleMetadata[]): void;
901
+ onAfterStart(engine: Microservice): void;
843
902
  }
844
903
 
845
904
  /**
846
- * 渲染工具函数
847
- */
848
- /**
849
- * 安全渲染值(支持 JSX 和字符串 HTML)
850
- * 如果返回的是字符串 HTML,将其转换为 JSX 元素
905
+ * 认证工具函数
851
906
  */
852
- declare function safeRender(value: any): any;
853
907
 
854
908
  /**
855
- * 表单组件(用于编辑和新建)
856
- */
857
- /**
858
- * 字段定义
909
+ * 从 Context 获取用户信息
859
910
  */
860
- interface FormField$1 {
861
- /** 字段名 */
862
- name: string;
863
- /** 字段标签 */
864
- label: string;
865
- /** 字段类型 */
866
- type?: "text" | "email" | "number" | "textarea" | "select" | "date" | "datetime-local";
867
- /** 是否必填 */
868
- required?: boolean;
869
- /** 占位符 */
870
- placeholder?: string;
871
- /** 选项(用于 select 类型) */
872
- options?: Array<{
873
- value: string | number;
874
- label: string;
875
- }>;
876
- /** 自定义渲染函数 */
877
- render?: (value: any, item: any) => any;
878
- }
879
- /**
880
- * 表单组件 Props
881
- */
882
- interface FormProps<T = any> {
883
- /** 数据项(编辑时传入,新建时为 null) */
884
- item: T | null;
885
- /** 字段定义列表 */
886
- fields: FormField$1[];
887
- /** 提交 URL */
888
- submitUrl: string;
889
- /** 提交方法(默认 PUT) */
890
- method?: "PUT" | "POST";
891
- /** 提交后重定向 URL */
892
- redirectUrl?: string;
893
- /** 页面标题(默认 "编辑" 或 "新建") */
894
- title?: string;
895
- /** 取消按钮 URL */
896
- cancelUrl?: string;
897
- /** 是否在对话框中显示 */
898
- isDialog?: boolean;
899
- /** 表单数据(用于回填验证失败时的值) */
900
- formData?: Record<string, any>;
901
- }
902
- /**
903
- * 表单组件
904
- */
905
- declare const Form: <T extends Record<string, any>>(props: FormProps<T>) => hono_jsx_jsx_dev_runtime.JSX.Element;
911
+ declare function getUserInfo(ctx: Context, authProvider?: AuthProvider): Promise<UserInfo | null>;
906
912
 
907
913
  /**
908
- * Zod Schema 表单工具
909
- * 从 Zod Schema 自动生成表单字段定义和校验逻辑
910
- */
911
-
912
- /**
913
- * 从 Zod Object Schema 生成表单字段定义
914
- */
915
- declare function generateFormFieldsFromSchema<T extends z.ZodObject<any>>(schema: T, options?: {
916
- /** 字段标签映射(覆盖从 description 提取的标签) */
917
- fieldLabels?: Record<string, string>;
918
- /** 字段占位符映射 */
919
- fieldPlaceholders?: Record<string, string>;
920
- /** 字段选项映射(覆盖从 enum 提取的选项) */
921
- fieldOptions?: Record<string, Array<{
922
- value: string | number;
923
- label: string;
924
- }>>;
925
- /** 字段类型映射(覆盖自动推断的类型) */
926
- fieldTypes?: Record<string, FormField$1["type"]>;
927
- /** 要排除的字段 */
928
- excludeFields?: string[];
929
- }): FormField$1[];
930
- /**
931
- * 使用 Zod Schema 验证表单数据
932
- */
933
- declare function validateFormDataWithSchema<T extends z.ZodObject<any>>(schema: T, data: Record<string, any>): {
934
- success: true;
935
- data: z.infer<T>;
936
- } | {
937
- success: false;
938
- error: string;
939
- };
940
-
941
- /**
942
- * 操作按钮组件
943
- */
944
- interface ActionButtonProps {
945
- /** 按钮文本 */
946
- label: string;
947
- /** 链接地址 */
948
- href: string | ((item: any) => string);
949
- /** HTTP 方法 */
950
- method?: string;
951
- /** 自定义类名 */
952
- className?: string;
953
- /** 数据项(用于生成动态链接) */
954
- item?: any;
955
- }
956
- /**
957
- * 操作按钮组件
914
+ * 参数解析工具函数
958
915
  */
959
- declare const ActionButton: (props: ActionButtonProps) => hono_jsx_jsx_dev_runtime.JSX.Element;
960
916
 
961
917
  /**
962
- * 最近活动卡片组件
963
- */
964
- interface ActivityItem {
965
- /** 活动描述 */
966
- description: string;
967
- /** 时间(如"2分钟前") */
968
- time: string;
969
- /** 活动类型颜色(blue, green, purple, gray等) */
970
- color?: "blue" | "green" | "purple" | "gray" | "yellow" | "red";
971
- }
972
- interface ActivityCardProps {
973
- /** 标题 */
974
- title: string;
975
- /** 活动列表 */
976
- activities: ActivityItem[];
977
- /** 自定义类名 */
978
- className?: string;
979
- }
980
- /**
981
- * 最近活动卡片组件
982
- * 用于展示最近的活动记录列表
918
+ * 解析列表查询参数
983
919
  */
984
- declare const ActivityCard: (props: ActivityCardProps) => hono_jsx_jsx_dev_runtime.JSX.Element;
920
+ declare function parseListParams(ctx: Context): ListParams;
985
921
 
986
922
  /**
987
- * 徽章组件(用于标签显示)
923
+ * 路径工具函数
988
924
  */
989
- interface BadgeProps {
990
- /** 标签文本 */
991
- children: any;
992
- /** 颜色主题 */
993
- variant?: "blue" | "green" | "yellow" | "red" | "gray" | "purple" | "indigo";
994
- /** 自定义类名 */
995
- className?: string;
996
- }
997
925
  /**
998
- * 徽章组件
999
- * 用于显示状态标签,如日志级别、状态等
926
+ * 将模型名转换为路径
1000
927
  */
1001
- declare const Badge: (props: BadgeProps) => hono_jsx_jsx_dev_runtime.JSX.Element;
928
+ declare function modelNameToPath(modelName: string): string;
1002
929
 
1003
930
  /**
1004
- * 按钮组件
931
+ * 权限校验工具
932
+ * 支持灵活的权限系统,包括通配符和禁止权限
1005
933
  */
1006
- interface ButtonProps {
1007
- /** 按钮文本 */
1008
- children: any;
1009
- /** 按钮类型 */
1010
- variant?: "primary" | "secondary" | "danger" | "ghost";
1011
- /** 按钮大小 */
1012
- size?: "sm" | "md" | "lg";
1013
- /** 是否禁用 */
1014
- disabled?: boolean;
1015
- /** 自定义类名 */
1016
- className?: string;
1017
- /** HTMX 属性 */
1018
- hxGet?: string;
1019
- hxPost?: string;
1020
- hxPut?: string;
1021
- hxDelete?: string;
1022
- hxTarget?: string;
1023
- hxSwap?: string;
1024
- hxPushUrl?: string | boolean;
1025
- hxIndicator?: string;
1026
- hxConfirm?: string;
1027
- hxHeaders?: string;
1028
- /** 其他属性 */
1029
- [key: string]: any;
1030
- }
1031
- /**
1032
- * 按钮组件
1033
- */
1034
- declare const Button: (props: ButtonProps) => hono_jsx_jsx_dev_runtime.JSX.Element;
1035
-
1036
- /**
1037
- * 卡片组件
1038
- */
1039
- interface CardProps {
1040
- /** 卡片内容 */
1041
- children: any;
1042
- /** 卡片标题 */
1043
- title?: string;
1044
- /** 自定义类名 */
1045
- className?: string;
1046
- /** 是否显示阴影 */
1047
- shadow?: boolean;
1048
- /** 是否显示边框 */
1049
- bordered?: boolean;
1050
- /** 是否去掉内边距 */
1051
- noPadding?: boolean;
1052
- }
1053
- /**
1054
- * 卡片组件
1055
- */
1056
- declare const Card: (props: CardProps) => hono_jsx_jsx_dev_runtime.JSX.Element;
1057
-
1058
- /**
1059
- * 详情页面组件
1060
- */
1061
- /**
1062
- * 字段组定义
1063
- */
1064
- interface FieldGroup {
1065
- title: string;
1066
- fields: string[];
1067
- }
1068
- /**
1069
- * 详情页面组件 Props
1070
- */
1071
- interface DetailProps<T = any> {
1072
- /** 数据项 */
1073
- item: T;
1074
- /** 字段标签映射(字段名 -> 中文标签) */
1075
- fieldLabels?: Record<string, string>;
1076
- /** 字段渲染函数(字段名 -> 渲染函数) */
1077
- fieldRenderers?: Record<string, (value: any, item: T) => any>;
1078
- /** 字段分组(可选,如果不提供则平铺显示) */
1079
- fieldGroups?: FieldGroup[];
1080
- /** 可见字段列表(控制显示顺序和可见性) */
1081
- visibleFields?: string[];
1082
- /** 操作按钮 */
1083
- actions?: Array<{
1084
- label: string;
1085
- href: string | ((item: T) => string);
1086
- method?: string;
1087
- class?: string;
1088
- }>;
1089
- /** 页面标题(默认 "详情") */
1090
- title?: string;
1091
- /** 是否在对话框中显示 */
1092
- isDialog?: boolean;
1093
- }
1094
- /**
1095
- * 详情页面组件
1096
- */
1097
- declare const Detail: <T extends Record<string, any>>(props: DetailProps<T>) => hono_jsx_jsx_dev_runtime.JSX.Element;
1098
-
1099
- /**
1100
- * DetailContent - 详情内容组件(纯组件)
1101
- * 接收渲染所需的数据,渲染详情页面内容
1102
- */
1103
- /**
1104
- * 详情内容组件 Props
1105
- */
1106
- interface DetailContentProps<T = any> {
1107
- /** 数据项 */
1108
- item: T;
1109
- /** 字段标签映射 */
1110
- fieldLabels: Record<string, string>;
1111
- /** 字段渲染器映射 */
1112
- fieldRenderers?: Record<string, (value: any, item: T) => any>;
1113
- /** 字段分组 */
1114
- fieldGroups?: Array<{
1115
- title: string;
1116
- fields: string[];
1117
- }>;
1118
- /** 可见字段列表 */
1119
- visibleFields?: string[];
1120
- /** 操作按钮配置 */
1121
- actions?: Array<{
1122
- label: string;
1123
- href: string | ((item: T) => string);
1124
- method?: string;
1125
- class?: string;
1126
- }>;
1127
- /** 页面标题 */
1128
- title: string;
1129
- /** 是否是对话框模式 */
1130
- isDialog: boolean;
934
+ interface PermissionCheckResult {
935
+ allowed: boolean;
936
+ reason?: string;
937
+ matchedPermission?: string;
1131
938
  }
1132
939
  /**
1133
- * 详情内容组件
940
+ * 权限校验函数
1134
941
  */
1135
- declare function DetailContent<T extends Record<string, any> = Record<string, any>>(props: DetailContentProps<T>): hono_jsx_jsx_dev_runtime.JSX.Element;
942
+ declare function checkUserPermission(requiredPermission: string | null, userPermissions: string[]): PermissionCheckResult;
1136
943
 
1137
- /**
1138
- * 对话框组件(Modal/Dialog)
1139
- */
1140
944
  interface DialogProps {
1141
945
  /** 对话框标题 */
1142
946
  title?: string;
@@ -1144,33 +948,21 @@ interface DialogProps {
1144
948
  children: any;
1145
949
  /** 是否显示关闭按钮 */
1146
950
  showClose?: boolean;
1147
- /** 关闭时的回调 URL(用于关闭对话框) */
1148
- closeUrl?: string;
1149
951
  /** 自定义类名 */
1150
952
  className?: string;
1151
953
  /** 对话框大小 */
1152
954
  size?: "sm" | "md" | "lg" | "xl" | "full";
955
+ /** 是否允许点击遮罩区域关闭(默认 true,设置为 false 时只能通过关闭按钮关闭) */
956
+ closeOnBackdropClick?: boolean;
957
+ /** 操作按钮(在 Footer 中显示,固定在底部) */
958
+ actions?: ActionButton[];
1153
959
  }
1154
- /**
1155
- * 对话框组件
1156
- * 用于在模态框中显示内容,支持 HTMX 交互
1157
- */
1158
- declare const Dialog: (props: DialogProps) => hono_jsx_jsx_dev_runtime.JSX.Element;
960
+ declare function Dialog(props: DialogProps): hono_jsx_jsx_dev_runtime.JSX.Element;
1159
961
 
1160
962
  /**
1161
- * 空状态组件
963
+ * 错误提示组件(通知组件)
1162
964
  */
1163
- interface EmptyStateProps {
1164
- /** 提示文本 */
1165
- message?: string;
1166
- /** 自定义内容 */
1167
- children?: any;
1168
- }
1169
- /**
1170
- * 空状态组件
1171
- */
1172
- declare const EmptyState: (props: EmptyStateProps) => hono_jsx_jsx_dev_runtime.JSX.Element;
1173
-
965
+ type NotificationType = "error" | "warning" | "info" | "success";
1174
966
  interface ErrorAlertProps {
1175
967
  /** 错误标题 */
1176
968
  title?: string;
@@ -1182,433 +974,19 @@ interface ErrorAlertProps {
1182
974
  showClose?: boolean;
1183
975
  /** 自定义类名 */
1184
976
  className?: string;
977
+ /** 自动关闭时间(毫秒),0 表示不自动关闭 */
978
+ autoClose?: number;
1185
979
  }
1186
980
  /**
1187
981
  * 错误提示组件
1188
982
  * 用于显示错误、警告或信息提示
1189
983
  */
1190
- declare const ErrorAlert: (props: ErrorAlertProps) => hono_jsx_jsx_dev_runtime.JSX.Element;
1191
-
1192
- /**
1193
- * 选择框组件
1194
- */
1195
- interface SelectOption {
1196
- value: string | number;
1197
- label: string;
1198
- disabled?: boolean;
1199
- }
1200
- interface SelectProps {
1201
- /** 字段ID */
1202
- id?: string;
1203
- /** 字段名 */
1204
- name: string;
1205
- /** 字段值 */
1206
- value?: string | number;
1207
- /** 默认值 */
1208
- defaultValue?: string | number;
1209
- /** 是否必填 */
1210
- required?: boolean;
1211
- /** 是否禁用 */
1212
- disabled?: boolean;
1213
- /** 选项列表 */
1214
- options: SelectOption[];
1215
- /** 占位符选项(当required为false时显示) */
1216
- placeholder?: string;
1217
- /** 自定义类名 */
1218
- className?: string;
1219
- /** 其他属性 */
1220
- [key: string]: any;
1221
- }
1222
- /**
1223
- * 选择框组件
1224
- */
1225
- declare const Select: (props: SelectProps) => hono_jsx_jsx_dev_runtime.JSX.Element;
1226
-
1227
- interface FilterField {
1228
- /** 字段名 */
1229
- name: string;
1230
- /** 字段标签 */
1231
- label: string;
1232
- /** 选项列表 */
1233
- options: SelectOption[];
1234
- /** 当前值 */
1235
- value?: string | number;
1236
- /** 默认值 */
1237
- defaultValue?: string | number;
1238
- }
1239
- interface FilterCardProps {
1240
- /** 标题 */
1241
- title?: string;
1242
- /** 筛选字段列表 */
1243
- fields: FilterField[];
1244
- /** 筛选按钮文本 */
1245
- filterButtonText?: string;
1246
- /** 筛选按钮的 HTMX 属性 */
1247
- filterButtonHxGet?: string;
1248
- /** 需要保留的查询参数名列表(如排序参数) */
1249
- preserveParams?: string[];
1250
- /** 自定义类名 */
1251
- className?: string;
1252
- }
1253
- /**
1254
- * 筛选卡片组件
1255
- * 用于展示筛选表单,包含多个下拉选择器和筛选按钮
1256
- */
1257
- declare const FilterCard: (props: FilterCardProps) => hono_jsx_jsx_dev_runtime.JSX.Element;
1258
-
1259
- /**
1260
- * 列表内容组件 Props
1261
- */
1262
- interface ListContentProps<T = any> {
1263
- /** 列表查询结果 */
1264
- result: ListResult<T>;
1265
- /** 列表查询参数 */
1266
- params: ListParams;
1267
- /** 页面标题 */
1268
- pageTitle: string;
1269
- /** 页面描述 */
1270
- pageDescription?: string;
1271
- /** 表格标题 */
1272
- tableTitle: string;
1273
- /** 列定义 */
1274
- columns: Array<{
1275
- key: string;
1276
- label: string;
1277
- render?: (value: any, item: T) => any;
1278
- }>;
1279
- /** 操作按钮配置 */
1280
- actions?: Array<{
1281
- label: string;
1282
- href: string | ((item: T) => string);
1283
- method?: string;
1284
- class?: string;
1285
- }>;
1286
- /** 统计信息(KPI卡片) */
1287
- stats?: Array<{
1288
- title: string;
1289
- value: string | number;
1290
- change?: number;
1291
- changeLabel?: string;
1292
- iconColor?: "blue" | "green" | "yellow" | "purple" | "red" | "indigo";
1293
- icon?: any;
1294
- }>;
1295
- /** 筛选器配置 */
1296
- filters?: Array<{
1297
- name: string;
1298
- label: string;
1299
- options: Array<{
1300
- value: string | number;
1301
- label: string;
1302
- disabled?: boolean;
1303
- }>;
1304
- value?: string | number;
1305
- defaultValue?: string | number;
1306
- }>;
1307
- /** 表格操作按钮 */
1308
- tableActions?: Array<{
1309
- label: string;
1310
- href?: string;
1311
- hxGet?: string;
1312
- hxPost?: string;
1313
- hxDelete?: string;
1314
- variant?: "primary" | "secondary" | "danger" | "ghost";
1315
- hxConfirm?: string;
1316
- }>;
1317
- /** 是否有 form 模块(用于决定是否显示新建按钮) */
1318
- hasFormModule: boolean;
1319
- /** 新建按钮路径 */
1320
- createPath: string;
1321
- /** 列表路径(用于分页和筛选) */
1322
- listPath: string;
1323
- }
1324
- /**
1325
- * 列表内容组件
1326
- */
1327
- declare function ListContent<T extends {
1328
- id: string | number;
1329
- } = {
1330
- id: string | number;
1331
- }>(props: ListContentProps<T>): hono_jsx_jsx_dev_runtime.JSX.Element;
1332
-
1333
- /**
1334
- * 页面标题组件
1335
- */
1336
- interface PageHeaderProps {
1337
- /** 标题 */
1338
- title: string;
1339
- /** 描述文本 */
1340
- description?: string;
1341
- /** 右侧操作按钮 */
1342
- actions?: any;
1343
- /** 自定义类名 */
1344
- className?: string;
1345
- }
1346
- /**
1347
- * 页面标题组件
1348
- */
1349
- declare const PageHeader: (props: PageHeaderProps) => hono_jsx_jsx_dev_runtime.JSX.Element;
1350
-
1351
- /**
1352
- * 分页组件
1353
- */
1354
- interface PaginationProps {
1355
- /** 当前页码 */
1356
- page: number;
1357
- /** 每页数量 */
1358
- pageSize: number;
1359
- /** 总记录数 */
1360
- total: number;
1361
- /** 总页数 */
1362
- totalPages: number;
1363
- /** 基础 URL */
1364
- baseUrl: string;
1365
- /** 当前查询参数(用于保留筛选条件等) */
1366
- currentParams?: Record<string, string | number | undefined>;
1367
- }
1368
- /**
1369
- * 分页组件
1370
- */
1371
- declare const Pagination: (props: PaginationProps) => hono_jsx_jsx_dev_runtime.JSX.Element | null;
1372
-
1373
- /**
1374
- * 统计卡片组件(KPI卡片)
1375
- */
1376
- interface StatCardProps {
1377
- /** 标题 */
1378
- title: string;
1379
- /** 数值 */
1380
- value: string | number;
1381
- /** 变化百分比(正数表示增长,负数表示下降) */
1382
- change?: number;
1383
- /** 变化描述(如"相比上月") */
1384
- changeLabel?: string;
1385
- /** 图标颜色(blue, green, yellow, purple等) */
1386
- iconColor?: "blue" | "green" | "yellow" | "purple" | "red" | "indigo";
1387
- /** 自定义图标(SVG或emoji) */
1388
- icon?: any;
1389
- /** 自定义类名 */
1390
- className?: string;
1391
- }
1392
- /**
1393
- * 统计卡片组件
1394
- * 用于展示关键指标,包含标题、数值、变化趋势和图标
1395
- */
1396
- declare const StatCard: (props: StatCardProps) => hono_jsx_jsx_dev_runtime.JSX.Element;
1397
-
1398
- /**
1399
- * 系统状态卡片组件
1400
- */
1401
- interface StatusItem {
1402
- /** 状态名称 */
1403
- label: string;
1404
- /** 当前值(百分比或文本) */
1405
- value: string | number;
1406
- /** 进度条百分比(0-100) */
1407
- progress?: number;
1408
- /** 进度条颜色 */
1409
- color?: "blue" | "green" | "orange" | "red" | "purple" | "yellow";
1410
- /** 是否为文本状态(如"正常") */
1411
- isText?: boolean;
1412
- }
1413
- interface SystemStatusCardProps {
1414
- /** 标题 */
1415
- title: string;
1416
- /** 状态项列表 */
1417
- statusItems: StatusItem[];
1418
- /** 自定义类名 */
1419
- className?: string;
1420
- }
1421
- /**
1422
- * 系统状态卡片组件
1423
- * 用于展示系统资源使用情况,包含进度条和文本状态
1424
- */
1425
- declare const SystemStatusCard: (props: SystemStatusCardProps) => hono_jsx_jsx_dev_runtime.JSX.Element;
1426
-
1427
- /**
1428
- * 日期输入组件
1429
- */
1430
- interface DateInputProps {
1431
- /** 字段ID */
1432
- id?: string;
1433
- /** 字段名 */
1434
- name: string;
1435
- /** 日期类型 */
1436
- type?: "date" | "datetime-local" | "time" | "month" | "week";
1437
- /** 字段值 */
1438
- value?: string;
1439
- /** 默认值 */
1440
- defaultValue?: string;
1441
- /** 是否必填 */
1442
- required?: boolean;
1443
- /** 是否禁用 */
1444
- disabled?: boolean;
1445
- /** 是否只读 */
1446
- readOnly?: boolean;
1447
- /** 最小值 */
1448
- min?: string;
1449
- /** 最大值 */
1450
- max?: string;
1451
- /** 自定义类名 */
1452
- className?: string;
1453
- /** 其他属性 */
1454
- [key: string]: any;
1455
- }
1456
- /**
1457
- * 日期输入组件
1458
- */
1459
- declare const DateInput: (props: DateInputProps) => hono_jsx_jsx_dev_runtime.JSX.Element;
984
+ declare function ErrorAlert(props: ErrorAlertProps): hono_jsx_jsx_dev_runtime.JSX.Element;
1460
985
 
1461
986
  /**
1462
- * 表单字段组件(标签 + 输入框的包装器)
987
+ * 加载条组件
988
+ * 用于显示 HTMX 请求的加载状态
1463
989
  */
1464
- interface FormFieldProps {
1465
- /** 字段标签 */
1466
- label: string;
1467
- /** 字段ID(用于关联label和input) */
1468
- id: string;
1469
- /** 是否必填 */
1470
- required?: boolean;
1471
- /** 错误信息 */
1472
- error?: string;
1473
- /** 帮助文本 */
1474
- help?: string;
1475
- /** 子元素(输入框等) */
1476
- children: any;
1477
- /** 自定义类名 */
1478
- className?: string;
1479
- }
1480
- /**
1481
- * 表单字段组件
1482
- * 提供统一的标签、错误提示、帮助文本样式
1483
- */
1484
- declare const FormField: (props: FormFieldProps) => hono_jsx_jsx_dev_runtime.JSX.Element;
1485
-
1486
- /**
1487
- * 输入框组件
1488
- */
1489
- interface InputProps {
1490
- /** 字段ID */
1491
- id?: string;
1492
- /** 字段名 */
1493
- name: string;
1494
- /** 字段类型 */
1495
- type?: "text" | "email" | "password" | "number" | "tel" | "url" | "search";
1496
- /** 字段值 */
1497
- value?: string | number;
1498
- /** 默认值 */
1499
- defaultValue?: string | number;
1500
- /** 占位符 */
1501
- placeholder?: string;
1502
- /** 是否必填 */
1503
- required?: boolean;
1504
- /** 是否禁用 */
1505
- disabled?: boolean;
1506
- /** 是否只读 */
1507
- readOnly?: boolean;
1508
- /** 最小值(用于number类型) */
1509
- min?: number;
1510
- /** 最大值(用于number类型) */
1511
- max?: number;
1512
- /** 步长(用于number类型) */
1513
- step?: number;
1514
- /** 自定义类名 */
1515
- className?: string;
1516
- /** 其他属性 */
1517
- [key: string]: any;
1518
- }
1519
- /**
1520
- * 输入框组件
1521
- */
1522
- declare const Input: (props: InputProps) => hono_jsx_jsx_dev_runtime.JSX.Element;
1523
-
1524
- /**
1525
- * 文本域组件
1526
- */
1527
- interface TextareaProps {
1528
- /** 字段ID */
1529
- id?: string;
1530
- /** 字段名 */
1531
- name: string;
1532
- /** 字段值 */
1533
- value?: string;
1534
- /** 默认值 */
1535
- defaultValue?: string;
1536
- /** 占位符 */
1537
- placeholder?: string;
1538
- /** 是否必填 */
1539
- required?: boolean;
1540
- /** 是否禁用 */
1541
- disabled?: boolean;
1542
- /** 是否只读 */
1543
- readOnly?: boolean;
1544
- /** 行数 */
1545
- rows?: number;
1546
- /** 自定义类名 */
1547
- className?: string;
1548
- /** 其他属性 */
1549
- [key: string]: any;
1550
- }
1551
- /**
1552
- * 文本域组件
1553
- */
1554
- declare const Textarea: (props: TextareaProps) => hono_jsx_jsx_dev_runtime.JSX.Element;
1555
-
1556
- /**
1557
- * HtmxAdmin 组件导出
1558
- * 外部可用的组件通过 Components 命名空间导出
1559
- */
1560
-
1561
- declare const index_ActionButton: typeof ActionButton;
1562
- type index_ActionButtonProps = ActionButtonProps;
1563
- declare const index_ActivityCard: typeof ActivityCard;
1564
- type index_ActivityCardProps = ActivityCardProps;
1565
- type index_ActivityItem = ActivityItem;
1566
- declare const index_Badge: typeof Badge;
1567
- type index_BadgeProps = BadgeProps;
1568
- declare const index_Button: typeof Button;
1569
- type index_ButtonProps = ButtonProps;
1570
- declare const index_Card: typeof Card;
1571
- type index_CardProps = CardProps;
1572
- declare const index_DateInput: typeof DateInput;
1573
- type index_DateInputProps = DateInputProps;
1574
- declare const index_Detail: typeof Detail;
1575
- declare const index_DetailContent: typeof DetailContent;
1576
- type index_DetailContentProps<T = any> = DetailContentProps<T>;
1577
- type index_DetailProps<T = any> = DetailProps<T>;
1578
- declare const index_Dialog: typeof Dialog;
1579
- type index_DialogProps = DialogProps;
1580
- declare const index_EmptyState: typeof EmptyState;
1581
- type index_EmptyStateProps = EmptyStateProps;
1582
- declare const index_ErrorAlert: typeof ErrorAlert;
1583
- type index_ErrorAlertProps = ErrorAlertProps;
1584
- type index_FieldGroup = FieldGroup;
1585
- declare const index_FilterCard: typeof FilterCard;
1586
- type index_FilterCardProps = FilterCardProps;
1587
- type index_FilterField = FilterField;
1588
- declare const index_Form: typeof Form;
1589
- declare const index_FormField: typeof FormField;
1590
- type index_FormFieldProps = FormFieldProps;
1591
- type index_FormProps<T = any> = FormProps<T>;
1592
- declare const index_Input: typeof Input;
1593
- type index_InputProps = InputProps;
1594
- declare const index_ListContent: typeof ListContent;
1595
- type index_ListContentProps<T = any> = ListContentProps<T>;
1596
- declare const index_PageHeader: typeof PageHeader;
1597
- type index_PageHeaderProps = PageHeaderProps;
1598
- declare const index_Pagination: typeof Pagination;
1599
- type index_PaginationProps = PaginationProps;
1600
- declare const index_Select: typeof Select;
1601
- type index_SelectOption = SelectOption;
1602
- type index_SelectProps = SelectProps;
1603
- declare const index_StatCard: typeof StatCard;
1604
- type index_StatCardProps = StatCardProps;
1605
- type index_StatusItem = StatusItem;
1606
- declare const index_SystemStatusCard: typeof SystemStatusCard;
1607
- type index_SystemStatusCardProps = SystemStatusCardProps;
1608
- declare const index_Textarea: typeof Textarea;
1609
- type index_TextareaProps = TextareaProps;
1610
- declare namespace index {
1611
- export { index_ActionButton as ActionButton, type index_ActionButtonProps as ActionButtonProps, index_ActivityCard as ActivityCard, type index_ActivityCardProps as ActivityCardProps, type index_ActivityItem as ActivityItem, index_Badge as Badge, type index_BadgeProps as BadgeProps, index_Button as Button, type index_ButtonProps as ButtonProps, index_Card as Card, type index_CardProps as CardProps, index_DateInput as DateInput, type index_DateInputProps as DateInputProps, index_Detail as Detail, index_DetailContent as DetailContent, type index_DetailContentProps as DetailContentProps, type index_DetailProps as DetailProps, index_Dialog as Dialog, type index_DialogProps as DialogProps, index_EmptyState as EmptyState, type index_EmptyStateProps as EmptyStateProps, index_ErrorAlert as ErrorAlert, type index_ErrorAlertProps as ErrorAlertProps, type index_FieldGroup as FieldGroup, index_FilterCard as FilterCard, type index_FilterCardProps as FilterCardProps, type index_FilterField as FilterField, index_Form as Form, index_FormField as FormField, type index_FormFieldProps as FormFieldProps, type FormField$1 as FormFieldType, type index_FormProps as FormProps, index_Input as Input, type index_InputProps as InputProps, index_ListContent as ListContent, type index_ListContentProps as ListContentProps, index_PageHeader as PageHeader, type index_PageHeaderProps as PageHeaderProps, index_Pagination as Pagination, type index_PaginationProps as PaginationProps, index_Select as Select, type index_SelectOption as SelectOption, type index_SelectProps as SelectProps, index_StatCard as StatCard, type index_StatCardProps as StatCardProps, type index_StatusItem as StatusItem, index_SystemStatusCard as SystemStatusCard, type index_SystemStatusCardProps as SystemStatusCardProps, index_Textarea as Textarea, type index_TextareaProps as TextareaProps };
1612
- }
990
+ declare function LoadingBar(): hono_jsx_jsx_dev_runtime.JSX.Element;
1613
991
 
1614
- export { type BreadcrumbItem, index as Components, type DetailDatasource, DetailPageModule, type FormDatasource, FormPageModule, HtmxAdminContext, type HtmxAdminModuleOptions, HtmxAdminPlugin, type HtmxAdminPluginOptions, type ListDatasource, ListPageModule, type ListParams, type ListResult, MemoryListDatasource, type ModuleType, PageModule, PathHelper, type UserInfo, generateFormFieldsFromSchema, safeRender, validateFormDataWithSchema };
992
+ export { type AuthProvider, BaseFeature, CustomFeature, DefaultCreateFeature, DefaultDeleteFeature, DefaultDetailFeature, DefaultEditFeature, DefaultListFeature, Dialog, type DialogProps, type DialogSize, ErrorAlert, type ErrorAlertProps, type Feature, type FeatureContext, type FeatureType, type FieldMetadata, HtmxAdminPlugin, type HtmxAdminPluginOptions, type ListParams, type ListResult, LoadingBar, type ModelSchema, type NavItemConfig, type Notification, type NotificationType$1 as NotificationType, type PageMetadata, PageModel, type PermissionResult, type UserInfo, checkUserPermission, getUserInfo, modelNameToPath, parseListParams };