import React, { useEffect, useMemo, useState } from 'react'; import { Alert, Empty, Form, Input, Modal, Popconfirm, Select, Space, Table, Tag } from 'antd'; import { BankOutlined, InboxOutlined, PlusOutlined, UndoOutlined } from '@ant-design/icons'; import api from '../../api'; import PermissionButton from '../../components/PermissionButton'; import EditableCell from '../../components/EditableCell'; import { message } from '../../ui/app-message'; const PRESET_COLORS = [ '#ff7875', '#ffa940', '#ffc53d', '#73d13d', '#36cfc9', '#40a9ff', '#597ef7', '#9254de', '#f759ab', '#8c8c8c', ]; interface OrganizationItem { id: number; code: string; name: string; isHost: boolean; contactName?: string; phone?: string; color?: string; notes?: string; status: 'active' | 'archived'; } const OrganizationsPage: React.FC = () => { const [data, setData] = useState([]); const [loading, setLoading] = useState(false); const [modalOpen, setModalOpen] = useState(false); const [editing, setEditing] = useState(null); const [form] = Form.useForm(); const [saving, setSaving] = useState(false); const [searchText, setSearchText] = useState(''); const [filterStatus, setFilterStatus] = useState(); const filteredData = useMemo(() => { const keyword = searchText.trim().toLowerCase(); return data.filter((item) => { const matchesKeyword = !keyword || item.name.toLowerCase().includes(keyword) || item.code.toLowerCase().includes(keyword) || item.contactName?.toLowerCase().includes(keyword); return matchesKeyword && (!filterStatus || item.status === filterStatus); }); }, [data, searchText, filterStatus]); const fetchData = async () => { setLoading(true); try { setData( await api.get('/organizations', { params: { includeArchived: true } }), ); } catch (error: any) { message.error(error?.message || '机构数据加载失败'); } finally { setLoading(false); } }; useEffect(() => { void fetchData(); }, []); const openEditor = (record?: OrganizationItem) => { setEditing(record ?? null); form.resetFields(); if (record) form.setFieldsValue(record); else form.setFieldsValue({ color: PRESET_COLORS[data.length % PRESET_COLORS.length] }); setModalOpen(true); }; const handleSave = async () => { const values = await form.validateFields(); setSaving(true); try { if (editing) await api.put(`/organizations/${editing.id}`, values); else await api.post('/organizations', values); message.success(editing ? '机构已更新' : '机构已创建'); setModalOpen(false); await fetchData(); } catch (error: any) { message.error(error?.message || '保存失败'); } finally { setSaving(false); } }; const saveCell = async (record: OrganizationItem, field: string, value: unknown) => { await api.put(`/organizations/${record.id}`, { [field]: value }); message.success('已保存'); await fetchData(); }; const columns = [ { title: '机构', dataIndex: 'name', width: 220, render: (name: string, record: OrganizationItem) => ( saveCell(record, 'name', next)} > {name} {record.isHost ? ( }> 本机构 ) : ( 外部机构 )} ), }, { title: '机构编码', dataIndex: 'code', width: 130, render: (value: string, record: OrganizationItem) => ( saveCell(record, 'code', next)} > {value} ), }, { title: '联系人', dataIndex: 'contactName', width: 120, render: (value: string | undefined, record: OrganizationItem) => ( saveCell(record, 'contactName', next)} > {value || '-'} ), }, { title: '电话', dataIndex: 'phone', width: 140, render: (value: string | undefined, record: OrganizationItem) => ( saveCell(record, 'phone', next)} > {value || '-'} ), }, { title: '备注', dataIndex: 'notes', ellipsis: true, render: (value: string | undefined, record: OrganizationItem) => ( saveCell(record, 'notes', next)} > {value || '-'} ), }, { title: '状态', dataIndex: 'status', width: 90, render: (status: string) => ( {status === 'active' ? '正常' : '已归档'} ), }, { title: '操作', width: 160, render: (_: unknown, record: OrganizationItem) => ( {record.status === 'archived' ? ( { try { await api.put(`/organizations/${record.id}`, { status: 'active' }); message.success('机构已恢复'); await fetchData(); } catch (error: any) { message.error(error?.message || '恢复失败'); } }} > } > 恢复 ) : ( <> openEditor(record)} > 编辑 {!record.isHost ? ( { try { await api.delete(`/organizations/${record.id}`); message.success('机构已归档'); await fetchData(); } catch (error: any) { message.error(error?.message || '归档失败'); } }} > } > 归档 ) : null} )} ), }, ]; return (
setSearchText(event.target.value)} /> form.setFieldValue('code', event.target.value.toUpperCase())} /> {PRESET_COLORS.map((color) => (
); }; export default OrganizationsPage;