fix:调整Table组件 完善权限管理-字典管理

This commit is contained in:
liangdong
2026-01-14 13:33:03 +08:00
parent e4c5330a18
commit c6d57ed0db
13 changed files with 274 additions and 200 deletions

View File

@@ -22,7 +22,7 @@
<slot></slot>
</div>
</el-popover>
<div class="mj-icon-item" title="下载" @click="$emit('download')" v-if="download">
<div class="mj-icon-item" title="下载" @click="onDownload" v-if="download">
<el-icon><Download /></el-icon>
</div>
</div>
@@ -53,6 +53,12 @@ defineExpose({
filterPopover.value?.hide()
},
});
const onDownload = () => {
ElMessage.warning("功能开发中...");
emit("download");
};
</script>
<style lang="scss" scoped>

View File

@@ -31,8 +31,9 @@
</div>
</template>
<!-- 空数据 -->
<template #empty>
<el-empty description="暂无相关数据" :image-size="100" />
<el-empty description="暂无数据" :image-size="100" />
</template>
</el-table-v2>
</div>
@@ -40,7 +41,7 @@
<script setup lang="tsx">
import { ref, computed, onMounted, onUnmounted, nextTick } from "vue";
import { ElTag, ElButton, ElText,ElTooltip } from "element-plus";
import { ElTag, ElButton, ElText, ElTooltip } from "element-plus";
import { debounce } from "lodash-es";
import dayjs from "dayjs";
import { DictManage } from "@/dict";
@@ -64,10 +65,50 @@ const total = ref(0);
const pageNo = ref(1);
const tableSize = ref({ width: 0, height: 400 });
const noMore = computed(
() => innerData.value.length >= total.value && total.value > 0
);
const noMore = computed(() => {
if (total.value <= 0) return false;
const isReachTotal = innerData.value.length >= total.value;
return isReachTotal;
});
// --- 1. 核心渲染工厂 (内置常用业务组件) ---
// 定义一个内部小组件处理溢出逻辑
const OverflowTooltip = defineComponent({
props: {
val: { type: String, default: "" }
},
setup(props) {
const isOverflow = ref(false);
const textRef = ref<HTMLElement | null>(null);
const checkOverflow = () => {
if (textRef.value) {
// 计算溢出
isOverflow.value = textRef.value.scrollWidth > textRef.value.clientWidth;
}
};
return () => (
<ElTooltip
content={props.val}
placement="top"
effect="dark"
disabled={!isOverflow.value}
>
{{
default: () => (
<div
ref={textRef}
class="mj-ellipsis-cell"
onMouseenter={checkOverflow}
>
{props.val}
</div>
)
}}
</ElTooltip>
);
}
});
const RenderFactory = {
// 状态点/标签
status: (scope: any, col: any) => {
@@ -114,21 +155,8 @@ const RenderFactory = {
// 文本自动省略
ellipsis: (scope: any, col: any) => {
const val = scope.rowData[col.prop] ?? "-";
return (
<ElTooltip
effect="dark"
content={String(val)}
placement="top"
// 只有当内容不是 "-" 且达到截断条件时才显示可选优化
fallback-placements={['bottom', 'top']}
enterable={false}
>
<div class="mj-ellipsis-cell">
{val}
</div>
</ElTooltip>
);
},
return <OverflowTooltip val={val} />;
}
};
/**
@@ -149,7 +177,7 @@ const updateRow = (id: string | number, rowData: object) => {
* @param id 唯一标识
*/
const removeRow = (id: string | number) => {
const index = innerData.value.findIndex(item => item.id == id);
const index = innerData.value.findIndex((item) => item.id == id);
if (index !== -1) {
innerData.value.splice(index, 1);
total.value = Math.max(0, total.value - 1);
@@ -190,7 +218,8 @@ const adaptedColumns = computed(() => {
// 4. 计算剩余可用宽度
const remainingWidth = Math.max(containerWidth - fixedWidthTotal, 0);
// 5. 计算每个自适应列应该分配到的平均宽度
const perAutoWidth = autoColumns.length > 0
const perAutoWidth =
autoColumns.length > 0
? Math.floor(remainingWidth / autoColumns.length)
: 0;
return props.columns.map((col: any) => {
@@ -206,14 +235,14 @@ const adaptedColumns = computed(() => {
fixed: col.fixed,
align: col.align || "left",
cellRenderer: (scope: any) => {
const isOp = col.prop === 'actions' || col.valueType === 'actions';
const cellClass = isOp ? 'operation-column-cell' : '';
const isOp = col.prop === "actions" || col.valueType === "actions";
const cellClass = isOp ? "operation-column-cell" : "";
// 2. 如果是操作列,包裹一层带 class 的 div
if (isOp && col.actions) {
return (
<div class={cellClass}>
<div class="v2-operation-btns">
{col.actions.map(btn => {
{col.actions.map((btn) => {
// --- 权限校验开始 ---
if (btn.permission) {
const hasAuth = checkPermission(btn.permission);
@@ -221,12 +250,27 @@ const adaptedColumns = computed(() => {
}
// 2. 现有的 show 逻辑判断(业务逻辑显隐)
const isShow = typeof btn.show === 'function' ? btn.show(scope.rowData) : true;
const isShow =
typeof btn.show === "function"
? btn.show(scope.rowData)
: true;
const isDisabled =
typeof btn.disabled === "function"
? btn.disabled(scope.rowData)
: false;
if (!isShow) return null;
const { onClick, label, permission, show, ...otherProps } = btn;
const {
onClick,
label,
permission,
show,
disabled,
...otherProps
} = btn;
return (
<ElButton
{...otherProps}
disabled={isDisabled}
onClick={() => btn.onClick(scope.rowData)}
>
{btn.label}
@@ -241,7 +285,9 @@ const adaptedColumns = computed(() => {
if (col.valueType && RenderFactory[col.valueType]) {
return RenderFactory[col.valueType](scope, col);
}
return <span class="v2-cell-text">{scope.rowData[col.prop] ?? "-"}</span>;
return (
<span class="v2-cell-text">{scope.rowData[col.prop] ?? "-"}</span>
);
},
};
});
@@ -254,8 +300,7 @@ const fetchTableData = async (isReset = false) => {
if (isReset) {
pageNo.value = 1;
noMore.value = false;
// 重置时不立即清空数据,防止闪烁
innerData.value = [];
}
loading.value = true;
@@ -270,9 +315,6 @@ const fetchTableData = async (isReset = false) => {
innerData.value = isReset ? records : [...innerData.value, ...records];
total.value = res?.total || 0;
if (innerData.value.length >= total.value || records.length < props.pageSize) {
noMore.value = true;
}
pageNo.value++;
} finally {
loading.value = false;
@@ -321,9 +363,9 @@ defineExpose({
getCurrentParams: () => ({
pageNo: pageNo.value - 1, // 因为 fetch 完后 pageNo 会自增,所以要减 1 才是当前页
pageSize: props.pageSize,
...props.initParam
...props.initParam,
}),
innerData
innerData,
});
</script>
@@ -334,7 +376,9 @@ defineExpose({
background-color: #fff;
border-radius: 4px;
/* 移除外边框,让样式更融入页面 */
.el-table-v2 {
box-shadow: 0 0 6px #eef1f6;
}
// 1. 初始全屏 Loading
.v2-initial-loading {
position: absolute;
@@ -394,6 +438,7 @@ defineExpose({
// 适配 el-table-v2 核心样式
:deep(.el-table-v2__main) {
background: #fff;
box-sizing: border-box;
}
:deep(.el-table-v2__header-wrapper) {
@@ -420,7 +465,9 @@ defineExpose({
transition: opacity 0.2s;
display: flex;
justify-content: center;
gap: 8px;
.el-button + .el-button {
margin-left: 8px;
}
}
}

View File

@@ -2,8 +2,7 @@
<div class="mj-standard-menu">
<el-menu
:default-active="activeIndex"
:active-text-color="mode === 'horizontal' ? '#409EFF' : undefined"
class="mj-menu"
:class="['mj-menu',menuClass]"
:mode="mode"
:collapse="isCollapse"
@select="handleMenuSelect"
@@ -20,7 +19,7 @@
<template #title>{{ row.meta.title }}</template>
</el-menu-item>
</el-sub-menu>
<el-menu-item v-else :index="getFirstChildPath(item)">
<el-menu-item v-else :index="getFirstChildPath(item)" :disabled="item.meta.disabled">
<el-icon v-if="item.meta?.icon"><component :is="item.meta.icon" /></el-icon>
<template #title>{{ item.meta.title }}</template>
</el-menu-item>
@@ -32,11 +31,12 @@
defineOptions({ name: "standardMenu" })
const route = useRoute();
const {mode="vertical",menuList,isCollapse,activeMenu} = defineProps<{
const {mode="vertical",menuList,isCollapse,activeMenu,menuClass} = defineProps<{
mode?: 'vertical' | 'horizontal'
menuList: any[]
isCollapse?:boolean
activeMenu?: string
menuClass?: string
}>()
const emit = defineEmits<{
@@ -112,7 +112,7 @@ const handleMenuSelect = (index: string) => {
display: inline-block;
white-space: nowrap;
width: auto;
max-width: 1000px; // 设置一个足够大的值
max-width: 1000px;
overflow: hidden;
transition: max-width 0.25s, opacity 0.25s, width 0.25s;
opacity: 1;
@@ -150,5 +150,43 @@ const handleMenuSelect = (index: string) => {
flex-shrink: 0;
transition: none;
}
// 菜单样式类
.mj-top_menu{
--el-menu-hover-bg-color:transparent;
--el-menu-active-color:var(--el-color-primary);
--el-menu-text-color:#62748E;
}
.mj-aside_menu{
--el-menu-hover-bg-color:#F8FAFC;
--el-menu-item-height:46px;
--el-menu-item-padding:20px;
--el-menu-item-border-color:#DBEAFE;
--el-menu-item-active-color:#EFF6FF;
padding: 0 12px;
.el-menu-item{
margin-bottom: 3px;
}
.el-menu-item.is-active{
background-color: var(--el-menu-item-active-color);
border: 1px solid var(--el-menu-item-border-color);
border-radius: var(--el-menu-item-padding);
}
.el-menu-item:hover{
border-radius: var(--el-menu-item-padding);
transition: transform .12s ease;
.el-icon{
transform: scale(1.08);
}
}
}
// 收缩菜单样式
.el-menu--collapse{
--el-menu-hover-bg-color:transparent;
--el-menu-item-border-color:transparent;
--el-menu-item-active-color:transparent;
}
}
</style>

View File

@@ -12,7 +12,7 @@
{{ topTitle }}
</div>
<standardMenu
class="mj-aside_menu"
menu-class="mj-aside_menu"
:isCollapse="isCollapse"
:menuList="sideMenuList"
:active-menu="selectedActiveMenu"
@@ -27,14 +27,15 @@
</el-aside>
<el-container>
<el-header class="mj-header-content">
<!-- 左侧的菜单展示 -->
<!-- 顶部左侧的菜单展示 -->
<standardMenu
menu-class="mj-top_menu"
:menuList="topLevelMenuList"
mode="horizontal"
:active-menu="selectedTopMenu"
@menu-select="handleTopMenuSelect"
/>
<!-- 右侧用户的内容 -->
<!-- 顶部右侧用户的内容 -->
<rightMenuGroup @on-stage-manage="(path)=>handleTopMenuSelect(path)" />
</el-header>
<el-main class="mj-main-backend-content">
@@ -96,7 +97,15 @@ const menuList = computed(() => {
const topLevelMenuList = computed(() => {
return menuList.value.map((item) => {
const { children, ...rest } = item;
return rest;
const hasChildren = children && Array.isArray(children) && children.length > 0;
const enhancedMeta = {
...rest.meta,
disabled: !hasChildren
};
return {
...rest,
meta: enhancedMeta
};
}).filter(itv=>itv.name !== 'stage');
});
@@ -272,7 +281,7 @@ onUnmounted(() => {
.mj-aside-title {
font-size: 10px;
color: #888;
padding: 10px var(--el-menu-base-level-padding);
padding: 10px calc(var(--el-menu-base-level-padding) + 16px);
transition: opacity 0.3s;
}
}

View File

@@ -19,7 +19,7 @@
placeholder="搜索字段名称..."
class="custom-search-input auto-expand-input"
:prefix-icon="Search"
@keyup.enter="onConfirmSuccess"
@keyup.enter="onSearchData"
/>
</div>
<!-- 状态筛选的内容 -->
@@ -55,7 +55,7 @@
<el-option
:label="item.label"
:value="item.value"
v-for="(item, index) in DictManage.statusOptions"
v-for="(item, index) in dicts.permission_list_enable_disable"
:key="index"
/>
</el-select>
@@ -64,7 +64,7 @@
<el-button
type="primary"
class="apply-btn"
@click="onConfirmSuccess"
@click="onSearchData"
>应用筛选</el-button
>
</div>
@@ -86,19 +86,9 @@
<!-- Table列表 -->
<CommonTable
ref="tableRef"
:data="list"
:columns="columns"
:total="total"
:request-api="fetchData"
>
<!-- 名称点击 -->
<!-- <template #labelName="{ row }">
<el-button link type="primary" @click="onLevelNext(row)" v-if="!hasChild">{{
row.label
}}</el-button>
<span v-else>{{ row.label }}</span>
</template> -->
</CommonTable>
<!-- 新增字段 -->
<dictFieldLevelManage
@@ -126,6 +116,7 @@ import dictFieldLevelManage from "./dictFieldLevelManage.vue";
import { DictManage } from "@/dict";
import { useTableAction } from "@/hooks/useTableAction";
import { useDict } from "@/hooks/useDictData";
// import { formatIndex } from "@/utils/utils";
const { dicts, refresh } = useDict("permission_list_enable_disable");
import {
@@ -149,8 +140,6 @@ const tableRef = ref(null);
const { handleAction, handleDelete: runDelete } = useTableAction(tableRef);
const visible = ref<boolean>(false);
const parentId = ref<string>("");
const total = ref(0);
const list = ref([]);
const hasChild = ref<boolean>(false); //是否是子级弹窗
const childId = ref<string | number>(""); // 子集的id
const childModals = ref([]); //子弹窗的列表
@@ -160,7 +149,7 @@ const columns = computed(() => [
{
prop: "id",
align:'center',
label: "字典编码",
label: "字典编码"
},
{
prop: "label",
@@ -341,10 +330,15 @@ const onCloseFilter = () => {
filterForm.status = "";
};
// 筛选
const onSearchData = () =>{
tableRef.value?.refresh();
}
// 筛选重置
const onReset = () => {
onCloseFilter();
onConfirmSuccess();
onSearchData();
};
// 添加二级字段

View File

@@ -66,8 +66,6 @@
<CommonTable
ref="dictTableRef"
:columns="columns"
:data="dataValue"
:total="total"
:request-api="getTableData"
>
</CommonTable>
@@ -109,7 +107,6 @@ const dictTableRef = ref(null);
const { handleAction, handleDelete: runDelete } = useTableAction(dictTableRef);
const dictVisible = ref<boolean>(false);
const searchVal = ref<string>("");
const total = ref<number>(0);
const filterForm = reactive({
status: "",
@@ -208,9 +205,6 @@ const columns = [
},
];
// 返回的data数据信息
const dataValue = ref([]);
// popover关闭事件
const onPopoverHide = () => {
filterForm.status = "";
@@ -275,14 +269,14 @@ const onConfirmSuccess = async () => {
Promise.resolve(true),
selectItem.id,
getTableData,
{ showMsg: false, silentUpdate: true }
{ showMsg: false }
);
}
else {
dictTableRef.value?.refresh();
}
};
// TODO:字段配置
// 字段配置
const handlefieldsConfig = (ite) => {
fieldsConfigRef.value.open({ ...ite, parentId: ite.id });
};

View File

@@ -31,39 +31,8 @@
<CommonTable
ref="tableRef"
:columns="tableColumns"
v-model:data="dataList"
v-model:total="total"
pagination
:request-api="getTableData"
>
<!-- 状态 -->
<template #status="{ row }">
<div
class="mj-status-dot"
:style="{
'--data-status-color': DictManage.statusDictColor[row.status],
}"
@click="handleDictStatus(row)"
>
{{ dicts.permission_list_enable_disable.find(item=>item.value == row.status)?.label }}
</div>
</template>
<!-- 类型 -->
<template #type="{ row }">
<el-tag type="primary">{{ row.type }}</el-tag>
</template>
<!-- 成员数量 -->
<template #member="{ row }">
<el-button
link
icon="UserFilled"
type="primary"
@click.stop="addMember(row)"
>{{ row.memberCount }}</el-button
>
</template>
</CommonTable>
</div>
@@ -82,16 +51,19 @@
/>
<!-- 权限抽屉 -->
<permission-drawer v-model:visible="showPermission" :checkAuth="selectMember"/>
<permission-drawer
v-model:visible="showPermission"
:checkAuth="selectMember"
/>
</template>
<script setup lang="ts">
import dayjs from "dayjs";
import CommonTable from "@/components/proTable/index.vue";
import CommonTable from "@/components/proTable/proTablev2.vue";
import memberSelector from "@/components/memberSelector/index.vue";
import addRoles from "./addRoles.vue";
import permissionDrawer from "./permissionDrawer.vue";
import { DictManage } from "@/dict";
import { useDict } from '@/hooks/useDictData';
import { useDict } from "@/hooks/useDictData";
import { formatIndex } from "@/utils/utils";
import {
getRoleList,
@@ -103,15 +75,16 @@ import {
disableRole,
getRoleMemberList,
copyRolePermission,
batchSaveRole
batchSaveRole,
} from "@/api/stage/permission/index.ts";
import { useLocalManager } from "@/hooks/useLocalManager";
import { useTableAction } from "@/hooks/useTableAction";
defineOptions({ name: "PermissionManagement" });
const { dicts,refresh } = useDict('permission_list_enable_disable');
const { dicts, refresh } = useDict("permission_list_enable_disable");
const activeTab = ref(1);
const tableRef = ref(null);
const { handleAction, handleDelete } = useTableAction(tableRef);
const searchVal = ref("");
const dataList = ref([]);
const memberList = ref([]); // 获取成员角色列表
const total = ref(0);
const showMember = ref(false);
@@ -134,61 +107,78 @@ const roleColumns = [
label: "编号",
width: "80",
align: "center",
formatter: (val) => {
return `#${formatIndex(val.id)}`;
render: ({ rowData, rowIndex }) => {
return h("span", `#${formatIndex(rowIndex)}`);
},
},
{
prop: "name",
label: "角色名称",
align: "center",
showOverflowTooltip: true,
valueType: "ellipsis",
width: 150,
},
{
prop: "memberCount",
label: "成员数量",
align: "center",
slot: "member",
render: ({ rowData }: any) => {
return h(
ElButton,
{
type: "primary",
link: true,
icon: "UserFilled",
onClick: (e) => {
e.stopPropagation();
addMember(rowData);
},
},
() => rowData.memberCount
);
},
},
{
prop: "permissionCount",
label: "权限数量",
align: "center",
formatter: (val) => {
return val.permissionCount ? `${val.permissionCount}` : "-";
},
render:({rowData})=>{
return h('span',rowData.permissionCount ? `${rowData.permissionCount}` : "-")
}
},
{
prop: "status",
label: "状态",
align: "center",
slot: "status",
valueType: "status",
options: computed(() => dicts.value.permission_list_enable_disable),
onClick: ({ cellValue, rowData }) => {
handleDictStatus(rowData);
},
},
{
prop: "type",
label: "角色类型",
align: "center",
slot: "type",
render: ({ rowData }: any) => {
return h(ElTag, { size: "small" }, () => rowData.type);
},
},
{
prop: "positionIds",
label: "关联岗位",
align: "center",
showOverflowTooltip: true,
formatter: (val) => {
return val.positionIds ? val.positionIds.join(",") : "-";
valueType: "ellipsis",
render: ({ rowData, rowIndex }) => {
return h("span", rowData.positionIds ? rowData.positionIds.join(",") : "-");
},
},
{
prop: "updateTime",
label: "更新时间",
align: "center",
showOverflowTooltip: true,
formatter: (val) => {
return val.updateTime
? dayjs(val.updateTime).format("YYYY-MM-DD HH:mm")
: "-";
},
valueType: "date",
format: "YYYY-MM-DD HH:mm",
},
{
prop: "updater",
@@ -199,8 +189,7 @@ const roleColumns = [
prop: "actions",
label: "操作",
align: "right",
fixed: "right",
width: "200",
width: 200,
actions: [
{
label: "权限",
@@ -209,7 +198,7 @@ const roleColumns = [
permission: ["*"],
onClick: (row) => {
showPermission.value = true;
selectMember.value = {...row};
selectMember.value = { ...row };
},
},
{
@@ -234,7 +223,7 @@ const roleColumns = [
permission: ["*"],
onClick: (row) => {
showRoles.value = true;
selectMember.value = {...row};
selectMember.value = { ...row };
},
},
{
@@ -242,7 +231,7 @@ const roleColumns = [
type: "danger",
link: true,
permission: ["*"],
disabledFn: (row) => {
disabled: (row) => {
return row.type !== "SYSTEM";
},
onClick: async (row) => {
@@ -251,12 +240,9 @@ const roleColumns = [
cancelButtonText: "取消",
type: "warning",
})
.then(() => {
.then(async () => {
try {
deleteRole(row.id).then(() => {
ElMessage.success("删除成功");
tableRef.value.refresh();
});
await handleDelete(deleteRole,row.id)
} catch (error) {
console.log("error", error);
}
@@ -280,7 +266,7 @@ const tableColumns = computed(() => {
// 当前成员数量
const addMember = (row) => {
showMember.value = true;
selectMember.value = {...row};
selectMember.value = { ...row };
getMemberList({ id: row.id });
};
@@ -289,34 +275,29 @@ const handleSaveMember = async (row) => {
const { id } = selectMember.value;
const userIds = memberList.value.map((item) => item.id);
try {
await batchSaveRole(id,{userIds})
ElMessage.success("保存成功");
const currentRow = dataList.value.find(item => item.id === id);
if (currentRow) {
currentRow.memberCount = memberList.value.length;
}
await handleAction(()=>batchSaveRole(id,{userIds}),id, getTableData);
} catch (error) {
console.log('batch save error',error);
console.log("batch save error", error);
}
};
// 刷新列表
const onRefresh = () => {
tableRef.value && tableRef.value.reset();
tableRef.value && tableRef.value.refresh();
};
// 监听Tabs变化
watch(activeTab, () => {
dataList.value = [];
tableRef.value && tableRef.value.reset();
});
// 监听Tabs变化(目前暂时先用不到)
// watch(activeTab, () => {
// dataList.value = [];
// tableRef.value && tableRef.value.refresh();
// });
// 启用-停用
const handleDictStatus = async (row) => {
try {
row.status === 1 ? await disableRole(row.id) : await enableRole(row.id);
ElMessage.success("操作成功");
onRefresh();
// row.status === 1 ? await disableRole(row.id) : await enableRole(row.id);
const apiCall = row.status === 1 ? disableRole(row.id) : enableRole(row.id);
await handleAction(apiCall, row.id, getTableData);
} catch (error) {
console.log("error", error);
}
@@ -327,8 +308,7 @@ const getTableData = async (params) => {
// 正式请求
const queryParams = {
...(searchVal.value && { name: searchVal.value }),
pageNo: 1,
pageSize: 10,
...params
};
try {
const res = await getRoleList(queryParams);
@@ -340,7 +320,6 @@ const getTableData = async (params) => {
// 后面会修改成全部获取获取成员角色列表
const getMemberList = async (params) => {
try {
const response = await getRoleMemberList(params.id);
memberList.value = response;
@@ -369,14 +348,9 @@ const checkRolesText = computed(() => {
const addBtnClick = () => {
if (activeTab.value === 1) {
showRoles.value = true;
selectMember.value = {id:''}
selectMember.value = { id: "" };
}
};
// 初始化
onMounted(() => {
refresh();
});
</script>
<style lang="scss" scoped>
.mj-permission-management {

View File

@@ -103,9 +103,11 @@ const roleDetail = async (roleId) =>{
const response = await getRolePermission(roleId);
menuList.value = response.map(group => {
const checkedGroup = (group.children || []).filter(c => c.selected);
const allCheckedGroup = (group.children || []).every(c => c.selected); //兼容后端全选后返回为false的问题
const checkedCount = checkedGroup.length;
return {
...group,
selected:allCheckedGroup,
isIndeterminate: checkedCount > 0 && checkedCount < group.children.length,
children:(group.children||[]).map(child=>{
const actions = child.selected ? child.operations.filter(action => action.selected).map(action => action.id) : [];

View File

@@ -1,27 +1,12 @@
<template>
<div class="personnel">
<el-drawer
v-model="drawer"
size="80%"
title="测试评论"
:close-on-click-modal="false"
:close-on-press-escape="false"
destroy-on-close
class="standard-ui-back-drawer"
>
<div style="padding: 20px;height:100%">
<Comment />
</div>
</el-drawer>
人员管理
</div>
</template>
<script setup lang="ts">
import Comment from "@/modules/Comment/index.vue";
defineOptions({ name: "Personnel" });
const drawer = ref(true);
</script>
<style lang="scss" scoped>
.personnel {
height: 100%;
}
</style>

View File

@@ -164,12 +164,14 @@ const addDynamicRoutes = async () => {
try {
const { modules:backendRawData } = await getUserInfo();
const allRoutes = transformBackendTree(backendRawData);
// console.log('获取最终渲染的菜单数据格式:',allRoutes);
console.log('获取最终渲染的菜单数据格式:',allRoutes);
if (allRoutes) {
// 转换路由数据
const dynamicRoutes = transformRoutes(
Array.isArray(allRoutes) ? allRoutes : [allRoutes]
);
console.log('最终渲染的菜单数据:',dynamicRoutes)
// 将动态路由添加到 Layout 的 children 中
const layoutRoute = router
.getRoutes()

View File

@@ -15,8 +15,27 @@ const businessRoute = {
"business.opportunity":"businessOpport",
}
const contractRoute = {
contract: "contractManage",
}
const teamRoute = {
team: "teamManage",
}
const financeRoute = {
finance: "financeManage",
}
const recruitmentRoute = {
recruitment: "recruitmentManage",
}
export const componentMap: Record<string, string> = {
...stageRoute,
...businessRoute
...businessRoute,
...contractRoute,
...teamRoute,
...financeRoute,
...recruitmentRoute
};

View File

@@ -203,5 +203,6 @@ body {
text-overflow: ellipsis;
white-space: nowrap;
word-break: break-all;
display: block;
cursor: default;
}

View File

@@ -15,13 +15,16 @@ export const usePermission = () => {
const userPermissions = appStore.role;
const permissionArray = Array.isArray(requiredPermissions) ? requiredPermissions : [requiredPermissions];
// 为*跳过权限校验
const isSkipCheck = requiredPermissions === "*" || (permissionArray && permissionArray.includes("*"));
if (isSkipCheck) {return true;}
const hasPermission = permissionArray.some((permission) =>
userPermissions.includes(permission)
);
return hasPermission;
};
return { checkPermission };
};