|
|
@@ -0,0 +1,143 @@
|
|
|
+import React, { useState, useEffect } from 'react';
|
|
|
+import { Table, Button, Input } from 'antd';
|
|
|
+import { PlusOutlined, EditOutlined, DeleteOutlined, DownloadOutlined } from '@ant-design/icons';
|
|
|
+import MemberForm from './MemberForm';
|
|
|
+
|
|
|
+interface Member {
|
|
|
+ id: number;
|
|
|
+ name: string;
|
|
|
+ gender: string;
|
|
|
+ age: number;
|
|
|
+ birthDate: string;
|
|
|
+ contact: string;
|
|
|
+ occupation: string;
|
|
|
+ servicePosition: string;
|
|
|
+ isBaptized: boolean;
|
|
|
+ baptismDate?: string;
|
|
|
+ notes?: string;
|
|
|
+}
|
|
|
+
|
|
|
+const MemberList: React.FC = () => {
|
|
|
+ const [members, setMembers] = useState<Member[]>([]);
|
|
|
+ const [isModalVisible, setIsModalVisible] = useState(false);
|
|
|
+ const [editingMember, setEditingMember] = useState<Member | null>(null);
|
|
|
+ const [searchTerm, setSearchTerm] = useState('');
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ // 这里应该从API获取会员数据
|
|
|
+ // 暂时使用模拟数据
|
|
|
+ const mockMembers: Member[] = [
|
|
|
+ {
|
|
|
+ id: 1,
|
|
|
+ name: '张三',
|
|
|
+ gender: '男',
|
|
|
+ age: 30,
|
|
|
+ birthDate: '1994-01-01',
|
|
|
+ contact: '13800138000',
|
|
|
+ occupation: '工程师',
|
|
|
+ servicePosition: '主日学老师',
|
|
|
+ isBaptized: true,
|
|
|
+ baptismDate: '2020-05-01',
|
|
|
+ notes: '热心服侍'
|
|
|
+ },
|
|
|
+ // ... 更多模拟数据
|
|
|
+ ];
|
|
|
+ setMembers(mockMembers);
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ const columns = [
|
|
|
+ {
|
|
|
+ title: '姓名',
|
|
|
+ dataIndex: 'name',
|
|
|
+ key: 'name',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '性别',
|
|
|
+ dataIndex: 'gender',
|
|
|
+ key: 'gender',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '年龄',
|
|
|
+ dataIndex: 'age',
|
|
|
+ key: 'age',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '联系方式',
|
|
|
+ dataIndex: 'contact',
|
|
|
+ key: 'contact',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '操作',
|
|
|
+ key: 'action',
|
|
|
+ render: (text: string, record: Member) => (
|
|
|
+ <span>
|
|
|
+ <Button icon={<EditOutlined />} onClick={() => handleEdit(record)}>编辑</Button>
|
|
|
+ <Button icon={<DeleteOutlined />} onClick={() => handleDelete(record.id)}>删除</Button>
|
|
|
+ </span>
|
|
|
+ ),
|
|
|
+ },
|
|
|
+ ];
|
|
|
+
|
|
|
+ const handleAdd = () => {
|
|
|
+ setEditingMember(null);
|
|
|
+ setIsModalVisible(true);
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleEdit = (member: Member) => {
|
|
|
+ setEditingMember(member);
|
|
|
+ setIsModalVisible(true);
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleDelete = (id: number) => {
|
|
|
+ setMembers(members.filter(member => member.id !== id));
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleSave = (member: Member) => {
|
|
|
+ if (editingMember) {
|
|
|
+ setMembers(members.map(m => m.id === member.id ? member : m));
|
|
|
+ } else {
|
|
|
+ setMembers([...members, { ...member, id: members.length + 1 }]);
|
|
|
+ }
|
|
|
+ setIsModalVisible(false);
|
|
|
+ };
|
|
|
+
|
|
|
+ const handleSearch = (value: string) => {
|
|
|
+ setSearchTerm(value);
|
|
|
+ };
|
|
|
+
|
|
|
+ const filteredMembers = members.filter(member =>
|
|
|
+ member.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
|
+ member.contact.includes(searchTerm)
|
|
|
+ );
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div>
|
|
|
+ <div style={{ marginBottom: 16 }}>
|
|
|
+ <Button icon={<PlusOutlined />} onClick={handleAdd}>添加会员</Button>
|
|
|
+ <Button icon={<DownloadOutlined />}>导出Excel</Button>
|
|
|
+ <Input.Search
|
|
|
+ placeholder="搜索姓名或联系方式"
|
|
|
+ onSearch={handleSearch}
|
|
|
+ style={{ width: 200, float: 'right' }}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <Table
|
|
|
+ columns={columns}
|
|
|
+ dataSource={filteredMembers}
|
|
|
+ rowKey="id"
|
|
|
+ pagination={{
|
|
|
+ total: filteredMembers.length,
|
|
|
+ showTotal: (total) => `共 ${total} 条记录`,
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ <MemberForm
|
|
|
+ visible={isModalVisible}
|
|
|
+ onCancel={() => setIsModalVisible(false)}
|
|
|
+ onSave={handleSave}
|
|
|
+ member={editingMember}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+export default MemberList;
|