-
-
用户管理
-
平台所有用户账户的集中管理
+
+
+
+
+
+
用户管理
+
+ 平台所有用户账户的集中管理,支持搜索、筛选和详情查看
+
+
+
+ 搜索功能
+
+
+ 状态筛选
+
+
+ 详情查看
+
+
+
+
+
+
+
-
-
-
-
-
+
);
}
\ No newline at end of file
diff --git a/crop-x/src/app/(app)/central-config/tenant/user-management/components/UserManagementStatsCards.tsx b/crop-x/src/app/(app)/central-config/tenant/user-management/components/UserManagementStatsCards.tsx
index d592e7c..d4fe0c2 100644
--- a/crop-x/src/app/(app)/central-config/tenant/user-management/components/UserManagementStatsCards.tsx
+++ b/crop-x/src/app/(app)/central-config/tenant/user-management/components/UserManagementStatsCards.tsx
@@ -1,47 +1,49 @@
+/**
+ * filekorolheader: 用户管理统计卡片组件 - 用户统计数据展示界面
+ * 功能:总用户数、活跃用户、管理员、已验证用户统计展示
+ * 路径:/central-config/tenant/user-management/components/UserManagementStatsCards
+ * 规范:遵循crop-x/docs/开发项目规范.md,使用shadcn/ui组件,TypeScript类型安全
+ */
+
'use client';
-import React from 'react';
import { Card } from '@/components/ui/card';
-import { UserManagementStats, User } from '../types';
interface UserManagementStatsCardsProps {
- users: User[];
+ stats: Array<{
+ label: string;
+ value: number;
+ color: string;
+ bg: string;
+ }>;
+ loading?: boolean;
}
-export function UserManagementStatsCards({ users }: UserManagementStatsCardsProps) {
- const stats: UserManagementStats[] = [
- {
- label: '总用户数',
- value: users.length,
- color: 'text-blue-600',
- bg: 'bg-blue-100',
- },
- {
- label: '超级管理员',
- value: users.filter(u => u.userType === 'super_admin').length,
- color: 'text-purple-600',
- bg: 'bg-purple-100',
- },
- {
- label: '企业管理员',
- value: users.filter(u => u.userType === 'enterprise_admin').length,
- color: 'text-blue-600',
- bg: 'bg-blue-100',
- },
- {
- label: '正常用户',
- value: users.filter(u => u.status === 'active').length,
- color: 'text-green-600',
- bg: 'bg-green-100',
- },
- ];
+export function UserManagementStatsCards({
+ stats,
+ loading = false
+}: UserManagementStatsCardsProps) {
+ if (loading) {
+ return (
+
+ {stats.map((_, index) => (
+
+
+
+ ))}
+
+ );
+ }
return (
{stats.map((stat, index) => (
{stat.label}
- {stat.value}
+ {stat.value}
))}
diff --git a/crop-x/src/app/(app)/central-config/tenant/user-management/components/userManagementApi.ts b/crop-x/src/app/(app)/central-config/tenant/user-management/components/userManagementApi.ts
new file mode 100644
index 0000000..1acf497
--- /dev/null
+++ b/crop-x/src/app/(app)/central-config/tenant/user-management/components/userManagementApi.ts
@@ -0,0 +1,193 @@
+/**
+ * filekorolheader: 用户管理API接口 - 用户数据查询接口服务
+ * 功能:API请求封装、数据转换、错误处理、分页查询
+ * 路径:/central-config/tenant/user-management/components/userManagementApi
+ * 规范:遵循crop-x/docs/开发项目规范.md,使用SDK API调用,TypeScript类型安全
+ */
+
+import { getAuthToken } from "@/utils/token";
+import {
+ getUsersApiV1UsersGet,
+} from "@/lib/api/sdk.gen";
+
+// API返回的用户数据类型
+export interface UserData {
+ id: string;
+ tenant_id: string;
+ email: string;
+ username: string;
+ full_name: string | null;
+ phone: string | null;
+ is_active: boolean;
+ is_superuser: boolean;
+ is_verified: boolean;
+ created_at: string;
+ updated_at: string;
+ last_login_at: string | null;
+ avatar_url: string | null;
+ bio: string | null;
+ display_name: string | null;
+ department_id: string | null;
+ department_name: string | null;
+ scope: string;
+ company_name: string | null;
+}
+
+// API响应接口
+export interface UsersApiResponse {
+ data: UserData[];
+ total: number;
+ page: number;
+ size: number;
+ total_pages: number;
+ has_next: boolean;
+ has_prev: boolean;
+}
+
+// 查询参数接口
+export interface UsersQueryParams {
+ search?: string;
+ is_active?: boolean;
+ page?: number;
+ size?: number;
+ order_by?: string;
+ sort_order?: 'asc' | 'desc';
+}
+
+// 页面使用的用户数据类型(转换后的)
+export interface User {
+ id: string;
+ username: string;
+ email: string;
+ fullName: string | null;
+ phone: string | null;
+ isActive: boolean;
+ isSuperuser: boolean;
+ isVerified: boolean;
+ createdAt: string;
+ updatedAt: string;
+ lastLoginAt: string | null;
+ avatarUrl: string | null;
+ bio: string | null;
+ displayName: string | null;
+ departmentId: string | null;
+ departmentName: string | null;
+ scope: string;
+ companyName: string | null;
+ tenantId: string;
+}
+
+/**
+ * 获取用户列表数据
+ */
+export async function fetchUsers(params: UsersQueryParams = {}): Promise
{
+ try {
+ // 构建查询参数对象
+ const queryParams: any = {};
+
+ if (params.search) queryParams.search = params.search;
+ if (params.is_active !== undefined) queryParams.is_active = params.is_active;
+ if (params.page) queryParams.page = params.page;
+ if (params.size) queryParams.size = params.size;
+ if (params.order_by) queryParams.order_by = params.order_by;
+ 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';
+
+ // 使用SDK API调用用户查询接口,添加缓存破坏器和认证头部
+ const token = getAuthToken();
+ console.log('用户管理API调用参数:', queryParams);
+
+ const response = await getUsersApiV1UsersGet({
+ 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返回的数据结构: { data: [...], total: 25, page: 1, size: 10, ... }
+ return {
+ data: data?.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,
+ };
+ } catch (error) {
+ console.error('Failed to fetch users:', error);
+ throw error;
+ }
+}
+
+/**
+ * 将API数据转换为页面所需的用户数据格式
+ * 优先显示display_name,其次full_name,最后username
+ */
+export function transformUserData(user: UserData): User {
+ return {
+ id: user.id,
+ username: user.username,
+ email: user.email,
+ fullName: user.full_name,
+ phone: user.phone,
+ isActive: user.is_active,
+ isSuperuser: user.is_superuser,
+ isVerified: user.is_verified,
+ createdAt: formatDate(user.created_at),
+ updatedAt: formatDate(user.updated_at),
+ lastLoginAt: user.last_login_at ? formatDate(user.last_login_at) : null,
+ avatarUrl: user.avatar_url,
+ bio: user.bio,
+ displayName: user.display_name || user.full_name || user.username,
+ departmentId: user.department_id,
+ departmentName: user.department_name,
+ scope: user.scope,
+ companyName: user.company_name,
+ tenantId: user.tenant_id,
+ };
+}
+
+/**
+ * 格式化日期
+ */
+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;
+ }
+}
+
+// Pagination state interface for page components
+export interface PaginationState {
+ page: number;
+ size: number;
+ total: number;
+ totalPages: number;
+ hasNext: boolean;
+ hasPrev: boolean;
+}
\ No newline at end of file
diff --git a/crop-x/src/app/(app)/central-config/tenant/user-management/page.tsx b/crop-x/src/app/(app)/central-config/tenant/user-management/page.tsx
index 48141d2..0ea2d0f 100644
--- a/crop-x/src/app/(app)/central-config/tenant/user-management/page.tsx
+++ b/crop-x/src/app/(app)/central-config/tenant/user-management/page.tsx
@@ -1,271 +1,330 @@
+/**
+ * filekorolheader: 用户管理页面 - 用户查询和管理页面
+ * 功能:用户列表查询、搜索筛选、详情查看、用户管理
+ * 路径:/central-config/tenant/user-management
+ * 规范:遵循crop-x/docs/开发项目规范.md,使用useReducer状态管理,API集成,shadcn语义化样式
+ */
'use client';
-import { useState, useEffect } from 'react';
+import { useReducer, useEffect } from 'react';
import { toast } from 'sonner';
+import { fetchUsers, transformUserData, UsersQueryParams, User, UsersApiResponse, PaginationState } from './components/userManagementApi';
import { UserManagementHeader } from './components/UserManagementHeader';
import { UserManagementStatsCards } from './components/UserManagementStatsCards';
import { UserManagementFilters } from './components/UserManagementFilters';
import { UserList } from './components/UserList';
-import { UserFormDialog } from './components/UserFormDialog';
import { UserDetailDialog } from './components/UserDetailDialog';
-import { User, Enterprise, UserFilters, UserFormData } from './types';
+import { Enterprise, UserFilters } from './types';
-export default function TenantUserManagementPage() {
- const [users, setUsers] = useState([]);
- const [enterprises, setEnterprises] = useState([]);
- const [filters, setFilters] = useState({
+// 用户管理状态管理
+interface UserManagementState {
+ users: User[];
+ enterprises: Enterprise[];
+ loading: boolean;
+ error: string | null;
+ pagination: PaginationState;
+ filters: UserFilters;
+ sortBy?: string;
+ sortOrder: 'asc' | 'desc';
+ selectedUser: User | null;
+ showDetailDialog: boolean;
+}
+
+type UserManagementAction =
+ | { type: 'SET_USERS'; payload: { data: User[]; pagination: PaginationState } }
+ | { type: 'SET_LOADING'; payload: boolean }
+ | { type: 'SET_ERROR'; payload: string | null }
+ | { type: 'SET_FILTERS'; payload: Partial }
+ | { type: 'SET_SORT'; payload: { sortBy?: string; sortOrder: 'asc' | 'desc' } }
+ | { type: 'SET_PAGINATION'; payload: Partial }
+ | { type: 'SET_ENTERPRISES'; payload: Enterprise[] }
+ | { type: 'SET_SELECTED_USER'; payload: User | null }
+ | { type: 'TOGGLE_DETAIL_DIALOG'; payload: boolean }
+ | { type: 'REFRESH_DATA' };
+
+const userManagementReducer = (state: UserManagementState, action: UserManagementAction): UserManagementState => {
+ switch (action.type) {
+ case 'SET_USERS':
+ return {
+ ...state,
+ users: action.payload.data,
+ pagination: action.payload.pagination,
+ loading: false,
+ error: null,
+ };
+ case 'SET_LOADING':
+ return { ...state, loading: action.payload };
+ case 'SET_ERROR':
+ return { ...state, error: action.payload, loading: false };
+ case 'SET_FILTERS':
+ return { ...state, filters: { ...state.filters, ...action.payload } };
+ case 'SET_SORT':
+ return { ...state, sortBy: action.payload.sortBy, sortOrder: action.payload.sortOrder };
+ case 'SET_PAGINATION':
+ return { ...state, pagination: { ...state.pagination, ...action.payload } };
+ case 'SET_ENTERPRISES':
+ return { ...state, enterprises: action.payload };
+ case 'SET_SELECTED_USER':
+ return { ...state, selectedUser: action.payload };
+ case 'TOGGLE_DETAIL_DIALOG':
+ return { ...state, showDetailDialog: !state.showDetailDialog };
+ case 'REFRESH_DATA':
+ return { ...state, error: null };
+ default:
+ return state;
+ }
+};
+
+const initialState: UserManagementState = {
+ users: [],
+ enterprises: [],
+ loading: false,
+ error: null,
+ pagination: {
+ page: 1,
+ size: 10,
+ total: 0,
+ totalPages: 0,
+ hasNext: false,
+ hasPrev: false,
+ },
+ filters: {
searchKeyword: '',
statusFilter: 'all',
typeFilter: 'all'
- });
- const [showForm, setShowForm] = useState(false);
- const [showDetailDialog, setShowDetailDialog] = useState(false);
- const [editingUser, setEditingUser] = useState(null);
- const [selectedUser, setSelectedUser] = useState(null);
- const [formData, setFormData] = useState({
- userType: 'enterprise_admin',
- status: 'active',
- roleIds: [],
- });
+ },
+ sortBy: 'created_at',
+ sortOrder: 'desc',
+ selectedUser: null,
+ showDetailDialog: false,
+};
+export default function TenantUserManagementPage() {
+ const [state, dispatch] = useReducer(userManagementReducer, initialState);
+
+ // 加载用户数据
+ const loadUsers = async (resetPage = false) => {
+ try {
+ dispatch({ type: 'SET_LOADING', payload: true });
+
+ const params: UsersQueryParams = {
+ search: state.filters.searchKeyword || undefined,
+ page: resetPage ? 1 : state.pagination.page,
+ size: state.pagination.size,
+ order_by: state.sortBy,
+ sort_order: state.sortOrder,
+ };
+
+ // 根据状态筛选器设置 is_active 参数
+ if (state.filters.statusFilter === 'active') {
+ params.is_active = true;
+ } else if (state.filters.statusFilter === 'inactive') {
+ params.is_active = false;
+ }
+
+ const response: UsersApiResponse = await fetchUsers(params);
+ const transformedUsers = response.data.map(transformUserData);
+
+ dispatch({
+ type: 'SET_USERS',
+ payload: {
+ data: transformedUsers,
+ pagination: {
+ page: response.page,
+ size: response.size,
+ total: response.total,
+ totalPages: response.total_pages,
+ hasNext: response.has_next,
+ hasPrev: response.has_prev,
+ }
+ }
+ });
+ } catch (error) {
+ console.error('Failed to load users:', error);
+ dispatch({
+ type: 'SET_ERROR',
+ payload: error instanceof Error ? error.message : '加载用户数据失败'
+ });
+ }
+ };
+
+ // 加载企业数据(这里暂时使用mock数据,后续可以添加企业API)
+ const loadEnterprises = () => {
+ // 这里可以添加企业API调用,现在使用mock数据
+ const mockEnterprises: Enterprise[] = [
+ { id: 'ent-1', name: '丰收现代农业集团' },
+ { id: 'ent-2', name: '绿色种植科技有限公司' },
+ { id: 'ent-3', name: '智慧农业示范区' },
+ ];
+ dispatch({ type: 'SET_ENTERPRISES', payload: mockEnterprises });
+ };
+
+ // 搜索处理
+ const handleSearch = (value: string) => {
+ dispatch({ type: 'SET_FILTERS', payload: { searchKeyword: value } });
+ };
+
+ // 状态筛选
+ const handleStatusFilter = (value: string) => {
+ dispatch({ type: 'SET_FILTERS', payload: { statusFilter: value } });
+ };
+
+ // 类型筛选
+ const handleTypeFilter = (value: string) => {
+ dispatch({ type: 'SET_FILTERS', payload: { typeFilter: value } });
+ };
+
+ // 排序处理
+ const handleSort = (sortBy: string) => {
+ const newSortOrder = state.sortBy === sortBy && state.sortOrder === 'desc' ? 'asc' : 'desc';
+ dispatch({ type: 'SET_SORT', payload: { sortBy, sortOrder: newSortOrder } });
+ };
+
+ // 分页处理
+ const handlePageChange = (page: number) => {
+ // 边界检查,确保页码在有效范围内
+ if (page < 1) {
+ page = 1;
+ } else if (page > state.pagination.totalPages && state.pagination.totalPages > 0) {
+ page = state.pagination.totalPages;
+ }
+ dispatch({ type: 'SET_PAGINATION', payload: { page } });
+ };
+
+ // 查看详情
+ const handleViewDetail = (user: User) => {
+ dispatch({ type: 'SET_SELECTED_USER', payload: user });
+ dispatch({ type: 'TOGGLE_DETAIL_DIALOG', payload: true });
+ };
+
+ // 编辑用户
+ const handleEdit = (user: User) => {
+ // 这里可以添加编辑逻辑,比如打开编辑对话框
+ toast.info('编辑功能开发中...');
+ };
+
+ // 删除用户
+ const handleDelete = (user: User) => {
+ if (!confirm(`确定要删除用户 ${user.fullName || user.username} 吗?`)) return;
+ // 这里可以添加删除逻辑,调用API删除用户
+ toast.info('删除功能开发中...');
+ };
+
+ // 切换用户状态
+ const handleToggleStatus = (user: User) => {
+ const newStatus = !user.isActive;
+ const statusText = newStatus ? '激活' : '停用';
+ if (!confirm(`确定要${statusText}用户 ${user.fullName || user.username} 吗?`)) return;
+ // 这里可以添加状态切换逻辑,调用API更新用户状态
+ toast.info(`${statusText}功能开发中...`);
+ };
+
+ // 重置密码
+ const handleResetPassword = (user: User) => {
+ if (!confirm(`确定要重置用户 ${user.fullName || user.username} 的密码吗?`)) return;
+ // 这里可以添加重置密码逻辑,调用API重置密码
+ toast.info('重置密码功能开发中...');
+ };
+
+ // 刷新数据
+ const handleRefresh = () => {
+ dispatch({ type: 'REFRESH_DATA' });
+ loadUsers(true);
+ toast.success('数据已刷新');
+ };
+
+ // 统计数据计算
+ const stats = [
+ {
+ label: '总用户数',
+ value: state.pagination.total,
+ color: 'text-blue-600',
+ bg: 'bg-blue-100',
+ },
+ {
+ label: '活跃用户',
+ value: state.users.filter(u => u.isActive).length,
+ color: 'text-green-600',
+ bg: 'bg-green-100',
+ },
+ {
+ label: '管理员',
+ value: state.users.filter(u => u.isSuperuser).length,
+ color: 'text-purple-600',
+ bg: 'bg-purple-100',
+ },
+ {
+ label: '已验证',
+ value: state.users.filter(u => u.isVerified).length,
+ color: 'text-orange-600',
+ bg: 'bg-orange-100',
+ },
+ ];
+
+ // 初始化和监听器
useEffect(() => {
loadUsers();
loadEnterprises();
}, []);
- const loadEnterprises = () => {
- const data = localStorage.getItem('smart_agriculture_enterprises');
- if (data) {
- const allEnterprises = JSON.parse(data);
- setEnterprises(allEnterprises.map((e: any) => ({ id: e.id, name: e.name })));
+ useEffect(() => {
+ const timer = setTimeout(() => {
+ loadUsers();
+ }, 300);
+
+ return () => clearTimeout(timer);
+ }, [state.filters.searchKeyword, state.filters.statusFilter, state.filters.typeFilter, state.sortBy, state.sortOrder]);
+
+ useEffect(() => {
+ if (state.pagination.page > 1) {
+ loadUsers();
}
- };
-
- const loadUsers = () => {
- const data = localStorage.getItem('smart_agriculture_users');
- if (data) {
- setUsers(JSON.parse(data));
- } else {
- // 初始化示例数据
- const mockUsers: User[] = [
- {
- id: 'user-1',
- username: 'admin',
- name: '系统管理员',
- phone: '13900000000',
- email: 'admin@system.com',
- userType: 'super_admin',
- roleIds: ['role-1'],
- roles: ['超级管理员'],
- status: 'active',
- createdAt: '2024-01-01T00:00:00',
- updatedAt: '2024-01-01T00:00:00',
- lastLoginTime: '2024-10-14T10:00:00',
- },
- {
- id: 'user-2',
- username: 'ent_admin_1',
- name: '李总',
- phone: '13900139002',
- email: 'litotal@fengshou.com',
- enterpriseId: 'ent-2',
- enterpriseName: '丰收现代农业集团',
- userType: 'enterprise_admin',
- roleIds: ['role-2'],
- roles: ['企业管理员'],
- status: 'active',
- createdAt: '2024-10-05T10:00:00',
- updatedAt: '2024-10-05T10:00:00',
- lastLoginTime: '2024-10-14T09:00:00',
- },
- {
- id: 'user-3',
- username: 'zhangsan',
- name: '张三',
- phone: '13800138001',
- email: 'zhangsan@fengshou.com',
- enterpriseId: 'ent-2',
- enterpriseName: '丰收现代农业集团',
- userType: 'employee',
- roleIds: ['role-3'],
- roles: ['操作员'],
- status: 'active',
- createdAt: '2024-10-01T08:00:00',
- updatedAt: '2024-10-01T08:00:00',
- lastLoginTime: '2024-10-14T08:30:00',
- },
- ];
- localStorage.setItem('smart_agriculture_users', JSON.stringify(mockUsers));
- setUsers(mockUsers);
- }
- };
-
- const filteredUsers = users.filter(user => {
- const matchKeyword = !filters.searchKeyword ||
- user.name.includes(filters.searchKeyword) ||
- user.username.includes(filters.searchKeyword) ||
- user.phone.includes(filters.searchKeyword) ||
- (user.enterpriseName && user.enterpriseName.includes(filters.searchKeyword));
-
- const matchStatus = filters.statusFilter === 'all' || user.status === filters.statusFilter;
- const matchType = filters.typeFilter === 'all' || user.userType === filters.typeFilter;
-
- return matchKeyword && matchStatus && matchType;
- });
-
- const handleAddUser = () => {
- setEditingUser(null);
- setFormData({
- userType: 'enterprise_admin',
- status: 'active',
- roleIds: [],
- });
- setShowForm(true);
- };
-
- const handleEdit = (user: User) => {
- setEditingUser(user);
- setFormData(user);
- setShowForm(true);
- };
-
- const handleSave = () => {
- if (!formData.username || !formData.name || !formData.phone) {
- toast.error('请填写必填项');
- return;
- }
-
- // 如果是企业管理员,必须选择企业
- if (formData.userType === 'enterprise_admin' && !formData.enterpriseId) {
- toast.error('企业管理员必须选择所属企业');
- return;
- }
-
- // 根据选择的企业ID设置企业名称
- let enterpriseName = formData.enterpriseName;
- if (formData.enterpriseId && !enterpriseName) {
- const selectedEnterprise = enterprises.find(e => e.id === formData.enterpriseId);
- if (selectedEnterprise) {
- enterpriseName = selectedEnterprise.name;
- }
- }
-
- if (editingUser) {
- const updated = users.map(user =>
- user.id === editingUser.id
- ? {
- ...user,
- ...formData,
- enterpriseName,
- updatedAt: new Date().toISOString(),
- }
- : user
- );
- setUsers(updated);
- localStorage.setItem('smart_agriculture_users', JSON.stringify(updated));
- toast.success('用户信息更新成功');
- } else {
- const newUser: User = {
- id: `user-${Date.now()}`,
- ...formData as User,
- enterpriseName,
- createdAt: new Date().toISOString(),
- updatedAt: new Date().toISOString(),
- };
- const updated = [...users, newUser];
- setUsers(updated);
- localStorage.setItem('smart_agriculture_users', JSON.stringify(updated));
- toast.success('用户添加成功');
- }
-
- setShowForm(false);
- };
-
- const handleDelete = (id: string) => {
- if (!confirm('确定要删除该用户吗?')) return;
-
- const updated = users.filter(user => user.id !== id);
- setUsers(updated);
- localStorage.setItem('smart_agriculture_users', JSON.stringify(updated));
- toast.success('用户删除成功');
- };
-
- const handleToggleStatus = (user: User) => {
- const newStatus = user.status === 'active' ? 'frozen' : 'active';
- const updated = users.map(u =>
- u.id === user.id
- ? { ...u, status: newStatus, updatedAt: new Date().toISOString() }
- : u
- );
- setUsers(updated);
- localStorage.setItem('smart_agriculture_users', JSON.stringify(updated));
- toast.success(newStatus === 'active' ? '账户已激活' : '账户已冻结');
- };
-
- const handleResetPassword = (user: User) => {
- if (!confirm(`确定要重置 ${user.name} 的密码吗?`)) return;
- toast.success('密码已重置为:123456');
- };
-
- const handleViewDetail = (user: User) => {
- setSelectedUser(user);
- setShowDetailDialog(true);
- };
-
- const handleExport = () => {
- const dataStr = JSON.stringify(users, null, 2);
- const dataBlob = new Blob([dataStr], { type: 'application/json' });
- const url = URL.createObjectURL(dataBlob);
- const link = document.createElement('a');
- link.href = url;
- link.download = `users_${new Date().getTime()}.json`;
- link.click();
- toast.success('用户数据导出成功');
- };
+ }, [state.pagination.page]);
return (
-
+ {/* 页面标题和统计 */}
+
{/* 统计卡片 */}
-
+
{/* 搜索和筛选 */}
+ {/* 错误显示 */}
+ {state.error && (
+
+ )}
+
{/* 用户列表 */}
- {/* 添加/编辑表单 */}
-
-
- {/* 详情对话框 */}
+ {/* 用户详情对话框 */}
dispatch({ type: 'TOGGLE_DETAIL_DIALOG', payload: open })}
+ user={state.selectedUser}
/>
);
diff --git a/crop-x/src/app/(app)/central-config/tenant/user-management/types.ts b/crop-x/src/app/(app)/central-config/tenant/user-management/types.ts
index ca463b5..d7080c7 100644
--- a/crop-x/src/app/(app)/central-config/tenant/user-management/types.ts
+++ b/crop-x/src/app/(app)/central-config/tenant/user-management/types.ts
@@ -3,18 +3,37 @@
export interface User {
id: string;
username: string;
- name: string;
- phone: string;
- email?: string;
- enterpriseId?: string;
- enterpriseName?: string;
- roleIds: string[];
- roles?: string[];
- userType: UserType;
- status: UserStatus;
+ email: string;
+ fullName: string | null;
+ phone: string | null;
+ isActive: boolean;
+ isSuperuser: boolean;
+ isVerified: boolean;
createdAt: string;
updatedAt: string;
+ lastLoginAt: string | null;
+ avatarUrl: string | null;
+ bio: string | null;
+ displayName: string | null;
+ departmentId: string | null;
+ departmentName: string | null;
+ scope: string;
+ companyName: string | null;
+ tenantId: string;
+}
+
+// 为了兼容现有代码,保留一些映射属性
+export interface UserWithLegacyFields extends User {
+ // 向后兼容的属性
+ name: string;
+ phone: string;
+ enterpriseId?: string;
+ enterpriseName?: string;
+ userType: UserType;
+ status: UserStatus;
lastLoginTime?: string;
+ roleIds: string[];
+ roles?: string[];
}
export type UserType = 'super_admin' | 'enterprise_admin' | 'employee';
@@ -40,6 +59,37 @@ export interface UserFilters {
typeFilter: string;
}
+// API响应数据类型
+export interface UsersApiResponse {
+ data: User[];
+ total: number;
+ page: number;
+ size: number;
+ total_pages: number;
+ has_next: boolean;
+ has_prev: boolean;
+}
+
+// 分页状态
+export interface PaginationState {
+ page: number;
+ size: number;
+ total: number;
+ totalPages: number;
+ hasNext: boolean;
+ hasPrev: boolean;
+}
+
+// API查询参数
+export interface UsersQueryParams {
+ search?: string;
+ is_active?: boolean;
+ page?: number;
+ size?: number;
+ order_by?: string;
+ sort_order?: 'asc' | 'desc';
+}
+
// 表单数据
export interface UserFormData {
username?: string;