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> <slot></slot>
</div> </div>
</el-popover> </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> <el-icon><Download /></el-icon>
</div> </div>
</div> </div>
@@ -53,6 +53,12 @@ defineExpose({
filterPopover.value?.hide() filterPopover.value?.hide()
}, },
}); });
const onDownload = () => {
ElMessage.warning("功能开发中...");
emit("download");
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

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

View File

@@ -2,8 +2,7 @@
<div class="mj-standard-menu"> <div class="mj-standard-menu">
<el-menu <el-menu
:default-active="activeIndex" :default-active="activeIndex"
:active-text-color="mode === 'horizontal' ? '#409EFF' : undefined" :class="['mj-menu',menuClass]"
class="mj-menu"
:mode="mode" :mode="mode"
:collapse="isCollapse" :collapse="isCollapse"
@select="handleMenuSelect" @select="handleMenuSelect"
@@ -20,7 +19,7 @@
<template #title>{{ row.meta.title }}</template> <template #title>{{ row.meta.title }}</template>
</el-menu-item> </el-menu-item>
</el-sub-menu> </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> <el-icon v-if="item.meta?.icon"><component :is="item.meta.icon" /></el-icon>
<template #title>{{ item.meta.title }}</template> <template #title>{{ item.meta.title }}</template>
</el-menu-item> </el-menu-item>
@@ -32,11 +31,12 @@
defineOptions({ name: "standardMenu" }) defineOptions({ name: "standardMenu" })
const route = useRoute(); const route = useRoute();
const {mode="vertical",menuList,isCollapse,activeMenu} = defineProps<{ const {mode="vertical",menuList,isCollapse,activeMenu,menuClass} = defineProps<{
mode?: 'vertical' | 'horizontal' mode?: 'vertical' | 'horizontal'
menuList: any[] menuList: any[]
isCollapse?:boolean isCollapse?:boolean
activeMenu?: string activeMenu?: string
menuClass?: string
}>() }>()
const emit = defineEmits<{ const emit = defineEmits<{
@@ -112,7 +112,7 @@ const handleMenuSelect = (index: string) => {
display: inline-block; display: inline-block;
white-space: nowrap; white-space: nowrap;
width: auto; width: auto;
max-width: 1000px; // 设置一个足够大的值 max-width: 1000px;
overflow: hidden; overflow: hidden;
transition: max-width 0.25s, opacity 0.25s, width 0.25s; transition: max-width 0.25s, opacity 0.25s, width 0.25s;
opacity: 1; opacity: 1;
@@ -150,5 +150,43 @@ const handleMenuSelect = (index: string) => {
flex-shrink: 0; flex-shrink: 0;
transition: none; 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> </style>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,27 +1,12 @@
<template> <template>
<div class="personnel"> <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> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import Comment from "@/modules/Comment/index.vue";
defineOptions({ name: "Personnel" }); defineOptions({ name: "Personnel" });
const drawer = ref(true); const drawer = ref(true);
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.personnel {
height: 100%;
}
</style> </style>

View File

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

View File

@@ -15,8 +15,27 @@ const businessRoute = {
"business.opportunity":"businessOpport", "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> = { export const componentMap: Record<string, string> = {
...stageRoute, ...stageRoute,
...businessRoute ...businessRoute,
...contractRoute,
...teamRoute,
...financeRoute,
...recruitmentRoute
}; };

View File

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

View File

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