# @vention/machine-apps-components 中文文档

规范地址：https://npmcn.com/package/%40vention/machine-apps-components/

版本：1\.30\.27
npm 元数据更新时间：2026-11-02T19:43:29.610Z
中文译文更新时间：2026-11-02T20:19:48.593Z
软件包许可：MIT

本文由上游 README 机器翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40vention/machine-apps-components
原文对照：https://npmcn.com/package/%40vention/machine-apps-components/?lang=original
源码仓库：https://github.com/VentionCo/machine-cloud

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：445 kB，44 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：6 个
- peer 依赖：react 17\.0\.2，@mui/material ^5\.0\.0，react-router-dom ^6\.0\.0，@vention/machine-ui ^6\.7\.2
- 首次发布：2025-10-27T16:14:25.063Z
- 最新版本发布：2026-11-02T19:43:29.447Z
- 已发布版本数：285（近 12 个月 279 个）

## 中文简介

暂无中文简介

## 安装

```sh
npm install @vention/machine-apps-components
```

也可以使用：`pnpm add @vention/machine-apps-components`、`yarn add @vention/machine-apps-components`、`bun add @vention/machine-apps-components`

## README

# 机器应用程序组件

用于机器应用程序的可重用组件。

## 组件

### NavigationBar

一个导航栏组件，支持：

-   带有图标的多个导航项
-   控制中心按钮
-   支持按钮
-   可选定时器显示

#### 道具

```typescript
interface NavigationItem {
  label: string
  path: string
  icon: ReactNode
  onClick?: () => void // Optional: Custom click handler (overrides default navigation)
}

interface NavigationBarProps {
  navigationItems: NavigationItem[]
  showTimer?: boolean // Default: true
}
```

#### 示例使用

##### 基本用法

```tsx
import { NavigationBar } from "@vention/machine-apps-components"
import { VentionIcon } from "@vention/machine-ui"

const NAV_ITEMS = [
  {
    label: "Operation",
    path: "/operation",
    icon: <VentionIcon size={32} type="category-filled" color="white" />,
  },
  {
    label: "Settings",
    path: "/settings",
    icon: <VentionIcon size={32} type="tool-1" color="white" />,
  },
]

// With timer (default)
<NavigationBar navigationItems={NAV_ITEMS} />

// Without timer
<NavigationBar navigationItems={NAV_ITEMS} showTimer={false} />
```

##### 自定义单击处理程序

你可以通过提供自定义的点击处理程序来覆盖默认的导航行为：

```tsx
// Custom handler for navigation items
const NAV_ITEMS = [
  {
    label: "Settings",
    path: "/settings",
    icon: <VentionIcon size={32} type="tool-1" color="white" />,
    onClick: () => {
      // Show confirmation before navigating
      if (confirm("You have unsaved changes. Continue?")) {
        navigate("/settings")
      }
    },
  },
  {
    label: "Logs",
    path: "/logs",
    icon: <VentionIcon size={32} type="alarm-bell-filled" color="white" />,
    onClick: () => {
      // Do something before navigating
      localStorage.setItem("lastView", "operation")
      navigate("/logs")
    },
  },
]
```

**注意：** 当一个习惯 `onClick` 处理程序，它将完全覆盖默认的导航行为。如果需要，处理程序负责任何导航逻辑。

### StatusTopBar

位于屏幕顶部的状态栏组件，显示：

-   带标签和彩色圆点的状态指示灯
-   具有可见性和禁用状态的可配置操作按钮
-   按钮的自定义样式

**主要特点:**

-   ✅声明式的，基于配置的API
-   ✅完全受控组件（无内部状态）
-   ✅类型安全按钮配置
-   ✅易于测试和推理

#### 道具

```typescript
interface ButtonConfig {
  id: string // Unique identifier for the button
  label: string // Button text
  onClick?: () => void // Click handler
  visible?: boolean // Show/hide button (default: true)
  disabled?: boolean // Enable/disable button (default: false)
  backgroundColor?: string // Button background color (e.g., "#4CAF50")
  backgroundColorHover?: string // Hover background color
  borderColor?: string // Border color
  textColor?: string // Text color
  width?: number // Button width in pixels (default: 208)
  height?: number // Button height in pixels (default: 80)
  icon?: ReactNode // Icon to display when enabled
  iconDisabled?: ReactNode // Icon to display when disabled
}

interface StatusTopBarProps {
  status?: {
    label: string // Status label text
    color: string // Color of the status dot
  }
  buttonConfigs?: ButtonConfig[] // Array of button configurations
}
```

#### 示例使用

##### 基本用法

```tsx
import { StatusTopBar, ButtonConfig } from "@vention/machine-apps-components"
import { VentionIcon } from "@vention/machine-ui"

function App() {
  const buttonConfigs: ButtonConfig[] = [
    {
      id: "start",
      label: "Start",
      onClick: () => console.log("Start clicked"),
      backgroundColor: "#2196F3",
      textColor: "white",
      icon: <VentionIcon size={32} type="player-play-filled" color="white" />,
      visible: true,
      disabled: false,
    },
    {
      id: "stop",
      label: "Stop",
      onClick: () => console.log("Stop clicked"),
      backgroundColor: "#F44336",
      textColor: "white",
      icon: <VentionIcon size={32} type="player-stop-filled" color="white" />,
      visible: false, // Hidden by default
      disabled: false,
    },
  ]

  return (
    <StatusTopBar
      status={{
        label: "Machine state: Ready",
        color: "#4CAF50",
      }}
      buttonConfigs={buttonConfigs}
    />
  )
}
```

##### 动态状态管理

组件是完全受控的——所有的按钮状态都来自于你的应用状态：

```tsx
import { StatusTopBar, ButtonConfig } from "@vention/machine-apps-components"
import { useMemo } from "react"

function MachineApp() {
  const { machineState, isRunning, canStart } = useMachineState()

  const buttonConfigs: ButtonConfig[] = useMemo(() => {
    const configs: ButtonConfig[] = []

    // Start button - visible when not running
    if (!isRunning) {
      configs.push({
        id: "start",
        label: "Start",
        onClick: handleStart,
        backgroundColor: "#2196F3",
        textColor: "white",
        visible: true,
        disabled: !canStart, // Disabled if prerequisites not met
      })
    }

    // Stop button - visible when running
    if (isRunning) {
      configs.push({
        id: "stop",
        label: "Stop",
        onClick: handleStop,
        backgroundColor: "#F44336",
        textColor: "white",
        visible: true,
        disabled: false,
      })
    }

    // Home button - always visible
    configs.push({
      id: "home",
      label: "Home",
      onClick: handleHome,
      borderColor: "#E2E8F0",
      textColor: "#1A202C",
      visible: true,
      disabled: isRunning, // Can't home while running
    })

    return configs
  }, [isRunning, canStart])

  return (
    <StatusTopBar
      status={{
        label: `Machine state: ${machineState}`,
        color: getStatusColor(machineState),
      }}
      buttonConfigs={buttonConfigs}
    />
  )
}
```

##### 有条件的按钮

根据应用程序状态轻松显示/隐藏按钮：

```tsx
const buttonConfigs: ButtonConfig[] = useMemo(() => {
  const configs: ButtonConfig[] = []

  // Operation page buttons
  if (currentPage === "operation") {
    configs.push({
      id: "start",
      label: isRunning ? "Stop" : "Start",
      onClick: isRunning ? handleStop : handleStart,
      backgroundColor: isRunning ? "#F44336" : "#2196F3",
      textColor: "white",
      visible: true,
      disabled: false,
    })
  }

  // Calibration page buttons
  if (currentPage === "calibration") {
    configs.push({
      id: "freedrive",
      label: isFreeDriveEnabled ? "Disable Free Drive" : "Enable Free Drive",
      onClick: toggleFreeDrive,
      backgroundColor: isFreeDriveEnabled ? "#CBD5E0" : undefined,
      borderColor: !isFreeDriveEnabled ? "#E2E8F0" : undefined,
      textColor: "black",
      visible: true,
      disabled: false,
    })
  }

  return configs
}, [currentPage, isRunning, isFreeDriveEnabled])
```

#### 从命令式API迁移

如果你正在从旧的复合组件模式迁移：

**前（复合成分）：**

```tsx
<StatusTopBar statusLabel="Ready" dotColor="#4CAF50" visibleButtons={["start"]} disabledButtons={["stop"]}>
  <StatusTopBar.Button id="start" label="Start" onClick={handleStart} backgroundColor="#2196F3" textColor="white" />
  <StatusTopBar.Button id="stop" label="Stop" onClick={handleStop} backgroundColor="#F44336" textColor="white" />
</StatusTopBar>
```

**后(config-based):**

```tsx
<StatusTopBar
  status={{ label: "Ready", color: "#4CAF50" }}
  buttonConfigs={[
    { id: "start", label: "Start", onClick: handleStart, backgroundColor: "#2196F3", textColor: "white", visible: true },
    { id: "stop", label: "Stop", onClick: handleStop, backgroundColor: "#F44336", textColor: "white", visible: false },
  ]}
/>
```

**新API的好处：**

-   按钮状态的单一真实来源
-   不需要refs或命令式方法
-   更容易测试（只需通过不同的配置）
-   更好的TypeScript支持
-   更可预测的行为

### 日志

用于过滤、排序和显示机器日志的可重用日志组件。

#### 出口

```typescript
import { LogsPanel, LogsTable, LogFilterForm, LogsPagination } from "@vention/machine-apps-components"
import type {
  LogEntry,
  LogType,
  LogFilterFormValues,
  SortOrder,
  LogsPanelHandle,
  PaginationConfig,
  PaginationMode,
  FetchParams,
  FetchResult,
} from "@vention/machine-apps-components"
```

#### 类型

```typescript
type LogType = "error" | "warning" | "info"

interface LogEntry {
  id: string
  date: string // ISO or locale string parsable by Date
  level: LogType
  code: string
  message: string
  description: string
}

type SortOrder = "latest" | "oldest"

interface LogFilterFormValues {
  fromDate?: string // YYYY-MM-DD
  toDate?: string // YYYY-MM-DD
  logType?: LogType
  sortOrder: SortOrder
}

type PaginationMode = "pagination" | "infinite-scroll" | "none"

interface PaginationConfig {
  mode: PaginationMode
  pageSize?: number // Default: 10
  initialPage?: number // Default: 1
}

// Parameters passed to the dataFetcher
interface FetchParams {
  filters: LogFilterFormValues // Current filter state
  page: number // Current page number
  pageSize: number // Items per page
}

// Expected return type from dataFetcher
interface FetchResult {
  logs: LogEntry[] // The log entries for this page
  totalCount: number // Total number of logs (after filtering)
  totalPages: number // Total number of pages
  currentPage: number // Current page number
  hasMore: boolean // Whether there are more pages available
}

// Type definition for data fetcher
type DataFetcher = (params: FetchParams) => Promise<FetchResult>

interface LogsPanelHandle {
  refresh: () => Promise<void>
  resetFilters: () => void
  applyFilters: (filters: Partial<LogFilterFormValues>) => void
  getCurrentFilters: () => LogFilterFormValues
  exportLogs: () => LogEntry[]
}
```

#### LogsPanel

一个组合组件，它将过滤器UI和表显示与加载状态和错误处理结合在一起。这个分量是a **纯表示组件** -它显示数据并管理UI状态，同时将所有数据操作（过滤，排序，分页）委托给用户 `dataFetcher` 函数。

**特点:**

-   🔄自动加载状态，获取数据时带有旋转器
-   ❌内置错误显示与VentionAlert
-   🔍日期范围和日志类型的过滤器UI
-   ↕️排序UI为最新/最旧
-   📅日期格式（YYYY-MM-DD h:mm:ssa）
-   🎨基于类型的图标（错误、警告、信息）
-   📄分页支持（标准分页或无限滚动）
-   🎯编程控制的命令式API
-   🔔用于集成的事件回调
-   🎨可定制的样式和空状态
-   ⚡性能优化与React.memo

##### 它是如何工作的

组件调用您的 `dataFetcher` 函数，每当过滤器、排序顺序或页面更改时。你实现了过滤、排序和分页逻辑，并返回结果：

```tsx
import { LogsPanel } from "@vention/machine-apps-components"
import type { FetchParams, FetchResult } from "@vention/machine-apps-components"

const fetchLogs = async (params: FetchParams): Promise<FetchResult> => {
  // params contains:
  // - params.filters.fromDate
  // - params.filters.toDate
  // - params.filters.logType
  // - params.filters.sortOrder
  // - params.page
  // - params.pageSize

  const response = await fetch(
    `/api/logs?${new URLSearchParams({
      fromDate: params.filters.fromDate || "",
      toDate: params.filters.toDate || "",
      logType: params.filters.logType || "",
      sortOrder: params.filters.sortOrder,
      page: params.page.toString(),
      pageSize: params.pageSize.toString(),
    })}`
  )

  const data = await response.json()

  return {
    logs: data.logs,
    totalCount: data.total,
    totalPages: Math.ceil(data.total / params.pageSize),
    currentPage: params.page,
    hasMore: params.page < Math.ceil(data.total / params.pageSize),
  }
}

;<LogsPanel
  dataFetcher={fetchLogs}
  pagination={{
    mode: "pagination",
    pageSize: 20,
  }}
/>
```

**重要:** 当使用 `dataFetcher`，你有责任：

-   ✅按日期范围和类型过滤日志
-   ✅按日期（最新/最老）排序日志
-   ✅对结果进行分页
-   ✅返回分页元数据（totalCount, totalPages, hasMore）

组件处理：

-   ✅呈现过滤器UI
-   ✅过滤器状态管理
-   ✅给你打电话 `dataFetcher` 当过滤器/页面发生变化时
-   ✅加载和错误状态
-   ✅显示结果

##### 完整的客户端示例

下面是一个完整的示例，展示了如何在客户端实现过滤、排序和分页：

```tsx
import { useCallback, useMemo } from "react"
import { LogsPanel } from "@vention/machine-apps-components"
import type { FetchParams, FetchResult, LogEntry } from "@vention/machine-apps-components"
import dayjs from "dayjs"

function LogsPage() {
  // Your data source (could come from props, context, etc.)
  const allLogs: LogEntry[] = useMemo(
    () => [
      { id: "1", date: "2025-10-07T14:00:00Z", type: "error", code: "ERR_001", message: "Error", description: "..." },
      { id: "2", date: "2025-10-07T13:00:00Z", type: "warning", code: "WARN_001", message: "Warning", description: "..." },
      { id: "3", date: "2025-10-07T12:00:00Z", type: "info", code: "INFO_001", message: "Info", description: "..." },
      // ... more logs
    ],
    []
  )

  const fetchLogs = useCallback(
    async (params: FetchParams): Promise<FetchResult> => {
      // Simulate network delay (optional)
      await new Promise(resolve => setTimeout(resolve, 500))

      // 1. Apply filtering
      let filtered = [...allLogs]

      // Filter by date range
      if (params.filters.fromDate) {
        const fromTimestamp = dayjs(params.filters.fromDate).valueOf()
        filtered = filtered.filter(log => dayjs(log.date).valueOf() >= fromTimestamp)
      }

      if (params.filters.toDate) {
        const toTimestamp = dayjs(params.filters.toDate).endOf("day").valueOf()
        filtered = filtered.filter(log => dayjs(log.date).valueOf() <= toTimestamp)
      }

      // Filter by log type
      if (params.filters.logType) {
        filtered = filtered.filter(log => log.type === params.filters.logType)
      }

      // 2. Apply sorting
      filtered.sort((a, b) => {
        const aTime = dayjs(a.date).valueOf()
        const bTime = dayjs(b.date).valueOf()
        return params.filters.sortOrder === "latest" ? bTime - aTime : aTime - bTime
      })

      // 3. Apply pagination
      const totalCount = filtered.length
      const totalPages = Math.ceil(totalCount / params.pageSize)
      const start = (params.page - 1) * params.pageSize
      const end = start + params.pageSize
      const paginated = filtered.slice(start, end)

      // 4. Return result
      return {
        logs: paginated,
        totalCount,
        totalPages,
        currentPage: params.page,
        hasMore: end < totalCount,
      }
    },
    [allLogs]
  )

  return (
    <LogsPanel
      dataFetcher={fetchLogs}
      pagination={{
        mode: "pagination",
        pageSize: 10,
      }}
    />
  )
}
```

##### 道具

```typescript
interface LogsPanelProps {
  // Required - Data fetcher function
  dataFetcher: (params: FetchParams) => Promise<FetchResult>

  // Optional - Initial state
  initialFilters?: Partial<LogFilterFormValues>

  // Optional - Error handling
  onError?: (error: unknown) => void

  // Optional - Pagination
  pagination?: PaginationConfig

  // Optional - Event callbacks
  onFilterChange?: (filters: LogFilterFormValues) => void
  onLogClick?: (log: LogEntry) => void

  // Optional - Customization
  className?: string
  tableHeight?: string | number
  emptyStateMessage?: string
  emptyStateIcon?: ReactNode
}
```

##### 州

-   **加载**：显示带有“Loading logs…”消息的VentionSpinner
-   **错误**：显示带有错误标题和描述的VentionAlert
-   **空**：显示可自定义的空状态消息
-   **成功**：呈现带有数据的可过滤/可排序表

##### 最初的过滤器

```tsx
<LogsPanel
  data={logs}
  initialFilters={{
    fromDate: "2025-09-01",
    toDate: "2025-09-30",
    logType: "error",
    sortOrder: "latest",
  }}
/>
```

##### 分页

```tsx
// Standard pagination (default: 10 items per page)
<LogsPanel
  data={logs}
  pagination={{
    mode: "pagination",
    pageSize: 20,
    initialPage: 1,
  }}
/>

// Infinite scroll (loads more as you scroll)
<LogsPanel
  data={logs}
  pagination={{
    mode: "infinite-scroll",
    pageSize: 10,
  }}
/>

// No pagination (show all logs)
<LogsPanel
  data={logs}
  pagination={{ mode: "none" }}
/>

// Default behavior (no pagination prop = show all logs)
<LogsPanel data={logs} />
```

##### 事件回调

当用户与组件交互时获得通知：

```tsx
import { LogsPanel } from "@vention/machine-apps-components"
import type { LogEntry, LogFilterFormValues } from "@vention/machine-apps-components"
;<LogsPanel
  data={logs}
  onFilterChange={(filters: LogFilterFormValues) => {
    console.log("User changed filters:", filters)
    // Track analytics, sync to URL params, etc.
  }}
  onLogClick={(log: LogEntry) => {
    console.log("User clicked log:", log)
    // Show details modal, navigate to details page, etc.
  }}
/>
```

##### 命令式的API

使用ref以编程方式控制组件：

```tsx
import { useRef } from "react"
import { LogsPanel } from "@vention/machine-apps-components"
import type { LogsPanelHandle } from "@vention/machine-apps-components"

function MyComponent() {
  const logsPanelRef = useRef<LogsPanelHandle>(null)

  const handleRefresh = async () => {
    // Manually refresh async data
    await logsPanelRef.current?.refresh()
  }

  const handleResetFilters = () => {
    // Reset all filters to default
    logsPanelRef.current?.resetFilters()
  }

  const handleShowErrors = () => {
    // Programmatically apply filters
    logsPanelRef.current?.applyFilters({ logType: "error" })
  }

  const handleExport = () => {
    // Get current filtered/sorted logs
    const logs = logsPanelRef.current?.exportLogs()
    if (logs) {
      // Export to CSV, JSON, etc.
      downloadAsCSV(logs)
    }
  }

  const handleGetFilters = () => {
    // Get current filter state
    const filters = logsPanelRef.current?.getCurrentFilters()
    console.log("Current filters:", filters)
  }

  return (
    <>
      <div>
        <button onClick={handleRefresh}>Refresh</button>
        <button onClick={handleResetFilters}>Reset Filters</button>
        <button onClick={handleShowErrors}>Show Errors Only</button>
        <button onClick={handleExport}>Export Logs</button>
      </div>
      <LogsPanel ref={logsPanelRef} data={fetchLogs} />
    </>
  )
}
```

**可用的方法:**

-   `refresh()` -手动重新获取当前过滤器/页面的数据
-   `resetFilters()` —将所有过滤器重置为默认值
-   `applyFilters(filters)` —可编程设置过滤器
-   `getCurrentFilters()` -获取当前过滤器状态
-   `exportLogs()` —获取当前显示的日志数组

##### 定制

自定义外观和行为：

```tsx
import { LogsPanel } from "@vention/machine-apps-components"
import { VentionIcon } from "@vention/machine-ui"
;<LogsPanel
  data={logs}
  className="my-custom-logs-panel"
  tableHeight="600px"
  emptyStateMessage="No logs match your filters"
  emptyStateIcon={<VentionIcon type="inbox" size={48} color="gray" />}
/>
```

**定制道具:**

-   `className` —在根容器中添加自定义CSS类
-   `tableHeight` -设置自定义表格高度（例如，“500px”，600）
-   `emptyStateMessage` -当没有日志时自定义消息（默认：“你没有日志”）
-   `emptyStateIcon` -自定义React节点显示上述空消息

#### LogsTable

只有表组件。如果您想自己处理过滤/排序或使用过滤器组合自己的自定义布局，则非常有用。

```tsx
import { LogsTable } from "@vention/machine-apps-components"
import type { LogEntry } from "@vention/machine-apps-components"

<LogsTable 
  logs={logs} 
  onLogClick={log => showDetailsModal(log)} 
  tableHeight="500px" 
  emptyStateMessage="No logs available" 
/>
```

**道具:**

```typescript
interface LogsTableProps {
  logs?: LogEntry[]
  isLoading?: boolean
  error?: string | null
  onLoadMoreLogs?: () => void // For infinite scroll
  hasMoreLogs?: boolean // For infinite scroll
  onLogClick?: (log: LogEntry) => void
  tableHeight?: string | number
  emptyStateMessage?: string
  emptyStateIcon?: ReactNode
}
```

#### LogFilterForm

只有过滤器UI。当您想要完全控制过滤逻辑时，请使用此功能。

```tsx
import { LogFilterForm } from "@vention/machine-apps-components"
import type { LogFilterFormValues } from "@vention/machine-apps-components"

const handleFilterChange = (filters: LogFilterFormValues) => {
  // Apply filters to your own data source
  const filtered = myLogs.filter(log => {
    // Your custom filter logic
  })
}

const handleReset = () => {
  // Handle reset
}

;<LogFilterForm onFilterChange={handleFilterChange} onReset={handleReset} initialFilters={{ logType: "error" }} />
```

#### LogsPagination

只有分页控件。将此用于自定义分页实现。

```tsx
import { LogsPagination } from "@vention/machine-apps-components"
;<LogsPagination currentPage={currentPage} totalPages={totalPages} onPageChange={page => setCurrentPage(page)} />
```

## 开发

### 运行测试

```bash
# Run tests
nx test machine-apps-components

# Run tests with coverage
nx test machine-apps-components --coverage

# Run tests in watch mode
cd projects/machine-code/libs/machine-apps-components
npx vitest
```

### 测试设置

这个库使用带有jdom环境的Vitest来测试React组件。中提供了测试实用程序 `src/test-utils.tsx` 用必要的提供程序包装组件：

-   `ThemeProvider` 与 `machineUiTheme`
-   `MemoryRouter` 进行路由

示例测试:

```tsx
import { renderWithProviders } from "../../test-utils"
import { NavigationBar } from "./navigation-bar"

it("should render correctly", () => {
  renderWithProviders(<NavigationBar navigationItems={mockNavigationItems} />)
  expect(screen.getByText("Operation")).toBeDefined()
})
```

## 建筑

```bash
nx build machine-apps-components
```

## 产品毛羽

```bash
nx lint machine-apps-components
```

## 常见问题

### 如何安装 @vention/machine-apps-components？

在项目目录运行 npm install @vention/machine-apps-components，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：react（17\.0\.2）、@mui/material（^5\.0\.0）、react-router-dom（^6\.0\.0）、@vention/machine-ui（^6\.7\.2）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @vention/machine-apps-components 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @vention/machine-apps-components 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @vention/machine-apps-components 可以商用吗？

@vention/machine-apps-components 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @vention/machine-apps-components 还在维护吗？

最新版本 1\.30\.27 发布于 2026/11/03（今天）；至今共发布 285 个版本，其中过去 12 个月发布了 279 个；首次发布于 2025/10/28。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

