npm package: @lonersyk/record-grid
Description: 企业级多维表格组件 - 完全自包含，Gantt 可选
Author: david.yang
Latest version: 1.0.32


# 仅用于自己项目测试 ，不适合当公组件引入
# RecordGrid 多维表格组件

企业级多维表格组件，基于 AG Grid Enterprise 构建，提供强大的数据展示和编辑能力。

> 📖 **第三方系统使用指南**：详细的使用说明请查看 [USAGE_GUIDE.md](./USAGE_GUIDE.md)


### 完全自包含设计

RecordGrid 采用**完全自包含设计**，**所有依赖都已打包在 `dist` 中**：

✅ **已包含**（无需安装）:
- antd（完整 UI 库）
- ag-grid-community、ag-grid-enterprise、ag-grid-react
- @tanstack/react-query
- lodash、dayjs、moment
- @ant-design/icons、@ant-design/pro-*
- file-saver、xlsx、react-big-calendar
- ...所有其他依赖

❗ **仅需这 2 个**:

```bash
# 只需确保有 React（大多数项目已有）
npm install react react-dom
```

**就这么简单！** 不需要安装 antd、ag-grid、react-query 等任何其他依赖。

> 💡 **提示**：
> - RecordGrid 内部已包含并配置了 React Query 和 Ant Design，无需额外配置
> - 如果使用 **Gantt 功能**，需要额外配置 `@/components/gantt` 路径别名（见常见问题）
> - 详细说明请参考 [INSTALLATION_GUIDE.md](./INSTALLATION_GUIDE.md)

## 📖 快速开始

### 1. 初始化服务

在应用启动时初始化必要的服务：

```javascript
// app.js
import RecordGrid from '@streams/record-grid'
import '@streams/record-grid/dist/index.css'
import * as DataService from './services/DataService'
import { history } from 'your-router'

// 初始化（应用启动时调用一次）
RecordGrid.initialize({
  // 数据服务（必需）
  dataService: DataService,
  
  // 权限服务（可选）
  authService: {
    check: (auth) => {
      // 你的权限检查逻辑
      return true
    },
    userInfo: {
      username: 'user',
      type: 'user'
    },
    isAdmin: false
  },
  
  // 路由服务（可选）
  routeService: {
    push: (path) => history.push(path)
  }
})
```

### 2. 使用组件

**方式一：使用 RecordGridServiceProvider（推荐，支持多实例）**

```javascript
import RecordGrid, { RecordGridServiceProvider } from '@streams/record-grid'
import '@streams/record-grid/dist/index.css'
import * as DataService from './services/DataService'

function MyComponent() {
  const authService = {
    check: (auth) => authInfo?.check?.(auth),
    userInfo: () => userInfo || {},
    getAppInfo: () => appInfo
  }

  return (
    <RecordGridServiceProvider
      dataService={DataService}
      authService={authService}
    >
      <div style={{ height: '600px' }}>
        <RecordGrid
          subjectName="your-subject-name"
          pagination={true}
          readonly={false}
        />
      </div>
    </RecordGridServiceProvider>
  )
}
```

**方式二：全局初始化（适用于单实例场景）**

```javascript
import RecordGrid from '@streams/record-grid'
import '@streams/record-grid/dist/index.css'

function MyComponent() {
  return (
    <div style={{ height: '600px' }}>
      <RecordGrid
        subjectName="your-subject-name"
        pagination={true}
        readonly={false}
      />
    </div>
  )
}
```

## 🎯 DataService 接口规范

你的项目必须实现以下接口（16个核心方法）：

```javascript
// services/DataService.js

// Subject 相关
export async function loadSubject(name) {
  // 返回格式: { _id, name, label, fields: [...] }
}

export async function updateSubject(name, data) {
  // 更新Subject配置
}

export async function addSubjectField(subjectName, params) {
  // 添加字段
}

export async function deleteSubjectField(subjectName, fieldName) {
  // 删除字段
}

export async function updateSubjectField(subjectName, fieldName, params) {
  // 更新字段
}

// SubjectView 相关
export async function getSubjectView(subjectName) {
  // 返回格式: [{ name, type, title, settings }]
}

export async function createSubjectView(subjectName, view) {
  // 创建视图
}

export async function updateSubjectView(subjectName, viewName, view) {
  // 更新视图
}

export async function deleteSubjectView(subjectName, viewName) {
  // 删除视图
}

export async function reorderSubjectView(subjectName, params) {
  // 重排序视图
}

// Record 相关
export async function loadRecord(name) {
  // 返回格式: { _id, name, title, metadata: {...} }
}

export async function createRecord(params) {
  // 创建记录
}

export async function updateRecord(name, model) {
  // 更新记录
}

export async function batchRemoveRecords(data) {
  // 批量删除记录
}

export async function aggregateRecords(aggregation) {
  // 聚合查询记录
  // aggregation: { subject, stages, page, page_size }
}

// 可选：导入功能
export async function importRecords(subject, records) {
  // 批量导入记录
}
```

## ⚙️ Props API

### RecordGrid

| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| subjectName | `string` | - | 必需，数据源名称 |
| readonly | `boolean \| object` | `false` | 只读模式配置 |
| pagination | `boolean \| object` | `true` | 分页配置 |
| rowSelection | `object` | `{}` | 行选择配置 |
| actions | `object` | `{}` | 自定义事件处理 |
| useFrontView | `boolean \| object` | `false` | 前端视图模式 |
| filterView | `array` | `[]` | 过滤视图 |
| displayConfig | `object` | `{}` | 显示配置（见下方说明） |
| authApp | `string` | - | 权限应用名 |
| quickSelect | `boolean` | `false` | 快速选择模式，开启后引用字段可直接在单元格内选择 |
| autoExpandGroups | `boolean` | `false` | 是否在首次加载和刷新后自动展开所有分组 |
| useClientSide | `boolean` | `false` | 客户端模式，数据在客户端处理 |
| useCustomSidebar | `boolean \| object` | `false` | 自定义侧边栏配置 |
| useCustomContextMenu | `boolean \| object` | `false` | 自定义右键菜单 |
| useCustomOperation | `boolean \| object` | `false` | 自定义操作栏 |
| tabBarRightSlot | `function` | - | 标签栏右侧插槽，接收 `(gridApi) => ReactNode` |
| toolBarRightSlot | `function` | - | 工具栏右侧插槽，接收 `(gridApi) => ReactNode` |
| extraTheme | `object` | `{}` | 主题定制配置 |
| recordDetailRenderer | `function` | - | 自定义记录详情渲染器 |
| documentDetailRenderer | `function` | - | 自定义文档详情渲染器 |
| columnRenderers | `object` | `{}` | 列自定义渲染器映射 `{ fieldName: renderFunction }` |
| detailGridColumnRenderers | `object` | `{}` | 详情抽屉中的多维表格专用列渲染器 |
| components | `object` | `{}` | 组件映射（兼容 columnRenderers 的别名） |
| extraFilters | `array` | `[]` | 额外的过滤条件，支持 MongoDB aggregation stages 数组 |

### displayConfig 配置

```javascript
{
  maxTagCount: 3,        // 标签字段最多显示的标签数量，超出部分显示 "+N"
  maxAvatarCount: 5      // 用户/引用字段最多显示的头像数量，超出部分显示 "+N"
}
```

示例：

```javascript
<RecordGrid
  subjectName="your-subject"
  displayConfig={{
    maxTagCount: 10,
    maxAvatarCount: 10
  }}
/>
```

### readonly 配置

```javascript
{
  disableAddRow: false,        // 禁用添加行
  disableAddColumn: false,     // 禁用添加列
  disableEdit: false,          // 禁用编辑
  hideEditRecordBtn: false,    // 隐藏编辑按钮
  hideCreateRecordBtn: false,  // 隐藏创建按钮
  hideFilterBtn: false,        // 隐藏筛选按钮
  hideGroupBtn: false,         // 隐藏分组按钮
  hideSearchBtn: false,        // 隐藏搜索按钮
  hideFillBtn: false,          // 隐藏填充按钮
  hideImportBtn: false,        // 隐藏导入按钮
  hideTriggerBtn: false,       // 隐藏触发器按钮
  hideFullScreenBtn: false,    // 隐藏全屏按钮
  disablePersistence: false    // 禁用持久化
}
```

### actions 自定义事件

```javascript
{
  onEditorOpen: ({ record, gridApi }) => {},     // 编辑器打开
  onCellDoubleClicked: (params) => {},           // 单元格双击
  onColumnChange: (params) => {},                // 列变化
  onCustomGridReady: (event) => {},              // Grid就绪
  onAddRow: ({ gridApi }) => {},                 // 添加行
  onRemoveRows: ({ rows, gridApi }) => {},       // 删除行
  onUpdateRecord: ({ params, record }) => {},    // 更新记录
  onCellValueChanged: (params) => {}             // 单元格值变化
}
```

## 🎨 样式定制

```javascript
<RecordGrid
  extraTheme={{
    accentColor: '#1890ff',
    valueChangeValueHighlightBackgroundColor: '#ffe58f'
  }}
/>
```

## 📝 高级用法

### 使用前端视图模式

```javascript
<RecordGrid
  subjectName="your-subject"
  useFrontView={{
    columns: [
      { field: 'title', hide: false, width: 200 },
      { field: 'metadata.status', hide: false, width: 100 }
    ],
    filters: {
      conditions: [
        { field: 'metadata.status', operator: 'equals', value: 'active' }
      ],
      filterType: 'and'
    },
    restrictions: [
      { type: 'field', field: 'metadata.category', value: ['A', 'B'] }
    ]
  }}
/>
```

### 自定义工具栏和标签栏

```javascript
<RecordGrid
  subjectName="your-subject"
  toolBarRightSlot={(gridApi) => (
    <Button onClick={() => console.log(gridApi)}>
      自定义按钮
    </Button>
  )}
  tabBarRightSlot={(gridApi) => (
    <span>自定义内容</span>
  )}
/>
```

### 使用权限服务（authService）

权限服务用于控制字段编辑权限和视图访问权限。可以通过 `RecordGridServiceProvider` 传入：

```javascript
import { RecordGridServiceProvider } from '@streams/record-grid'

const authService = {
  // 权限检查函数
  check: (auth) => {
    // auth 可能是字符串（如 '管理'）或对象（如 { role: '成员' }）
    // 返回 true/false
    return authInfo?.check?.(auth)
  },
  
  // 用户信息（可以是对象或函数）
  userInfo: () => ({
    username: 'user',
    type: 'admin',  // 'admin' 或 'system' 时，字段权限设置按钮可用
    display_name: '用户名'
  }),
  
  // 获取应用信息（用于权限设置弹窗）
  getAppInfo: async () => ({
    members: [],      // 用户组列表
    roles: [],        // 角色列表
    permissions: []   // 权限列表
  })
}

<RecordGridServiceProvider
  dataService={DataService}
  authService={authService}
>
  <RecordGrid subjectName="your-subject" />
</RecordGridServiceProvider>
```

**重要说明**：
- `userInfo.type` 为 `'admin'` 或 `'system'` 时，字段和视图的"权限设置"按钮才会启用
- `getAppInfo` 返回的数据用于权限设置弹窗中的选项

### 自定义列渲染器

```javascript
<RecordGrid
  subjectName="your-subject"
  columnRenderers={{
    // 为特定字段自定义渲染
    'metadata.status': ({ value, data, field }) => {
      return <Tag color={value === 'active' ? 'green' : 'red'}>{value}</Tag>
    },
    'metadata.workflow': ({ value, data, field }) => {
      // 自定义工作流渲染逻辑
      return <CustomWorkflowDisplay value={value} />
    }
  }}
  // 或者使用 components（与 columnRenderers 等价）
  components={{
    'metadata.status': StatusRenderer
  }}
/>
```

### 详情抽屉中的列渲染器

```javascript
<RecordGrid
  subjectName="your-subject"
  detailGridColumnRenderers={{
    // 详情抽屉中的多维表格使用不同的渲染器
    'metadata.workflow': ({ value, data, field }) => {
      return (
        <>
          {(!data.metadata?.status || data.metadata.status === 'new') && (
            <>{renderTagStatus('unstarted')}</>
          )}
          {data.metadata.status === 'completed' && (
            <>{renderTagStatus('completed')}</>
          )}
          {data.metadata.status === 'in_progress' && (
            <>{renderTagStatus('inprogress', data.metadata.workflow_data?.[(data.metadata.step * 1 || 1) - 1].title)}</>
          )}
        </>
      )
    }
  }}
/>
```

### 使用额外过滤条件

```javascript
<RecordGrid
  subjectName="your-subject"
  extraFilters={[
    // MongoDB aggregation stages
    { $match: { 'metadata.status': 'active' } },
    { $lookup: { /* ... */ } }
  ]}
/>
```

### 获取选中行

```javascript
const gridRef = useRef(null)

<RecordGrid
  ref={gridRef}
  subjectName="your-subject"
/>

// 获取选中行
const selectedRows = gridRef.current.getSelectedRows()
```

## 🔌 扩展开发

### 自定义字段编辑器

```javascript
// 实现自定义编辑器
const CustomEditor = forwardRef((props, ref) => {
  const [value, setValue] = useState(props.value)
  
  useImperativeHandle(ref, () => ({
    getValue: () => value
  }))
  
  return (
    <input 
      value={value} 
      onChange={e => setValue(e.target.value)} 
    />
  )
})

// 在字段配置中使用
{
  name: 'custom_field',
  type: 'text',
  cellEditor: CustomEditor
}
```

## 🐛 常见问题

### Q: TypeError: Cannot read properties of undefined (reading 'call')

A: 这个问题在 v2.0.0 已彻底修复！

**原因**:
- `@/components/gantt` 路径别名未配置
- 或使用了旧版本（< v2.0.0）

**解决方案**:
1. 更新到 v2.0.0+
2. 如果使用 Gantt 功能，需要配置 `@/components/gantt`（见下方）
3. 清理缓存：`rm -rf node_modules/.cache`

详见 [FINAL_FIX_REPORT.md](./FINAL_FIX_REPORT.md)

### Q: 提示"未找到 DataService"

A: 请确保在应用启动时调用了 `RecordGrid.initialize()` 并传入了 dataService。

### Q: 样式显示异常

A: 请确保导入了组件样式：
```javascript
import '@streams/record-grid/dist/index.css'
```

### Q: AG Grid License 警告

A: 本组件依赖 AG Grid Enterprise，请确保你有有效的许可证。

### Q: useQuery is not defined

A: 在 v2.0.0+ 版本中，`@tanstack/react-query` 已经打包进 dist，不需要单独安装！

如果仍然遇到此问题：
1. 确保使用 v2.0.0+
2. 清理缓存：`rm -rf node_modules/.cache && rm -rf .umi`
3. 重新安装：`npm install @streams/record-grid`

### Q: 字段权限设置按钮一直是灰色的

A: 权限设置按钮需要管理员权限才能使用。

**原因**：
- `authService.userInfo.type` 必须是 `'admin'` 或 `'system'`
- 如果 `userInfo` 是函数，需要返回包含 `type` 字段的对象

**解决方案**：

```javascript
const authService = {
  check: (auth) => authInfo?.check?.(auth),
  userInfo: () => ({
    username: 'user',
    type: 'admin',  // 必须是 'admin' 或 'system'
    // ... 其他字段
  }),
  getAppInfo: () => appInfo
}

<RecordGridServiceProvider
  dataService={DataService}
  authService={authService}
>
  <RecordGrid subjectName="your-subject" />
</RecordGridServiceProvider>
```

### Q: 使用 Gantt 视图报错或显示空白

A: **从 v2.0.0 开始，Gantt 功能改为可选模式！**

**如果不使用 Gantt 视图**：
- ✅ 无需任何配置
- ✅ 其他功能正常使用

**如果需要使用 Gantt 视图**：

方案 1（推荐）- 初始化 Gantt 适配器：
```javascript
import RecordGrid, { ganttAdapter } from '@streams/record-grid'
import Scheduler, { SchedulerData, ViewType, DemoData } from 'react-big-scheduler'

// 在应用启动时初始化
ganttAdapter.initializeGantt({
  Scheduler,
  SchedulerData,
  ViewType,
  DemoData
})
```

方案 2 - 配置 Webpack/UMI alias：
```javascript
// .umirc.ts 或 webpack.config.js
alias: {
  '@/components/gantt': '/src/components/gantt'
}
```

详见 [GANTT_SETUP_GUIDE.md](./GANTT_SETUP_GUIDE.md)

## 📄 许可证

MIT

## 🤝 贡献

欢迎提交 Issue 和 Pull Request！

## 📧 联系我们

- Email: dev@your-company.com
- 文档: https://docs.your-company.com/record-grid