import React, { useState, useEffect } from 'react';
|
import {
|
Table, Card, Button, Modal, Form, Input, Select, Space, message,
|
Popconfirm, Tag, Avatar, Row, Col, DatePicker
|
} from 'antd';
|
import {
|
PlusOutlined, EditOutlined, DeleteOutlined, UserOutlined,
|
ReloadOutlined, SearchOutlined, KeyOutlined
|
} from '@ant-design/icons';
|
import { adminAPI } from '../../services/api';
|
import dayjs from 'dayjs';
|
|
const { Option } = Select;
|
const { RangePicker } = DatePicker;
|
|
const AdminManagement = () => {
|
const [form] = Form.useForm();
|
const [searchForm] = Form.useForm();
|
const [modalVisible, setModalVisible] = useState(false);
|
const [resetPasswordModalVisible, setResetPasswordModalVisible] = useState(false);
|
const [passwordForm] = Form.useForm();
|
const [editingRecord, setEditingRecord] = useState(null);
|
const [resetPasswordRecord, setResetPasswordRecord] = useState(null);
|
const [loading, setLoading] = useState(false);
|
const [admins, setAdmins] = useState([]);
|
const [pagination, setPagination] = useState({
|
current: 1,
|
pageSize: 10,
|
total: 0,
|
});
|
const [filters, setFilters] = useState({});
|
|
// 获取管理员列表
|
const fetchAdmins = async (params = {}) => {
|
try {
|
setLoading(true);
|
const queryParams = {
|
page: pagination.current,
|
size: pagination.pageSize,
|
...filters,
|
...params,
|
};
|
|
// 处理时间范围参数
|
if (queryParams.createStart && queryParams.createEnd) {
|
// 保持原格式
|
}
|
|
const response = await adminAPI.getAdminList(queryParams);
|
if (response.code === 0) {
|
setAdmins(response.data.content || []);
|
setPagination(prev => ({
|
...prev,
|
total: response.data.totalElements || 0,
|
}));
|
} else {
|
message.error(response.msg || '获取管理员列表失败');
|
}
|
} catch (error) {
|
console.error('获取管理员列表失败:', error);
|
message.error(error.message || '获取管理员列表失败');
|
} finally {
|
setLoading(false);
|
}
|
};
|
|
// 页面初始化加载数据
|
useEffect(() => {
|
fetchAdmins();
|
}, [pagination.current, pagination.pageSize]);
|
|
// 处理分页变化
|
const handleTableChange = (paginationInfo) => {
|
setPagination(prev => ({
|
...prev,
|
current: paginationInfo.current,
|
pageSize: paginationInfo.pageSize,
|
}));
|
};
|
|
// 处理搜索
|
const handleSearch = () => {
|
const values = searchForm.getFieldsValue();
|
const newFilters = {};
|
|
if (values.username) {
|
newFilters.username = values.username;
|
}
|
if (values.name) {
|
newFilters.name = values.name;
|
}
|
if (values.role) {
|
newFilters.role = values.role;
|
}
|
if (values.status !== undefined && values.status !== null) {
|
newFilters.status = values.status;
|
}
|
if (values.createTimeRange && values.createTimeRange.length === 2) {
|
newFilters.createStart = values.createTimeRange[0].format('YYYY-MM-DD HH:mm:ss');
|
newFilters.createEnd = values.createTimeRange[1].format('YYYY-MM-DD HH:mm:ss');
|
}
|
|
setFilters(newFilters);
|
setPagination(prev => ({ ...prev, current: 1 }));
|
fetchAdmins(newFilters);
|
};
|
|
// 重置搜索
|
const handleReset = () => {
|
searchForm.resetFields();
|
setFilters({});
|
setPagination(prev => ({ ...prev, current: 1 }));
|
fetchAdmins({});
|
};
|
|
const columns = [
|
{
|
title: '管理员',
|
key: 'admin',
|
render: (_, record) => (
|
<Space>
|
<Avatar icon={<UserOutlined />} />
|
<div>
|
<div style={{ fontWeight: 'bold' }}>{record.name}</div>
|
<div style={{ fontSize: '12px', color: '#8c8c8c' }}>{record.username}</div>
|
</div>
|
</Space>
|
),
|
},
|
{
|
title: '手机号',
|
dataIndex: 'phone',
|
key: 'phone',
|
},
|
{
|
title: '角色',
|
dataIndex: 'role',
|
key: 'role',
|
render: (role) => {
|
const colorMap = {
|
'admin': 'red',
|
'user': 'blue',
|
'operator': 'green',
|
};
|
const roleNameMap = {
|
'admin': '管理员',
|
'user': '普通用户',
|
'operator': '操作员',
|
};
|
return <Tag color={colorMap[role] || 'default'}>{roleNameMap[role] || role}</Tag>;
|
},
|
},
|
{
|
title: '状态',
|
dataIndex: 'status',
|
key: 'status',
|
render: (status) => (
|
<Tag color={status === '1' ? 'success' : 'default'}>
|
{status === '1' ? '正常' : '禁用'}
|
</Tag>
|
),
|
},
|
{
|
title: '所属区域',
|
key: 'area',
|
render: (_, record) => {
|
const areas = [];
|
if (record.districtName) areas.push(record.districtName);
|
if (record.subdistrictName) areas.push(record.subdistrictName);
|
if (record.communityName) areas.push(record.communityName);
|
return areas.length > 0 ? areas.join(' / ') : '-';
|
},
|
},
|
{
|
title: '最后登录',
|
dataIndex: 'lastLoginTime',
|
key: 'lastLoginTime',
|
render: (time) => time || '-',
|
},
|
{
|
title: '创建时间',
|
dataIndex: 'createTime',
|
key: 'createTime',
|
},
|
{
|
title: '操作',
|
key: 'action',
|
width: 200,
|
render: (_, record) => (
|
<Space size="middle">
|
<Button
|
type="link"
|
icon={<EditOutlined />}
|
onClick={() => handleEdit(record)}
|
>
|
编辑
|
</Button>
|
<Button
|
type="link"
|
icon={<KeyOutlined />}
|
onClick={() => handleResetPassword(record)}
|
>
|
重置密码
|
</Button>
|
<Popconfirm
|
title="确定要删除这个管理员吗?"
|
onConfirm={() => handleDelete(record.id)}
|
okText="确定"
|
cancelText="取消"
|
>
|
<Button type="link" danger icon={<DeleteOutlined />}>
|
删除
|
</Button>
|
</Popconfirm>
|
</Space>
|
),
|
},
|
];
|
|
const handleAdd = () => {
|
setEditingRecord(null);
|
form.resetFields();
|
form.setFieldsValue({
|
status: '1',
|
role: 'user',
|
});
|
setModalVisible(true);
|
};
|
|
const handleEdit = async (record) => {
|
try {
|
setLoading(true);
|
const response = await adminAPI.getAdminById(record.id);
|
if (response.code === 0 && response.data) {
|
setEditingRecord(response.data);
|
form.setFieldsValue({
|
...response.data,
|
});
|
setModalVisible(true);
|
} else {
|
message.error('获取管理员详情失败');
|
}
|
} catch (error) {
|
console.error('获取管理员详情失败:', error);
|
message.error(error.message || '获取管理员详情失败');
|
} finally {
|
setLoading(false);
|
}
|
};
|
|
const handleDelete = async (id) => {
|
try {
|
const response = await adminAPI.deleteAdmins(id.toString());
|
if (response.code === 0) {
|
message.success('删除成功');
|
fetchAdmins();
|
} else {
|
message.error(response.msg || '删除失败');
|
}
|
} catch (error) {
|
console.error('删除管理员失败:', error);
|
message.error(error.message || '删除管理员失败');
|
}
|
};
|
|
const handleResetPassword = (record) => {
|
setResetPasswordRecord(record);
|
passwordForm.resetFields();
|
setResetPasswordModalVisible(true);
|
};
|
|
const handleResetPasswordOk = async () => {
|
try {
|
const values = await passwordForm.validateFields();
|
setLoading(true);
|
|
const response = await adminAPI.resetPassword(resetPasswordRecord.id, values.newPassword);
|
if (response.code === 0) {
|
message.success('密码重置成功');
|
setResetPasswordModalVisible(false);
|
passwordForm.resetFields();
|
} else {
|
message.error(response.msg || '密码重置失败');
|
}
|
} catch (error) {
|
console.error('密码重置失败:', error);
|
if (error.errorFields) {
|
// 表单验证错误
|
return;
|
}
|
message.error(error.message || '密码重置失败');
|
} finally {
|
setLoading(false);
|
}
|
};
|
|
const handleModalOk = async () => {
|
try {
|
const values = await form.validateFields();
|
setLoading(true);
|
|
const formData = { ...values };
|
// 如果是编辑且有ID,需要传递ID
|
if (editingRecord && editingRecord.id) {
|
formData.id = editingRecord.id;
|
}
|
|
const response = await adminAPI.saveAdmin(formData);
|
if (response.code === 0) {
|
message.success(editingRecord ? '更新成功' : '添加成功');
|
setModalVisible(false);
|
form.resetFields();
|
fetchAdmins();
|
} else {
|
message.error(response.msg || '保存失败');
|
}
|
} catch (error) {
|
console.error('保存管理员失败:', error);
|
if (error.errorFields) {
|
// 表单验证错误
|
return;
|
}
|
message.error(error.message || '保存管理员失败');
|
} finally {
|
setLoading(false);
|
}
|
};
|
|
const handleModalCancel = () => {
|
setModalVisible(false);
|
setEditingRecord(null);
|
form.resetFields();
|
};
|
|
return (
|
<div>
|
<div className="page-header">
|
<h1 className="page-title">管理员管理</h1>
|
<p className="page-description">管理系统管理员账号和权限</p>
|
</div>
|
|
<Card style={{ marginBottom: 16 }}>
|
<Form form={searchForm} layout="inline">
|
<Row gutter={16} style={{ width: '100%' }}>
|
<Col span={6}>
|
<Form.Item name="username" label="用户名">
|
<Input placeholder="请输入用户名" allowClear />
|
</Form.Item>
|
</Col>
|
<Col span={6}>
|
<Form.Item name="name" label="姓名">
|
<Input placeholder="请输入姓名" allowClear />
|
</Form.Item>
|
</Col>
|
<Col span={6}>
|
<Form.Item name="role" label="角色">
|
<Select placeholder="请选择角色" allowClear style={{ width: '100%' }}>
|
<Option value="admin">管理员</Option>
|
<Option value="user">普通用户</Option>
|
<Option value="operator">操作员</Option>
|
</Select>
|
</Form.Item>
|
</Col>
|
<Col span={6}>
|
<Form.Item name="status" label="状态">
|
<Select placeholder="请选择状态" allowClear style={{ width: '100%' }}>
|
<Option value="1">正常</Option>
|
<Option value="0">禁用</Option>
|
</Select>
|
</Form.Item>
|
</Col>
|
</Row>
|
<Row gutter={16} style={{ width: '100%', marginTop: 16 }}>
|
<Col span={8}>
|
<Form.Item name="createTimeRange" label="创建时间">
|
<RangePicker
|
showTime
|
format="YYYY-MM-DD HH:mm:ss"
|
style={{ width: '100%' }}
|
/>
|
</Form.Item>
|
</Col>
|
<Col span={16}>
|
<Form.Item>
|
<Space>
|
<Button
|
type="primary"
|
icon={<SearchOutlined />}
|
onClick={handleSearch}
|
>
|
查询
|
</Button>
|
<Button icon={<ReloadOutlined />} onClick={handleReset}>
|
重置
|
</Button>
|
</Space>
|
</Form.Item>
|
</Col>
|
</Row>
|
</Form>
|
</Card>
|
|
<Card>
|
<div className="table-actions">
|
<Button
|
type="primary"
|
icon={<PlusOutlined />}
|
onClick={handleAdd}
|
>
|
新增管理员
|
</Button>
|
</div>
|
|
<Table
|
columns={columns}
|
dataSource={admins}
|
rowKey="id"
|
loading={loading}
|
pagination={{
|
current: pagination.current,
|
pageSize: pagination.pageSize,
|
total: pagination.total,
|
showSizeChanger: true,
|
showQuickJumper: true,
|
showTotal: (total, range) => `第 ${range[0]}-${range[1]} 条/共 ${total} 条`,
|
}}
|
onChange={handleTableChange}
|
/>
|
</Card>
|
|
{/* 新增/编辑管理员弹窗 */}
|
<Modal
|
title={editingRecord ? '编辑管理员' : '新增管理员'}
|
open={modalVisible}
|
onOk={handleModalOk}
|
onCancel={handleModalCancel}
|
confirmLoading={loading}
|
width={600}
|
>
|
<Form
|
form={form}
|
layout="vertical"
|
>
|
<Form.Item
|
name="username"
|
label="用户名"
|
rules={[{ required: true, message: '请输入用户名' }]}
|
>
|
<Input placeholder="请输入用户名" disabled={!!editingRecord} />
|
</Form.Item>
|
|
<Form.Item
|
name="name"
|
label="姓名"
|
rules={[{ required: true, message: '请输入姓名' }]}
|
>
|
<Input placeholder="请输入姓名" />
|
</Form.Item>
|
|
<Form.Item
|
name="phone"
|
label="手机号"
|
rules={[
|
{ required: true, message: '请输入手机号' },
|
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号' }
|
]}
|
>
|
<Input placeholder="请输入手机号" />
|
</Form.Item>
|
|
<Form.Item
|
name="role"
|
label="角色"
|
rules={[{ required: true, message: '请选择角色' }]}
|
>
|
<Select placeholder="请选择角色">
|
<Option value="admin">管理员</Option>
|
<Option value="user">普通用户</Option>
|
<Option value="operator">操作员</Option>
|
</Select>
|
</Form.Item>
|
|
<Form.Item
|
name="status"
|
label="状态"
|
rules={[{ required: true, message: '请选择状态' }]}
|
>
|
<Select placeholder="请选择状态">
|
<Option value="1">正常</Option>
|
<Option value="0">禁用</Option>
|
</Select>
|
</Form.Item>
|
|
<Form.Item
|
name="districtCode"
|
label="区代码"
|
>
|
<Input placeholder="请输入区代码" />
|
</Form.Item>
|
|
<Form.Item
|
name="districtName"
|
label="区名称"
|
>
|
<Input placeholder="请输入区名称" />
|
</Form.Item>
|
|
<Form.Item
|
name="subdistrictCode"
|
label="街道代码"
|
>
|
<Input placeholder="请输入街道代码" />
|
</Form.Item>
|
|
<Form.Item
|
name="subdistrictName"
|
label="街道名称"
|
>
|
<Input placeholder="请输入街道名称" />
|
</Form.Item>
|
|
<Form.Item
|
name="communityCode"
|
label="社区代码"
|
>
|
<Input placeholder="请输入社区代码" />
|
</Form.Item>
|
|
<Form.Item
|
name="communityName"
|
label="社区名称"
|
>
|
<Input placeholder="请输入社区名称" />
|
</Form.Item>
|
|
{!editingRecord && (
|
<Form.Item
|
name="password"
|
label="密码"
|
rules={[
|
{ required: true, message: '请输入密码' },
|
{ min: 6, message: '密码至少6位' }
|
]}
|
>
|
<Input.Password placeholder="请输入密码" />
|
</Form.Item>
|
)}
|
</Form>
|
</Modal>
|
|
{/* 重置密码弹窗 */}
|
<Modal
|
title="重置密码"
|
open={resetPasswordModalVisible}
|
onOk={handleResetPasswordOk}
|
onCancel={() => {
|
setResetPasswordModalVisible(false);
|
passwordForm.resetFields();
|
}}
|
confirmLoading={loading}
|
>
|
<Form
|
form={passwordForm}
|
layout="vertical"
|
>
|
<Form.Item
|
label="管理员"
|
>
|
<Input
|
value={resetPasswordRecord ? `${resetPasswordRecord.name} (${resetPasswordRecord.username})` : ''}
|
disabled
|
/>
|
</Form.Item>
|
<Form.Item
|
name="newPassword"
|
label="新密码"
|
rules={[
|
{ required: true, message: '请输入新密码' },
|
{ min: 6, message: '密码至少6位' }
|
]}
|
>
|
<Input.Password placeholder="请输入新密码" />
|
</Form.Item>
|
</Form>
|
</Modal>
|
</div>
|
);
|
};
|
|
export default AdminManagement;
|