import { useState, useEffect, useRef } from "react"; import { useNavigate, useSearchParams, useLoaderData } from "@remix-run/react"; import { ActionFunctionArgs, LoaderFunctionArgs, MetaFunction } from "@remix-run/node"; import { Card } from "~/components/ui/Card"; import { Button } from "~/components/ui/Button"; import { toastService } from "~/components/ui/Toast"; import { Modal } from "~/components/ui/Modal"; import { getEntryModuleById, createEntryModule, updateEntryModule, type EntryModule } from "~/api/entry-modules/entry-modules"; import { API_BASE_URL, DOCUMENT_URL } from "~/config/api-config"; // 页面元数据 export const meta: MetaFunction = () => { return [ { title: "入口模块编辑 - 中国烟草AI合同及卷宗审核系统" }, { name: "description", content: "创建或编辑入口模块" }, ]; }; export const handle = { breadcrumb: "新建/编辑入口模块", previousRoute: { title: "入口模块管理", to: "/entry-modules" } }; // 定义加载器返回的数据类型 interface LoaderData { module?: EntryModule; error?: string; frontendJWT?: string | null; } // 加载函数 - 获取入口模块数据(编辑模式) export async function loader({ request }: LoaderFunctionArgs) { try { const { getUserSession } = await import("~/api/login/auth.server"); const { frontendJWT } = await getUserSession(request); const url = new URL(request.url); const id = url.searchParams.get('id'); if (id) { const moduleResponse = await getEntryModuleById(parseInt(id), frontendJWT); if (moduleResponse.error) { throw new Error(moduleResponse.error); } return Response.json({ module: moduleResponse.data, frontendJWT }); } return Response.json({ frontendJWT }); } catch (error) { console.error("加载入口模块失败:", error); return Response.json( { error: error || "加载入口模块失败", status: 500 } ); } } // 地区选项 const AREA_OPTIONS = [ { value: "梅州", label: "梅州" }, { value: "云浮", label: "云浮" }, { value: "揭阳", label: "揭阳" }, { value: "潮州", label: "潮州" }, { value: "省局", label: "省局" } ]; // 入口模块新建/编辑组件 export default function EntryModuleNew() { const navigate = useNavigate(); const [searchParams] = useSearchParams(); const { module, error, frontendJWT } = useLoaderData(); const id = searchParams.get('id'); const isEditMode = !!id; // 表单状态 const [name, setName] = useState(module?.name || ''); const [description, setDescription] = useState(module?.description || ''); const [selectedAreas, setSelectedAreas] = useState(module?.areas || []); const [logoFile, setLogoFile] = useState(null); const [logoPreview, setLogoPreview] = useState( module?.path ? `${DOCUMENT_URL}${module.path}` : null ); const [isSubmitting, setIsSubmitting] = useState(false); const [showConfirmModal, setShowConfirmModal] = useState(false); const fileInputRef = useRef(null); // 处理loader加载数据的时候的错误 useEffect(() => { if (error) { toastService.error(error); } }, [error]); // 处理logo文件选择 const handleLogoChange = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (file) { // 验证文件类型 if (!file.type.startsWith('image/')) { toastService.error('请选择图片文件'); return; } // 验证文件大小(限制5MB) if (file.size > 5 * 1024 * 1024) { toastService.error('图片大小不能超过5MB'); return; } setLogoFile(file); // 生成预览 const reader = new FileReader(); reader.onload = (event) => { setLogoPreview(event.target?.result as string); }; reader.readAsDataURL(file); } }; // 处理地区选择 const handleAreaToggle = (area: string) => { setSelectedAreas(prev => { if (prev.includes(area)) { return prev.filter(a => a !== area); } else { return [...prev, area]; } }); }; // 验证表单 const validateForm = () => { if (!name.trim()) { toastService.error('请输入模块名称'); return false; } if (selectedAreas.length === 0) { toastService.error('请至少选择一个适用地区'); return false; } return true; }; // 上传logo图片 const uploadLogo = async (): Promise => { if (!logoFile) return module?.path || null; try { const formData = new FormData(); formData.append('file', logoFile); formData.append('folder', 'entryModule'); const response = await fetch(`${API_BASE_URL}/admin/upload`, { method: 'POST', headers: { 'Authorization': `Bearer ${frontendJWT}` }, body: formData }); if (!response.ok) { throw new Error('图片上传失败'); } const result = await response.json(); console.log('图片上传结果:', result); // 根据后端返回的数据结构提取路径 if (result.data?.path) { return result.data.path; } else if (result.path) { return result.path; } else { throw new Error('未获取到图片路径'); } } catch (error) { console.error('上传logo失败:', error); throw error; } }; // 处理表单提交 const handleSubmit = async () => { if (!validateForm()) return; setIsSubmitting(true); try { // 上传logo let logoPath = module?.path || null; if (logoFile) { logoPath = await uploadLogo(); } const moduleData = { name: name.trim(), description: description.trim() || undefined, path: logoPath, areas: selectedAreas }; let result; if (isEditMode) { result = await updateEntryModule(parseInt(id!), moduleData, frontendJWT); } else { result = await createEntryModule(moduleData, frontendJWT); } if (result.error) { toastService.error(result.error); return; } toastService.success(isEditMode ? '更新成功!' : '创建成功!'); setTimeout(() => { navigate('/entry-modules'); }, 1000); } catch (error) { console.error('提交失败:', error); toastService.error(error instanceof Error ? error.message : '操作失败,请重试'); } finally { setIsSubmitting(false); } }; // 处理取消 const handleCancel = () => { setShowConfirmModal(true); }; // 确认取消 const confirmCancel = () => { navigate('/entry-modules'); }; return (
{/* 页面头部 */}

{isEditMode ? '编辑入口模块' : '新建入口模块'}

{isEditMode ? '修改入口模块信息' : '创建新的入口模块'}

{/* 表单内容 */}
{/* 模块名称 */}
setName(e.target.value)} placeholder="请输入模块名称,如:合同管理" maxLength={255} className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" />
{/* 描述 */}