生产管理系统 - 角色管理联调
This commit is contained in:
@@ -5,18 +5,21 @@ import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, Di
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Loader2 } from 'lucide-react';
|
||||
import { Role, RoleType } from '../types';
|
||||
|
||||
interface RoleDetailDialogProps {
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
selectedRole: Role | null;
|
||||
detailLoading?: boolean;
|
||||
}
|
||||
|
||||
export function RoleDetailDialog({
|
||||
open,
|
||||
onOpenChange,
|
||||
selectedRole
|
||||
selectedRole,
|
||||
detailLoading = false
|
||||
}: RoleDetailDialogProps) {
|
||||
const getRoleTypeBadge = (type: RoleType) => {
|
||||
return type === 'system' ? (
|
||||
@@ -34,8 +37,6 @@ export function RoleDetailDialog({
|
||||
);
|
||||
};
|
||||
|
||||
if (!selectedRole) return null;
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="max-w-2xl">
|
||||
@@ -46,58 +47,69 @@ export function RoleDetailDialog({
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="space-y-4">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<Label>角色名称</Label>
|
||||
<div className="mt-1">{selectedRole.name}</div>
|
||||
{detailLoading ? (
|
||||
<div className="flex items-center justify-center py-8">
|
||||
<Loader2 className="h-6 w-6 animate-spin mr-2" />
|
||||
<span>正在加载角色详情...</span>
|
||||
</div>
|
||||
<div>
|
||||
<Label>角色代码</Label>
|
||||
<div className="mt-1">{selectedRole.code}</div>
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<Label>角色描述</Label>
|
||||
<div className="mt-1">{selectedRole.description || '-'}</div>
|
||||
</div>
|
||||
<div>
|
||||
<Label>角色类型</Label>
|
||||
<div className="mt-1">{getRoleTypeBadge(selectedRole.type)}</div>
|
||||
</div>
|
||||
<div>
|
||||
<Label>状态</Label>
|
||||
<div className="mt-1">{getStatusBadge(selectedRole.status)}</div>
|
||||
</div>
|
||||
{selectedRole.defaultHomePage && (
|
||||
) : selectedRole ? (
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<Label>角色名称</Label>
|
||||
<div className="mt-1">{selectedRole.name}</div>
|
||||
</div>
|
||||
<div>
|
||||
<Label>角色代码</Label>
|
||||
<div className="mt-1">{selectedRole.code}</div>
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<Label>默认首页</Label>
|
||||
<div className="mt-1">{selectedRole.defaultHomePage}</div>
|
||||
<Label>角色描述</Label>
|
||||
<div className="mt-1">{selectedRole.description || '-'}</div>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<Label>菜单数量</Label>
|
||||
<div className="mt-1">
|
||||
{selectedRole.menuIds.includes('*') ? '全部' : selectedRole.menuIds.length}
|
||||
<div>
|
||||
<Label>角色类型</Label>
|
||||
<div className="mt-1">{getRoleTypeBadge(selectedRole.type)}</div>
|
||||
</div>
|
||||
<div>
|
||||
<Label>状态</Label>
|
||||
<div className="mt-1">{getStatusBadge(selectedRole.status)}</div>
|
||||
</div>
|
||||
{selectedRole.defaultHomePage && (
|
||||
<div className="col-span-2">
|
||||
<Label>默认首页</Label>
|
||||
<div className="mt-1">{selectedRole.defaultHomePage}</div>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<Label>菜单数量</Label>
|
||||
<div className="mt-1">
|
||||
{selectedRole.menuIds?.includes('*') ? '全部' : (selectedRole.menuIds?.length || 0)}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Label>权限数量</Label>
|
||||
<div className="mt-1">
|
||||
{selectedRole.permissionIds?.includes('*') ? '全部' : (selectedRole.permissionIds?.length || 0)}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Label>创建时间</Label>
|
||||
<div className="mt-1">
|
||||
{new Date(selectedRole.createdAt).toLocaleString('zh-CN')}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Label>更新时间</Label>
|
||||
<div className="mt-1">
|
||||
{new Date(selectedRole.updatedAt).toLocaleString('zh-CN')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Label>权限数量</Label>
|
||||
<div className="mt-1">
|
||||
{selectedRole.permissionIds.includes('*') ? '全部' : selectedRole.permissionIds.length}
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center justify-center py-8">
|
||||
<span>无角色数据</span>
|
||||
</div>
|
||||
<div>
|
||||
<Label>创建时间</Label>
|
||||
<div className="mt-1">
|
||||
{new Date(selectedRole.createdAt).toLocaleString('zh-CN')}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Label>更新时间</Label>
|
||||
<div className="mt-1">
|
||||
{new Date(selectedRole.updatedAt).toLocaleString('zh-CN')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => onOpenChange(false)}>
|
||||
|
||||
@@ -9,7 +9,7 @@ import { Textarea } from '@/components/ui/textarea';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { Card } from '@/components/ui/card';
|
||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||
import { ChevronRight } from 'lucide-react';
|
||||
import { ChevronRight, Loader2 } from 'lucide-react';
|
||||
import { Role, RoleFormData, allSystemMenus } from '../types';
|
||||
|
||||
interface RoleFormDialogProps {
|
||||
@@ -19,6 +19,7 @@ interface RoleFormDialogProps {
|
||||
formData: RoleFormData;
|
||||
onFormDataChange: (data: RoleFormData) => void;
|
||||
onSave: () => void;
|
||||
editFormLoading?: boolean;
|
||||
}
|
||||
|
||||
export function RoleFormDialog({
|
||||
@@ -27,7 +28,8 @@ export function RoleFormDialog({
|
||||
editingRole,
|
||||
formData,
|
||||
onFormDataChange,
|
||||
onSave
|
||||
onSave,
|
||||
editFormLoading = false
|
||||
}: RoleFormDialogProps) {
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
@@ -38,8 +40,16 @@ export function RoleFormDialog({
|
||||
{editingRole ? '编辑角色信息' : '添加新角色'}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<ScrollArea className="max-h-[calc(90vh-180px)]">
|
||||
<div className="space-y-6 pr-4">
|
||||
|
||||
{/* Loading state for edit form */}
|
||||
{editFormLoading && editingRole ? (
|
||||
<div className="flex items-center justify-center py-12">
|
||||
<Loader2 className="h-6 w-6 animate-spin mr-2" />
|
||||
<span>正在加载角色数据...</span>
|
||||
</div>
|
||||
) : (
|
||||
<ScrollArea className="max-h-[calc(90vh-180px)]">
|
||||
<div className="space-y-6 pr-4">
|
||||
{/* 基本信息 */}
|
||||
<div className="space-y-4">
|
||||
<h4 className="text-green-800">基本信息</h4>
|
||||
@@ -222,7 +232,8 @@ export function RoleFormDialog({
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</ScrollArea>
|
||||
</ScrollArea>
|
||||
)}
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={() => onOpenChange(false)}>
|
||||
取消
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Card } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
||||
import { DataPagination } from '@/components/ui/data-pagination';
|
||||
import { Eye, Edit, Trash2, Shield } from 'lucide-react';
|
||||
import { Role, RoleType } from '../types';
|
||||
import { PaginationState } from './roleApi';
|
||||
@@ -125,60 +126,20 @@ export function RoleList({
|
||||
</Table>
|
||||
|
||||
{/* 分页控制 */}
|
||||
{!loading && pagination && pagination.totalPages > 1 && (
|
||||
<div className="flex items-center justify-between px-2 py-4">
|
||||
<div className="flex items-center space-x-2 text-sm text-muted-foreground">
|
||||
<span>显示第 {(pagination.page - 1) * pagination.size + 1} 至 {Math.min(pagination.page * pagination.size, pagination.total)} 条,共 {pagination.total} 条</span>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => onPageChange?.(pagination.page - 1)}
|
||||
disabled={!pagination.hasPrev}
|
||||
>
|
||||
上一页
|
||||
</Button>
|
||||
|
||||
<div className="flex items-center space-x-1">
|
||||
{Array.from({ length: pagination.totalPages }, (_, i) => i + 1).map((pageNum) => (
|
||||
<Button
|
||||
key={pageNum}
|
||||
variant={pageNum === pagination.page ? "default" : "outline"}
|
||||
size="sm"
|
||||
className="w-8 h-8 p-0"
|
||||
onClick={() => onPageChange?.(pageNum)}
|
||||
>
|
||||
{pageNum}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => onPageChange?.(pagination.page + 1)}
|
||||
disabled={!pagination.hasNext}
|
||||
>
|
||||
下一页
|
||||
</Button>
|
||||
|
||||
{onPageSizeChange && (
|
||||
<>
|
||||
<select
|
||||
value={pagination.size}
|
||||
onChange={(e) => onPageSizeChange(Number(e.target.value))}
|
||||
className="ml-2 h-8 w-16 rounded-md border border-input bg-background text-sm"
|
||||
>
|
||||
<option value={10}>10</option>
|
||||
<option value={20}>20</option>
|
||||
<option value={50}>50</option>
|
||||
</select>
|
||||
<span className="text-sm text-muted-foreground">条/页</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{!loading && pagination && pagination.total > 0 && (
|
||||
<DataPagination
|
||||
currentPage={pagination.page}
|
||||
totalPages={pagination.totalPages}
|
||||
pageSize={pagination.size}
|
||||
totalItems={pagination.total}
|
||||
startIndex={(pagination.page - 1) * pagination.size + 1}
|
||||
endIndex={Math.min(pagination.page * pagination.size, pagination.total)}
|
||||
onPageChange={(page) => onPageChange?.(page)}
|
||||
onPageSizeChange={(size) => onPageSizeChange?.(size)}
|
||||
canPreviousPage={pagination.hasPrev}
|
||||
canNextPage={pagination.hasNext}
|
||||
pageSizeOptions={[10, 20, 50, 100]}
|
||||
/>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
|
||||
@@ -8,10 +8,16 @@
|
||||
import { getAuthToken } from "@/utils/token";
|
||||
import {
|
||||
getRolesApiV1UsersPermissionsRolesGet,
|
||||
createRoleApiV1UsersPermissionsRolesPost,
|
||||
getRoleApiV1UsersPermissionsRolesRoleIdGet,
|
||||
deleteRoleApiV1UsersPermissionsRolesRoleIdDelete,
|
||||
updateRoleApiV1UsersPermissionsRolesRoleIdPut,
|
||||
} from "@/lib/api/sdk.gen";
|
||||
import {
|
||||
RoleApiData,
|
||||
Role,
|
||||
RolesApiResponse,
|
||||
RolesQueryParams,
|
||||
} from '../types';
|
||||
|
||||
// 本地定义PaginationState以避免导入问题
|
||||
@@ -102,9 +108,9 @@ export async function fetchRoles(params: RolesQueryParams = {}): Promise<RolesAp
|
||||
*/
|
||||
export function transformRoleData(apiRole: RoleApiData): Role {
|
||||
return {
|
||||
id: apiRole.id,
|
||||
id: apiRole.id, // 使用API返回的真实ID
|
||||
name: apiRole.name,
|
||||
code: apiRole.name.toLowerCase().replace(/\s+/g, '_'), // 生成code
|
||||
code: apiRole.id, // 使用API返回的ID作为code,确保唯一性
|
||||
description: apiRole.description,
|
||||
type: 'custom', // 默认为自定义角色
|
||||
menuIds: [],
|
||||
@@ -123,6 +129,140 @@ export function transformRolesList(apiRoles: RoleApiData[]): Role[] {
|
||||
return apiRoles.map(transformRoleData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建新角色
|
||||
*/
|
||||
export async function createRole(roleData: {
|
||||
name: string;
|
||||
description: string;
|
||||
permission_ids: string[];
|
||||
}) {
|
||||
try {
|
||||
// 获取认证token
|
||||
const token = getAuthToken();
|
||||
console.log('创建角色API调用参数:', roleData);
|
||||
|
||||
// 使用SDK API调用创建角色
|
||||
const response = await createRoleApiV1UsersPermissionsRolesPost({
|
||||
body: roleData,
|
||||
headers: token ? {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
} : undefined,
|
||||
});
|
||||
|
||||
if (response.error) {
|
||||
throw new Error(response.error.message || '创建角色失败');
|
||||
}
|
||||
|
||||
console.log('创建角色API响应:', response.data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Failed to create role:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色详情
|
||||
*/
|
||||
export async function getRoleDetail(roleId: string) {
|
||||
try {
|
||||
// 获取认证token
|
||||
const token = getAuthToken();
|
||||
console.log('获取角色详情API调用参数:', roleId);
|
||||
console.log('即将调用的URL: /api/v1/users/permissions/roles/' + roleId);
|
||||
|
||||
// 使用SDK API调用获取角色详情
|
||||
const response = await getRoleApiV1UsersPermissionsRolesRoleIdGet({
|
||||
path: {
|
||||
role_id: roleId,
|
||||
},
|
||||
headers: token ? {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
} : undefined,
|
||||
});
|
||||
|
||||
if (response.error) {
|
||||
throw new Error(response.error.message || '获取角色详情失败');
|
||||
}
|
||||
|
||||
console.log('获取角色详情API响应:', response.data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Failed to get role detail:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新角色
|
||||
*/
|
||||
export async function updateRole(roleId: string, roleData: {
|
||||
name: string;
|
||||
description: string;
|
||||
permission_ids: string[];
|
||||
}) {
|
||||
try {
|
||||
// 获取认证token
|
||||
const token = getAuthToken();
|
||||
console.log('更新角色API调用参数:', roleId, roleData);
|
||||
console.log('即将调用的URL: /api/v1/users/permissions/roles/' + roleId);
|
||||
|
||||
// 使用SDK API调用更新角色
|
||||
const response = await updateRoleApiV1UsersPermissionsRolesRoleIdPut({
|
||||
path: {
|
||||
role_id: roleId,
|
||||
},
|
||||
body: roleData,
|
||||
headers: token ? {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
} : undefined,
|
||||
});
|
||||
|
||||
if (response.error) {
|
||||
throw new Error(response.error.message || '更新角色失败');
|
||||
}
|
||||
|
||||
console.log('更新角色API响应:', response.data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Failed to update role:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除角色
|
||||
*/
|
||||
export async function deleteRole(roleId: string) {
|
||||
try {
|
||||
// 获取认证token
|
||||
const token = getAuthToken();
|
||||
console.log('删除角色API调用参数:', roleId);
|
||||
console.log('即将调用的URL: /api/v1/users/permissions/roles/' + roleId);
|
||||
|
||||
// 使用SDK API调用删除角色
|
||||
const response = await deleteRoleApiV1UsersPermissionsRolesRoleIdDelete({
|
||||
path: {
|
||||
role_id: roleId,
|
||||
},
|
||||
headers: token ? {
|
||||
'Authorization': `Bearer ${token}`,
|
||||
} : undefined,
|
||||
});
|
||||
|
||||
if (response.error) {
|
||||
throw new Error(response.error.message || '删除角色失败');
|
||||
}
|
||||
|
||||
console.log('删除角色API响应:', response.data);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Failed to delete role:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化日期
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user