feat: 添加权限管理
This commit is contained in:
@@ -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',
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -75,7 +75,7 @@ export const useLocale = (tableRef: Ref) => {
|
||||
{
|
||||
label: "操作",
|
||||
fixed: "right",
|
||||
width: 200,
|
||||
width: 250,
|
||||
slot: "operation"
|
||||
}
|
||||
];
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
511
src/views/system/permission/components/form.vue
Normal file
511
src/views/system/permission/components/form.vue
Normal 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>
|
||||
167
src/views/system/permission/index.vue
Normal file
167
src/views/system/permission/index.vue
Normal 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>
|
||||
344
src/views/system/permission/utils/hook.tsx
Normal file
344
src/views/system/permission/utils/hook.tsx
Normal 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加父节点parentId,parentId取父节点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
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user