import React, { useState, useEffect } from 'react'; import { Table, Button, Form, Input, Space, message, Popconfirm, Select, Divider, Card, Typography, Upload, Modal } from 'antd'; import { PlusOutlined, DeleteOutlined, InboxOutlined, UploadOutlined } from '@ant-design/icons'; import { supabaseService } from '@/hooks/supabaseService'; import { v4 as uuidv4 } from 'uuid'; import { supabase } from "@/config/supabase"; const TYPE = 'project'; const ProjectSections = () => { const [data, setData] = useState([]); const [loading, setLoading] = useState(false); const [editingKey, setEditingKey] = useState(''); const [form] = Form.useForm(); const [loadingUnits, setLoadingUnits] = useState(false); const [units, setUnits] = useState([]); const [formValues, setFormValues] = useState({}); const [uploadModalVisible, setUploadModalVisible] = useState(false); const [currentAddItem, setCurrentAddItem] = useState(null); const [pagination, setPagination] = useState({ current: 1, pageSize: 10, total: 0, }); const fetchSections = async (page = pagination.current, pageSize = pagination.pageSize) => { setLoading(true); try { const { data: sections, total } = await supabaseService.select('resources', { filter: { 'type': { eq: 'sections' }, 'attributes->>template_type': { eq: TYPE } }, order: { column: 'created_at', ascending: false }, page, pageSize }); setData(sections || []); setPagination(prev => ({ ...prev, current: page, pageSize, total })); } catch (error) { message.error('获取模块数据失败'); console.error(error); } finally { setLoading(false); } }; const fetchUnits = async () => { setLoadingUnits(true); try { const { data: units } = await supabaseService.select("resources", { filter: { type: { eq: "units" }, "attributes->>template_type": { in: `(${TYPE})` }, }, order: { column: "created_at", ascending: false, }, }); setUnits(units || []); } catch (error) { message.error("获取资源类型列表失败"); console.error(error); } finally { setLoadingUnits(false); } }; useEffect(() => { fetchSections(1, pagination.pageSize); fetchUnits(); }, [TYPE]); const handleAdd = () => { const newData = { id: Date.now().toString(), attributes: { name: '', template_type: TYPE, items: [{ key: uuidv4(), url: '', title: '', unit: '', description: '' }] }, isNew: true }; setData([newData, ...data]); setEditingKey(newData.id); form.setFieldsValue(newData.attributes); }; const handleSave = async (record) => { try { const values = await form.validateFields(); const items = form.getFieldValue(['items']) || []; if (!items.length || !items.some(item => item.title)) { message.error('请至少添加一个有效的资源项目'); return; } const formattedItems = items.filter(item => item.title).map(item => ({ url: item.url, title: item.title, unit: item.unit, description: item.description })); if (record.isNew) { await supabaseService.insert('resources', { type: 'sections', attributes: { name: values.name, template_type: TYPE, items: formattedItems, }, schema_version: 1 }); } else { await supabaseService.update('resources', { id: record.id }, { attributes: { name: values.name, template_type: TYPE, items: formattedItems, }, updated_at: new Date().toISOString() } ); } message.success('保存成功'); setEditingKey(''); fetchSections(pagination.current, pagination.pageSize); } catch (error) { message.error('保存失败'); console.error(error); } }; const handleDelete = async (record) => { try { await supabaseService.delete('resources', { id: record.id }); message.success('删除成功'); if (data.length === 1 && pagination.current > 1) { fetchSections(pagination.current - 1, pagination.pageSize); } else { fetchSections(pagination.current, pagination.pageSize); } } catch (error) { message.error('删除失败'); console.error(error); } }; const handleAddUnit = async (unitName) => { try { await supabaseService.insert("resources", { type: "units", attributes: { name: unitName, template_type: TYPE, }, schema_version: 1, }); message.success("新增资源类型成功"); fetchUnits(); return true; } catch (error) { message.error("新增资源类型失败"); console.error(error); return false; } }; const handleValuesChange = (changedValues, allValues) => { setFormValues(allValues); }; const handleFileUpload = async (file, addItem) => { try { const fileExt = file.name.split('.').pop(); const fileName = `${Date.now()}.${fileExt}`; const { data, error } = await supabase.storage .from('file') .upload(filePath, file); if (error) throw error; const { data: { publicUrl } } = supabase.storage .from('file') .getPublicUrl(fileName); let fileType = ''; if (file.type.startsWith('image/')) { fileType = '图片'; } else if (file.type.startsWith('video/')) { fileType = '视频'; } else if (file.type.includes('pdf')) { fileType = 'PDF文档'; } else { fileType = '其他文件'; } addItem({ key: uuidv4(), url: publicUrl, title: `${fileType}-${file.name}`, unit: fileType, description: '', }); return true; } catch (error) { message.error('文件上传失败'); console.error(error); return false; } }; const renderUploadModal = () => ( setUploadModalVisible(false)} footer={null} > { try { const result = await handleFileUpload(file, currentAddItem); if (result) { onSuccess(); } else { onError(); } } catch (err) { onError(); } }} onChange={(info) => { if (info.file.status === 'done') { message.success(`${info.file.name} 上传成功`); } else if (info.file.status === 'error') { message.error(`${info.file.name} 上传失败`); } }} >

点击或拖拽文件到此区域上传

支持单个或批量上传

); const columns = [ { title: '模块名称', dataIndex: ['attributes', 'name'], width: 200, render: (text, record) => { const isEditing = record.id === editingKey; return isEditing ? ( ) : ( {text} ); }, }, { title: '资源项目', dataIndex: ['attributes', 'items'], render: (items, record) => { const isEditing = record.id === editingKey; if (isEditing) { return ( {(fields, { add, remove }) => (
{fields.map((field, index) => (
))}
)}
); } return (
{(items || []).map((item, index) => (
{item.title} {item.unit || '未设置类型'} {item.description && ( ({item.description}) )}
))}
); }, }, { title: '操作', width: 160, fixed: 'right', render: (_, record) => { const isEditing = record.id === editingKey; return isEditing ? ( ) : ( handleDelete(record)} okText="确定" cancelText="取消" okButtonProps={{ className: "bg-red-500 hover:bg-red-600 border-red-500" }} > ); }, }, ]; return (
`共 ${total} 条记录`, pageSizeOptions: ['10', '20', '50', '100'], onChange: (page, pageSize) => { if (pageSize !== pagination.pageSize) { setPagination(prev => ({ ...prev, pageSize })); fetchSections(1, pageSize); } else { fetchSections(page, pageSize); } } }} className="rounded-lg" /> {renderUploadModal()} ); }; export default ProjectSections;