更新代码
This commit is contained in:
@@ -0,0 +1,396 @@
|
|||||||
|
<template>
|
||||||
|
<a-form :model="form" :rules="rules" ref="dialogForm" :label-col="{ span: 4 }" :wrapper-col="{ span: 18 }">
|
||||||
|
<!-- 第一行:权限名称和类型 -->
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item label="权限名称" name="title">
|
||||||
|
<a-input v-model:value="form.title" placeholder="权限名称" allow-clear />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item label="类型" name="type" :label-col="{ span: 6 }" :wrapper-col="{ span: 16 }">
|
||||||
|
<a-radio-group v-model:value="form.type" button-style="solid">
|
||||||
|
<a-radio-button value="menu">菜单</a-radio-button>
|
||||||
|
<a-radio-button value="api">接口</a-radio-button>
|
||||||
|
<a-radio-button value="button">按钮</a-radio-button>
|
||||||
|
</a-radio-group>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<!-- 第二行:上级权限和权限编码 -->
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item label="上级权限" name="parent_id">
|
||||||
|
<a-tree-select v-model:value="form.parent_id" :tree-data="menuOptions"
|
||||||
|
:field-names="menuFieldNames" :tree-default-expand-all="false" show-icon placeholder="顶级权限"
|
||||||
|
allow-clear tree-node-filter-prop="title" :disabled="!!menuId" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item label="权限编码" name="name">
|
||||||
|
<a-input v-model:value="form.name" placeholder="如: system.user.list" allow-clear />
|
||||||
|
<div class="form-tip">格式:模块.功能.操作,系统唯一标识</div>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<!-- 第三行:路由地址和组件路径 -->
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item label="路由地址" name="path">
|
||||||
|
<a-input v-model:value="form.path" placeholder="/system/users" allow-clear />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item label="组件路径" name="component">
|
||||||
|
<a-input v-model:value="form.component" placeholder="system/users/index" allow-clear>
|
||||||
|
<template #addonBefore>pages/</template>
|
||||||
|
</a-input>
|
||||||
|
<div class="form-tip">顶级菜单或有子菜单的父节点不需要填写</div>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<!-- 第四行:菜单图标和排序 -->
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item label="菜单图标" name="icon">
|
||||||
|
<sc-icon-picker v-model:value="form.icon" placeholder="请选择图标" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item label="排序" name="sort">
|
||||||
|
<a-input-number v-model:value="form.sort" :min="0" :max="10000" style="width: 100%" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<!-- 分隔线 -->
|
||||||
|
<a-divider />
|
||||||
|
|
||||||
|
<!-- 选项设置区域 -->
|
||||||
|
<div class="options-section">
|
||||||
|
<h4>选项设置</h4>
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="是否隐藏" name="hidden" :label-col="{ span: 8 }" :wrapper-col="{ span: 14 }">
|
||||||
|
<a-checkbox v-model:checked="form.hidden">隐藏菜单</a-checkbox>
|
||||||
|
<a-checkbox v-model:checked="form.hiddenBreadcrumb">隐藏面包屑</a-checkbox>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="是否缓存" name="keepAlive" :label-col="{ span: 8 }" :wrapper-col="{ span: 14 }">
|
||||||
|
<a-switch v-model:checked="form.keepAlive" size="small" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="是否固定" name="affix" :label-col="{ span: 8 }" :wrapper-col="{ span: 14 }">
|
||||||
|
<a-switch v-model:checked="form.affix" size="small" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-form-item label="外链" name="target">
|
||||||
|
<a-radio-group v-model:value="form.target" button-style="solid" size="small">
|
||||||
|
<a-radio-button value="null">当前窗口</a-radio-button>
|
||||||
|
<a-radio-button value="_blank">新窗口</a-radio-button>
|
||||||
|
</a-radio-group>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 分隔线 -->
|
||||||
|
<a-divider />
|
||||||
|
|
||||||
|
<!-- 状态 -->
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-form-item label="状态" name="status" :label-col="{ span: 6 }" :wrapper-col="{ span: 16 }">
|
||||||
|
<a-switch v-model:checked="statusChecked" checked-children="启用" un-checked-children="禁用" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
|
||||||
|
<!-- 操作按钮 -->
|
||||||
|
<a-form-item :wrapper-col="{ span: 18, offset: 4 }" style="margin-top: 32px">
|
||||||
|
<a-space>
|
||||||
|
<a-button type="primary" @click="handleSave" :loading="loading" size="large">保存</a-button>
|
||||||
|
<a-button @click="$emit('cancel')" size="large">取消</a-button>
|
||||||
|
</a-space>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, watch, computed, onMounted } from 'vue'
|
||||||
|
import { message } from 'ant-design-vue'
|
||||||
|
import authApi from '@/api/auth'
|
||||||
|
import scIconPicker from '@/components/scIconPicker/index.vue'
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'PermissionSaveForm'
|
||||||
|
})
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
menu: { type: [Object, Array], default: () => [] },
|
||||||
|
menuId: { type: [Number, String], default: null },
|
||||||
|
parentId: { type: [Number, String], default: null }
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['success', 'cancel'])
|
||||||
|
|
||||||
|
// 表单数据
|
||||||
|
const form = reactive({
|
||||||
|
id: '',
|
||||||
|
parent_id: 0,
|
||||||
|
name: '',
|
||||||
|
title: '',
|
||||||
|
path: '',
|
||||||
|
component: '',
|
||||||
|
icon: '',
|
||||||
|
sort: 0,
|
||||||
|
type: 'menu',
|
||||||
|
status: 1,
|
||||||
|
target: null,
|
||||||
|
// meta 字段内容
|
||||||
|
hidden: false,
|
||||||
|
hiddenBreadcrumb: false,
|
||||||
|
keepAlive: false,
|
||||||
|
affix: false
|
||||||
|
})
|
||||||
|
|
||||||
|
// 表单引用
|
||||||
|
const dialogForm = ref()
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
// 验证规则
|
||||||
|
const rules = {
|
||||||
|
name: [{ required: true, message: '请输入权限名称', trigger: 'blur' }],
|
||||||
|
code: [{ required: true, message: '请输入权限编码', trigger: 'blur' }],
|
||||||
|
type: [{ required: true, message: '请选择类型', trigger: 'change' }]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 菜单选项
|
||||||
|
const menuOptions = ref([])
|
||||||
|
const menuFieldNames = {
|
||||||
|
value: 'id',
|
||||||
|
label: 'title',
|
||||||
|
children: 'children'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 状态开关计算属性
|
||||||
|
const statusChecked = computed({
|
||||||
|
get: () => form.status === 1,
|
||||||
|
set: (val) => {
|
||||||
|
form.status = val ? 1 : 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 筛单化菜单树,排除自己和子节点
|
||||||
|
const treeToMap = (tree, excludeId = null) => {
|
||||||
|
const map = []
|
||||||
|
tree.forEach(item => {
|
||||||
|
if (item.id === excludeId) return // 排除自己
|
||||||
|
const obj = {
|
||||||
|
id: item.id,
|
||||||
|
parent_id: item.parent_id,
|
||||||
|
title: item.title,
|
||||||
|
children: item.children && item.children.length > 0 ? treeToMap(item.children, excludeId) : null
|
||||||
|
}
|
||||||
|
map.push(obj)
|
||||||
|
})
|
||||||
|
return map
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查找权限节点
|
||||||
|
const findMenuNode = (tree, id) => {
|
||||||
|
for (const node of tree) {
|
||||||
|
if (node.id === id) {
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
if (node.children && node.children.length > 0) {
|
||||||
|
const found = findMenuNode(node.children, id)
|
||||||
|
if (found) return found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听菜单树变化
|
||||||
|
watch(
|
||||||
|
() => props.menu,
|
||||||
|
(newVal) => {
|
||||||
|
if (newVal) {
|
||||||
|
// 排除当前编辑的节点,避免选择自己作为父节点
|
||||||
|
menuOptions.value = treeToMap(newVal, props.menuId)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: true, immediate: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
// 监听 menuId 变化,从菜单树中查找并赋值
|
||||||
|
watch(
|
||||||
|
() => props.menuId,
|
||||||
|
(newVal) => {
|
||||||
|
if (newVal && props.menu && props.menu.length > 0) {
|
||||||
|
const menuNode = findMenuNode(props.menu, newVal)
|
||||||
|
if (menuNode) {
|
||||||
|
setData(menuNode, props.parentId)
|
||||||
|
}
|
||||||
|
} else if (!newVal) {
|
||||||
|
// 清空表单
|
||||||
|
setData({
|
||||||
|
id: '',
|
||||||
|
parent_id: props.parentId || 0,
|
||||||
|
name: '',
|
||||||
|
title: '',
|
||||||
|
path: '',
|
||||||
|
component: '',
|
||||||
|
icon: '',
|
||||||
|
sort: 0,
|
||||||
|
type: 'menu',
|
||||||
|
status: 1,
|
||||||
|
target: null,
|
||||||
|
hidden: false,
|
||||||
|
hiddenBreadcrumb: false,
|
||||||
|
keepAlive: false,
|
||||||
|
affix: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// 加载权限详情
|
||||||
|
const loadMenuDetail = async (id) => {
|
||||||
|
try {
|
||||||
|
const res = await authApi.permissions.detail.get(id)
|
||||||
|
if (res.code === 200 && res.data) {
|
||||||
|
setData(res.data, props.parentId)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载权限详情失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存
|
||||||
|
const handleSave = async () => {
|
||||||
|
try {
|
||||||
|
await dialogForm.value.validate()
|
||||||
|
loading.value = true
|
||||||
|
|
||||||
|
// 构建提交数据
|
||||||
|
const submitData = {
|
||||||
|
id: form.id || undefined,
|
||||||
|
parent_id: form.parent_id || 0,
|
||||||
|
name: form.name,
|
||||||
|
title: form.title,
|
||||||
|
path: form.path,
|
||||||
|
component: form.component,
|
||||||
|
icon: form.icon,
|
||||||
|
sort: form.sort,
|
||||||
|
type: form.type,
|
||||||
|
status: form.status,
|
||||||
|
target: form.target,
|
||||||
|
meta: {
|
||||||
|
hidden: form.hidden,
|
||||||
|
hiddenBreadcrumb: form.hiddenBreadcrumb,
|
||||||
|
keepAlive: form.keepAlive,
|
||||||
|
affix: form.affix
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let res = {}
|
||||||
|
if (form.id) {
|
||||||
|
res = await authApi.permissions.edit.put(form.id, submitData)
|
||||||
|
} else {
|
||||||
|
res = await authApi.permissions.add.post(submitData)
|
||||||
|
}
|
||||||
|
|
||||||
|
loading.value = false
|
||||||
|
if (res.code === 200) {
|
||||||
|
message.success('保存成功')
|
||||||
|
emit('success')
|
||||||
|
} else {
|
||||||
|
message.error(res.message || '保存失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('表单验证失败', error)
|
||||||
|
loading.value = false
|
||||||
|
message.error('保存失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表单注入数据
|
||||||
|
const setData = (data, pid) => {
|
||||||
|
form.id = data.id || ''
|
||||||
|
form.parent_id = data.parent_id !== undefined ? data.parent_id : (pid || 0)
|
||||||
|
form.name = data.name || ''
|
||||||
|
form.title = data.title || ''
|
||||||
|
form.path = data.path || ''
|
||||||
|
form.component = data.component || ''
|
||||||
|
form.icon = data.icon || ''
|
||||||
|
form.sort = data.sort || 0
|
||||||
|
form.type = data.type || 'menu'
|
||||||
|
form.status = data.status !== undefined ? data.status : 1
|
||||||
|
form.target = data.target || '_blank'
|
||||||
|
|
||||||
|
// 解析 meta 字段
|
||||||
|
const meta = data.meta && typeof data.meta === 'string' ? JSON.parse(data.meta) : (data.meta || {})
|
||||||
|
form.hidden = meta.hidden || false
|
||||||
|
form.hiddenBreadcrumb = meta.hiddenBreadcrumb || false
|
||||||
|
form.keepAlive = meta.keepAlive || false
|
||||||
|
form.affix = meta.affix || false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
onMounted(() => {
|
||||||
|
if (props.menuId) {
|
||||||
|
loadMenuDetail(props.menuId)
|
||||||
|
} else if (props.parentId) {
|
||||||
|
form.parent_id = props.parentId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 暴露方法给父组件
|
||||||
|
defineExpose({
|
||||||
|
setData
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.save-form {
|
||||||
|
padding: 24px;
|
||||||
|
background: #fff;
|
||||||
|
|
||||||
|
.form-tip {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #8c8c8;
|
||||||
|
margin-top: 4px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.options-section {
|
||||||
|
margin-top: 16px;
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #262626;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-divider {
|
||||||
|
margin: 32px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-form-item {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-input-number {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,20 +1,27 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="pages permission-page">
|
<div class="pages-sidebar-layout permission-page">
|
||||||
<div class="left-box">
|
<div class="left-box">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<a-input v-model:value="menuFilterText" placeholder="搜索菜单..." allow-clear @change="handleMenuSearch">
|
<a-input v-model:value="menuFilterText" placeholder="搜索权限..." allow-clear @change="handleMenuSearch">
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<SearchOutlined style="color: rgba(0, 0, 0, 0.45)" />
|
<SearchOutlined style="color: rgba(0, 0, 0, 0.45)" />
|
||||||
</template>
|
</template>
|
||||||
</a-input>
|
</a-input>
|
||||||
</div>
|
</div>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<a-tree v-model:selectedKeys="selectedMenuKeys" v-model:checkedKeys="checkedMenuKeys"
|
<a-tree
|
||||||
:tree-data="filteredMenuTree" :field-names="{ title: 'title', key: 'id', children: 'children' }"
|
v-model:selectedKeys="selectedMenuKeys"
|
||||||
showLine checkable :check-strictly="true" :expand-on-click-node="false" @select="onMenuSelect"
|
v-model:checkedKeys="checkedMenuKeys"
|
||||||
|
:tree-data="filteredMenuTree"
|
||||||
|
:field-names="{ title: 'title', key: 'id', children: 'children' }"
|
||||||
|
show-line
|
||||||
|
checkable
|
||||||
|
:check-strictly="false"
|
||||||
|
:expand-on-click-node="false"
|
||||||
|
@select="onMenuSelect"
|
||||||
@check="onMenuCheck">
|
@check="onMenuCheck">
|
||||||
<template #icon="{ dataRef }">
|
<template #icon="{ dataRef }">
|
||||||
<FolderOutlined v-if="dataRef.children" />
|
<ApartmentOutlined v-if="dataRef.children" />
|
||||||
<FileOutlined v-else />
|
<FileOutlined v-else />
|
||||||
</template>
|
</template>
|
||||||
<template #title="{ dataRef }">
|
<template #title="{ dataRef }">
|
||||||
@@ -23,22 +30,14 @@
|
|||||||
</template>
|
</template>
|
||||||
</a-tree>
|
</a-tree>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
|
||||||
<a-space>
|
|
||||||
<a-button type="primary" @click="handleAdd(null)">
|
|
||||||
<template #icon><PlusOutlined /></template>
|
|
||||||
新增
|
|
||||||
</a-button>
|
|
||||||
<a-button danger @click="handleDeleteBatch">
|
|
||||||
<template #icon><DeleteOutlined /></template>
|
|
||||||
删除
|
|
||||||
</a-button>
|
|
||||||
</a-space>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="right-box">
|
<div class="right-box">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div class="title">{{ selectedMenu?.title || '请选择权限节点' }}</div>
|
<div class="title">{{ selectedMenu?.title || '请选择权限节点' }}</div>
|
||||||
|
<a-button type="link" size="small" @click="handleRefresh">
|
||||||
|
<template #icon><ReloadOutlined /></template>
|
||||||
|
刷新
|
||||||
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<save-form v-if="selectedMenu" :menu="menuTree" :menu-id="selectedMenu.id" :parent-id="parentId"
|
<save-form v-if="selectedMenu" :menu="menuTree" :menu-id="selectedMenu.id" :parent-id="parentId"
|
||||||
@@ -52,8 +51,14 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { message, Modal } from 'ant-design-vue'
|
import { message, Modal } from 'ant-design-vue'
|
||||||
import { SearchOutlined, FolderOutlined, FileOutlined, PlusOutlined, DeleteOutlined } from '@ant-design/icons-vue'
|
import {
|
||||||
import saveForm from './save.vue'
|
SearchOutlined,
|
||||||
|
ReloadOutlined,
|
||||||
|
ApartmentOutlined,
|
||||||
|
FileOutlined,
|
||||||
|
PlusOutlined
|
||||||
|
} from '@ant-design/icons-vue'
|
||||||
|
import saveForm from './components/SaveForm.vue'
|
||||||
import authApi from '@/api/auth'
|
import authApi from '@/api/auth'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
@@ -84,7 +89,19 @@ const loadMenuTree = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 权限搜索
|
// 刷新
|
||||||
|
const handleRefresh = () => {
|
||||||
|
loadMenuTree()
|
||||||
|
if (selectedMenu.value) {
|
||||||
|
// 重新获取当前选中的权限详情
|
||||||
|
const menuNode = findMenuNode(menuTree.value, selectedMenu.value.id)
|
||||||
|
if (menuNode) {
|
||||||
|
selectedMenu.value = menuNode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索权限
|
||||||
const handleMenuSearch = (e) => {
|
const handleMenuSearch = (e) => {
|
||||||
const keyword = e.target?.value || ''
|
const keyword = e.target?.value || ''
|
||||||
menuFilterText.value = keyword
|
menuFilterText.value = keyword
|
||||||
@@ -141,7 +158,7 @@ const findParentId = (tree, id) => {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
// 权限选择事件
|
// 限制选择事件
|
||||||
const onMenuSelect = (selectedKeys, { selected }) => {
|
const onMenuSelect = (selectedKeys, { selected }) => {
|
||||||
if (selected) {
|
if (selected) {
|
||||||
const menuId = selectedKeys[0]
|
const menuId = selectedKeys[0]
|
||||||
@@ -154,7 +171,7 @@ const onMenuSelect = (selectedKeys, { selected }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 权限勾选事件
|
// 限制勾选事件
|
||||||
const onMenuCheck = (checkedKeys, info) => {
|
const onMenuCheck = (checkedKeys, info) => {
|
||||||
console.log('checkedKeys:', checkedKeys, 'info:', info)
|
console.log('checkedKeys:', checkedKeys, 'info:', info)
|
||||||
}
|
}
|
||||||
@@ -249,86 +266,6 @@ onMounted(() => {
|
|||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.permission-page {
|
.permission-page {
|
||||||
display: flex;
|
@extend .pages-sidebar-layout;
|
||||||
flex-direction: row;
|
|
||||||
height: 100%;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
.left-box {
|
|
||||||
width: 300px;
|
|
||||||
border-right: 1px solid #f0f0f0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
background: #fff;
|
|
||||||
|
|
||||||
.header {
|
|
||||||
padding: 12px 16px;
|
|
||||||
border-bottom: 1px solid #f0f0f0;
|
|
||||||
background: #fafafa;
|
|
||||||
height: 56px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.body {
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 12px;
|
|
||||||
|
|
||||||
.tree-node-title {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tree-node-add {
|
|
||||||
margin-left: 8px;
|
|
||||||
color: #999;
|
|
||||||
display: none;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: #1890ff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.ant-tree-node-content-wrapper) {
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.tree-node-add {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer {
|
|
||||||
padding: 12px 16px;
|
|
||||||
border-top: 1px solid #f0f0f0;
|
|
||||||
background: #fafafa;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.right-box {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
.header {
|
|
||||||
padding: 16px 24px;
|
|
||||||
border-bottom: 1px solid #f0f0f0;
|
|
||||||
background: #fff;
|
|
||||||
height: 56px;
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.body {
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
background: #f5f5f5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="pages role-page">
|
<div class="pages-base-layout role-page">
|
||||||
<div class="tool-bar">
|
<div class="tool-bar">
|
||||||
<div class="left-panel">
|
<div class="left-panel">
|
||||||
<a-form layout="inline" :model="searchForm">
|
<a-form layout="inline" :model="searchForm">
|
||||||
@@ -7,20 +7,14 @@
|
|||||||
<a-input v-model:value="searchForm.keyword" placeholder="请输入角色名称" allow-clear
|
<a-input v-model:value="searchForm.keyword" placeholder="请输入角色名称" allow-clear
|
||||||
style="width: 180px" />
|
style="width: 180px" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="状态">
|
|
||||||
<a-select v-model:value="searchForm.status" placeholder="请选择状态" allow-clear style="width: 100px">
|
|
||||||
<a-select-option :value="1">正常</a-select-option>
|
|
||||||
<a-select-option :value="0">禁用</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<a-space>
|
<a-space>
|
||||||
<a-button type="primary" @click="handleSearch">
|
<a-button type="primary" @click="handleSearch">
|
||||||
<template #icon><search-outlined /></template>
|
<template #icon><SearchOutlined /></template>
|
||||||
搜索
|
搜索
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-button @click="handleReset">
|
<a-button @click="handleUserReset">
|
||||||
<template #icon><redo-outlined /></template>
|
<template #icon><RedoOutlined /></template>
|
||||||
重置
|
重置
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-space>
|
</a-space>
|
||||||
@@ -31,25 +25,25 @@
|
|||||||
<a-dropdown :disabled="selectedRows.length === 0">
|
<a-dropdown :disabled="selectedRows.length === 0">
|
||||||
<a-button :disabled="selectedRows.length === 0">
|
<a-button :disabled="selectedRows.length === 0">
|
||||||
批量操作
|
批量操作
|
||||||
<down-outlined />
|
<DownOutlined />
|
||||||
</a-button>
|
</a-button>
|
||||||
<template #overlay>
|
<template #overlay>
|
||||||
<a-menu>
|
<a-menu>
|
||||||
<a-menu-item @click="handleBatchStatus">
|
<a-menu-item @click="handleBatchStatus">
|
||||||
<check-circle-outlined />批量启用/禁用
|
<CheckCircleOutlined />批量启用/禁用
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item @click="handleBatchCopy">
|
<a-menu-item @click="handleBatchCopy">
|
||||||
<copy-outlined />批量复制
|
<CopyOutlined />批量复制
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-divider />
|
<a-menu-divider />
|
||||||
<a-menu-item @click="handleBatchDelete" danger>
|
<a-menu-item @click="handleBatchDelete" danger>
|
||||||
<delete-outlined />批量删除
|
<DeleteOutlined />批量删除
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
</a-menu>
|
</a-menu>
|
||||||
</template>
|
</template>
|
||||||
</a-dropdown>
|
</a-dropdown>
|
||||||
<a-button type="primary" @click="handleAdd">
|
<a-button type="primary" @click="handleAdd">
|
||||||
<template #icon><plus-outlined /></template>
|
<template #icon><PlusOutlined /></template>
|
||||||
新增
|
新增
|
||||||
</a-button>
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
@@ -89,9 +83,18 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive } from 'vue'
|
import { ref, reactive } from 'vue'
|
||||||
import { message, Modal } from 'ant-design-vue'
|
import { message, Modal } from 'ant-design-vue'
|
||||||
|
import {
|
||||||
|
SearchOutlined,
|
||||||
|
RedoOutlined,
|
||||||
|
PlusOutlined,
|
||||||
|
DownOutlined,
|
||||||
|
CheckCircleOutlined,
|
||||||
|
CopyOutlined,
|
||||||
|
DeleteOutlined
|
||||||
|
} from '@ant-design/icons-vue'
|
||||||
import scTable from '@/components/scTable/index.vue'
|
import scTable from '@/components/scTable/index.vue'
|
||||||
import saveDialog from './save.vue'
|
import saveDialog from './components/SaveDialog.vue'
|
||||||
import permissionDialog from './permission.vue'
|
import permissionDialog from './components/PermissionDialog.vue'
|
||||||
import authApi from '@/api/auth'
|
import authApi from '@/api/auth'
|
||||||
import { useTable } from '@/hooks/useTable'
|
import { useTable } from '@/hooks/useTable'
|
||||||
|
|
||||||
@@ -283,6 +286,13 @@ const handlePermission = (record) => {
|
|||||||
}, 0)
|
}, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 重置
|
||||||
|
const handleUserReset = () => {
|
||||||
|
searchForm.keyword = ''
|
||||||
|
searchForm.status = null
|
||||||
|
handleSearch()
|
||||||
|
}
|
||||||
|
|
||||||
// 保存成功回调
|
// 保存成功回调
|
||||||
const handleSaveSuccess = () => {
|
const handleSaveSuccess = () => {
|
||||||
refreshTable()
|
refreshTable()
|
||||||
@@ -296,14 +306,6 @@ const permissionSuccess = () => {
|
|||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.role-page {
|
.role-page {
|
||||||
display: flex;
|
@extend .pages-base-layout;
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
.table-content {
|
|
||||||
flex: 1;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="pages user-page">
|
<div class="pages-sidebar-layout user-page">
|
||||||
<div class="left-box">
|
<div class="left-box">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<a-input v-model:value="departmentKeyword" placeholder="搜索部门..." allow-clear @change="handleDeptSearch">
|
<a-input v-model:value="departmentKeyword" placeholder="搜索部门..." allow-clear @change="handleDeptSearch">
|
||||||
<template #prefix>
|
<template #prefix>
|
||||||
<search-outlined style="color: rgba(0, 0, 0, 0.45)" />
|
<SearchOutlined style="color: rgba(0, 0, 0, 0.45)" />
|
||||||
</template>
|
</template>
|
||||||
</a-input>
|
</a-input>
|
||||||
</div>
|
</div>
|
||||||
@@ -12,8 +12,8 @@
|
|||||||
<a-tree v-model:selectedKeys="selectedDeptKeys" :tree-data="filteredDepartmentTree"
|
<a-tree v-model:selectedKeys="selectedDeptKeys" :tree-data="filteredDepartmentTree"
|
||||||
:field-names="{ title: 'name', key: 'id', children: 'children' }" show-line @select="onDeptSelect">
|
:field-names="{ title: 'name', key: 'id', children: 'children' }" show-line @select="onDeptSelect">
|
||||||
<template #icon="{ dataRef }">
|
<template #icon="{ dataRef }">
|
||||||
<apartment-outlined v-if="dataRef.children && dataRef.children.length > 0" />
|
<ApartmentOutlined v-if="dataRef.children && dataRef.children.length > 0" />
|
||||||
<user-outlined v-else />
|
<UserOutlined v-else />
|
||||||
</template>
|
</template>
|
||||||
</a-tree>
|
</a-tree>
|
||||||
</div>
|
</div>
|
||||||
@@ -26,28 +26,14 @@
|
|||||||
<a-input v-model:value="searchForm.username" placeholder="请输入用户名" allow-clear
|
<a-input v-model:value="searchForm.username" placeholder="请输入用户名" allow-clear
|
||||||
style="width: 140px" />
|
style="width: 140px" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="姓名">
|
|
||||||
<a-input v-model:value="searchForm.real_name" placeholder="请输入姓名" allow-clear
|
|
||||||
style="width: 140px" />
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="邮箱">
|
|
||||||
<a-input v-model:value="searchForm.email" placeholder="请输入邮箱" allow-clear
|
|
||||||
style="width: 160px" />
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item label="状态">
|
|
||||||
<a-select v-model:value="searchForm.status" placeholder="请选择状态" allow-clear style="width: 100px">
|
|
||||||
<a-select-option :value="1">正常</a-select-option>
|
|
||||||
<a-select-option :value="0">禁用</a-select-option>
|
|
||||||
</a-select>
|
|
||||||
</a-form-item>
|
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<a-space>
|
<a-space>
|
||||||
<a-button type="primary" @click="handleSearch">
|
<a-button type="primary" @click="handleSearch">
|
||||||
<template #icon><search-outlined /></template>
|
<template #icon><SearchOutlined /></template>
|
||||||
搜索
|
搜索
|
||||||
</a-button>
|
</a-button>
|
||||||
<a-button @click="handleUserReset">
|
<a-button @click="handleUserReset">
|
||||||
<template #icon><redo-outlined /></template>
|
<template #icon><RedoOutlined /></template>
|
||||||
重置
|
重置
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-space>
|
</a-space>
|
||||||
@@ -58,22 +44,22 @@
|
|||||||
<a-dropdown :disabled="selectedRows.length === 0">
|
<a-dropdown :disabled="selectedRows.length === 0">
|
||||||
<a-button :disabled="selectedRows.length === 0">
|
<a-button :disabled="selectedRows.length === 0">
|
||||||
批量操作
|
批量操作
|
||||||
<down-outlined />
|
<DownOutlined />
|
||||||
</a-button>
|
</a-button>
|
||||||
<template #overlay>
|
<template #overlay>
|
||||||
<a-menu>
|
<a-menu>
|
||||||
<a-menu-item @click="handleBatchStatus">
|
<a-menu-item @click="handleBatchStatus">
|
||||||
<check-circle-outlined />批量启用/禁用
|
<CheckCircleOutlined />批量启用/禁用
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item @click="handleBatchDepartment">
|
<a-menu-item @click="handleBatchDepartment">
|
||||||
<apartment-outlined />批量分配部门
|
<ApartmentOutlined />批量分配部门
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item @click="handleBatchRoles">
|
<a-menu-item @click="handleBatchRoles">
|
||||||
<team-outlined />批量分配角色
|
<TeamOutlined />批量分配角色
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-divider />
|
<a-menu-divider />
|
||||||
<a-menu-item @click="handleBatchDelete" danger>
|
<a-menu-item @click="handleBatchDelete" danger>
|
||||||
<delete-outlined />批量删除
|
<DeleteOutlined />批量删除
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
</a-menu>
|
</a-menu>
|
||||||
</template>
|
</template>
|
||||||
@@ -81,35 +67,35 @@
|
|||||||
<a-dropdown>
|
<a-dropdown>
|
||||||
<a-button>
|
<a-button>
|
||||||
更多
|
更多
|
||||||
<down-outlined />
|
<DownOutlined />
|
||||||
</a-button>
|
</a-button>
|
||||||
<template #overlay>
|
<template #overlay>
|
||||||
<a-menu>
|
<a-menu>
|
||||||
<a-menu-item @click="handleImport">
|
<a-menu-item @click="handleImport">
|
||||||
<import-outlined />导入用户
|
<ImportOutlined />导入用户
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item @click="handleExport">
|
<a-menu-item @click="handleExport">
|
||||||
<export-outlined />导出用户
|
<ExportOutlined />导出用户
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
<a-menu-item @click="handleDownloadTemplate">
|
<a-menu-item @click="handleDownloadTemplate">
|
||||||
<download-outlined />下载模板
|
<DownloadOutlined />下载模板
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
</a-menu>
|
</a-menu>
|
||||||
</template>
|
</template>
|
||||||
</a-dropdown>
|
</a-dropdown>
|
||||||
<a-button type="primary" @click="handleAdd">
|
<a-button type="primary" @click="handleAdd">
|
||||||
<template #icon><plus-outlined /></template>
|
<template #icon><PlusOutlined /></template>
|
||||||
新增
|
新增
|
||||||
</a-button>
|
</a-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="table-content">
|
<div class="table-content">
|
||||||
<scTable ref="tableRef" :columns="columns" :data-source="tableData" :loading="loading"
|
<scTable ref="tableRef" :columns="columns" :data-source="tableData" :loading="loading"
|
||||||
:pagination="pagination" :row-key="rowKey" :row-selection="rowSelection" @refresh="refreshTable"
|
:pagination="pagination" :row-key="rowKey" :row-selection="rowSelection" @refresh="refreshTable"
|
||||||
@paginationChange="handlePaginationChange" @select="handleSelectChange" @selectAll="handleSelectAll">
|
@paginationChange="handlePaginationChange" @select="handleSelectChange" @selectAll="handleSelectAll">
|
||||||
<template #avatar="{ record }">
|
<template #avatar="{ record }">
|
||||||
<a-avatar :src="record.avatar" :size="32">
|
<a-avatar :src="record.avatar" :size="32">
|
||||||
<template #icon><user-outlined /></template>
|
<template #icon><UserOutlined /></template>
|
||||||
</a-avatar>
|
</a-avatar>
|
||||||
</template>
|
</template>
|
||||||
<template #status="{ record }">
|
<template #status="{ record }">
|
||||||
@@ -151,9 +137,23 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, onMounted } from 'vue'
|
import { ref, reactive, onMounted } from 'vue'
|
||||||
import { message, Modal } from 'ant-design-vue'
|
import { message, Modal } from 'ant-design-vue'
|
||||||
|
import {
|
||||||
|
SearchOutlined,
|
||||||
|
RedoOutlined,
|
||||||
|
PlusOutlined,
|
||||||
|
DeleteOutlined,
|
||||||
|
CheckCircleOutlined,
|
||||||
|
ApartmentOutlined,
|
||||||
|
TeamOutlined,
|
||||||
|
DownOutlined,
|
||||||
|
ImportOutlined,
|
||||||
|
ExportOutlined,
|
||||||
|
DownloadOutlined,
|
||||||
|
UserOutlined
|
||||||
|
} from '@ant-design/icons-vue'
|
||||||
import scTable from '@/components/scTable/index.vue'
|
import scTable from '@/components/scTable/index.vue'
|
||||||
import saveDialog from './save.vue'
|
import saveDialog from './components/SaveDialog.vue'
|
||||||
import roleDialog from './role.vue'
|
import roleDialog from './components/RoleDialog.vue'
|
||||||
import authApi from '@/api/auth'
|
import authApi from '@/api/auth'
|
||||||
import { useTable } from '@/hooks/useTable'
|
import { useTable } from '@/hooks/useTable'
|
||||||
|
|
||||||
@@ -194,14 +194,12 @@ const {
|
|||||||
// 对话框状态
|
// 对话框状态
|
||||||
const dialog = reactive({
|
const dialog = reactive({
|
||||||
save: false,
|
save: false,
|
||||||
role: false,
|
role: false
|
||||||
department: false
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 弹窗引用
|
// 弹窗引用
|
||||||
const saveDialogRef = ref(null)
|
const saveDialogRef = ref(null)
|
||||||
const roleDialogRef = ref(null)
|
const roleDialogRef = ref(null)
|
||||||
const departmentDialogRef = ref(null)
|
|
||||||
|
|
||||||
// 部门树数据
|
// 部门树数据
|
||||||
const departmentTree = ref([])
|
const departmentTree = ref([])
|
||||||
@@ -217,10 +215,10 @@ const columns = [
|
|||||||
{ title: '头像', dataIndex: 'avatar', key: 'avatar', width: 80, align: 'center', slot: 'avatar' },
|
{ title: '头像', dataIndex: 'avatar', key: 'avatar', width: 80, align: 'center', slot: 'avatar' },
|
||||||
{ title: '用户名', dataIndex: 'username', key: 'username', width: 150 },
|
{ title: '用户名', dataIndex: 'username', key: 'username', width: 150 },
|
||||||
{ title: '姓名', dataIndex: 'real_name', key: 'real_name', width: 150 },
|
{ title: '姓名', dataIndex: 'real_name', key: 'real_name', width: 150 },
|
||||||
{ title: '邮箱', dataIndex: 'email', key: 'email', width: 180 },
|
{ title: '邮箱', dataIndex: 'email', key: 'email', width: 180, ellipsis: true },
|
||||||
{ title: '手机号', dataIndex: 'phone', key: 'phone', width: 130 },
|
{ title: '手机号', dataIndex: 'phone', key: 'phone', width: 130 },
|
||||||
{ title: '部门', dataIndex: 'department', key: 'department', slot: 'department', width: 150 },
|
{ title: '部门', dataIndex: 'department', key: 'department', slot: 'department', width: 150, ellipsis: true },
|
||||||
{ title: '角色', dataIndex: 'roles', key: 'roles', width: 200, slot: 'roles' },
|
{ title: '角色', dataIndex: 'roles', key: 'roles', width: 200, slot: 'roles', ellipsis: true },
|
||||||
{ title: '状态', dataIndex: 'status', key: 'status', width: 100, align: 'center', slot: 'status' },
|
{ title: '状态', dataIndex: 'status', key: 'status', width: 100, align: 'center', slot: 'status' },
|
||||||
{ title: '最后登录', dataIndex: 'last_login_at', key: 'last_login_at', width: 180 },
|
{ title: '最后登录', dataIndex: 'last_login_at', key: 'last_login_at', width: 180 },
|
||||||
{ title: '操作', dataIndex: 'action', key: 'action', width: 280, align: 'center', slot: 'action', fixed: 'right' }
|
{ title: '操作', dataIndex: 'action', key: 'action', width: 280, align: 'center', slot: 'action', fixed: 'right' }
|
||||||
@@ -278,7 +276,7 @@ const handleUserReset = () => {
|
|||||||
selectedDeptKeys.value = []
|
selectedDeptKeys.value = []
|
||||||
departmentKeyword.value = ''
|
departmentKeyword.value = ''
|
||||||
filteredDepartmentTree.value = departmentTree.value
|
filteredDepartmentTree.value = departmentTree.value
|
||||||
handleReset()
|
handleSearch()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 部门选择事件
|
// 部门选择事件
|
||||||
@@ -508,44 +506,6 @@ onMounted(() => {
|
|||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.user-page {
|
.user-page {
|
||||||
display: flex;
|
@extend .pages-sidebar-layout;
|
||||||
flex-direction: row;
|
|
||||||
height: 100%;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
.left-box {
|
|
||||||
width: 260px;
|
|
||||||
border-right: 1px solid #f0f0f0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
background: #fff;
|
|
||||||
|
|
||||||
.header {
|
|
||||||
padding: 12px 16px;
|
|
||||||
font-weight: 500;
|
|
||||||
border-bottom: 1px solid #f0f0f0;
|
|
||||||
font-size: 14px;
|
|
||||||
background: #fafafa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.body {
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.right-box {
|
|
||||||
flex: 1;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
.table-content {
|
|
||||||
flex: 1;
|
|
||||||
overflow: hidden;
|
|
||||||
background: #f5f5f5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user