feat: 添加角色管理
This commit is contained in:
@@ -25,6 +25,11 @@ buttons:Add: Add
|
|||||||
buttons:Update: Update
|
buttons:Update: Update
|
||||||
buttons:Delete: Delete
|
buttons:Delete: Delete
|
||||||
buttons:Export: Export
|
buttons:Export: Export
|
||||||
|
buttons:Save: Save
|
||||||
|
buttons:Permission: Permission
|
||||||
|
buttons:ExpandOrCollapse: Expand Or Collapse
|
||||||
|
buttons:CheckAllOrCheckOutAll: Check All Or Check Out All
|
||||||
|
buttons:Linked: Linked
|
||||||
search:Total: Total
|
search:Total: Total
|
||||||
search:History: History
|
search:History: History
|
||||||
search:Collect: Collect
|
search:Collect: Collect
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ buttons:Add: 添加
|
|||||||
buttons:Update: 修改
|
buttons:Update: 修改
|
||||||
buttons:Delete: 删除
|
buttons:Delete: 删除
|
||||||
buttons:Export: 导出
|
buttons:Export: 导出
|
||||||
|
buttons:Save: 保存
|
||||||
|
buttons:Permission: 权限
|
||||||
|
buttons:ExpandOrCollapse: 展开或折叠
|
||||||
|
buttons:CheckAllOrCheckOutAll: 全选或者全不选
|
||||||
|
buttons:Linked: 联动
|
||||||
search:Total: 共
|
search:Total: 共
|
||||||
search:History: 搜索历史
|
search:History: 搜索历史
|
||||||
search:Collect: 收藏
|
search:Collect: 收藏
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
import { http } from "@/utils/http";
|
import { http } from "@/utils/http";
|
||||||
import type { DepartmentInfo, PermissionInfo } from "types/system";
|
import type {
|
||||||
|
DepartmentInfo,
|
||||||
|
PermissionInfo,
|
||||||
|
RoleInfo,
|
||||||
|
RolePermissionInfo
|
||||||
|
} from "types/system";
|
||||||
import { filterEmptyObject } from "./utils";
|
import { filterEmptyObject } from "./utils";
|
||||||
|
|
||||||
// ---------------------------部门相关-------------------------------------
|
// ---------------------------部门相关-------------------------------------
|
||||||
@@ -31,7 +36,7 @@ type GetDepartmentListParams = {
|
|||||||
};
|
};
|
||||||
/**获取部门列表 */
|
/**获取部门列表 */
|
||||||
export const getDepartmentListAPI = (params: GetDepartmentListParams) => {
|
export const getDepartmentListAPI = (params: GetDepartmentListParams) => {
|
||||||
return http.request<QueryListResult<DepartmentInfo[]>>(
|
return http.request<QueryListResult<DepartmentInfo>>(
|
||||||
"get",
|
"get",
|
||||||
`/api/department/list`,
|
`/api/department/list`,
|
||||||
{
|
{
|
||||||
@@ -135,7 +140,7 @@ type GetPermissionListParams = {
|
|||||||
|
|
||||||
/**获取权限列表 */
|
/**获取权限列表 */
|
||||||
export const getPermissionListAPI = (params: GetPermissionListParams) => {
|
export const getPermissionListAPI = (params: GetPermissionListParams) => {
|
||||||
return http.request<QueryListResult<PermissionInfo[]>>(
|
return http.request<QueryListResult<PermissionInfo>>(
|
||||||
"get",
|
"get",
|
||||||
`/api/permission/list`,
|
`/api/permission/list`,
|
||||||
{
|
{
|
||||||
@@ -224,3 +229,88 @@ export const putUpdatePermissionAPI = (
|
|||||||
data
|
data
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取角色权限列表
|
||||||
|
* @param id 角色ID
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getRolePermissionsAPI = (id: string) => {
|
||||||
|
return http.request<QueryListResult<RolePermissionInfo>>(
|
||||||
|
"get",
|
||||||
|
`/api/role/permissionList/${id}`
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新角色权限信息
|
||||||
|
* @param id 角色ID
|
||||||
|
* @param data 角色权限列表
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const putUpdateRolePermissionsAPI = (
|
||||||
|
id: string,
|
||||||
|
data: {
|
||||||
|
permission_ids: string[];
|
||||||
|
}
|
||||||
|
) => {
|
||||||
|
return http.request<null>("put", `/api/role/updatePermission/${id}`, {
|
||||||
|
data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// -----------------------------角色相关-----------------------------------
|
||||||
|
|
||||||
|
type GetRoleListParams = {
|
||||||
|
/**当前页 */
|
||||||
|
page: number;
|
||||||
|
/**每页数量 */
|
||||||
|
pageSize: number;
|
||||||
|
/**角色名称 */
|
||||||
|
name?: string;
|
||||||
|
/**角色标识符 */
|
||||||
|
code?: string;
|
||||||
|
/**角色描述 */
|
||||||
|
description?: string;
|
||||||
|
/**所属部门ID */
|
||||||
|
department_id?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**获取角色列表 */
|
||||||
|
export const getRoleListAPI = (params: GetRoleListParams) => {
|
||||||
|
return http.request<QueryListResult<RoleInfo>>("get", `/api/role/list`, {
|
||||||
|
params: filterEmptyObject(params)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**添加角色参数 */
|
||||||
|
type AddRoleParams = {
|
||||||
|
/**角色姓名 */
|
||||||
|
name: string;
|
||||||
|
/**角色标识 */
|
||||||
|
code: string;
|
||||||
|
/**角色描述 */
|
||||||
|
description: string;
|
||||||
|
/**所属部门ID */
|
||||||
|
department_id: string;
|
||||||
|
/**状态 */
|
||||||
|
status: number | string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**更新角色数据 */
|
||||||
|
export const putUpdateRoleAPI = (data: AddRoleParams, id: string) => {
|
||||||
|
return http.request<null>("post", `/api/role/update/${id}`, {
|
||||||
|
data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**添加角色数据 */
|
||||||
|
export const postAddRoleAPI = (data: AddRoleParams) => {
|
||||||
|
return http.request<null>("post", `/api/role/add`, {
|
||||||
|
data
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/**删除角色 */
|
||||||
|
export const deleteRoleAPI = (id: string) => {
|
||||||
|
return http.request<null>("post", `/api/role/delete/${id}`);
|
||||||
|
};
|
||||||
|
|||||||
141
src/views/system/role/components/form.vue
Normal file
141
src/views/system/role/components/form.vue
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, reactive } from "vue";
|
||||||
|
import type { FormRules } from "element-plus";
|
||||||
|
import { getDepartmentListAPI } from "@/api/system";
|
||||||
|
import type { DepartmentInfo } from "types/system";
|
||||||
|
import { usePublicHooks } from "../../hooks";
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: "SystemRoleForm"
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 自定义表单规则校验 */
|
||||||
|
const formRules = reactive<FormRules>({
|
||||||
|
name: [{ required: true, message: "角色名称为必填项", trigger: "blur" }],
|
||||||
|
code: [{ required: true, message: "角色标识为必填项", trigger: "blur" }]
|
||||||
|
});
|
||||||
|
interface FormItemProps {
|
||||||
|
/**角色ID */
|
||||||
|
id: string;
|
||||||
|
/** 角色名称 */
|
||||||
|
name: string;
|
||||||
|
/** 角色编号 */
|
||||||
|
code: string;
|
||||||
|
/**角色状态 */
|
||||||
|
status: number;
|
||||||
|
/** 角色描述 */
|
||||||
|
description: string;
|
||||||
|
/** 角色部门ID */
|
||||||
|
department_id: string;
|
||||||
|
}
|
||||||
|
interface FormProps {
|
||||||
|
formInline: FormItemProps;
|
||||||
|
}
|
||||||
|
const props = withDefaults(defineProps<FormProps>(), {
|
||||||
|
formInline: () => ({
|
||||||
|
id: "",
|
||||||
|
name: "",
|
||||||
|
code: "",
|
||||||
|
description: "",
|
||||||
|
status: 1,
|
||||||
|
department_id: ""
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
const ruleFormRef = ref();
|
||||||
|
const newFormInline = ref(props.formInline);
|
||||||
|
const departments = ref<DepartmentInfo[]>([]);
|
||||||
|
const { switchStyle } = usePublicHooks();
|
||||||
|
function getRef() {
|
||||||
|
return ruleFormRef.value;
|
||||||
|
}
|
||||||
|
/**获取部门列表 */
|
||||||
|
const getDepartments = async () => {
|
||||||
|
const res = await getDepartmentListAPI({ page: 1, pageSize: 9999 });
|
||||||
|
if (res.code === 200) {
|
||||||
|
departments.value = formatHigherOptions(res.data.result);
|
||||||
|
} else {
|
||||||
|
departments.value = [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
defineExpose({ getRef });
|
||||||
|
/**组件挂载执行 */
|
||||||
|
onMounted(async () => {
|
||||||
|
await getDepartments();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<el-form
|
||||||
|
ref="ruleFormRef"
|
||||||
|
:model="newFormInline"
|
||||||
|
:rules="formRules"
|
||||||
|
label-width="82px"
|
||||||
|
>
|
||||||
|
<el-form-item label="角色名称" prop="name">
|
||||||
|
<el-input
|
||||||
|
v-model="newFormInline.name"
|
||||||
|
clearable
|
||||||
|
placeholder="请输入角色名称"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="角色标识" prop="code">
|
||||||
|
<el-input
|
||||||
|
v-model="newFormInline.code"
|
||||||
|
clearable
|
||||||
|
placeholder="请输入角色标识"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
<el-form-item label="角色描述">
|
||||||
|
<el-input
|
||||||
|
v-model="newFormInline.description"
|
||||||
|
placeholder="请输入角色描述信息"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="所属部门" prop="department_id">
|
||||||
|
<el-cascader
|
||||||
|
v-model="newFormInline.department_id"
|
||||||
|
class="w-full"
|
||||||
|
:options="departments"
|
||||||
|
:props="{
|
||||||
|
value: 'id',
|
||||||
|
label: 'name',
|
||||||
|
emitPath: false,
|
||||||
|
checkStrictly: true
|
||||||
|
}"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
placeholder="请选择所属部门~"
|
||||||
|
>
|
||||||
|
<template #default="{ node, data }">
|
||||||
|
<span>{{ data.name }}</span>
|
||||||
|
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
|
||||||
|
</template>
|
||||||
|
</el-cascader>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="角色状态" prop="status">
|
||||||
|
<el-switch
|
||||||
|
v-model="newFormInline.status"
|
||||||
|
inline-prompt
|
||||||
|
:active-value="1"
|
||||||
|
:inactive-value="0"
|
||||||
|
active-text="启用"
|
||||||
|
inactive-text="停用"
|
||||||
|
:style="switchStyle"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</template>
|
||||||
340
src/views/system/role/index.vue
Normal file
340
src/views/system/role/index.vue
Normal file
@@ -0,0 +1,340 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, computed, nextTick, onMounted } from "vue";
|
||||||
|
import { useRole } from "./utils/hook";
|
||||||
|
import { PureTableBar } from "@/components/RePureTableBar";
|
||||||
|
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import {
|
||||||
|
delay,
|
||||||
|
subBefore,
|
||||||
|
deviceDetection,
|
||||||
|
useResizeObserver
|
||||||
|
} from "@pureadmin/utils";
|
||||||
|
import Delete from "@iconify-icons/ep/delete";
|
||||||
|
import EditPen from "@iconify-icons/ep/edit-pen";
|
||||||
|
import Refresh from "@iconify-icons/ep/refresh";
|
||||||
|
import Menu from "@iconify-icons/ep/menu";
|
||||||
|
import AddFill from "@iconify-icons/ri/add-circle-line";
|
||||||
|
import Close from "@iconify-icons/ep/close";
|
||||||
|
import Check from "@iconify-icons/ep/check";
|
||||||
|
import { onBeforeRouteUpdate } from "vue-router";
|
||||||
|
const { t } = useI18n();
|
||||||
|
defineOptions({
|
||||||
|
name: "SystemRole"
|
||||||
|
});
|
||||||
|
|
||||||
|
const iconClass = computed(() => {
|
||||||
|
return [
|
||||||
|
"w-[22px]",
|
||||||
|
"h-[22px]",
|
||||||
|
"flex",
|
||||||
|
"justify-center",
|
||||||
|
"items-center",
|
||||||
|
"outline-none",
|
||||||
|
"rounded-[4px]",
|
||||||
|
"cursor-pointer",
|
||||||
|
"transition-colors",
|
||||||
|
"hover:bg-[#0000000f]",
|
||||||
|
"dark:hover:bg-[#ffffff1f]",
|
||||||
|
"dark:hover:text-[#ffffffd9]"
|
||||||
|
];
|
||||||
|
});
|
||||||
|
const treeRef = ref();
|
||||||
|
|
||||||
|
const formRef = ref();
|
||||||
|
const tableRef = ref();
|
||||||
|
const contentRef = ref();
|
||||||
|
const treeHeight = ref();
|
||||||
|
const {
|
||||||
|
form,
|
||||||
|
isShow,
|
||||||
|
curRow,
|
||||||
|
loading,
|
||||||
|
columns,
|
||||||
|
rowStyle,
|
||||||
|
dataList,
|
||||||
|
treeData,
|
||||||
|
treeProps,
|
||||||
|
isLinkage,
|
||||||
|
pagination,
|
||||||
|
isExpandAll,
|
||||||
|
isSelectAll,
|
||||||
|
treeSearchValue,
|
||||||
|
departments,
|
||||||
|
onSearch,
|
||||||
|
resetForm,
|
||||||
|
openDialog,
|
||||||
|
handleMenu,
|
||||||
|
handleSave,
|
||||||
|
handleDelete,
|
||||||
|
filterMethod,
|
||||||
|
transformI18n,
|
||||||
|
onQueryChanged,
|
||||||
|
handleSizeChange,
|
||||||
|
handleCurrentChange
|
||||||
|
} = useRole(treeRef);
|
||||||
|
onMounted(() => {
|
||||||
|
useResizeObserver(contentRef, async () => {
|
||||||
|
await nextTick();
|
||||||
|
delay(60).then(() => {
|
||||||
|
treeHeight.value = parseFloat(
|
||||||
|
subBefore(tableRef.value.getTableDoms().tableWrapper.style.height, "px")
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
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] overflow-auto"
|
||||||
|
>
|
||||||
|
<el-form-item label="角色名称:" prop="name">
|
||||||
|
<el-input
|
||||||
|
v-model="form.name"
|
||||||
|
placeholder="请输入角色名称"
|
||||||
|
clearable
|
||||||
|
class="!w-[200px]"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="角色标识:" prop="code">
|
||||||
|
<el-input
|
||||||
|
v-model="form.code"
|
||||||
|
placeholder="请输入角色标识"
|
||||||
|
clearable
|
||||||
|
class="!w-[200px]"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="角色描述:" prop="description">
|
||||||
|
<el-input
|
||||||
|
v-model="form.description"
|
||||||
|
placeholder="请输入角色描述"
|
||||||
|
clearable
|
||||||
|
class="!w-[200px]"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="所属部门:" prop="department_id">
|
||||||
|
<el-cascader
|
||||||
|
v-model="form.department_id"
|
||||||
|
class="w-full"
|
||||||
|
:options="departments"
|
||||||
|
:props="{
|
||||||
|
value: 'id',
|
||||||
|
label: 'name',
|
||||||
|
emitPath: false,
|
||||||
|
checkStrictly: true
|
||||||
|
}"
|
||||||
|
clearable
|
||||||
|
filterable
|
||||||
|
placeholder="请选择所属部门~"
|
||||||
|
>
|
||||||
|
<template #default="{ node, data }">
|
||||||
|
<span>{{ data.name }}</span>
|
||||||
|
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
|
||||||
|
</template>
|
||||||
|
</el-cascader>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="状态:" prop="status">
|
||||||
|
<el-select
|
||||||
|
v-model="form.status"
|
||||||
|
placeholder="请选择状态"
|
||||||
|
clearable
|
||||||
|
class="!w-[200px]"
|
||||||
|
>
|
||||||
|
<el-option label="已启用" value="1" />
|
||||||
|
<el-option label="已停用" value="0" />
|
||||||
|
</el-select>
|
||||||
|
</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>
|
||||||
|
<div
|
||||||
|
ref="contentRef"
|
||||||
|
:class="['flex', deviceDetection() ? 'flex-wrap' : '']"
|
||||||
|
>
|
||||||
|
<PureTableBar
|
||||||
|
:class="[isShow && !deviceDetection() ? '!w-[60vw]' : 'w-full']"
|
||||||
|
style="transition: width 220ms cubic-bezier(0.4, 0, 0.2, 1)"
|
||||||
|
title="角色管理"
|
||||||
|
:columns="columns"
|
||||||
|
@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"
|
||||||
|
align-whole="center"
|
||||||
|
showOverflowTooltip
|
||||||
|
table-layout="auto"
|
||||||
|
:loading="loading"
|
||||||
|
:size="size"
|
||||||
|
adaptive
|
||||||
|
border
|
||||||
|
stripe
|
||||||
|
:row-style="rowStyle"
|
||||||
|
:adaptiveConfig="{ offsetBottom: 108 }"
|
||||||
|
:data="dataList"
|
||||||
|
:columns="dynamicColumns"
|
||||||
|
:pagination="pagination"
|
||||||
|
:paginationSmall="size === 'small' ? true : false"
|
||||||
|
:header-cell-style="{
|
||||||
|
background: 'var(--el-fill-color-light)',
|
||||||
|
color: 'var(--el-text-color-primary)'
|
||||||
|
}"
|
||||||
|
@page-size-change="handleSizeChange"
|
||||||
|
@page-current-change="handleCurrentChange"
|
||||||
|
>
|
||||||
|
<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-popconfirm
|
||||||
|
:title="`是否确认删除角色名称为${row.name}的这条数据`"
|
||||||
|
@confirm="handleDelete(row)"
|
||||||
|
>
|
||||||
|
<template #reference>
|
||||||
|
<el-button
|
||||||
|
class="reset-margin"
|
||||||
|
link
|
||||||
|
type="danger"
|
||||||
|
:size="size"
|
||||||
|
:icon="useRenderIcon(Delete)"
|
||||||
|
>
|
||||||
|
{{ t("buttons:Delete") }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-popconfirm>
|
||||||
|
<el-button
|
||||||
|
class="reset-margin"
|
||||||
|
link
|
||||||
|
type="primary"
|
||||||
|
:size="size"
|
||||||
|
:icon="useRenderIcon(Menu)"
|
||||||
|
@click="handleMenu(row)"
|
||||||
|
>
|
||||||
|
{{ t("buttons:Permission") }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</pure-table>
|
||||||
|
</template>
|
||||||
|
</PureTableBar>
|
||||||
|
<div
|
||||||
|
v-if="isShow"
|
||||||
|
class="!min-w-[calc(100vw-60vw-268px)] w-full mt-2 px-2 pb-2 bg-bg_color ml-2 overflow-auto"
|
||||||
|
>
|
||||||
|
<div class="flex justify-between w-full px-3 pt-5 pb-4">
|
||||||
|
<div class="flex">
|
||||||
|
<span :class="iconClass">
|
||||||
|
<IconifyIconOffline
|
||||||
|
v-tippy="{
|
||||||
|
content: t('buttons:Close')
|
||||||
|
}"
|
||||||
|
class="dark:text-white"
|
||||||
|
width="18px"
|
||||||
|
height="18px"
|
||||||
|
:icon="Close"
|
||||||
|
@click="handleMenu"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span :class="[iconClass, 'ml-2']">
|
||||||
|
<IconifyIconOffline
|
||||||
|
v-tippy="{
|
||||||
|
content: t('buttons:Save')
|
||||||
|
}"
|
||||||
|
class="dark:text-white"
|
||||||
|
width="18px"
|
||||||
|
height="18px"
|
||||||
|
:icon="Check"
|
||||||
|
@click="handleSave"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<p class="font-bold truncate">
|
||||||
|
{{ `${curRow?.name ? `${curRow.name}` : ""}` }}-权限列表
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<el-input
|
||||||
|
v-model="treeSearchValue"
|
||||||
|
placeholder="请输入权限进行搜索"
|
||||||
|
class="mb-1"
|
||||||
|
clearable
|
||||||
|
@input="onQueryChanged"
|
||||||
|
/>
|
||||||
|
<div class="flex flex-wrap">
|
||||||
|
<el-checkbox
|
||||||
|
v-model="isExpandAll"
|
||||||
|
:label="t('buttons:ExpandOrCollapse')"
|
||||||
|
/>
|
||||||
|
<el-checkbox
|
||||||
|
v-model="isSelectAll"
|
||||||
|
:label="t('buttons:CheckAllOrCheckOutAll')"
|
||||||
|
/>
|
||||||
|
<el-checkbox v-model="isLinkage" :label="t('buttons:Linked')" />
|
||||||
|
</div>
|
||||||
|
<el-tree-v2
|
||||||
|
ref="treeRef"
|
||||||
|
show-checkbox
|
||||||
|
:data="treeData"
|
||||||
|
:props="treeProps"
|
||||||
|
:height="treeHeight"
|
||||||
|
:check-strictly="!isLinkage"
|
||||||
|
:filter-method="filterMethod"
|
||||||
|
>
|
||||||
|
<template #default="{ node }">
|
||||||
|
<span>{{ transformI18n(node.label) }}</span>
|
||||||
|
</template>
|
||||||
|
</el-tree-v2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
:deep(.el-dropdown-menu__item i) {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
margin: 24px 24px 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-form {
|
||||||
|
:deep(.el-form-item) {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
402
src/views/system/role/utils/hook.tsx
Normal file
402
src/views/system/role/utils/hook.tsx
Normal file
@@ -0,0 +1,402 @@
|
|||||||
|
import dayjs from "dayjs";
|
||||||
|
import editForm from "../components/form.vue";
|
||||||
|
import { message } from "@/utils/message";
|
||||||
|
|
||||||
|
import {
|
||||||
|
deleteRoleAPI,
|
||||||
|
getPermissionListAPI,
|
||||||
|
getRoleListAPI,
|
||||||
|
postAddRoleAPI,
|
||||||
|
putUpdateRoleAPI,
|
||||||
|
getRolePermissionsAPI,
|
||||||
|
putUpdateRolePermissionsAPI,
|
||||||
|
getDepartmentListAPI
|
||||||
|
} from "@/api/system";
|
||||||
|
|
||||||
|
import { handleTree } from "@/utils/tree";
|
||||||
|
import { usePublicHooks } from "../../hooks";
|
||||||
|
import { getKeyList } from "@pureadmin/utils";
|
||||||
|
import { transformI18n } from "@/plugins/i18n";
|
||||||
|
import { addDialog } from "@/components/ReDialog";
|
||||||
|
import type { PaginationProps } from "@pureadmin/table";
|
||||||
|
import { type Ref, reactive, ref, onMounted, h, watch, toRaw } from "vue";
|
||||||
|
import type {
|
||||||
|
DepartmentInfo,
|
||||||
|
RoleInfo,
|
||||||
|
RolePermissionInfo
|
||||||
|
} from "types/system";
|
||||||
|
|
||||||
|
export const useRole = (treeRef: Ref) => {
|
||||||
|
/**查询表单 */
|
||||||
|
const form = reactive({
|
||||||
|
name: "",
|
||||||
|
code: "",
|
||||||
|
status: "",
|
||||||
|
department_id: "",
|
||||||
|
description: ""
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* 表单Ref
|
||||||
|
*/
|
||||||
|
const formRef = ref();
|
||||||
|
/**
|
||||||
|
* 数据列表
|
||||||
|
*/
|
||||||
|
const dataList = ref<RoleInfo[]>([]);
|
||||||
|
/**
|
||||||
|
* 加载状态
|
||||||
|
*/
|
||||||
|
const loading = ref(true);
|
||||||
|
/**
|
||||||
|
* 标签样式
|
||||||
|
*/
|
||||||
|
const { tagStyle } = usePublicHooks();
|
||||||
|
/**树形列表id列表 */
|
||||||
|
const treeIds = ref<string[]>([]);
|
||||||
|
/**
|
||||||
|
* 树形列表
|
||||||
|
*/
|
||||||
|
const treeProps = {
|
||||||
|
value: "id",
|
||||||
|
label: "title",
|
||||||
|
children: "children"
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* 分页参数
|
||||||
|
*/
|
||||||
|
const pagination = reactive<PaginationProps>({
|
||||||
|
total: 0,
|
||||||
|
pageSize: 10,
|
||||||
|
currentPage: 1,
|
||||||
|
background: true
|
||||||
|
});
|
||||||
|
const curRow = ref();
|
||||||
|
/**
|
||||||
|
* 树形列表数据
|
||||||
|
*/
|
||||||
|
const treeData = ref([]);
|
||||||
|
/**是否显示 */
|
||||||
|
const isShow = ref<boolean>(false);
|
||||||
|
/**是否关联 */
|
||||||
|
const isLinkage = ref<boolean>(false);
|
||||||
|
/**查询值 */
|
||||||
|
const treeSearchValue = ref<string>("");
|
||||||
|
/**是否展开 */
|
||||||
|
const isExpandAll = ref<boolean>(false);
|
||||||
|
/**是否全选 */
|
||||||
|
const isSelectAll = ref<boolean>(false);
|
||||||
|
const columns: TableColumnList = [
|
||||||
|
{
|
||||||
|
label: "角色名称",
|
||||||
|
prop: "name",
|
||||||
|
minWidth: 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "角色标识",
|
||||||
|
prop: "code",
|
||||||
|
minWidth: 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "状态",
|
||||||
|
minWidth: 130,
|
||||||
|
cellRenderer: ({ row, props }) => (
|
||||||
|
<el-tag size={props.size} style={tagStyle.value(row.status)}>
|
||||||
|
{row.status === 1 ? "启用" : "停用"}
|
||||||
|
</el-tag>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "角色描述",
|
||||||
|
prop: "description",
|
||||||
|
minWidth: 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "所属部门",
|
||||||
|
prop: "department_name",
|
||||||
|
minWidth: 150
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "创建时间",
|
||||||
|
minWidth: 180,
|
||||||
|
prop: "create_time",
|
||||||
|
formatter: ({ create_time }) =>
|
||||||
|
dayjs(create_time).format("YYYY-MM-DD HH:mm:ss")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "更新时间",
|
||||||
|
minWidth: 180,
|
||||||
|
prop: "update_time",
|
||||||
|
formatter: ({ update_time }) =>
|
||||||
|
dayjs(update_time).format("YYYY-MM-DD HH:mm:ss")
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "操作",
|
||||||
|
fixed: "right",
|
||||||
|
width: 300,
|
||||||
|
slot: "operation"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
/**
|
||||||
|
* 初次查询
|
||||||
|
*/
|
||||||
|
const onSearch = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
const data = await getRoleListAPI({
|
||||||
|
page: pagination.currentPage,
|
||||||
|
pageSize: pagination.pageSize,
|
||||||
|
...toRaw(form)
|
||||||
|
});
|
||||||
|
dataList.value = data.data.result;
|
||||||
|
pagination.total = data.data.total;
|
||||||
|
pagination.currentPage = data.data.page;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
loading.value = false;
|
||||||
|
}, 500);
|
||||||
|
};
|
||||||
|
const resetForm = formEl => {
|
||||||
|
if (!formEl) return;
|
||||||
|
formEl.resetFields();
|
||||||
|
onSearch();
|
||||||
|
};
|
||||||
|
/**处理页码变化 */
|
||||||
|
const handleSizeChange = async (val: number) => {
|
||||||
|
const res = await getRoleListAPI({
|
||||||
|
page: pagination.currentPage,
|
||||||
|
pageSize: val
|
||||||
|
});
|
||||||
|
if (res.code === 200) {
|
||||||
|
const data = res.data;
|
||||||
|
dataList.value = data.result;
|
||||||
|
pagination.total = data.total;
|
||||||
|
pagination.currentPage = data.page;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**处理每页数量变化 */
|
||||||
|
const handleCurrentChange = async (val: number) => {
|
||||||
|
const res = await getRoleListAPI({
|
||||||
|
page: val,
|
||||||
|
pageSize: pagination.pageSize
|
||||||
|
});
|
||||||
|
if (res.code === 200) {
|
||||||
|
const data = res.data;
|
||||||
|
dataList.value = data.result;
|
||||||
|
pagination.total = data.total;
|
||||||
|
pagination.currentPage = data.page;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = async (row: RoleInfo) => {
|
||||||
|
const res = await deleteRoleAPI(row.id);
|
||||||
|
if (res.code === 200) {
|
||||||
|
message(`您删除了角色名称为${row.name}的这条数据`, { type: "success" });
|
||||||
|
onSearch();
|
||||||
|
} else {
|
||||||
|
message(`删除失败!`, { type: "error" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const openDialog = (title = "新增", row?: RoleInfo) => {
|
||||||
|
addDialog({
|
||||||
|
title: `${title}角色`,
|
||||||
|
props: {
|
||||||
|
formInline: {
|
||||||
|
id: row?.id ?? "",
|
||||||
|
name: row?.name ?? "",
|
||||||
|
code: row?.code ?? "",
|
||||||
|
description: row?.description ?? "",
|
||||||
|
status: row?.status ?? 1,
|
||||||
|
department_id: row?.department_id ?? ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
width: "40%",
|
||||||
|
draggable: true,
|
||||||
|
fullscreenIcon: true,
|
||||||
|
closeOnClickModal: false,
|
||||||
|
contentRenderer: () =>
|
||||||
|
h(editForm, {
|
||||||
|
ref: formRef,
|
||||||
|
formInline: {
|
||||||
|
id: row?.id ?? "",
|
||||||
|
name: row?.name ?? "",
|
||||||
|
code: row?.code ?? "",
|
||||||
|
description: row?.description ?? "",
|
||||||
|
status: row?.status ?? 1,
|
||||||
|
department_id: row?.department_id ?? ""
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
beforeSure: (done, { options }) => {
|
||||||
|
const FormRef = formRef.value.getRef();
|
||||||
|
let curData = options.props.formInline as RoleInfo;
|
||||||
|
function chores() {
|
||||||
|
message(`您${title}了角色名称为${curData.name}的这条数据`, {
|
||||||
|
type: "success"
|
||||||
|
});
|
||||||
|
done(); // 关闭弹框
|
||||||
|
onSearch(); // 刷新表格数据
|
||||||
|
}
|
||||||
|
FormRef.validate(async (valid: any) => {
|
||||||
|
if (valid) {
|
||||||
|
console.log("curData", curData);
|
||||||
|
// 表单规则校验通过
|
||||||
|
if (title === "新增") {
|
||||||
|
// 实际开发先调用新增接口,再进行下面操作
|
||||||
|
const res = await postAddRoleAPI(curData);
|
||||||
|
if (res.code === 200) {
|
||||||
|
chores();
|
||||||
|
} else {
|
||||||
|
message(`添加失败!`, {
|
||||||
|
type: "error"
|
||||||
|
});
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 实际开发先调用修改接口,再进行下面操作
|
||||||
|
const res = await putUpdateRoleAPI(curData, row.id);
|
||||||
|
if (res.code === 200) {
|
||||||
|
chores();
|
||||||
|
} else {
|
||||||
|
message(`修改失败!`, {
|
||||||
|
type: "error"
|
||||||
|
});
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 角色权限
|
||||||
|
*/
|
||||||
|
const handleMenu = async (row?: RolePermissionInfo) => {
|
||||||
|
const { id } = row;
|
||||||
|
if (id) {
|
||||||
|
curRow.value = row;
|
||||||
|
isShow.value = true;
|
||||||
|
const res = await getRolePermissionsAPI(id);
|
||||||
|
if (res.success) {
|
||||||
|
treeRef.value.setCheckedKeys(
|
||||||
|
getKeyList(res.data.result, "permission_id")
|
||||||
|
);
|
||||||
|
isExpandAll.value = true;
|
||||||
|
} else {
|
||||||
|
treeRef.value.setCheckedKeys([]);
|
||||||
|
isExpandAll.value = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
curRow.value = null;
|
||||||
|
isShow.value = false;
|
||||||
|
isExpandAll.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 高亮当前权限选中行 */
|
||||||
|
const rowStyle = ({ row: { id } }) => {
|
||||||
|
return {
|
||||||
|
cursor: "pointer",
|
||||||
|
background: id === curRow.value?.id ? "var(--el-fill-color-light)" : ""
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/**保存角色权限 */
|
||||||
|
const handleSave = async () => {
|
||||||
|
const { id, name } = curRow.value;
|
||||||
|
// 根据用户 id 调用实际项目中菜单权限修改接口
|
||||||
|
let permissions = treeRef.value.getCheckedKeys();
|
||||||
|
let halfCheckedKeys = treeRef.value.getHalfCheckedKeys();
|
||||||
|
permissions = [...new Set(permissions.concat(halfCheckedKeys))];
|
||||||
|
const res = await putUpdateRolePermissionsAPI(id, {
|
||||||
|
permission_ids: permissions
|
||||||
|
});
|
||||||
|
if (res.code === 200) {
|
||||||
|
message(`角色名称为${name}的权限修改成功~`, {
|
||||||
|
type: "success"
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
message(`角色名称为${name}的权限修改失败!`, {
|
||||||
|
type: "error"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**查询权限变化 */
|
||||||
|
const onQueryChanged = (query: string) => {
|
||||||
|
treeRef.value!.filter(query);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**过滤方法 */
|
||||||
|
const filterMethod = (query: string, node) => {
|
||||||
|
return transformI18n(node.title)!.includes(query);
|
||||||
|
};
|
||||||
|
/**部门列表 */
|
||||||
|
const departments = ref<DepartmentInfo[]>([]);
|
||||||
|
/**获取部门列表 */
|
||||||
|
const getDepartments = async () => {
|
||||||
|
const res = await getDepartmentListAPI({ page: 1, pageSize: 9999 });
|
||||||
|
if (res.code === 200) {
|
||||||
|
departments.value = formatHigherOptions(res.data.result);
|
||||||
|
} else {
|
||||||
|
departments.value = [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
onSearch();
|
||||||
|
const res = await getPermissionListAPI({ page: 1, pageSize: 99999 });
|
||||||
|
const data = res.data.result;
|
||||||
|
treeIds.value = getKeyList(data, "id");
|
||||||
|
treeData.value = handleTree(data, "id", "parent_id");
|
||||||
|
await getDepartments();
|
||||||
|
});
|
||||||
|
watch(isExpandAll, val => {
|
||||||
|
val
|
||||||
|
? treeRef.value.setExpandedKeys(treeIds.value)
|
||||||
|
: treeRef.value.setExpandedKeys([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(isSelectAll, val => {
|
||||||
|
val
|
||||||
|
? treeRef.value.setCheckedKeys(treeIds.value)
|
||||||
|
: treeRef.value.setCheckedKeys([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
form,
|
||||||
|
isShow,
|
||||||
|
curRow,
|
||||||
|
loading,
|
||||||
|
columns,
|
||||||
|
dataList,
|
||||||
|
treeData,
|
||||||
|
treeProps,
|
||||||
|
isLinkage,
|
||||||
|
pagination,
|
||||||
|
isExpandAll,
|
||||||
|
isSelectAll,
|
||||||
|
treeSearchValue,
|
||||||
|
departments,
|
||||||
|
rowStyle,
|
||||||
|
onSearch,
|
||||||
|
resetForm,
|
||||||
|
openDialog,
|
||||||
|
handleMenu,
|
||||||
|
handleSave,
|
||||||
|
handleDelete,
|
||||||
|
filterMethod,
|
||||||
|
transformI18n,
|
||||||
|
onQueryChanged,
|
||||||
|
handleSizeChange,
|
||||||
|
handleCurrentChange
|
||||||
|
};
|
||||||
|
};
|
||||||
52
types/system.d.ts
vendored
52
types/system.d.ts
vendored
@@ -119,3 +119,55 @@ export type PermissionInfo = {
|
|||||||
/** 是否显示父菜单 */
|
/** 是否显示父菜单 */
|
||||||
show_parent: boolean;
|
show_parent: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**角色信息类型 */
|
||||||
|
export type RoleInfo = {
|
||||||
|
/**角色ID */
|
||||||
|
id: string;
|
||||||
|
/**状态 */
|
||||||
|
status: number;
|
||||||
|
/**创建时间 */
|
||||||
|
create_time: string;
|
||||||
|
/**修改时间 */
|
||||||
|
update_time: string;
|
||||||
|
/**部门名称 */
|
||||||
|
name: string;
|
||||||
|
/**角色标识符 */
|
||||||
|
code: string;
|
||||||
|
/**角色描述 */
|
||||||
|
description: string;
|
||||||
|
/**角色部门ID */
|
||||||
|
department_id: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 角色权限关联信息类型 */
|
||||||
|
export type RolePermissionInfo = {
|
||||||
|
/** 主键ID */
|
||||||
|
id: string;
|
||||||
|
/** 创建人 */
|
||||||
|
create_by: string;
|
||||||
|
/** 创建时间 */
|
||||||
|
create_time: string;
|
||||||
|
/** 更新人 */
|
||||||
|
update_by: string;
|
||||||
|
/** 更新时间 */
|
||||||
|
update_time: string;
|
||||||
|
/** 角色ID */
|
||||||
|
role_id: string;
|
||||||
|
/** 角色名称 */
|
||||||
|
role_name: string;
|
||||||
|
/** 角色编码 */
|
||||||
|
role_code: string;
|
||||||
|
/** 权限ID */
|
||||||
|
permission_id: string;
|
||||||
|
/**
|
||||||
|
* 权限父ID
|
||||||
|
*/
|
||||||
|
permission_parent_id: string;
|
||||||
|
/** 权限名称 */
|
||||||
|
permission_name: string;
|
||||||
|
/** 权限编码 */
|
||||||
|
permission_code: string;
|
||||||
|
/** 权限类型 */
|
||||||
|
permission_type: string;
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user