leaser_front/src/views/setting/user/role.vue

495 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<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 v-model:active-key="currentTabsKey" class="tabs_card">
<template #extra>
<p style="margin-right: 10px">
<span>{{ $t('last.updated') }}</span>
<span>{{ roleItemInfo ? roleItemInfo.updatedAt : '' }}</span>
</p>
<a-button
v-if="currentTabsKey !== '3'"
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')">
<h4>{{ $t('data.permission.setting') }}</h4>
<div style="padding: 20px 0">
<a-radio-group v-model="dataType">
<a-radio :value="1">{{ $t('all.data.permission') }}</a-radio>
<a-radio :value="2">{{
$t('customize.data.permission')
}}</a-radio>
<a-radio :value="3">{{ $t('self.data.permission') }}</a-radio>
</a-radio-group>
<a-row
v-if="dataType === 2"
:gutter="12"
style="margin-top: 20px"
>
<a-col :span="12">
<a-card>
<h4 style="margin-bottom: 10px">选择组织架构</h4>
<DepartmentTree
v-model:expanded-keys="expandedKeys"
v-model:selected-keys="selectedKeys"
:data="departmentListData"
checkable
/>
</a-card>
</a-col>
<a-col :span="12">
<a-card>
<h4 style="margin-bottom: 10px">选择项目</h4>
<div style="margin-top: 20px"> TODO 后面再对接 </div>
</a-card>
</a-col>
</a-row>
</div>
</a-tab-pane>
<a-tab-pane key="3" :title="$t('user.assignment')">
<h4>{{ $t('user.assignment.setting') }}</h4>
<div style="padding-bottom: 20px">
<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>
</div>
<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>
<script lang="ts" setup>
import { ref, onMounted, watch } from 'vue';
import {
getRoleList,
delRole,
saveRolePermission,
getPermissionList,
getUserListFromRole,
} from '@/api/setting';
import { UserList, RoleItem } from '@/types/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 DepartmentTree from '@/components/common/DepartmentTree.vue';
import useDepartmentList from '@/composables/useDepartmentList';
import permissionCollapse from './components/permission-collapse.vue';
import roleFormDrawer from './components/role-form-drawer.vue';
import changeRoleDrawer from './components/change-role-drawer.vue';
const { departmentListData, allDepartmentKeys } = useDepartmentList();
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);
const currentTabsKey = ref<string>('1');
const dataType = ref<number>(1);
const expandedKeys = ref<(string | number)[]>([]);
const selectedKeys = ref<(string | number)[]>([]);
// 使用 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',
align: 'center',
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);
};
watch(
allDepartmentKeys,
(val) => {
expandedKeys.value = val;
},
{ immediate: true }
);
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 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>