<div align="center">
English | [简体中文](./README.zh.md)
</div>

# Vue UI Kit Documentation

A Vue 3 UI component library based on Ant Design Vue, providing enhanced form, grid, and utility components.

## Installation

```bash
npm install @vue-ui-kit/ant
# or
yarn add @vue-ui-kit/ant
# or
pnpm add @vue-ui-kit/ant
```

## Quick Start

### 1. Basic Usage

```ts
/*main.ts*/
import { createApp } from 'vue';
import App from './App.vue';
import Antd from 'ant-design-vue';
import UIKit from '@vue-ui-kit/ant';

// Import styles - choose one of the following methods:
// Method 1: Import SCSS source files (for development, allows variable override)
import '@vue-ui-kit/ant/style.scss';

// Method 1.1: Import compiled SCSS file (for production, standalone file)
// import '@vue-ui-kit/ant/dist/style.scss';

// Method 2: Import compiled CSS file
// import '@vue-ui-kit/ant/style.css';

createApp(App).use(Antd).use(UIKit).mount('#app');
```

### 2. Configure Global Defaults

```ts
/*main.ts*/
import { createApp } from 'vue';
import App from './App.vue';
import Antd from 'ant-design-vue';
import UIKit, { setup } from '@vue-ui-kit/ant';
import '@vue-ui-kit/ant/style.scss';

// Configure global defaults
setup({
  form: {
    labelCol: { span: 8 }, // Modify form label column width
    wrapperCol: { span: 14 }, // Modify form input column width
  },
  grid: {
    align: 'center', // Set default table alignment
    lazyReset: true, // Don't auto-submit after reset
    fitHeight: 30, // Set adaptive height
  },
});

createApp(App).use(Antd).use(UIKit).mount('#app');
```

### 3. Alternative import methods (if main method doesn't work)

If you encounter issues with the standard import, try these alternatives:

```scss
// In your main.scss file
@use '@vue-ui-kit/ant/dist/style.scss';
// or
@import '@vue-ui-kit/ant/dist/style.scss';
```

```ts
// Or using require in JavaScript/TypeScript
require('@vue-ui-kit/ant/style.css');
```

### 4. For Vite users

If using Vite, make sure your vite.config.js includes sass support:

```js
// vite.config.js
export default {
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `@import '@vue-ui-kit/ant/dist/style.scss';`,
      },
    },
  },
};
```

## 🎯 样式文件导入 - 故障排除指南

如果遇到样式文件导入问题，请按顺序尝试以下方法：

### 方法1: 标准导入（推荐）

```typescript
import '@vue-ui-kit/ant/style.scss';
// 或
import '@vue-ui-kit/ant/style.css';
```

### 方法2: 完整路径导入

```typescript
import '@vue-ui-kit/ant/dist/style.scss';
// 或
import '@vue-ui-kit/ant/dist/style.css';
```

### 方法3: SCSS @use 语法

```scss
// 开发环境（源码文件）
@use '@vue-ui-kit/ant/style.scss';

// 生产环境（编译后的独立文件）
@use '@vue-ui-kit/ant/dist/style.scss';
```

### 方法4: 在 style 标签中

```vue
<style lang="scss">
  @import '@vue-ui-kit/ant/style.scss';
</style>
```

### 方法5: Vite 配置导入

```javascript
// vite.config.js
export default defineConfig({
  css: {
    preprocessorOptions: {
      scss: {
        additionalData: `@import '@vue-ui-kit/ant/dist/style.scss';`,
      },
    },
  },
});
```

### 方法6: Webpack 配置

```javascript
// webpack.config.js 或 vue.config.js
module.exports = {
  css: {
    loaderOptions: {
      sass: {
        additionalData: `@import '@vue-ui-kit/ant/dist/style.scss';`,
      },
    },
  },
};
```

### 🔧 调试步骤

1. **检查包版本**: 确保使用 `@vue-ui-kit/ant@1.8.4` 或更高版本
2. **验证文件存在**: 检查 `node_modules/@vue-ui-kit/ant/dist/` 目录下是否有 `style.scss` 和 `style.css`
3. **检查构建工具**: 确保您的构建工具支持处理 `.scss` 文件
4. **清除缓存**: 删除 `node_modules` 和 lock 文件后重新安装

### 📦 包内容确认

安装后可以在以下位置找到样式文件：

```
node_modules/@vue-ui-kit/ant/
├── dist/
│   ├── style.css      # 编译后的CSS
│   └── style.scss     # SCSS源文件
└── src/packages/styles/  # 源文件(开发时参考)
```

```tsx
/*kit.tsx*/
import UIKit from '@vue-ui-kit/ant';
import { TypographyParagraph, Switch } from 'ant-design-vue';

export const setupKit = () => {
  /*Register $paragraph as cell renderer*/
  UIKit.addRender('$paragraph', {
    renderDefault({ props = {} }: RenderOptions, { row, field }: RenderTableParams) {
      const content = props.getContent?.({ row, field }) ?? (valued(field) ? row[field!] : '');
      return valued(field) ? (
        <TypographyParagraph
          {...merge({}, defaultProps.$paragraph, omit(props, ['content', 'getContent']))}
          content={content}
        />
      ) : null;
    },
  });
  /*Register $switch as form renderer*/
  UIKit.addRender('$switch', {
    renderItemContent(
      { props = {}, events = {} }: RenderOptions,
      { data, field }: RenderFormParams,
    ) {
      return valued(field) ? (
        <Switch
          v-model:checked={data[field!]}
          {...props}
          onChange={(...arg) => {
            events.change?.({ data, field }, ...arg);
          }}
        />
      ) : null;
    },
  });
};

/*
* Built-in renderers:
* 
  $input: Input,
  AInput: Input,
  $textarea: Textarea,
  Textarea: Textarea,
  $number: InputNumber,
  AInputNumber: InputNumber,
  $select: Select,
  ASelect: Select,
  $date: DatePicker,
  ADatePicker: DatePicker,
  $range: RangePicker,
  ARangePicker: RangePicker,
  AAutoComplete: AutoComplete,
  $Cascader: Cascader,
  ACascader: Cascader,
  ACheckbox: Checkbox,
  AMentions: Mentions,
  ARate: Rate,
  ASlider: Slider,
  $time: TimePicker,
  ATimePicker: TimePicker,
  ATreeSelect: TreeSelect,
* 
* */
```

## Requirements

- Node.js >= 16
- Vue >= 3.2.0
- ant-design-vue >= 4.0.0
- @ant-design/icons-vue >= 7.0.0

## Components

### PGrid

Enhanced data table component with integrated search form, pagination, and toolbar.

#### Basic Example

```vue
<script setup lang="ts">
  import { computed } from 'vue';
  import { PGridProps, labelColDict } from '@vue-ui-kit/ant';

  const gridSetting = computed<PGridProps<Student, { keyword?: string }>>(() => ({
    columns: [
      { field: 'name', title: 'Name', width: 200 },
      { field: 'email', title: 'Email', width: 200 },
      { field: 'age', title: 'Age', width: 100 },
    ],
    formConfig: {
      searchItems: [
        {
          field: 'keyword',
          title: 'Keyword',
          labelCol: labelColDict[3],
          itemRender: {
            name: '$input',
            props: { placeholder: 'Search...' },
          },
        },
      ],
    },
    proxyConfig: {
      ajax: {
        query: ({ form, page }) => api.getStudents({ ...form, ...page }),
      },
    },
  }));
</script>

<template>
  <p-grid v-bind="gridSetting" />
</template>
```

### PForm

Enhanced Form component with simplified configuration and dynamic fields.

#### Props

| Prop        | Type               | Description                    | Default        |
| ----------- | ------------------ | ------------------------------ | -------------- |
| items       | `PFormItemProps[]` | Form items configuration array | -              |
| data        | `T`                | Form data object               | -              |
| customReset | `() => void`       | Custom reset function          | -              |
| labelCol    | `ColProps`         | Label column layout            | `{ span: 6 }`  |
| wrapperCol  | `ColProps`         | Wrapper column layout          | `{ span: 16 }` |
| ...others   | `FormProps`        | All ant-design-vue Form props  | -              |

#### Events

| Event | Description                      | Parameters              |
| ----- | -------------------------------- | ----------------------- |
| apply | Triggered when form is submitted | `(formData: T) => void` |
| reset | Triggered when form is reset     | `() => void`            |

#### PFormItemProps

| Prop          | Type                            | Description                      | Default  |
| ------------- | ------------------------------- | -------------------------------- | -------- |
| field         | `string`                        | Form field name                  | -        |
| title         | `string`                        | Field label                      | -        |
| span          | `number`                        | Grid span (1-24)                 | -        |
| colon         | `boolean`                       | Show colon after label           | `true`   |
| labelCol      | `ColProps`                      | Label column layout              | -        |
| wrapperCol    | `ColProps`                      | Wrapper column layout            | -        |
| forceRequired | `boolean`                       | Show required mark (visual only) | `false`  |
| align         | `'left' \| 'right' \| 'center'` | Text alignment                   | `'left'` |
| col           | `ColProps`                      | Grid column properties           | -        |
| rule          | `Rule[]`                        | Validation rules                 | -        |
| itemRender    | `ItemRender`                    | Field renderer configuration     | -        |
| tooltipConfig | `TooltipConfig`                 | Tooltip configuration            | -        |
| slots         | `object`                        | Custom slot renderers            | -        |

#### Built-in Renderers

- `$input`: Input field
- `$textarea`: Textarea field
- `$number`: Number input
- `$select`: Select dropdown
- `$date`: Date picker
- `$range`: Date range picker
- `$time`: Time picker
- `ASwitch`: Switch component
- `ACheckbox`: Checkbox
- `ARate`: Rate component
- `ASlider`: Slider component

#### Basic Example

```vue
<script setup lang="ts">
  import { ref, computed } from 'vue';
  import { PFormProps } from '@vue-ui-kit/ant';

  interface UserForm {
    name: string;
    email: string;
    age?: number;
    gender: string;
    skills: string[];
  }

  const formData = ref<UserForm>({
    name: '',
    email: '',
    age: undefined,
    gender: '',
    skills: [],
  });

  const formSetting = computed<PFormProps<UserForm>>(() => ({
    items: [
      {
        field: 'name',
        title: 'Name',
        span: 12,
        rule: [{ required: true, message: 'Please enter name' }],
        itemRender: {
          name: '$input',
          props: { placeholder: 'Enter name' },
        },
      },
      {
        field: 'email',
        title: 'Email',
        span: 12,
        rule: [
          { required: true, message: 'Please enter email' },
          { type: 'email', message: 'Invalid email format' },
        ],
        itemRender: {
          name: '$input',
          props: { placeholder: 'Enter email' },
        },
      },
      {
        field: 'gender',
        title: 'Gender',
        span: 12,
        rule: [{ required: true, message: 'Please select gender' }],
        itemRender: {
          name: '$select',
          props: {
            placeholder: 'Select gender',
            options: [
              { label: 'Male', value: 'male' },
              { label: 'Female', value: 'female' },
            ],
          },
        },
      },
      {
        field: 'skills',
        title: 'Skills',
        span: 24,
        itemRender: {
          name: '$select',
          props: {
            mode: 'multiple',
            placeholder: 'Select skills',
            options: [
              { label: 'Vue.js', value: 'vue' },
              { label: 'React', value: 'react' },
              { label: 'Angular', value: 'angular' },
            ],
          },
        },
      },
    ],
  }));

  const handleSubmit = (data: UserForm) => {
    console.log('Form submitted:', data);
  };
</script>

<template>
  <p-form v-bind="formSetting" :data="formData" @apply="handleSubmit" />
</template>
```

#### Advanced Example with Custom Slots

```vue
<script setup lang="tsx">
  import { ref, computed } from 'vue';

  const formData = ref({
    name: '',
    isActive: false,
  });

  const formSetting = computed(() => ({
    items: [
      {
        field: 'isActive',
        title: 'Status',
        span: 24,
        slots: {
          default: ({ data }) => (
            <a-switch
              v-model:checked={data.isActive}
              checkedChildren="Active"
              unCheckedChildren="Inactive"
            />
          ),
        },
      },
    ],
  }));
</script>
```

### PSearchForm

A search-form wrapper based on `PForm`. Pass only search fields; it appends search and reset buttons automatically and keeps the action column inline when the fields occupy one row. Labels size to their content by default, and search controls default to `width: 100%`; override it through `itemRender.attrs.style.width` when needed.

```vue
<p-search-form
  :data="queryData"
  :items="searchItems"
  :loading="loading"
  @search="handleSearch"
  @reset="handleReset"
/>
```

`PGrid` and `PCanvasGrid` expose the same behavior through `formConfig.searchItems`. It takes precedence over legacy `formConfig.items`; legacy configurations render unchanged without automatic buttons.

| Prop | Type | Description | Default |
| --- | --- | --- | --- |
| items | `PFormItemProps[]` | Search fields; do not include an action item | - |
| data | `T` | Search data object | - |
| loading | `boolean` | Search button loading state | `false` |
| autoReset | `boolean` | Whether to use PForm's existing reset flow | `true` |
| labelCol | `ColProps` | Label layout | `{ flex: 'none' }` |
| wrapperCol | `ColProps` | Control layout | `{ flex: 'auto' }` |
| ...others | `PFormProps` | Props forwarded to PForm | - |

| Event | Description | Parameters |
| --- | --- | --- |
| search | Triggered by search or form submission | `(data: T) => void` |
| reset | Triggered by reset | `() => void` |

### PFormGroup

Dynamic form group component for managing multiple form instances with add/remove capabilities.

#### Props

| Prop | Type | Description | Default |
| --- | --- | --- | --- |
| v-model | `Array<T & { __index: number }>` | Form group data array | `[]` |
| getFormSetting | `(data: T) => PFormProps<T>` | Function to get form configuration | - |
| title | `string` | Group title | - |
| tabLabel | `string` | Custom tab label template | - |
| editAble | `boolean` | Whether tabs are editable | `true` |
| showAdd | `boolean` | Show add button | `true` |
| lazyErrorMark | `boolean` | Lazy error marking | `false` |
| forceRender | `boolean` | Force render all tabs | `false` |
| keepSerial | `boolean` | Keep serial indexing | `false` |
| loading | `boolean` | Loading state | `false` |
| max | `number` | Maximum number of items | `Infinity` |
| itemMenus | `GroupMenuItem[]` | Custom menu items | Default copy/delete |
| createItem | `(opts: { list: T[] }) => Promise<T>` | Custom item creator | - |
| menuHandler | `GroupMenuItemHandler<T>` | Custom menu handler | - |

#### Exposed Methods

| Method       | Description                     | Parameters        | Returns         |
| ------------ | ------------------------------- | ----------------- | --------------- |
| validateAll  | Validate all form instances     | -                 | `Promise<void>` |
| validate     | Validate specific form instance | `__index: number` | `Promise<void>` |
| setActiveKey | Set active tab                  | `key: number`     | `void`          |

#### Basic Example

```vue
<script setup lang="ts">
  import { ref, computed } from 'vue';
  import { PFormGroupProps } from '@vue-ui-kit/ant';

  interface Project {
    __index: number;
    name: string;
    startDate: string;
    endDate: string;
    budget?: number;
  }

  const projects = ref<Project[]>([
    {
      __index: 0,
      name: 'Project A',
      startDate: '',
      endDate: '',
      budget: undefined,
    },
  ]);

  const groupSetting = computed<PFormGroupProps<Project>>(() => ({
    title: 'Project Management',
    showAdd: true,
    max: 10,
    getFormSetting: (data) => ({
      items: [
        {
          field: 'name',
          title: 'Project Name',
          span: 24,
          rule: [{ required: true, message: 'Please enter project name' }],
          itemRender: {
            name: '$input',
            props: { placeholder: 'Enter project name' },
          },
        },
        {
          field: 'startDate',
          title: 'Start Date',
          span: 12,
          rule: [{ required: true, message: 'Please select start date' }],
          itemRender: {
            name: '$date',
            props: { placeholder: 'Select start date' },
          },
        },
        {
          field: 'endDate',
          title: 'End Date',
          span: 12,
          rule: [{ required: true, message: 'Please select end date' }],
          itemRender: {
            name: '$date',
            props: { placeholder: 'Select end date' },
          },
        },
        {
          field: 'budget',
          title: 'Budget',
          span: 24,
          itemRender: {
            name: '$number',
            props: {
              min: 0,
              placeholder: 'Enter budget',
              formatter: (value) => `$ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ','),
              parser: (value) => value.replace(/\$\s?|(,*)/g, ''),
            },
          },
        },
      ],
    }),
  }));

  const handleSave = async () => {
    try {
      await groupRef.value?.validateAll();
      console.log('All projects saved:', projects.value);
    } catch (error) {
      console.error('Validation failed:', error);
    }
  };

  const groupRef = ref();
</script>

<template>
  <div>
    <p-form-group ref="groupRef" v-model="projects" v-bind="groupSetting" />
    <a-button type="primary" @click="handleSave"> Save All Projects </a-button>
  </div>
</template>
```

#### Advanced Example with Custom Menu

```vue
<script setup lang="ts">
  import { ref, computed } from 'vue';

  const projects = ref([]);

  const groupSetting = computed(() => ({
    title: 'Advanced Project Management',
    itemMenus: [
      { content: 'Copy', code: 'copy' },
      { content: 'Delete', code: 'delete' },
      { content: 'Export', code: 'export' },
      {
        content: 'Archive',
        code: 'archive',
        visibleMethod: ({ data }) => data.status !== 'archived',
      },
    ],
    createItem: async ({ list }) => {
      return {
        name: `Project ${list.length + 1}`,
        status: 'active',
        startDate: new Date().toISOString().split('T')[0],
      };
    },
    menuHandler: ({ code, data, index }) => {
      switch (code) {
        case 'export':
          exportProject(data);
          break;
        case 'archive':
          archiveProject(data, index);
          break;
      }
    },
    getFormSetting: (data) => ({
      // ... form configuration
    }),
  }));
</script>
```

## Utility Functions

### labelColDict

Pre-defined label column configurations for different text lengths:

```ts
import { labelColDict } from '@vue-ui-kit/ant';

// Usage in form items
{
  field: 'shortField',
  title: 'Name', // 2 characters
  labelCol: labelColDict[2],
}

{
  field: 'longerField',
  title: 'Description', // 4+ characters
  labelCol: labelColDict[4],
}
```

### Custom Renderers

Register custom form field renderers:

```tsx
import UIKit from '@vue-ui-kit/ant';
import { Switch } from 'ant-design-vue';

UIKit.addRender('$switch', {
  renderItemContent({ props = {}, events = {} }, { data, field }) {
    return (
      <Switch
        v-model:checked={data[field]}
        {...props}
        onChange={(...args) => {
          events.change?.({ data, field }, ...args);
        }}
      />
    );
  },
});
```

### Custom Formatters

Register custom cell formatters for PGrid:

```ts
UIKit.addFormatter({
  currency: ({ cellValue }) => `$${cellValue?.toLocaleString() || '0'}`,
  percentage: ({ cellValue }) => `${(cellValue * 100).toFixed(2)}%`,
});
```

## FAQ

### 1. When using computed + v-bind to generate dynamic tables + forms, form option updates cause table re-rendering. How to solve?

Answer: Separate the formConfig into another computed property

```vue
<p-grid v-bind="gridSetting" :form-config="computedFormConfig" />
```

### 2. Does the table ajax currently only support multiDelete and table data fetching?

Answer: Edit details in most cases cannot correspond one-to-one with the table, so there's no development significance. Multi-row deletion needs to be used together with:

```ts
selectConfig: {
  multiple: true,
},
toolbarConfig: {
  buttons: {
    code: "multipleDelete"
  }
}
```

### 3. Why is the computed approach recommended?

Answer: It simplifies all dynamic logic. For complex scenarios, you can try using reactive and maintain it yourself, but in most cases, computed is more convenient.

## 🔤 TypeScript 类型使用

### 基本类型导入

```typescript
import {
  PGridProps,
  PFormProps,
  PFormItemProps,
  ColumnProps,
  ToolbarConfig,
  UIKitConfig,
} from '@vue-ui-kit/ant';
```

### PGrid 类型使用示例

```typescript
import { computed } from 'vue';
import { PGridProps } from '@vue-ui-kit/ant';

// 定义数据类型
interface Student {
  id: number;
  name: string;
  email: string;
  age: number;
}

// 定义查询表单类型
interface StudentQuery {
  keyword?: string;
  age?: number;
}

// 使用PGridProps类型
const gridSetting = computed<PGridProps<Student, StudentQuery>>(() => ({
  columns: [
    { field: 'name', title: '姓名', width: 200 },
    { field: 'email', title: '邮箱', width: 200 },
    { field: 'age', title: '年龄', width: 100 },
  ],
  formConfig: {
    items: [
      {
        field: 'keyword',
        title: '关键字',
        itemRender: {
          name: '$input',
          props: { placeholder: '请输入关键字' },
        },
      },
    ],
  },
  proxyConfig: {
    ajax: {
      query: ({ form, page }) => api.getStudents({ ...form, ...page }),
    },
  },
}));
```

### PForm 类型使用示例

```typescript
import { ref, computed } from 'vue';
import { PFormProps, PFormItemProps } from '@vue-ui-kit/ant';

// 定义表单数据类型
interface UserForm {
  name: string;
  email: string;
  age?: number;
  gender: string;
}

const formData = ref<UserForm>({
  name: '',
  email: '',
  age: undefined,
  gender: '',
});

// 使用PFormProps类型
const formSetting = computed<PFormProps<UserForm>>(() => ({
  items: [
    {
      field: 'name',
      title: '姓名',
      rule: [{ required: true, message: '请输入姓名' }],
      itemRender: {
        name: '$input',
        props: { placeholder: '请输入姓名' },
      },
    },
    {
      field: 'email',
      title: '邮箱',
      rule: [
        { required: true, message: '请输入邮箱' },
        { type: 'email', message: '邮箱格式不正确' },
      ],
      itemRender: {
        name: '$input',
        props: { placeholder: '请输入邮箱' },
      },
    },
  ] as PFormItemProps<UserForm>[],
}));
```

### 高级类型使用

```typescript
// 1. 自定义列类型
import { ColumnProps } from '@vue-ui-kit/ant';

const customColumns: ColumnProps<Student>[] = [
  {
    field: 'name',
    title: '姓名',
    formatter: (arg) => arg.cellValue?.toUpperCase(),
  },
  {
    field: 'actions',
    title: '操作',
    slots: {
      default: ({ row, rowIndex }) => (
        <button onClick={() => handleEdit(row)}>编辑</button>
      ),
    },
  },
];

// 2. 工具栏配置类型
import { ToolbarConfig } from '@vue-ui-kit/ant';

const toolbarConfig: ToolbarConfig = {
  buttons: [
    {
      code: 'add',
      content: '新增',
      type: 'primary',
      icon: 'PlusOutlined',
    },
  ],
  tools: [
    {
      code: 'refresh',
      icon: 'ReloadOutlined',
    },
  ],
};

// 3. Setup配置类型
import { UIKitConfig } from '@vue-ui-kit/ant';

const kitConfig: UIKitConfig = {
  form: {
    labelCol: { span: 8 },
    wrapperCol: { span: 14 },
  },
  grid: {
    align: 'center',
    lazyReset: true,
    fitHeight: 30,
  },
};
```

### 组件实例类型

```typescript
import { ref } from 'vue';
import { PGridInstance, PFormInstance } from '@vue-ui-kit/ant';

// PGrid 组件实例
const gridRef = ref<PGridInstance<Student, StudentQuery>>();

// 调用实例方法
gridRef.value?.commitProxy.reload();
gridRef.value?.resizeTable();

// PForm 组件实例
const formRef = ref<PFormInstance>();

// 调用实例方法
formRef.value?.reset();
formRef.value?.$form.validateFields();
```

## TypeScript Support

This library is fully written in TypeScript and provides comprehensive type definitions:

```ts
import type {
  PFormProps,
  PFormItemProps,
  PFormGroupProps,
  PGridProps,
  ColumnProps,
} from '@vue-ui-kit/ant';
```

## License

MIT

### 🛠️ 工具方法使用

#### 从npm包导入工具方法

```typescript
import {
  // 响应式布局工具
  getButtonResponsive,
  defaultItemResponsive,
  defaultLabelCol,
  labelColDict,
  get24rest,

  // 表格工具
  cleanCol,

  // 其他工具
  UIKitConfig,
  setup,
} from '@vue-ui-kit/ant';
```

#### getButtonResponsive 使用示例

```typescript
import { getButtonResponsive, defaultItemResponsive } from '@vue-ui-kit/ant';

// 方式1: 根据表单项数量自动计算按钮响应式布局
const buttonSpan1 = getButtonResponsive(3); // 3个表单项
console.log(buttonSpan1);
// 结果: { xs: 24, sm: 24, md: 24, lg: 0, xl: 0, xxl: 6 }

// 方式2: 传入自定义响应式配置数组
const customResponsive = [
  { xs: 24, sm: 12, md: 8, lg: 6, xl: 6, xxl: 6 },
  { xs: 24, sm: 12, md: 8, lg: 6, xl: 6, xxl: 6 },
];
const buttonSpan2 = getButtonResponsive(customResponsive);
console.log(buttonSpan2);
// 计算剩余空间作为按钮区域
```

#### labelColDict 使用示例

```typescript
import { labelColDict } from '@vue-ui-kit/ant';

// 根据标签字符数获取合适的labelCol配置
const labelCol = labelColDict[4]; // 4个字符的标签
console.log(labelCol);
// 结果: { xs: 12, sm: 4, md: 6, lg: 9, xl: 7, xxl: 6 }

// 在表单配置中使用
const formSetting = computed(() => ({
  items: [
    {
      field: 'username',
      title: '用户名称', // 4个字符
      labelCol: labelColDict[4],
      itemRender: {
        name: '$input',
        props: { placeholder: '请输入用户名称' },
      },
    },
  ],
}));
```

#### 响应式布局工具完整示例

```typescript
import { getButtonResponsive, defaultItemResponsive, labelColDict } from '@vue-ui-kit/ant';

// 创建一个动态表单布局计算器
function createFormLayout(items: Array<{ title: string }>) {
  return {
    // 表单项布局
    items: items.map((item) => ({
      ...item,
      col: defaultItemResponsive, // 使用默认响应式布局
      labelCol: labelColDict[item.title.length] || labelColDict[4], // 根据标题长度选择
    })),

    // 按钮区域布局
    buttonCol: getButtonResponsive(items.length),
  };
}

// 使用示例
const layout = createFormLayout([{ title: '姓名' }, { title: '邮箱地址' }, { title: '手机号码' }]);

console.log('按钮布局:', layout.buttonCol);
// 自动计算最后一行剩余空间给按钮使用
```

#### cleanCol 表格列处理

```typescript
import { cleanCol, type ColumnProps } from '@vue-ui-kit/ant';

// 自定义列配置
const customColumn: ColumnProps<User> = {
  field: 'name',
  title: '用户名',
  formatter: 'capitalize',
  cellRender: {
    name: '$link',
    props: { href: '#' },
  },
  slots: {
    default: ({ row }) => <span>{row.name}</span>,
  },
};

// 清理列配置，移除UI Kit特有属性，转换为Ant Design Vue标准格式
const antColumn = cleanCol(customColumn);
console.log(antColumn);
// 结果会移除 formatter, cellRender, slots 等UI Kit特有属性
// 保留 Ant Design Vue 原生支持的属性
```

#### get24rest 栅格计算

```typescript
import { get24rest } from '@vue-ui-kit/ant';

// 计算24栅格系统中的剩余空间
const usedSpans = [6, 8, 4]; // 已使用的栅格数
const restSpan = get24rest(usedSpans);
console.log(restSpan); // 结果: 6 (24 - 6 - 8 - 4 = 6)

// 在表单中动态计算按钮位置
const formItems = [
  { span: 8 }, // 表单项1
  { span: 8 }, // 表单项2
  { span: 6 }, // 表单项3
];
const buttonSpan = get24rest(formItems.map((item) => item.span));
// 按钮将占据剩余的2格空间，如果小于等于1则占满整行(24格)
```

#### 在Vue组件中使用

```vue
<template>
  <div>
    <a-row :gutter="[16, 16]">
      <!-- 动态表单项 -->
      <a-col v-for="(item, index) in formItems" :key="index" v-bind="defaultItemResponsive">
        <a-form-item :label="item.label" :label-col="getLabelCol(item.label)">
          <a-input v-model:value="item.value" />
        </a-form-item>
      </a-col>

      <!-- 动态按钮区域 -->
      <a-col v-bind="buttonLayout">
        <a-button type="primary">提交</a-button>
        <a-button>重置</a-button>
      </a-col>
    </a-row>
  </div>
</template>

<script setup lang="ts">
  import { computed } from 'vue';
  import { getButtonResponsive, defaultItemResponsive, labelColDict } from '@vue-ui-kit/ant';

  const formItems = ref([
    { label: '姓名', value: '' },
    { label: '电子邮箱', value: '' },
    { label: '联系电话', value: '' },
  ]);

  // 动态计算按钮布局
  const buttonLayout = computed(() => getButtonResponsive(formItems.value.length));

  // 根据标签长度获取合适的labelCol
  const getLabelCol = (label: string) => labelColDict[label.length] || labelColDict[4];
</script>
```

## 📦 组件和工具导入

### ✅ 正确的导入方式

```typescript
// 方式1: 分别导入 (推荐)
import {
  // 组件
  PForm,
  PGrid,
  PFormGroup,
  PGroupBlock,
  PromisePicker,

  // 类型
  PGridProps,
  PFormProps,
  PFormItemProps,
  ColumnProps,
  UIKitConfig,

  // 工具方法
  getButtonResponsive,
  labelColDict,
  defaultItemResponsive,
  get24rest,
  cleanCol,

  // 配置方法
  setup,
  addFormatter,
  addRender,
} from '@vue-ui-kit/ant';

// 方式2: 默认导入 + 命名导入
import UIKit, { PForm, PGrid, setup } from '@vue-ui-kit/ant';
```

### 🔧 完整使用示例

```vue
<template>
  <div class="demo-page">
    <!-- PForm 组件 -->
    <PForm
      ref="formRef"
      v-bind="formSetting"
      :data="formData"
      @apply="handleFormSubmit"
      @reset="handleFormReset"
    />

    <!-- PGrid 组件 -->
    <PGrid ref="gridRef" v-bind="gridSetting" @toolbar-button-click="handleToolbarClick" />
  </div>
</template>

<script setup lang="ts">
  import { ref, computed } from 'vue';
  import {
    // 直接导入组件
    PForm,
    PGrid,

    // 导入类型
    PFormProps,
    PGridProps,
    PFormInstance,
    PGridInstance,

    // 导入工具方法
    getButtonResponsive,
    labelColDict,

    // 导入配置方法
    setup,
  } from '@vue-ui-kit/ant';

  // 配置全局默认值
  setup({
    grid: {
      align: 'center',
      fitHeight: 30,
    },
    form: {
      labelCol: labelColDict[4],
    },
  });

  // 类型定义
  interface User {
    id: number;
    name: string;
    email: string;
  }

  interface UserForm {
    name: string;
    email: string;
  }

  interface UserQuery {
    keyword?: string;
  }

  // 组件引用
  const formRef = ref<PFormInstance>();
  const gridRef = ref<PGridInstance<User, UserQuery>>();

  // 表单数据
  const formData = ref<UserForm>({
    name: '',
    email: '',
  });

  // 表单配置
  const formSetting = computed<PFormProps<UserForm>>(() => ({
    items: [
      {
        field: 'name',
        title: '用户名',
        labelCol: labelColDict[3], // 3个字符的标签
        rule: [{ required: true, message: '请输入用户名' }],
        itemRender: {
          name: '$input',
          props: { placeholder: '请输入用户名' },
        },
      },
      {
        field: 'email',
        title: '邮箱地址',
        labelCol: labelColDict[4], // 4个字符的标签
        rule: [
          { required: true, message: '请输入邮箱' },
          { type: 'email', message: '邮箱格式不正确' },
        ],
        itemRender: {
          name: '$input',
          props: { placeholder: '请输入邮箱地址' },
        },
      },
    ],
  }));

  // 网格配置
  const gridSetting = computed<PGridProps<User, UserQuery>>(() => ({
    columns: [
      { field: 'name', title: '用户名', width: 200 },
      { field: 'email', title: '邮箱', width: 200 },
    ],
    formConfig: {
      items: [
        {
          field: 'keyword',
          title: '关键字',
          labelCol: labelColDict[3],
          itemRender: {
            name: '$input',
            props: { placeholder: '请输入关键字' },
          },
        },
      ],
    },
    toolbarConfig: {
      buttons: [
        {
          code: 'add',
          content: '新增',
          type: 'primary',
          icon: 'PlusOutlined',
        },
      ],
    },
    proxyConfig: {
      ajax: {
        query: ({ form, page }) => api.getUsers({ ...form, ...page }),
      },
    },
  }));

  // 事件处理
  const handleFormSubmit = (data: UserForm) => {
    console.log('表单提交:', data);
  };

  const handleFormReset = () => {
    console.log('表单重置');
  };

  const handleToolbarClick = ({ code, data, selectedKeys }) => {
    console.log('工具栏点击:', { code, data, selectedKeys });

    if (code === 'add') {
      // 处理新增逻辑
    }
  };

  // 使用工具方法
  const buttonLayout = computed(
    () => getButtonResponsive(2), // 根据表单项数量计算按钮布局
  );
</script>
```

### 🚨 常见导入错误

```typescript
// ❌ 错误：这样无法导入组件
import { PForm, PGrid } from '@vue-ui-kit/ant/components';

// ❌ 错误：组件不能从utils路径导入
import { PForm } from '@vue-ui-kit/ant/utils';

// ❌ 错误：混合默认导入和组件导入
import UIKit, PForm from '@vue-ui-kit/ant'; // 语法错误

// ✅ 正确：从主包路径导入所有内容
import {
  PForm,
  PGrid,
  getButtonResponsive,
  labelColDict
} from '@vue-ui-kit/ant';
```

### 📋 可导入的完整列表

#### 组件

- `PForm` - 增强表单组件
- `PGrid` - 增强数据表格组件
- `PFormGroup` - 动态表单组组件
- `PGroupBlock` - 表单块组件
- `PromisePicker` - 数据选择器组件

#### 类型定义

- `PFormProps<T>` - 表单属性类型
- `PGridProps<D, F>` - 网格属性类型
- `PFormInstance` - 表单实例类型
- `PGridInstance<D, F>` - 网格实例类型
- `ColumnProps<T>` - 列配置类型
- `UIKitConfig` - 全局配置类型

#### 工具方法

- `getButtonResponsive()` - 计算按钮响应式布局
- `labelColDict` - 标签宽度配置字典
- `defaultItemResponsive` - 默认响应式配置
- `get24rest()` - 栅格剩余空间计算
- `cleanCol()` - 清理列配置

#### 配置方法

- `setup()` - 全局配置设置
- `addFormatter()` - 添加格式化器
- `addRender()` - 添加渲染器
