# 通用列表 UniList

ElTable 的二次封装

通过配置提供分页,请求,筛选按钮,操作按钮,表单生成等功能

你应该使用本组件

  • 需求为用于显示数据的普通列表
  • 有通用的请求方式
  • 有比较固定的表结构

你不应该使用本组件

  • 需求有树状结构,多级表头,排序,合并行等的复杂列表
  • 请求方式与其他页面不通用
  • 表结构需要频繁更改

# 基础显示

# schema 属性描述表结构

schema 属性允许你定义表结构,覆盖表样式,每一个 UniList 组件都应首先定义 schema

简单的schema配置示例
暂无数据
  • 1
前往
共 0 条

schema 属性接收一个对象,key 为字段名,value 为表头名








 
 
 
 
 
 





<template>
  <UniList title="简单的schema配置示例" :schema="schema" />
</template>
<script>
  export default {
    data() {
      return {
        schema: {
          title: "标题",
          name: "姓名",
          address: "地址",
          content: "内容",
        },
      };
    },
  };
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Expand Copy

schema 属性每一项的 value 被绑定到了对应的 el-table-column 组件,所以你也可以使用这些属性来自定义列样式:

参数 说明 类型 可选值 默认值
label 显示的标题 string
width 对应列的宽度 string
min-width 对应列的最小宽度,与 width 的区别是 width 是固定的,min-width 会把剩余宽度按比例分配给设置了 min-width 的列 string 150
formatter 用来格式化内容 Function({row, column, value, $index})
align 对齐方式 String left/center/right center
class-name 列的 className string

例外

为了使用方便,formatter类型与 element 不同,为Function({row, column, value, $index})

使用时:

schema = {
  //错误
  foo:{
    formatter:(row,column,cellValue)=>{ console.log(cellValue,row) }
  }
  //正确
  bar:{
    formatter:({value,row})=>{ console.log(value,row) }
  }
  //正确
  baz:{
    formatter:({row,$index})=>{ console.log(row,$index) }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
复杂的schema配置示例
暂无数据
  • 1
前往
共 0 条

schema 属性接收一个对象,key 为字段名,value 为一个 el-table-column 组件的属性








 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 





<template>
  <UniList title="复杂的schema配置示例" :schema="schema" />
</template>
<script>
  export default {
    data() {
      return {
        schema: {
          $index: "", //特殊属性,渲染序号
          $selection: "", //特殊属性,多选模式
          title: {
            label: "标题",
            minWidth: 200,
            align: "left",
          },
          name: "姓名",
          address: "地址",
          content: {
            label: "内容",
            formatter: ({ value, $index }) => {
              return "第" + $index + "行的内容:" + value;
            },
          },
        },
      };
    },
  };
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Expand Copy

# 使用插槽定制列元素

聪明的你可能会问,表格中的图片或更复杂的东西怎么显示呢

不用怕,我们用保留了定制列的能力

使用列插槽定制你的表格
暂无数据
  • 1
前往
共 0 条

列插槽的名字是字段名,所以你在写插槽之前需要先使用 schema 定义表结构




 
 
 
 
 
 
























<template>
  <UniList title="使用列插槽定制你的表格" :schema="schema">
    <!-- 作用域插槽的传值依然是{row, column, value, $index} -->
    <template #avatar="{row}">
      <el-avatar>王{{ row.id }}</el-avatar>
    </template>
    <template #name="{value}">
      <el-tag type="success">{{ value }}</el-tag>
    </template>
  </UniList>
</template>
<script>
  export default {
    data() {
      return {
        schema: {
          avatar: {
            label: "", //可以使用空string隐藏表头
            width: 70,
          },
          title: {
            label: "标题",
            align: "left",
          },
          name: "姓名",
          address: "地址",
          content: "内容",
        },
      };
    },
  };
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Expand Copy

# 重写配置

不同的项目中可能需要完全不一样的请求,刷新,操作逻辑和样式

我们提供了两种覆盖配置的方式

# 全局配置策略

使用方法:直接修改自定义配置文件 UniList/custom.ts 中的方法和成员

提示

首次使用本组件时,你应该修改 UniList/custom.ts 配置文件中的 fetch 方法以适配当前项目的请求方式














 
 
 
 








 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 






import { Component } from "vue-property-decorator";
import Base from "./base";

//类语法 我已经替你写好了,你只需要改这个类里面的方法
@Component({})
export default class extends Base {
  //其他配置...

  /**
   * 例1
   * 列样式
   * 可以被schema中的value覆盖
   */
  columnStyle = {
    align: "center", // 默认对齐
    minWidth: "150", // 默认最小宽度
  };

  /**
   * 例2
   * 这是本页面示例中的 fetch 方法
   * 延时并返回模拟数据
   * 可以在init中覆盖
   * 更多信息请查看 UniList/custom.ts
   */
  async fetch() {
    //在这里你也可以通过this.api获得接口标记,并做出相关处理
    const formData = { ...this.pages, ...this.params };
    const total = 31;
    const data = [];
    for (let i = 1; i <= total; i++) {
      data.push({
        id: i,
        title: "title" + i,
        name: "王小虎",
        address: `上海市普陀区金沙江路 ${1517 + i}`,
        content: "text" + i,
      });
    }

    return new Promise<any>((R) =>
      setTimeout(
        () =>
          R({
            pages: { current: formData.current, total },
            data: data.slice(
              (formData.current - 1) * formData.size,
              formData.current * formData.size
            ),
          }),
        500
      )
    );
  }

  //其他配置...
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58

# 单组件配置策略

使用方法:初始化时返回构造配置对象

传递init函数,接收一个参数为本组件实例,返回配置对象
暂无数据
  • 1
前往
共 0 条

init 函数可以定义在 data 中





 










 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 





<template>
  <UniList
    title="传递init函数,接收一个参数为本组件实例,返回配置对象"
    :schema="schema"
    :init="init"
  />
</template>
<script>
  export default {
    data() {
      return {
        schema: {
          title: "标题",
          name: "姓名",
        },
        init: (page) => {
          // 别着急,此处接收的组件实例在后面会有大用
          return {
            async fetch() {
              return {
                pages: { current: 1, total: 1 },
                data: [
                  {
                    title: "妈耶,我的值被自定义fetch方法给覆盖了",
                    name: "由于设置了columnStyle.align,本行应该靠右对齐",
                  },
                ],
              };
            },
            columnStyle: {
              align: "right", // 默认对齐
              minWidth: "150", // 默认最小宽度
            },
          };
        },
      };
    },
  };
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Expand Copy

# 数据流向

有两种方式为本组件提供数据,

# api 属性注入请求标记 通用

注意

api 属性仅仅是一个标记,理论上来说你可以传入任何值,具体实现要由 fetch 方法实现

例:

api 属性传入 fetch 中实现 备注
'/user/list' axios.post(this.api, data) 传入地址直接引入 axios 发出请求
'userList' app.post[this.api](data) 传入某个方法名并由自定义的 app.post 类集中控制发出请求

# data 属性接管表格数据 慎用

注意

当你使用了 data 属性,fetch 方法将失效,所有数据流都需要由外部接管

使用data提供数据
  • 1
前往
共 0 条
<template>
  <UniList
    title="使用data提供数据"
    :schema="schema"
    :data="[{ title: '法外狂徒', name: '张三' }]"
    :init="init"
  />
</template>
<script>
  export default {
    data() {
      return {
        schema: {
          title: "标题",
          name: "姓名",
        },
        init() {
          return {
            pages: { current: 123, total: 4321 },
          };
        },
      };
    },
  };
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Expand Copy
监听fetch事件修改data
暂无数据
  • 1
前往
共 0 条
<template>
  <UniList
    title="监听fetch事件修改data"
    :schema="schema"
    :data="data"
    :init="init"
    @fetch="(list) => getData(list.pages.current)"
  />
</template>
<script>
  export default {
    data() {
      return {
        data: [],
        schema: {
          title: "标题",
          name: "姓名",
        },
        init() {
          return {
            pages: { current: 1, total: 7, size: 5 },
          };
        },
      };
    },
    methods: {
      getData(current) {
        const start = 5 * (current - 1);
        const nzh = "三四五六七八九";
        const d = [];
        for (let i = 0; i < 5; i++) {
          if (nzh[start + i])
            d.push({ title: "法外狂徒", name: "张" + nzh[start + i] });
        }
        this.data = d;
      },
    },
  };
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Expand Copy

# 按钮和内容的依赖注入

前置知识学完,终于可以向你介绍本组件最为强大的功能:依赖注入

依赖可以是你的按钮,文本,表单,自定义组件或者其他

从配置中注入渲染Action和Header的能力
暂无数据
  • 1
前往
共 0 条
<template>
  <UniList
    title="从配置中注入渲染Action和Header的能力"
    :schema="schema"
    :init="init"
  />
</template>
<script>
  export default {
    data() {
      return {
        schema: {
          title: "标题",
          name: "姓名",
        },
        init(page) {
          //这里接收到的是UniList组件实例
          //其中暴露了一些功能方法
          return {
            header: {
              打开view层: () => page.view({ text: 123 }),
            },
            action: {
              文本dialog: ({ row }) => page.dialog({ text: row.title }),
              组件dialog: ({ row }) =>
                page.dialog({ component: "Badge", props: { text: row.name } }),
            },
          };
        },
      };
    },
  };
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Expand Copy

# 按钮注入能力

你可以在 init 函数的返回对象中定义 action 或 header 对象,其中的每一项都会生成对应的按钮

Action Header
位置 表格上方 表格中每一行右侧
配置语法 action 对象{按钮名字:触发方法} header 对象{按钮名字:触发方法}
方法接收参数 {row, column, value, $index} 已选行数组(仅在多选模式生效)
一般用于 当前行的编辑,删除,详情 当前列表的添加,导入,下载,批量删除(开启多选模式)
修改样式 使用 actionStyle 对象 使用 headerStyle 对象

actionStyle 和 headerStyle 对象中,key 值是正则字符串,value 是一个对象,其中的值会被绑定到 el-button 组件上 action 和 header 对象中每一项的 value 值除了可以传一个函数作为触发方法外,你也可以传递完整的配置属性用于更复杂的判断:

参数 说明 类型
fn() 按钮点击事的触发方法 Function=>void
show() 返回一个布尔值,当前按钮是否显示 Function=>boolean
size 尺寸 medium / small / mini
type 类型 primary / success / warning / danger / info
plain 是否朴素按钮 boolean
icon 图标类名 string

fn 和 show 方法都接收一个参数:{row, column, value, $index}(action 时)或已选行数组(header 并开启多选模式时)

各种按钮的生成
暂无数据
  • 1
前往
共 0 条
<template>
  <UniList title="各种按钮的生成" :schema="schema" :init="init" />
</template>
<script>
  export default {
    data() {
      return {
        schema: {
          $selection: "",
          title: "标题",
          name: "姓名",
        },
        init(page) {
          return {
            header: {
              此按钮选中可见: {
                show: (rows) => !!rows.length,
                fn: (rows) => page.view({ text: rows }),
              },
              //全局配置中也可以控制按钮样式
              //下面这个测试样式是全局配置中规定的
              测试按钮: () => page.view({ text: 123 }),
            },
            action: {
              //创建操作按钮
              "123AA123": ({ row }) => page.view({ text: row }),
              "123BB123": ({ row }) => page.view({ text: row }),
              AA123: ({ row }) => page.view({ text: row }),
              //也可以直接传配置对象
              测试按钮: {
                show: ({ $index }) => $index != 2, //下标为2则不显示
                fn: ({ row }) => page.view({ text: row }),
              },
            },
            actionWidth: 450, //设定操作条宽度
            actionStyle: {
              "123.*123": {
                //匹配前后有'123'的内容
                type: "danger",
              },
              AA: {
                //匹配存在'AA'的内容
                icon: "ri-cactus-fill",
              },
              测试: {
                //匹配存在'测试'的内容
                type: "warning",
                icon: "ri-flask-fill",
                style: "width:100px",
              },
            },
          };
        },
      };
    },
  };
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
Expand Copy

# 文本,表单,自定义组件注入能力

通俗的来讲,我们为每个 UniList 组件内置了弹窗和浮层的调用接口,也就是 UniList 实例中的 viewdialog 方法

  • 它们接收 同样 的 option 参数,用于向其中注入文本,表单和自定义组件
  • 你可以通过 refs 或者 init 函数的第一个参数取得 UniList 的实例
  • 它们均返回标准 Promise 对象,这意味着你可以使用.thenawait运算符取得文本,表单和自定义组件的返回值
参数 说明 类型
title 标题,留空默认为按钮的名字 string
text 三选一 注入文本 string
form 三选一 注入表单json,需要通过表单生成器 (opens new window)生成 jsonObject
component 三选一 注入组件,可以直接传全局组件的名字,或者直接传组件 string | VueComponent
data 表单 将数据传入表单中,一般用于编辑时。 Record<string,any>
use 表单 用 UniCell 替换表单中某些字段,详见 UniCell object
props 组件 组件的绑定属性 Record<string,any>
  • 如果你注入了组件,除了传进去的 props, 你还可以在组件 props 中接收到 close(关闭本 view 或 dialog) 和 resolve(关闭并回传数据)两个函数,resolve 方法中传入的第一个参数会在 view 或 dialog 方法的 then 中接收到,直接关闭则不执行 then
注入文本,表单,自定义组件
暂无数据
  • 1
前往
共 0 条
<template>
  <UniList title="注入文本,表单,自定义组件" :schema="schema" :init="init" />
</template>
<script>
  export default {
    data() {
      return {
        schema: {
          $index: "",
          title: "标题",
          name: "姓名",
        },
        init(page) {
          return {
            // actionWidth: 350, //设定操作条宽度
            header: {
              表单: () =>
                page
                  .view({ form: testForm })
                  .then((res) => page.dialog({ text: res })) //res回传数据,在这里请求接口
                  .then(() => this.$message.success("添加成功")),
            },
            action: {
              文本: () =>
                page
                  .dialog({ text: "此操作不可逆,确认要删除吗?" })
                  .then(() => console.log(123)) //在这里请求接口
                  .then(() => this.$message.success("删除成功"))
                  .catch(() => this.$message.error("删除失败")),
              有初始值的表单: ({ row }) =>
                page
                  .dialog({ form: testForm, data: row })
                  .then((res) => page.dialog({ text: res })) //res回传数据,在这里请求接口
                  .then(() => this.$message.success("编辑成功")),
              组件: () =>
                page.view({
                  component: "UniList", //UniList已注册为全局组件
                  props: {
                    use: {}, //抑制UniCell报错,并无意义
                    schema: {
                      $index: "",
                      title: "标题",
                      name: "姓名",
                    },
                  },
                }),
            },
          };
        },
      };
    },
  };

  //测试用json,实际应用时你应该单独创建一个json文件并引入
  const testForm = {
    fields: [
      {
        __config__: {
          label: "标题",
          labelWidth: null,
          showLabel: true,
          changeTag: true,
          tag: "el-input",
          tagIcon: "input",
          required: true,
          layout: "colFormItem",
          span: 24,
          document: "https://element.eleme.cn/#/zh-CN/component/input",
          regList: [],
          formId: 101,
          renderKey: 1635397742235,
        },
        __slot__: {
          prepend: "",
          append: "",
        },
        placeholder: "请输入标题",
        style: {
          width: "100%",
        },
        clearable: true,
        "prefix-icon": "",
        "suffix-icon": "",
        maxlength: null,
        "show-word-limit": false,
        readonly: false,
        disabled: false,
        __vModel__: "title",
      },
      {
        __config__: {
          label: "姓名",
          labelWidth: null,
          showLabel: true,
          changeTag: true,
          tag: "el-input",
          tagIcon: "input",
          required: true,
          layout: "colFormItem",
          span: 24,
          document: "https://element.eleme.cn/#/zh-CN/component/input",
          regList: [],
          formId: 102,
          renderKey: 1635397743179,
        },
        __slot__: {
          prepend: "",
          append: "",
        },
        placeholder: "请输入姓名",
        style: {
          width: "100%",
        },
        clearable: true,
        "prefix-icon": "",
        "suffix-icon": "",
        maxlength: null,
        "show-word-limit": false,
        readonly: false,
        disabled: false,
        __vModel__: "name",
      },
      {
        __config__: {
          label: "时间选择",
          tag: "el-time-picker",
          tagIcon: "time",
          defaultValue: null,
          span: 24,
          showLabel: true,
          layout: "colFormItem",
          labelWidth: null,
          required: true,
          regList: [],
          changeTag: true,
          document: "https://element.eleme.cn/#/zh-CN/component/time-picker",
          formId: 107,
          renderKey: 1635397815408,
        },
        placeholder: "请选择时间选择",
        style: {
          width: "100%",
        },
        disabled: false,
        clearable: true,
        "picker-options": {
          selectableRange: "00:00:00-23:59:59",
        },
        format: "HH:mm:ss",
        "value-format": "HH:mm:ss",
        __vModel__: "test",
      },
    ],
    formRef: "elForm",
    formModel: "formData",
    size: "medium",
    labelPosition: "right",
    labelWidth: 100,
    formRules: "rules",
    gutter: 15,
    disabled: false,
    span: 24,
    formBtns: true,
    unFocusedComponentBorder: false,
  };
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
Expand Copy

# 筛选功能和 UniCell 通用表单管理器

UniList 组件支持内建的筛选功能,使用了一种全新的模式。

你可能已经使用过我上面说的表单生成器 (opens new window)了,但他针对一种常见情况却无从下手

以角色管理列表举例,你需要在添加或编辑角色时提供可用的权限,那么你得先使用接口获取相应权限数据,再渲染到下拉选择框中。

但表单生成器提供的下拉选择框没有你需要的数据

那么有没有一种方法可以让你既享受到生成器的快感,又保留自己自由定制表单的能力?

请使用 UniCell™ 通用表单管理器

我敢打赌你会喜欢这种由策略模式驱动的表单的,它会让你的表单复用率达到最高,并且永远易于管理,易于移植

提示

在我们继续之前,请先阅读 UniCell™ 通用表单管理器的文档

UniList 组件中对 UniCell 和表单生成器进行了深层次的兼容,甚至会根据表单 label 自动绑定字段名

# 筛选

和 UniCell 一样,你需要在组件上写入要调用执行的策略,其中的值将会绑定到 UniList 组件实例的 params 变量中

这样在 custom.ts 的 fetch 方法中你可以使用this.params得到筛选表单的记录。

标题
地址
海星
暂无数据
  • 1
前往
共 0 条

UniList 的 attrs 会传入内部 UniCell, 在 schema 中未记录的 label 须提供字段,否则会报错。

<template>
  <UniList
    :schema="schema"
    text:标题
    text:地址="address"
    text:海星
    @fetch="
      (page) =>
        Object.keys(page.params).length && page.dialog({ text: page.params })
    "
  />
</template>
<script>
  export default {
    data() {
      return {
        schema: {
          title: "标题",
          name: "姓名",
          address: "地址",
          content: "内容",
        },
      };
    },
  };
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Expand Copy

# 替换表单

回到最初的问题,当我们使用表单生成器时该如何使用自定义的表单呢?

使用use参数替换表单生成器的某一元素
暂无数据
  • 1
前往
共 0 条
<template>
  <UniList
    title="使用use参数替换表单生成器的某一元素"
    :schema="schema"
    :init="init"
  />
</template>
<script>
  export default {
    data() {
      return {
        schema: {
          title: "标题",
          name: "姓名",
          address: "地址",
          content: "内容",
        },
        init(page) {
          return {
            header: {
              原测试表单: () =>
                page
                  .dialog({ form: testForm })
                  .then((res) => page.dialog({ text: res })),
              替换了元素的测试表单: () =>
                page
                  .dialog({
                    form: testForm,
                    use: {
                      title: "text:海星", // 将title字段对应的表单替换为text策略,并重命名为海星
                      role: "食物:角色", // 假设在这个食物组件中请求了角色下拉
                    },
                  })
                  .then((res) => page.dialog({ text: res })),
            },
          };
        },
      };
    },
  };

  //测试用json,实际应用时你应该单独创建一个json文件并引入
  const testForm = {
    fields: [
      {
        __config__: {
          label: "标题",
          labelWidth: null,
          showLabel: true,
          changeTag: true,
          tag: "el-input",
          tagIcon: "input",
          required: true,
          layout: "colFormItem",
          span: 24,
          document: "https://element.eleme.cn/#/zh-CN/component/input",
          regList: [],
          formId: 101,
          renderKey: 1635397742235,
        },
        __slot__: {
          prepend: "",
          append: "",
        },
        placeholder: "请输入标题",
        style: {
          width: "100%",
        },
        clearable: true,
        "prefix-icon": "",
        "suffix-icon": "",
        maxlength: null,
        "show-word-limit": false,
        readonly: false,
        disabled: false,
        __vModel__: "title",
      },
      {
        __config__: {
          label: "姓名",
          labelWidth: null,
          showLabel: true,
          changeTag: true,
          tag: "el-input",
          tagIcon: "input",
          required: true,
          layout: "colFormItem",
          span: 24,
          document: "https://element.eleme.cn/#/zh-CN/component/input",
          regList: [],
          formId: 102,
          renderKey: 1635397743179,
        },
        __slot__: {
          prepend: "",
          append: "",
        },
        placeholder: "请输入姓名",
        style: {
          width: "100%",
        },
        clearable: true,
        "prefix-icon": "",
        "suffix-icon": "",
        maxlength: null,
        "show-word-limit": false,
        readonly: false,
        disabled: false,
        __vModel__: "name",
      },
      {
        __config__: {
          label: "角色",
          showLabel: true,
          labelWidth: null,
          tag: "el-select",
          tagIcon: "select",
          layout: "colFormItem",
          span: 24,
          required: true,
          regList: [],
          changeTag: true,
          document: "https://element.eleme.cn/#/zh-CN/component/select",
          formId: 109,
          renderKey: 1635746801726,
        },
        __slot__: {
          options: [
            {
              label: "选项一",
              value: 1,
            },
            {
              label: "选项二",
              value: 2,
            },
          ],
        },
        placeholder: "请选择角色",
        style: {
          width: "100%",
        },
        clearable: true,
        disabled: false,
        filterable: false,
        multiple: false,
        __vModel__: "role",
      },
    ],
    formRef: "elForm",
    formModel: "formData",
    size: "medium",
    labelPosition: "right",
    labelWidth: 100,
    formRules: "rules",
    gutter: 15,
    disabled: false,
    span: 24,
    formBtns: true,
    unFocusedComponentBorder: false,
  };
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
Expand Copy