Files
yunzerwebsiteallinone/backend/src/views/basicSettings/roles/index.vue
T
2026-09-15 10:44:31 +08:00

240 lines
7.1 KiB
Vue

<template>
<div class="container-box">
<div class="header-bar">
<h2>角色管理</h2>
<div class="header-actions">
<el-button type="primary" @click="handleAdd">
<el-icon><Plus /></el-icon>
添加自定义角色
</el-button>
<el-button @click="refresh">
<el-icon><Refresh /></el-icon>
刷新</el-button
>
</div>
</div>
<el-divider></el-divider>
<!-- 分类筛选 -->
<div class="filter-bar">
<el-radio-group v-model="typeFilter">
<el-radio-button :value="'all'">全部</el-radio-button>
<el-radio-button :value="'global'">全局角色</el-radio-button>
<el-radio-button :value="'custom'">自定义角色</el-radio-button>
</el-radio-group>
</div>
<!-- 错误状态 -->
<div v-if="error" class="error-state">
<el-alert title="加载失败" :message="error" type="error" show-icon />
<el-button type="primary" @click="refresh">重试</el-button>
</div>
<!-- 角色列表 -->
<div v-else>
<el-table :data="displayRoles" stripe style="width: 100%" v-loading="loading">
<el-table-column
prop="name"
label="角色名称"
min-width="150"
align="center"
/>
<el-table-column prop="cid" label="类型" width="150" align="center">
<template #default="{ row }">
<el-tag v-if="Number(row.tenant_id || 0) === 0" type="success" size="small">
全局角色
</el-tag>
<el-tag v-else-if="Number(row.is_custom) === 1" type="warning" size="small">
自定义角色
</el-tag>
<el-tag v-else type="primary" size="small">租户角色</el-tag>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="100" align="center">
<template #default="{ row }">
<el-tag :type="row.status === 1 ? 'success' : 'info'" size="small">
{{ row.status === 1 ? "启用" : "禁用" }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="权限" min-width="150" align="center">
<template #default="{ row }">
<el-tag v-if="!row.rights" type="success" size="small">全权限</el-tag>
<el-tag v-else type="info" size="small">自定义权限</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="220" fixed="right" align="center">
<template #default="{ row }">
<el-button
size="small"
type="primary"
link
@click="handleView(row)"
>
<el-icon><View /></el-icon>
详情
</el-button>
<el-button
v-if="Number(row.tenant_id || 0) > 0"
size="small"
type="primary"
link
@click="handleEdit(row)"
>
<el-icon><Edit /></el-icon>
编辑
</el-button>
<el-button
v-if="Number(row.is_custom) === 1"
size="small"
type="danger"
link
@click="handleDelete(row)"
>
<el-icon><Delete /></el-icon>
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 编辑对话框 -->
<RoleEditDialog
v-model="editDialogVisible"
:role="currentRole"
@success="handleEditSuccess"
/>
<!-- 详情对话框 -->
<RoleDetailDialog
v-model="detailDialogVisible"
:roleId="currentRoleId"
/>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from "vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { Plus, View, Edit, Delete, Refresh } from "@element-plus/icons-vue";
import { getAllRoles, deleteRole } from "@/api/role";
import RoleEditDialog from "./components/edit.vue";
import RoleDetailDialog from "./components/detail.vue";
const roles = ref<any[]>([]);
const loading = ref(false);
const error = ref("");
const typeFilter = ref<string | number>("all");
const displayRoles = computed(() => {
// global = 全局角色(所有租户共用,平台端维护);custom = 本租户自建的自定义角色
if (typeFilter.value === "all") return roles.value;
if (typeFilter.value === "global") return roles.value.filter((r) => Number(r.tenant_id || 0) === 0);
if (typeFilter.value === "custom") return roles.value.filter((r) => Number(r.is_custom) === 1);
return roles.value.filter((r) => Number(r.cid) === Number(typeFilter.value));
});
const editDialogVisible = ref(false);
const detailDialogVisible = ref(false);
const currentRole = ref<any>(null);
const currentRoleId = ref<number | null>(null);
// 获取角色列表:仅返回当前登录租户名下的租户角色(服务端按租户隔离)
const fetchRoles = async () => {
loading.value = true;
error.value = "";
try {
const res = await getAllRoles();
if (res.code === 200) {
roles.value = res.data || [];
// console.log('角色列表:', roles.value);
} else {
error.value = res.msg || "获取角色列表失败";
ElMessage.error(error.value);
}
} catch (err: any) {
error.value = err.message || "获取角色列表失败";
ElMessage.error(error.value);
} finally {
loading.value = false;
}
};
// 刷新界面
async function refresh() {
await fetchRoles();
if (!error.value) {
ElMessage.success("刷新成功");
}
}
// 添加角色
function handleAdd() {
currentRole.value = null;
editDialogVisible.value = true;
}
// 查看详情
function handleView(row: any) {
currentRoleId.value = row.id;
detailDialogVisible.value = true;
}
// 编辑角色
function handleEdit(row: any) {
currentRole.value = { ...row };
editDialogVisible.value = true;
}
// 删除角色
async function handleDelete(row: any) {
try {
await ElMessageBox.confirm(
`确定要删除角色「${row.name}」吗?删除后不可恢复。`,
"警告",
{ type: "warning" }
);
loading.value = true;
try {
const res = await deleteRole(row.id);
if (res.code === 200) {
ElMessage.success("删除成功");
fetchRoles();
} else {
ElMessage.error(res.msg || "删除失败");
}
} catch (err: any) {
ElMessage.error(err.message || "删除失败");
} finally {
loading.value = false;
}
} catch {
// 取消删除
}
}
// 编辑成功回调
function handleEditSuccess() {
fetchRoles();
}
onMounted(() => {
fetchRoles();
});
</script>
<style scoped>
.error-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 220px;
padding: 32px 0 16px 0;
background: var(--el-bg-color-page);
border-radius: 5px;
gap: 16px;
}
</style>