生产管理系统 - 角色管理、员工管理主页面联调

This commit is contained in:
2025-11-04 17:01:42 +08:00
parent fffd37a0a9
commit 1058767515
13 changed files with 4426 additions and 1428 deletions

View File

@@ -7,9 +7,14 @@ import { Badge } from '@/components/ui/badge';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
import { Eye, Edit, Trash2, Shield } from 'lucide-react';
import { Role, RoleType } from '../types';
import { PaginationState } from './roleApi';
interface RoleListProps {
roles: Role[];
loading?: boolean;
pagination?: PaginationState;
onPageChange?: (page: number) => void;
onPageSizeChange?: (size: number) => void;
onViewDetail: (role: Role) => void;
onEdit: (role: Role) => void;
onDelete: (id: string) => void;
@@ -17,6 +22,10 @@ interface RoleListProps {
export function RoleList({
roles,
loading = false,
pagination,
onPageChange,
onPageSizeChange,
onViewDetail,
onEdit,
onDelete
@@ -52,7 +61,13 @@ export function RoleList({
</TableRow>
</TableHeader>
<TableBody>
{roles.length === 0 ? (
{loading ? (
<TableRow>
<TableCell colSpan={7} className="text-center text-muted-foreground py-8">
...
</TableCell>
</TableRow>
) : roles.length === 0 ? (
<TableRow>
<TableCell colSpan={7} className="text-center text-muted-foreground py-8">
@@ -108,6 +123,63 @@ export function RoleList({
)}
</TableBody>
</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>
)}
</Card>
);
}

View File

@@ -0,0 +1,143 @@
/**
* filekorolheader: 角色管理API接口 - 角色数据查询接口服务
* 功能API请求封装、数据转换、错误处理、分页查询
* 路径:/central-config/user/role/components/roleApi
* 规范遵循crop-x/docs/开发项目规范.md使用SDK API调用TypeScript类型安全
*/
import { getAuthToken } from "@/utils/token";
import {
getRolesApiV1UsersPermissionsRolesGet,
} from "@/lib/api/sdk.gen";
import {
RoleApiData,
Role,
} from '../types';
// 本地定义PaginationState以避免导入问题
export interface PaginationState {
page: number;
size: number;
total: number;
totalPages: number;
hasNext: boolean;
hasPrev: boolean;
}
// Re-export types from types.ts for convenience
export type { RolesApiResponse, RolesQueryParams } from '../types';
/**
* 获取角色列表数据
*/
export async function fetchRoles(params: RolesQueryParams = {}): Promise<RolesApiResponse> {
try {
// 构建查询参数对象
const queryParams: any = {};
if (params.page) queryParams.page = params.page;
if (params.size) queryParams.size = params.size;
if (params.sort_order) queryParams.sort_order = params.sort_order;
// 默认参数
if (!params.page) queryParams.page = 1;
if (!params.size) queryParams.size = 10;
if (!params.sort_order) queryParams.sort_order = 'desc';
// 获取认证token
const token = getAuthToken();
console.log('角色管理API调用参数:', queryParams);
// 使用真正的SDK API调用
const response = await getRolesApiV1UsersPermissionsRolesGet({
query: {
...queryParams,
// 添加时间戳防止缓存
_t: Date.now(),
},
headers: token ? {
'Authorization': `Bearer ${token}`,
} : undefined,
});
if (response.error) {
throw new Error(`API error: ${response.error.message || 'Unknown error'}`);
}
const data = response.data as any;
console.log('角色管理API响应:', data);
// 处理API响应数据
if (data && typeof data === 'object' && data.data) {
return {
data: data.data || [],
total: data.total || 0,
page: data.page || 1,
size: data.size || 10,
total_pages: data.total_pages || 0,
has_next: data.has_next || false,
has_prev: data.has_prev || false,
};
} else {
// 其他情况,返回空结果
return {
data: [],
total: 0,
page: 1,
size: 10,
total_pages: 0,
has_next: false,
has_prev: false,
};
}
} catch (error) {
console.error('Failed to fetch roles:', error);
throw error;
}
}
/**
* 将API数据转换为页面所需的角色数据格式
* 为了保持兼容性,这里转换数据格式
*/
export function transformRoleData(apiRole: RoleApiData): Role {
return {
id: apiRole.id,
name: apiRole.name,
code: apiRole.name.toLowerCase().replace(/\s+/g, '_'), // 生成code
description: apiRole.description,
type: 'custom', // 默认为自定义角色
menuIds: [],
permissionIds: [],
status: 'active',
createdAt: apiRole.created_at,
updatedAt: apiRole.updated_at,
tenant_id: apiRole.tenant_id,
};
}
/**
* 批量转换角色数据
*/
export function transformRolesList(apiRoles: RoleApiData[]): Role[] {
return apiRoles.map(transformRoleData);
}
/**
* 格式化日期
*/
export function formatDate(dateString: string): string {
try {
const date = new Date(dateString);
return date.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
}).replace(/\//g, '-');
} catch (error) {
return dateString;
}
}