npm package: @qiyuedeyu/do-ui
Description: 基于Vue2和Element-UI的组件库
Author: qiyuedeyu
Latest version: 1.0.6

# BigUI 组件库

基于 Vue2 和 Element-UI 的组件库，提供了一套常用的 UI 组件，方便在项目中快速搭建界面。

## 安装

```bash
npm install @qiyuedeyu/do-ui
```

## 使用

### 全量引入

```javascript
import Vue from 'vue'
import DoUI from '@qiyuedeyu/do-ui'
import '@qiyuedeyu/do-ui/lib/index.css'

Vue.use(DoUI)
```

### 按需引入

```javascript
import Vue from 'vue'
import { EButton, ETable } from '@qiyuedeyu/do-ui'
import '@qiyuedeyu/do-ui/lib/index.css'

Vue.component('EButton', EButton)
Vue.component('ETable', ETable)
```

## 组件列表

- `EButton` - 按钮组件
- `EForm` - 表单组件
- `ETable` - 表格组件（带分页）
- `ESearchTable` - 搜索表格组件
- `EDialog` - 对话框组件

## 组件示例

### EButton 按钮组件

```vue
<template>
  <div>
    <e-button>默认按钮</e-button>
    <e-button type="primary">主要按钮</e-button>
    <e-button type="success">成功按钮</e-button>
    <e-button type="warning">警告按钮</e-button>
    <e-button type="danger">危险按钮</e-button>
    <e-button type="info">信息按钮</e-button>
  </div>
</template>
```

### ETable 表格组件

增强型表格组件，基于 Element UI 的 el-table，提供了数据获取、分页、导出等常用功能。

#### 基本用法

```vue
<template>
  <e-table 
    :data="tableData" 
    :loading="loading"
    :total="total"
    :current-page="currentPage"
    @current-change="handlePageChange">
    <el-table-column prop="name" label="姓名" width="180"></el-table-column>
    <el-table-column prop="age" label="年龄" width="180"></el-table-column>
    <el-table-column prop="address" label="地址"></el-table-column>
  </e-table>
</template>

<script>
export default {
  data() {
    return {
      tableData: [],
      loading: false,
      total: 100,
      currentPage: 1
    }
  },
  methods: {
    handlePageChange(page) {
      console.log('当前页:', page)
    }
  }
}
</script>
```

#### 属性 (Props)

| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| api | 数据获取接口函数 | Function | null |
| lazy | 是否不自动调用 fetch 方法 | Boolean/String | true |
| treeProps | 树形结构配置 | Object | { hasChildren: 'hasChildren', children: 'children' } |
| treeLazy | 是否启用树形懒加载 | Boolean | false |
| treeLoad | 树形懒加载函数 | Function | null |
| exportApi | 导出接口函数 | Function/Boolean/String | null |
| exportMax | 直接导出最大数量，超过后触发下载任务 | Number | 0 |
| exportFileName | 导出文件名称 | Function/String | null |
| exportFileNameEditable | 异步导出文件名是否可编辑 | Boolean | false |
| beforeExport | 导出前校验函数 | Function/Promise | null |
| beforeFetch | 查询前校验函数 | Function/Promise | null |
| params | 请求参数 | Object | null |
| static | 是否静态分页 | Boolean | false |
| height | 表格高度 | Number/String | 250 |
| page | 分页信息 | Object | { current: 1, total: 0, size: 10 } |
| footerSticky | 底部分页是否贴底 | Boolean | false |
| paginationEvents | 分页事件 | Object | null |
| paginationProps | 分页属性 | Object | {} |
| paging | 是否显示分页 | Boolean | true |
| hideFooter | 是否隐藏底部（包括分页） | Boolean | false |
| containerStyle | 显示分页时外层容器的样式 | Object | null |
| bottomStyle | 底层组件样式 | Object | null |
| bottomHeight | 底部组件高度 | Number | 38 |
| columns | 字段配置 | Array | [] |
| data | 表格要显示的数据 | Array | [] |
| disableSelect | 是否禁用选择 | Boolean | false |
| selectDisabled | 判断当前行是否禁止选择的函数 | Function | null |
| multiple | 是否多选 | Boolean | false |
| crossPageSelect | 多选是否跨页面 | Boolean | false |
| rowKey | 行数据的 key | String | null |
| selections | 选中的列表 | Array | [] |
| slots | 插槽配置 | Object | null |
| scopedSlots | 作用域插槽配置 | Object | null |

#### 方法 (Methods)

| 方法名 | 说明 | 参数 |
| --- | --- | --- |
| fetch | 获取数据 | otherParams, keepPage |
| exportFile | 导出文件 | otherParams |
| clear | 清空数据 | - |
| setLoading | 设置加载状态 | Boolean |

#### 事件 (Events)

支持所有 el-table 的事件，以及以下自定义事件：

| 事件名 | 说明 | 参数 |
| --- | --- | --- |
| loaded | 数据加载完成 | data |
| dataChange | 静态分页数据变化 | data |

#### 插槽 (Slots)

| 名称 | 说明 |
| --- | --- |
| bottomLeft | 底部左侧内容 |
| bottomRight | 底部右侧内容 |
| exportDialogContent | 导出对话框内容 |

#### 作用域插槽 (Scoped Slots)

| 名称 | 说明 | 参数 |
| --- | --- | --- |
| bottomLeft | 底部左侧内容 | { table } |
| bottomRight | 底部右侧内容 | { table } |

#### 使用示例

##### 基本数据获取

```vue
<template>
  <e-table 
    :api="fetchData"
    :columns="columns"
    ref="table">
  </e-table>
</template>

<script>
export default {
  data() {
    return {
      columns: [
        { prop: 'name', label: '姓名' },
        { prop: 'age', label: '年龄' },
        { prop: 'address', label: '地址' }
      ]
    }
  },
  methods: {
    async fetchData(params) {
      // 模拟 API 调用
      const response = await this.$http.get('/api/users', { params })
      return response
    }
  },
  mounted() {
    // 手动触发数据获取
    this.$refs.table.fetch()
  }
}
</script>
```

##### 带导出功能的表格

```vue
<template>
  <e-table 
    :api="fetchData"
    :export-api="exportData"
    :export-file-name="'用户列表'"
    :columns="columns"
    ref="table">
    <template #bottomRight>
      <e-button @click="handleExport">导出</e-button>
    </template>
  </e-table>
</template>

<script>
export default {
  data() {
    return {
      columns: [
        { prop: 'name', label: '姓名' },
        { prop: 'age', label: '年龄' },
        { prop: 'address', label: '地址' }
      ]
    }
  },
  methods: {
    async fetchData(params) {
      const response = await this.$http.get('/api/users', { params })
      return response
    },
    async exportData(params) {
      const response = await this.$http.get('/api/users/export', { params })
      return response
    },
    handleExport() {
      this.$refs.table.exportFile()
    }
  }
}
</script>
```

##### 树形表格

```vue
<template>
  <e-table 
    :api="fetchData"
    :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
    :tree-lazy="true"
    :tree-load="loadNode"
    :columns="columns">
  </e-table>
</template>

<script>
export default {
  data() {
    return {
      columns: [
        { prop: 'name', label: '名称' },
        { prop: 'type', label: '类型' }
      ]
    }
  },
  methods: {
    async fetchData(params) {
      const response = await this.$http.get('/api/tree-data', { params })
      return response
    },
    loadNode(node, resolve) {
      if (node.level === 0) {
        return resolve([{ name: '根节点1', type: 'directory' }])
      }
      if (node.level > 3) return resolve([])
      
      setTimeout(() => {
        const data = [{
          name: '子节点' + node.level,
          type: 'file'
        }, {
          name: '子节点' + (node.level + 1),
          type: 'file'
        }]
        resolve(data)
      }, 500)
    }
  }
}
</script>
```

### EForm 表单组件

EForm 组件提供了一种更简洁的方式来创建表单，支持多种字段类型和配置方式。

#### 基本用法

```vue
<template>
  <e-form
    :fields="formFields"
    v-model="formData"
    :inline="true"
    @submit="submitForm"
  >
    <template #actions>
      <div style="margin-left: auto;">
        <e-button type="primary" @click="submitForm">提交</e-button>
        <e-button @click="resetForm">重置</e-button>
      </div>
    </template>
  </e-form>
  
  <div style="margin-top: 20px; padding: 10px; background: #f5f5f5;">
    <h3>表单数据：</h3>
    <pre>{{ formData }}</pre>
  </div>
</template>

<script>
export default {
  data() {
    return {
      formData: {
        name: '',
        age: null,
        email: '',
        status: '',
        gender: '',
        date: ''
      },
      formFields: [
        // 方式一：直接使用普通对象配置字段（推荐）
        {
          prop: 'name',
          label: '姓名',
          type: 'input',
          props: {
            placeholder: '请输入姓名'
          }
        },
        {
          prop: 'age',
          label: '年龄',
          type: 'number',
          props: {
            placeholder: '请输入年龄'
          }
        },
        {
          prop: 'email',
          label: '邮箱',
          type: 'input',
          props: {
            placeholder: '请输入邮箱'
          }
        },
        {
          prop: 'status',
          label: '状态',
          type: 'select',
          options: [
            { label: '启用', value: 'enabled' },
            { label: '禁用', value: 'disabled' }
          ],
          props: {
            placeholder: '请选择状态'
          }
        },
        {
          prop: 'gender',
          label: '性别',
          type: 'radioGroup',
          options: [
            { label: '男', value: 'male' },
            { label: '女', value: 'female' }
          ]
        },
        {
          prop: 'date',
          label: '日期',
          type: 'date',
          props: {
            placeholder: '请选择日期'
          }
        }
      ]
    }
  },
  methods: {
    submitForm() {
      this.$message.success('表单提交成功！')
      console.log('表单数据:', this.formData)
    },
    resetForm() {
      this.formData = {
        name: '',
        age: null,
        email: '',
        status: '',
        gender: '',
        date: ''
      }
      this.$message.info('表单已重置')
    }
  }
}
</script>
```

#### 字段类型

EForm 支持多种字段类型：

- `input` - 输入框
- `number` - 数字输入框
- `select` - 下拉选择框
- `radio` - 单选框
- `radioGroup` - 单选框组
- `checkbox` - 复选框
- `switch` - 开关
- `date` - 日期选择器
- `time` - 时间选择器
- `datetime` - 日期时间选择器
- `daterange` - 日期范围选择器
- `component` - 自定义组件
- `slot` - 插槽

#### 字段配置选项

每个字段支持以下配置选项：

- `prop` - 字段属性名（必填）
- `label` - 字段标签
- `type` - 字段类型（默认为 'input'）
- `props` - 传递给组件的属性
- `events` - 组件事件监听器
- `options` - 选项列表（用于 select、radio 等）
- `readonly` - 是否只读
- `hide` - 是否隐藏
- `itemProps` - 传递给 el-form-item 的属性
- `itemEvents` - el-form-item 的事件监听器
- `submitOnEnter` - 是否在回车时提交表单

#### 使用 Field 类（可选）

您也可以使用 Field 类来创建字段配置：

```javascript
import { Field } from 'do-ui'

formFields: [
  new Field({
    prop: 'name',
    label: '姓名',
    type: 'input',
    props: {
      placeholder: '请输入姓名'
    }
  })
]
```

注意：直接使用普通对象配置字段是推荐的方式，无需导入 Field 类。

### ESearchTable 搜索表格组件

```vue
<template>
  <e-search-table>
    <template slot="search">
      <e-form :model="searchForm" inline>
        <el-form-item label="姓名">
          <el-input v-model="searchForm.name"></el-input>
        </el-form-item>
        <el-form-item label="年龄">
          <el-input v-model="searchForm.age"></el-input>
        </el-form-item>
        <el-form-item>
          <e-button type="primary">搜索</e-button>
          <e-button>重置</e-button>
        </el-form-item>
      </e-form>
    </template>
    
    <template slot="table">
      <e-table :data="searchTableData">
        <el-table-column prop="name" label="姓名" />
        <el-table-column prop="age" label="年龄" />
        <el-table-column prop="address" label="地址" />
      </e-table>
    </template>
  </e-search-table>
</template>

<script>
export default {
  data() {
    return {
      searchForm: {
        name: '',
        age: ''
      },
      searchTableData: []
    }
  }
}
</script>
```

### EDialog 对话框组件

```vue
<template>
  <div>
    <e-button @click="dialogVisible = true">打开对话框</e-button>
    
    <e-dialog title="提示" :visible.sync="dialogVisible">
      <span>这是一个对话框示例</span>
      <span slot="footer">
        <e-button @click="dialogVisible = false">取 消</e-button>
        <e-button type="primary" @click="dialogVisible = false">确 定</e-button>
      </span>
    </e-dialog>
  </div>
</template>

<script>
export default {
  data() {
    return {
      dialogVisible: false
    }
  }
}
</script>
```

## 样式定制

组件库提供了一套默认样式，您可以通过修改 `src/styles` 目录下的 SCSS 变量来自定义样式。

主要的样式文件包括：
- `_variables.scss` - 定义了颜色、字体、间距等变量
- `_mixins.scss` - 定义了常用的 mixins
- `components/_button.scss` - 按钮组件样式
- `components/_table.scss` - 表格组件样式

所有样式类都以 `e-` 为前缀，避免与其他样式冲突。

## 开发

### 本地开发

```bash
# 启动开发服务器
npm run dev

# 构建组件库
npm run build

# 构建 lib 版本
npm run lib
```

### 目录结构

```
do-ui/
├── src/
│   ├── components/      # 组件源码
│   │   ├── button/
│   │   ├── dialog/
│   │   ├── form/
│   │   ├── search-table/
│   │   └── table/
│   ├── styles/          # 样式文件
│   │   ├── components/  # 组件样式
│   │   ├── _mixins.scss
│   │   ├── _variables.scss
│   │   └── index.scss
│   └── index.js         # 组件库入口文件
├── examples/            # 示例代码
├── build/               # 构建配置
├── lib/                 # 构建后的 lib 版本
├── es/                  # 构建后的 es 版本
└── dist/                # 开发服务器输出目录
```

## 发布到 npm

1. 登录 npm 账户：
   ```bash
   npm login
   ```

2. 更新 package.json 中的版本号

3. 构建组件库：
   ```bash
   npm run build
   ```

4. 发布到 npm：
   ```bash
   npm publish
   ```

## License

MIT