Appearance
Pxcharts Ultra 技术文档
体验地址:ultra版多维表格编辑器
🎯 项目概述
Pxcharts Ultra 是一个基于 React 18+ 构建的现代化多表格编辑器,集成了 AI 助手、协作编辑(ui层)、甘特图、看板视图等多种功能。项目采用 TypeScript + React + Tailwind CSS 技术栈,提供了完整的表格数据管理解决方案。
TIP
注意:ultra是在plus版本基础上构建的更复杂的多维表格编辑器,所以部分实现文档可以参考plus版本。
项目特色
- 企业级架构: 采用现代化的前端架构设计,支持大规模应用
- AI 驱动: 集成多种 AI 交互层,可以轻松接入AI模型,提供智能数据分析和处理
- 性能优化: 虚拟化渲染、懒加载等性能优化技术
- 高度可定制: 模块化设计,易于扩展和定制
✨ 功能特点
🗄️ 核心功能
- 多表格管理: 支持创建、编辑、删除多个数据表格
- 多种视图模式: 表格视图、看板视图、甘特图、图表仪表板
- 智能表单生成器: 可视化拖拽式表单设计,支持多种字段类型
- AI 智能助手: 集成多种 AI 模型交互UI,支持数据分析、数据生成等
- 实时协作UI控件: 多用户实时编辑、评论、在线状态显示的UI层界面
- 数据导入导出: 支持 Excel、CSV 格式的导入导出
🚀 高级特性
- 性能优化: 虚拟化渲染、懒加载、性能测试工具
- 甘特图管理: 项目任务时间线管理、依赖关系、进度跟踪
- 图表分析: 多种图表类型、自定义仪表板布局
- 模板系统: 丰富的预设模板,快速创建常用表格
- 主题定制: 支持明暗主题切换
📁 目录结构介绍
multi-table-ultra/
├── app/ # Next.js 应用主目录
│ ├── globals.css # 全局样式文件
│ ├── layout.tsx # 应用布局组件
│ └── page.tsx # 主页面组件
├── components/ # 组件目录
│ ├── ui/ # 基础 UI 组件库
│ │ ├── button.tsx # 按钮组件
│ │ ├── dialog.tsx # 对话框组件
│ │ ├── form.tsx # 表单组件
│ │ ├── sidebar.tsx # 侧边栏组件
│ │ └── ... # 其他 UI 组件
│ ├── table-editor.tsx # 主表格编辑器
│ ├── form-generator.tsx # 表单生成器
│ ├── ai-assistant.tsx # AI 助手组件
│ ├── gantt-view.tsx # 甘特图视图
│ ├── kanban-view.tsx # 看板视图
│ ├── collaboration-panel.tsx # 协作面板
│ ├── chart-dashboard.tsx # 图表仪表板
│ └── ... # 其他功能组件
├── lib/ # 核心库文件
│ ├── store.ts # Zustand 状态管理
│ ├── types.ts # TypeScript 类型定义
│ ├── ai-service.ts # AI 服务接口
│ ├── collaboration-service.ts # 协作服务
│ ├── gantt-utils.ts # 甘特图工具函数
│ └── ... # 其他工具库
├── hooks/ # 自定义 React Hooks
├── styles/ # 样式文件
├── public/ # 静态资源
├── package.json # 项目依赖配置
├── next.config.mjs # Next.js 配置
├── tailwind.config.ts # Tailwind CSS 配置
└── tsconfig.json # TypeScript 配置
目录说明
app/
目录
- globals.css: 全局样式定义,包含 CSS 变量和基础样式
- layout.tsx: 应用根布局,包含主题提供者和全局配置
- page.tsx: 主页面入口,渲染 TableEditor 组件
components/
目录
- ui/: 基础 UI 组件库,基于 Radix UI 构建
- table-editor.tsx: 主表格编辑器,整合所有功能模块
- form-generator.tsx: 智能表单生成器,支持拖拽式设计
- ai-assistant.tsx: AI 助手组件,集成多种 AI 模型
- gantt-view.tsx: 甘特图视图,支持项目管理功能
- kanban-view.tsx: 看板视图,支持任务流程管理
- collaboration-panel.tsx: 协作面板,实时协作功能
lib/
目录
- store.ts: Zustand 状态管理,包含所有业务逻辑
- types.ts: TypeScript 类型定义,确保类型安全
- ai-service.ts: AI 服务接口,支持多种 AI 模型
- collaboration-service.ts: 协作服务,实时数据同步
- gantt-utils.ts: 甘特图工具函数,时间计算和布局
🛠️ 技术栈详解
🎨 前端框架
Next.js 14
- App Router: 使用最新的 App Router 架构
- Server Components: 支持服务端组件渲染
- Streaming: 流式渲染提升用户体验
- Turbopack: 快速的开发服务器
React 18
- Concurrent Features: 并发特性支持
- Automatic Batching: 自动批处理优化
- Suspense: 异步组件加载
- Strict Mode: 严格模式开发
🎯 状态管理
Zustand
typescript
// 轻量级状态管理
import { create } from 'zustand'
const useStore = create((set) => ({
count: 0,
increment: () => set((state) => ({ count: state.count + 1 })),
decrement: () => set((state) => ({ count: state.count - 1 })),
}))
优势:
- 体积小,bundle size 仅 1.5KB
- API 简洁,学习成本低
- 支持 TypeScript
- 内置持久化中间件
React Hook Form
typescript
// 高性能表单处理
import { useForm } from 'react-hook-form'
const { register, handleSubmit, formState: { errors } } = useForm()
const onSubmit = (data) => {
console.log(data)
}
特性:
- 零依赖重渲染
- 内置验证
- 支持复杂表单
- 性能优化
🎨 UI 组件库
Radix UI
- 无样式: 只提供功能,样式完全自定义
- 可访问性: 符合 WCAG 标准
- 键盘导航: 完整的键盘操作支持
- 状态管理: 内置状态管理逻辑
Tailwind CSS
typescript
// 原子化 CSS 类
<div className="
flex items-center justify-between
p-4 bg-white rounded-lg shadow-md
hover:shadow-lg transition-shadow
">
{/* 内容 */}
</div>
优势:
- 快速开发
- 响应式设计
- 自定义主题
- 生产环境优化
📊 数据可视化
Recharts
typescript
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip } from 'recharts'
<LineChart width={600} height={300} data={data}>
<CartesianGrid strokeDasharray="3 3" />
<XAxis dataKey="name" />
<YAxis />
<Tooltip />
<Line type="monotone" dataKey="value" stroke="#8884d8" />
</LineChart>
React Grid Layout
typescript
import GridLayout from 'react-grid-layout'
<GridLayout
className="layout"
layout={layout}
cols={12}
rowHeight={30}
width={1200}
>
{items.map(item => (
<div key={item.i}>{item.content}</div>
))}
</GridLayout>
🤖 AI 集成
多模型支持
- OpenAI: GPT-3.5/4 系列模型
- DeepSeek: 深度求索模型
- 通义千问: 阿里云 AI 模型
- Claude: Anthropic AI 模型
- Gemini: Google AI 模型
智能功能
- 数据分析: 自动数据洞察
- 报表生成: 智能报表创建
- 自然语言查询: 用自然语言操作数据
- 异常检测: 自动发现数据异常
🏗️ 核心架构设计
状态管理架构
主要状态结构
typescript
interface TableStore {
tables: Table[] // 表格列表
currentTableId: string | null // 当前表格ID
currentView: ViewType // 当前视图类型
searchTerm: string // 搜索关键词
filters: Filter[] // 过滤器
selectedRecords: Set<string> // 选中的记录
dashboardLayouts: DashboardLayout[] // 仪表板布局
templates: Template[] // 模板列表
ganttSettings: GanttViewSettings[] // 甘特图设置
}
状态更新流程
typescript
// 状态更新示例
const updateRecord = (id: string, data: any) => {
set((state) => ({
tables: state.tables.map(table => ({
...table,
records: table.records?.map(record =>
record.id === id
? { ...record, data: { ...record.data, ...data } }
: record
)
}))
}))
}
组件架构
分层设计
- 容器组件: 负责状态管理和业务逻辑
- 展示组件: 纯 UI 组件,通过 props 接收数据
- 复合组件: 组合多个基础组件的复杂功能组件
组件通信
typescript
// 父子组件通信
interface ParentProps {
onDataChange: (data: any) => void
}
// 兄弟组件通信
const useSharedState = create((set) => ({
sharedData: null,
setSharedData: (data: any) => set({ sharedData: data })
}))
数据流架构
用户操作 → 组件事件 → Store Action → 状态更新 → 组件重渲染
↓
AI 服务 → 数据处理 → 结果展示
↓
协作服务 → 实时同步 → 多用户状态
数据流示例
typescript
// 1. 用户操作
const handleEdit = (recordId: string, newData: any) => {
// 2. 调用 Store Action
updateRecord(recordId, newData)
// 3. 同步到协作服务
collaborationService.syncUpdate(recordId, newData)
// 4. 触发 AI 分析
aiService.analyzeChange(recordId, newData)
}
🔧 二次开发指南
1. 安装依赖
bash
pnpm install
# 或
npm install
2. 启动开发服务器
bash
pnpm dev
# 或
npm run dev
3. 环境变量配置(可选)
bash
# .env.local
NEXT_PUBLIC_AI_API_KEY=your_api_key
NEXT_PUBLIC_COLLABORATION_WS_URL=ws://your-websocket-server
NEXT_PUBLIC_APP_ENV=development
🔧 添加新功能
1. 创建新的视图类型
步骤 1: 在 types.ts
中添加新视图类型
typescript
export type ViewType = "table" | "kanban" | "gantt" | "your-view"
export interface YourViewSettings {
id: string
tableId: string
config: YourViewConfig
updatedAt: string
}
步骤 2: 在 store.ts
中添加相关状态和方法
typescript
interface TableStore {
// ... 现有代码
yourViewSettings: YourViewSettings[]
// 添加新方法
updateYourViewSettings: (tableId: string, settings: YourViewSettings) => void
getYourViewSettings: (tableId: string) => YourViewSettings | undefined
}
// 实现方法
updateYourViewSettings: (tableId: string, settings: YourViewSettings) => {
set((state) => ({
yourViewSettings: state.yourViewSettings.map(s =>
s.tableId === tableId ? settings : s
)
}))
}
步骤 3: 创建视图组件
typescript
// components/your-view.tsx
import React from 'react'
import { useTableStore } from '@/lib/store'
import type { Table } from '@/lib/types'
interface YourViewProps {
table: Table
}
export function YourView({ table }: YourViewProps) {
const { yourViewSettings, updateYourViewSettings } = useTableStore()
// 实现视图逻辑
return (
<div className="your-view">
{/* 你的视图内容 */}
</div>
)
}
步骤 4: 在主编辑器中集成
typescript
// components/table-editor.tsx
import { YourView } from './your-view'
// 在视图切换逻辑中添加
const renderCurrentView = () => {
switch (currentView) {
case 'your-view':
return <YourView table={currentTable} />
// ... 其他视图
}
}
2. 扩展字段类型
步骤 1: 在 types.ts
中添加新字段类型
typescript
export type FieldType = "text" | "textarea" | "number" | "your-field-type"
export interface YourFieldConfig {
customOption1?: string
customOption2?: number
}
步骤 2: 在 form-generator.tsx
中添加字段配置
typescript
const FIELD_TYPES = [
// ... 现有字段类型
{
type: "your-field-type",
label: "你的字段",
icon: YourIcon,
category: "自定义类型",
component: YourFieldComponent
}
]
步骤 3: 创建字段组件
typescript
// components/fields/your-field.tsx
interface YourFieldProps {
value: any
onChange: (value: any) => void
config: YourFieldConfig
}
export function YourField({ value, onChange, config }: YourFieldProps) {
return (
<div className="your-field">
{/* 字段渲染逻辑 */}
</div>
)
}
3. 集成新的 AI 服务
步骤 1: 在 ai-service.ts
中添加新服务
typescript
export const aiService = {
// ... 现有服务
yourService: async (prompt: string, config: any) => {
try {
const response = await fetch('/api/your-ai-service', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prompt, config })
})
if (!response.ok) {
throw new Error('AI service request failed')
}
return await response.json()
} catch (error) {
console.error('Your AI service error:', error)
throw error
}
}
}
步骤 2: 创建 API 路由
typescript
// app/api/your-ai-service/route.ts
import { NextRequest, NextResponse } from 'next/server'
export async function POST(request: NextRequest) {
try {
const { prompt, config } = await request.json()
// 调用你的 AI 服务
const result = await callYourAIService(prompt, config)
return NextResponse.json(result)
} catch (error) {
return NextResponse.json(
{ error: 'AI service error' },
{ status: 500 }
)
}
}
🎨 自定义主题
1. 修改 Tailwind 配置
typescript
// tailwind.config.ts
export default {
theme: {
extend: {
colors: {
// 添加自定义颜色
'custom-primary': '#your-color',
'custom-secondary': '#your-secondary-color',
},
spacing: {
'18': '4.5rem',
'88': '22rem',
},
animation: {
'bounce-slow': 'bounce 2s infinite',
}
}
}
}
2. 创建主题组件
typescript
// components/theme-provider.tsx
'use client'
import { createContext, useContext, useEffect, useState } from 'react'
type Theme = 'light' | 'dark' | 'system'
interface ThemeContextType {
theme: Theme
setTheme: (theme: Theme) => void
}
const ThemeContext = createContext<ThemeContextType | undefined>(undefined)
export function ThemeProvider({ children }: { children: React.ReactNode }) {
const [theme, setTheme] = useState<Theme>('system')
useEffect(() => {
const root = window.document.documentElement
root.classList.remove('light', 'dark')
if (theme === 'system') {
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark'
: 'light'
root.classList.add(systemTheme)
} else {
root.classList.add(theme)
}
}, [theme])
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
{children}
</ThemeContext.Provider>
)
}
export const useTheme = () => {
const context = useContext(ThemeContext)
if (context === undefined) {
throw new Error('useTheme must be used within a ThemeProvider')
}
return context
}
📱 响应式适配
1. 使用移动端 Hook
typescript
// hooks/use-mobile.tsx
import { useState, useEffect } from 'react'
export function useMobile() {
const [isMobile, setIsMobile] = useState(false)
useEffect(() => {
const checkMobile = () => {
setIsMobile(window.innerWidth < 768)
}
checkMobile()
window.addEventListener('resize', checkMobile)
return () => window.removeEventListener('resize', checkMobile)
}, [])
return isMobile
}
2. 响应式组件示例
typescript
import { useMobile } from '@/hooks/use-mobile'
export function ResponsiveComponent() {
const isMobile = useMobile()
return (
<div className={`
${isMobile ? 'mobile-layout' : 'desktop-layout'}
p-4 md:p-6 lg:p-8
grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3
`}>
{/* 响应式内容 */}
</div>
)
}
🔌 插件系统
1. 创建插件接口
typescript
// lib/plugin-types.ts
export interface Plugin {
id: string
name: string
version: string
description: string
author: string
initialize: () => void | Promise<void>
destroy: () => void
onTableCreate?: (table: Table) => void
onRecordUpdate?: (record: Record) => void
}
export interface PluginContext {
store: any
api: any
utils: any
}
2. 插件管理器
typescript
// lib/plugin-manager.ts
export class PluginManager {
private plugins: Map<string, Plugin> = new Map()
private context: PluginContext
constructor(context: PluginContext) {
this.context = context
}
async register(plugin: Plugin) {
try {
await plugin.initialize()
this.plugins.set(plugin.id, plugin)
console.log(`Plugin ${plugin.name} registered successfully`)
} catch (error) {
console.error(`Failed to register plugin ${plugin.name}:`, error)
}
}
unregister(pluginId: string) {
const plugin = this.plugins.get(pluginId)
if (plugin) {
plugin.destroy()
this.plugins.delete(pluginId)
console.log(`Plugin ${plugin.name} unregistered`)
}
}
getPlugin(pluginId: string): Plugin | undefined {
return this.plugins.get(pluginId)
}
getAllPlugins(): Plugin[] {
return Array.from(this.plugins.values())
}
// 触发插件事件
triggerEvent(eventName: string, data: any) {
this.plugins.forEach(plugin => {
if (plugin[eventName as keyof Plugin]) {
try {
(plugin as any)[eventName](data)
} catch (error) {
console.error(`Plugin ${plugin.name} event error:`, error)
}
}
})
}
}
3. 使用插件系统(仅供扩展参考)
typescript
// 在主应用中初始化插件管理器
import { PluginManager } from '@/lib/plugin-manager'
const pluginManager = new PluginManager({
store: useTableStore,
api: apiService,
utils: utilityFunctions
})
// 注册插件
await pluginManager.register({
id: 'my-plugin',
name: 'My Plugin',
version: '1.0.0',
description: 'A custom plugin',
author: 'Your Name',
initialize: () => {
console.log('My plugin initialized')
},
destroy: () => {
console.log('My plugin destroyed')
}
})
🔍 实现原理详解
🗄️ 数据存储机制
1. 本地存储
typescript
// 使用 Zustand 的 persist 中间件
export const useTableStore = create<TableStore>()(
persist(
(set, get) => ({
// ... store 实现
}),
{
name: 'table-storage', // localStorage 键名
version: 1, // 版本号,用于数据迁移
migrate: (persistedState: any, version: number) => {
// 数据迁移逻辑
if (version === 0) {
return migrateFromV0ToV1(persistedState)
}
return persistedState
}
}
)
)
2. 状态同步
typescript
// 状态更新流程
const updateRecord = (id: string, data: any) => {
set((state) => {
// 创建新状态
const newState = {
...state,
tables: state.tables.map(table => ({
...table,
records: table.records?.map(record =>
record.id === id
? {
...record,
data: { ...record.data, ...data },
updatedAt: new Date().toISOString()
}
: record
)
}))
}
// 触发插件事件
pluginManager.triggerEvent('onRecordUpdate', { id, data })
return newState
})