优化(todo): 添加/更新/删除/状态切换加loading+乐观更新,修复Switch类型抛错
CI/CD Deploy (Web) / 构建前端镜像并部署 (push) Successful in 19s
CI/CD Deploy (Web) / 构建前端镜像并部署 (push) Successful in 19s
This commit is contained in:
+102
-36
@@ -27,7 +27,10 @@
|
|||||||
:data="dataList"
|
:data="dataList"
|
||||||
:loading="tableLoading">
|
:loading="tableLoading">
|
||||||
<template slot-scope="{ row }" slot="status">
|
<template slot-scope="{ row }" slot="status">
|
||||||
<i-switch :value="row.status === 1" true-value="1" false-value="0"
|
<!-- value 必须与 true-value/false-value 同类型(都是数字),否则组件内部会抛
|
||||||
|
'Value should be trueValue or falseValue.' 且状态不更新 -->
|
||||||
|
<i-switch :value="row.status" :true-value="1" :false-value="0"
|
||||||
|
:loading="!!rowLoading[row.id]"
|
||||||
@on-change="val => updateStatus(row, val)">
|
@on-change="val => updateStatus(row, val)">
|
||||||
<span slot="open">完成</span>
|
<span slot="open">完成</span>
|
||||||
<span slot="close">未完成</span>
|
<span slot="close">未完成</span>
|
||||||
@@ -49,7 +52,7 @@
|
|||||||
:transfer="true"
|
:transfer="true"
|
||||||
@on-ok="toDelete(index)"
|
@on-ok="toDelete(index)"
|
||||||
>
|
>
|
||||||
<Button type="error" size="small" icon="md-trash">删除</Button>
|
<Button type="error" size="small" icon="md-trash" :loading="!!rowLoading[row.id]">删除</Button>
|
||||||
</Poptip>
|
</Poptip>
|
||||||
</template>
|
</template>
|
||||||
</Table>
|
</Table>
|
||||||
@@ -200,6 +203,7 @@ export default {
|
|||||||
addModal: false, // 添加
|
addModal: false, // 添加
|
||||||
editModal: false, // 编辑
|
editModal: false, // 编辑
|
||||||
submitLoading: false,
|
submitLoading: false,
|
||||||
|
rowLoading: {}, // 行级 loading:{ 待办id: true },用于开关与删除按钮
|
||||||
formItem: {
|
formItem: {
|
||||||
id: '',
|
id: '',
|
||||||
title: '',
|
title: '',
|
||||||
@@ -214,18 +218,27 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getDataList () {
|
/**
|
||||||
|
* 拉取列表
|
||||||
|
* @param {Boolean} silent 静默刷新:不显示表格 loading,用于乐观更新后的后台同步
|
||||||
|
*/
|
||||||
|
getDataList (silent) {
|
||||||
let temp = JSON.parse(JSON.stringify(this.pageParam))
|
let temp = JSON.parse(JSON.stringify(this.pageParam))
|
||||||
let data = objectUtil.trimJoin(temp, this.search)
|
let data = objectUtil.trimJoin(temp, this.search)
|
||||||
this.tableLoading = true
|
if (!silent) {
|
||||||
|
this.tableLoading = true
|
||||||
|
}
|
||||||
|
const closeLoading = () => {
|
||||||
|
this.tableLoading = false
|
||||||
|
}
|
||||||
getDataList(data).then(res => {
|
getDataList(data).then(res => {
|
||||||
let page = res.data.data
|
let page = res.data.data
|
||||||
this.pageTotal = page.total
|
this.pageTotal = page.total
|
||||||
this.dataList = page.records
|
this.dataList = page.records
|
||||||
// 延迟300毫秒,给它更流畅的感觉
|
closeLoading()
|
||||||
setTimeout(() => {
|
}).catch(() => {
|
||||||
this.tableLoading = false
|
// 出错也要复位 loading,否则表格一直转圈
|
||||||
}, 300)
|
closeLoading()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
toAdd () {
|
toAdd () {
|
||||||
@@ -267,53 +280,112 @@ export default {
|
|||||||
let data = Object.assign({}, this.formItem)
|
let data = Object.assign({}, this.formItem)
|
||||||
// DatePicker 绑定的是 Date 对象,后端按 yyyy-MM-dd 字符串接收
|
// DatePicker 绑定的是 Date 对象,后端按 yyyy-MM-dd 字符串接收
|
||||||
data.dueDate = this.formatDate(this.formItem.dueDate)
|
data.dueDate = this.formatDate(this.formItem.dueDate)
|
||||||
if (this.addModal) { // 添加
|
const isAdd = this.addModal
|
||||||
add(data).then(res => {
|
// 按钮转圈:公网穿透链路有延迟,没有反馈会像卡住
|
||||||
this.$Message.success('添加成功!')
|
this.submitLoading = true
|
||||||
this.refresh()
|
const req = isAdd ? add(data) : update(data)
|
||||||
this.getDataList()
|
req.then(res => {
|
||||||
})
|
// 编辑走本地合并,改完立刻看到结果,不等服务端回包
|
||||||
} else { // 编辑
|
if (!isAdd) {
|
||||||
update(data).then(res => {
|
this.mergeRow(data)
|
||||||
this.$Message.success('编辑成功!')
|
}
|
||||||
this.refresh()
|
this.$Message.success(isAdd ? '添加成功!' : '编辑成功!')
|
||||||
this.getDataList()
|
// 请求成功后再关弹窗,避免"点了没反应"
|
||||||
})
|
this.modal = false
|
||||||
}
|
this.resetForm()
|
||||||
this.cancel()
|
this.submitLoading = false
|
||||||
|
// 新增的行 id 由服务端生成,静默拉一次同步(不显示表格 loading)
|
||||||
|
if (isAdd) {
|
||||||
|
this.getDataList(true)
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
this.submitLoading = false
|
||||||
|
this.$Message.error(isAdd ? '添加失败,请重试' : '编辑失败,请重试')
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
/** 把提交的字段合并进当前列表对应行,实现即时更新 **/
|
||||||
|
mergeRow (data) {
|
||||||
|
let row = this.dataList.find(item => String(item.id) === String(data.id))
|
||||||
|
if (!row) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
row.title = data.title
|
||||||
|
row.status = data.status
|
||||||
|
row.priority = data.priority
|
||||||
|
row.dueDate = data.dueDate
|
||||||
|
row.remark = data.remark
|
||||||
|
},
|
||||||
cancel () {
|
cancel () {
|
||||||
// Modal cancel
|
// Modal cancel:只关弹窗并复位表单,不清空搜索条件与分页
|
||||||
this.modal = false
|
this.modal = false
|
||||||
this.refresh()
|
this.resetForm()
|
||||||
|
},
|
||||||
|
/** 复位弹窗表单 **/
|
||||||
|
resetForm () {
|
||||||
|
this.formItem = {
|
||||||
|
id: '',
|
||||||
|
title: '',
|
||||||
|
status: 0,
|
||||||
|
priority: 2,
|
||||||
|
dueDate: '',
|
||||||
|
remark: ''
|
||||||
|
}
|
||||||
|
this.submitLoading = false
|
||||||
},
|
},
|
||||||
toDelete (index) {
|
toDelete (index) {
|
||||||
let temp = this.dataList[index]
|
let temp = this.dataList[index]
|
||||||
let data = {
|
let data = {
|
||||||
id: temp.id
|
id: temp.id
|
||||||
}
|
}
|
||||||
|
// 删除按钮转圈,给即时反馈
|
||||||
|
this.$set(this.rowLoading, temp.id, true)
|
||||||
remove(data).then(res => {
|
remove(data).then(res => {
|
||||||
this.refresh()
|
// 先本地移除,画面立即响应,再静默同步分页数据
|
||||||
this.getDataList()
|
this.dataList.splice(index, 1)
|
||||||
|
this.pageTotal = Math.max(0, this.pageTotal - 1)
|
||||||
|
// 本页删空了就退回上一页,避免停在空页
|
||||||
|
if (this.dataList.length === 0 && this.pageParam.pageNum > 1) {
|
||||||
|
this.pageParam.pageNum -= 1
|
||||||
|
}
|
||||||
|
this.$set(this.rowLoading, temp.id, false)
|
||||||
this.$Message.success('删除成功!')
|
this.$Message.success('删除成功!')
|
||||||
|
this.getDataList(true)
|
||||||
|
}).catch(() => {
|
||||||
|
this.$set(this.rowLoading, temp.id, false)
|
||||||
|
this.$Message.error('删除失败,请重试')
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
updateStatus (row, value) {
|
updateStatus (row, value) {
|
||||||
let status = value === true || value === 1 || value === '1' ? 1 : 0
|
let status = value === true || value === 1 || value === '1' ? 1 : 0
|
||||||
|
if (row.status === status) {
|
||||||
|
return
|
||||||
|
}
|
||||||
let data = {
|
let data = {
|
||||||
id: row.id,
|
id: row.id,
|
||||||
status: status
|
status: status
|
||||||
}
|
}
|
||||||
|
const oldStatus = row.status
|
||||||
|
// 乐观更新:先改本地,开关立刻响应,不等网络
|
||||||
|
row.status = status
|
||||||
|
this.$set(this.rowLoading, row.id, true)
|
||||||
updateStatus(data).then(res => {
|
updateStatus(data).then(res => {
|
||||||
|
this.$set(this.rowLoading, row.id, false)
|
||||||
this.$Message.success(status === 1 ? '已完成!' : '已标记为未完成!')
|
this.$Message.success(status === 1 ? '已完成!' : '已标记为未完成!')
|
||||||
this.getDataList()
|
// 当前按状态筛选且该行已不匹配条件时,静默刷新让它消失
|
||||||
|
if (this.search.status !== '' && Number(this.search.status) !== status) {
|
||||||
|
this.getDataList(true)
|
||||||
|
}
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
this.getDataList()
|
// 失败回滚到原状态
|
||||||
|
this.$set(this.rowLoading, row.id, false)
|
||||||
|
row.status = oldStatus
|
||||||
|
this.$Message.error('状态更新失败,请重试')
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
refresh () {
|
refresh () {
|
||||||
|
// 重置查询条件:回到第一页并重新拉取(原来只清变量不刷列表,点了没变化)
|
||||||
this.pageParam = {
|
this.pageParam = {
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 10
|
pageSize: 10
|
||||||
@@ -323,14 +395,8 @@ export default {
|
|||||||
status: '',
|
status: '',
|
||||||
priority: ''
|
priority: ''
|
||||||
}
|
}
|
||||||
this.formItem = {
|
this.resetForm()
|
||||||
id: '',
|
this.getDataList()
|
||||||
title: '',
|
|
||||||
status: 0,
|
|
||||||
priority: 2,
|
|
||||||
dueDate: '',
|
|
||||||
remark: ''
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
changePage (index) {
|
changePage (index) {
|
||||||
// 需要显示开始数据的index,(因为数据是从0开始的,页码是从1开始的,需要-1)
|
// 需要显示开始数据的index,(因为数据是从0开始的,页码是从1开始的,需要-1)
|
||||||
|
|||||||
Reference in New Issue
Block a user