import React, { useEffect, useMemo, useState } from 'react';
import { Avatar, Button, Form, Input, Modal, Popconfirm, Select, Space, Switch, Table, Tag, Typography, message } from 'antd';
import { AppstoreOutlined, EditOutlined, LockOutlined, PlusOutlined, ReloadOutlined, SyncOutlined, DeleteOutlined, SafetyCertificateOutlined, UserOutlined } from '@ant-design/icons';
import dayjs from 'dayjs';
import { SycmCard } from '../../components/Common';
import {
createUser,
deleteUser,
getDepartments,
getUserPagePermissions,
getUsers,
resetPassword,
syncDingTalkUsers,
updateUser,
updateUserAdminRole,
updateUserPagePermissions,
} from '../../api/admin';
const { Text } = Typography;
const { Search } = Input;
const ROLE_LABELS = {
admin: '管理员',
analyst: '分析师',
user: '用户',
guest: '访客',
};
const SOURCE_META = {
local: { color: 'default', text: '本地账号' },
dingtalk: { color: 'blue', text: '钉钉' },
google: { color: 'red', text: 'Google' },
};
const UserManagement = () => {
const [users, setUsers] = useState([]);
const [departments, setDepartments] = useState([]);
const [loading, setLoading] = useState(false);
const [saving, setSaving] = useState(false);
const [syncing, setSyncing] = useState(false);
const [switchingAdminId, setSwitchingAdminId] = useState(null);
const [modalVisible, setModalVisible] = useState(false);
const [resetVisible, setResetVisible] = useState(false);
const [permissionVisible, setPermissionVisible] = useState(false);
const [editingUser, setEditingUser] = useState(null);
const [resetUser, setResetUser] = useState(null);
const [permissionUser, setPermissionUser] = useState(null);
const [pagePermissions, setPagePermissions] = useState([]);
const [permissionSaving, setPermissionSaving] = useState(false);
const [keyword, setKeyword] = useState('');
const [pagination, setPagination] = useState({ current: 1, pageSize: 10, total: 0 });
const [form] = Form.useForm();
const [resetForm] = Form.useForm();
const departmentOptions = useMemo(
() =>
departments
.filter((item) => item.status === 'active')
.map((item) => ({
label: item.name,
value: item.id,
})),
[departments]
);
const fetchDepartments = async () => {
try {
const data = await getDepartments();
setDepartments(Array.isArray(data) ? data : []);
} catch (error) {
message.error(error.response?.data?.error || '获取部门列表失败');
}
};
const fetchUsers = async (page = pagination.current, pageSize = pagination.pageSize, nextKeyword = keyword) => {
try {
setLoading(true);
const res = await getUsers({
page,
size: pageSize,
keyword: nextKeyword,
});
setUsers(res.data || []);
setPagination({
current: res.page || page,
pageSize: res.size || pageSize,
total: res.total || 0,
});
} catch (error) {
message.error(error.response?.data?.error || '获取用户列表失败');
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchDepartments();
fetchUsers(1, 10, '');
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const openCreateModal = () => {
setEditingUser(null);
form.resetFields();
form.setFieldsValue({
role: 'user',
status: 'active',
});
setModalVisible(true);
};
const openEditModal = (record) => {
setEditingUser(record);
form.setFieldsValue({
username: record.username,
name: record.name,
email: record.email,
mobile: record.mobile,
jobTitle: record.jobTitle,
role: record.role,
departmentId: record.department_id || undefined,
status: record.status,
});
setModalVisible(true);
};
const handleSave = async () => {
try {
const values = await form.validateFields();
setSaving(true);
if (editingUser) {
await updateUser(editingUser.id, values);
message.success('用户信息已更新');
} else {
await createUser(values);
message.success('用户已创建');
}
setModalVisible(false);
fetchUsers();
} catch (error) {
if (!error?.errorFields) {
message.error(error.response?.data?.error || '保存用户失败');
}
} finally {
setSaving(false);
}
};
const handleDelete = async (id) => {
try {
await deleteUser(id);
message.success('用户已删除');
fetchUsers();
} catch (error) {
message.error(error.response?.data?.error || '删除用户失败');
}
};
const handleToggleAdminRole = async (record) => {
const nextIsAdmin = record.role !== 'admin';
try {
setSwitchingAdminId(record.id);
const res = await updateUserAdminRole(record.id, { isAdmin: nextIsAdmin });
message.success(res.message || (nextIsAdmin ? '已授予管理员权限' : '已取消管理员权限'));
fetchUsers(pagination.current, pagination.pageSize, keyword);
} catch (error) {
message.error(error.response?.data?.error || '更新管理员权限失败');
} finally {
setSwitchingAdminId(null);
}
};
const openPagePermissionModal = async (record) => {
try {
setPermissionUser(record);
const data = await getUserPagePermissions(record.id);
setPagePermissions(Array.isArray(data.permissions) ? data.permissions : []);
setPermissionVisible(true);
} catch (error) {
message.error(error.response?.data?.error || '获取用户可见页面失败');
}
};
const handlePagePermissionToggle = (pageKey, userAllowed) => {
setPagePermissions((prev) =>
prev.map((item) => (item.pageKey === pageKey ? { ...item, userAllowed, effectiveAllowed: Boolean(item.baseAllowed) || userAllowed } : item))
);
};
const handleSavePagePermissions = async () => {
if (!permissionUser) {
return;
}
try {
setPermissionSaving(true);
const res = await updateUserPagePermissions(permissionUser.id, {
permissions: pagePermissions.map((item) => ({
pageKey: item.pageKey,
allowed: Boolean(item.userAllowed),
})),
});
setPagePermissions(Array.isArray(res.permissions) ? res.permissions : []);
message.success(res.message || '用户可见页面已更新');
setPermissionVisible(false);
} catch (error) {
message.error(error.response?.data?.error || '更新用户可见页面失败');
} finally {
setPermissionSaving(false);
}
};
const openResetModal = (record) => {
setResetUser(record);
resetForm.resetFields();
setResetVisible(true);
};
const handleResetPassword = async () => {
try {
const values = await resetForm.validateFields();
setSaving(true);
await resetPassword(resetUser.id, { newPassword: values.newPassword });
message.success('密码已重置');
setResetVisible(false);
} catch (error) {
if (!error?.errorFields) {
message.error(error.response?.data?.error || '重置密码失败');
}
} finally {
setSaving(false);
}
};
const handleSync = async () => {
try {
setSyncing(true);
const res = await syncDingTalkUsers();
message.success(`同步完成,共处理 ${res.total || 0} 位钉钉用户`);
await Promise.all([fetchUsers(1, pagination.pageSize, keyword), fetchDepartments()]);
} catch (error) {
message.error(error.response?.data?.error || '同步钉钉用户失败');
} finally {
setSyncing(false);
}
};
const columns = [
{
title: '用户',
key: 'user',
width: 280,
render: (_, record) => (