npm package: @mingfuyun/star-allinone
Description: 星系运维前端能力包
Author: lilu
Latest version: 0.1.2

# @mingfuyun/star-allinone

星系运维前端能力包 - 包含Cron表达式生成器等实用组件

## 📦 安装

```bash
npm install @mingfuyun/star-allinone
# 或
yarn add @mingfuyun/star-allinone
# 或
pnpm add @mingfuyun/star-allinone
```

### 在 Umi 项目中使用

如果您的项目使用 **Umi** 框架，组件库会自动从您的项目中获取 `@umijs/max` 的能力（如 `useAccess`）。

**确保安装 peerDependencies：**

```bash
# Umi 项目通常已经安装了 @umijs/max，如果没有，请安装：
npm install @umijs/max
# 或
yarn add @umijs/max
# 或
pnpm add @umijs/max
```

**工作原理：**

1. 组件库通过 `webpack externals` 配置，不会打包 `@umijs/max`
2. 运行时，组件库会从业务项目的 `node_modules` 中动态获取 `@umijs/max`
3. 组件库中的权限相关功能（如 `MFTablePro` 的权限过滤）会自动使用您项目中的 `useAccess` Hook

**示例：在 Umi 项目中使用带权限的组件**

```tsx
import React from 'react';
import { MFTablePro } from '@mingfuyun/star-allinone';
import { useAccess } from '@umijs/max';

function TablePage() {
  // 组件库会自动使用您项目中的 useAccess
  // 无需手动传递，组件库内部会自动获取
  return (
    <MFTablePro
      columns={[
        {
          title: '操作',
          dataIndex: 'action',
          render: (_, record) => (
            <Button permission="edit">编辑</Button>
          ),
        },
      ]}
      // ... 其他配置
    />
  );
}
```

## 🚀 快速开始

### 基础使用

```tsx
import React from 'react';
import { Cron, CustomDrawer } from '@mingfuyun/star-allinone';
import '@mingfuyun/star-allinone/dist/styles.css';

function App() {
  return (
    <div>
      <Cron cronExpression="0 0 12 * * ?" />
      <CustomDrawer open={true} title="示例" onClose={() => {}}>
        内容
      </CustomDrawer>
    </div>
  );
}
```

### 按需引入

```tsx
// 引入单个组件
import { Cron } from '@mingfuyun/star-allinone';
import '@mingfuyun/star-allinone/dist/styles.css';

// 引入多个组件
import { Cron, CustomDrawer, HocModal } from '@mingfuyun/star-allinone';
```

### 单独引入组件

如果某些组件未在主入口导出，可以直接从组件路径引入：

```tsx
// BaseModal
import BaseModal from '@mingfuyun/star-allinone/components/BaseModal';

// ErrorBoundary
import ErrorBoundary from '@mingfuyun/star-allinone/components/ErrorBoundary';
```

## 📚 组件文档

### Cron 表达式生成器

一个功能强大的Cron表达式可视化生成器组件，支持通过Tab页切换配置分钟、小时、日、月、周，并提供实时预览和验证功能。

#### 基础用法

```tsx
import React, { useRef } from 'react';
import { Cron } from '@mingfuyun/star-allinone';

function CronExample() {
  const cronRef = useRef<any>();

  const handleGetCron = () => {
    const cronExpression = cronRef.current?.refGetCron();
    console.log('Cron表达式:', cronExpression);
  };

  const handleReset = () => {
    cronRef.current?.resetCronState();
  };

  const handleGetStatus = () => {
    const status = cronRef.current?.getValidateStatus();
    console.log('验证状态:', status); // 'success' | 'error' | undefined
  };

  return (
    <div>
      <Cron 
        ref={cronRef}
        cronExpression="0 0 12 * * ?" 
      />
      <button onClick={handleGetCron}>获取Cron表达式</button>
      <button onClick={handleReset}>重置</button>
      <button onClick={handleGetStatus}>获取验证状态</button>
    </div>
  );
}
```

#### 功能特性

- ✅ 支持5种时间维度配置：分钟、小时、日、月、周
- ✅ 支持4种执行模式：每分/时/日/月/周执行、周期执行、循环执行、指定时间执行
- ✅ 实时预览Cron表达式
- ✅ 自动验证Cron表达式有效性
- ✅ 支持通过props传入初始Cron表达式进行回显
- ✅ 支持通过ref调用方法获取表达式、重置状态、获取验证状态

#### API

| 参数 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| cronExpression | 初始Cron表达式（5位格式：分钟 小时 日 月 周） | string | - |

#### Ref 方法

通过ref可以调用以下方法：

| 方法名 | 说明 | 返回值 |
|--------|------|--------|
| refGetCron | 获取当前生成的Cron表达式 | string |
| resetCronState | 重置组件状态到初始值 | void |
| getValidateStatus | 获取Cron表达式验证状态 | 'success' \| 'error' \| undefined |

#### 使用示例

```tsx
// 示例1: 每天12点执行
<Cron cronExpression="0 12 * * *" />

// 示例2: 每5分钟执行一次
<Cron cronExpression="*/5 * * * *" />

// 示例3: 每周一到周五的9点执行
<Cron cronExpression="0 9 * * 2-6" />
```

### BaseModal 基础模态框

基于Antd Modal封装的模态框组件，提供统一的样式和默认配置。

#### 基础用法

```tsx
import React, { useState } from 'react';
import BaseModal from '@mingfuyun/star-allinone/components/BaseModal';

function ModalExample() {
  const [visible, setVisible] = useState(false);

  const handleOk = () => {
    console.log('确定');
    setVisible(false);
  };

  return (
    <BaseModal
      visible={visible}
      title="示例模态框"
      onOk={handleOk}
      onCancel={() => setVisible(false)}
      width={600}
    >
      <p>模态框内容</p>
    </BaseModal>
  );
}
```

#### API

| 参数 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| title | 标题 | string \| ReactNode | - |
| visible | 是否显示 | boolean | - |
| onOk | 确定回调 | () => void | - |
| onCancel | 取消回调 | () => void | - |
| children | 内容 | ReactNode | - |
| width | 宽度 | number | 320 |
| afterClose | 关闭后的回调 | () => void | - |
| okText | 确定按钮文字 | string | "确定" |
| cancelText | 取消按钮文字 | string | "取消" |
| confirmLoading | 确定按钮loading状态 | boolean | false |
| footer | 底部内容，设置为null时不显示 | ReactNode \| null | undefined |
| wrapClassName | 外层容器的类名 | string | "" |
| className | Modal的类名 | string | "" |
| keyboard | 是否支持ESC关闭 | boolean | true |
| maskClosable | 点击蒙层是否关闭 | boolean | true |
| mask | 是否显示遮罩 | boolean | true |
| getContainer | 指定Modal挂载的HTML节点 | () => HTMLElement | - |
| closable | 是否显示右上角关闭按钮 | boolean | true |
| destroyOnClose | 关闭时销毁Modal里的子元素 | boolean | true |
| closeIcon | 自定义关闭图标 | ReactNode | - |

**注意**: 组件默认居中显示（centered），关闭时自动销毁内容（destroyOnClose）。

### HocModal 高阶模态框

高阶组件（HOC），用于将任意组件包装成具有Modal功能的组件，通过ref控制显示和隐藏。

#### 基础用法

```tsx
import React, { useRef } from 'react';
import { HocModal } from '@mingfuyun/star-allinone';
import BaseModal from '@mingfuyun/star-allinone/components/BaseModal';

// 定义你的内容组件
function MyContent({ visible, handleCancel, ...props }: any) {
  return (
    <BaseModal
      visible={visible}
      onCancel={handleCancel}
      title="通过HOC包装的Modal"
    >
      <p>这是通过HocModal包装的内容</p>
      <p>接收到的props: {JSON.stringify(props)}</p>
    </BaseModal>
  );
}

// 使用HOC包装组件
const WrappedModal = HocModal(MyContent);

function App() {
  const modalRef = useRef<any>();

  const handleShow = () => {
    // 通过ref调用show方法，可以传入参数
    modalRef.current?.show({ 
      userId: 123,
      userName: '张三' 
    });
  };

  const handleHide = () => {
    modalRef.current?.hide();
  };

  return (
    <div>
      <button onClick={handleShow}>显示Modal</button>
      <button onClick={handleHide}>隐藏Modal</button>
      <WrappedModal ref={modalRef} />
    </div>
  );
}
```

#### 工作原理

HocModal会将你的组件包装，并注入以下props：
- `visible`: boolean - Modal的显示状态
- `handleCancel`: () => void - 关闭Modal的函数

通过ref可以调用：
- `show(args)`: 显示Modal，可以传入参数，参数会作为props传递给被包装的组件
- `hide()`: 隐藏Modal

#### 使用场景

适用于需要动态控制显示/隐藏，并且需要传递参数的Modal场景。

#### ⚠️ 常见错误

**错误用法**：
```tsx
// ❌ 错误：HocModal 是一个高阶组件，不能直接作为组件使用
<HocModal />
```

**正确用法**：
```tsx
// ✅ 正确：先使用 HocModal 包装你的组件
const WrappedModal = HocModal(MyContent);
<WrappedModal ref={modalRef} />
```

**注意**：`HocModal` 是一个函数，接受一个组件作为参数，返回一个新的包装组件。不能直接作为 React 组件使用。

### CustomDrawer 自定义抽屉

基于Antd Drawer的增强组件，提供统一的样式和默认配置，支持自定义底部操作栏。

#### 基础用法

```tsx
import React, { useState } from 'react';
import { CustomDrawer } from '@mingfuyun/star-allinone';

function DrawerExample() {
  const [open, setOpen] = useState(false);

  const handleConfirm = () => {
    console.log('确定');
    setOpen(false);
  };

  return (
    <CustomDrawer
      open={open}
      title="示例抽屉"
      onClose={() => setOpen(false)}
      onConfirm={handleConfirm}
      width={600}
    >
      <p>抽屉内容</p>
    </CustomDrawer>
  );
}
```

#### API

| 参数 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| title | 标题 | string | - |
| open | 是否显示 | boolean | - |
| onClose | 关闭回调 | () => void | - |
| onConfirm | 确定回调 | () => void | - |
| width | 宽度 | number \| string | - |
| closable | 是否显示关闭按钮 | boolean | true |
| cancelText | 取消按钮文字 | string | "取消" |
| okText | 确定按钮文字 | string | "确定" |
| children | 内容 | ReactNode | - |
| className | 自定义类名 | string | - |
| footer | 自定义底部内容，设置为null时不显示 | ReactNode \| null | undefined |
| extra | 标题右侧额外内容 | ReactNode | null |

**注意**: 组件默认从右侧滑出（placement="right"），标题左对齐。

### ErrorBoundary 错误边界

React错误边界组件，用于捕获子组件树中的JavaScript错误，并显示友好的错误提示页面。支持捕获同步错误和异步错误（包括Promise rejection和全局错误）。

#### 基础用法

```tsx
import React from 'react';
import ErrorBoundary from '@mingfuyun/star-allinone/components/ErrorBoundary';

function App() {
  return (
    <ErrorBoundary onError={(error, errorInfo) => {
      console.error('捕获到错误:', error, errorInfo);
      // 可以在这里上报错误到监控系统
    }}>
      <YourApp />
    </ErrorBoundary>
  );
}
```

#### API

| 参数 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| children | 子组件 | ReactNode | - |
| onError | 错误回调函数 | (error: Error, errorInfo: any) => void | - |

#### 功能特性

- ✅ 捕获组件渲染、生命周期方法中的错误
- ✅ 捕获未处理的Promise rejection
- ✅ 捕获全局JavaScript错误
- ✅ 显示友好的错误提示页面
- ✅ 提供刷新页面按钮
- ✅ 支持自定义错误处理回调

#### 使用示例

```tsx
// 包裹整个应用
function App() {
  return (
    <ErrorBoundary onError={(error, errorInfo) => {
      // 上报错误到监控系统
      reportError(error, errorInfo);
    }}>
      <Router>
        <Routes>
          {/* 你的路由 */}
        </Routes>
      </Router>
    </ErrorBoundary>
  );
}

// 包裹特定组件
function Page() {
  return (
    <ErrorBoundary>
      <UnstableComponent />
    </ErrorBoundary>
  );
}
```

## 🎨 样式定制

组件库使用Less和CSS Modules，支持样式定制：

### Cron组件样式

```css
/* 自定义Cron组件样式 */
.cronCom {
  /* 你的自定义样式 */
}

.cronPreview {
  /* 预览区域样式 */
}
```

### BaseModal样式

组件会自动添加 `base-modal` 类名到 `wrapClassName`，可以通过该类名自定义样式：

```css
.base-modal {
  /* 自定义Modal外层容器样式 */
}
```

### CustomDrawer样式

组件会自动添加 `custom-footer` 类名到底部操作栏，可以通过该类名自定义样式：

```css
.custom-footer {
  /* 自定义底部操作栏样式 */
}
```

## 📋 依赖要求

- React >= 19.1.1
- React-DOM >= 19.1.1
- Antd >= 5.27.3
- cron-validator >= 1.4.0 (用于Cron表达式验证)

**重要提示**：组件库使用 `peerDependencies` 管理 React 和 Antd，确保你的项目中已安装这些依赖。

### 常见问题排查

#### 1. "Invalid hook call" 错误

如果遇到此错误，请检查：

1. 确保项目中只安装了一个 React 版本
2. 确保 React 和 React-DOM 版本匹配
3. 如果使用 npm/yarn，可以尝试删除 `node_modules` 和锁文件后重新安装
4. 如果使用 pnpm，确保在 `.npmrc` 中配置了：
   ```ini
   shamefully-hoist=true
   ```
   或
   ```ini
   public-hoist-pattern[]=*react*
   ```

#### 2. "Cannot read properties of undefined (reading 'recentlyCreatedOwnerStacks')" 错误

这是 React 19 的一个已知问题，可能的原因和解决方案：

1. **React 版本问题**：确保使用 React 19.0.0 或更高版本（推荐 19.1.1+）
2. **多个 React 实例**：确保项目中只有一个 React 实例
   ```bash
   # 检查是否有多个 React 实例
   npm ls react
   # 或
   pnpm list react
   ```
3. **pnpm 配置**：如果使用 pnpm，在 `.npmrc` 中添加：
   ```ini
   shamefully-hoist=true
   public-hoist-pattern[]=*react*
   public-hoist-pattern[]=*react-dom*
   ```
4. **清除缓存**：尝试清除构建缓存和 node_modules
   ```bash
   rm -rf node_modules .next dist build
   npm install
   # 或
   pnpm install
   ```
5. **降级到 React 18**：如果问题持续，可以考虑暂时使用 React 18：
   ```bash
   npm install react@^18.0.0 react-dom@^18.0.0
   ```

## 🔧 开发

### 本地开发

```bash
# 克隆项目
git clone <repository-url>

# 安装依赖
npm install

# 启动开发模式
npm run dev
```

### 构建

```bash
# 构建生产版本
npm run build

# 清理构建产物
npm run clean
```

### 发布

```bash
# 发布到npm（生产环境）
npm run publish

# 发布到npm（开发环境）
npm run publish:dev
```

## 📄 许可证

MIT License

## 🤝 贡献

欢迎提交Issue和Pull Request来改进这个组件库。

## 📞 支持

如有问题，请通过以下方式联系：

- 提交Issue: [Codeup Issues](https://codeup.aliyun.com/61762c5110204867ecfd5ca4/cmdb/star-allinone/issues)
- 项目地址: [Codeup Repository](https://codeup.aliyun.com/61762c5110204867ecfd5ca4/cmdb/star-allinone)

---

Made with ❤️ by 星系运维团队