import React, { useState, useEffect, useCallback } from 'react';
|
import { Table, Button, Space, Card, message, Tag, Row, Col, Avatar, Form, Input, Select, Spin, Modal, Radio } from 'antd';
|
import { EyeOutlined, UserOutlined, CheckOutlined } from '@ant-design/icons';
|
import { useNavigate } from 'react-router-dom';
|
import { applicationAPI } from '../../services/api';
|
|
const { Option } = Select;
|
|
const VolunteerList = () => {
|
const [searchForm] = Form.useForm();
|
const [selectedStatus, setSelectedStatus] = useState('全部');
|
const [volunteers, setVolunteers] = useState([]);
|
const [loading, setLoading] = useState(false);
|
const [pagination, setPagination] = useState({
|
current: 1,
|
pageSize: 10,
|
total: 0,
|
});
|
const [filters, setFilters] = useState({});
|
const [reviewModal, setReviewModal] = useState({
|
visible: false,
|
id: null,
|
name: '',
|
});
|
const [reviewForm] = Form.useForm();
|
|
const navigate = useNavigate();
|
|
// 获取志愿者列表数据
|
const fetchVolunteerData = useCallback(async (params = {}) => {
|
try {
|
setLoading(true);
|
const queryParams = {
|
page: pagination.current,
|
size: pagination.pageSize,
|
...filters,
|
...params,
|
};
|
|
const response = await applicationAPI.getApplicationList(queryParams);
|
if (response.code === 0) {
|
// 转换数据格式以适配前端显示
|
const transformedData = response.data.content?.map(item => {
|
// 调试日志:查看状态值类型
|
console.log('状态值:', item.status, '类型:', typeof item.status);
|
return {
|
id: item.id,
|
name: item.name, // 志愿者姓名
|
idCard: item.idCard, // 志愿者身份证号
|
phone: item.phone, // 志愿者手机号码
|
createTime: item.createTime, // 加入时间
|
status: (item.status === 0 || item.status === '0') ? '待审核' : (item.status === 1 || item.status === '1') ? '通过' : (item.status === 2 || item.status === '2') ? '不通过' : '未知', // 审核状态映射
|
totalPoints: item.applicationsCount?.points || 0, // 积分数量
|
activities: item.applicationsCount?.activityNum || 0, // 参加活动次数
|
serviceHours: item.applicationsCount?.serviceHours || 0, // 服务时长
|
originalData: item,
|
};
|
}) || [];
|
|
console.log('转换后的数据:', transformedData);
|
setVolunteers(transformedData);
|
setPagination(prev => ({
|
...prev,
|
total: response.data.totalElements || 0,
|
}));
|
}
|
} catch (error) {
|
console.error('获取志愿者列表失败:', error);
|
message.error('获取志愿者列表失败');
|
} finally {
|
setLoading(false);
|
}
|
}, [pagination.current, pagination.pageSize, filters]);
|
|
// 页面初始化加载数据
|
useEffect(() => {
|
fetchVolunteerData();
|
}, [fetchVolunteerData]);
|
|
const getStatusColor = (status) => {
|
switch (status) {
|
case '通过':
|
return 'success';
|
case '待审核':
|
return 'warning';
|
case '不通过':
|
return 'error';
|
default:
|
return 'default';
|
}
|
};
|
|
const columns = [
|
{
|
title: '志愿者',
|
key: 'volunteer',
|
width: 200,
|
render: (_, record) => (
|
<Space>
|
<Avatar icon={<UserOutlined />} />
|
<div style={{ fontWeight: 'bold' }}>{record.name}</div>
|
</Space>
|
),
|
},
|
{
|
title: '联系方式',
|
key: 'contact',
|
width: 180,
|
render: (_, record) => (
|
<div>
|
<div>{record.phone}</div>
|
<div style={{ fontSize: '12px', color: '#8c8c8c' }}>{record.email}</div>
|
</div>
|
),
|
},
|
{
|
title: '积分',
|
dataIndex: 'totalPoints',
|
key: 'totalPoints',
|
width: 100,
|
render: (points) => (
|
<span style={{ color: '#52c41a', fontWeight: 'bold', fontSize: '16px' }}>
|
{points}
|
</span>
|
),
|
},
|
{
|
title: '参与活动',
|
dataIndex: 'activities',
|
key: 'activities',
|
width: 100,
|
render: (activities) => (
|
<span style={{ color: '#1890ff' }}>{activities}次</span>
|
),
|
},
|
{
|
title: '服务时长',
|
dataIndex: 'serviceHours',
|
key: 'serviceHours',
|
width: 100,
|
render: (hours) => (
|
<span style={{ color: '#faad14' }}>{hours}小时</span>
|
),
|
},
|
{
|
title: '加入时间',
|
dataIndex: 'createTime',
|
key: 'createTime',
|
width: 150,
|
render: (time) => time ? new Date(time).toLocaleString('zh-CN', {
|
year: 'numeric',
|
month: '2-digit',
|
day: '2-digit',
|
hour: '2-digit',
|
minute: '2-digit',
|
hour12: false
|
}).replace(/\//g, '-') : '-',
|
},
|
{
|
title: '状态',
|
dataIndex: 'status',
|
key: 'status',
|
width: 100,
|
render: (status) => <Tag color={getStatusColor(status)}>{status}</Tag>,
|
},
|
{
|
title: '操作',
|
key: 'action',
|
width: 200,
|
render: (_, record) => (
|
<Space size="middle">
|
<Button
|
type="link"
|
icon={<EyeOutlined />}
|
onClick={() => handleViewDetail(record)}
|
>
|
查看详情
|
</Button>
|
{record.status === '待审核' && (
|
<Button
|
type="link"
|
icon={<CheckOutlined />}
|
onClick={() => handleApprove(record)}
|
>
|
审核
|
</Button>
|
)}
|
|
</Space>
|
),
|
},
|
];
|
|
|
|
const handleApprove = (record) => {
|
setReviewModal({
|
visible: true,
|
id: record.id,
|
name: record.name,
|
});
|
reviewForm.resetFields();
|
};
|
|
const handleReviewSubmit = async () => {
|
try {
|
const values = await reviewForm.validateFields();
|
const response = await applicationAPI.reviewApplication({
|
id: reviewModal.id,
|
status: values.status,
|
reviewComment: values.reviewComment || '',
|
});
|
if (response.code === 0) {
|
message.success('审核成功');
|
setReviewModal({ visible: false, id: null, name: '' });
|
fetchVolunteerData(); // 重新获取数据
|
} else {
|
message.error('审核失败');
|
}
|
} catch (error) {
|
console.error('审核失败:', error);
|
message.error('审核失败');
|
}
|
};
|
|
const handleReviewCancel = () => {
|
setReviewModal({ visible: false, id: null, name: '' });
|
reviewForm.resetFields();
|
};
|
|
|
|
const handleSearch = (values) => {
|
console.log('搜索条件:', values);
|
setSelectedStatus(values.status || '全部');
|
setFilters(values);
|
setPagination(prev => ({ ...prev, current: 1 }));
|
fetchVolunteerData({ ...values, page: 1 });
|
};
|
|
const handleReset = () => {
|
searchForm.resetFields();
|
setSelectedStatus('全部');
|
setFilters({});
|
setPagination(prev => ({ ...prev, current: 1 }));
|
fetchVolunteerData({ page: 1 });
|
};
|
|
// 处理查看详情
|
const handleViewDetail = async (record) => {
|
try {
|
// 调用接口获取志愿者详情
|
const response = await applicationAPI.getApplicationById(record.id);
|
if (response.code === 0) {
|
// 跳转到详情页面
|
navigate(`/volunteers/${record.id}`);
|
} else {
|
message.error('获取志愿者详情失败');
|
}
|
} catch (error) {
|
console.error('获取志愿者详情失败:', error);
|
message.error('获取志愿者详情失败');
|
}
|
};
|
|
// 处理分页变化
|
const handleTableChange = (paginationInfo) => {
|
setPagination(prev => ({
|
...prev,
|
current: paginationInfo.current,
|
pageSize: paginationInfo.pageSize,
|
}));
|
fetchVolunteerData({
|
page: paginationInfo.current,
|
size: paginationInfo.pageSize,
|
});
|
};
|
|
|
|
return (
|
<div>
|
<div className="page-header">
|
<h1 className="page-title">志愿者列表</h1>
|
<p className="page-description">管理所有志愿者信息,查看志愿者积分和活动参与情况</p>
|
</div>
|
|
{/* 搜索表单 */}
|
<Card className="search-form">
|
<Form
|
form={searchForm}
|
layout="inline"
|
onFinish={handleSearch}
|
>
|
<Row gutter={[16, 16]} style={{ width: '100%' }}>
|
<Col xs={24} sm={12} md={6}>
|
<Form.Item name="name" label="姓名">
|
<Input placeholder="请输入姓名" />
|
</Form.Item>
|
</Col>
|
<Col xs={24} sm={12} md={6}>
|
<Form.Item name="phone" label="手机号">
|
<Input placeholder="请输入手机号" />
|
</Form.Item>
|
</Col>
|
<Col xs={24} sm={12} md={6}>
|
<Form.Item name="status" label="状态">
|
<Select placeholder="请选择状态" allowClear>
|
<Option value="0">待审核</Option>
|
<Option value="1">审核通过</Option>
|
<Option value="2">审核不通过</Option>
|
</Select>
|
</Form.Item>
|
</Col>
|
<Col xs={24} sm={12} md={6}>
|
<Form.Item name="gender" label="性别">
|
<Select placeholder="请选择性别" allowClear>
|
<Option value="男">男</Option>
|
<Option value="女">女</Option>
|
</Select>
|
</Form.Item>
|
</Col>
|
</Row>
|
<div className="form-actions">
|
<Button type="primary" htmlType="submit">
|
搜索
|
</Button>
|
<Button onClick={handleReset}>
|
重置
|
</Button>
|
</div>
|
</Form>
|
</Card>
|
|
<Card>
|
|
<Table
|
columns={columns}
|
dataSource={volunteers}
|
rowKey="id"
|
scroll={{ x: 1200 }}
|
loading={loading}
|
pagination={{
|
...pagination,
|
showSizeChanger: true,
|
showQuickJumper: true,
|
showTotal: (total, range) => `第 ${range[0]}-${range[1]} 条/共 ${total} 条`,
|
}}
|
onChange={handleTableChange}
|
/>
|
</Card>
|
|
{/* 审核弹出框 */}
|
<Modal
|
title="审核志愿者申请"
|
open={reviewModal.visible}
|
onOk={handleReviewSubmit}
|
onCancel={handleReviewCancel}
|
okText="确定"
|
cancelText="取消"
|
width={500}
|
>
|
<div style={{ marginBottom: '16px' }}>
|
<strong>志愿者姓名:</strong>{reviewModal.name}
|
</div>
|
<Form
|
form={reviewForm}
|
layout="vertical"
|
initialValues={{
|
status: '1',
|
}}
|
>
|
<Form.Item
|
name="status"
|
label="审核结果"
|
rules={[{ required: true, message: '请选择审核结果' }]}
|
>
|
<Radio.Group>
|
<Radio value="1">通过</Radio>
|
<Radio value="2">不通过</Radio>
|
</Radio.Group>
|
</Form.Item>
|
<Form.Item
|
name="reviewComment"
|
label="审核意见"
|
>
|
<Input.TextArea
|
placeholder="请输入审核意见(可选)"
|
rows={4}
|
maxLength={200}
|
showCount
|
/>
|
</Form.Item>
|
</Form>
|
</Modal>
|
|
</div>
|
);
|
};
|
|
export default VolunteerList;
|