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 | 13 | display: flex; |
| 14 | 14 | flex-wrap: wrap; |
| 15 | 15 | align-items: center; |
| 16 | - line-height: 1; | |
| 17 | 16 | justify-content: flex-start; |
| 17 | + line-height: 1; | |
| 18 | 18 | .el-button + .el-button { |
| 19 | 19 | margin-left: 0; |
| 20 | 20 | } |
| ... | ... | @@ -23,6 +23,20 @@ |
| 23 | 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 | 40 | &__dialog-button { |
| 27 | 41 | display: flex; |
| 28 | 42 | align-items: center; |
| ... | ... | @@ -32,6 +46,27 @@ |
| 32 | 46 | &__footer { |
| 33 | 47 | margin-top: 10px; |
| 34 | 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 | 72 | </style> |
| ... | ... | @@ -42,7 +77,7 @@ |
| 42 | 77 | <slot name="header" :filterModel="filterModel" v-bind="_slotScope"></slot> |
| 43 | 78 | </div> |
| 44 | 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 | 81 | </div> |
| 47 | 82 | <div v-if="action" class="zee-scheme__action"> |
| 48 | 83 | <slot v-if="hadSlot('action')" name="action" v-bind="_slotScope"></slot> |
| ... | ... | @@ -52,17 +87,38 @@ |
| 52 | 87 | </template> |
| 53 | 88 | </div> |
| 54 | 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 | 101 | <template #column-end> |
| 57 | 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 | 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 | 109 | </el-table-column> |
| 62 | 110 | </template> |
| 63 | 111 | </z-table> |
| 64 | 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 | 122 | <el-pagination |
| 67 | 123 | @size-change="handleSizeChange" |
| 68 | 124 | @current-change="handleCurrentChange" |
| ... | ... | @@ -74,14 +130,14 @@ |
| 74 | 130 | > |
| 75 | 131 | </el-pagination> |
| 76 | 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 | 134 | <div v-loading="dialogLoading"> |
| 79 | 135 | <slot v-if="hadSlot('dialog-title')" slot="title" name="dialog-title" :dialogType="dialogType" v-bind="_slotScope"></slot> |
| 80 | 136 | <template v-if="dialogRender"> |
| 81 | 137 | <slot v-if="hadSlot(`dialog-${dialogType}`)" :name="`dialog-${dialogType}`" :model="_formModel" v-bind="_slotScope"></slot> |
| 82 | 138 | <z-form v-else ref="form" :value="_formModel" :list="list" label-width="80px" :span="12" @input="onFormInput" @validate="onFormValidate"></z-form> |
| 83 | 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 | 141 | <el-button :size="size" plain @click="closeDialog">取消</el-button> |
| 86 | 142 | </div> |
| 87 | 143 | </template> |
| ... | ... | @@ -105,12 +161,26 @@ export default { |
| 105 | 161 | type: Boolean, |
| 106 | 162 | default: true, |
| 107 | 163 | }, |
| 164 | + pagination: { | |
| 165 | + type: Boolean, | |
| 166 | + default: true, | |
| 167 | + }, | |
| 108 | 168 | size: { |
| 109 | 169 | type: String, |
| 110 | 170 | default: 'mini', |
| 111 | 171 | }, |
| 172 | + tableProps: { | |
| 173 | + type: Object, | |
| 174 | + default: () => ({}), | |
| 175 | + }, | |
| 112 | 176 | formModel: Object, |
| 113 | 177 | filterModel: Object, |
| 178 | + auto: Boolean, | |
| 179 | + realSelection: Boolean, | |
| 180 | + searchAPI: Function, | |
| 181 | + submitAPI: Function, | |
| 182 | + getAPI: Function, | |
| 183 | + deleteAPI: Function, | |
| 114 | 184 | }, |
| 115 | 185 | data() { |
| 116 | 186 | return { |
| ... | ... | @@ -121,17 +191,23 @@ export default { |
| 121 | 191 | dialogType: 'none', |
| 122 | 192 | dialogLoading: false, |
| 123 | 193 | dialogTitle: '', |
| 124 | - dialogCloseCallback: undefined, | |
| 125 | 194 | currentPage: 1, |
| 126 | - pageSize: 10, | |
| 195 | + // pageSize: 10, | |
| 196 | + pageSize: 5, | |
| 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 | 211 | filters: { |
| 136 | 212 | noRulesFilter(val = []) { |
| 137 | 213 | let list = cloneDeep(val); |
| ... | ... | @@ -163,17 +239,95 @@ export default { |
| 163 | 239 | }, |
| 164 | 240 | }, |
| 165 | 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 | 309 | onFilterInput(val) { |
| 167 | 310 | this.filterForm = val || {}; |
| 168 | 311 | this.$emit('update:filterModel', val || {}); |
| 169 | 312 | }, |
| 313 | + // 更新表单model | |
| 170 | 314 | onFormInput(val) { |
| 171 | 315 | this.editForm = val || {}; |
| 172 | 316 | this.$emit('update:formModel', val || {}); |
| 173 | 317 | }, |
| 174 | - onFormValidate(valid, model) { | |
| 318 | + // 表单提交且通过校验 | |
| 319 | + async onFormValidate(valid, model) { | |
| 175 | 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 | 347 | this.openDialog('new', '新增'); |
| 194 | 348 | }, |
| 195 | 349 | // 打开编辑弹出框 |
| 196 | - openEdit({ row }) { | |
| 350 | + async openEdit({ row }) { | |
| 197 | 351 | this.dialogLoading = true; |
| 198 | - setTimeout(() => { | |
| 199 | - this.editForm = { ...row }; | |
| 200 | - this.dialogLoading = false; | |
| 201 | - }, 300); | |
| 202 | 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 | 377 | openDialog(type, title) { |
| ... | ... | @@ -207,32 +379,31 @@ export default { |
| 207 | 379 | this.dialogRender = true; |
| 208 | 380 | this.dialogType = type; |
| 209 | 381 | this.dialogTitle = title; |
| 210 | - this.dialogCloseCallback = undefined; | |
| 211 | 382 | }, |
| 212 | 383 | // 关闭弹出框 |
| 213 | - closeDialog(callback) { | |
| 384 | + closeDialog() { | |
| 214 | 385 | this.dialogVisible = false; |
| 215 | - this.dialogCloseCallback = callback instanceof Event ? undefined : callback; | |
| 216 | 386 | }, |
| 217 | 387 | // 清空表单 |
| 218 | 388 | clearEditForm() { |
| 219 | 389 | this.editForm = {}; |
| 220 | 390 | }, |
| 221 | - // 弹出框关闭 | |
| 391 | + // 弹出框关闭动画结束 | |
| 222 | 392 | onDialogClosed() { |
| 223 | 393 | this.clearEditForm(); |
| 224 | 394 | this.dialogRender = false; |
| 225 | 395 | this.dialogType = 'none'; |
| 226 | - this.dialogCloseCallback && this.dialogCloseCallback(); | |
| 227 | 396 | }, |
| 228 | 397 | // 分页-每页个数 |
| 229 | 398 | handleSizeChange(val) { |
| 230 | 399 | this.pageSize = val; |
| 231 | 400 | this.currentPage = 1; |
| 401 | + this.$nextTick(this.search); | |
| 232 | 402 | }, |
| 233 | 403 | // 分页-当前页数 |
| 234 | 404 | handleCurrentChange(val) { |
| 235 | 405 | this.currentPage = val; |
| 406 | + this.$nextTick(this.search); | |
| 236 | 407 | }, |
| 237 | 408 | }, |
| 238 | 409 | }; | ... | ... |