UNPKG

@vue-ui-kit/ant

Version:

Vue3 UI Kit based on Ant Design

1,394 lines (1,172 loc) 33.6 kB
<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: 200, // 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源文件(已内联variables) └── 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: { items: [ { 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> ``` ### 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: 200, }, }; ``` ### 组件实例类型 ```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: 180, }, 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()` - 添加渲染器