# Element Component Pro

基于 Element UI 的二次封装组件库，参考 VbenAdmin 的 Ant Design 版本，提供 Pro 系列增强组件。

## 技术栈

- **Vue 2.7** - 支持 Composition API 和 `<script setup>` 语法糖
- **TypeScript** - 完整类型支持
- **Element UI** - 基础 UI 组件

## 组件列表

| 组件 | 说明 |
|------|------|
| ProTable | 增强表格，集成搜索、工具栏、分页 |
| ProTableForm | 对比表表单：固定行 + 友商动态行，指标列可千分位 |
| CollapseContainer | Vben 风格折叠容器，适合收纳查询区和内容面板 |
| ProForm | Schema 驱动的表单，支持栅格布局 |
| FormattedNumberInput | 千分位数字输入（`component: 'formatted-number'` 所用组件，可单独按需引入） |
| ProCard | 卡片容器 |
| ProDescriptions | 详情描述列表 |

## 安装

```bash
npm install element-component-pro element-ui vue
```

## 使用

### 全局注册

```ts
import Vue from 'vue'
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import ElementComponentPro from 'element-component-pro'

Vue.use(ElementUI)
Vue.use(ElementComponentPro)
```

### 按需引入

```vue
<script setup lang="ts">
import { ProTable, ProForm, ProDescriptions } from 'element-component-pro'
</script>

<template>
  <ProTable :columns="columns" :request="fetchData" />
</template>
```

## ProTable

```vue
<template>
  <ProTable
    :columns="columns"
    :api="fetchTableData"
    row-key="id"
    :pagination="{ pageSize: 10 }"
  />
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { ProTable } from 'element-component-pro'
import type { ProColumn } from 'element-component-pro'

const columns: ProColumn[] = [
  { title: 'ID', dataIndex: 'id', width: 80, valueType: 'index' },
  { title: '姓名', dataIndex: 'name', width: 120 },
  {
    title: '状态',
    dataIndex: 'status',
    valueType: 'select',
    valueEnum: { 1: { text: '启用' }, 0: { text: '禁用' } },
  },
]

const fetchTableData = async (params) => {
  const res = await api.getList(params)
  // ProTable 约定返回 { list, total }，与 VbenAdmin 一致
  return { list: res.list, total: res.total }
}
</script>
```

### ProTable + useProTable（tableAction）

参考 VbenAdmin 的 `useTable`，ProTable 提供 `useProTable` Hook，对外暴露 `tableAction` 方法。**可选传入 props**：`useProTable(props)` 支持传入 `ProTableProps` 或 `Ref<ProTableProps>`，会在表格 `@register` 时通过 `setProps` 应用，且 props 为响应式时变更会自动同步到表格（类型 `UseProTablePropsReactive`）。

```vue
<template>
  <ProTable
    @register="registerTable"
    title="用户列表"
    :columns="columns"
    :api="fetchTableData"
    row-key="id"
    :row-selection="{ type: 'checkbox' }"
  />
</template>

<script setup lang="ts">
import { ProTable, useProTable } from 'element-component-pro'
import type { ProColumn, TableActionType } from 'element-component-pro'

const columns: ProColumn[] = [
  { title: 'ID', dataIndex: 'id', width: 80 },
  { title: '姓名', dataIndex: 'name', width: 120 },
  { title: '年龄', dataIndex: 'age', width: 80 },
]

const [registerTable, tableAction] = useProTable()

const reload = () => {
  // 支持传入 page / pageSize / searchInfo，与 VbenAdmin 对齐
  tableAction.reload({ page: 1 })
}
</script>
```

**TableActionType 常用方法（与 VbenAdmin BasicTable 对齐）：**

| 方法 | 说明 |
|------|------|
| `setProps` | 动态更新 ProTable Props，例如列配置、分页配置等 |
| `reload(opt?: FetchParams)` | 重新请求数据，支持指定页码、每页条数、搜索参数 |
| `setLoading(loading: boolean)` | 手动切换表格 loading 状态 |
| `getDataSource()` / `setTableData(data)` | 获取 / 设置当前表格数据 |
| `getRawDataSource()` | 获取接口原始返回数据（未经过 afterFetch） |
| `getColumns()` / `setColumns(cols)` | 获取 / 设置列配置，支持传 `ProColumn[]` 或列 key 数组 |
| `setPagination(info)` | 设置分页信息（page、pageSize、total） |
| `getSelectRowKeys()` / `getSelectRows()` | 获取当前选中行的 keys / 行数据 |
| `getRowSelection()` | 获取当前行选择配置（rowSelection） |
| `setSelectedRowKeys(keys)` / `clearSelectedRowKeys()` | 设置 / 清空选中行 |
| `deleteSelectRowByKey(key)` | 取消勾选指定 key 的行 |
| `updateTableDataRecord(rowKey, record)` | 按 rowKey 更新某一行（局部刷新，不重新请求接口） |
| `deleteTableDataRecord(rowKey)` | 按 rowKey 删除行（支持单个或数组） |
| `insertTableDataRecord(record, index?)` | 在指定位置插入一行数据 |
| `getPaginationRef()` | 获取当前分页信息 `{ page, pageSize, total }` |
| `getShowPagination()` / `setShowPagination(show)` | 获取 / 设置是否显示分页 |
| `expandAll()` / `collapseAll()` | 展开 / 折叠树形表格所有行 |

### ProTable 操作列 + TableAction 组件

参考 VbenAdmin 的 `TableAction`，ProTable 提供了独立的 `TableAction` 组件，用于快速渲染「编辑 / 删除 / 更多」等操作按钮。

```vue
<template>
  <ProTable
    title="操作列示例"
    :columns="columns"
    :data-source="data"
    :action-column="{ title: 'Action', dataIndex: 'action', width: 220, fixed: 'right' }"
  >
    <template #bodyCell="{ column, record }">
      <!-- 只处理 action 列，其它列仍按默认方式渲染（与 Vben bodyCell 行为一致） -->
      <template v-if="column.dataIndex === 'action'">
        <TableAction
          :actions="[
            {
              label: '编辑',
              onClick: () => handleEdit(record),
            },
          ]"
          :drop-down-actions="[
            {
              label: '删除',
              color: 'error',
              popConfirm: {
                title: '确认删除该行？',
                confirm: () => handleDelete(record),
              },
            },
          ]"
        />
      </template>
    </template>
  </ProTable>
</template>

<script setup lang="ts">
import { ProTable, TableAction } from 'element-component-pro'
import type { ProColumn } from 'element-component-pro'

const columns: ProColumn[] = [
  { title: '姓名', dataIndex: 'name', width: 120 },
  { title: '年龄', dataIndex: 'age', width: 80 },
  { title: '地址', dataIndex: 'address', minWidth: 200 },
]

const data = [
  { id: 1, name: '张三', age: 28, address: '北京市朝阳区' },
  { id: 2, name: '李四', age: 32, address: '上海市浦东新区' },
]

const handleEdit = (record: Record<string, unknown>) => {
  console.log('编辑', record)
}
const handleDelete = (record: Record<string, unknown>) => {
  console.log('删除', record)
}
</script>
```

**TableActionItem 支持的字段（与 VbenAdmin ActionItem 对齐）：**

- **label**：按钮文本
- **icon**：图标 class（可传 Element UI 图标或自定义 iconfont）
- **color**：`success / error / warning`，内部映射为对应按钮类型
- **type**：直接透传给 `el-button` 的 `type`
- **props**：额外的按钮 props
- **disabled**：是否禁用
- **divider**：是否在该操作后显示分隔线
- **ifShow**：是否显示当前操作项（支持函数）
- **tooltip**：字符串或 Tooltip 配置对象
- **popConfirm**：气泡确认配置 `{ title, okText, cancelText, confirm, cancel }`
- **onClick**：点击回调

## ProForm

参考 [Vben Admin Form](https://doc.vvbin.cn/components/form.html)，支持 Schema 驱动、useForm、render/slot、动态显示等。

### 基础用法

```vue
<template>
  <ProForm
    :schemas="schemas"
    :initial-values="{ name: '' }"
    :base-col-props="{ span: 8 }"
    @submit="handleSubmit"
  />
</template>

<script setup lang="ts">
import { ProForm } from 'element-component-pro'
import type { ProFormSchema } from 'element-component-pro'

const schemas: ProFormSchema[] = [
  { field: 'name', label: '姓名', component: 'input', required: true, colProps: { span: 8 } },
  {
    field: 'status',
    label: '状态',
    component: 'select',
    componentProps: {
      options: [
        { label: '启用', value: 1 },
        { label: '禁用', value: 0 },
      ],
    },
    colProps: { span: 8 },
  },
]

const handleSubmit = (values) => {
  console.log(values)
}
</script>
```

### useForm 方式（参考 Vben Admin）

```vue
<template>
  <ProForm @register="register" @submit="handleSubmit" />
</template>

<script setup lang="ts">
import { ProForm, useForm } from 'element-component-pro'

const [register, formActions] = useForm({
  schemas: [...],
  labelWidth: '120px',
  actionColOptions: { span: 24 },
})

// 支持 ref/computed 响应式 props
const formProps = ref({ schemas: [...] })
const [register2] = useForm(formProps)

const handleSubmit = (values) => {
  console.log(values)
}
</script>
```

**useForm 方法（与 Vben Admin 对齐）：**

| 方法 | 说明 |
|------|------|
| getFieldsValue | 获取表单值 |
| setFieldsValue | 设置表单字段值 |
| resetFields | 重置表单 |
| validate | 校验整个表单 |
| validateFields | 校验指定表单项 |
| submit | 提交表单 |
| scrollToField | 滚动到对应字段 |
| clearValidate | 清空校验 |
| updateSchema | 更新 schema |
| appendSchemaByField | 插入 schema |
| removeSchemaByField | 删除 schema |
| setProps | 设置表单 Props |

### Schema 高级特性

- **render**: 自定义渲染
- **slot**: 使用具名插槽自定义
- **ifShow** / **show**: 动态显示（ifShow 不渲染 DOM）
- **dynamicDisabled**: 动态禁用
- **dynamicRules**: 动态校验规则
- **labelWidth**: 支持字段级标签宽度，覆盖表单级 `labelWidth`
- **tooltip**: 支持字段 value 的悬浮提示，可直接显示当前值或动态文案
- **v-model**: 支持 `modelValue` 双向绑定，`initialValues` 仅补齐缺失字段
- **useForm + v-model**: 编程式 `setFieldsValue/resetFields` 与受控 `modelValue` 保持同步
- **componentProps**: 支持函数，可获取 formModel、formActionType

```ts
{
  field: 'name',
  label: '姓名',
  component: 'input',
  tooltip: true,
}

{
  field: 'status',
  label: '状态',
  component: 'select',
  tooltip: ({ values }) => values.name ? `当前姓名：${values.name}` : '请选择状态',
}
```

更多说明见 `docs/ProForm.md`。

## ProDescriptions

参考 [Vben Admin Description](https://doc.vvbin.cn/components/desc.html#usage)，用于详情页信息展示，支持 `schema` 驱动、响应式列数、折叠以及 `useDescription` 编程式更新。

- **tooltip**: 支持字段 value 的悬浮提示，适合长文本、数组值和对象值预览

```vue
<template>
  <ProDescriptions
    title="基础示例"
    :column="3"
    :data="detailData"
    :schema="schema"
    :use-collapse="true"
    :collapse-options="{ canExpand: true }"
  />
</template>

<script setup lang="ts">
import { ProDescriptions } from 'element-component-pro'
import type { DescriptionSchema } from 'element-component-pro'

const detailData = {
  username: 'test',
  nickName: 'VB',
  phone: '15695909xxx',
  email: '190848757@qq.com',
}

const schema: DescriptionSchema[] = [
  { label: '用户名', dataIndex: 'username' },
  { label: '昵称', dataIndex: 'nickName' },
  { label: '联系电话', dataIndex: 'phone' },
  { label: '邮箱', dataIndex: 'email' },
]
</script>
```

### useDescription

```vue
<template>
  <ProDescriptions @register="register" />
</template>

<script setup lang="ts">
import { ProDescriptions, useDescription } from 'element-component-pro'

const [register, descriptionAction] = useDescription({
  title: 'useDescription',
  data: {
    name: '张三',
    status: '启用',
  },
  schema: [
    { label: '姓名', dataIndex: 'name' },
    { label: '状态', dataIndex: 'status' },
  ],
})

const updateData = () => {
  descriptionAction.setData({ status: '禁用' })
}
</script>
```

## 示例与文档

- **示例**：运行 `npm run dev` 后访问开发预览，包含 ProTable、ProForm、componentSettings 测试等示例
- **ProTable 文档**：[docs/ProTable.md](./docs/ProTable.md)
- **ProForm 文档**：[docs/ProForm.md](./docs/ProForm.md)
- **组件默认配置**：[docs/ComponentSetting.md](./docs/ComponentSetting.md)（`useComponentSetting`）

## 开发

```bash
# 安装依赖
npm install

# 开发预览
npm run dev

# 构建
npm run build
```

## License

MIT
