@wecode-team/we0-cms
v1.1.11
Published
A CMS component for React applications with shadcn/ui
Downloads
1,666
Readme
@wecode-team/we0-cms
一个基于 React 的动态 CMS 前端组件库,支持 shadcn/ui 风格的现代化 UI,与 @wecode-team/cms-supabase-api 配合使用实现完整的内容管理系统。
📖 设计理念
核心思想
本包的核心理念是 "配置驱动的 CMS UI":
- 模型驱动 UI:根据 JSON Schema 模型配置自动生成表单和表格
- 零代码管理:无需编写代码,通过配置即可实现数据的增删改查
- 关系可视化:支持关联字段的下拉选择和数据展示
- 多租户支持:通过 Session ID 实现数据隔离
架构设计
┌─────────────────────────────────────────────────────────────┐
│ CmsLayoutShadcn │
│ (主布局组件) │
├─────────────────────────────────────────────────────────────┤
│ UI Components (shadcn/ui) │
│ ├── Sidebar 侧边栏导航 │
│ ├── DataTable 数据表格 │
│ ├── Dialog 弹窗表单 │
│ └── Form Controls 表单控件 │
├─────────────────────────────────────────────────────────────┤
│ Pages (页面组件) │
│ ├── LoginPage 登录页面 │
│ ├── DataListPage 数据列表页 │
│ └── DataManagePage 数据管理页(按模型) │
├─────────────────────────────────────────────────────────────┤
│ Services (服务层) │
│ ├── modelApi 模型管理 API │
│ ├── dataApi 数据操作 API │
│ └── authApi 认证 API │
├─────────────────────────────────────────────────────────────┤
│ Request Layer (请求层) │
│ └── request.ts Axios 封装,自动添加 Token │
└─────────────────────────────────────────────────────────────┘数据流
用户操作 → UI 组件 → Services API → HTTP 请求 → 后端 API → Supabase
↓
用户界面 ← UI 更新 ← State 更新 ← API 响应 ←🚀 安装
npm install @wecode-team/we0-cms
# 或
pnpm add @wecode-team/we0-cms
# 或
yarn add @wecode-team/we0-cms📋 依赖
Peer Dependencies(必须安装)
{
"react": "^18.2.0",
"react-dom": "^18.2.0"
}内置依赖
@radix-ui/*- 无障碍 UI 原语lucide-react- 图标库tailwind-merge- Tailwind 类名合并class-variance-authority- 变体样式管理dayjs- 日期处理
🔧 快速开始
第一步:配置 Tailwind CSS
确保你的项目已配置 Tailwind CSS:
// tailwind.config.js
module.exports = {
content: [
'./src/**/*.{js,jsx,ts,tsx}',
'./node_modules/@wecode-team/we0-cms/dist/**/*.{js,jsx}'
],
theme: {
extend: {}
},
plugins: []
}第二步:引入样式
import '@wecode-team/we0-cms/dist/index.css'第三步:使用组件
import React from 'react'
import { CmsLayoutShadcn, setSessionId } from '@wecode-team/we0-cms'
import '@wecode-team/we0-cms/dist/index.css'
// 设置 Session ID(用于多租户隔离)
setSessionId('your-session-id')
// 定义模型配置
const modelData = {
models: [
{
id: 1,
name: '用户模型',
table_name: 'users',
json_schema: {
fields: [
{
name: 'name',
type: 'string',
comment: '用户姓名',
required: true,
maxLength: 100
},
{
name: 'email',
type: 'email',
unique: true,
comment: '用户邮箱',
required: true
},
{
name: 'age',
type: 'integer',
comment: '年龄',
required: false
}
]
},
created_at: '2023-07-18T19:00:28.098Z',
updated_at: '2023-07-18T19:00:28.099Z'
}
]
}
function App() {
return (
<div className="min-h-screen">
<CmsLayoutShadcn inputModels={modelData} />
</div>
)
}
export default App📚 组件 API
CmsLayoutShadcn
主布局组件,包含侧边栏、导航和内容区域。
interface CmsLayoutProps {
inputModels: {
models: CmsModel[]
}
/**
* 是否跳过登录验证(免登录模式)
* 当设置为 true 时,组件将跳过所有登录检查,直接进入后台配置页面
* 适用于由使用方统一处理鉴权的场景
* @default false
*/
skipAuth?: boolean
}Props
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| inputModels | { models: CmsModel[] } | - | 模型配置对象 |
| skipAuth | boolean | false | 是否跳过登录验证 |
使用示例
// 标准模式(需要登录)
<CmsLayoutShadcn inputModels={modelData} />
// 免登录模式(适用于已有鉴权系统)
<CmsLayoutShadcn inputModels={modelData} skipAuth={true} />setSessionId
设置会话 ID,用于多租户数据隔离。
import { setSessionId } from '@wecode-team/we0-cms'
// 设置 Session ID
setSessionId('tenant-123')
// 后续 API 调用会自动添加前缀
// 例如:GET /data/users → GET /data/tenant-123_users🏗️ 模型配置
CmsModel 结构
interface CmsModel {
id: number
name: string // 模型显示名称
table_name: string // 数据表名
json_schema: {
fields: SchemaField[]
}
created_at: string
updated_at: string
}SchemaField 结构
interface SchemaField {
name: string // 字段名
type: string // 字段类型
comment?: string // 字段显示名称
required?: boolean // 是否必填
unique?: boolean // 是否唯一
maxLength?: number // 最大长度
defaultValue?: any // 默认值
relation?: RelationConfig // 关联配置
editable?: boolean // 是否允许在后台编辑(默认 true;false=不可编辑)
readOnly?: boolean // 兼容字段:readOnly=true 等价于 editable=false
}字段不可编辑(协议层)
当你希望某些字段(如 created_at、updated_at、owner_id、token)在后台 只展示不允许修改 时,可以在字段上标记:
editable: false(推荐)- 或
readOnly: true(兼容写法)
前端行为:
- 表单控件会被禁用
- create/update 提交时会自动跳过该字段(不会传到后端)
示例:
{
name: "created_at",
type: "datetime",
comment: "创建时间",
readOnly: true
},
{
name: "owner_id",
type: "string",
comment: "归属用户",
editable: false
}字段类型
| 类型 | 渲染组件 | 说明 |
|------|----------|------|
| string | <Input /> | 单行文本输入 |
| text | <Textarea /> | 多行文本输入 |
| integer | <Input type="number" /> | 整数输入 |
| float | <Input type="number" /> | 浮点数输入 |
| boolean | <Switch /> | 开关切换 |
| date | <Input type="date" /> | 日期选择 |
| datetime | <Input type="datetime-local" /> | 日期时间选择 |
| email | <Input type="email" /> | 邮箱输入 |
| relation | <Select /> | 关联下拉选择 |
关联字段配置
interface RelationConfig {
type: 'belongsTo' | 'hasMany' | 'belongsToMany'
target: string // 目标表名
foreignKey?: string // 外键字段名
displayField?: string // 下拉显示的字段
showInList?: boolean // 是否在列表中显示
}示例:文章关联作者
{
name: 'author',
type: 'relation',
comment: '作者',
required: true,
relation: {
type: 'belongsTo',
target: 'users', // 关联 users 表
foreignKey: 'author_id', // 外键字段
displayField: 'name' // 下拉显示用户姓名
}
}📡 API 配置
配置 API 基础 URL
在 request.ts 中配置:
// 创建自定义 request 实例
import axios from 'axios'
const request = axios.create({
baseURL: 'http://your-api-url/api/cms',
timeout: 10000
})
// 请求拦截器 - 自动添加 Token
request.interceptors.request.use((config) => {
const token = localStorage.getItem('cms_token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
})API 服务
import { modelApi, dataApi, authApi } from '@wecode-team/we0-cms'
// 模型 API
await modelApi.getModels()
await modelApi.createModel(data)
await modelApi.updateModel(data)
await modelApi.deleteModel(id)
// 数据 API
await dataApi.getTableData('users', { page: 1, limit: 10 })
await dataApi.createData('users', { name: 'John' })
await dataApi.updateData('users', { id: '1', name: 'Jane' })
await dataApi.deleteData('users', '1')
// 关联选项 API
await dataApi.getRelationOptions('users', { displayField: 'name' })
// 认证 API
await authApi.login({ username: 'admin', password: '123456' })
await authApi.verifyAuth()
await authApi.getCurrentUser()
await authApi.logout()🎨 自定义样式
覆盖 CSS 变量
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
/* ... 更多变量 */
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
/* ... 暗色模式变量 */
}扩展组件
import { CmsLayoutShadcn } from '@wecode-team/we0-cms'
function CustomCms() {
return (
<div className="custom-wrapper">
<header className="custom-header">
<h1>我的 CMS</h1>
</header>
<CmsLayoutShadcn inputModels={modelData} skipAuth={true} />
</div>
)
}🔐 认证流程
1. 登录流程
用户输入账号密码 → 调用 authApi.login() → 保存 Token 到 localStorage
↓
跳转到数据管理页2. Token 验证
页面加载 → 检查 localStorage 中的 Token → 调用 authApi.verifyAuth()
↓
验证成功:显示内容
验证失败:跳转登录页3. 免登录模式
// 适用于已有鉴权系统的场景
<CmsLayoutShadcn inputModels={modelData} skipAuth={true} />📱 响应式设计
组件内置响应式支持:
- 桌面端:完整侧边栏 + 内容区域
- 平板端:可折叠侧边栏
- 移动端:底部抽屉式导航
🐛 常见问题
1. 样式不生效
确保引入了 CSS 文件:
import '@wecode-team/we0-cms/dist/index.css'2. Tailwind 类名冲突
确保 Tailwind 配置包含了组件库的路径:
content: [
'./node_modules/@wecode-team/we0-cms/dist/**/*.{js,jsx}'
]3. 关联字段不显示数据
检查模型配置中的 relation.displayField 是否正确设置为目标表中存在的字段。
4. API 请求失败
检查:
- Session ID 是否正确设置
- API 基础 URL 是否正确
- CORS 是否配置正确
📄 许可证
MIT
🔗 相关包
- @wecode-team/cms-supabase-api - 后端 API 包
