feat: 添加权限管理

This commit is contained in:
2025-02-11 16:37:08 +08:00
parent 0cb6c80d57
commit 6de042b07e
27 changed files with 6095 additions and 94 deletions

View File

@@ -12,7 +12,7 @@ defineOptions({
* 表单
*/
interface FormItemProps {
higherDeptOptions: Record<string, unknown>[];
higherOptions: Record<string, unknown>[];
id: string;
parent_id: string;
name: string;
@@ -61,7 +61,7 @@ const formRules = reactive<FormRules>({
const props = withDefaults(defineProps<FormProps>(), {
formInline: () => ({
id: "",
higherDeptOptions: [],
higherOptions: [],
parent_id: "",
name: "",
principal: "",
@@ -97,7 +97,7 @@ defineExpose({ getRef });
<el-cascader
v-model="newFormInline.parent_id"
class="w-full"
:options="newFormInline.higherDeptOptions"
:options="newFormInline.higherOptions"
:props="{
value: 'id',
label: 'name',

View File

@@ -4,7 +4,6 @@ import { handleTree } from "@/utils/tree";
import { message } from "@/utils/message";
import { addDialog } from "@/components/ReDialog";
import { reactive, ref, onMounted, h } from "vue";
import type { FormItemProps } from "../utils/types";
import { cloneDeep } from "@pureadmin/utils";
import type { DepartmentInfo } from "types/system";
import { usePublicHooks } from "../../hooks";
@@ -51,7 +50,7 @@ export const useDepartment = () => {
/**
* 标签样式
*/
const { tagStyle, formatHigherDeptOptions } = usePublicHooks();
const { tagStyle } = usePublicHooks();
/**
* 表格列设置
*/
@@ -126,13 +125,23 @@ export const useDepartment = () => {
formEl.resetFields();
onSearch();
};
const openDialog = (title = "新增", row?: FormItemProps) => {
const formatHigherOptions = treeList => {
// 根据返回数据的status字段值判断追加是否禁用disabled字段返回处理后的树结构用于上级部门级联选择器的展示实际开发中也是如此不可能前端需要的每个字段后端都会返回这时需要前端自行根据后端返回的某些字段做逻辑处理
if (!treeList || !treeList.length) return;
const newTreeList = [];
for (let i = 0; i < treeList.length; i++) {
treeList[i].disabled = treeList[i].status === 0 ? true : false;
formatHigherOptions(treeList[i].children);
newTreeList.push(treeList[i]);
}
return newTreeList;
};
const openDialog = (title = "新增", row?: DepartmentInfo) => {
addDialog({
title: `${title}部门`,
props: {
formInline: {
higherDeptOptions: formatHigherDeptOptions(cloneDeep(dataList.value)),
higherDeptOptions: formatHigherOptions(cloneDeep(dataList.value)),
id: row?.id ?? "",
parent_id: row?.parent_id ?? "",
name: row?.name ?? "",
@@ -151,9 +160,7 @@ export const useDepartment = () => {
contentRenderer: () =>
h(editForm, {
formInline: {
higherDeptOptions: formatHigherDeptOptions(
cloneDeep(dataList.value)
),
higherOptions: formatHigherOptions(cloneDeep(dataList.value)),
id: row?.id ?? "",
parent_id: row?.parent_id ?? "",
name: row?.name ?? "",
@@ -168,7 +175,7 @@ export const useDepartment = () => {
}),
beforeSure: (done, { options }) => {
const FormRef = formRef.value.getRef();
const curData = options.props.formInline as FormItemProps;
const curData = options.props.formInline as DepartmentInfo;
function chores() {
message(`${title}了部门名称为${curData.name}的这条数据`, {
type: "success"

View File

@@ -28,26 +28,12 @@ export function usePublicHooks() {
};
});
const formatHigherDeptOptions = treeList => {
// 根据返回数据的status字段值判断追加是否禁用disabled字段返回处理后的树结构用于上级部门级联选择器的展示实际开发中也是如此不可能前端需要的每个字段后端都会返回这时需要前端自行根据后端返回的某些字段做逻辑处理
if (!treeList || !treeList.length) return;
const newTreeList = [];
for (let i = 0; i < treeList.length; i++) {
treeList[i].disabled = treeList[i].status === 0 ? true : false;
formatHigherDeptOptions(treeList[i].children);
newTreeList.push(treeList[i]);
}
return newTreeList;
};
return {
/** 当前网页是否为`dark`模式 */
isDark,
/** 表现更鲜明的`el-switch`组件 */
switchStyle,
/** 表现更鲜明的`el-tag`组件 */
tagStyle,
/** 获取上级部门级联选择器的数据结构*/
formatHigherDeptOptions
tagStyle
};
}

View File

@@ -44,10 +44,10 @@
:loading="loading"
@click="onSearch"
>
搜索
{{ t("buttons:Search") }}
</el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)">
重置
{{ t("buttons:Reset") }}
</el-button>
</el-form-item>
</el-form>
@@ -58,7 +58,7 @@
:icon="useRenderIcon(AddFill)"
@click="openDialog('新增')"
>
新增
{{ t("buttons:Add") }}
</el-button>
</template>
<template v-slot="{ size, dynamicColumns }">
@@ -116,7 +116,7 @@
:icon="useRenderIcon(EditPen)"
@click="openDialog('修改', row)"
>
修改
{{ t("buttons:Update") }}
</el-button>
<el-popconfirm
:title="`是否确认删除国际化key为 ${row.key} 的这条数据`"
@@ -130,7 +130,7 @@
:size="size"
:icon="useRenderIcon(Delete)"
>
删除
{{ t("buttons:Delete") }}
</el-button>
</template>
</el-popconfirm>
@@ -147,12 +147,14 @@ defineOptions({
});
import { ref } from "vue";
import { useI18n } from "./hook";
import { useI18n as i18n } from "vue-i18n";
import { PureTableBar } from "@/components/RePureTableBar";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import Delete from "@iconify-icons/ep/delete";
import EditPen from "@iconify-icons/ep/edit-pen";
import Refresh from "@iconify-icons/ep/refresh";
import AddFill from "@iconify-icons/ri/add-circle-line";
const { t } = i18n();
/**
* 表格Ref
*/

View File

@@ -75,7 +75,7 @@ export const useLocale = (tableRef: Ref) => {
{
label: "操作",
fixed: "right",
width: 200,
width: 250,
slot: "operation"
}
];

View File

@@ -29,10 +29,10 @@
:loading="loading"
@click="onSearch"
>
搜索
{{ t("buttons:Search") }}
</el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)">
重置
{{ t("buttons:Reset") }}
</el-button>
</el-form-item>
</el-form>
@@ -43,7 +43,7 @@
:icon="useRenderIcon(AddFill)"
@click="openDialog('新增')"
>
新增
{{ t("buttons:Add") }}
</el-button>
</template>
<template v-slot="{ size, dynamicColumns }">
@@ -101,7 +101,7 @@
:icon="useRenderIcon(EditPen)"
@click="openDialog('修改', row)"
>
修改
{{ t("buttons:Update") }}
</el-button>
<el-popconfirm
:title="`是否确认导出语言名称为 ${row.name} 的这条数据为yaml文件`"
@@ -115,7 +115,7 @@
:size="size"
:icon="useRenderIcon(Download)"
>
导出
{{ t("buttons:Export") }}
</el-button>
</template>
</el-popconfirm>
@@ -131,7 +131,7 @@
:size="size"
:icon="useRenderIcon(Delete)"
>
删除
{{ t("buttons:Delete") }}
</el-button>
</template>
</el-popconfirm>
@@ -150,11 +150,13 @@ import { ref } from "vue";
import { useLocale } from "./hook";
import { PureTableBar } from "@/components/RePureTableBar";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { useI18n } from "vue-i18n";
import Delete from "@iconify-icons/ep/delete";
import EditPen from "@iconify-icons/ep/edit-pen";
import Refresh from "@iconify-icons/ep/refresh";
import AddFill from "@iconify-icons/ri/add-circle-line";
import Download from "@iconify-icons/ri/file-download-line";
const { t } = useI18n();
/**
* 表格Ref
*/

View File

@@ -0,0 +1,511 @@
<script setup lang="ts">
import { reactive, ref } from "vue";
import ReCol from "@/components/ReCol";
import { transformI18n } from "@/plugins/i18n";
import { IconSelect } from "@/components/ReIcon";
import Segmented, { OptionsType } from "@/components/ReSegmented";
import ReAnimateSelector from "@/components/ReAnimateSelector";
import type { FormRules } from "element-plus";
const menuTypeOptions: Array<OptionsType> = [
{
label: "菜单",
value: 0
},
{
label: "iframe",
value: 1
},
{
label: "外链",
value: 2
},
{
label: "按钮",
value: 3
}
];
const showLinkOptions: Array<OptionsType> = [
{
label: "显示",
tip: "会在菜单中显示",
value: true
},
{
label: "隐藏",
tip: "不会在菜单中显示",
value: false
}
];
const fixedTagOptions: Array<OptionsType> = [
{
label: "固定",
tip: "当前菜单名称固定显示在标签页且不可关闭",
value: true
},
{
label: "不固定",
tip: "当前菜单名称不固定显示在标签页且可关闭",
value: false
}
];
const keepAliveOptions: Array<OptionsType> = [
{
label: "缓存",
tip: "会保存该页面的整体状态,刷新后会清空状态",
value: true
},
{
label: "不缓存",
tip: "不会保存该页面的整体状态",
value: false
}
];
const hiddenTagOptions: Array<OptionsType> = [
{
label: "允许",
tip: "当前菜单名称或自定义信息允许添加到标签页",
value: false
},
{
label: "禁止",
tip: "当前菜单名称或自定义信息禁止添加到标签页",
value: true
}
];
const showParentOptions: Array<OptionsType> = [
{
label: "显示",
tip: "会显示父级菜单",
value: true
},
{
label: "隐藏",
tip: "不会显示父级菜单",
value: false
}
];
const frameLoadingOptions: Array<OptionsType> = [
{
label: "开启",
tip: "有首次加载动画",
value: true
},
{
label: "关闭",
tip: "无首次加载动画",
value: false
}
];
interface FormItemProps {
/** 菜单类型0代表菜单、1代表iframe、2代表外链、3代表按钮*/
id: string;
menu_type: number;
higherOptions: Record<string, unknown>[];
parent_id: string;
title: string;
name: string;
path: string;
component: string;
rank: number;
redirect: string;
icon: string;
extra_icon: string;
enter_transition: string;
leave_transition: string;
active_path: string;
auths: string | null;
frame_src: string;
frame_loading: boolean;
keep_alive: boolean;
hidden_tag: boolean;
fixed_tag: boolean;
show_link: boolean;
show_parent: boolean;
}
interface FormProps {
formInline: FormItemProps;
}
/** 自定义表单规则校验 */
const formRules = reactive<FormRules>({
title: [{ required: true, message: "菜单名称为必填项", trigger: "blur" }],
name: [{ required: true, message: "路由名称为必填项", trigger: "blur" }],
path: [{ required: true, message: "路由路径为必填项", trigger: "blur" }],
auths: [{ required: true, message: "权限标识为必填项", trigger: "blur" }]
});
defineOptions({
name: "SystemPermissionForm"
});
const props = withDefaults(defineProps<FormProps>(), {
formInline: () => ({
id: "",
menu_type: 0,
higherOptions: [],
parent_id: "",
title: "",
name: "",
path: "",
component: "",
rank: 99,
redirect: "",
icon: "",
extra_icon: "",
enter_transition: "",
leave_transition: "",
active_path: "",
auths: "",
frame_src: "",
frame_loading: true,
keep_alive: false,
hidden_tag: false,
fixed_tag: false,
show_link: true,
show_parent: false
})
});
const ruleFormRef = ref();
const newFormInline = ref(props.formInline);
function getRef() {
return ruleFormRef.value;
}
defineExpose({ getRef });
</script>
<template>
<el-form
ref="ruleFormRef"
:model="newFormInline"
:rules="formRules"
label-width="82px"
>
<el-row :gutter="30">
<re-col>
<el-form-item label="权限类型">
<Segmented
v-model="newFormInline.menu_type"
:options="menuTypeOptions"
/>
</el-form-item>
</re-col>
<re-col>
<el-form-item label="上级菜单">
<el-cascader
v-model="newFormInline.parent_id"
class="w-full"
:options="newFormInline.higherOptions"
:props="{
value: 'id',
label: 'title',
emitPath: false,
checkStrictly: true
}"
clearable
filterable
placeholder="请选择上级菜单"
>
<template #default="{ node, data }">
<span>{{ transformI18n(data.title) }}</span>
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
</template>
</el-cascader>
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<el-form-item label="菜单名称" prop="title">
<el-input
v-model="newFormInline.title"
clearable
placeholder="请输入菜单名称"
/>
</el-form-item>
</re-col>
<re-col
v-if="newFormInline.menu_type !== 3"
:value="12"
:xs="24"
:sm="24"
>
<el-form-item label="路由名称" prop="name">
<el-input
v-model="newFormInline.name"
clearable
placeholder="请输入路由名称"
/>
</el-form-item>
</re-col>
<re-col
v-if="newFormInline.menu_type !== 3"
:value="12"
:xs="24"
:sm="24"
>
<el-form-item label="路由路径" prop="path">
<el-input
v-model="newFormInline.path"
clearable
placeholder="请输入路由路径"
/>
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<!-- 按钮级别权限设置 -->
<el-form-item label="权限标识" prop="auths">
<el-input
v-model="newFormInline.auths"
clearable
placeholder="请输入权限标识"
/>
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menu_type === 0"
:value="12"
:xs="24"
:sm="24"
>
<el-form-item label="组件路径">
<el-input
v-model="newFormInline.component"
clearable
placeholder="请输入组件路径"
/>
</el-form-item>
</re-col>
<re-col :value="12" :xs="24" :sm="24">
<el-form-item label="菜单排序">
<el-input-number
v-model="newFormInline.rank"
class="!w-full"
:min="1"
:max="9999"
controls-position="right"
/>
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menu_type === 0"
:value="12"
:xs="24"
:sm="24"
>
<el-form-item label="路由重定向">
<el-input
v-model="newFormInline.redirect"
clearable
placeholder="请输入默认跳转地址"
/>
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menu_type !== 3"
:value="12"
:xs="24"
:sm="24"
>
<el-form-item label="菜单图标">
<IconSelect v-model="newFormInline.icon" class="w-full" />
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menu_type !== 3"
:value="12"
:xs="24"
:sm="24"
>
<el-form-item label="右侧图标">
<el-input
v-model="newFormInline.extra_icon"
clearable
placeholder="菜单名称右侧的额外图标"
/>
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menu_type < 2"
:value="12"
:xs="24"
:sm="24"
>
<el-form-item label="进场动画">
<ReAnimateSelector
v-model="newFormInline.enter_transition"
placeholder="请选择页面进场加载动画"
/>
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menu_type < 2"
:value="12"
:xs="24"
:sm="24"
>
<el-form-item label="离场动画">
<ReAnimateSelector
v-model="newFormInline.leave_transition"
placeholder="请选择页面离场加载动画"
/>
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menu_type === 0"
:value="12"
:xs="24"
:sm="24"
>
<el-form-item label="菜单激活">
<el-input
v-model="newFormInline.active_path"
clearable
placeholder="请输入需要激活的菜单"
/>
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menu_type === 1"
:value="12"
:xs="24"
:sm="24"
>
<!-- iframe -->
<el-form-item label="链接地址">
<el-input
v-model="newFormInline.frame_src"
clearable
placeholder="请输入 iframe 链接地址"
/>
</el-form-item>
</re-col>
<re-col
v-if="newFormInline.menu_type === 1"
:value="12"
:xs="24"
:sm="24"
>
<el-form-item label="加载动画">
<Segmented
:modelValue="newFormInline.frame_loading ? 0 : 1"
:options="frameLoadingOptions"
@change="
({ option: { value } }) => {
newFormInline.frame_loading = value;
}
"
/>
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menu_type !== 3"
:value="12"
:xs="24"
:sm="24"
>
<el-form-item label="菜单">
<Segmented
:modelValue="newFormInline.show_link ? 0 : 1"
:options="showLinkOptions"
@change="
({ option: { value } }) => {
newFormInline.show_link = value;
}
"
/>
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menu_type !== 3"
:value="12"
:xs="24"
:sm="24"
>
<el-form-item label="父级菜单">
<Segmented
:modelValue="newFormInline.show_parent ? 0 : 1"
:options="showParentOptions"
@change="
({ option: { value } }) => {
newFormInline.show_parent = value;
}
"
/>
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menu_type < 2"
:value="12"
:xs="24"
:sm="24"
>
<el-form-item label="缓存页面">
<Segmented
:modelValue="newFormInline.keep_alive ? 0 : 1"
:options="keepAliveOptions"
@change="
({ option: { value } }) => {
newFormInline.keep_alive = value;
}
"
/>
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menu_type < 2"
:value="12"
:xs="24"
:sm="24"
>
<el-form-item label="标签页">
<Segmented
:modelValue="newFormInline.hidden_tag ? 1 : 0"
:options="hiddenTagOptions"
@change="
({ option: { value } }) => {
newFormInline.hidden_tag = value;
}
"
/>
</el-form-item>
</re-col>
<re-col
v-show="newFormInline.menu_type < 2"
:value="12"
:xs="24"
:sm="24"
>
<el-form-item label="固定标签页">
<Segmented
:modelValue="newFormInline.fixed_tag ? 0 : 1"
:options="fixedTagOptions"
@change="
({ option: { value } }) => {
newFormInline.fixed_tag = value;
}
"
/>
</el-form-item>
</re-col>
</el-row>
</el-form>
</template>

View File

@@ -0,0 +1,167 @@
<script setup lang="ts">
import { ref } from "vue";
import { usePermission } from "./utils/hook";
import { transformI18n } from "@/plugins/i18n";
import { PureTableBar } from "@/components/RePureTableBar";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import { useI18n } from "vue-i18n";
import Delete from "@iconify-icons/ep/delete";
import EditPen from "@iconify-icons/ep/edit-pen";
import Refresh from "@iconify-icons/ep/refresh";
import AddFill from "@iconify-icons/ri/add-circle-line";
import { onBeforeRouteUpdate } from "vue-router";
const { t } = useI18n();
defineOptions({
name: "SystemPermission"
});
/**
* 权限Ref
*/
const formRef = ref();
/**
* 表格Ref
*/
const tableRef = ref();
const {
form,
loading,
columns,
dataList,
onSearch,
resetForm,
openDialog,
handleDelete
} = usePermission();
onBeforeRouteUpdate((to, from, next) => {
onSearch();
next();
});
</script>
<template>
<div class="main">
<el-form
ref="formRef"
:inline="true"
:model="form"
class="search-form bg-bg_color w-[99/100] pl-8 pt-[12px]"
>
<el-form-item label="权限名称:" prop="title">
<el-input
v-model="form.title"
placeholder="请输入权限名称"
clearable
class="!w-[180px]"
/>
</el-form-item>
<el-form-item>
<el-button
type="primary"
:icon="useRenderIcon('ri:search-line')"
:loading="loading"
@click="onSearch"
>
{{ t("buttons:Search") }}
</el-button>
<el-button :icon="useRenderIcon(Refresh)" @click="resetForm(formRef)">
{{ t("buttons:Reset") }}
</el-button>
</el-form-item>
</el-form>
<PureTableBar
title="权限管理"
:columns="columns"
:isExpandAll="false"
:tableRef="tableRef?.getTableRef()"
@refresh="onSearch"
>
<template #buttons>
<el-button
type="primary"
:icon="useRenderIcon(AddFill)"
@click="openDialog()"
>
{{ t("buttons:Add") }}
</el-button>
</template>
<template v-slot="{ size, dynamicColumns }">
<pure-table
ref="tableRef"
adaptive
border
stripe
:adaptiveConfig="{ offsetBottom: 45 }"
align-whole="center"
row-key="id"
showOverflowTooltip
table-layout="auto"
:loading="loading"
:size="size"
:data="dataList"
:columns="dynamicColumns"
:header-cell-style="{
background: 'var(--el-fill-color-light)',
color: 'var(--el-text-color-primary)'
}"
>
<template #operation="{ row }">
<el-button
class="reset-margin"
link
type="primary"
:size="size"
:icon="useRenderIcon(EditPen)"
@click="openDialog('修改', row)"
>
{{ t("buttons:Update") }}
</el-button>
<el-button
v-show="row.menuType !== 3"
class="reset-margin"
link
type="primary"
:size="size"
:icon="useRenderIcon(AddFill)"
@click="openDialog('新增', { parent_id: row.id } as any)"
>
{{ t("buttons:Add") }}
</el-button>
<el-popconfirm
:title="`是否确认删除权限名称为${transformI18n(row.title)}的这条数据${row?.children?.length > 0 ? '。注意下级权限也会一并删除,请谨慎操作' : ''}`"
@confirm="handleDelete(row)"
>
<template #reference>
<el-button
class="reset-margin"
link
type="primary"
:size="size"
:icon="useRenderIcon(Delete)"
>
{{ t("buttons:Delete") }}
</el-button>
</template>
</el-popconfirm>
</template>
</pure-table>
</template>
</PureTableBar>
</div>
</template>
<style lang="scss" scoped>
:deep(.el-table__inner-wrapper::before) {
height: 0;
}
.main-content {
margin: 24px 24px 0 !important;
}
.search-form {
:deep(.el-form-item) {
margin-bottom: 12px;
}
}
</style>

View File

@@ -0,0 +1,344 @@
import editForm from "../components/form.vue";
import { handleTree } from "@/utils/tree";
import { message } from "@/utils/message";
import {
deletePermissionAPI,
getPermissionListAPI,
postAddPermissionAPI,
putUpdatePermissionAPI
} from "@/api/system";
import { transformI18n } from "@/plugins/i18n";
import { addDialog } from "@/components/ReDialog";
import { reactive, ref, onMounted, h } from "vue";
import { cloneDeep, isAllEmpty, deviceDetection } from "@pureadmin/utils";
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import type { PermissionInfo } from "types/system";
export const usePermission = () => {
/**
* 表单
*/
const form = reactive({
title: ""
});
/**
* 表单Ref
*/
const formRef = ref();
/**
* 数据列表
*/
const dataList = ref<PermissionInfo[]>([]);
/**
* 加载状态
*/
const loading = ref(true);
/**
* 获取菜单类型
* @param type 菜单类型
* @param text 文本
* @returns
*/
const getMenuType = (type, text = false) => {
switch (type) {
case 0:
return text ? "菜单" : "primary";
case 1:
return text ? "iframe" : "warning";
case 2:
return text ? "外链" : "danger";
case 3:
return text ? "按钮" : "info";
}
};
/**
* 表格数据
*/
const columns: TableColumnList = [
{
label: "权限名称",
prop: "title",
align: "left",
cellRenderer: ({ row }) => (
<>
<span class="inline-block mr-1">
{h(useRenderIcon(row.icon), {
style: { paddingTop: "1px" }
})}
</span>
<span>{transformI18n(row.title)}</span>
</>
)
},
{
label: "权限类型",
prop: "menu_type",
cellRenderer: ({ row, props }) => (
<el-tag
size={props.size}
type={getMenuType(row.menu_type)}
effect="plain"
>
{getMenuType(row.menu_type, true)}
</el-tag>
)
},
{
label: "路由路径",
prop: "path"
},
{
label: "组件路径",
prop: "component",
formatter: ({ path, component }) =>
isAllEmpty(component) ? path : component
},
{
label: "权限标识",
prop: "auths"
},
{
label: "排序",
prop: "rank",
width: 100
},
{
label: "隐藏",
prop: "show_link",
formatter: ({ show_link }) => (show_link ? "否" : "是"),
width: 100
},
{
label: "操作",
fixed: "right",
width: 230,
slot: "operation"
}
];
/**
* 搜索
*/
const onSearch = async () => {
loading.value = true; // 这里是返回一维数组结构前端自行处理成树结构返回格式要求唯一id加父节点parentIdparentId取父节点id
const res = await getPermissionListAPI({
page: 1,
pageSize: 9999,
...form
});
if (res.success) {
let newData = res.data.result;
dataList.value = handleTree(newData, "id", "parent_id"); // 处理成树结构
}
setTimeout(() => {
loading.value = false;
}, 500);
};
/**
* 重置表单
* @param formEl
* @returns
*/
const resetForm = formEl => {
if (!formEl) return;
formEl.resetFields();
onSearch();
};
const formatHigherOptions = treeList => {
if (!treeList || !treeList.length) return;
const newTreeList = [];
for (let i = 0; i < treeList.length; i++) {
treeList[i].title = transformI18n(treeList[i].title);
formatHigherOptions(treeList[i].children);
newTreeList.push(treeList[i]);
}
return newTreeList;
};
const openDialog = (title = "新增", row?: PermissionInfo) => {
addDialog({
title: `${title}权限`,
props: {
formInline: {
id: row?.id ?? "",
higherOptions: formatHigherOptions(cloneDeep(dataList.value)),
parent_id: row?.parent_id ?? "",
title: row?.title ?? "",
menu_type: row?.menu_type ?? 0,
name: row?.name ?? "",
path: row?.path ?? "",
component: row?.component ?? "",
rank: row?.rank ?? 99,
redirect: row?.redirect ?? "",
icon: row?.icon ?? "",
extra_icon: row?.extra_icon ?? "",
enter_transition: row?.enter_transition ?? "",
leave_transition: row?.leave_transition ?? "",
active_path: row?.active_path ?? "",
auths: row?.auths ?? "",
frame_src: row?.frame_src ?? "",
frame_loading: row?.frame_loading ?? true,
keep_alive: row?.keep_alive ?? false,
hidden_tag: row?.hidden_tag ?? false,
fixed_tag: row?.fixed_tag ?? false,
show_link: row?.show_link ?? true,
show_parent: row?.show_parent ?? false
}
},
width: "45%",
draggable: true,
fullscreen: deviceDetection(),
fullscreenIcon: true,
closeOnClickModal: false,
contentRenderer: () =>
h(editForm, {
ref: formRef,
formInline: {
id: row?.id ?? "",
higherOptions: formatHigherOptions(cloneDeep(dataList.value)),
parent_id: row?.parent_id ?? "",
title: row?.title ?? "",
menu_type: row?.menu_type ?? 0,
name: row?.name ?? "",
path: row?.path ?? "",
component: row?.component ?? "",
rank: row?.rank ?? 99,
redirect: row?.redirect ?? "",
icon: row?.icon ?? "",
extra_icon: row?.extra_icon ?? "",
enter_transition: row?.enter_transition ?? "",
leave_transition: row?.leave_transition ?? "",
active_path: row?.active_path ?? "",
frame_src: row?.frame_src ?? "",
auths: row?.auths ?? "",
frame_loading: row?.frame_loading ?? true,
keep_alive: row?.keep_alive ?? false,
hidden_tag: row?.hidden_tag ?? false,
fixed_tag: row?.fixed_tag ?? false,
show_link: row?.show_link ?? true,
show_parent: row?.show_parent ?? false
}
}),
beforeSure: (done, { options }) => {
const FormRef = formRef.value.getRef();
const curData = options.props.formInline as PermissionInfo;
console.log(curData);
function chores() {
message(
`${title}了权限名称为${transformI18n(curData.title)}的这条数据`,
{
type: "success"
}
);
done(); // 关闭弹框
onSearch(); // 刷新表格数据
}
FormRef.validate(async valid => {
if (valid) {
console.log("curData", curData);
// 表单规则校验通过
if (title === "新增") {
let addForm = {
menu_type: 0,
parent_id: "",
title: "",
name: "",
path: "",
component: "",
rank: 99,
redirect: "",
icon: "",
extra_icon: "",
enter_transition: "",
leave_transition: "",
active_path: "",
auths: "",
frame_src: "",
frame_loading: true,
keep_alive: false,
hidden_tag: false,
fixed_tag: false,
show_link: true,
show_parent: false
};
for (let key in addForm) {
// 检查第二个字典是否包含相同的键
if (key in curData) {
// 将第二个字典中对应键的值赋给第一个字典
addForm[key] = curData[key];
}
}
const res = await postAddPermissionAPI(addForm);
if (res.code === 200) {
// 实际开发先调用新增接口,再进行下面操作
chores();
} else {
message(`添加失败!`, { type: "success" });
}
} else {
let updateForm = {
menu_type: 0,
parent_id: "",
title: "",
name: "",
path: "",
component: "",
rank: 99,
redirect: "",
icon: "",
extra_icon: "",
enter_transition: "",
leave_transition: "",
active_path: "",
auths: "",
frame_src: "",
frame_loading: true,
keep_alive: false,
hidden_tag: false,
fixed_tag: false,
show_link: true,
show_parent: false
};
for (let key in updateForm) {
// 检查第二个字典是否包含相同的键
if (key in curData) {
// 将第二个字典中对应键的值赋给第一个字典
updateForm[key] = curData[key];
}
}
const res = await putUpdatePermissionAPI(curData.id, updateForm);
if (res.code === 200) {
chores();
} else {
message(`更新失败!`, { type: "error" });
}
}
}
});
}
});
};
const handleDelete = async (row: PermissionInfo) => {
const res = await deletePermissionAPI(row.id);
if (res.code === 200) {
message(`您删除了权限名称为${transformI18n(row.title)}的这条数据`, {
type: "success"
});
onSearch();
} else {
message("权限删除失败!", { type: "error" });
}
};
onMounted(() => {
onSearch();
});
return {
form,
formRef,
dataList,
loading,
columns,
onSearch,
resetForm,
openDialog,
handleDelete
};
};