mirror of
http://183.237.82.114:10086/kilo/leaser_front.git
synced 2026-10-23 19:35:25 +00:00
feat: 完成角色权限的功能权限和用户分配
This commit is contained in:
parent
293beb9f5d
commit
c5588374ba
12 changed files with 1562 additions and 133 deletions
|
|
@ -1,6 +1,30 @@
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import type { UserPermission } from '@/types/api';
|
||||||
import { HttpResponse } from './interceptor';
|
import { HttpResponse } from './interceptor';
|
||||||
|
|
||||||
|
// ==================== 通用类型定义 ====================
|
||||||
|
export interface BaseEntity {
|
||||||
|
id: number;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PaginationParams {
|
||||||
|
role_id?: number | null;
|
||||||
|
page?: number;
|
||||||
|
page_size?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PaginationResult {
|
||||||
|
total?: number;
|
||||||
|
total_pages?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UserStatus = 1 | 2; // 1: 启用, 2: 禁用
|
||||||
|
export type ManagerStatus = 1 | 2; // 1: 是主管, 2: 否
|
||||||
|
export type DataType = 1 | 2 | 3; // 1: 全部数据权限, 2: 自定义数据权限, 3: 仅本人数据
|
||||||
|
|
||||||
|
// ==================== 部门相关类型 ====================
|
||||||
export interface DepartmentFormParams {
|
export interface DepartmentFormParams {
|
||||||
parent_id: number | null;
|
parent_id: number | null;
|
||||||
name: string;
|
name: string;
|
||||||
|
|
@ -12,21 +36,8 @@ export interface DepartmentFormParams {
|
||||||
export interface DepartmentIdData {
|
export interface DepartmentIdData {
|
||||||
departmentId: number | string;
|
departmentId: number | string;
|
||||||
}
|
}
|
||||||
type DepartmentFormRes = HttpResponse<DepartmentIdData>;
|
|
||||||
// 创建部门
|
export interface DepartmentItem extends BaseEntity {
|
||||||
export function createDepartment(
|
|
||||||
params: DepartmentFormParams
|
|
||||||
): Promise<DepartmentFormRes> {
|
|
||||||
return axios.post('/department/createDepartment', params);
|
|
||||||
}
|
|
||||||
// 更新(编辑)部门
|
|
||||||
export function updateDepartment(
|
|
||||||
params: DepartmentFormParams
|
|
||||||
): Promise<DepartmentFormRes> {
|
|
||||||
return axios.post('/department/updateDepartment', params);
|
|
||||||
}
|
|
||||||
export interface DepartmentItem {
|
|
||||||
id: number;
|
|
||||||
systemTenantId: number;
|
systemTenantId: number;
|
||||||
name: string;
|
name: string;
|
||||||
parentId: number;
|
parentId: number;
|
||||||
|
|
@ -35,24 +46,127 @@ export interface DepartmentItem {
|
||||||
path: string;
|
path: string;
|
||||||
remark: string;
|
remark: string;
|
||||||
isDelete: number;
|
isDelete: number;
|
||||||
createdAt: string;
|
|
||||||
updatedAt: string;
|
|
||||||
sort: number;
|
sort: number;
|
||||||
children?: DepartmentItem[]; // 递归结构
|
children?: DepartmentItem[]; // 递归结构
|
||||||
isShowEditIcon?: boolean; // 是否展示编辑icon
|
isShowEditIcon?: boolean; // 是否展示编辑icon
|
||||||
username?: string;
|
username?: string;
|
||||||
parentName?: string;
|
parentName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DepartmentDetailData {
|
||||||
|
department: DepartmentItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 用户相关类型 ====================
|
||||||
|
export interface UserItem {
|
||||||
|
id: number;
|
||||||
|
username: string;
|
||||||
|
realname: string;
|
||||||
|
email: string;
|
||||||
|
tel: string;
|
||||||
|
status: UserStatus;
|
||||||
|
roleId: number;
|
||||||
|
departmentId: number;
|
||||||
|
roleName: string;
|
||||||
|
deptName: string;
|
||||||
|
lastLoginTime: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FormUserItem {
|
||||||
|
username: string;
|
||||||
|
realname: string;
|
||||||
|
tel: string | number;
|
||||||
|
password: string;
|
||||||
|
repassword: string;
|
||||||
|
role_id: number | null;
|
||||||
|
department_id: number | null;
|
||||||
|
email: string;
|
||||||
|
is_manager: ManagerStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DisableUserParam {
|
||||||
|
id: number;
|
||||||
|
status: UserStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserInfo {
|
||||||
|
user: FormUserItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AllUserList {
|
||||||
|
page: PaginationParams & PaginationResult;
|
||||||
|
user?: UserItem[];
|
||||||
|
userList?: UserItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 角色相关类型 ====================
|
||||||
|
export interface RoleItem extends BaseEntity {
|
||||||
|
systemTenantId: number;
|
||||||
|
name: string;
|
||||||
|
createUserId?: number;
|
||||||
|
isDelete?: number;
|
||||||
|
remark?: string;
|
||||||
|
dataType: DataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RoleFormParam {
|
||||||
|
id?: number;
|
||||||
|
name: string;
|
||||||
|
remark?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RoleList {
|
||||||
|
rolesList: RoleItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserPermissionItem {
|
||||||
|
permission: UserPermission;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserPermissionItemList {
|
||||||
|
permission: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SaveRolePermissionParam {
|
||||||
|
id: number;
|
||||||
|
children?: Array<{
|
||||||
|
id: number;
|
||||||
|
path: string;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
export interface UpdateUserRoleParam {
|
||||||
|
role_id: number | null;
|
||||||
|
user_id: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 响应类型别名 ====================
|
||||||
|
export type DepartmentFormRes = HttpResponse<DepartmentIdData>;
|
||||||
export type DepartmentList = DepartmentItem[];
|
export type DepartmentList = DepartmentItem[];
|
||||||
export type DepartmentListRes = HttpResponse<{
|
export type DepartmentListRes = HttpResponse<{
|
||||||
departmentList: DepartmentItem[];
|
departmentList: DepartmentItem[];
|
||||||
}>;
|
}>;
|
||||||
export interface DepartmentDetailData {
|
|
||||||
department: DepartmentItem;
|
|
||||||
}
|
|
||||||
export type DepartmentDetailRes = HttpResponse<DepartmentDetailData>;
|
export type DepartmentDetailRes = HttpResponse<DepartmentDetailData>;
|
||||||
|
export type UserList = UserItem[];
|
||||||
|
export type UserListRes = HttpResponse<UserList>;
|
||||||
|
export type AllUserListRes = HttpResponse<AllUserList>;
|
||||||
|
export type UserInfoRes = HttpResponse<UserInfo>;
|
||||||
|
export type RoleListRes = HttpResponse<RoleList>;
|
||||||
|
export type PermissionRes = HttpResponse<UserPermissionItem>;
|
||||||
|
export type RolePermissionRes = HttpResponse<UserPermissionItemList>;
|
||||||
|
|
||||||
|
// ==================== 部门相关 API ====================
|
||||||
|
export function createDepartment(
|
||||||
|
params: DepartmentFormParams
|
||||||
|
): Promise<DepartmentFormRes> {
|
||||||
|
return axios.post('/department/createDepartment', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateDepartment(
|
||||||
|
params: DepartmentFormParams
|
||||||
|
): Promise<DepartmentFormRes> {
|
||||||
|
return axios.post('/department/updateDepartment', params);
|
||||||
|
}
|
||||||
|
|
||||||
// 获取部门列表
|
|
||||||
export function getDepartmentList(): Promise<DepartmentListRes> {
|
export function getDepartmentList(): Promise<DepartmentListRes> {
|
||||||
return axios.get('/department/getDepartmentList');
|
return axios.get('/department/getDepartmentList');
|
||||||
}
|
}
|
||||||
|
|
@ -61,137 +175,89 @@ export function getDepartmentDetail(id: number): Promise<DepartmentDetailRes> {
|
||||||
return axios.get(`/department/getDepartment?id=${id}`);
|
return axios.get(`/department/getDepartment?id=${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserItem {
|
|
||||||
id: number; // 用户id
|
|
||||||
username: string; // 用户名称
|
|
||||||
realname: string; // 姓名
|
|
||||||
email: string; // 邮箱
|
|
||||||
tel: string; // 手机号
|
|
||||||
status: 1 | 2; // 状态:1 启用,2 禁用
|
|
||||||
roleId: number; // 角色id
|
|
||||||
departmentId: number; // 部门id
|
|
||||||
roleName: string; // 角色名称
|
|
||||||
deptName: string; // 部门名称
|
|
||||||
lastLoginTime: string; // 最后登录时间
|
|
||||||
}
|
|
||||||
export type UserList = UserItem[];
|
|
||||||
export type UserListRes = HttpResponse<UserList>;
|
|
||||||
export interface Pagination {
|
|
||||||
page: number;
|
|
||||||
page_size: number;
|
|
||||||
total?: number;
|
|
||||||
total_pages?: number;
|
|
||||||
}
|
|
||||||
export interface AllUserList {
|
|
||||||
page: Pagination;
|
|
||||||
user: UserListRes;
|
|
||||||
}
|
|
||||||
export type AllUserListRes = HttpResponse<AllUserList>;
|
|
||||||
// 后台-用户列表(除主管外所有用户)
|
|
||||||
export function getAllUserList(params): Promise<AllUserListRes> {
|
|
||||||
return axios.post('/user/getAllUserList', params);
|
|
||||||
}
|
|
||||||
// 后台-用户列表(所有用户)
|
|
||||||
export function getUserList(params): Promise<AllUserListRes> {
|
|
||||||
return axios.post('/user/getUserList', params);
|
|
||||||
}
|
|
||||||
export interface FormUserItem {
|
|
||||||
username: string; // 用户名
|
|
||||||
realname: string; // 姓名
|
|
||||||
tel: string | number; // 手机号
|
|
||||||
password: string; // 密码
|
|
||||||
repassword: string; // 确认密码
|
|
||||||
role_id: number | null; // 角色id
|
|
||||||
department_id: number | null; // 部门id
|
|
||||||
email: string; // 邮件
|
|
||||||
is_manager: 1 | 2; // 是否为主管:1是,2否
|
|
||||||
}
|
|
||||||
// 创建用户
|
|
||||||
export function createUser(params: FormUserItem): Promise<HttpResponse> {
|
|
||||||
return axios.post('/user/createUser', params);
|
|
||||||
}
|
|
||||||
// 更新用户信息
|
|
||||||
export function updateUser(params: FormUserItem): Promise<HttpResponse> {
|
|
||||||
return axios.post('/user/updateUser', params);
|
|
||||||
}
|
|
||||||
interface UserInfo {
|
|
||||||
user: FormUserItem;
|
|
||||||
}
|
|
||||||
export type UserInfoRES = HttpResponse<UserInfo>;
|
|
||||||
// 获取用户信息
|
|
||||||
export function getUserInfo(id: number): Promise<UserInfoRES> {
|
|
||||||
return axios.get(`/user/getUser?id=${id}`);
|
|
||||||
}
|
|
||||||
// 删除用户
|
|
||||||
export function delUser(id: number): Promise<HttpResponse> {
|
|
||||||
return axios.get(`/user/delUser?id=${id}`);
|
|
||||||
}
|
|
||||||
export interface DisableUserParam {
|
|
||||||
id: number;
|
|
||||||
status: number;
|
|
||||||
}
|
|
||||||
// 禁用启用用户
|
|
||||||
export function disableUser(params: DisableUserParam): Promise<HttpResponse> {
|
|
||||||
return axios.post('/user/disableUser', params);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 部门-向上移动
|
|
||||||
export function departmentSetUp(id: number): Promise<HttpResponse> {
|
export function departmentSetUp(id: number): Promise<HttpResponse> {
|
||||||
return axios.get(`/department/setUp?id=${id}`);
|
return axios.get(`/department/setUp?id=${id}`);
|
||||||
}
|
}
|
||||||
// 部门-向下移动
|
|
||||||
export function departmentSetDown(id: number): Promise<HttpResponse> {
|
export function departmentSetDown(id: number): Promise<HttpResponse> {
|
||||||
return axios.get(`/department/setDown?id=${id}`);
|
return axios.get(`/department/setDown?id=${id}`);
|
||||||
}
|
}
|
||||||
// 删除部门
|
|
||||||
export function delDepartment(id: number): Promise<HttpResponse> {
|
export function delDepartment(id: number): Promise<HttpResponse> {
|
||||||
return axios.get(`/department/delDepartment?id=${id}`);
|
return axios.get(`/department/delDepartment?id=${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RoleItem {
|
// ==================== 用户相关 API ====================
|
||||||
id: number; // 角色id
|
export function getAllUserList(
|
||||||
systemTenantId: number; // 租户名称
|
params: PaginationParams
|
||||||
name: string; // 角色名称
|
): Promise<AllUserListRes> {
|
||||||
createUserId?: number; // 创建人id
|
return axios.post('/user/getAllUserList', params);
|
||||||
isDelete?: number; // 是否删除
|
|
||||||
remark?: string;
|
|
||||||
dataType: number; // 数据权限类型:1全部数据权限,2自定义数据权限,3仅本人数据
|
|
||||||
createdAt: string;
|
|
||||||
updatedAt: string;
|
|
||||||
}
|
}
|
||||||
// 角色列表
|
|
||||||
export interface RoleList {
|
export function getUserList(params: PaginationParams): Promise<AllUserListRes> {
|
||||||
rolesList: RoleItem[];
|
return axios.post('/user/getUserList', params);
|
||||||
}
|
}
|
||||||
export type RoleListRes = HttpResponse<RoleList>;
|
|
||||||
// 角色列表
|
export function createUser(params: FormUserItem): Promise<HttpResponse> {
|
||||||
|
return axios.post('/user/createUser', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateUser(params: FormUserItem): Promise<HttpResponse> {
|
||||||
|
return axios.post('/user/updateUser', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUserInfo(id: number): Promise<UserInfoRes> {
|
||||||
|
return axios.get(`/user/getUser?id=${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function delUser(id: number): Promise<HttpResponse> {
|
||||||
|
return axios.get(`/user/delUser?id=${id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function disableUser(params: DisableUserParam): Promise<HttpResponse> {
|
||||||
|
return axios.post('/user/disableUser', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 角色相关 API ====================
|
||||||
export function getRoleList(): Promise<RoleListRes> {
|
export function getRoleList(): Promise<RoleListRes> {
|
||||||
return axios.get('/role/getRoleList');
|
return axios.get('/role/getRoleList');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建角色
|
|
||||||
export interface RoleFormParam {
|
|
||||||
id?: number; // 角色id
|
|
||||||
name: string; // 姓名
|
|
||||||
remark?: string; // 备注
|
|
||||||
}
|
|
||||||
export function createRole(params: RoleFormParam): Promise<HttpResponse> {
|
export function createRole(params: RoleFormParam): Promise<HttpResponse> {
|
||||||
return axios.post('/role/createRole', params);
|
return axios.post('/role/createRole', params);
|
||||||
}
|
}
|
||||||
// 更新角色
|
|
||||||
export function updateRole(params: RoleFormParam): Promise<HttpResponse> {
|
export function updateRole(params: RoleFormParam): Promise<HttpResponse> {
|
||||||
return axios.post('/role/updateRole', params);
|
return axios.post('/role/updateRole', params);
|
||||||
}
|
}
|
||||||
// 删除角色
|
|
||||||
export function delRole(id: number): Promise<HttpResponse> {
|
export function delRole(id: number): Promise<HttpResponse> {
|
||||||
return axios.get(`/role/delRole?id=${id}`);
|
return axios.get(`/role/delRole?id=${id}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// // 项目信息
|
export function getPermissionList(): Promise<PermissionRes> {
|
||||||
// export function getProjectDetail(id: string) {
|
return axios.get('/role/getPermissionList');
|
||||||
// return axios.get<any>(`/project/getProject?id=${id}`);
|
}
|
||||||
// }
|
|
||||||
// // 项目列表(分页)
|
export function getRolePermission(id: number): Promise<RolePermissionRes> {
|
||||||
// export function queryPolicyList(params: ProjectParams) {
|
return axios.get(`role/getRolePermission?id=${id}`);
|
||||||
// return axios.post<any>('/project/getProjectList', { params });
|
}
|
||||||
// }
|
|
||||||
|
export function saveRolePermission(
|
||||||
|
params: SaveRolePermissionParam
|
||||||
|
): Promise<HttpResponse> {
|
||||||
|
return axios.post('role/saveRolePermission', params);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 角色下的用户列表
|
||||||
|
export function getUserListFromRole(
|
||||||
|
params: PaginationParams
|
||||||
|
): Promise<AllUserListRes> {
|
||||||
|
return axios.post('role/getUserList', params);
|
||||||
|
}
|
||||||
|
// 角色下的用户列表
|
||||||
|
export function updateUserRole(
|
||||||
|
params: UpdateUserRoleParam
|
||||||
|
): Promise<HttpResponse> {
|
||||||
|
return axios.post('role/updateUserRole', params);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,5 +9,5 @@ export default {
|
||||||
'messageBox.switchRoles': '切换角色',
|
'messageBox.switchRoles': '切换角色',
|
||||||
'messageBox.userCenter': '用户中心',
|
'messageBox.userCenter': '用户中心',
|
||||||
'messageBox.userSettings': '用户设置',
|
'messageBox.userSettings': '用户设置',
|
||||||
'messageBox.logout': '登出登录',
|
'messageBox.logout': '退出登录',
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,22 @@ export default {
|
||||||
'edit': '编辑',
|
'edit': '编辑',
|
||||||
'more': '更多',
|
'more': '更多',
|
||||||
'user': '用户',
|
'user': '用户',
|
||||||
|
'role.list': '角色列表',
|
||||||
|
'role.add': '新增角色',
|
||||||
|
'role.edit': '编辑角色',
|
||||||
|
'roleName': '角色名称',
|
||||||
|
'roleDesc': '角色描述',
|
||||||
|
'permission': '权限',
|
||||||
|
'function.permission': '功能权限',
|
||||||
|
'data.permission': '数据权限',
|
||||||
|
'user.assignment': '用户分配',
|
||||||
|
'submit': '保存',
|
||||||
|
'last.updated': '最后更新',
|
||||||
|
'all.checked': '全部选中',
|
||||||
|
'all.clear': '全部清空',
|
||||||
|
'function.permission.setting': '功能权限设置',
|
||||||
|
'user.assignment.setting': '用户分配设置',
|
||||||
|
'change.role': '变更角色',
|
||||||
|
|
||||||
...localeSettings,
|
...localeSettings,
|
||||||
...localeMessageBox,
|
...localeMessageBox,
|
||||||
|
|
|
||||||
|
|
@ -72,4 +72,7 @@ export interface UserPermission {
|
||||||
visible: 1 | 2; // 是否可见:1显示、2隐藏
|
visible: 1 | 2; // 是否可见:1显示、2隐藏
|
||||||
createdAt: string; // 创建时间
|
createdAt: string; // 创建时间
|
||||||
updatedAt: string; // 更新时间
|
updatedAt: string; // 更新时间
|
||||||
|
system_tenant_permission_id?: number; // 租客权限id
|
||||||
|
tenant_id?: number; // 租客id
|
||||||
|
children?: UserPermission[] | []; // 子集
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
<template>
|
<template>
|
||||||
<div>house-view</div>
|
<div>house-view</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
98
src/views/setting/user/components/change-role-drawer.vue
Normal file
98
src/views/setting/user/components/change-role-drawer.vue
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
<template>
|
||||||
|
<a-modal
|
||||||
|
:visible="visible"
|
||||||
|
:title="t('change.role')"
|
||||||
|
unmount-on-close
|
||||||
|
@ok="handleOk"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
>
|
||||||
|
<a-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="form"
|
||||||
|
:rules="rules"
|
||||||
|
auto-label-width
|
||||||
|
layout="vertical"
|
||||||
|
>
|
||||||
|
<!-- 角色 -->
|
||||||
|
<a-form-item :label="$t('change.role')" field="role_id" required>
|
||||||
|
<a-select
|
||||||
|
v-model="form.role_id"
|
||||||
|
:placeholder="$t('please.select', { placeholder: $t('role') })"
|
||||||
|
>
|
||||||
|
<a-option
|
||||||
|
v-for="role in props.roleList"
|
||||||
|
:key="Number(role.id)"
|
||||||
|
:value="Number(role.id)"
|
||||||
|
>
|
||||||
|
{{ role.name }}</a-option
|
||||||
|
>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, watch, reactive } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import type { FormInstance } from '@arco-design/web-vue';
|
||||||
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
import { UpdateUserRoleParam, updateUserRole, RoleItem } from '@/api/setting';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
visible: boolean;
|
||||||
|
roleId: number | null;
|
||||||
|
userId: number | null;
|
||||||
|
roleList: RoleItem[] | null;
|
||||||
|
}>();
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'update:visible', val: boolean): void;
|
||||||
|
(e: 'updateUser'): void;
|
||||||
|
}>();
|
||||||
|
// 表单数据
|
||||||
|
const formRef = ref<FormInstance>();
|
||||||
|
const defaultForm: UpdateUserRoleParam = {
|
||||||
|
role_id: props.roleId,
|
||||||
|
user_id: props.userId,
|
||||||
|
};
|
||||||
|
const form = reactive<UpdateUserRoleParam>({ ...defaultForm });
|
||||||
|
const { t } = useI18n();
|
||||||
|
// 校验规则
|
||||||
|
const rules = reactive({
|
||||||
|
role_id: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: t('please.select', { placeholder: t('role') }),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
watch(
|
||||||
|
() => [props.roleId, props.userId],
|
||||||
|
([newRoleId, newUserId]) => {
|
||||||
|
form.role_id = newRoleId;
|
||||||
|
form.user_id = newUserId;
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
const handleOk = async () => {
|
||||||
|
try {
|
||||||
|
const valid = await formRef.value.validate();
|
||||||
|
if (valid) return;
|
||||||
|
const params = { ...form };
|
||||||
|
const res = await updateUserRole(params);
|
||||||
|
if (res?.code === 200) {
|
||||||
|
Message.success(res?.message);
|
||||||
|
emit('updateUser');
|
||||||
|
emit('update:visible', false);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// 捕获异常,暂不处理
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
emit('update:visible', false);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped></style>
|
||||||
268
src/views/setting/user/components/mock.json
Normal file
268
src/views/setting/user/components/mock.json
Normal file
|
|
@ -0,0 +1,268 @@
|
||||||
|
{
|
||||||
|
"permission": [
|
||||||
|
{
|
||||||
|
"system_tenant_permission_id": 100,
|
||||||
|
"tenant_id": 1,
|
||||||
|
"perm_id": 1,
|
||||||
|
"id": 1,
|
||||||
|
"parent_id": 0,
|
||||||
|
"prem_name": "业务",
|
||||||
|
"level": 1,
|
||||||
|
"perm_key": "business",
|
||||||
|
"prem_type": 1,
|
||||||
|
"path": "/1/",
|
||||||
|
"sort": 1,
|
||||||
|
"visible": 1,
|
||||||
|
"createdAt": "2024-06-20 10:00:00",
|
||||||
|
"updatedAt": "2024-06-20 10:00:00",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"system_tenant_permission_id": 101,
|
||||||
|
"tenant_id": 1,
|
||||||
|
"perm_id": 2,
|
||||||
|
"id": 2,
|
||||||
|
"parent_id": 1,
|
||||||
|
"prem_name": "项目管理",
|
||||||
|
"level": 2,
|
||||||
|
"perm_key": "project_manage",
|
||||||
|
"prem_type": 1,
|
||||||
|
"path": "/1/2/",
|
||||||
|
"sort": 1,
|
||||||
|
"visible": 1,
|
||||||
|
"createdAt": "2024-06-20 10:01:00",
|
||||||
|
"updatedAt": "2024-06-20 10:01:00",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"system_tenant_permission_id": 102,
|
||||||
|
"tenant_id": 1,
|
||||||
|
"perm_id": 3,
|
||||||
|
"id": 3,
|
||||||
|
"parent_id": 2,
|
||||||
|
"prem_name": "查看项目",
|
||||||
|
"level": 3,
|
||||||
|
"perm_key": "view_project",
|
||||||
|
"prem_type": 4,
|
||||||
|
"path": "/1/2/3/",
|
||||||
|
"sort": 1,
|
||||||
|
"visible": 1,
|
||||||
|
"createdAt": "2024-06-20 10:02:00",
|
||||||
|
"updatedAt": "2024-06-20 10:02:00",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"system_tenant_permission_id": 103,
|
||||||
|
"tenant_id": 1,
|
||||||
|
"perm_id": 4,
|
||||||
|
"id": 4,
|
||||||
|
"parent_id": 3,
|
||||||
|
"prem_name": "添加收入目标",
|
||||||
|
"level": 4,
|
||||||
|
"perm_key": "add_income_target",
|
||||||
|
"prem_type": 2,
|
||||||
|
"path": "/1/2/3/4/",
|
||||||
|
"sort": 1,
|
||||||
|
"visible": 1,
|
||||||
|
"createdAt": "2024-06-20 10:03:00",
|
||||||
|
"updatedAt": "2024-06-20 10:03:00",
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"system_tenant_permission_id": 104,
|
||||||
|
"tenant_id": 1,
|
||||||
|
"perm_id": 5,
|
||||||
|
"id": 5,
|
||||||
|
"parent_id": 3,
|
||||||
|
"prem_name": "编辑收入目标",
|
||||||
|
"level": 4,
|
||||||
|
"perm_key": "edit_income_target",
|
||||||
|
"prem_type": 2,
|
||||||
|
"path": "/1/2/3/5/",
|
||||||
|
"sort": 2,
|
||||||
|
"visible": 1,
|
||||||
|
"createdAt": "2024-06-20 10:04:00",
|
||||||
|
"updatedAt": "2024-06-20 10:04:00",
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"system_tenant_permission_id": 105,
|
||||||
|
"tenant_id": 1,
|
||||||
|
"perm_id": 6,
|
||||||
|
"id": 6,
|
||||||
|
"parent_id": 2,
|
||||||
|
"prem_name": "编辑项目",
|
||||||
|
"level": 3,
|
||||||
|
"perm_key": "edit_project",
|
||||||
|
"prem_type": 4,
|
||||||
|
"path": "/1/2/6/",
|
||||||
|
"sort": 2,
|
||||||
|
"visible": 1,
|
||||||
|
"createdAt": "2024-06-20 10:05:00",
|
||||||
|
"updatedAt": "2024-06-20 10:05:00",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"system_tenant_permission_id": 106,
|
||||||
|
"tenant_id": 1,
|
||||||
|
"perm_id": 7,
|
||||||
|
"id": 7,
|
||||||
|
"parent_id": 6,
|
||||||
|
"prem_name": "删除收入目标",
|
||||||
|
"level": 4,
|
||||||
|
"perm_key": "delete_income_target",
|
||||||
|
"prem_type": 2,
|
||||||
|
"path": "/1/2/6/7/",
|
||||||
|
"sort": 1,
|
||||||
|
"visible": 1,
|
||||||
|
"createdAt": "2024-06-20 10:06:00",
|
||||||
|
"updatedAt": "2024-06-20 10:06:00",
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"system_tenant_permission_id": 107,
|
||||||
|
"tenant_id": 1,
|
||||||
|
"perm_id": 8,
|
||||||
|
"id": 8,
|
||||||
|
"parent_id": 1,
|
||||||
|
"prem_name": "合同管理",
|
||||||
|
"level": 2,
|
||||||
|
"perm_key": "contract_manage",
|
||||||
|
"prem_type": 1,
|
||||||
|
"path": "/1/8/",
|
||||||
|
"sort": 2,
|
||||||
|
"visible": 1,
|
||||||
|
"createdAt": "2024-06-20 10:07:00",
|
||||||
|
"updatedAt": "2024-06-20 10:07:00",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"system_tenant_permission_id": 108,
|
||||||
|
"tenant_id": 1,
|
||||||
|
"perm_id": 9,
|
||||||
|
"id": 9,
|
||||||
|
"parent_id": 8,
|
||||||
|
"prem_name": "查看合同",
|
||||||
|
"level": 3,
|
||||||
|
"perm_key": "view_contract",
|
||||||
|
"prem_type": 4,
|
||||||
|
"path": "/1/8/9/",
|
||||||
|
"sort": 1,
|
||||||
|
"visible": 1,
|
||||||
|
"createdAt": "2024-06-20 10:08:00",
|
||||||
|
"updatedAt": "2024-06-20 10:08:00",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"system_tenant_permission_id": 109,
|
||||||
|
"tenant_id": 1,
|
||||||
|
"perm_id": 10,
|
||||||
|
"id": 10,
|
||||||
|
"parent_id": 9,
|
||||||
|
"prem_name": "导出合同",
|
||||||
|
"level": 4,
|
||||||
|
"perm_key": "export_contract",
|
||||||
|
"prem_type": 2,
|
||||||
|
"path": "/1/8/9/10/",
|
||||||
|
"sort": 1,
|
||||||
|
"visible": 1,
|
||||||
|
"createdAt": "2024-06-20 10:09:00",
|
||||||
|
"updatedAt": "2024-06-20 10:09:00",
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"system_tenant_permission_id": 200,
|
||||||
|
"tenant_id": 1,
|
||||||
|
"perm_id": 20,
|
||||||
|
"id": 20,
|
||||||
|
"parent_id": 0,
|
||||||
|
"prem_name": "房源视图",
|
||||||
|
"level": 1,
|
||||||
|
"perm_key": "house_view",
|
||||||
|
"prem_type": 1,
|
||||||
|
"path": "/20/",
|
||||||
|
"sort": 2,
|
||||||
|
"visible": 1,
|
||||||
|
"createdAt": "2024-06-20 11:00:00",
|
||||||
|
"updatedAt": "2024-06-20 11:00:00",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"system_tenant_permission_id": 201,
|
||||||
|
"tenant_id": 1,
|
||||||
|
"perm_id": 21,
|
||||||
|
"id": 21,
|
||||||
|
"parent_id": 20,
|
||||||
|
"prem_name": "新建房源",
|
||||||
|
"level": 2,
|
||||||
|
"perm_key": "add_house",
|
||||||
|
"prem_type": 2,
|
||||||
|
"path": "/20/21/",
|
||||||
|
"sort": 1,
|
||||||
|
"visible": 1,
|
||||||
|
"createdAt": "2024-06-20 11:01:00",
|
||||||
|
"updatedAt": "2024-06-20 11:01:00",
|
||||||
|
"children": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"system_tenant_permission_id": 202,
|
||||||
|
"tenant_id": 1,
|
||||||
|
"perm_id": 22,
|
||||||
|
"id": 22,
|
||||||
|
"parent_id": 20,
|
||||||
|
"prem_name": "导入房源",
|
||||||
|
"level": 2,
|
||||||
|
"perm_key": "import_house",
|
||||||
|
"prem_type": 3,
|
||||||
|
"path": "/20/22/",
|
||||||
|
"sort": 2,
|
||||||
|
"visible": 1,
|
||||||
|
"createdAt": "2024-06-20 11:02:00",
|
||||||
|
"updatedAt": "2024-06-20 11:02:00",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"system_tenant_permission_id": 203,
|
||||||
|
"tenant_id": 1,
|
||||||
|
"perm_id": 23,
|
||||||
|
"id": 23,
|
||||||
|
"parent_id": 22,
|
||||||
|
"prem_name": "批量导入",
|
||||||
|
"level": 3,
|
||||||
|
"perm_key": "batch_import",
|
||||||
|
"prem_type": 3,
|
||||||
|
"path": "/20/22/23/",
|
||||||
|
"sort": 1,
|
||||||
|
"visible": 1,
|
||||||
|
"createdAt": "2024-06-20 11:03:00",
|
||||||
|
"updatedAt": "2024-06-20 11:03:00",
|
||||||
|
"children": [
|
||||||
|
{
|
||||||
|
"system_tenant_permission_id": 204,
|
||||||
|
"tenant_id": 1,
|
||||||
|
"perm_id": 24,
|
||||||
|
"id": 24,
|
||||||
|
"parent_id": 23,
|
||||||
|
"prem_name": "导入校验",
|
||||||
|
"level": 4,
|
||||||
|
"perm_key": "import_check",
|
||||||
|
"prem_type": 2,
|
||||||
|
"path": "/20/22/23/24/",
|
||||||
|
"sort": 1,
|
||||||
|
"visible": 1,
|
||||||
|
"createdAt": "2024-06-20 11:04:00",
|
||||||
|
"updatedAt": "2024-06-20 11:04:00",
|
||||||
|
"children": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
145
src/views/setting/user/components/permission-collapse.vue
Normal file
145
src/views/setting/user/components/permission-collapse.vue
Normal file
|
|
@ -0,0 +1,145 @@
|
||||||
|
<template>
|
||||||
|
<div class="function_permission_collapse">
|
||||||
|
<div class="top">
|
||||||
|
<h4 class="title">{{ $t('function.permission.setting') }}</h4>
|
||||||
|
<a-space>
|
||||||
|
<a-button @click="selectAll">全部选中</a-button>
|
||||||
|
<a-button @click="clearAll">全部清空</a-button>
|
||||||
|
</a-space>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="collapse_wrap">
|
||||||
|
<a-collapse accordion :active-key="defaultActiveKey">
|
||||||
|
<a-collapse-item
|
||||||
|
v-for="item in props.permissionList"
|
||||||
|
:key="item.id"
|
||||||
|
:header="item.prem_name"
|
||||||
|
>
|
||||||
|
<div class="collapse-item-body">
|
||||||
|
<PermissionNode
|
||||||
|
v-for="child in item.children"
|
||||||
|
:key="child.id"
|
||||||
|
:node="child"
|
||||||
|
:parent-node="item"
|
||||||
|
:checked-keys="checkedKeys"
|
||||||
|
@update:checked-keys="(val) => (checkedKeys = val)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</a-collapse-item>
|
||||||
|
</a-collapse>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, watch } from 'vue';
|
||||||
|
import { getRolePermission } from '@/api/setting';
|
||||||
|
import PermissionNode from './permission-node.vue';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
roleId: number | null;
|
||||||
|
permissionList: any;
|
||||||
|
}>();
|
||||||
|
const emit = defineEmits(['update:checkedKeys']);
|
||||||
|
|
||||||
|
const checkedKeys = ref<number[]>([]);
|
||||||
|
const defaultActiveKey = ref<number[]>([]);
|
||||||
|
|
||||||
|
const getRolePermissionData = async (id: number) => {
|
||||||
|
try {
|
||||||
|
const { code, data } = await getRolePermission(id);
|
||||||
|
if (code === 200 && data) {
|
||||||
|
const { permission } = data;
|
||||||
|
if (!permission || permission.length === 0) {
|
||||||
|
checkedKeys.value = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 如果返回的是权限对象数组,提取ID
|
||||||
|
checkedKeys.value = Array.isArray(permission)
|
||||||
|
? permission.map((p: any) => (typeof p === 'object' ? p.id : p))
|
||||||
|
: [];
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取角色权限失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 递归收集所有权限ID(支持无限层级)
|
||||||
|
function collectAllIds(list: any[]): number[] {
|
||||||
|
const ids: number[] = [];
|
||||||
|
|
||||||
|
const traverse = (items: any[]) => {
|
||||||
|
items.forEach((item: any) => {
|
||||||
|
ids.push(item.id);
|
||||||
|
if (item.children && item.children.length > 0) {
|
||||||
|
traverse(item.children);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
traverse(list);
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectAll() {
|
||||||
|
if (!props.permissionList || props.permissionList.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
checkedKeys.value = collectAllIds(props.permissionList);
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearAll() {
|
||||||
|
checkedKeys.value = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => checkedKeys.value,
|
||||||
|
(val) => {
|
||||||
|
emit('update:checkedKeys', checkedKeys.value);
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.roleId,
|
||||||
|
(val, oldval) => {
|
||||||
|
if (val && val !== oldval) {
|
||||||
|
getRolePermissionData(val);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
// 监听权限列表变化,设置默认展开项
|
||||||
|
watch(
|
||||||
|
() => props.permissionList,
|
||||||
|
(newList) => {
|
||||||
|
if (newList && newList.length > 0) {
|
||||||
|
defaultActiveKey.value = [newList[0].id];
|
||||||
|
console.log(defaultActiveKey.value, 'defaultActiveKey');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.function_permission_collapse {
|
||||||
|
.top {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 16px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapse_wrap {
|
||||||
|
padding-bottom: 20px;
|
||||||
|
margin-top: 10px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
237
src/views/setting/user/components/permission-node.vue
Normal file
237
src/views/setting/user/components/permission-node.vue
Normal file
|
|
@ -0,0 +1,237 @@
|
||||||
|
<template>
|
||||||
|
<div class="permission-node" :class="'level-' + node.level">
|
||||||
|
<!-- 非按钮权限 -->
|
||||||
|
<a-checkbox
|
||||||
|
v-if="node.prem_type !== 2"
|
||||||
|
:indeterminate="isIndeterminate"
|
||||||
|
:model-value="isChecked"
|
||||||
|
@change="onCheck($event)"
|
||||||
|
>
|
||||||
|
{{ node.prem_name }}
|
||||||
|
</a-checkbox>
|
||||||
|
|
||||||
|
<!-- 递归渲染所有子节点(非按钮权限) -->
|
||||||
|
<div v-if="normalChildren.length" class="children">
|
||||||
|
<PermissionNode
|
||||||
|
v-for="child in normalChildren"
|
||||||
|
:key="child.id"
|
||||||
|
:node="child"
|
||||||
|
:parent-node="node"
|
||||||
|
:checked-keys="checkedKeys"
|
||||||
|
@update:checked-keys="updateCheckedKeys"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 按钮权限一行展示 -->
|
||||||
|
<div v-if="buttonChildren.length" class="btn-permission-row">
|
||||||
|
<a-button
|
||||||
|
v-for="btn in buttonChildren"
|
||||||
|
:key="btn.id"
|
||||||
|
size="mini"
|
||||||
|
:type="checkedKeys.includes(btn.id) ? 'outline' : undefined"
|
||||||
|
@click="toggleButtonPermission(btn.id)"
|
||||||
|
>
|
||||||
|
{{ btn.prem_name }}
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
node: any;
|
||||||
|
checkedKeys: number[];
|
||||||
|
parentNode?: any;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:checkedKeys']);
|
||||||
|
|
||||||
|
// 递归获取所有子节点的ID(包括子节点的子节点)
|
||||||
|
function getAllChildrenIds(node: any): number[] {
|
||||||
|
let ids: number[] = [node.id];
|
||||||
|
if (node.children && node.children.length > 0) {
|
||||||
|
node.children.forEach((child: any) => {
|
||||||
|
ids = ids.concat(getAllChildrenIds(child));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归获取所有父节点的ID
|
||||||
|
function getAllParentIds(node: any, parentNode: any): number[] {
|
||||||
|
const ids: number[] = [];
|
||||||
|
let currentParent = parentNode;
|
||||||
|
|
||||||
|
while (currentParent) {
|
||||||
|
if (!ids.includes(currentParent.id)) {
|
||||||
|
ids.push(currentParent.id);
|
||||||
|
}
|
||||||
|
currentParent = currentParent.parentNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ids;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 移除空的父节点(当所有子节点都未选中时)
|
||||||
|
function removeEmptyParents(node: any, keys: number[]) {
|
||||||
|
const parent = props.parentNode;
|
||||||
|
if (!parent || !parent.children) return;
|
||||||
|
|
||||||
|
// 检查当前父节点的所有子节点是否都没有被选中
|
||||||
|
const hasCheckedChildren = parent.children.some((child: any) => {
|
||||||
|
const childIds = getAllChildrenIds(child);
|
||||||
|
return childIds.some((id) => keys.includes(id));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!hasCheckedChildren) {
|
||||||
|
// 移除父节点
|
||||||
|
const parentIndex = keys.indexOf(parent.id);
|
||||||
|
if (parentIndex !== -1) {
|
||||||
|
keys.splice(parentIndex, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归检查上级父节点
|
||||||
|
if (parent.parentNode) {
|
||||||
|
removeEmptyParents(parent, keys);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查当前节点是否被选中
|
||||||
|
const isChecked = computed(() => {
|
||||||
|
if (!props.node.children || props.node.children.length === 0) {
|
||||||
|
return props.checkedKeys.includes(props.node.id);
|
||||||
|
}
|
||||||
|
// 对于有子节点的节点,只有当所有子节点都被选中时才认为被选中
|
||||||
|
const allChildrenIds = getAllChildrenIds(props.node);
|
||||||
|
return allChildrenIds.every((id) => props.checkedKeys.includes(id));
|
||||||
|
});
|
||||||
|
|
||||||
|
// 检查是否为半选状态
|
||||||
|
const isIndeterminate = computed(() => {
|
||||||
|
if (!props.node.children || props.node.children.length === 0) return false;
|
||||||
|
|
||||||
|
const allChildrenIds = getAllChildrenIds(props.node);
|
||||||
|
const checkedCount = allChildrenIds.filter((id) =>
|
||||||
|
props.checkedKeys.includes(id)
|
||||||
|
).length;
|
||||||
|
|
||||||
|
return checkedCount > 0 && checkedCount < allChildrenIds.length;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 过滤出非按钮权限的子节点
|
||||||
|
const normalChildren = computed(() =>
|
||||||
|
(props.node.children || []).filter((child: any) => child.prem_type !== 2)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 过滤出按钮权限的子节点
|
||||||
|
const buttonChildren = computed(() =>
|
||||||
|
(props.node.children || []).filter((child: any) => child.prem_type === 2)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 处理复选框变化
|
||||||
|
function onCheck(checked: boolean) {
|
||||||
|
let newKeys = [...props.checkedKeys];
|
||||||
|
const allChildrenIds = getAllChildrenIds(props.node);
|
||||||
|
|
||||||
|
if (checked) {
|
||||||
|
// 选中当前节点及其所有子节点
|
||||||
|
allChildrenIds.forEach((id) => {
|
||||||
|
if (!newKeys.includes(id)) {
|
||||||
|
newKeys.push(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 选中所有父节点
|
||||||
|
const parentIds = getAllParentIds(props.node, props.parentNode);
|
||||||
|
parentIds.forEach((id) => {
|
||||||
|
if (!newKeys.includes(id)) {
|
||||||
|
newKeys.push(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// 取消选中当前节点及其所有子节点
|
||||||
|
newKeys = newKeys.filter((id) => !allChildrenIds.includes(id));
|
||||||
|
|
||||||
|
// 检查并移除空的父节点
|
||||||
|
removeEmptyParents(props.node, newKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit('update:checkedKeys', newKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 切换按钮权限
|
||||||
|
function toggleButtonPermission(id: number) {
|
||||||
|
const newKeys = [...props.checkedKeys];
|
||||||
|
const index = newKeys.indexOf(id);
|
||||||
|
|
||||||
|
if (index > -1) {
|
||||||
|
// 取消选中
|
||||||
|
newKeys.splice(index, 1);
|
||||||
|
removeEmptyParents(props.node, newKeys);
|
||||||
|
} else {
|
||||||
|
// 选中
|
||||||
|
newKeys.push(id);
|
||||||
|
|
||||||
|
// 选中所有父节点
|
||||||
|
const parentIds = getAllParentIds(props.node, props.parentNode);
|
||||||
|
parentIds.forEach((parentId) => {
|
||||||
|
if (!newKeys.includes(parentId)) {
|
||||||
|
newKeys.push(parentId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
emit('update:checkedKeys', newKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新选中的权限
|
||||||
|
function updateCheckedKeys(newKeys: number[]) {
|
||||||
|
emit('update:checkedKeys', newKeys);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.permission-node {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.level-1 {
|
||||||
|
margin-left: 0;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.level-2 {
|
||||||
|
margin-left: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.level-3 {
|
||||||
|
margin-left: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.level-4 {
|
||||||
|
margin-left: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.level-5 {
|
||||||
|
margin-left: 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.level-6 {
|
||||||
|
margin-left: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.children {
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-permission-row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
margin-left: 32px;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
150
src/views/setting/user/components/role-form-drawer.vue
Normal file
150
src/views/setting/user/components/role-form-drawer.vue
Normal file
|
|
@ -0,0 +1,150 @@
|
||||||
|
<template>
|
||||||
|
<a-modal
|
||||||
|
:visible="visible"
|
||||||
|
:title="isEdit ? $t('role.edit') : $t('role.add')"
|
||||||
|
unmount-on-close
|
||||||
|
@ok="handleOk"
|
||||||
|
@cancel="handleCancel"
|
||||||
|
>
|
||||||
|
<a-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="form"
|
||||||
|
:rules="rules"
|
||||||
|
auto-label-width
|
||||||
|
layout="vertical"
|
||||||
|
>
|
||||||
|
<!-- 角色名称 -->
|
||||||
|
<a-form-item :label="$t('roleName')" field="name" required>
|
||||||
|
<a-input
|
||||||
|
v-model="form.name"
|
||||||
|
:placeholder="$t('please.enter', { placeholder: $t('roleName') })"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
<!-- 角色描述 -->
|
||||||
|
<a-form-item :label="$t('roleDesc')" field="remark">
|
||||||
|
<a-textarea
|
||||||
|
v-model="form.remark"
|
||||||
|
:auto-size="{ minRows: 3, maxRows: 8 }"
|
||||||
|
:placeholder="$t('please.enter', { placeholder: $t('roleDesc') })"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</a-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, watch, reactive } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import type { FormInstance } from '@arco-design/web-vue';
|
||||||
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
import {
|
||||||
|
RoleFormParam,
|
||||||
|
RoleItem,
|
||||||
|
updateRole,
|
||||||
|
createRole,
|
||||||
|
} from '@/api/setting';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
visible: boolean;
|
||||||
|
isEdit: boolean;
|
||||||
|
record?: RoleItem | null;
|
||||||
|
}>();
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'update:visible', val: boolean): void;
|
||||||
|
(e: 'submitted'): void;
|
||||||
|
}>();
|
||||||
|
// 表单数据
|
||||||
|
const formRef = ref<FormInstance>();
|
||||||
|
const defaultForm: RoleFormParam = {
|
||||||
|
name: '',
|
||||||
|
remark: '',
|
||||||
|
};
|
||||||
|
const form = reactive<RoleFormParam>({ ...defaultForm });
|
||||||
|
const { t } = useI18n();
|
||||||
|
// 校验规则
|
||||||
|
const rules = reactive({
|
||||||
|
name: [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: t('please.enter', { placeholder: t('roleName') }),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
remark: [
|
||||||
|
{
|
||||||
|
message: t('please.enter', { placeholder: t('roleDesc') }),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
watch(
|
||||||
|
() => props.visible,
|
||||||
|
(val) => {
|
||||||
|
if (val) {
|
||||||
|
if (props.isEdit && props.record) {
|
||||||
|
const record = props.record as RoleItem & {
|
||||||
|
roleId?: number;
|
||||||
|
departmentId?: number;
|
||||||
|
isManager?: number;
|
||||||
|
};
|
||||||
|
Object.assign(form, {
|
||||||
|
...record,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Object.assign(form, defaultForm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
const handleOk = async () => {
|
||||||
|
try {
|
||||||
|
const valid = await formRef.value.validate();
|
||||||
|
if (valid) return;
|
||||||
|
const params = { ...form };
|
||||||
|
const res = props?.isEdit
|
||||||
|
? await updateRole(params)
|
||||||
|
: await createRole(params);
|
||||||
|
if (res?.code === 200) {
|
||||||
|
Message.success(res?.message);
|
||||||
|
emit('submitted');
|
||||||
|
emit('update:visible', false);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// 捕获异常,暂不处理
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
emit('update:visible', false);
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
:deep(label.arco-form-item-label) {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label_wrap {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.required {
|
||||||
|
color: #f53f3f;
|
||||||
|
margin-right: 4px;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -133,6 +133,7 @@
|
||||||
FormUserItem,
|
FormUserItem,
|
||||||
disableUser,
|
disableUser,
|
||||||
delUser,
|
delUser,
|
||||||
|
UserStatus,
|
||||||
} from '@/api/setting';
|
} from '@/api/setting';
|
||||||
import useDepartmentList from '@/composables/useDepartmentList';
|
import useDepartmentList from '@/composables/useDepartmentList';
|
||||||
import useDataTable from '@/composables/useDataTable';
|
import useDataTable from '@/composables/useDataTable';
|
||||||
|
|
@ -329,7 +330,8 @@
|
||||||
};
|
};
|
||||||
const handleDisableUser = async (id: number, currentStatus: number) => {
|
const handleDisableUser = async (id: number, currentStatus: number) => {
|
||||||
try {
|
try {
|
||||||
const param = { id, status: currentStatus === 1 ? 2 : 1 };
|
const status: UserStatus = currentStatus === 1 ? 2 : 1;
|
||||||
|
const param = { id, status };
|
||||||
const { code, message } = await disableUser(param);
|
const { code, message } = await disableUser(param);
|
||||||
if (code === 200) {
|
if (code === 200) {
|
||||||
Message.success(message);
|
Message.success(message);
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,447 @@
|
||||||
<template>
|
<template>
|
||||||
<div>帅哥kilo</div>
|
<div class="setting_role_list">
|
||||||
|
<Breadcrumb
|
||||||
|
:items="['menu.setting', 'menu.setting.user', 'menu.setting.role']"
|
||||||
|
/>
|
||||||
|
<a-row :gutter="12" :wrap="false">
|
||||||
|
<a-col flex="310px">
|
||||||
|
<a-card class="full_height" :bordered="false">
|
||||||
|
<template #title>
|
||||||
|
<div class="card-title_between">
|
||||||
|
<p class="title">{{ $t('role.list') }}</p>
|
||||||
|
<a-button type="primary" @click="handleAddRole">
|
||||||
|
<template #icon>
|
||||||
|
<icon-plus />
|
||||||
|
</template>
|
||||||
|
{{ $t('role.add') }}
|
||||||
|
</a-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<a-spin style="display: block" :loading="loading">
|
||||||
|
<ul class="role_list">
|
||||||
|
<li
|
||||||
|
v-for="role in roleList"
|
||||||
|
:key="role.id"
|
||||||
|
:class="[
|
||||||
|
'role_item',
|
||||||
|
{ active: currentRoleActiveId === role.id },
|
||||||
|
]"
|
||||||
|
@click="handleClickRoleItem(role.id)"
|
||||||
|
>
|
||||||
|
<p class="name">{{ role.name }}</p>
|
||||||
|
<div v-if="currentRoleActiveId === role.id" class="actions">
|
||||||
|
<span @click="handleEditRole(role)"><icon-edit /></span>
|
||||||
|
<span>
|
||||||
|
<a-popconfirm
|
||||||
|
:ok-text="$t('cancel')"
|
||||||
|
:cancel-text="$t('delete')"
|
||||||
|
:ok-button-props="{ type: 'outline' }"
|
||||||
|
:cancel-button-props="{
|
||||||
|
type: 'primary',
|
||||||
|
status: 'danger',
|
||||||
|
}"
|
||||||
|
:content="
|
||||||
|
$t('please.confirm.delete.some', { name: $t('role') })
|
||||||
|
"
|
||||||
|
type="error"
|
||||||
|
@cancel="handleDelRole(role.id)"
|
||||||
|
>
|
||||||
|
<icon-delete />
|
||||||
|
</a-popconfirm>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</a-spin>
|
||||||
|
<roleFormDrawer
|
||||||
|
v-model:visible="showDrawer"
|
||||||
|
:record="roleItemInfo"
|
||||||
|
:is-edit="isEdit"
|
||||||
|
@submitted="onRoleSubmit"
|
||||||
|
@update:checked-keys="(val) => (checkedKeys = val)"
|
||||||
|
/>
|
||||||
|
</a-card>
|
||||||
|
</a-col>
|
||||||
|
<a-col flex="auto" class="full_height">
|
||||||
|
<a-tabs class="tabs_card" @change="handleTabChange">
|
||||||
|
<template #extra>
|
||||||
|
<p style="margin-right: 10px">
|
||||||
|
<span>{{ $t('last.updated') }}</span>
|
||||||
|
<span>{{ roleItemInfo ? roleItemInfo.updatedAt : '' }}</span>
|
||||||
|
</p>
|
||||||
|
<a-button type="primary" @click="handleSubmit">{{
|
||||||
|
$t('submit')
|
||||||
|
}}</a-button>
|
||||||
|
</template>
|
||||||
|
<a-tab-pane key="1" :title="$t('function.permission')">
|
||||||
|
<permissionCollapse
|
||||||
|
:role-id="currentRoleActiveId"
|
||||||
|
:permission-list="permissionList"
|
||||||
|
@update:checked-keys="(val) => (checkedKeys = val)"
|
||||||
|
/>
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane key="2" :title="$t('data.permission')">
|
||||||
|
Content of Tab Panel 2
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane key="3" :title="$t('user.assignment')">
|
||||||
|
<h4>{{ $t('user.assignment.setting') }}</h4>
|
||||||
|
<DataTable
|
||||||
|
style="margin-top: 20px"
|
||||||
|
:data="renderData"
|
||||||
|
:columns="projectColumn"
|
||||||
|
:loading="loading"
|
||||||
|
:total="total"
|
||||||
|
:current="current"
|
||||||
|
:page-size="pageSize"
|
||||||
|
pagination
|
||||||
|
@page-change="onPageChange"
|
||||||
|
@page-size-change="onPageSizeChange"
|
||||||
|
>
|
||||||
|
<template #realname="{ record }">
|
||||||
|
<span>{{ record.realname }}</span>
|
||||||
|
<icon-idcard v-if="record.isManager === 1" />
|
||||||
|
</template>
|
||||||
|
<template #status="{ record }">
|
||||||
|
<a-tag :color="record.status == 1 ? 'green' : 'red'">
|
||||||
|
{{ record.status == 1 ? $t('enable') : $t('disable') }}</a-tag
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
<template #operate="{ record }">
|
||||||
|
<a-button @click="changeRole(record?.id)">{{
|
||||||
|
$t('change.role')
|
||||||
|
}}</a-button>
|
||||||
|
</template>
|
||||||
|
</DataTable>
|
||||||
|
<changeRoleDrawer
|
||||||
|
v-model:visible="changeRoleDrawerVisible"
|
||||||
|
:role-id="currentRoleActiveId"
|
||||||
|
:user-id="selectedUserId"
|
||||||
|
:role-list="roleList"
|
||||||
|
@update-user="onChangeRole"
|
||||||
|
/>
|
||||||
|
</a-tab-pane>
|
||||||
|
</a-tabs>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, onMounted } from 'vue';
|
||||||
|
import {
|
||||||
|
getRoleList,
|
||||||
|
RoleItem,
|
||||||
|
delRole,
|
||||||
|
saveRolePermission,
|
||||||
|
getPermissionList,
|
||||||
|
getUserListFromRole,
|
||||||
|
UserList,
|
||||||
|
} from '@/api/setting';
|
||||||
|
import useLoading from '@/hooks/loading';
|
||||||
|
import { Message } from '@arco-design/web-vue';
|
||||||
|
import useDataTable from '@/composables/useDataTable';
|
||||||
|
import type { TableColumnData } from '@arco-design/web-vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
import permissionCollapse from './components/permission-collapse.vue';
|
||||||
|
import roleFormDrawer from './components/role-form-drawer.vue';
|
||||||
|
import changeRoleDrawer from './components/change-role-drawer.vue';
|
||||||
|
|
||||||
|
const { loading, setLoading } = useLoading(true);
|
||||||
|
const { t } = useI18n();
|
||||||
|
const roleList = ref<RoleItem[]>([]);
|
||||||
|
const currentRoleActiveId = ref<number | null>(null);
|
||||||
|
const showDrawer = ref<boolean>(false);
|
||||||
|
const isEdit = ref<boolean>(false);
|
||||||
|
const roleItemInfo = ref<RoleItem | null>(null);
|
||||||
|
const checkedKeys = ref<number[]>([]);
|
||||||
|
const permissionList = ref<any[]>([]);
|
||||||
|
const changeRoleDrawerVisible = ref<boolean>(false);
|
||||||
|
const selectedUserId = ref<number | null>(null);
|
||||||
|
// 使用 DataTable composable
|
||||||
|
const {
|
||||||
|
data: renderData,
|
||||||
|
columns: projectColumn,
|
||||||
|
// loading,
|
||||||
|
total,
|
||||||
|
current,
|
||||||
|
pageSize,
|
||||||
|
setData,
|
||||||
|
setColumns,
|
||||||
|
// setLoading,
|
||||||
|
setTotal,
|
||||||
|
setCurrent,
|
||||||
|
setPageSize,
|
||||||
|
} = useDataTable({
|
||||||
|
initialPage: 1,
|
||||||
|
initialPageSize: 10,
|
||||||
|
pageSizeOptions: [10, 20, 50, 100],
|
||||||
|
});
|
||||||
|
const userListData = ref<UserList>([]);
|
||||||
|
const columns: TableColumnData[] = [
|
||||||
|
{
|
||||||
|
title: t('username'),
|
||||||
|
dataIndex: 'username',
|
||||||
|
key: 'username',
|
||||||
|
width: 120,
|
||||||
|
ellipsis: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('name'),
|
||||||
|
dataIndex: 'realname',
|
||||||
|
key: 'realname',
|
||||||
|
width: 150,
|
||||||
|
ellipsis: true,
|
||||||
|
slotName: 'realname',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('department'),
|
||||||
|
dataIndex: 'deptName',
|
||||||
|
key: 'departmentId',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('role'),
|
||||||
|
dataIndex: 'roleName',
|
||||||
|
key: 'roleName',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('status'),
|
||||||
|
dataIndex: 'status',
|
||||||
|
key: 'status',
|
||||||
|
slotName: 'status',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('lastLogin'),
|
||||||
|
dataIndex: 'lastLoginTime',
|
||||||
|
key: 'lastLoginTime',
|
||||||
|
render: ({ record }) => record.lastLoginTime || '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '操作',
|
||||||
|
key: 'operate',
|
||||||
|
slotName: 'operate',
|
||||||
|
width: 200,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
// 获取权限列表数据
|
||||||
|
const getPermissionListData = async () => {
|
||||||
|
try {
|
||||||
|
const { code, data } = await getPermissionList();
|
||||||
|
if (code === 200 && data) {
|
||||||
|
// 根据 permission-collapse 组件的使用,API 返回的是权限数组
|
||||||
|
permissionList.value = Array.isArray(data?.permission)
|
||||||
|
? data.permission
|
||||||
|
: [];
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取权限列表失败:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 根据权限ID获取权限信息(包括路径)
|
||||||
|
const getPermissionById = (id: number): any => {
|
||||||
|
const findPermission = (list: any[]): any => {
|
||||||
|
// 用数组方法替换 for...of 循环
|
||||||
|
return list.reduce((found, item) => {
|
||||||
|
if (found) return found;
|
||||||
|
if (item.id === id) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
if (item.children && item.children.length > 0) {
|
||||||
|
return findPermission(item.children) || found;
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}, null);
|
||||||
|
};
|
||||||
|
return findPermission(permissionList.value);
|
||||||
|
};
|
||||||
|
const getUserListFromRoleData = async () => {
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
const params = {
|
||||||
|
role_id: currentRoleActiveId.value,
|
||||||
|
page: current.value,
|
||||||
|
page_size: pageSize.value,
|
||||||
|
};
|
||||||
|
const { code, data } = await getUserListFromRole(params);
|
||||||
|
if (code === 200) {
|
||||||
|
const { page, userList } = data;
|
||||||
|
userListData.value = Array.isArray(userList) ? userList : [];
|
||||||
|
setData(userListData.value);
|
||||||
|
setTotal(typeof page.total === 'number' ? page.total : 0);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const getRoleListData = async (isInit: boolean) => {
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
const { code, data } = await getRoleList();
|
||||||
|
if (code === 200) {
|
||||||
|
roleList.value = Array.isArray(data?.rolesList) ? data.rolesList : [];
|
||||||
|
if (isInit) {
|
||||||
|
roleItemInfo.value = roleList.value[0];
|
||||||
|
currentRoleActiveId.value = roleItemInfo.value
|
||||||
|
? roleItemInfo.value.id
|
||||||
|
: null;
|
||||||
|
getUserListFromRoleData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// 错误处理(保留注释,避免空代码块)
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleAddRole = () => {
|
||||||
|
isEdit.value = false;
|
||||||
|
showDrawer.value = true;
|
||||||
|
roleItemInfo.value = null;
|
||||||
|
};
|
||||||
|
const handleClickRoleItem = (id: number) => {
|
||||||
|
if (id === currentRoleActiveId.value) return;
|
||||||
|
currentRoleActiveId.value = id;
|
||||||
|
getUserListFromRoleData();
|
||||||
|
};
|
||||||
|
const handleEditRole = (role: RoleItem) => {
|
||||||
|
roleItemInfo.value = role;
|
||||||
|
isEdit.value = true;
|
||||||
|
showDrawer.value = true;
|
||||||
|
};
|
||||||
|
const handleDelRole = async (id: number) => {
|
||||||
|
try {
|
||||||
|
const { code, message } = await delRole(Number(id));
|
||||||
|
if (code === 200) {
|
||||||
|
Message.success(message);
|
||||||
|
getRoleListData(false);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// 处理错误
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const onRoleSubmit = () => {
|
||||||
|
getRoleListData(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
function handleSubmit() {
|
||||||
|
if (!currentRoleActiveId.value) {
|
||||||
|
Message.warning('请先选择一个角色');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (checkedKeys.value.length === 0) {
|
||||||
|
Message.warning('请至少选择一个权限');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据选中的权限ID获取完整的权限信息
|
||||||
|
const permissionData = checkedKeys.value
|
||||||
|
.map((key) => {
|
||||||
|
const permission = getPermissionById(key);
|
||||||
|
return {
|
||||||
|
id: key,
|
||||||
|
path: permission?.path || '',
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter((item) => item.id);
|
||||||
|
|
||||||
|
// 调用保存角色权限的API
|
||||||
|
saveRolePermission({
|
||||||
|
id: currentRoleActiveId.value,
|
||||||
|
children: permissionData,
|
||||||
|
})
|
||||||
|
.then(({ code, message }) => {
|
||||||
|
if (code === 200) {
|
||||||
|
Message.success(message || '权限保存成功');
|
||||||
|
} else {
|
||||||
|
Message.error(message || '权限保存失败');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
Message.error('权限保存失败');
|
||||||
|
console.error('保存角色权限失败:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleTabChange = (key) => {
|
||||||
|
if (key === '3') {
|
||||||
|
// 占位注释,避免空代码块
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 分页事件处理
|
||||||
|
const onPageChange = (page: number) => {
|
||||||
|
setCurrent(page);
|
||||||
|
current.value = page;
|
||||||
|
getUserListFromRoleData();
|
||||||
|
};
|
||||||
|
const onPageSizeChange = (size: number) => {
|
||||||
|
setPageSize(size);
|
||||||
|
pageSize.value = size;
|
||||||
|
getUserListFromRoleData();
|
||||||
|
};
|
||||||
|
const changeRole = (id: number) => {
|
||||||
|
selectedUserId.value = id;
|
||||||
|
changeRoleDrawerVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const onChangeRole = () => {
|
||||||
|
getUserListFromRoleData();
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getRoleListData(true);
|
||||||
|
getPermissionListData();
|
||||||
|
setColumns(columns);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.tabs_card {
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.role_list {
|
||||||
|
.role_item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 42px;
|
||||||
|
line-height: 42px;
|
||||||
|
padding: 0 16px;
|
||||||
|
border-bottom: 1px solid #efefef;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: #efefef;
|
||||||
|
|
||||||
|
.name {
|
||||||
|
cursor: pointer;
|
||||||
|
color: #2d5cf6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
color: #000;
|
||||||
|
font-size: 14px;
|
||||||
|
text-align: left;
|
||||||
|
flex: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
& > span {
|
||||||
|
width: 16px;
|
||||||
|
margin-left: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue