Commit bc4f9b65ceae6598167a6fa859f58e71cff973a9
1 parent
ef2583ca
Exists in
master
and in
2 other branches
feat: 修改SchemaFilter组件
Showing
9 changed files
with
290 additions
and
669 deletions
Show diff stats
examples/router/routes.js
examples/views/docs/component/schema-filter.md
| 1 | 1 | # Schema Filter 筛选 |
| 2 | 2 | |
| 3 | -根据JSON Schema配置自动生成一个筛选条件表单 | |
| 3 | +通过配置JSON Schema的方式快速生成一个筛选表单 | |
| 4 | 4 | |
| 5 | 5 | ## 基础用法 |
| 6 | 6 | |
| 7 | -配置`list`属性设置JSON Schema配置列表 | |
| 7 | +`schema`设置配置项,基本参数与`z-schema-form`相同;不同的是,由于本组件包含了展开状态,配置项的显示隐藏需要统一控制,因此本组件中不包含配置项的显隐逻辑。 | |
| 8 | 8 | |
| 9 | -::: snippet 通过`list`配置项目 | |
| 9 | +::: snippet `schema`设置配置项,`loading`设置加载状态 | |
| 10 | 10 | |
| 11 | 11 | ```html |
| 12 | 12 | <template> |
| 13 | - <div> | |
| 14 | - <pre class="demo-model">{{ model }}</pre> | |
| 15 | - <z-schema-filter v-model="model" :list="list" @search="onSearch" @reset="onReset"></z-schema-filter> | |
| 16 | - </div> | |
| 13 | + <z-schema-filter v-model="form" :schema="schema" :loading="loading" @search="onSearch" @reset="onReset"></z-schema-filter> | |
| 17 | 14 | </template> |
| 18 | 15 | |
| 19 | 16 | <script> |
| 20 | 17 | export default { |
| 21 | 18 | data() { |
| 22 | 19 | return { |
| 23 | - model: {}, | |
| 24 | - list: [ | |
| 25 | - { type: 'el-input', label: '姓名', key: 'name' }, | |
| 26 | - { type: 'el-input', label: '年龄', key: 'age' }, | |
| 27 | - { type: 'el-input', label: '省', key: 'province' }, | |
| 28 | - { type: 'el-input', label: '市', key: 'city' }, | |
| 29 | - { type: 'el-input', label: '区', key: 'area' }, | |
| 30 | - { type: 'el-input', label: '地址', key: 'address' }, | |
| 31 | - ] | |
| 32 | - } | |
| 20 | + form: { | |
| 21 | + name: '', | |
| 22 | + age: '', | |
| 23 | + gender: '', | |
| 24 | + }, | |
| 25 | + schema: { | |
| 26 | + items: [ | |
| 27 | + { is: 'el-input', prop: 'name', label: '姓名' }, | |
| 28 | + { is: 'el-input', prop: 'age', label: '年龄' }, | |
| 29 | + { is: 'el-input', prop: 'gender', label: '性别' }, | |
| 30 | + ] | |
| 31 | + }, | |
| 32 | + loading: false | |
| 33 | + }; | |
| 33 | 34 | }, |
| 34 | 35 | methods: { |
| 35 | - onSearch(params) { | |
| 36 | - console.log(JSON.parse(JSON.stringify(params))); | |
| 36 | + onSearch(model) { | |
| 37 | + this.loading = true; | |
| 38 | + console.log(model); | |
| 39 | + setTimeout(() => { | |
| 40 | + this.loading = false; | |
| 41 | + }, 1500); | |
| 37 | 42 | }, |
| 38 | 43 | onReset() { |
| 39 | 44 | console.log('reset'); |
| 40 | 45 | } |
| 41 | 46 | } |
| 42 | -} | |
| 47 | +}; | |
| 43 | 48 | </script> |
| 44 | 49 | ``` |
| 45 | 50 | |
| 46 | 51 | ::: |
| 47 | 52 | |
| 48 | -## 自定义按钮 | |
| 49 | - | |
| 50 | -支持自定义按钮占位及按钮组件 | |
| 51 | - | |
| 52 | -::: snippet 配置`uncollapsedSpan`改变展开时操作区占位,默认值`24`;插槽`operation`自定义按钮内容; | |
| 53 | +::: snippet 默认显示数量为`3`,超过则会显示展开按钮 | |
| 53 | 54 | |
| 54 | 55 | ```html |
| 55 | 56 | <template> |
| 56 | - <z-schema-filter v-model="model" :list="list" :uncollapsedSpan="12"> | |
| 57 | - <template #operation="{ size, handleSearch, handleReset, handleCollapse, showCollapsed, collapsed, loading }"> | |
| 58 | - <div style="text-align: right;"> | |
| 59 | - <el-button-group :size="size"> | |
| 60 | - <el-button type="primary" round @click="handleSearch" :loading="loading" icon="el-icon-search"><span>查询</span></el-button> | |
| 61 | - <el-button @click="handleReset"><span>重置</span></el-button> | |
| 62 | - <el-button round v-if="showCollapsed" @click="handleCollapse"> | |
| 63 | - <span>{{ collapsed ? '展开' : '收起' }}</span> | |
| 64 | - </el-button> | |
| 65 | - </el-button-group> | |
| 66 | - </div> | |
| 67 | - </template> | |
| 68 | - </z-schema-filter> | |
| 57 | + <z-schema-filter v-model="form" :schema="schema"></z-schema-filter> | |
| 69 | 58 | </template> |
| 70 | 59 | |
| 71 | 60 | <script> |
| 72 | 61 | export default { |
| 73 | 62 | data() { |
| 74 | 63 | return { |
| 75 | - model: {}, | |
| 76 | - list: [ | |
| 77 | - { type: 'el-input', label: '姓名', key: 'name' }, | |
| 78 | - { type: 'el-input', label: '年龄', key: 'age' }, | |
| 79 | - { type: 'el-input', label: '省', key: 'province' }, | |
| 80 | - { type: 'el-input', label: '市', key: 'city' }, | |
| 81 | - { type: 'el-input', label: '区', key: 'area' }, | |
| 82 | - { type: 'el-input', label: '地址', key: 'address' }, | |
| 83 | - ] | |
| 84 | - } | |
| 64 | + form: { | |
| 65 | + name: '', | |
| 66 | + age: '', | |
| 67 | + gender: '', | |
| 68 | + }, | |
| 69 | + schema: { | |
| 70 | + items: [ | |
| 71 | + { is: 'el-input', prop: 'name', label: '姓名' }, | |
| 72 | + { is: 'el-input', prop: 'age', label: '年龄' }, | |
| 73 | + { is: 'el-input', prop: 'gender', label: '性别' }, | |
| 74 | + { is: 'el-input', prop: 'address', label: '地址' }, | |
| 75 | + { is: 'el-input', prop: 'package', label: '包裹' }, | |
| 76 | + ] | |
| 77 | + }, | |
| 78 | + }; | |
| 85 | 79 | }, |
| 86 | -} | |
| 80 | +}; | |
| 87 | 81 | </script> |
| 88 | 82 | ``` |
| 89 | 83 | |
| 90 | 84 | ::: |
| 91 | 85 | |
| 92 | -## 自定义数据项 | |
| 86 | +## 默认展示数量 | |
| 93 | 87 | |
| 94 | -支持自定义数据项,一般用于通过JSON Schema较难配置出的,较复杂的局部组件 | |
| 88 | +常见的业务场景下,经常会出现多个筛选条件的情况,可以默认展示多行的搜索项。 | |
| 95 | 89 | |
| 96 | -::: snippet 插槽名与数据项`key`相同 | |
| 90 | +::: snippet `display`设置默认展示的搜索项数量,控制按钮栏占位会根据每行剩余搜索项数量自动计算。 | |
| 97 | 91 | |
| 98 | 92 | ```html |
| 99 | 93 | <template> |
| 100 | - <z-schema-filter v-model="model" :list="list"> | |
| 101 | - <template #name> | |
| 102 | - <el-input placeholder="请输入内容" v-model="model.name"> | |
| 103 | - <el-button slot="append" icon="el-icon-search"></el-button> | |
| 104 | - </el-input> | |
| 105 | - </template> | |
| 106 | - </z-schema-filter> | |
| 94 | + <z-schema-filter v-model="form" :schema="schema" :display="7"></z-schema-filter> | |
| 107 | 95 | </template> |
| 108 | 96 | |
| 109 | 97 | <script> |
| 110 | 98 | export default { |
| 111 | 99 | data() { |
| 112 | 100 | return { |
| 113 | - model: {}, | |
| 114 | - list: [ | |
| 115 | - { type: 'el-input', label: '姓名', key: 'name' }, | |
| 116 | - { type: 'el-input', label: '年龄', key: 'age' }, | |
| 117 | - { type: 'el-input', label: '省', key: 'province' }, | |
| 118 | - { type: 'el-input', label: '市', key: 'city' }, | |
| 119 | - { type: 'el-input', label: '区', key: 'area' }, | |
| 120 | - { type: 'el-input', label: '地址', key: 'address' }, | |
| 121 | - ] | |
| 122 | - } | |
| 101 | + form: { | |
| 102 | + name: '', | |
| 103 | + age: '', | |
| 104 | + gender: '', | |
| 105 | + }, | |
| 106 | + schema: { | |
| 107 | + items: [ | |
| 108 | + { is: 'el-input', prop: 'name', label: '姓名' }, | |
| 109 | + { is: 'el-input', prop: 'age', label: '年龄' }, | |
| 110 | + { is: 'el-input', prop: 'gender', label: '性别' }, | |
| 111 | + { is: 'el-input', prop: 'item1', label: '搜索项1' }, | |
| 112 | + { is: 'el-input', prop: 'item2', label: '搜索项2' }, | |
| 113 | + { is: 'el-input', prop: 'item3', label: '搜索项3' }, | |
| 114 | + { is: 'el-input', prop: 'item4', label: '搜索项4' }, | |
| 115 | + { is: 'el-input', prop: 'item5', label: '搜索项5' }, | |
| 116 | + { is: 'el-input', prop: 'item6', label: '搜索项6' }, | |
| 117 | + ] | |
| 118 | + }, | |
| 119 | + loading: false | |
| 120 | + }; | |
| 123 | 121 | }, |
| 124 | -} | |
| 122 | + methods: { | |
| 123 | + onSearch(model) { | |
| 124 | + this.loading = true; | |
| 125 | + console.log(model); | |
| 126 | + setTimeout(() => { | |
| 127 | + this.loading = false; | |
| 128 | + }, 1500); | |
| 129 | + }, | |
| 130 | + onReset() { | |
| 131 | + console.log('reset'); | |
| 132 | + } | |
| 133 | + } | |
| 134 | +}; | |
| 125 | 135 | </script> |
| 126 | 136 | ``` |
| 127 | 137 | |
| 128 | 138 | ::: |
| 129 | 139 | |
| 130 | -## 展示数量 | |
| 140 | +## 自定义操作栏 | |
| 131 | 141 | |
| 132 | -默认展示数量为`3`个,可以通过配置而改变 | |
| 142 | +特殊业务场景下,可以自定义操作栏 | |
| 133 | 143 | |
| 134 | -::: snippet 设置`visibleNum`改变默认展示数量的大小,`span`改变每一项的占位数量 | |
| 144 | +::: snippet `operation`插槽替换默认操作栏 | |
| 135 | 145 | |
| 136 | 146 | ```html |
| 137 | 147 | <template> |
| 138 | - <z-schema-filter :list="list" :visibleNum="2" :span="8" size="large"></z-schema-filter> | |
| 148 | + <z-schema-filter v-model="form" :schema="schema" :display="2" :loading="loading" @search="onSearch" @reset="onReset"> | |
| 149 | + <template #operation="{ search, reset, collapse, collapsed, loading }"> | |
| 150 | + <el-button-group round style="display: flex; justify-content: flex-end"> | |
| 151 | + <el-button round type="primary" @click="search" :loading="loading" icon="el-icon-search">查询</el-button> | |
| 152 | + <el-button round @click="reset">重置</el-button> | |
| 153 | + <el-button round @click="onClick">自定义按钮</el-button> | |
| 154 | + <el-button round @click="collapse">{{ collapsed ? '收起' : '展开' }}</el-button> | |
| 155 | + </el-button-group> | |
| 156 | + </template> | |
| 157 | + </z-schema-filter> | |
| 139 | 158 | </template> |
| 140 | 159 | |
| 141 | 160 | <script> |
| 142 | 161 | export default { |
| 143 | 162 | data() { |
| 144 | 163 | return { |
| 145 | - list: [ | |
| 146 | - { type: 'el-input', label: '姓名', key: 'name' }, | |
| 147 | - { type: 'el-input-number', label: '年龄', key: 'age', style: { width: '100%' }, props: { min: 0 } }, | |
| 148 | - { type: 'el-input', label: '省', key: 'province' }, | |
| 149 | - { type: 'el-input', label: '市', key: 'city' }, | |
| 150 | - { type: 'el-input', label: '区', key: 'area' }, | |
| 151 | - { type: 'el-input', label: '地址', key: 'address' }, | |
| 152 | - ] | |
| 153 | - } | |
| 164 | + form: { | |
| 165 | + name: '', | |
| 166 | + age: '', | |
| 167 | + gender: '', | |
| 168 | + }, | |
| 169 | + schema: { | |
| 170 | + items: [ | |
| 171 | + { is: 'el-input', prop: 'name', label: '姓名' }, | |
| 172 | + { is: 'el-input', prop: 'age', label: '年龄' }, | |
| 173 | + { is: 'el-input', prop: 'gender', label: '性别' }, | |
| 174 | + { is: 'el-input', prop: 'address', label: '地址' }, | |
| 175 | + { is: 'el-input', prop: 'address', label: '地址' }, | |
| 176 | + ] | |
| 177 | + }, | |
| 178 | + loading: false, | |
| 179 | + }; | |
| 154 | 180 | }, |
| 155 | -} | |
| 181 | + methods: { | |
| 182 | + onSearch(model) { | |
| 183 | + this.loading = true; | |
| 184 | + console.log(model); | |
| 185 | + setTimeout(() => { | |
| 186 | + this.loading = false; | |
| 187 | + }, 1500); | |
| 188 | + }, | |
| 189 | + onReset() { | |
| 190 | + console.log('reset'); | |
| 191 | + }, | |
| 192 | + onClick() { | |
| 193 | + console.log('click'); | |
| 194 | + } | |
| 195 | + } | |
| 196 | +}; | |
| 156 | 197 | </script> |
| 157 | 198 | ``` |
| 158 | 199 | |
| ... | ... | @@ -165,20 +206,18 @@ export default { |
| 165 | 206 | 参数|说明|类型|可选值|默认值 |
| 166 | 207 | -|-|-|-|- |
| 167 | 208 | value | 值 | Object | - | {} |
| 168 | -list | JSON Schema配置项列表 | Array | - | [] | |
| 169 | -labelWidth | 默认Label宽度 | String | 110px | |
| 170 | -size | 大小 | String | - | small | |
| 171 | -span | 占位 | Number | - | 24 | |
| 172 | -uncollapsedSpan | 展开时操作区占位 | Number | - | 24 | |
| 173 | -visibleNum | 折叠时可视项数量 | Number | - | 3 | |
| 174 | -loading | 加载状态 | Boolean | - | - | |
| 175 | -formProps | 默认el-form配置参数 | Object | - | {} | |
| 176 | -params | 自定义附加参数 | Object | - | - | |
| 209 | +schema | JSON Schema配置项列表 | Object | - | {} | |
| 210 | +size | 大小 | String | - | - | |
| 211 | +loading | 加载状态 | Boolean | - | false | |
| 212 | +display | 默认收起时显示数量 | Number | - | 3 | |
| 213 | +span | 子项占位 | Number | - | 6 | |
| 214 | +collapsedSpan | 展开时操作栏占位,默认自动计算,特殊情况下可手动设置 | Boolean | - | - | |
| 215 | +uncollapsedSpan | 收起时操作栏占位,默认自动计算,特殊情况下可手动设置 | Boolean | - | - | |
| 177 | 216 | |
| 178 | 217 | ## Events 事件 |
| 179 | 218 | |
| 180 | 219 | 事件名称|说明|回调参数 |
| 181 | 220 | -|-|- |
| 182 | 221 | input | 表单值变化 | model |
| 183 | -search | 查询 | model | |
| 184 | -reset | 重置表单 | - | |
| 185 | 222 | \ No newline at end of file |
| 223 | +search | 搜索 | model | |
| 224 | +reset | 重置 | - | |
| 186 | 225 | \ No newline at end of file | ... | ... |
examples/views/docs/component/schema-form.md
| ... | ... | @@ -590,4 +590,19 @@ export default { |
| 590 | 590 | </script> |
| 591 | 591 | ``` |
| 592 | 592 | |
| 593 | -::: | |
| 594 | 593 | \ No newline at end of file |
| 594 | +::: | |
| 595 | + | |
| 596 | +## API | |
| 597 | + | |
| 598 | +## Attribute 属性 | |
| 599 | + | |
| 600 | +参数|说明|类型|可选值|默认值 | |
| 601 | +-|-|-|-|- | |
| 602 | +value | 值 | Object | - | {} | |
| 603 | +schema | JSON Schema配置项列表 | Object | - | {} | |
| 604 | + | |
| 605 | +## Events 事件 | |
| 606 | + | |
| 607 | +事件名称|说明|回调参数 | |
| 608 | +-|-|- | |
| 609 | +input | 表单值变化 | model | |
| 595 | 610 | \ No newline at end of file | ... | ... |
packages/form/index.vue
| ... | ... | @@ -8,8 +8,11 @@ |
| 8 | 8 | </template> |
| 9 | 9 | |
| 10 | 10 | <script> |
| 11 | +import MIX_FORM from '../mixins/form'; | |
| 12 | + | |
| 11 | 13 | export default { |
| 12 | 14 | name: 'Form', |
| 15 | + mixins: [MIX_FORM], | |
| 13 | 16 | props: { |
| 14 | 17 | value: Object, |
| 15 | 18 | model: Object, |
| ... | ... | @@ -27,19 +30,5 @@ export default { |
| 27 | 30 | zForm: this, |
| 28 | 31 | }; |
| 29 | 32 | }, |
| 30 | - methods: { | |
| 31 | - validate(callback) { | |
| 32 | - return this.$refs.form.validate(callback); | |
| 33 | - }, | |
| 34 | - validateField(props, callback) { | |
| 35 | - return this.$refs.form.validateField(props, callback); | |
| 36 | - }, | |
| 37 | - resetFields() { | |
| 38 | - this.$refs.form.resetFields(); | |
| 39 | - }, | |
| 40 | - clearValidate(props) { | |
| 41 | - return this.$refs.form.clearValidate(props); | |
| 42 | - }, | |
| 43 | - }, | |
| 44 | 33 | }; |
| 45 | 34 | </script> | ... | ... |
| ... | ... | @@ -0,0 +1,27 @@ |
| 1 | +export default { | |
| 2 | + methods: { | |
| 3 | + validate(callback) { | |
| 4 | + if (this.$refs.form) { | |
| 5 | + return this.$refs.form.validate(callback); | |
| 6 | + } | |
| 7 | + return false; | |
| 8 | + }, | |
| 9 | + validateField(props, callback) { | |
| 10 | + if (this.$refs.form) { | |
| 11 | + return this.$refs.form.validateField(props, callback); | |
| 12 | + } | |
| 13 | + return false; | |
| 14 | + }, | |
| 15 | + resetFields() { | |
| 16 | + if (this.$refs.form) { | |
| 17 | + this.$refs.form.resetFields(); | |
| 18 | + } | |
| 19 | + }, | |
| 20 | + clearValidate(props) { | |
| 21 | + if (this.$refs.form) { | |
| 22 | + return this.$refs.form.clearValidate(props); | |
| 23 | + } | |
| 24 | + return false; | |
| 25 | + }, | |
| 26 | + }, | |
| 27 | +}; | ... | ... |
packages/schema-filter/index.vue
| 1 | 1 | <template> |
| 2 | - <z-schema-form | |
| 3 | - v-model="model" | |
| 4 | - class="z-schema-filter" | |
| 5 | - :list="formattedList" | |
| 6 | - :span="span" | |
| 7 | - :labelWidth="labelWidth" | |
| 8 | - :colClass="colVisibleRender" | |
| 9 | - :size="size" | |
| 10 | - :formProps="formProps" | |
| 11 | - :params="params" | |
| 12 | - > | |
| 2 | + <z-schema-form ref="form" class="z-schema-filter" v-model="model" :schema="formattedSchema"> | |
| 13 | 3 | <template v-for="key in slotKeys"> |
| 14 | - <template v-if="key === 'operation'"> | |
| 15 | - <slot :name="key" :slot="key" v-bind="{ size, handleSearch, handleReset, handleCollapse, showCollapsed, collapsed, loading }"></slot> | |
| 16 | - </template> | |
| 17 | - <slot v-else :name="key" :slot="key"></slot> | |
| 4 | + <slot :name="key" :slot="key" v-bind="slotProps"></slot> | |
| 18 | 5 | </template> |
| 19 | - <div v-if="!slotKeys.includes('operation')" slot="operation" class="z-schema-filter__button-group"> | |
| 20 | - <el-button-group :size="size"> | |
| 21 | - <el-button type="primary" @click="handleSearch" :loading="loading" icon="el-icon-search"><span>查询</span></el-button> | |
| 22 | - <el-button @click="handleReset"><span>重置</span></el-button> | |
| 23 | - <el-button v-if="showCollapsed" @click="handleCollapse"> | |
| 24 | - <span>{{ collapsed ? '展开' : '收起' }}</span> | |
| 25 | - </el-button> | |
| 26 | - </el-button-group> | |
| 27 | - </div> | |
| 6 | + <el-button-group v-if="!slotKeys.includes('operation')" slot="operation" style="display: flex; justify-content: flex-end"> | |
| 7 | + <el-button type="primary" @click="onSearch" :loading="loading" icon="el-icon-search">查询</el-button> | |
| 8 | + <el-button @click="onReset">重置</el-button> | |
| 9 | + <el-button v-if="showCollapsed" @click="onCollapse">{{ collapsed ? '收起' : '展开' }}</el-button> | |
| 10 | + </el-button-group> | |
| 28 | 11 | </z-schema-form> |
| 29 | 12 | </template> |
| 30 | 13 | |
| 31 | 14 | <script> |
| 15 | +import MIX_FORM from '../mixins/form'; | |
| 16 | +import { cloneDeep } from '../utils'; | |
| 17 | + | |
| 32 | 18 | export default { |
| 33 | 19 | name: 'SchemaFilter', |
| 20 | + mixins: [MIX_FORM], | |
| 34 | 21 | props: { |
| 35 | 22 | value: Object, |
| 36 | - list: Array, | |
| 37 | - labelWidth: { | |
| 38 | - type: String, | |
| 39 | - default: '110px', | |
| 40 | - }, | |
| 41 | - size: { | |
| 42 | - type: String, | |
| 43 | - default: 'small', | |
| 23 | + schema: { | |
| 24 | + type: Object, | |
| 25 | + default() { | |
| 26 | + return {}; | |
| 27 | + }, | |
| 44 | 28 | }, |
| 45 | - span: { | |
| 29 | + size: String, | |
| 30 | + loading: Boolean, | |
| 31 | + display: { | |
| 46 | 32 | type: Number, |
| 47 | - default: 6, | |
| 33 | + default: 3, | |
| 48 | 34 | }, |
| 49 | - collapsedSpan: { | |
| 35 | + span: { | |
| 50 | 36 | type: Number, |
| 51 | 37 | default: 6, |
| 52 | 38 | }, |
| 53 | - uncollapsedSpan: { | |
| 54 | - type: Number, | |
| 55 | - default: 24, | |
| 56 | - }, | |
| 57 | - visibleNum: { | |
| 58 | - type: Number, | |
| 59 | - default: 3, | |
| 60 | - }, | |
| 61 | - loading: Boolean, | |
| 62 | - formProps: { | |
| 63 | - type: Object, | |
| 64 | - default: () => ({}), | |
| 65 | - }, | |
| 66 | - params: Object, | |
| 39 | + collapsedSpan: Number, | |
| 40 | + uncollapsedSpan: Number, | |
| 67 | 41 | }, |
| 68 | 42 | data() { |
| 69 | 43 | return { |
| 70 | - collapsed: true, | |
| 71 | - model: this.value || {}, | |
| 44 | + collapsed: false, | |
| 45 | + model: this.value, | |
| 46 | + originData: {}, | |
| 72 | 47 | }; |
| 73 | 48 | }, |
| 74 | 49 | watch: { |
| ... | ... | @@ -80,50 +55,93 @@ export default { |
| 80 | 55 | }, |
| 81 | 56 | }, |
| 82 | 57 | computed: { |
| 83 | - formattedList() { | |
| 84 | - return [...this.list, { key: 'operation', label: '', labelWidth: '0px', span: this.collapsed ? this.collapsedSpan : this.uncollapsedSpan }]; | |
| 58 | + filterSize() { | |
| 59 | + return this.size || (this.$ELEMENT || {}).size; | |
| 60 | + }, | |
| 61 | + formattedItems() { | |
| 62 | + const items = this.schema.items || []; | |
| 63 | + const result = []; | |
| 64 | + const visibleNumber = this.display - 1; | |
| 65 | + items.forEach((item, index) => { | |
| 66 | + if (!this.collapsed && index > visibleNumber && index < items.length) { | |
| 67 | + result.push({ ...item, if: true, show: false }); | |
| 68 | + } else { | |
| 69 | + result.push({ ...item, if: true, show: true }); | |
| 70 | + } | |
| 71 | + }); | |
| 72 | + return result; | |
| 73 | + }, | |
| 74 | + formattedSchema() { | |
| 75 | + return { | |
| 76 | + props: { span: this.span, 'label-width': '75px', size: this.filterSize || 'small', ...(this.schema.props || {}) }, | |
| 77 | + items: [...this.formattedItems, { prop: 'operation', label: '', labelWidth: '0px', span: this.operationSpan }], | |
| 78 | + }; | |
| 79 | + }, | |
| 80 | + rowItemCount() { | |
| 81 | + return parseInt(24 / this.span); | |
| 82 | + }, | |
| 83 | + rowItemRemain() { | |
| 84 | + return this.formattedItems.length % this.rowItemCount; | |
| 85 | + }, | |
| 86 | + operationSpan() { | |
| 87 | + if (this.collapsed) { | |
| 88 | + if (this.collapsedSpan) { | |
| 89 | + return this.collapsedSpan; | |
| 90 | + } | |
| 91 | + return (this.rowItemCount - this.rowItemRemain) * this.span; | |
| 92 | + } else { | |
| 93 | + if (this.uncollapsedSpan) { | |
| 94 | + return this.uncollapsedSpan; | |
| 95 | + } | |
| 96 | + if (this.formattedItems.length < this.display) { | |
| 97 | + return this.span * (this.rowItemCount - this.rowItemRemain); | |
| 98 | + } | |
| 99 | + if (this.display < this.rowItemCount - 1) { | |
| 100 | + return this.span * this.display; | |
| 101 | + } | |
| 102 | + return this.span; | |
| 103 | + } | |
| 85 | 104 | }, |
| 86 | 105 | showCollapsed() { |
| 87 | - const { list, visibleNum } = this; | |
| 88 | - return list.length > visibleNum; | |
| 106 | + return this.formattedItems.length > this.display; | |
| 89 | 107 | }, |
| 90 | 108 | slotKeys() { |
| 91 | 109 | return Object.keys(this.$scopedSlots); |
| 92 | 110 | }, |
| 111 | + slotProps() { | |
| 112 | + return { | |
| 113 | + size: this.size, | |
| 114 | + search: this.onSearch, | |
| 115 | + reset: this.onReset, | |
| 116 | + collapse: this.onCollapse, | |
| 117 | + collapsed: this.collapsed, | |
| 118 | + loading: this.loading, | |
| 119 | + }; | |
| 120 | + }, | |
| 121 | + }, | |
| 122 | + created() { | |
| 123 | + const { originData, ...other } = this._data; | |
| 124 | + this.originData = cloneDeep(other); | |
| 93 | 125 | }, |
| 94 | 126 | methods: { |
| 95 | - // 渲染列表项class | |
| 96 | - colVisibleRender(item, index) { | |
| 97 | - if (this.collapsed) { | |
| 98 | - const visibleNumber = this.visibleNum ? this.visibleNum - 1 : 2; | |
| 99 | - return index > visibleNumber && index < this.list.length ? 'z-schema-filter__item hidden' : 'z-schema-filter__item'; | |
| 100 | - } | |
| 101 | - return 'z-schema-filter__item'; | |
| 102 | - }, | |
| 103 | 127 | // 搜索 |
| 104 | - handleSearch() { | |
| 105 | - this.$emit('search', this.model); | |
| 128 | + onSearch() { | |
| 129 | + this.$refs.form.validate(valid => { | |
| 130 | + if (valid) { | |
| 131 | + this.$emit('search', this.model); | |
| 132 | + } | |
| 133 | + }); | |
| 106 | 134 | }, |
| 107 | 135 | // 重置 |
| 108 | - handleReset() { | |
| 109 | - this.model = {}; | |
| 136 | + onReset() { | |
| 137 | + this.model = cloneDeep(this.originData).model; | |
| 138 | + this.$refs.form.resetFields(); | |
| 110 | 139 | this.$emit('reset'); |
| 111 | 140 | }, |
| 112 | 141 | // 折叠 |
| 113 | - handleCollapse() { | |
| 142 | + onCollapse() { | |
| 114 | 143 | this.collapsed = !this.collapsed; |
| 115 | 144 | }, |
| 116 | 145 | }, |
| 117 | 146 | }; |
| 118 | 147 | </script> |
| 119 | - | |
| 120 | -<style> | |
| 121 | -.z-schema-filter__item.hidden { | |
| 122 | - display: none; | |
| 123 | -} | |
| 124 | -.z-schema-filter__button-group { | |
| 125 | - width: 100%; | |
| 126 | - box-sizing: border-box; | |
| 127 | - text-align: right; | |
| 128 | -} | |
| 129 | -</style> | ... | ... |
packages/schema-form/index copy.vue
| ... | ... | @@ -1,216 +0,0 @@ |
| 1 | -<style lang="scss"> | |
| 2 | -.z-schema-form { | |
| 3 | - &__flex-wrap { | |
| 4 | - display: flex; | |
| 5 | - flex-wrap: wrap; | |
| 6 | - width: 100%; | |
| 7 | - } | |
| 8 | - &__group-title { | |
| 9 | - font-weight: bold; | |
| 10 | - padding: 15px 5px; | |
| 11 | - border-bottom: 1px solid #d9d9d9; | |
| 12 | - margin-bottom: 15px; | |
| 13 | - } | |
| 14 | - &__group-content { | |
| 15 | - margin: 15px 0px; | |
| 16 | - } | |
| 17 | - &__footer { | |
| 18 | - padding-top: 10px; | |
| 19 | - display: flex; | |
| 20 | - align-items: center; | |
| 21 | - justify-content: center; | |
| 22 | - } | |
| 23 | -} | |
| 24 | -</style> | |
| 25 | - | |
| 26 | -<template> | |
| 27 | - <el-form | |
| 28 | - ref="form" | |
| 29 | - class="z-schema-form" | |
| 30 | - :size="size" | |
| 31 | - :class="formClass" | |
| 32 | - :model="formModel" | |
| 33 | - :label-width="labelWidth" | |
| 34 | - :label-position="labelPosition || labelWidth ? 'right' : 'top'" | |
| 35 | - v-bind="formProps" | |
| 36 | - > | |
| 37 | - <schema-form-render | |
| 38 | - :title-class="titleClass" | |
| 39 | - :content-class="contentClass" | |
| 40 | - :item-class="itemClass" | |
| 41 | - :col-class="colClass" | |
| 42 | - :group-class="groupClass" | |
| 43 | - :list="formList" | |
| 44 | - :value="model" | |
| 45 | - :model="model" | |
| 46 | - :span="span" | |
| 47 | - :type="type" | |
| 48 | - :params="params" | |
| 49 | - @item-change="onItemChange" | |
| 50 | - @form-item-change="onFormItemChange" | |
| 51 | - @item-update="onItemUpdate" | |
| 52 | - > | |
| 53 | - <slot v-for="key in slotKeys" :name="key" :slot="key"></slot> | |
| 54 | - </schema-form-render> | |
| 55 | - <div v-if="$scopedSlots.footer" class="z-schema-form__footer"> | |
| 56 | - <slot name="footer" :size="size" :validate="validate" :reset="reset" :model="model"></slot> | |
| 57 | - </div> | |
| 58 | - </el-form> | |
| 59 | -</template> | |
| 60 | - | |
| 61 | -<script> | |
| 62 | -import SchemaFormRender from './schema-form-render'; | |
| 63 | -import { cloneDeep, set } from '../utils'; | |
| 64 | - | |
| 65 | -export default { | |
| 66 | - name: 'SchemaForm', | |
| 67 | - components: { SchemaFormRender }, | |
| 68 | - props: { | |
| 69 | - value: Object, | |
| 70 | - list: Array, | |
| 71 | - formClass: String, | |
| 72 | - titleClass: String, | |
| 73 | - contentClass: String, | |
| 74 | - itemClass: String, | |
| 75 | - colClass: [String, Function], | |
| 76 | - groupClass: String, | |
| 77 | - labelWidth: String, | |
| 78 | - labelPosition: String, | |
| 79 | - type: String, | |
| 80 | - size: { | |
| 81 | - type: String, | |
| 82 | - default: 'small', | |
| 83 | - }, | |
| 84 | - span: { | |
| 85 | - type: Number, | |
| 86 | - default: 24, | |
| 87 | - }, | |
| 88 | - formProps: { | |
| 89 | - type: Object, | |
| 90 | - default: () => ({}), | |
| 91 | - }, | |
| 92 | - params: Object, | |
| 93 | - }, | |
| 94 | - data() { | |
| 95 | - return { | |
| 96 | - model: {}, | |
| 97 | - formModel: {}, | |
| 98 | - formList: [], | |
| 99 | - }; | |
| 100 | - }, | |
| 101 | - computed: { | |
| 102 | - slotKeys() { | |
| 103 | - return Object.keys(this.$scopedSlots); | |
| 104 | - }, | |
| 105 | - }, | |
| 106 | - watch: { | |
| 107 | - value: { | |
| 108 | - handler(val = {}) { | |
| 109 | - this.model = val; | |
| 110 | - this.setFormModel(val); | |
| 111 | - }, | |
| 112 | - immediate: true, | |
| 113 | - }, | |
| 114 | - list: { | |
| 115 | - handler(val) { | |
| 116 | - // 深度克隆传入的列表,避免原始值被修改 | |
| 117 | - const newList = cloneDeep(this.list); | |
| 118 | - // 生成列表值的全路径key,即列表项为对象时,对象内的key与上一级的key合并作为全路径key | |
| 119 | - const generateFullKey = (list, parentKey) => { | |
| 120 | - list.forEach(item => { | |
| 121 | - if (item.group && item.list) { | |
| 122 | - if (item.group.key) { | |
| 123 | - item.fullKey = `${parentKey ? `${parentKey}-${item.group.key}` : item.group.key}`; | |
| 124 | - } else { | |
| 125 | - item.fullKey = parentKey || item.key; | |
| 126 | - } | |
| 127 | - generateFullKey(item.list, item.fullKey); | |
| 128 | - } else { | |
| 129 | - item.fullKey = `${parentKey ? `${parentKey}-${item.key}` : item.key}`; | |
| 130 | - } | |
| 131 | - }); | |
| 132 | - }; | |
| 133 | - generateFullKey(newList); | |
| 134 | - this.formList = newList; | |
| 135 | - }, | |
| 136 | - immediate: true, | |
| 137 | - }, | |
| 138 | - }, | |
| 139 | - methods: { | |
| 140 | - handleInput(value) { | |
| 141 | - console.log(value); | |
| 142 | - }, | |
| 143 | - /** | |
| 144 | - * @description 表单项值变化 | |
| 145 | - * @param {Object} item 表单项值对象 | |
| 146 | - */ | |
| 147 | - onItemChange(item) { | |
| 148 | - this.$emit('input', { ...this.model, ...item }); | |
| 149 | - }, | |
| 150 | - /** | |
| 151 | - * @description 表单相校验值变化 | |
| 152 | - * @param {Object} item 表单项校验值对象 | |
| 153 | - */ | |
| 154 | - onFormItemChange(item) { | |
| 155 | - this.formModel = { ...this.formModel, ...item }; | |
| 156 | - }, | |
| 157 | - /** | |
| 158 | - * @description 校验表单 | |
| 159 | - */ | |
| 160 | - validate(cb) { | |
| 161 | - return new Promise(resolve => { | |
| 162 | - this.$refs.form.validate(valid => { | |
| 163 | - cb && cb(valid); | |
| 164 | - this.$emit('validate', valid, this.model); | |
| 165 | - return resolve(valid); | |
| 166 | - }); | |
| 167 | - }); | |
| 168 | - }, | |
| 169 | - /** | |
| 170 | - * @description 重置表单 | |
| 171 | - */ | |
| 172 | - reset() { | |
| 173 | - this.$refs.form.clearValidate(); | |
| 174 | - this.$emit('reset'); | |
| 175 | - }, | |
| 176 | - /** | |
| 177 | - * @description 根据表单值设置表单校验值 | |
| 178 | - * @param {Object} value 表单值 | |
| 179 | - */ | |
| 180 | - setFormModel(value) { | |
| 181 | - let formModel = {}; | |
| 182 | - // 递归深度解析表单值,将表单值扁平化为一层的对象并设置为表单校验值对象 | |
| 183 | - const setFormModelValue = (list, parentKey) => { | |
| 184 | - list.forEach(item => { | |
| 185 | - item.fullKey = `${parentKey ? `${parentKey}-${item.key}` : item.key}`; | |
| 186 | - if (item.value instanceof Object) { | |
| 187 | - setFormModelValue( | |
| 188 | - Object.keys(item.value).map(key => ({ key, value: item.value[key] })), | |
| 189 | - item.fullKey, | |
| 190 | - ); | |
| 191 | - } else { | |
| 192 | - formModel[item.fullKey] = item.value; | |
| 193 | - } | |
| 194 | - }); | |
| 195 | - }; | |
| 196 | - setFormModelValue(Object.keys(value).map(key => ({ key, value: value[key] }))); | |
| 197 | - this.formModel = formModel; | |
| 198 | - }, | |
| 199 | - /** | |
| 200 | - * @description 手动更新某一表单项的值 | |
| 201 | - * @param {Object} param 需要更新的参数对象或者对象数组 { name => 表单项key,可嵌套; value => 更新的值 } | |
| 202 | - * @example { name: 'a.b.c', value: 123 } | |
| 203 | - * @example { name: 'd.0.e', value: ['f'] } | |
| 204 | - */ | |
| 205 | - onItemUpdate(param) { | |
| 206 | - this.$nextTick(() => { | |
| 207 | - const newModel = cloneDeep(this.model); | |
| 208 | - Object.entries(param).forEach(entry => { | |
| 209 | - set(newModel, entry[0], entry[1]); | |
| 210 | - }); | |
| 211 | - this.$emit('input', newModel); | |
| 212 | - }); | |
| 213 | - }, | |
| 214 | - }, | |
| 215 | -}; | |
| 216 | -</script> |
packages/schema-form/index.vue
| 1 | 1 | <template> |
| 2 | - <z-form ref="form" v-model="model" v-bind="schema.props" v-on="schema.props"> | |
| 2 | + <z-form ref="form" class="z-schema-form" v-model="model" v-bind="schema.props" v-on="schema.on"> | |
| 3 | 3 | <template v-for="(item, index) in schema.items"> |
| 4 | 4 | <template v-if="item.is"> |
| 5 | - <z-form-item v-if="bindParam(item, 'if', true)" v-show="bindParam(item, 'show', true)" v-bind="bindItemProps(item)" :key="index"> | |
| 5 | + <z-form-item v-if="bindParam(item, 'if')" v-show="bindParam(item, 'show')" v-bind="bindItemProps(item)" :key="index"> | |
| 6 | 6 | <slot v-if="$scopedSlots[item.prop]" :name="item.prop" :value="get(model, item.prop)" :onInput="value => onComponentInput({ value, item })" v-bind="slotProps"> </slot> |
| 7 | 7 | <item-render v-else :item="item" :value="get(model, item.prop)" :onInput="value => onComponentInput({ value, item })"></item-render> |
| 8 | 8 | <slot :name="`label-${item.prop}`" slot="label" v-bind="slotProps"></slot> |
| ... | ... | @@ -10,7 +10,7 @@ |
| 10 | 10 | </z-form-item> |
| 11 | 11 | </template> |
| 12 | 12 | <template v-else> |
| 13 | - <z-form-item v-if="bindParam(item, 'if', true)" v-show="bindParam(item, 'show', true)" v-bind="bindItemProps(item)" :key="index" :value="get(model, item.prop)"> | |
| 13 | + <z-form-item v-if="bindParam(item, 'if')" v-show="bindParam(item, 'show')" v-bind="bindItemProps(item)" :key="index" :value="get(model, item.prop)"> | |
| 14 | 14 | <slot :name="item.prop" :value="get(model, item.prop)" :onInput="value => onComponentInput({ value, item })" v-bind="slotProps"></slot> |
| 15 | 15 | </z-form-item> |
| 16 | 16 | </template> |
| ... | ... | @@ -20,10 +20,12 @@ |
| 20 | 20 | </template> |
| 21 | 21 | |
| 22 | 22 | <script> |
| 23 | +import MIX_FORM from '../mixins/form'; | |
| 23 | 24 | import { cloneDeep, get, set } from '../utils'; |
| 24 | 25 | |
| 25 | 26 | export default { |
| 26 | 27 | name: 'SchemaForm', |
| 28 | + mixins: [MIX_FORM], | |
| 27 | 29 | components: { |
| 28 | 30 | ItemRender: { |
| 29 | 31 | functional: true, |
| ... | ... | @@ -102,11 +104,16 @@ export default { |
| 102 | 104 | }, |
| 103 | 105 | methods: { |
| 104 | 106 | get, |
| 105 | - bindParam(item, key, def) { | |
| 107 | + bindParam(item, key) { | |
| 106 | 108 | if (typeof item[key] === 'function') { |
| 107 | 109 | return item[key]({ model: this.model }); |
| 108 | 110 | } |
| 109 | - return def || item[key]; | |
| 111 | + if (['if', 'show'].includes(key)) { | |
| 112 | + if (['', null, undefined].includes(item[key])) { | |
| 113 | + return true; | |
| 114 | + } | |
| 115 | + } | |
| 116 | + return item[key]; | |
| 110 | 117 | }, |
| 111 | 118 | bindItemProps(item) { |
| 112 | 119 | const { children, is, props, on, ...other } = item || {}; |
| ... | ... | @@ -115,18 +122,6 @@ export default { |
| 115 | 122 | return result; |
| 116 | 123 | }, {}); |
| 117 | 124 | }, |
| 118 | - validate(callback) { | |
| 119 | - return this.$refs.form.validate(callback); | |
| 120 | - }, | |
| 121 | - validateField(props, callback) { | |
| 122 | - return this.$refs.form.validateField(props, callback); | |
| 123 | - }, | |
| 124 | - resetFields() { | |
| 125 | - this.$refs.form.resetFields(); | |
| 126 | - }, | |
| 127 | - clearValidate(props) { | |
| 128 | - return this.$refs.form.clearValidate(props); | |
| 129 | - }, | |
| 130 | 125 | onComponentInput({ value, item }) { |
| 131 | 126 | set(this.model, item.prop, value); |
| 132 | 127 | }, | ... | ... |
packages/schema-form/schema-form-render.vue
| ... | ... | @@ -1,246 +0,0 @@ |
| 1 | -<template> | |
| 2 | - <!-- 在row上使用flex,防止表单组件大小不一导致错位 --> | |
| 3 | - <component :is="rowComponent" class="z-schema-form__flex-wrap"> | |
| 4 | - <template v-for="(item, index) in list"> | |
| 5 | - <!-- 表单项有设置分组时 --> | |
| 6 | - <component | |
| 7 | - :is="colComponent" | |
| 8 | - v-if="item.group && item.list" | |
| 9 | - :key="index" | |
| 10 | - :span="type === 'div' ? undefined : item.group.span || 24" | |
| 11 | - :style="{ width: type === 'div' ? '100%' : undefined }" | |
| 12 | - :class="colClassRender(item, index, colClass)" | |
| 13 | - > | |
| 14 | - <component :is="rowComponent" class="z-schema-form__flex-wrap" :class="groupClass || 'z-schema-form__group'"> | |
| 15 | - <!-- 表单分组标题 --> | |
| 16 | - <component :is="rowComponent" :class="titleClass || 'z-schema-form__group-title'" v-if="item.group.title" style="width: 100%;"> | |
| 17 | - {{ item.group.title || item.group }} | |
| 18 | - </component> | |
| 19 | - <!-- 递归本组件 --> | |
| 20 | - <schema-form-render | |
| 21 | - :title-class="titleClass" | |
| 22 | - :item-class="itemClass" | |
| 23 | - :content-class="contentClass" | |
| 24 | - :group-class="groupClass" | |
| 25 | - :class="contentClass || 'z-schema-form__group-content'" | |
| 26 | - :list="item.list" | |
| 27 | - :value="value" | |
| 28 | - :model="itemKey ? model[itemKey] || {} : model" | |
| 29 | - :itemKey="item.group.key" | |
| 30 | - :type="type" | |
| 31 | - @item-change="onItemChange" | |
| 32 | - @form-item-change="onFormItemChange" | |
| 33 | - @item-update="onItemUpdate" | |
| 34 | - :span="type === 'div' ? undefined : span * (24 / (item.group.span || 24))" | |
| 35 | - ></schema-form-render> | |
| 36 | - </component> | |
| 37 | - </component> | |
| 38 | - <!-- 正常无分组表单项 --> | |
| 39 | - <template v-else> | |
| 40 | - <component | |
| 41 | - :is="colComponent" | |
| 42 | - v-if="bindItemVisible(item, 'visible')" | |
| 43 | - v-show="bindItemVisible(item, 'show')" | |
| 44 | - :span="type === 'div' ? undefined : item.span || span" | |
| 45 | - :key="index" | |
| 46 | - :style="{ width: type === 'div' && item.style && item.style.width.includes('%') ? item.style.width : undefined, paddingRight: '10px' }" | |
| 47 | - :class="colClassRender(item, index, colClass)" | |
| 48 | - > | |
| 49 | - <el-form-item :label="item.label" :label-width="item.labelWidth" :prop="item.fullKey" :rules="item | bindItemRulesFilter(model)" :class="itemClass || 'z-schema-form__item'"> | |
| 50 | - <slot v-if="$scopedSlots[item.fullKey]" :name="item.fullKey" :value="itemValue(item)" :model1="value"></slot> | |
| 51 | - <template v-else> | |
| 52 | - <!-- 自定义组件 --> | |
| 53 | - <dynamic-render | |
| 54 | - v-if="typeof item.type === 'function'" | |
| 55 | - :render=" | |
| 56 | - item.type($createElement, { | |
| 57 | - model: value, | |
| 58 | - config: { | |
| 59 | - props: { ...propsFormatter(item.props), value: itemValue(item) }, | |
| 60 | - style: item.style || { width: '100%' }, | |
| 61 | - on: { | |
| 62 | - ...bindItemEvent(item), | |
| 63 | - input: v => onInput({ value: v, item }), | |
| 64 | - }, | |
| 65 | - }, | |
| 66 | - }) | |
| 67 | - " | |
| 68 | - ></dynamic-render> | |
| 69 | - <component | |
| 70 | - v-else | |
| 71 | - :is="item.type" | |
| 72 | - :value="itemValue(item)" | |
| 73 | - @input="v => onInput({ value: v, item })" | |
| 74 | - v-on="bindItemEvent(item)" | |
| 75 | - v-bind="propsFormatter(item.props)" | |
| 76 | - :style="item.style || { width: '100%' }" | |
| 77 | - ></component> | |
| 78 | - </template> | |
| 79 | - </el-form-item> | |
| 80 | - </component> | |
| 81 | - </template> | |
| 82 | - </template> | |
| 83 | - </component> | |
| 84 | -</template> | |
| 85 | - | |
| 86 | -<script> | |
| 87 | -export default { | |
| 88 | - name: 'SchemaFormRender', | |
| 89 | - components: { | |
| 90 | - DynamicRender: { | |
| 91 | - functional: true, | |
| 92 | - render(h, context) { | |
| 93 | - return context.props.render; | |
| 94 | - }, | |
| 95 | - }, | |
| 96 | - }, | |
| 97 | - props: { | |
| 98 | - list: Array, | |
| 99 | - model: Object, | |
| 100 | - value: Object, | |
| 101 | - itemKey: String, | |
| 102 | - titleClass: String, | |
| 103 | - contentClass: String, | |
| 104 | - itemClass: String, | |
| 105 | - colClass: [String, Function], | |
| 106 | - groupClass: String, | |
| 107 | - type: String, | |
| 108 | - span: Number, | |
| 109 | - params: Object, | |
| 110 | - }, | |
| 111 | - computed: { | |
| 112 | - rowComponent() { | |
| 113 | - return this.type === 'div' ? 'div' : 'el-row'; | |
| 114 | - }, | |
| 115 | - colComponent() { | |
| 116 | - return this.type === 'div' ? 'div' : 'el-col'; | |
| 117 | - }, | |
| 118 | - }, | |
| 119 | - filters: { | |
| 120 | - /** | |
| 121 | - * @description 绑定表单项规则 | |
| 122 | - * @param {Object} item 表单项配置 | |
| 123 | - * @returns {Function} 事件函数 | |
| 124 | - */ | |
| 125 | - bindItemRulesFilter(item = {}, model) { | |
| 126 | - if (item.rules) { | |
| 127 | - if (typeof item.rules === 'function') { | |
| 128 | - return item.rules(model); | |
| 129 | - } else { | |
| 130 | - return item.rules; | |
| 131 | - } | |
| 132 | - } else { | |
| 133 | - return undefined; | |
| 134 | - } | |
| 135 | - }, | |
| 136 | - }, | |
| 137 | - methods: { | |
| 138 | - /** | |
| 139 | - * @description 渲染col class | |
| 140 | - * @param {Object} item 表单项配置 | |
| 141 | - * @param {Object} index 表单项渲染下标 | |
| 142 | - * @param {Object} colClass 表单项配置 | |
| 143 | - * @return {String} col class | |
| 144 | - */ | |
| 145 | - colClassRender(item, index, colClass) { | |
| 146 | - if (colClass instanceof Function) { | |
| 147 | - return colClass(item, index); | |
| 148 | - } else { | |
| 149 | - return colClass; | |
| 150 | - } | |
| 151 | - }, | |
| 152 | - /** | |
| 153 | - * @description 根据表单项的key查询该值 | |
| 154 | - * @param {Object} item 表单项配置 | |
| 155 | - * @returns {Any} 返回值 | |
| 156 | - */ | |
| 157 | - itemValue(item) { | |
| 158 | - if (this.itemKey) { | |
| 159 | - // 如果存在itemKey,即当前项位于嵌套分组内,查询分组名下对应key的值 | |
| 160 | - const groupItem = this.model[this.itemKey] || {}; | |
| 161 | - return groupItem[item.key]; | |
| 162 | - } else { | |
| 163 | - // 否则即意味着不在分组内,直接查询model下对应key的值 | |
| 164 | - return this.model[item.key]; | |
| 165 | - } | |
| 166 | - }, | |
| 167 | - /** | |
| 168 | - * @description 组件有值输入时的事件 | |
| 169 | - * @param {Object} data { value => 组件值; item => 表单项配置 } | |
| 170 | - */ | |
| 171 | - onInput({ value, item }) { | |
| 172 | - if (this.itemKey) { | |
| 173 | - this.$emit('item-change', { [this.itemKey]: { ...this.model[this.itemKey], [item.key]: value } }); | |
| 174 | - } else { | |
| 175 | - this.$emit('item-change', { [item.key]: value }); | |
| 176 | - } | |
| 177 | - this.$emit('form-item-change', { [item.fullKey]: value }); | |
| 178 | - }, | |
| 179 | - /** | |
| 180 | - * @description 当表单项有改动时的事件 | |
| 181 | - * @param {Any} 表单项值 | |
| 182 | - */ | |
| 183 | - onItemChange(value) { | |
| 184 | - if (this.itemKey) { | |
| 185 | - this.$emit('item-change', { [this.itemKey]: { ...this.model[this.itemKey], ...value } }); | |
| 186 | - } else { | |
| 187 | - this.$emit('item-change', value); | |
| 188 | - } | |
| 189 | - }, | |
| 190 | - /** | |
| 191 | - * @description 当表单项校验值有改动时的事件 | |
| 192 | - * @param {Any} 表单项校验值 | |
| 193 | - */ | |
| 194 | - onFormItemChange(value) { | |
| 195 | - this.$emit('form-item-change', value); | |
| 196 | - }, | |
| 197 | - /** | |
| 198 | - * @description 当表单项有手动更新时的事件 | |
| 199 | - * @param {Any} 表单项值 | |
| 200 | - */ | |
| 201 | - onItemUpdate(value) { | |
| 202 | - this.$emit('item-update', value); | |
| 203 | - }, | |
| 204 | - /** | |
| 205 | - * @description 绑定表单项事件 | |
| 206 | - * @param {Object} item 表单项配置 | |
| 207 | - * @returns {Function} 事件函数 | |
| 208 | - */ | |
| 209 | - bindItemEvent(item) { | |
| 210 | - if (item.on) { | |
| 211 | - if (typeof item.on === 'function') { | |
| 212 | - return item.on({ model: this.value, update: e => this.$emit('item-update', e) }); | |
| 213 | - } else { | |
| 214 | - return item.on; | |
| 215 | - } | |
| 216 | - } else { | |
| 217 | - return undefined; | |
| 218 | - } | |
| 219 | - }, | |
| 220 | - /** | |
| 221 | - * @description 绑定表单项显示状态 | |
| 222 | - * @param {Object} item 表单项配置 | |
| 223 | - * @param {String} type Vue显示类型,可选值:visible、show | |
| 224 | - * @returns {Boolean} 显示状态 | |
| 225 | - */ | |
| 226 | - bindItemVisible(item, type) { | |
| 227 | - const visible = item[type]; | |
| 228 | - if (typeof visible === 'function') { | |
| 229 | - return visible(this.model, this.params || {}); | |
| 230 | - } | |
| 231 | - return item[type] !== false; | |
| 232 | - }, | |
| 233 | - /** | |
| 234 | - * @description 格式化props属性 | |
| 235 | - * @param {Object|Function} props 属性或属性对象 | |
| 236 | - * @returns {Object} 格式化的属性 | |
| 237 | - */ | |
| 238 | - propsFormatter(props) { | |
| 239 | - if (typeof props === 'function') { | |
| 240 | - return props(this.model, this.params || {}); | |
| 241 | - } | |
| 242 | - return props || {}; | |
| 243 | - }, | |
| 244 | - }, | |
| 245 | -}; | |
| 246 | -</script> |