Commit 5eb15c695e161b4b200f9c763265bfdb18b14431
1 parent
6ddd056d
Exists in
master
and in
3 other branches
feat: 完善Scheme支持接口对接与表格多选
Showing
1 changed file
with
198 additions
and
27 deletions
Show diff stats
packages/scheme/index.vue
| @@ -13,8 +13,8 @@ | @@ -13,8 +13,8 @@ | ||
| 13 | display: flex; | 13 | display: flex; |
| 14 | flex-wrap: wrap; | 14 | flex-wrap: wrap; |
| 15 | align-items: center; | 15 | align-items: center; |
| 16 | - line-height: 1; | ||
| 17 | justify-content: flex-start; | 16 | justify-content: flex-start; |
| 17 | + line-height: 1; | ||
| 18 | .el-button + .el-button { | 18 | .el-button + .el-button { |
| 19 | margin-left: 0; | 19 | margin-left: 0; |
| 20 | } | 20 | } |
| @@ -23,6 +23,20 @@ | @@ -23,6 +23,20 @@ | ||
| 23 | margin-bottom: 10px; | 23 | margin-bottom: 10px; |
| 24 | } | 24 | } |
| 25 | } | 25 | } |
| 26 | + &__table { | ||
| 27 | + &-operation { | ||
| 28 | + display: flex; | ||
| 29 | + flex-wrap: wrap; | ||
| 30 | + align-items: center; | ||
| 31 | + justify-content: flex-start; | ||
| 32 | + .el-button + .el-button { | ||
| 33 | + margin-left: 0; | ||
| 34 | + } | ||
| 35 | + .el-button { | ||
| 36 | + margin-right: 10px; | ||
| 37 | + } | ||
| 38 | + } | ||
| 39 | + } | ||
| 26 | &__dialog-button { | 40 | &__dialog-button { |
| 27 | display: flex; | 41 | display: flex; |
| 28 | align-items: center; | 42 | align-items: center; |
| @@ -32,6 +46,27 @@ | @@ -32,6 +46,27 @@ | ||
| 32 | &__footer { | 46 | &__footer { |
| 33 | margin-top: 10px; | 47 | margin-top: 10px; |
| 34 | text-align: right; | 48 | text-align: right; |
| 49 | + display: flex; | ||
| 50 | + justify-content: space-between; | ||
| 51 | + align-items: center; | ||
| 52 | + .selection-info { | ||
| 53 | + word-break: break-all; | ||
| 54 | + white-space: nowrap; | ||
| 55 | + font-size: 12px; | ||
| 56 | + color: #606266; | ||
| 57 | + .num { | ||
| 58 | + color: #000; | ||
| 59 | + font-weight: bold; | ||
| 60 | + padding: 0 5px; | ||
| 61 | + font-size: 16px; | ||
| 62 | + } | ||
| 63 | + .el-button { | ||
| 64 | + margin-left: 5px; | ||
| 65 | + } | ||
| 66 | + } | ||
| 67 | + .el-pagination { | ||
| 68 | + flex: auto; | ||
| 69 | + } | ||
| 35 | } | 70 | } |
| 36 | } | 71 | } |
| 37 | </style> | 72 | </style> |
| @@ -42,7 +77,7 @@ | @@ -42,7 +77,7 @@ | ||
| 42 | <slot name="header" :filterModel="filterModel" v-bind="_slotScope"></slot> | 77 | <slot name="header" :filterModel="filterModel" v-bind="_slotScope"></slot> |
| 43 | </div> | 78 | </div> |
| 44 | <div class="zee-scheme__filter"> | 79 | <div class="zee-scheme__filter"> |
| 45 | - <z-filter v-if="filter" :value="_filterModel" :list="list | noRulesFilter" :size="size" @input="onFilterInput"></z-filter> | 80 | + <z-filter v-if="filter" :value="_filterModel" :list="list | noRulesFilter" :size="size" @input="onFilterInput" @search="search" :loading="loading"></z-filter> |
| 46 | </div> | 81 | </div> |
| 47 | <div v-if="action" class="zee-scheme__action"> | 82 | <div v-if="action" class="zee-scheme__action"> |
| 48 | <slot v-if="hadSlot('action')" name="action" v-bind="_slotScope"></slot> | 83 | <slot v-if="hadSlot('action')" name="action" v-bind="_slotScope"></slot> |
| @@ -52,17 +87,38 @@ | @@ -52,17 +87,38 @@ | ||
| 52 | </template> | 87 | </template> |
| 53 | </div> | 88 | </div> |
| 54 | <div class="zee-scheme__table"> | 89 | <div class="zee-scheme__table"> |
| 55 | - <z-table v-model="tableData" :list="list" :tableProps="{ border: true }" :size="size"> | 90 | + <z-table |
| 91 | + ref="table" | ||
| 92 | + v-model="tableData" | ||
| 93 | + v-loading="loading" | ||
| 94 | + :list="list" | ||
| 95 | + :tableProps="{ border: true, 'row-key': 'id', ...tableProps }" | ||
| 96 | + :size="size" | ||
| 97 | + @selection-change="onTableSelectionChange" | ||
| 98 | + @selection="onTableSelection" | ||
| 99 | + > | ||
| 100 | + <slot></slot> | ||
| 56 | <template #column-end> | 101 | <template #column-end> |
| 57 | <el-table-column prop="$operation" label="操作" :width="140" fixed="right"> | 102 | <el-table-column prop="$operation" label="操作" :width="140" fixed="right"> |
| 58 | - <template slot-scope="slotScope"> | 103 | + <div class="zee-scheme__table-operation" slot-scope="slotScope"> |
| 59 | <el-button type="text" icon="el-icon-edit" title="编辑" @click="openEdit(slotScope)"></el-button> | 104 | <el-button type="text" icon="el-icon-edit" title="编辑" @click="openEdit(slotScope)"></el-button> |
| 60 | - </template> | 105 | + <el-popconfirm confirmButtonText="确定" cancelButtonText="取消" title="确定删除吗?" placement="top" @onConfirm="handleDelete(slotScope)"> |
| 106 | + <el-button slot="reference" type="text" icon="el-icon-delete" title="删除"></el-button> | ||
| 107 | + </el-popconfirm> | ||
| 108 | + </div> | ||
| 61 | </el-table-column> | 109 | </el-table-column> |
| 62 | </template> | 110 | </template> |
| 63 | </z-table> | 111 | </z-table> |
| 64 | </div> | 112 | </div> |
| 65 | - <div class="zee-scheme__footer"> | 113 | + <div v-if="pagination" class="zee-scheme__footer"> |
| 114 | + <div v-if="selection.length > 0" class="selection-info"> | ||
| 115 | + <span>已选中</span> | ||
| 116 | + <span class="num">{{ selection.length }}</span> | ||
| 117 | + <span>项</span> | ||
| 118 | + <el-popconfirm confirmButtonText="确定" cancelButtonText="取消" title="确定清除吗?" placement="top" @onConfirm="clearSelection"> | ||
| 119 | + <el-button slot="reference" :size="size" type="text">清除</el-button> | ||
| 120 | + </el-popconfirm> | ||
| 121 | + </div> | ||
| 66 | <el-pagination | 122 | <el-pagination |
| 67 | @size-change="handleSizeChange" | 123 | @size-change="handleSizeChange" |
| 68 | @current-change="handleCurrentChange" | 124 | @current-change="handleCurrentChange" |
| @@ -74,14 +130,14 @@ | @@ -74,14 +130,14 @@ | ||
| 74 | > | 130 | > |
| 75 | </el-pagination> | 131 | </el-pagination> |
| 76 | </div> | 132 | </div> |
| 77 | - <el-dialog :visible.sync="dialogVisible" :title="dialogTitle" destroy-on-close append-to-body :close-on-click-modal="false" @closed="onDialogClosed"> | 133 | + <el-dialog :visible.sync="dialogVisible" :title="dialogTitle" destroy-on-close append-to-body :lock-scroll="false" :close-on-click-modal="false" @closed="onDialogClosed"> |
| 78 | <div v-loading="dialogLoading"> | 134 | <div v-loading="dialogLoading"> |
| 79 | <slot v-if="hadSlot('dialog-title')" slot="title" name="dialog-title" :dialogType="dialogType" v-bind="_slotScope"></slot> | 135 | <slot v-if="hadSlot('dialog-title')" slot="title" name="dialog-title" :dialogType="dialogType" v-bind="_slotScope"></slot> |
| 80 | <template v-if="dialogRender"> | 136 | <template v-if="dialogRender"> |
| 81 | <slot v-if="hadSlot(`dialog-${dialogType}`)" :name="`dialog-${dialogType}`" :model="_formModel" v-bind="_slotScope"></slot> | 137 | <slot v-if="hadSlot(`dialog-${dialogType}`)" :name="`dialog-${dialogType}`" :model="_formModel" v-bind="_slotScope"></slot> |
| 82 | <z-form v-else ref="form" :value="_formModel" :list="list" label-width="80px" :span="12" @input="onFormInput" @validate="onFormValidate"></z-form> | 138 | <z-form v-else ref="form" :value="_formModel" :list="list" label-width="80px" :span="12" @input="onFormInput" @validate="onFormValidate"></z-form> |
| 83 | <div class="zee-scheme__dialog-button" v-if="['new', 'edit'].includes(dialogType)"> | 139 | <div class="zee-scheme__dialog-button" v-if="['new', 'edit'].includes(dialogType)"> |
| 84 | - <el-button :size="size" type="primary" @click="handleConfirm">确定</el-button> | 140 | + <el-button :size="size" type="primary" @click="handleConfirm" :loading="submitting">确定</el-button> |
| 85 | <el-button :size="size" plain @click="closeDialog">取消</el-button> | 141 | <el-button :size="size" plain @click="closeDialog">取消</el-button> |
| 86 | </div> | 142 | </div> |
| 87 | </template> | 143 | </template> |
| @@ -105,12 +161,26 @@ export default { | @@ -105,12 +161,26 @@ export default { | ||
| 105 | type: Boolean, | 161 | type: Boolean, |
| 106 | default: true, | 162 | default: true, |
| 107 | }, | 163 | }, |
| 164 | + pagination: { | ||
| 165 | + type: Boolean, | ||
| 166 | + default: true, | ||
| 167 | + }, | ||
| 108 | size: { | 168 | size: { |
| 109 | type: String, | 169 | type: String, |
| 110 | default: 'mini', | 170 | default: 'mini', |
| 111 | }, | 171 | }, |
| 172 | + tableProps: { | ||
| 173 | + type: Object, | ||
| 174 | + default: () => ({}), | ||
| 175 | + }, | ||
| 112 | formModel: Object, | 176 | formModel: Object, |
| 113 | filterModel: Object, | 177 | filterModel: Object, |
| 178 | + auto: Boolean, | ||
| 179 | + realSelection: Boolean, | ||
| 180 | + searchAPI: Function, | ||
| 181 | + submitAPI: Function, | ||
| 182 | + getAPI: Function, | ||
| 183 | + deleteAPI: Function, | ||
| 114 | }, | 184 | }, |
| 115 | data() { | 185 | data() { |
| 116 | return { | 186 | return { |
| @@ -121,17 +191,23 @@ export default { | @@ -121,17 +191,23 @@ export default { | ||
| 121 | dialogType: 'none', | 191 | dialogType: 'none', |
| 122 | dialogLoading: false, | 192 | dialogLoading: false, |
| 123 | dialogTitle: '', | 193 | dialogTitle: '', |
| 124 | - dialogCloseCallback: undefined, | ||
| 125 | currentPage: 1, | 194 | currentPage: 1, |
| 126 | - pageSize: 10, | 195 | + // pageSize: 10, |
| 196 | + pageSize: 5, | ||
| 127 | total: 127, | 197 | total: 127, |
| 128 | - pageSizes: [10, 20, 50], | ||
| 129 | - tableData: [ | ||
| 130 | - { name: '张三', age: 16, driver: { name: '王五', bank: { name: '中国银行' } } }, | ||
| 131 | - { name: '李四', age: 24 }, | ||
| 132 | - ], | 198 | + // pageSizes: [10, 20, 50], |
| 199 | + pageSizes: [1, 2, 5], | ||
| 200 | + tableData: [], | ||
| 201 | + submitting: false, | ||
| 202 | + loading: false, | ||
| 203 | + selection: [], | ||
| 133 | }; | 204 | }; |
| 134 | }, | 205 | }, |
| 206 | + created() { | ||
| 207 | + if (this.auto) { | ||
| 208 | + this.search(); | ||
| 209 | + } | ||
| 210 | + }, | ||
| 135 | filters: { | 211 | filters: { |
| 136 | noRulesFilter(val = []) { | 212 | noRulesFilter(val = []) { |
| 137 | let list = cloneDeep(val); | 213 | let list = cloneDeep(val); |
| @@ -163,17 +239,95 @@ export default { | @@ -163,17 +239,95 @@ export default { | ||
| 163 | }, | 239 | }, |
| 164 | }, | 240 | }, |
| 165 | methods: { | 241 | methods: { |
| 242 | + // 空Promise | ||
| 243 | + emptyPromise() { | ||
| 244 | + return new Promise(resolve => { | ||
| 245 | + resolve(); | ||
| 246 | + }); | ||
| 247 | + }, | ||
| 248 | + // 设置第二行选中 | ||
| 249 | + toggleRowSelection() { | ||
| 250 | + this.tableData.forEach(row => { | ||
| 251 | + if (this.selection.find(item => item.id === row.id)) { | ||
| 252 | + this.$refs.table && this.$refs.table.toggleRowSelection(row); | ||
| 253 | + } | ||
| 254 | + }); | ||
| 255 | + }, | ||
| 256 | + // 表格选中状态 | ||
| 257 | + onTableSelectionChange(selection, type) { | ||
| 258 | + if (this.realSelection) { | ||
| 259 | + if (type === 'check') { | ||
| 260 | + const result = this.selection || []; | ||
| 261 | + selection.forEach(item => { | ||
| 262 | + if (!result.find(i => i.id === item.id)) { | ||
| 263 | + result.push(item); | ||
| 264 | + } | ||
| 265 | + }); | ||
| 266 | + this.selection = result; | ||
| 267 | + } else if (type === 'uncheck') { | ||
| 268 | + selection.forEach(i => { | ||
| 269 | + this.selection = this.selection.filter(item => item.id !== i.id); | ||
| 270 | + }); | ||
| 271 | + } | ||
| 272 | + } | ||
| 273 | + }, | ||
| 274 | + // 表格选中 | ||
| 275 | + onTableSelection(selection) { | ||
| 276 | + if (!this.realSelection) { | ||
| 277 | + this.selection = selection; | ||
| 278 | + } | ||
| 279 | + }, | ||
| 280 | + // 清除表格选中 | ||
| 281 | + clearSelection() { | ||
| 282 | + this.$refs.table && this.$refs.table.clearSelection(); | ||
| 283 | + this.selection = []; | ||
| 284 | + }, | ||
| 285 | + // 搜索 | ||
| 286 | + async search() { | ||
| 287 | + this.loading = true; | ||
| 288 | + const params = { | ||
| 289 | + ...this._filterModel, | ||
| 290 | + currentPage: this.currentPage, | ||
| 291 | + pageSize: this.pageSize, | ||
| 292 | + }; | ||
| 293 | + const searchAPI = this.searchAPI || this.emptyPromise; | ||
| 294 | + await searchAPI(params) | ||
| 295 | + .then(response => { | ||
| 296 | + const { result, totalCount } = response || {}; | ||
| 297 | + this.tableData = result; | ||
| 298 | + this.total = totalCount; | ||
| 299 | + this.$nextTick(() => { | ||
| 300 | + this.toggleRowSelection(); | ||
| 301 | + }); | ||
| 302 | + }) | ||
| 303 | + .catch(() => { | ||
| 304 | + this.$message.error('失败'); | ||
| 305 | + }); | ||
| 306 | + this.loading = false; | ||
| 307 | + }, | ||
| 308 | + // 更新筛选model | ||
| 166 | onFilterInput(val) { | 309 | onFilterInput(val) { |
| 167 | this.filterForm = val || {}; | 310 | this.filterForm = val || {}; |
| 168 | this.$emit('update:filterModel', val || {}); | 311 | this.$emit('update:filterModel', val || {}); |
| 169 | }, | 312 | }, |
| 313 | + // 更新表单model | ||
| 170 | onFormInput(val) { | 314 | onFormInput(val) { |
| 171 | this.editForm = val || {}; | 315 | this.editForm = val || {}; |
| 172 | this.$emit('update:formModel', val || {}); | 316 | this.$emit('update:formModel', val || {}); |
| 173 | }, | 317 | }, |
| 174 | - onFormValidate(valid, model) { | 318 | + // 表单提交且通过校验 |
| 319 | + async onFormValidate(valid, model) { | ||
| 175 | if (valid) { | 320 | if (valid) { |
| 176 | - console.log(model); | 321 | + this.submitting = true; |
| 322 | + const submitAPI = this.submitAPI || this.emptyPromise; | ||
| 323 | + await submitAPI(model, { type: this.dialogType }) | ||
| 324 | + .then(() => { | ||
| 325 | + this.closeDialog(); | ||
| 326 | + }) | ||
| 327 | + .catch(() => { | ||
| 328 | + this.$message.error('失败'); | ||
| 329 | + }); | ||
| 330 | + this.submitting = false; | ||
| 177 | } | 331 | } |
| 178 | }, | 332 | }, |
| 179 | // 表单按钮确定 | 333 | // 表单按钮确定 |
| @@ -193,13 +347,31 @@ export default { | @@ -193,13 +347,31 @@ export default { | ||
| 193 | this.openDialog('new', '新增'); | 347 | this.openDialog('new', '新增'); |
| 194 | }, | 348 | }, |
| 195 | // 打开编辑弹出框 | 349 | // 打开编辑弹出框 |
| 196 | - openEdit({ row }) { | 350 | + async openEdit({ row }) { |
| 197 | this.dialogLoading = true; | 351 | this.dialogLoading = true; |
| 198 | - setTimeout(() => { | ||
| 199 | - this.editForm = { ...row }; | ||
| 200 | - this.dialogLoading = false; | ||
| 201 | - }, 300); | ||
| 202 | this.openDialog('edit', '编辑'); | 352 | this.openDialog('edit', '编辑'); |
| 353 | + const getRow = () => { | ||
| 354 | + this.editForm = { ...row }; | ||
| 355 | + }; | ||
| 356 | + const getAPI = this.getAPI || getRow; | ||
| 357 | + await getAPI(row).then(result => { | ||
| 358 | + this.editForm = { ...result }; | ||
| 359 | + }); | ||
| 360 | + this.dialogLoading = false; | ||
| 361 | + }, | ||
| 362 | + // 删除 | ||
| 363 | + async handleDelete({ row, $index }) { | ||
| 364 | + const deleteAPI = this.deleteAPI || this.emptyPromise; | ||
| 365 | + const loading = this.$loading({ | ||
| 366 | + text: '处理中', | ||
| 367 | + spinner: 'el-icon-loading', | ||
| 368 | + background: 'rgba(255, 255, 255, 0.5)', | ||
| 369 | + }); | ||
| 370 | + await deleteAPI(row).then(() => { | ||
| 371 | + this.tableData.splice($index, 1); | ||
| 372 | + this.$message.success('删除成功'); | ||
| 373 | + }); | ||
| 374 | + loading.close(); | ||
| 203 | }, | 375 | }, |
| 204 | // 打开弹出框 | 376 | // 打开弹出框 |
| 205 | openDialog(type, title) { | 377 | openDialog(type, title) { |
| @@ -207,32 +379,31 @@ export default { | @@ -207,32 +379,31 @@ export default { | ||
| 207 | this.dialogRender = true; | 379 | this.dialogRender = true; |
| 208 | this.dialogType = type; | 380 | this.dialogType = type; |
| 209 | this.dialogTitle = title; | 381 | this.dialogTitle = title; |
| 210 | - this.dialogCloseCallback = undefined; | ||
| 211 | }, | 382 | }, |
| 212 | // 关闭弹出框 | 383 | // 关闭弹出框 |
| 213 | - closeDialog(callback) { | 384 | + closeDialog() { |
| 214 | this.dialogVisible = false; | 385 | this.dialogVisible = false; |
| 215 | - this.dialogCloseCallback = callback instanceof Event ? undefined : callback; | ||
| 216 | }, | 386 | }, |
| 217 | // 清空表单 | 387 | // 清空表单 |
| 218 | clearEditForm() { | 388 | clearEditForm() { |
| 219 | this.editForm = {}; | 389 | this.editForm = {}; |
| 220 | }, | 390 | }, |
| 221 | - // 弹出框关闭 | 391 | + // 弹出框关闭动画结束 |
| 222 | onDialogClosed() { | 392 | onDialogClosed() { |
| 223 | this.clearEditForm(); | 393 | this.clearEditForm(); |
| 224 | this.dialogRender = false; | 394 | this.dialogRender = false; |
| 225 | this.dialogType = 'none'; | 395 | this.dialogType = 'none'; |
| 226 | - this.dialogCloseCallback && this.dialogCloseCallback(); | ||
| 227 | }, | 396 | }, |
| 228 | // 分页-每页个数 | 397 | // 分页-每页个数 |
| 229 | handleSizeChange(val) { | 398 | handleSizeChange(val) { |
| 230 | this.pageSize = val; | 399 | this.pageSize = val; |
| 231 | this.currentPage = 1; | 400 | this.currentPage = 1; |
| 401 | + this.$nextTick(this.search); | ||
| 232 | }, | 402 | }, |
| 233 | // 分页-当前页数 | 403 | // 分页-当前页数 |
| 234 | handleCurrentChange(val) { | 404 | handleCurrentChange(val) { |
| 235 | this.currentPage = val; | 405 | this.currentPage = val; |
| 406 | + this.$nextTick(this.search); | ||
| 236 | }, | 407 | }, |
| 237 | }, | 408 | }, |
| 238 | }; | 409 | }; |