优化(sys): 用户/角色/部门/权限页提交按钮启用loading,响应成功后关闭动画
CI/CD Deploy (Web) / 构建前端镜像并部署 (push) Successful in 18s

This commit is contained in:
张家训
2026-10-23 10:36:45 +08:00
parent 65c37d3b4a
commit 10660209f2
4 changed files with 715 additions and 714 deletions
+99 -100
View File
@@ -116,58 +116,58 @@
</template>
<script>
import { getTreeList, getTreeSelectList, getDataList, add, update, remove, getExcelTemplate} from '@/api/sys/sys-dept'
import { objectUtil, utils, exportExcel } from "@/common/js/util"
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import { getTreeList, getTreeSelectList, getDataList, add, update, remove } from '@/api/sys/sys-dept'
import { objectUtil } from '@/common/js/util'
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
export default {
name: "sso-dept",
export default {
name: 'sso-dept',
components: {
Treeselect
},
data() {
data () {
return {
fixedHeader: true,// 高度自适应
autoHeight: `${window.innerHeight} ` * 0.58,// 表格高度(随容器可用高度动态修正)
treeHeight: `${window.innerHeight} ` * 0.58,// 左侧树高度,对齐到右侧表格底部
treeLoading: false,//树加载中
fixedHeader: true, // 高度自适应
autoHeight: `${window.innerHeight} ` * 0.58, // 表格高度(随容器可用高度动态修正)
treeHeight: `${window.innerHeight} ` * 0.58, // 左侧树高度,对齐到右侧表格底部
treeLoading: false, // 树加载中
treeList: [],
disabledTreeSelect: false,
treeSelectList: [],
search: {
deptName: '',
parentId:'0'
parentId: '0'
},
listColumns: [
{
title: "#",
title: '#',
type: 'index',
width: 60,
align: 'center',
indexMethod: (row) => {
return (row._index + 1) + ((this.pageParam.pageNum - 1) * this.pageParam.pageSize);
return (row._index + 1) + ((this.pageParam.pageNum - 1) * this.pageParam.pageSize)
}
},
{
title: '部门名称',
key: 'deptName',
width: 300,
width: 300
},
{
title: '部门编码',
key: 'deptCode',
width: 100,
width: 100
},
{
title: '上级部门',
key: 'pDeptName',
width: 300,
width: 300
},
{
title: '部门描述',
key: 'deptDesc',
width: 300,
width: 300
},
{
title: '操作区',
@@ -184,14 +184,14 @@
},
{
title: '部门编码',
key: 'deptCode',
key: 'deptCode'
},
{
title: '部门描述',
key: 'deptDesc'
},
}
],
pDeptList:[], //父级部门列表
pDeptList: [], // 父级部门列表
dataList: [],
tableLoading: false,
pageTotal: 0, // 总页数
@@ -208,12 +208,12 @@
submitLoading: false,
formItem: {
id: '',
parentId: '0' ,
parentId: '0',
deptName: '',
deptCode: '',
level: 0,
deptDesc: '',
sort: 0,
sort: 0
},
ruleCustom: {
parentId: [{
@@ -224,13 +224,13 @@
}],
deptCode: [{
required: true, message: '请输入部门编码', trigger: 'blur'
}],
},
}]
}
}
},
methods: {
// 依据内容区可用高度动态分配:表格自适应,左侧树底部与表格底部严格对齐
calcHeight() {
calcHeight () {
const wrap = this.$el.closest('.content-wrapper')
const option = this.$refs.optionBox
const btn = this.$refs.btnBox
@@ -240,15 +240,15 @@
return
}
const wrapStyle = window.getComputedStyle(wrap)
const avail = wrap.clientHeight
- (parseFloat(wrapStyle.paddingTop) || 0)
- (parseFloat(wrapStyle.paddingBottom) || 0)
const avail = wrap.clientHeight -
(parseFloat(wrapStyle.paddingTop) || 0) -
(parseFloat(wrapStyle.paddingBottom) || 0)
const pageStyle = window.getComputedStyle(page)
const pageMarginTop = parseFloat(pageStyle.marginTop) || 0
const pageMarginBottom = parseFloat(pageStyle.marginBottom) || 0
// 除表格外的固定块:查询区 + 按钮区 + 分页区(含上下外边距)
const fixed = option.offsetHeight + btn.offsetHeight
+ page.offsetHeight + pageMarginTop + pageMarginBottom
const fixed = option.offsetHeight + btn.offsetHeight +
page.offsetHeight + pageMarginTop + pageMarginBottom
this.autoHeight = Math.max(200, avail - fixed)
// 等表格按新高度重排后再量底边,避免拿到上一帧的位置
this.$nextTick(() => {
@@ -261,9 +261,9 @@
})
})
},
getTreeChoose() {
getTreeChoose () {
// 获取选中的节点信息
let choose = this.$refs.tree.getSelectedNodes();
let choose = this.$refs.tree.getSelectedNodes()
if (choose.length > 0) {
this.formItem.parentId = choose[0].id
this.formItem.level = choose[0].level + 1
@@ -272,23 +272,23 @@
} else {
}
},
getTreeList() {
getTreeList () {
getTreeList().then(res => {
this.treeList = res.data.data
})
},
getTreeSelectList() {
getTreeSelectList () {
getTreeSelectList().then(res => {
this.treeSelectList = res.data.data
})
},
getDataList() {
getDataList () {
let temp = JSON.parse(JSON.stringify(this.pageParam))
let data = objectUtil.trimJoin(temp, this.search)
this.tableLoading = true
getDataList(data).then(res => {
let page = res.data.data
if (page != null ){
if (page != null) {
this.pageTotal = page.total
this.dataList = page.records
}
@@ -298,15 +298,15 @@
}, 300)
})
},
toAdd() {
this.modalTitle = "添加"
toAdd () {
this.modalTitle = '添加'
this.modal = true
this.addModal = true
this.editModal = false
},
toEdit(index) {
this.modalTitle = "编辑"
toEdit (index) {
this.modalTitle = '编辑'
let temp = this.dataList[index]
this.addModal = false
@@ -327,37 +327,36 @@
this.formItem.sort = temp.sort
})
},
submit(formItem) {
submit (formItem) {
// modal 提交
this.$refs[formItem].validate((valid) => {
if (valid) {
if (this.addModal) {//添加
add(this.formItem).then(res => {
// 点击即转圈,等请求响应成功后再关闭,同时防重复提交
this.submitLoading = true
const isAdd = this.addModal
const req = isAdd ? add(this.formItem) : update(this.formItem)
req.then(res => {
this.refresh()
this.getTreeSelectList()
this.getTreeList()
this.getDataList()
this.$Message.success("添加成功!")
})
} else {//编辑
update(this.formItem).then(res => {
this.refresh()
this.getTreeSelectList()
this.getTreeList()
this.getDataList()
this.$Message.success("编辑成功!")
})
}
this.$Message.success(isAdd ? '添加成功!' : '编辑成功!')
this.cancel()
this.submitLoading = false
}).catch(() => {
// 失败保持弹窗打开,方便直接重试
this.submitLoading = false
this.$Message.error(isAdd ? '添加失败,请重试' : '编辑失败,请重试')
})
}
})
},
cancel() {
cancel () {
// Modal cancel
this.modal = false;
this.refresh();
this.modal = false
this.refresh()
},
toDelete(index) {
toDelete (index) {
let temp = this.dataList[index]
let data = {
@@ -366,18 +365,18 @@
remove(data).then(res => {
this.refresh()
this.getDataList()
this.$Message.success("删除成功!")
this.$Message.success('删除成功!')
})
},
refresh() {
refresh () {
this.pageParam = {
pageNum: 1,
pageSize: 10
};
}
this.search = {
deptName: '',
parentId:this.search.parentId
};
parentId: this.search.parentId
}
this.formItem = {
id: '',
parentId: '0',
@@ -385,82 +384,82 @@
deptCode: '',
level: 0,
deptDesc: '',
sort: 0,
};
sort: 0
}
},
changePage(index) {
changePage (index) {
// 需要显示开始数据的index,(因为数据是从0开始的,页码是从1开始的,需要-1)
this.pageParam.pageNum = index;
this.getDataList();
this.pageParam.pageNum = index
this.getDataList()
},
changePageSize(page) {
changePageSize (page) {
// 切换分页条数
this.pageParam.pageNum = 1;
this.pageParam.pageSize = page;
this.getDataList();
this.pageParam.pageNum = 1
this.pageParam.pageSize = page
this.getDataList()
},
renderContent(h, { root, node, data }) {
let icon = "";
renderContent (h, { root, node, data }) {
let icon = ''
if (data.level === 0) {
icon = "ios-navigate";
icon = 'ios-navigate'
} else if (data.level === 1) {
icon = "md-planet";
}else if (data.level === 2) {
icon = "ios-paper-plane";
}else if (data.level === 3) {
icon = "md-radio";
}else {
icon = "md-radio-button-off";
icon = 'md-planet'
} else if (data.level === 2) {
icon = 'ios-paper-plane'
} else if (data.level === 3) {
icon = 'md-radio'
} else {
icon = 'md-radio-button-off'
}
return h(
"span",
'span',
{
style: {
display: "inline-block",
cursor: "pointer"
display: 'inline-block',
cursor: 'pointer'
},
on: {
click: () => {
data.checked = !data.checked;
data.checked = !data.checked
}
}
},
[
h("span", [
h("Icon", {
h('span', [
h('Icon', {
props: {
type: icon,
size: "16"
size: '16'
},
style: {
"margin-right": "8px",
"margin-bottom": "3px"
'margin-right': '8px',
'margin-bottom': '3px'
}
}),
h("span", { class: "ivu-tree-title" }, data.title)
h('span', { class: 'ivu-tree-title' }, data.title)
])
]
);
},
)
}
},
created() {
created () {
this.getTreeList()
this.getTreeSelectList()
this.getDataList()
},
mounted() {
mounted () {
this.calcHeight()
window.addEventListener('resize', this.calcHeight)
},
activated() {
activated () {
// keep-alive 缓存组件重新显示时,容器高度可能已变化,需重算
this.calcHeight()
},
beforeDestroy() {
beforeDestroy () {
window.removeEventListener('resize', this.calcHeight)
}
}
}
</script>
<style lang="less" scoped>
+86 -87
View File
@@ -133,24 +133,24 @@
</template>
<script>
import {getTreeList, getTreeSelectList, getDataList, add, update, remove} from '@/api/sys/sys-permission'
import {objectUtil, utils, exportExcel} from "@/common/js/util"
import IconChoose from "@/components/my-components/icon-choose"
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
import { getTreeList, getTreeSelectList, getDataList, add, update, remove } from '@/api/sys/sys-permission'
import { objectUtil } from '@/common/js/util'
import IconChoose from '@/components/my-components/icon-choose'
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
export default {
name: "sso-menu",
export default {
name: 'sso-menu',
components: {
IconChoose,
Treeselect
},
data() {
data () {
return {
fixedHeader: true,// 高度自适应
autoHeight: `${window.innerHeight} ` * 0.58,// 表格高度(随容器可用高度动态修正)
treeHeight: `${window.innerHeight} ` * 0.58,// 左侧树高度,对齐到右侧表格底部
treeLoading: false,//树加载中
fixedHeader: true, // 高度自适应
autoHeight: `${window.innerHeight} ` * 0.58, // 表格高度(随容器可用高度动态修正)
treeHeight: `${window.innerHeight} ` * 0.58, // 左侧树高度,对齐到右侧表格底部
treeLoading: false, // 树加载中
treeList: [],
disabledTreeSelect: false,
treeSelectList: [],
@@ -160,12 +160,12 @@
},
listColumns: [
{
title: "#",
title: '#',
type: 'index',
width: 60,
align: 'center',
indexMethod: (row) => {
return (row._index + 1) + ((this.pageParam.pageNum - 1) * this.pageParam.pageSize);
return (row._index + 1) + ((this.pageParam.pageNum - 1) * this.pageParam.pageSize)
}
},
{
@@ -174,7 +174,7 @@
},
{
title: '菜单编码',
key: 'permissionCode',
key: 'permissionCode'
},
{
title: '上级菜单',
@@ -199,14 +199,14 @@
},
{
title: '菜单编码',
key: 'permissionCode',
key: 'permissionCode'
},
{
title: '菜单描述',
key: 'permissionDesc'
},
}
],
pMenuList: [], //父级菜单列表
pMenuList: [], // 父级菜单列表
dataList: [],
tableLoading: false,
pageTotal: 0, // 总页数
@@ -232,7 +232,7 @@
url: '',
component: '',
status: '1',
sort: 0,
sort: 0
},
ruleCustom: {
parentId: [{
@@ -252,13 +252,13 @@
}],
component: [{
required: true, message: '请输入组件地址', trigger: 'blur'
}],
},
}]
}
}
},
methods: {
// 依据内容区可用高度动态分配:表格自适应,左侧树底部与表格底部严格对齐
calcHeight() {
calcHeight () {
const wrap = this.$el.closest('.content-wrapper')
const option = this.$refs.optionBox
const btn = this.$refs.btnBox
@@ -268,15 +268,15 @@
return
}
const wrapStyle = window.getComputedStyle(wrap)
const avail = wrap.clientHeight
- (parseFloat(wrapStyle.paddingTop) || 0)
- (parseFloat(wrapStyle.paddingBottom) || 0)
const avail = wrap.clientHeight -
(parseFloat(wrapStyle.paddingTop) || 0) -
(parseFloat(wrapStyle.paddingBottom) || 0)
const pageStyle = window.getComputedStyle(page)
const pageMarginTop = parseFloat(pageStyle.marginTop) || 0
const pageMarginBottom = parseFloat(pageStyle.marginBottom) || 0
// 除表格外的固定块:查询区 + 按钮区 + 分页区(含上下外边距)
const fixed = option.offsetHeight + btn.offsetHeight
+ page.offsetHeight + pageMarginTop + pageMarginBottom
const fixed = option.offsetHeight + btn.offsetHeight +
page.offsetHeight + pageMarginTop + pageMarginBottom
this.autoHeight = Math.max(200, avail - fixed)
// 等表格按新高度重排后再量底边,避免拿到上一帧的位置
this.$nextTick(() => {
@@ -289,9 +289,9 @@
})
})
},
getTreeChoose() {
getTreeChoose () {
// 获取选中的节点信息
let choose = this.$refs.tree.getSelectedNodes();
let choose = this.$refs.tree.getSelectedNodes()
if (choose.length > 0) {
this.formItem.parentId = choose[0].id
this.formItem.level = choose[0].level + 1
@@ -299,17 +299,17 @@
this.getDataList()
}
},
getTreeList() {
getTreeList () {
getTreeList().then(res => {
this.treeList = res.data.data
})
},
getTreeSelectList() {
getTreeSelectList () {
getTreeSelectList().then(res => {
this.treeSelectList = res.data.data
})
},
getDataList() {
getDataList () {
let temp = JSON.parse(JSON.stringify(this.pageParam))
let data = objectUtil.trimJoin(temp, this.search)
this.tableLoading = true
@@ -323,13 +323,13 @@
}, 300)
})
},
toAdd() {
toAdd () {
if (this.formItem.level === 3) {
this.$Message.warning("不可以添加子菜单!")
this.$Message.warning('不可以添加子菜单!')
return
}
this.modalTitle = "添加"
this.modalTitle = '添加'
this.addModal = true
this.editModal = false
this.modal = true
@@ -340,8 +340,8 @@
}
})
},
toEdit(index) {
this.modalTitle = "编辑"
toEdit (index) {
this.modalTitle = '编辑'
let temp = this.dataList[index]
this.addModal = false
@@ -365,37 +365,36 @@
this.formItem.sort = temp.sort
})
},
submit(formItem) {
submit (formItem) {
// modal 提交
this.$refs[formItem].validate((valid) => {
if (valid) {
if (this.addModal) {//添加
add(this.formItem).then(res => {
// 点击即转圈,等请求响应成功后再关闭,同时防重复提交
this.submitLoading = true
const isAdd = this.addModal
const req = isAdd ? add(this.formItem) : update(this.formItem)
req.then(res => {
this.refresh()
this.getTreeSelectList()
this.getTreeList()
this.getDataList()
this.$Message.success("添加成功!")
})
} else {//编辑
update(this.formItem).then(res => {
this.refresh()
this.getTreeSelectList()
this.getTreeList()
this.getDataList()
this.$Message.success("编辑成功!")
})
}
this.$Message.success(isAdd ? '添加成功!' : '编辑成功!')
this.cancel()
this.submitLoading = false
}).catch(() => {
// 失败保持弹窗打开,方便直接重试
this.submitLoading = false
this.$Message.error(isAdd ? '添加失败,请重试' : '编辑失败,请重试')
})
}
})
},
cancel() {
cancel () {
// Modal cancel
this.modal = false;
this.refresh();
this.modal = false
this.refresh()
},
toDelete(index) {
toDelete (index) {
let temp = this.dataList[index]
let data = {
@@ -406,18 +405,18 @@
this.getTreeSelectList()
this.getTreeList()
this.getDataList()
this.$Message.success("删除成功!")
this.$Message.success('删除成功!')
})
},
refresh() {
refresh () {
this.pageParam = {
pageNum: 1,
pageSize: 10
};
}
this.search = {
permissionName: '',
parentId: this.search.parentId
};
}
this.formItem = {
id: '',
parentId: '0',
@@ -428,70 +427,70 @@
permissionDesc: '',
url: '',
component: '',
sort: 0,
};
sort: 0
}
},
changePage(index) {
changePage (index) {
// 需要显示开始数据的index,(因为数据是从0开始的,页码是从1开始的,需要-1)
this.pageParam.pageNum = index;
this.getDataList();
this.pageParam.pageNum = index
this.getDataList()
},
changePageSize(page) {
changePageSize (page) {
// 切换分页条数
this.pageParam.pageNum = 1;
this.pageParam.pageSize = page;
this.getDataList();
this.pageParam.pageNum = 1
this.pageParam.pageSize = page
this.getDataList()
},
renderContent(h, {root, node, data}) {
let icon = data.icon;
renderContent (h, { root, node, data }) {
let icon = data.icon
return h(
"span",
'span',
{
style: {
display: "inline-block",
cursor: "pointer"
display: 'inline-block',
cursor: 'pointer'
},
on: {
click: () => {
data.checked = !data.checked;
data.checked = !data.checked
}
}
},
[
h("span", [
h("Icon", {
h('span', [
h('Icon', {
props: {
type: icon,
size: "16"
size: '16'
},
style: {
"margin-right": "8px",
"margin-bottom": "3px"
'margin-right': '8px',
'margin-bottom': '3px'
}
}),
h("span", {class: "ivu-tree-title"}, data.title)
h('span', { class: 'ivu-tree-title' }, data.title)
])
]
);
)
}
},
},
created() {
created () {
this.getTreeList()
this.getTreeSelectList()
this.getDataList()
},
mounted() {
mounted () {
this.calcHeight()
window.addEventListener('resize', this.calcHeight)
},
activated() {
activated () {
// keep-alive 缓存组件重新显示时,容器高度可能已变化,需重算
this.calcHeight()
},
beforeDestroy() {
beforeDestroy () {
window.removeEventListener('resize', this.calcHeight)
}
}
}
</script>
<style lang="less" scoped>
+15 -14
View File
@@ -142,7 +142,7 @@
import { getTreeListByRoleId } from '@/api/sys/sys-permission'
import { getDataList, add, update, remove, addRolePermission } from '@/api/sys/sys-role'
import { getTreeSelectList } from '@/api/sys/sys-dept'
import { objectUtil, utils, exportExcel } from '@/common/js/util'
import { objectUtil } from '@/common/js/util'
import Treeselect from '@riophae/vue-treeselect'
import '@riophae/vue-treeselect/dist/vue-treeselect.css'
@@ -313,20 +313,21 @@ export default {
// modal 提交
this.$refs[formItem].validate((valid) => {
if (valid) {
if (this.addModal) { // 添加
add(this.formItem).then(res => {
// 点击即转圈,等请求响应成功后再关闭,避免无反馈像卡住,同时防重复提交
this.submitLoading = true
const isAdd = this.addModal
const req = isAdd ? add(this.formItem) : update(this.formItem)
req.then(res => {
this.refresh()
this.getDataList()
this.$Message.success('添加成功!')
})
} else { // 编辑
update(this.formItem).then(res => {
this.refresh()
this.getDataList()
this.$Message.success('编辑成功!')
})
}
this.$Message.success(isAdd ? '添加成功!' : '编辑成功!')
this.cancel()
this.submitLoading = false
}).catch(() => {
// 失败保持弹窗打开,方便直接重试
this.submitLoading = false
this.$Message.error(isAdd ? '添加失败,请重试' : '编辑失败,请重试')
})
}
})
},
@@ -404,7 +405,7 @@ export default {
this.treeList = res.data.data
})
},
renderContent (h, {root, node, data}) {
renderContent (h, { root, node, data }) {
// 初始化树的icon
let icon = data.icon
return h(
@@ -432,7 +433,7 @@ export default {
'margin-bottom': '3px'
}
}),
h('span', {class: 'ivu-tree-title'}, data.title)
h('span', { class: 'ivu-tree-title' }, data.title)
])
]
)
+12 -10
View File
@@ -372,18 +372,20 @@ export default {
userRoleStr: JSON.stringify(userAndRoleArr).toString()
})
if (this.addModal) { // 添加
add(data).then(res => {
// 点击即转圈,等请求响应成功后再关闭,同时防重复提交
this.submitLoading = true
const isAdd = this.addModal
const req = isAdd ? add(data) : update(data)
req.then(res => {
this.getDataList()
this.$Message.success('添加成功!')
})
} else { // 编辑
update(data).then(res => {
this.getDataList()
this.$Message.success('编辑成功!')
})
}
this.$Message.success(isAdd ? '添加成功!' : '编辑成功!')
this.cancel()
this.submitLoading = false
}).catch(() => {
// 失败保持弹窗打开,方便直接重试
this.submitLoading = false
this.$Message.error(isAdd ? '添加失败,请重试' : '编辑失败,请重试')
})
}
})
},