数据权限

szh-new
sunzehua 3 months ago
parent 58a26e0570
commit 369a6809a7

@ -1,8 +1,22 @@
<template> <template>
<BasicModal v-bind="$attrs" :use-wrapper="true" :title="getTitle" :width="670" @register="registerModal" <BasicModal v-bind="$attrs" :use-wrapper="true" :title="getTitle" :width="900" @register="registerModal"
@ok="handleSave"> @ok="handleSave">
<!-- 费用模版表单 --> <!-- 费用模版表单 -->
<BasicForm @register="registerForm" @linkageForm="ChangeColumnView" /> <BasicForm @register="registerForm" @linkageForm="ChangeColumnView" />
<div style="font-weight: bold;font-size: 12px;">权限规则</div>
<div style="margin-bottom: 10px" >
<a-button type="link" @click="copy('{loginUser}')"><i class="icon-fuzhi3 iconfont"></i>本人</a-button>
<a-button type="link" @click="copy('{loginDept}')"><i class="icon-fuzhi3 iconfont"></i>本部门</a-button>
<a-button type="link" @click="copy('{loginOrg}')"><i class="icon-fuzhi3 iconfont"></i>本公司</a-button>
<a-select v-model:value="orgListValue" @change="handleCopySelect" size="small" mode="multiple" style="width: 250px">
<a-select-option v-for="(item, index) in orgList" :value="item.value" :key="index">{{ item.label
}}</a-select-option>
</a-select>
<a-select v-model:value="userListValue" @change="handleCopySelectUser" size="small" mode="multiple" style="width: 250px;margin-left: 20px">
<a-select-option v-for="(item, index) in userList" :value="item.value" :key="index">{{ item.label
}}</a-select-option>
</a-select>
</div>
<!-- 费用字段表格 --> <!-- 费用字段表格 -->
<columnView ref="RefcolumnView" title="" :IsApi="true" :schemas="ColumnViewschemas" v-show="columnViewType"> <columnView ref="RefcolumnView" title="" :IsApi="true" :schemas="ColumnViewschemas" v-show="columnViewType">
</columnView> </columnView>
@ -29,6 +43,9 @@ import { BasicModal, useModalInner } from '/@/components/Modal'
import { BasicForm, useForm } from '/@/components/Form/index' import { BasicForm, useForm } from '/@/components/Form/index'
import { getDictOption } from '/@/utils/dictUtil' import { getDictOption } from '/@/utils/dictUtil'
import { getColumns, getClientPermissionList } from '/@/api/system/role' import { getColumns, getClientPermissionList } from '/@/api/system/role'
import {
getOrgList,GetUserList
} from '/@/api/common'
import columnView from './columnView.vue' import columnView from './columnView.vue'
// //
// import { formSchema } from './columns' // import { formSchema } from './columns'
@ -38,6 +55,8 @@ import { ApiEdit, ApiInfo } from './api'
import { useMessage } from '/@/hooks/web/useMessage' import { useMessage } from '/@/hooks/web/useMessage'
import { getTablesByClient } from '/@/views/baseinfo/formcopy/api' import { getTablesByClient } from '/@/views/baseinfo/formcopy/api'
const columnViewData: any = ref([]) const columnViewData: any = ref([])
const orgList = ref([]) as any
const userList = ref([]) as any
onMounted(() => { onMounted(() => {
getTablesByClient().then(res => { getTablesByClient().then(res => {
if (res.succeeded) { if (res.succeeded) {
@ -50,12 +69,28 @@ onMounted(() => {
}) })
} }
}) })
getOrgList().then(res => {
orgList.value = res.data
})
GetUserList().then(res => {
userList.value = res.data
})
}) })
const userListValue = ref([])
const orgListValue = ref([])
const props = defineProps({ const props = defineProps({
customerName: { type: String }, customerName: { type: String },
customerId: { type: String }, customerId: { type: String },
}) })
function copy(text) {
var cInput = document.createElement('input');
cInput.value = text;
document.body.appendChild(cInput);
cInput.select(); //
document.execCommand('copy');
document.body.removeChild(cInput);
createMessage.success('复制成功')
}
const formSchema = [ const formSchema = [
{ {
label: '主键Id', label: '主键Id',
@ -191,7 +226,7 @@ const formSchema = [
label: '可视/可操作', label: '可视/可操作',
component: 'Switch', component: 'Switch',
colProps: { span: 6 }, colProps: { span: 6 },
defaultValue: false, defaultValue: 'visible',
componentProps: { componentProps: {
checkedChildren: '可视', checkedChildren: '可视',
checkedValue: 'visible', checkedValue: 'visible',
@ -206,10 +241,10 @@ const formSchema = [
colProps: { span: 6 }, colProps: { span: 6 },
defaultValue: 0, defaultValue: 0,
componentProps: { componentProps: {
checkedChildren: '用', checkedChildren: '用',
checkedValue: 1, checkedValue: 0,
unCheckedChildren: '用', unCheckedChildren: '用',
unCheckedValue: 0, unCheckedValue: 1,
}, },
}, },
{ {
@ -223,6 +258,24 @@ const formSchema = [
}, },
] ]
function handleCopySelect(val) {
val = val.join(',')
var cInput = document.createElement('input');
cInput.value = val;
document.body.appendChild(cInput);
cInput.select(); //
document.execCommand('copy');
document.body.removeChild(cInput);
}
function handleCopySelectUser(val) {
val = val.join(',')
var cInput = document.createElement('input');
cInput.value = val;
document.body.appendChild(cInput);
cInput.select(); //
document.execCommand('copy');
document.body.removeChild(cInput);
}
// Emits // Emits
const emit = defineEmits(['success', 'register']) const emit = defineEmits(['success', 'register'])
const isUpdate = ref(true) const isUpdate = ref(true)
@ -259,6 +312,8 @@ const [registerModal, { setModalProps, closeModal, updateFormField }] = useModal
if (unref(isUpdate)) { if (unref(isUpdate)) {
setModalProps({ confirmLoading: true }) setModalProps({ confirmLoading: true })
rowId.value = data.record.id rowId.value = data.record.id
orgListValue.value = []
userListValue.value = []
const res: API.DataResult = await ApiInfo({ id: unref(rowId) }) const res: API.DataResult = await ApiInfo({ id: unref(rowId) })
if (res.succeeded) { if (res.succeeded) {
setFieldsValue({ setFieldsValue({
@ -312,6 +367,9 @@ async function handleSave(exit) {
setModalProps({ confirmLoading: false, loading: false }) setModalProps({ confirmLoading: false, loading: false })
} }
} }
</script> </script>
<style scoped lang="less">
/deep/ .ant-form-small {
margin-top: 0px !important;
}
</style>

@ -59,3 +59,10 @@ export function DeleteDetails(data: PageRequest) {
data data
}) })
} }
export function BatchCopyDataRuleTemplate(data: PageRequest) {
return request<DataResult>({
url: '/mainApi/CodeDataRuleTemplate/BatchCopyDataRuleTemplate',
method: 'post',
data
})
}

@ -42,11 +42,12 @@ export const columns: BasicColumn[] = [
{ {
title: '排序号', title: '排序号',
dataIndex: 'orderNo', dataIndex: 'orderNo',
// width: 200, width: 50,
}, },
{ {
title: '可视/可操作', title: '可视/可操作',
dataIndex: 'ruleType', dataIndex: 'ruleType',
width: 120,
customRender: ({ text }) => { customRender: ({ text }) => {
if (text === 'visible') { if (text === 'visible') {
return '可视' return '可视'

@ -17,7 +17,7 @@
<template #title> <template #title>
<span>复制</span> <span>复制</span>
</template> </template>
<a-button v-repeat type="link" @click="handleCreate"> <a-button v-repeat type="link" @click="handleCopy">
<img src="../../../assets/svg/infoclient/fuzhi.svg" class="SvgImg" /> <img src="../../../assets/svg/infoclient/fuzhi.svg" class="SvgImg" />
</a-button> </a-button>
</a-tooltip> </a-tooltip>
@ -26,12 +26,7 @@
<span>删除</span> <span>删除</span>
</template> </template>
<span class="ds-action-svg-btn"> <span class="ds-action-svg-btn">
<a-popconfirm <a-popconfirm title="确定删除当前选中数据?" ok-text="" cancel-text="" @confirm="handleDelete">
title="确定删除当前选中数据?"
ok-text="是"
cancel-text="否"
@confirm="handleDelete"
>
<a-button v-repeat type="link"> <a-button v-repeat type="link">
<img src="../../../assets/svg/infoclient/shanchu.svg" class="SvgImg" /> <img src="../../../assets/svg/infoclient/shanchu.svg" class="SvgImg" />
</a-button> </a-button>
@ -57,15 +52,13 @@
</template> </template>
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.key === 'action'"> <template v-if="column.key === 'action'">
<TableAction <TableAction :actions="[
:actions="[
{ {
icon: 'clarity:note-edit-line', icon: 'clarity:note-edit-line',
tooltip: '编辑', tooltip: '编辑',
onClick: handleAudit.bind(null, record), onClick: handleAudit.bind(null, record),
}, },
]" ]" />
/>
</template> </template>
</template> </template>
</BasicTable> </BasicTable>
@ -73,17 +66,17 @@
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { defineComponent, onMounted, ref } from 'vue' import { defineComponent, onMounted, ref } from 'vue'
import { BasicTable, useTable, TableAction, SorterResult } from '/@/components/Table' import { BasicTable, useTable, TableAction, SorterResult } from '/@/components/Table'
import { ApiList, ApiDel } from './api' import { ApiList, ApiDel, BatchCopyDataRuleTemplate } from './api'
import { useModal } from '/@/components/Modal' import { useModal } from '/@/components/Modal'
import TenantAuditStepModal from './TenantAuditStepModal.vue' import TenantAuditStepModal from './TenantAuditStepModal.vue'
import { columns, searchFormSchema } from './columns' import { columns, searchFormSchema } from './columns'
import { formatParams } from '/@/hooks/web/common' import { formatParams } from '/@/hooks/web/common'
import { useMessage } from '/@/hooks/web/useMessage' import { useMessage } from '/@/hooks/web/useMessage'
const { notification } = useMessage() const { notification } = useMessage()
const [registerModal, { openModal }] = useModal() const [registerModal, { openModal }] = useModal()
const [registerTable, { reload, getSelectRows, getForm, getPaginationRef }] = useTable({ const [registerTable, { reload, getSelectRows, getForm, getPaginationRef }] = useTable({
title: '', title: '',
api: async (p) => { api: async (p) => {
const res: API.DataResult = await ApiList(p) const res: API.DataResult = await ApiList(p)
@ -120,20 +113,36 @@
}, },
// rowSelection: { type: 'checkbox' }, // rowSelection: { type: 'checkbox' },
// clickToRowSelect: false, // clickToRowSelect: false,
}) })
function handleCreate() { function handleCreate() {
openModal(true, { openModal(true, {
isUpdate: false, isUpdate: false,
}) })
} }
function handleAudit(record: Recordable) { function handleAudit(record: Recordable) {
openModal(true, { openModal(true, {
record, record,
isUpdate: true, isUpdate: true,
}) })
}
function handleCopy() {
let ids = []
ids = getSelectRows().map((item) => {
return item.id
})
if (ids.length == 0) {
notification.error('请选择要复制的数据')
return false
} }
// BatchCopyDataRuleTemplate({ids:ids}).then(res=>{
async function handleDelete(record: Recordable) { if(res.succeeded){
notification.success('复制成功')
reload()
}
})
}
//
async function handleDelete(record: Recordable) {
const select = getSelectRows() const select = getSelectRows()
let ApiData: any = { let ApiData: any = {
ids: [], ids: [],
@ -162,14 +171,15 @@
// } else { // } else {
// notification.error({ message: res.message, duration: 3 }) // notification.error({ message: res.message, duration: 3 })
// } // }
} }
function handleSuccess() { function handleSuccess() {
reload() reload()
} }
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.ds-table-detail { .ds-table-detail {
margin-top: -16px; margin-top: -16px;
.title { .title {
font-size: 12px; font-size: 12px;
font-weight: 700; font-weight: 700;
@ -178,15 +188,17 @@
color: rgba(51, 56, 61, 1); color: rgba(51, 56, 61, 1);
text-align: left; text-align: left;
} }
} }
.SvgImg {
.SvgImg {
width: 16px; width: 16px;
} }
.tableTitleBox {
.tableTitleBox {
.ant-btn-link { .ant-btn-link {
border-radius: 2px; border-radius: 2px;
color: #000; color: #000;
font-size: 16px; font-size: 16px;
} }
} }
</style> </style>

@ -25,3 +25,45 @@ export function GetCodeDataRuleList(params) {
data: params data: params
}) })
} }
export function AssignDataRuleScope(params) {
return request<DataResult>({
url: '/mainApi/CodeDataRule/AssignDataRuleScope',
method: 'post',
data: params
})
}
export function GetDataRuleTemplateSelectList(params) {
return request<DataResult>({
url: '/mainApi/CodeDataRuleTemplate/GetDataRuleTemplateSelectList',
method: 'post',
params: params
})
}
export function CopyDataRuleScope(params) {
return request<DataResult>({
url: '/mainApi/CodeDataRule/CopyDataRuleScope',
method: 'post',
data: params
})
}
export function UserVisibleDataRuleScopeApply(params) {
return request<DataResult>({
url: '/mainApi/CodeDataRule/UserVisibleDataRuleScopeApply',
method: 'post',
data: params
})
}
export function UserOperateDataRuleScopeApply(params) {
return request<DataResult>({
url: '/mainApi/CodeDataRule/UserOperateDataRuleScopeApply',
method: 'post',
data: params
})
}

@ -1,22 +1,12 @@
<template> <template>
<div class="main"> <div class="main">
<div class="top"> <div class="top">
<a-tooltip placement="top" :mouseEnterDelay="0.5"> <a-button type="link" @click="openRule"><i class="icon-fuzhi3 iconfont"></i>复制设置并应用</a-button>
<template #title>
<span>新建</span>
</template>
<span class="ds-action-svg-btn">
<a-button @click="GoDetailed(false)" v-repeat type="link">
<img src="../../../assets/svg/infoclient/baocun.svg" class="SvgImg" />
</a-button>
</span>
</a-tooltip>
<a-button>复制设置并应用</a-button>
</div> </div>
<div class="tree-box"> <div class="tree-box">
<div class="tree-item"> <div class="tree-item border-left">
<div class="title">用户</div> <div class="title">用户</div>
<BasicTree ref="treeRef" check-strictly :tree-data="treeData" @select="handleSelect"> <BasicTree ref="treeRef" check-strictly :treeData="treeData" @select="handleSelect">
<template #title="custom"> <template #title="custom">
<span>{{ custom.node.title }}</span> <span>{{ custom.node.title }}</span>
</template> </template>
@ -24,52 +14,267 @@
</div> </div>
<div class="tree-item"> <div class="tree-item">
<div class="title">用户权限配置</div> <div class="title">用户权限配置</div>
<BasicTree ref="menuTreeRef" check-strictly :tree-data="menuTree" @select="handleSelectMenu"> <a-spin :spinning="menuLoad">
<BasicTree ref="menuTreeRef" check-strictly :treeData="menuTree" @select="handleSelectMenu">
<template #title="custom"> <template #title="custom">
<span>{{ custom.node.name }}</span> <span>{{ custom.node.name }}</span>
</template> </template>
</BasicTree> </BasicTree>
</a-spin>
</div> </div>
<div class="table-item">
<BasicTable class="ds-table-detail" @register="registerTable">
<template #tableTitle>
<span style="font-size: 12px;font-weight: bold;color: black">数据权限列表</span>
<a-button type="link" @click="setLook(1)"><i class="icon-yulan1 iconfont"></i>应用可视范围</a-button>
<a-button type="link" @click="setLook(2)"><i class="icon-shichuang-duoge iconfont"></i>应用操作范围到当前页</a-button>
</template>
<template v-slot:bodyCell="{ column, record }">
<template v-if="column.key === 'visibleRuleScopeName'">
<a-select @change="handleChangeLook($event, record)" v-model:value="record.visibleTemplateId" size="small"
style="width: 100%">
<a-select-option v-for="(item, index) in lookSelect" :key="index" :value="item.id">{{ item.ruleScopeName
}}</a-select-option>
</a-select>
</template>
<template v-if="column.key === 'operateRuleScopeName'">
<a-select @change="handleChangeLook($event, record)" v-model:value="record.operateTemplateId" size="small"
style="width: 100%">
<a-select-option v-for="(item, index) in actionSelect" :key="index" :value="item.id">{{
item.ruleScopeName }}</a-select-option>
</a-select>
</template>
</template>
</BasicTable>
</div> </div>
</div> </div>
<a-modal @ok="handleCopy" width="800px" @cancel="openFlag = false" :visible="openFlag" title="选择用户复制">
<a-spin :spinning="copyLoad" >
<BasicTree key="value" v-model:checkedKeys="checkedKeys" checkable check-strictly :treeData="treeDataCopy">
<template #title="custom">
<span>{{ custom.node.title }}</span>
</template>
</BasicTree>
</a-spin>
</a-modal>
</div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { defineComponent, onMounted, ref } from 'vue' import { defineComponent, onMounted, ref } from 'vue'
import { BasicTable, useTable, TableAction } from '/@/components/Table' import { BasicTable, useTable, TableAction } from '/@/components/Table'
import { getDataRuleList } from '/@/api/system/datarule' import { getDataRuleList } from '/@/api/system/datarule'
import { useModal } from '/@/components/Modal' import { useModal } from '/@/components/Modal'
import { GetOrgUserTree, GetClientUserPermissions,GetCodeDataRuleList } from './api' import {
GetOrgUserTree, GetClientUserPermissions, GetCodeDataRuleList, UserVisibleDataRuleScopeApply,
GetDataRuleTemplateSelectList, AssignDataRuleScope, CopyDataRuleScope, UserOperateDataRuleScopeApply
} from './api'
import { BasicTree } from '/@/components/Tree/index' import { BasicTree } from '/@/components/Tree/index'
import { useMessage } from '../../../hooks/web/useMessage'
const { createMessage } = useMessage()
// import { columns, searchFormSchema } from './columns' // import { columns, searchFormSchema } from './columns'
const treeData = ref([]) const treeData = ref([])
const treeDataCopy = ref([])
const menuTree = ref([]) const menuTree = ref([])
const openFlag = ref(false)
onMounted(() => { onMounted(() => {
GetOrgUserTree().then(res => { GetOrgUserTree().then(res => {
treeData.value = res.data treeData.value = res.data
treeDataCopy.value = JSON.parse(JSON.stringify(res.data))
treeData.value.forEach(item => { treeData.value.forEach(item => {
processNode(item); processNode(item);
}); });
treeDataCopy.value.forEach(item => {
item.disabled = true
processNodeCheck(item);
});
})
setProps({
rowSelection: {
onChange: onSelectChange
}
}) })
}) })
const menuLoad = ref(false)
const userId = ref('') const userId = ref('')
const copyLoad = ref(false)
function onSelectChange() {
}
const checkedKeys = ref([]) as any
function handleCopy() {
if (!checkedKeys.value.checked || checkedKeys.value.checked.length == 0) {
createMessage.warning('请选择要复制的用户')
return false
}
if (!userId.value) {
createMessage.warning('请选择要被复制的用户')
return false
}
const data = {
userId: userId.value,
copyUserIds: checkedKeys.value.checked
}
copyLoad.value = true
CopyDataRuleScope(data).then(res => {
if(res.succeeded){
createMessage.success('复制成功')
}
copyLoad.value = false
}).catch(err => {
copyLoad.value = false
})
}
function setLook(type) {
if (!userId.value) {
createMessage.warning('请选择用户')
return false
}
if (getSelectRows().length == 0) {
createMessage.warning('请选择要应用的数据')
return false
}
if (getSelectRows().length > 1) {
createMessage.warning('只能选择一条')
return false
}
const data = {
userId: userId.value,
ruleId: getSelectRows()[0].id
}
setLoading(true)
if (type == 1) {
UserVisibleDataRuleScopeApply(data).then(res => {
if (res.succeeded) {
createMessage.success('应用成功')
}
setLoading(false)
}).catch(err => {
setLoading(false)
})
} else {
UserOperateDataRuleScopeApply(data).then(res => {
if (res.succeeded) {
createMessage.success('应用成功')
}
setLoading(false)
}).catch(err => {
setLoading(false)
})
}
}
function handleSelect(selectedKeys: any, info: any) { function handleSelect(selectedKeys: any, info: any) {
if (info.node.id) { if (info.node.id) {
userId.value = info.node.value userId.value = info.node.value
menuLoad.value = true
GetClientUserPermissions({ id: info.node.value }).then(res => { GetClientUserPermissions({ id: info.node.value }).then(res => {
menuTree.value = res.data menuTree.value = res.data
menuLoad.value = false
}).catch(err => {
menuLoad.value = false
}) })
} }
} }
function handleSelectMenu(selectedKeys: any, info: any){ const lookSelect = ref([]) as any
console.log(info) const actionSelect = ref([]) as any
if(info.node.children==null || info.node.children.length==0){ function handleSelectMenu(selectedKeys: any, info: any) {
if (info.node.children == null || info.node.children.length == 0) {
const data = { const data = {
permissionId: info.node.id, permissionId: info.node.parentId,
id:userId.value userId: userId.value
}
setLoading(true)
GetCodeDataRuleList(data).then(res => {
if (res.succeeded) {
setTableData(res.data)
} }
GetCodeDataRuleList(data).then(res=>{ setLoading(false)
}).catch(err => {
setLoading(false)
})
GetDataRuleTemplateSelectList({ id: info.node.parentId, ruleType: 'visible' }).then(res => {
lookSelect.value = res.data
})
GetDataRuleTemplateSelectList({ id: info.node.parentId, ruleType: 'operate' }).then(res => {
actionSelect.value = res.data
})
}
}
function openRule() {
openFlag.value = true
}
const columns = [
{ dataIndex: 'templateName', width: 100, title: '权限模板类型' },
{ dataIndex: 'description', width: 100, title: '权限描述' },
{ dataIndex: 'note', width: 100, title: '备注' },
{ dataIndex: 'visibleRuleScopeName', width: 100, title: '可视范围' },
{ dataIndex: 'operateRuleScopeName', width: 100, title: '操作范围' },
]
const ruleList = ref([])
const [registerTable, { reload, setLoading, setTableData, getSelectRows, setProps }] = useTable({
immediate: false,
columns,
isTreeTable: false,
pagination: true,
striped: true,
useSearchForm: false,
bordered: true,
showIndexColumn: false,
canResize: true,
resizeHeightOffset: 35,
})
function handleChangeLook(val, row) {
const data = {} as any
lookSelect.value.forEach(item => {
if (item.id == val) {
data.templateId = item.id
data.ruleType = item.ruleType
data.ruleScope = item.ruleScope
data.ruleScopeName = item.ruleScopeName
}
})
data.id = row.id
setLoading(true)
AssignDataRuleScope(data).then(res => {
if (res.succeeded) {
createMessage.success('更新成功')
}
setLoading(false)
}) })
}
function processNodeCheck(node) {
// children userList
if (node.children && node.children.length === 0 && node.userList) {
node.children = node.userList.map(user => {
// title disabled
return {
...user,
title: user.userName,
disabled: false,
value: user.id,
key: user.id
};
});
} else {
// disabled true
if (node.children) {
node.children = node.children.map(child => {
return {
...child,
key: child.id,
disabled: true
};
});
}
}
//
if (node.children) {
node.children.forEach(child => {
processNodeCheck(child);
});
} }
} }
@ -97,12 +302,12 @@ function processNode(node) {
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>
.main { .main {
height: 100vh; height: 80vh;
} }
.top { .top {
background-color: rgba(245, 249, 252, 1); background-color: rgba(245, 249, 252, 1);
padding: 10px; padding: 8px 10px;
} }
.SvgImg { .SvgImg {
@ -118,6 +323,7 @@ function processNode(node) {
.tree-item { .tree-item {
width: 20%; width: 20%;
padding: 0 15px;
.title { .title {
font-size: 12px; font-size: 12px;
@ -127,8 +333,20 @@ function processNode(node) {
} }
} }
.border-left {
border-right: 1px solid #ebebeb;
}
.table-item {
width: 50%;
}
/deep/ .ant-tree-node-selected { /deep/ .ant-tree-node-selected {
color: #257afa; color: #257afa;
background-color: #f5f9fc !important; background-color: #f5f9fc !important;
} }
/deep/ .vben-basic-table .ant-table-wrapper .ant-table.ant-table-bordered .ant-table-title {
padding-top: 0px !important;
}
</style> </style>

Loading…
Cancel
Save