Commit 303ef68882af7d8e6b235acc89b0447735476d57
1 parent
bffb3d99
Exists in
master
and in
2 other branches
feat: 优化SchemaTransfer
Showing
3 changed files
with
144 additions
and
27 deletions
Show diff stats
examples/views/docs/component/schema-transfer.md
| @@ -100,11 +100,86 @@ export default { | @@ -100,11 +100,86 @@ export default { | ||
| 100 | 100 | ||
| 101 | 可以单独配置已选中的表格 | 101 | 可以单独配置已选中的表格 |
| 102 | 102 | ||
| 103 | -::: snippet `schema`中设置`selected`,格式与`z-schema-table`相同。 | 103 | +::: snippet `schema`中设置`selected`,配置与`SchemaTable`相同。其中已选中项的表格字段可以与数据源不同,设置`choose-formatter`改变选择的数据格式。 |
| 104 | 104 | ||
| 105 | ```html | 105 | ```html |
| 106 | <template> | 106 | <template> |
| 107 | - <z-schema-transfer v-model="model" :schema="schema" :source="source" value-key="id" size="small"></z-schema-transfer> | 107 | + <z-schema-transfer v-model="model" :schema="schema" :source="source" value-key="id" size="small" :choose-formatter="chooseFormatter"></z-schema-transfer> |
| 108 | +</template> | ||
| 109 | + | ||
| 110 | +<script> | ||
| 111 | +export default { | ||
| 112 | + data() { | ||
| 113 | + return { | ||
| 114 | + model: [], | ||
| 115 | + source: [ | ||
| 116 | + { id: '0', name: '姓名0', age: 17 }, | ||
| 117 | + { id: '1', name: '姓名1', age: 26 }, | ||
| 118 | + ], | ||
| 119 | + schema: { | ||
| 120 | + table: { | ||
| 121 | + items: [ | ||
| 122 | + { label: '姓名', prop: 'name', minWidth: 120 }, | ||
| 123 | + { label: '年龄', prop: 'age', minWidth: 120 }, | ||
| 124 | + { label: '地址', prop: 'address', minWidth: 120 }, | ||
| 125 | + ] | ||
| 126 | + }, | ||
| 127 | + selected: { | ||
| 128 | + props: { border: true, editable: true }, | ||
| 129 | + items: [ | ||
| 130 | + { label: '姓名', prop: 'name', minWidth: 120, editable: false }, | ||
| 131 | + { label: '性别', prop: 'gender', minWidth: 120, editable: false }, | ||
| 132 | + { label: '民族', prop: 'ethnicity', minWidth: 120, editalways: true }, | ||
| 133 | + ] | ||
| 134 | + } | ||
| 135 | + }, | ||
| 136 | + } | ||
| 137 | + }, | ||
| 138 | + methods: { | ||
| 139 | + chooseFormatter(row) { | ||
| 140 | + return { id: row.id, name: row.name, gender: '男', ethnicity: '汉' }; | ||
| 141 | + } | ||
| 142 | + } | ||
| 143 | +} | ||
| 144 | +</script> | ||
| 145 | +``` | ||
| 146 | + | ||
| 147 | +::: | ||
| 148 | + | ||
| 149 | +## 自定义插槽 | ||
| 150 | + | ||
| 151 | +同其他组件一样,可以对部分内容设置插槽 | ||
| 152 | + | ||
| 153 | +::: snippet 左侧插槽格式默认与`SchemaPage`组件相同,已选中表格的插槽以`selected-`开头 | ||
| 154 | + | ||
| 155 | +```html | ||
| 156 | +<template> | ||
| 157 | + <z-schema-transfer v-model="model" :schema="schema" :source="source" value-key="id" size="small"> | ||
| 158 | + <template #table-cell-name="{ value, size }"> | ||
| 159 | + <el-tag :size="size">{{ value }}</el-tag> | ||
| 160 | + </template> | ||
| 161 | + <template #operation="{ choose }"> | ||
| 162 | + <el-table-column label="新操作" width="80" align="center" fixed="right"> | ||
| 163 | + <template #default="{ row, $index }"> | ||
| 164 | + <div class="z-schema-page__table-operation"> | ||
| 165 | + <el-button size="mini" @click="choose(row)">选中</el-button> | ||
| 166 | + </div> | ||
| 167 | + </template> | ||
| 168 | + </el-table-column> | ||
| 169 | + </template> | ||
| 170 | + <template #selected-cell-name="{ value, size }"> | ||
| 171 | + <el-tag :size="size" type="success">{{ value }}</el-tag> | ||
| 172 | + </template> | ||
| 173 | + <template #selected-operation="{ remove }"> | ||
| 174 | + <el-table-column label="新操作" width="80" align="center" fixed="right"> | ||
| 175 | + <template #default="{ row, $index }"> | ||
| 176 | + <div class="z-schema-page__table-operation"> | ||
| 177 | + <el-button size="mini" @click="remove(row)">移除</el-button> | ||
| 178 | + </div> | ||
| 179 | + </template> | ||
| 180 | + </el-table-column> | ||
| 181 | + </template> | ||
| 182 | + </z-schema-transfer> | ||
| 108 | </template> | 183 | </template> |
| 109 | 184 | ||
| 110 | <script> | 185 | <script> |
| @@ -151,15 +226,15 @@ export default { | @@ -151,15 +226,15 @@ export default { | ||
| 151 | <template> | 226 | <template> |
| 152 | <z-schema-transfer v-model="model" :schema="schema" :source="source" value-key="id" size="small"> | 227 | <z-schema-transfer v-model="model" :schema="schema" :source="source" value-key="id" size="small"> |
| 153 | <template #title-left>未选择 <i class="el-icon-minus"></i></template> | 228 | <template #title-left>未选择 <i class="el-icon-minus"></i></template> |
| 154 | - <template #default="{ onChoose, valueFormatter }"> | 229 | + <template #default="{ choose, deselect }"> |
| 155 | <div> | 230 | <div> |
| 156 | - <el-button size="mini" v-for="item in valueFormatter(source)" @click="onChoose(item)">{{ item.name }}</el-button> | 231 | + <el-button size="mini" v-for="item in deselect(source)" @click="choose(item)">{{ item.name }}</el-button> |
| 157 | </div> | 232 | </div> |
| 158 | </template> | 233 | </template> |
| 159 | <template #title-right>已选择 <i class="el-icon-check"></i></template> | 234 | <template #title-right>已选择 <i class="el-icon-check"></i></template> |
| 160 | - <template #selected="{ onRemove }"> | 235 | + <template #selected="{ remove }"> |
| 161 | <div> | 236 | <div> |
| 162 | - <el-button size="mini" v-for="item in model" @click="onRemove(item)">{{ item.name }}</el-button> | 237 | + <el-button size="mini" v-for="item in model" @click="remove(item)">{{ item.name }}</el-button> |
| 163 | </div> | 238 | </div> |
| 164 | </template> | 239 | </template> |
| 165 | </z-schema-transfer> | 240 | </z-schema-transfer> |
packages/schema-transfer/index.vue
| @@ -29,11 +29,11 @@ | @@ -29,11 +29,11 @@ | ||
| 29 | <div class="z-schema-transfer__left"> | 29 | <div class="z-schema-transfer__left"> |
| 30 | <div class="z-schema-transfer__header"> | 30 | <div class="z-schema-transfer__header"> |
| 31 | <div class="z-schema-transfer__title"> | 31 | <div class="z-schema-transfer__title"> |
| 32 | - <slot name="title-left">{{ titles[0] }}</slot> | 32 | + <slot name="title-left" v-bind="_slotScope">{{ titles[0] }}</slot> |
| 33 | </div> | 33 | </div> |
| 34 | </div> | 34 | </div> |
| 35 | <div class="z-schema-transfer__content"> | 35 | <div class="z-schema-transfer__content"> |
| 36 | - <slot :onChoose="onChoose" :valueFormatter="valueFormatter"> | 36 | + <slot v-bind="_slotScope"> |
| 37 | <z-schema-page | 37 | <z-schema-page |
| 38 | :size="transferSize" | 38 | :size="transferSize" |
| 39 | :value-filter="valueFilter" | 39 | :value-filter="valueFilter" |
| @@ -43,14 +43,19 @@ | @@ -43,14 +43,19 @@ | ||
| 43 | @update:value-filter="e => $emit('update:value-filter', e)" | 43 | @update:value-filter="e => $emit('update:value-filter', e)" |
| 44 | :auto="auto" | 44 | :auto="auto" |
| 45 | > | 45 | > |
| 46 | + <template v-for="item in getSlotKeys('table-')" #[item.name]="slotScope"> | ||
| 47 | + <slot :name="item.slot" v-bind="{ ..._slotScope, ...slotScope }"></slot> | ||
| 48 | + </template> | ||
| 46 | <template #operation> | 49 | <template #operation> |
| 47 | - <el-table-column label="操作" width="80" align="center" fixed="right"> | ||
| 48 | - <template #default="{ row, $index }"> | ||
| 49 | - <div class="z-schema-page__table-operation"> | ||
| 50 | - <el-button type="text" :disabled="_rowDisabled(row, $index)" @click="onChoose(row)">选择</el-button> | ||
| 51 | - </div> | ||
| 52 | - </template> | ||
| 53 | - </el-table-column> | 50 | + <slot name="operation" v-bind="_slotScope"> |
| 51 | + <el-table-column label="操作" width="80" align="center" fixed="right"> | ||
| 52 | + <template #default="{ row, $index }"> | ||
| 53 | + <div class="z-schema-page__table-operation"> | ||
| 54 | + <el-button type="text" :disabled="_rowDisabled(row, $index)" @click="onChoose(row)">选择</el-button> | ||
| 55 | + </div> | ||
| 56 | + </template> | ||
| 57 | + </el-table-column> | ||
| 58 | + </slot> | ||
| 54 | </template> | 59 | </template> |
| 55 | </z-schema-page> | 60 | </z-schema-page> |
| 56 | </slot> | 61 | </slot> |
| @@ -63,15 +68,20 @@ | @@ -63,15 +68,20 @@ | ||
| 63 | </div> | 68 | </div> |
| 64 | </div> | 69 | </div> |
| 65 | <div class="z-schema-transfer__content"> | 70 | <div class="z-schema-transfer__content"> |
| 66 | - <slot name="selected" :onRemove="onRemove"> | 71 | + <slot name="selected" v-bind="_slotScope"> |
| 67 | <z-schema-table :size="transferSize" :value="value" :schema="schemaRight" @input="onInput"> | 72 | <z-schema-table :size="transferSize" :value="value" :schema="schemaRight" @input="onInput"> |
| 68 | - <el-table-column label="操作" width="80" align="center" fixed="right"> | ||
| 69 | - <template #default="{ row, $index }"> | ||
| 70 | - <div class="z-schema-page__table-operation"> | ||
| 71 | - <el-button type="text" :disabled="_rowDisabled(row, $index)" @click="onRemove(row, $index)">移除</el-button> | ||
| 72 | - </div> | ||
| 73 | - </template> | ||
| 74 | - </el-table-column> | 73 | + <template v-for="item in getSlotKeys('selected-', true)" #[item.name]="slotScope"> |
| 74 | + <slot :name="item.slot" v-bind="{ ..._slotScope, ...slotScope }"></slot> | ||
| 75 | + </template> | ||
| 76 | + <slot name="selected-operation" v-bind="_slotScope"> | ||
| 77 | + <el-table-column label="操作" width="80" align="center" fixed="right"> | ||
| 78 | + <template #default="{ row, $index }"> | ||
| 79 | + <div class="z-schema-page__table-operation"> | ||
| 80 | + <el-button type="text" :disabled="_rowDisabled(row, $index)" @click="onRemove(row, $index)">移除</el-button> | ||
| 81 | + </div> | ||
| 82 | + </template> | ||
| 83 | + </el-table-column> | ||
| 84 | + </slot> | ||
| 75 | </z-schema-table> | 85 | </z-schema-table> |
| 76 | </slot> | 86 | </slot> |
| 77 | </div> | 87 | </div> |
| @@ -114,6 +124,7 @@ export default { | @@ -114,6 +124,7 @@ export default { | ||
| 114 | auto: Boolean, | 124 | auto: Boolean, |
| 115 | rowDisabled: Function, | 125 | rowDisabled: Function, |
| 116 | apiSearch: Function, | 126 | apiSearch: Function, |
| 127 | + chooseFormatter: Function, | ||
| 117 | valueFilter: { | 128 | valueFilter: { |
| 118 | type: Object, | 129 | type: Object, |
| 119 | default() { | 130 | default() { |
| @@ -186,10 +197,37 @@ export default { | @@ -186,10 +197,37 @@ export default { | ||
| 186 | return this.value.map(item => item[this.valueKey]); | 197 | return this.value.map(item => item[this.valueKey]); |
| 187 | }, | 198 | }, |
| 188 | valueTable() { | 199 | valueTable() { |
| 189 | - return this.valueFormatter(this.dataSource || []); | 200 | + return this.deselect(this.dataSource || []); |
| 201 | + }, | ||
| 202 | + slotKeys() { | ||
| 203 | + return Object.keys(this.$scopedSlots); | ||
| 204 | + }, | ||
| 205 | + _slotScope() { | ||
| 206 | + const methods = ['deselect']; | ||
| 207 | + const defaultScope = { | ||
| 208 | + size: this.transferSize, | ||
| 209 | + disabled: this.transferDisabled, | ||
| 210 | + choose: this.onChoose, | ||
| 211 | + remove: this.onRemove, | ||
| 212 | + }; | ||
| 213 | + return [...methods].reduce((result, current) => { | ||
| 214 | + result[current] = this[current]; | ||
| 215 | + return result; | ||
| 216 | + }, defaultScope); | ||
| 190 | }, | 217 | }, |
| 191 | }, | 218 | }, |
| 192 | methods: { | 219 | methods: { |
| 220 | + getSlotKeys(prefix, fixed) { | ||
| 221 | + return this.slotKeys.reduce((result, current) => { | ||
| 222 | + if (current.indexOf(prefix) === 0) { | ||
| 223 | + result.push({ | ||
| 224 | + slot: current, | ||
| 225 | + name: fixed ? current.substring(prefix.length) : current, | ||
| 226 | + }); | ||
| 227 | + } | ||
| 228 | + return result; | ||
| 229 | + }, []); | ||
| 230 | + }, | ||
| 193 | _rowDisabled(row, index) { | 231 | _rowDisabled(row, index) { |
| 194 | if (this.transferDisabled) { | 232 | if (this.transferDisabled) { |
| 195 | return true; | 233 | return true; |
| @@ -199,11 +237,15 @@ export default { | @@ -199,11 +237,15 @@ export default { | ||
| 199 | } | 237 | } |
| 200 | return false; | 238 | return false; |
| 201 | }, | 239 | }, |
| 202 | - valueFormatter(value) { | 240 | + deselect(value) { |
| 203 | return value.filter(item => !this.valueKeys.includes(item[this.valueKey])); | 241 | return value.filter(item => !this.valueKeys.includes(item[this.valueKey])); |
| 204 | }, | 242 | }, |
| 205 | onChoose(row) { | 243 | onChoose(row) { |
| 206 | - this.$emit('input', [...this.value, row]); | 244 | + let newRow = cloneDeep(row); |
| 245 | + if (this.chooseFormatter) { | ||
| 246 | + newRow = this.chooseFormatter(newRow); | ||
| 247 | + } | ||
| 248 | + this.$emit('input', [...this.value, newRow]); | ||
| 207 | }, | 249 | }, |
| 208 | onRemove(row, index) { | 250 | onRemove(row, index) { |
| 209 | const newValue = cloneDeep(this.value || []); | 251 | const newValue = cloneDeep(this.value || []); |