@wecode-team/we0-cms 1.0.18

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 (42) hide show
  1. package/README.md +450 -0
  2. package/dist/components/componets/message.d.ts +42 -0
  3. package/dist/components/filters/DynamicFilters.d.ts +7 -0
  4. package/dist/components/json/JsonField.d.ts +11 -0
  5. package/dist/components/json/json-utils.d.ts +19 -0
  6. package/dist/components/page-shadcn.d.ts +16 -0
  7. package/dist/components/pages/admin.d.ts +2 -0
  8. package/dist/components/pages/data-list.d.ts +2 -0
  9. package/dist/components/pages/data-manage.d.ts +3 -0
  10. package/dist/components/pages/login.d.ts +6 -0
  11. package/dist/components/pages/model-create.d.ts +2 -0
  12. package/dist/components/pages/test-json.d.ts +2 -0
  13. package/dist/components/prase.d.ts +5 -0
  14. package/dist/components/routes.d.ts +12 -0
  15. package/dist/components/types.d.ts +69 -0
  16. package/dist/components/ui/badge.d.ts +9 -0
  17. package/dist/components/ui/button.d.ts +11 -0
  18. package/dist/components/ui/card.d.ts +8 -0
  19. package/dist/components/ui/dialog.d.ts +19 -0
  20. package/dist/components/ui/dropdown-menu.d.ts +27 -0
  21. package/dist/components/ui/input.d.ts +3 -0
  22. package/dist/components/ui/label.d.ts +5 -0
  23. package/dist/components/ui/select.d.ts +13 -0
  24. package/dist/components/ui/separator.d.ts +4 -0
  25. package/dist/components/ui/sheet.d.ts +25 -0
  26. package/dist/components/ui/sidebar.d.ts +50 -0
  27. package/dist/components/ui/skeleton.d.ts +3 -0
  28. package/dist/components/ui/switch.d.ts +4 -0
  29. package/dist/components/ui/table.d.ts +10 -0
  30. package/dist/components/ui/textarea.d.ts +3 -0
  31. package/dist/components/ui/tooltip.d.ts +7 -0
  32. package/dist/hooks/use-mobile.d.ts +1 -0
  33. package/dist/index.css +3 -0
  34. package/dist/index.d.ts +7 -0
  35. package/dist/index.esm.js +11 -0
  36. package/dist/index.esm.js.map +1 -0
  37. package/dist/index.js +11 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/lib/utils.d.ts +2 -0
  40. package/dist/request.d.ts +14 -0
  41. package/dist/services/index.d.ts +121 -0
  42. package/package.json +89 -0
package/README.md ADDED
@@ -0,0 +1,450 @@
1
+ # @wecode-team/we0-cms
2
+
3
+ 一个基于 React 的动态 CMS 前端组件库,支持 shadcn/ui 风格的现代化 UI,与 `@wecode-team/cms-supabase-api` 配合使用实现完整的内容管理系统。
4
+
5
+ ## 📖 设计理念
6
+
7
+ ### 核心思想
8
+
9
+ 本包的核心理念是 **"配置驱动的 CMS UI"**:
10
+
11
+ 1. **模型驱动 UI**:根据 JSON Schema 模型配置自动生成表单和表格
12
+ 2. **零代码管理**:无需编写代码,通过配置即可实现数据的增删改查
13
+ 3. **关系可视化**:支持关联字段的下拉选择和数据展示
14
+ 4. **多租户支持**:通过 Session ID 实现数据隔离
15
+
16
+ ### 架构设计
17
+
18
+ ```
19
+ ┌─────────────────────────────────────────────────────────────┐
20
+ │ CmsLayoutShadcn │
21
+ │ (主布局组件) │
22
+ ├─────────────────────────────────────────────────────────────┤
23
+ │ UI Components (shadcn/ui) │
24
+ │ ├── Sidebar 侧边栏导航 │
25
+ │ ├── DataTable 数据表格 │
26
+ │ ├── Dialog 弹窗表单 │
27
+ │ └── Form Controls 表单控件 │
28
+ ├─────────────────────────────────────────────────────────────┤
29
+ │ Pages (页面组件) │
30
+ │ ├── LoginPage 登录页面 │
31
+ │ ├── DataListPage 数据列表页 │
32
+ │ └── DataManagePage 数据管理页(按模型) │
33
+ ├─────────────────────────────────────────────────────────────┤
34
+ │ Services (服务层) │
35
+ │ ├── modelApi 模型管理 API │
36
+ │ ├── dataApi 数据操作 API │
37
+ │ └── authApi 认证 API │
38
+ ├─────────────────────────────────────────────────────────────┤
39
+ │ Request Layer (请求层) │
40
+ │ └── request.ts Axios 封装,自动添加 Token │
41
+ └─────────────────────────────────────────────────────────────┘
42
+ ```
43
+
44
+ ### 数据流
45
+
46
+ ```
47
+ 用户操作 → UI 组件 → Services API → HTTP 请求 → 后端 API → Supabase
48
+
49
+ 用户界面 ← UI 更新 ← State 更新 ← API 响应 ←
50
+ ```
51
+
52
+ ## 🚀 安装
53
+
54
+ ```bash
55
+ npm install @wecode-team/we0-cms
56
+ # 或
57
+ pnpm add @wecode-team/we0-cms
58
+ # 或
59
+ yarn add @wecode-team/we0-cms
60
+ ```
61
+
62
+ ## 📋 依赖
63
+
64
+ ### Peer Dependencies(必须安装)
65
+
66
+ ```json
67
+ {
68
+ "react": "^18.2.0",
69
+ "react-dom": "^18.2.0"
70
+ }
71
+ ```
72
+
73
+ ### 内置依赖
74
+
75
+ - `@radix-ui/*` - 无障碍 UI 原语
76
+ - `lucide-react` - 图标库
77
+ - `tailwind-merge` - Tailwind 类名合并
78
+ - `class-variance-authority` - 变体样式管理
79
+ - `dayjs` - 日期处理
80
+
81
+ ## 🔧 快速开始
82
+
83
+ ### 第一步:配置 Tailwind CSS
84
+
85
+ 确保你的项目已配置 Tailwind CSS:
86
+
87
+ ```javascript
88
+ // tailwind.config.js
89
+ module.exports = {
90
+ content: [
91
+ './src/**/*.{js,jsx,ts,tsx}',
92
+ './node_modules/@wecode-team/we0-cms/dist/**/*.{js,jsx}'
93
+ ],
94
+ theme: {
95
+ extend: {}
96
+ },
97
+ plugins: []
98
+ }
99
+ ```
100
+
101
+ ### 第二步:引入样式
102
+
103
+ ```jsx
104
+ import '@wecode-team/we0-cms/dist/index.css'
105
+ ```
106
+
107
+ ### 第三步:使用组件
108
+
109
+ ```jsx
110
+ import React from 'react'
111
+ import { CmsLayoutShadcn, setSessionId } from '@wecode-team/we0-cms'
112
+ import '@wecode-team/we0-cms/dist/index.css'
113
+
114
+ // 设置 Session ID(用于多租户隔离)
115
+ setSessionId('your-session-id')
116
+
117
+ // 定义模型配置
118
+ const modelData = {
119
+ models: [
120
+ {
121
+ id: 1,
122
+ name: '用户模型',
123
+ table_name: 'users',
124
+ json_schema: {
125
+ fields: [
126
+ {
127
+ name: 'name',
128
+ type: 'string',
129
+ comment: '用户姓名',
130
+ required: true,
131
+ maxLength: 100
132
+ },
133
+ {
134
+ name: 'email',
135
+ type: 'email',
136
+ unique: true,
137
+ comment: '用户邮箱',
138
+ required: true
139
+ },
140
+ {
141
+ name: 'age',
142
+ type: 'integer',
143
+ comment: '年龄',
144
+ required: false
145
+ }
146
+ ]
147
+ },
148
+ created_at: '2023-07-18T19:00:28.098Z',
149
+ updated_at: '2023-07-18T19:00:28.099Z'
150
+ }
151
+ ]
152
+ }
153
+
154
+ function App() {
155
+ return (
156
+ <div className="min-h-screen">
157
+ <CmsLayoutShadcn inputModels={modelData} />
158
+ </div>
159
+ )
160
+ }
161
+
162
+ export default App
163
+ ```
164
+
165
+ ## 📚 组件 API
166
+
167
+ ### CmsLayoutShadcn
168
+
169
+ 主布局组件,包含侧边栏、导航和内容区域。
170
+
171
+ ```tsx
172
+ interface CmsLayoutProps {
173
+ inputModels: {
174
+ models: CmsModel[]
175
+ }
176
+ /**
177
+ * 是否跳过登录验证(免登录模式)
178
+ * 当设置为 true 时,组件将跳过所有登录检查,直接进入后台配置页面
179
+ * 适用于由使用方统一处理鉴权的场景
180
+ * @default false
181
+ */
182
+ skipAuth?: boolean
183
+ }
184
+ ```
185
+
186
+ #### Props
187
+
188
+ | 属性 | 类型 | 默认值 | 说明 |
189
+ |------|------|--------|------|
190
+ | `inputModels` | `{ models: CmsModel[] }` | - | 模型配置对象 |
191
+ | `skipAuth` | `boolean` | `false` | 是否跳过登录验证 |
192
+
193
+ #### 使用示例
194
+
195
+ ```jsx
196
+ // 标准模式(需要登录)
197
+ <CmsLayoutShadcn inputModels={modelData} />
198
+
199
+ // 免登录模式(适用于已有鉴权系统)
200
+ <CmsLayoutShadcn inputModels={modelData} skipAuth={true} />
201
+ ```
202
+
203
+ ### setSessionId
204
+
205
+ 设置会话 ID,用于多租户数据隔离。
206
+
207
+ ```typescript
208
+ import { setSessionId } from '@wecode-team/we0-cms'
209
+
210
+ // 设置 Session ID
211
+ setSessionId('tenant-123')
212
+
213
+ // 后续 API 调用会自动添加前缀
214
+ // 例如:GET /data/users → GET /data/tenant-123_users
215
+ ```
216
+
217
+ ## 🏗️ 模型配置
218
+
219
+ ### CmsModel 结构
220
+
221
+ ```typescript
222
+ interface CmsModel {
223
+ id: number
224
+ name: string // 模型显示名称
225
+ table_name: string // 数据表名
226
+ json_schema: {
227
+ fields: SchemaField[]
228
+ }
229
+ created_at: string
230
+ updated_at: string
231
+ }
232
+ ```
233
+
234
+ ### SchemaField 结构
235
+
236
+ ```typescript
237
+ interface SchemaField {
238
+ name: string // 字段名
239
+ type: string // 字段类型
240
+ comment?: string // 字段显示名称
241
+ required?: boolean // 是否必填
242
+ unique?: boolean // 是否唯一
243
+ maxLength?: number // 最大长度
244
+ defaultValue?: any // 默认值
245
+ relation?: RelationConfig // 关联配置
246
+ }
247
+ ```
248
+
249
+ ### 字段类型
250
+
251
+ | 类型 | 渲染组件 | 说明 |
252
+ |------|----------|------|
253
+ | `string` | `<Input />` | 单行文本输入 |
254
+ | `text` | `<Textarea />` | 多行文本输入 |
255
+ | `integer` | `<Input type="number" />` | 整数输入 |
256
+ | `float` | `<Input type="number" />` | 浮点数输入 |
257
+ | `boolean` | `<Switch />` | 开关切换 |
258
+ | `date` | `<Input type="date" />` | 日期选择 |
259
+ | `datetime` | `<Input type="datetime-local" />` | 日期时间选择 |
260
+ | `email` | `<Input type="email" />` | 邮箱输入 |
261
+ | `relation` | `<Select />` | 关联下拉选择 |
262
+
263
+ ### 关联字段配置
264
+
265
+ ```typescript
266
+ interface RelationConfig {
267
+ type: 'belongsTo' | 'hasMany' | 'belongsToMany'
268
+ target: string // 目标表名
269
+ foreignKey?: string // 外键字段名
270
+ displayField?: string // 下拉显示的字段
271
+ showInList?: boolean // 是否在列表中显示
272
+ }
273
+ ```
274
+
275
+ #### 示例:文章关联作者
276
+
277
+ ```javascript
278
+ {
279
+ name: 'author',
280
+ type: 'relation',
281
+ comment: '作者',
282
+ required: true,
283
+ relation: {
284
+ type: 'belongsTo',
285
+ target: 'users', // 关联 users 表
286
+ foreignKey: 'author_id', // 外键字段
287
+ displayField: 'name' // 下拉显示用户姓名
288
+ }
289
+ }
290
+ ```
291
+
292
+ ## 📡 API 配置
293
+
294
+ ### 配置 API 基础 URL
295
+
296
+ 在 `request.ts` 中配置:
297
+
298
+ ```typescript
299
+ // 创建自定义 request 实例
300
+ import axios from 'axios'
301
+
302
+ const request = axios.create({
303
+ baseURL: 'http://your-api-url/api/cms',
304
+ timeout: 10000
305
+ })
306
+
307
+ // 请求拦截器 - 自动添加 Token
308
+ request.interceptors.request.use((config) => {
309
+ const token = localStorage.getItem('cms_token')
310
+ if (token) {
311
+ config.headers.Authorization = `Bearer ${token}`
312
+ }
313
+ return config
314
+ })
315
+ ```
316
+
317
+ ### API 服务
318
+
319
+ ```typescript
320
+ import { modelApi, dataApi, authApi } from '@wecode-team/we0-cms'
321
+
322
+ // 模型 API
323
+ await modelApi.getModels()
324
+ await modelApi.createModel(data)
325
+ await modelApi.updateModel(data)
326
+ await modelApi.deleteModel(id)
327
+
328
+ // 数据 API
329
+ await dataApi.getTableData('users', { page: 1, limit: 10 })
330
+ await dataApi.createData('users', { name: 'John' })
331
+ await dataApi.updateData('users', { id: '1', name: 'Jane' })
332
+ await dataApi.deleteData('users', '1')
333
+
334
+ // 关联选项 API
335
+ await dataApi.getRelationOptions('users', { displayField: 'name' })
336
+
337
+ // 认证 API
338
+ await authApi.login({ username: 'admin', password: '123456' })
339
+ await authApi.verifyAuth()
340
+ await authApi.getCurrentUser()
341
+ await authApi.logout()
342
+ ```
343
+
344
+ ## 🎨 自定义样式
345
+
346
+ ### 覆盖 CSS 变量
347
+
348
+ ```css
349
+ :root {
350
+ --background: 0 0% 100%;
351
+ --foreground: 222.2 84% 4.9%;
352
+ --primary: 222.2 47.4% 11.2%;
353
+ --primary-foreground: 210 40% 98%;
354
+ /* ... 更多变量 */
355
+ }
356
+
357
+ .dark {
358
+ --background: 222.2 84% 4.9%;
359
+ --foreground: 210 40% 98%;
360
+ /* ... 暗色模式变量 */
361
+ }
362
+ ```
363
+
364
+ ### 扩展组件
365
+
366
+ ```jsx
367
+ import { CmsLayoutShadcn } from '@wecode-team/we0-cms'
368
+
369
+ function CustomCms() {
370
+ return (
371
+ <div className="custom-wrapper">
372
+ <header className="custom-header">
373
+ <h1>我的 CMS</h1>
374
+ </header>
375
+ <CmsLayoutShadcn inputModels={modelData} skipAuth={true} />
376
+ </div>
377
+ )
378
+ }
379
+ ```
380
+
381
+ ## 🔐 认证流程
382
+
383
+ ### 1. 登录流程
384
+
385
+ ```
386
+ 用户输入账号密码 → 调用 authApi.login() → 保存 Token 到 localStorage
387
+
388
+ 跳转到数据管理页
389
+ ```
390
+
391
+ ### 2. Token 验证
392
+
393
+ ```
394
+ 页面加载 → 检查 localStorage 中的 Token → 调用 authApi.verifyAuth()
395
+
396
+ 验证成功:显示内容
397
+ 验证失败:跳转登录页
398
+ ```
399
+
400
+ ### 3. 免登录模式
401
+
402
+ ```jsx
403
+ // 适用于已有鉴权系统的场景
404
+ <CmsLayoutShadcn inputModels={modelData} skipAuth={true} />
405
+ ```
406
+
407
+ ## 📱 响应式设计
408
+
409
+ 组件内置响应式支持:
410
+
411
+ - **桌面端**:完整侧边栏 + 内容区域
412
+ - **平板端**:可折叠侧边栏
413
+ - **移动端**:底部抽屉式导航
414
+
415
+ ## 🐛 常见问题
416
+
417
+ ### 1. 样式不生效
418
+
419
+ 确保引入了 CSS 文件:
420
+ ```jsx
421
+ import '@wecode-team/we0-cms/dist/index.css'
422
+ ```
423
+
424
+ ### 2. Tailwind 类名冲突
425
+
426
+ 确保 Tailwind 配置包含了组件库的路径:
427
+ ```javascript
428
+ content: [
429
+ './node_modules/@wecode-team/we0-cms/dist/**/*.{js,jsx}'
430
+ ]
431
+ ```
432
+
433
+ ### 3. 关联字段不显示数据
434
+
435
+ 检查模型配置中的 `relation.displayField` 是否正确设置为目标表中存在的字段。
436
+
437
+ ### 4. API 请求失败
438
+
439
+ 检查:
440
+ 1. Session ID 是否正确设置
441
+ 2. API 基础 URL 是否正确
442
+ 3. CORS 是否配置正确
443
+
444
+ ## 📄 许可证
445
+
446
+ MIT
447
+
448
+ ## 🔗 相关包
449
+
450
+ - [@wecode-team/cms-supabase-api](../cms-supabase-api) - 后端 API 包
@@ -0,0 +1,42 @@
1
+ import React from "react";
2
+ export type MessageType = "info" | "success" | "error" | "warning" | "loading";
3
+ export interface MessageArgs {
4
+ key?: React.Key;
5
+ content: React.ReactNode;
6
+ duration?: number;
7
+ type?: MessageType;
8
+ onClose?: () => void;
9
+ icon?: React.ReactNode;
10
+ className?: string;
11
+ }
12
+ interface GlobalConfig {
13
+ top: number;
14
+ duration: number;
15
+ maxCount: number;
16
+ }
17
+ type OpenArg = MessageArgs | React.ReactNode;
18
+ export interface MessageAPI {
19
+ open: (args: MessageArgs) => {
20
+ close: () => void;
21
+ };
22
+ info: (arg1: OpenArg, duration?: number, onClose?: () => void) => {
23
+ close: () => void;
24
+ };
25
+ success: (arg1: OpenArg, duration?: number, onClose?: () => void) => {
26
+ close: () => void;
27
+ };
28
+ error: (arg1: OpenArg, duration?: number, onClose?: () => void) => {
29
+ close: () => void;
30
+ };
31
+ warning: (arg1: OpenArg, duration?: number, onClose?: () => void) => {
32
+ close: () => void;
33
+ };
34
+ loading: (arg1: OpenArg, duration?: number, onClose?: () => void) => {
35
+ close: () => void;
36
+ };
37
+ destroy: (key?: React.Key) => void;
38
+ config: (cfg: Partial<GlobalConfig>) => void;
39
+ useMessage: () => [MessageAPI, React.ReactElement];
40
+ }
41
+ export declare const message: MessageAPI;
42
+ export default message;
@@ -0,0 +1,7 @@
1
+ import React from "react";
2
+ import { SchemaField, SupabaseFilter } from "../../services";
3
+ export declare function DynamicFilters(props: {
4
+ fields: SchemaField[];
5
+ value: SupabaseFilter[];
6
+ onChange: (next: SupabaseFilter[]) => void;
7
+ }): React.JSX.Element;
@@ -0,0 +1,11 @@
1
+ import * as React from "react";
2
+ export declare function JsonViewerCell({ value, title }: {
3
+ value: any;
4
+ title?: string;
5
+ }): React.JSX.Element;
6
+ export declare function JsonEditorField(props: {
7
+ id: string;
8
+ value: string;
9
+ required?: boolean;
10
+ onChange: (next: string) => void;
11
+ }): React.JSX.Element;
@@ -0,0 +1,19 @@
1
+ export type ParsedJsonResult = {
2
+ ok: true;
3
+ value: any;
4
+ pretty: string;
5
+ compact: string;
6
+ } | {
7
+ ok: false;
8
+ message: string;
9
+ pretty: string;
10
+ compact: string;
11
+ };
12
+ export declare function parseJsonLike(textOrValue: any): ParsedJsonResult;
13
+ export declare function formatJsonText(text: string, indentSize?: number): {
14
+ ok: true;
15
+ formatted: string;
16
+ } | {
17
+ ok: false;
18
+ message: string;
19
+ };
@@ -0,0 +1,16 @@
1
+ import React from "react";
2
+ import { CmsModel } from "./types";
3
+ interface CmsLayoutProps {
4
+ inputModels: {
5
+ models: CmsModel[];
6
+ };
7
+ /**
8
+ * 是否跳过登录验证(免登录模式)
9
+ * 当设置为 true 时,组件将跳过所有登录检查,直接进入后台配置页面
10
+ * 适用于由使用方统一处理鉴权的场景
11
+ * @default false
12
+ */
13
+ skipAuth?: boolean;
14
+ }
15
+ export default function CmsLayoutShadcn({ inputModels, skipAuth }: CmsLayoutProps): React.JSX.Element;
16
+ export {};
@@ -0,0 +1,2 @@
1
+ import React from "react";
2
+ export default function AdminPage(): React.JSX.Element;
@@ -0,0 +1,2 @@
1
+ import React from "react";
2
+ export default function DataListPage(): React.JSX.Element;
@@ -0,0 +1,3 @@
1
+ import React from "react";
2
+ import { CmsModel } from '../../services';
3
+ export default function DataManagePage(nowModel: CmsModel): React.JSX.Element;
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ interface LoginPageProps {
3
+ onLoginSuccess?: (token: string, user: any) => void;
4
+ }
5
+ export default function LoginPage({ onLoginSuccess }: LoginPageProps): React.JSX.Element;
6
+ export {};
@@ -0,0 +1,2 @@
1
+ import React from "react";
2
+ export default function ModelCreatePage(): React.JSX.Element;
@@ -0,0 +1,2 @@
1
+ import React from "react";
2
+ export default function TestJsonPage(): React.JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { RouteConfig } from "./routes";
2
+ import { CmsModel } from "./types";
3
+ export declare function parseModelsToRoutes(inputModels: {
4
+ models: CmsModel[];
5
+ }): RouteConfig[];
@@ -0,0 +1,12 @@
1
+ import React from "react";
2
+ import { CmsModel } from "./types";
3
+ export interface RouteConfig {
4
+ path: string;
5
+ name: string;
6
+ icon: React.ReactNode;
7
+ component: React.ComponentType;
8
+ routes?: RouteConfig[];
9
+ }
10
+ export declare const cmsRoutes: (inputModels: {
11
+ models: CmsModel[];
12
+ }) => RouteConfig[];
@@ -0,0 +1,69 @@
1
+ export type RelationType = 'belongsTo' | 'hasMany' | 'belongsToMany';
2
+ export interface RelationConfig {
3
+ /**
4
+ * 关系类型
5
+ * - belongsTo: 多对一,当前表存储外键 (如:文章表的 author_id 关联作者表)
6
+ * - hasMany: 一对多,目标表存储外键 (如:作者表关联多篇文章)
7
+ * - belongsToMany: 多对多,需要中间表 (如:文章和标签)
8
+ */
9
+ type: RelationType;
10
+ /**
11
+ * 目标表名
12
+ */
13
+ target: string;
14
+ /**
15
+ * 外键字段名
16
+ * - belongsTo: 当前表中的外键字段,默认为 ${target}_id
17
+ * - hasMany: 目标表中的外键字段,默认为 ${currentTable}_id
18
+ */
19
+ foreignKey?: string;
20
+ /**
21
+ * 目标表的主键字段,默认为 'id'
22
+ */
23
+ targetKey?: string;
24
+ /**
25
+ * 多对多关系的中间表名 (仅 belongsToMany 需要)
26
+ */
27
+ through?: string;
28
+ /**
29
+ * 用于下拉选项显示的字段名,默认为 'name' 或 'title'
30
+ */
31
+ displayField?: string;
32
+ /**
33
+ * 是否在列表中显示关联数据
34
+ */
35
+ showInList?: boolean;
36
+ }
37
+ export interface RelationOption {
38
+ id: number | string;
39
+ label: string;
40
+ [key: string]: any;
41
+ }
42
+ export interface SchemaField {
43
+ name: string;
44
+ /**
45
+ * 字段类型
46
+ * - 基础类型: string, text, integer, float, boolean, date, datetime, json, email
47
+ * - 关系类型: relation (需要配置 relation 属性)
48
+ */
49
+ type: string;
50
+ required?: boolean;
51
+ unique?: boolean;
52
+ maxLength?: number;
53
+ defaultValue?: any;
54
+ comment?: string;
55
+ /**
56
+ * 关系配置 (当 type 为 'relation' 时必填)
57
+ */
58
+ relation?: RelationConfig;
59
+ }
60
+ export interface CmsModel {
61
+ id: number;
62
+ name: string;
63
+ table_name: string;
64
+ json_schema: {
65
+ fields: SchemaField[];
66
+ };
67
+ created_at: string;
68
+ updated_at: string;
69
+ }
@@ -0,0 +1,9 @@
1
+ import * as React from "react";
2
+ import { type VariantProps } from "class-variance-authority";
3
+ declare const badgeVariants: (props?: ({
4
+ variant?: "default" | "destructive" | "outline" | "secondary" | null | undefined;
5
+ } & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
6
+ export interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {
7
+ }
8
+ declare function Badge({ className, variant, ...props }: BadgeProps): React.JSX.Element;
9
+ export { Badge, badgeVariants };
@@ -0,0 +1,11 @@
1
+ import * as React from "react";
2
+ import { type VariantProps } from "class-variance-authority";
3
+ declare const buttonVariants: (props?: ({
4
+ variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | null | undefined;
5
+ size?: "default" | "sm" | "lg" | "icon" | null | undefined;
6
+ } & import("class-variance-authority/dist/types").ClassProp) | undefined) => string;
7
+ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
8
+ asChild?: boolean;
9
+ }
10
+ declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
11
+ export { Button, buttonVariants };