import { json, type MetaFunction, type LoaderFunctionArgs, type ActionFunctionArgs } from "@remix-run/node"; import { useLoaderData, useSearchParams, useSubmit, Link } from "@remix-run/react"; import { useState } from "react"; import { Button } from "~/components/ui/Button"; import { Card } from "~/components/ui/Card"; import { FilterPanel, FilterSelect, SearchFilter } from "~/components/ui/FilterPanel"; import { Pagination } from "~/components/ui/Pagination"; import { Table } from "~/components/ui/Table"; import { Tag } from "~/components/ui/Tag"; import configListsStyles from "~/styles/pages/config-lists_index.css?url"; export const links = () => [ { rel: "stylesheet", href: configListsStyles } ]; export const meta: MetaFunction = () => { return [ { title: "系统配置管理 - 中国烟草AI合同及卷宗审核系统" }, { name: "description", content: "管理系统配置,包括数据库、文件存储、AI引擎等配置项" }, { name: "keywords", content: "系统配置,配置管理,中国烟草,参数设置" } ]; }; // 配置环境枚举 export enum ConfigEnvironment { DEV = 'dev', TEST = 'test', PROD = 'prod' } // 配置模块枚举 export enum ConfigModule { SYSTEM = 'system', AUTH = 'auth', FILE = 'file', AI = 'ai', NOTIFICATION = 'notification' } // 环境标签映射 export const ENVIRONMENT_LABELS: Record = { [ConfigEnvironment.DEV]: '开发环境', [ConfigEnvironment.TEST]: '测试环境', [ConfigEnvironment.PROD]: '生产环境' }; // 模块标签映射 export const MODULE_LABELS: Record = { [ConfigModule.SYSTEM]: '系统', [ConfigModule.AUTH]: '认证', [ConfigModule.FILE]: '文件', [ConfigModule.AI]: 'AI配置', [ConfigModule.NOTIFICATION]: '通知' }; // 配置数据类型 interface ConfigDataType { [key: string]: string | number | boolean | string[] | ConfigDataType | ConfigDataType[]; } // 配置项模型 interface ConfigItem { id: string; configName: string; module: ConfigModule; environment: ConfigEnvironment; isActive: boolean; configData: ConfigDataType; createdAt: string; updatedAt: string; } interface LoaderData { configs: ConfigItem[]; totalCount: number; currentPage: number; pageSize: number; totalPages: number; } export async function loader({ request }: LoaderFunctionArgs) { const url = new URL(request.url); const configName = url.searchParams.get("configName") || ""; const module = url.searchParams.get("module") || ""; const environment = url.searchParams.get("environment") || ""; const isActive = url.searchParams.get("isActive") || ""; const currentPage = parseInt(url.searchParams.get("page") || "1", 10); const pageSize = parseInt(url.searchParams.get("pageSize") || "10", 10); try { // 模拟数据,实际项目中应从API获取 const mockConfigs: ConfigItem[] = [ { id: "1", configName: "database_connection", module: ConfigModule.SYSTEM, environment: ConfigEnvironment.PROD, isActive: true, configData: { database: { host: "db.cluster.com", port: 5432, pool_size: 20, ssl: true }, cache: { ttl: 3600, max_entries: 1000 }, feature_flags: ["new_ui", "analytics_v2"] }, createdAt: "2023-07-10 10:15:23", updatedAt: "2023-07-15 14:30:26" }, { id: "2", configName: "text_extraction_ai", module: ConfigModule.AI, environment: ConfigEnvironment.TEST, isActive: true, configData: { model: "gpt-4", parameters: { temperature: 0.7, max_tokens: 2000 }, api_key: "sk-**********", timeout: 30 }, createdAt: "2023-07-12 08:45:12", updatedAt: "2023-07-14 09:15:33" }, { id: "3", configName: "notification_service", module: ConfigModule.NOTIFICATION, environment: ConfigEnvironment.DEV, isActive: false, configData: { email: { smtp_server: "smtp.example.com", port: 587, use_tls: true, sender: "noreply@example.com" }, sms: { provider: "aliyun", region: "cn-hangzhou", sign_name: "AI审核系统" } }, createdAt: "2023-07-05 13:20:45", updatedAt: "2023-07-10 16:45:19" }, { id: "4", configName: "file_storage", module: ConfigModule.FILE, environment: ConfigEnvironment.PROD, isActive: true, configData: { type: "oss", region: "cn-shanghai", bucket: "contracts-ai-review", access_control: "private", lifecycle_rules: [ { prefix: "temp/", ttl_days: 7 } ] }, createdAt: "2023-06-28 09:30:18", updatedAt: "2023-07-08 11:22:07" } ]; // 过滤数据 let filteredConfigs = [...mockConfigs]; if (configName) { filteredConfigs = filteredConfigs.filter(config => config.configName.toLowerCase().includes(configName.toLowerCase()) ); } if (module) { filteredConfigs = filteredConfigs.filter(config => config.module === module); } if (environment) { filteredConfigs = filteredConfigs.filter(config => config.environment === environment); } if (isActive) { const activeValue = isActive === 'true'; filteredConfigs = filteredConfigs.filter(config => config.isActive === activeValue); } // 计算分页信息 const totalCount = filteredConfigs.length; const totalPages = Math.ceil(totalCount / pageSize); // 分页截取 const startIndex = (currentPage - 1) * pageSize; const endIndex = startIndex + pageSize; const paginatedConfigs = filteredConfigs.slice(startIndex, endIndex); return json({ configs: paginatedConfigs, totalCount, currentPage, pageSize, totalPages }, { headers: { "Cache-Control": "max-age=60, s-maxage=180" } }); } catch (error) { console.error('加载配置列表失败:', error); throw new Response('加载配置列表失败', { status: 500 }); } } export async function action({ request }: ActionFunctionArgs) { const formData = await request.formData(); const _action = formData.get('_action'); const configId = formData.get('configId'); if (!configId) { return json({ success: false, error: "缺少配置ID" }, { status: 400 }); } try { if (_action === 'toggleStatus') { const isActive = formData.get('isActive') === 'true'; const newStatus = !isActive; // 实际项目中应调用API更新状态 console.log(`切换配置 ${configId} 状态为: ${newStatus}`); // 模拟API调用 // const response = await fetch(`/api/configs/${configId}/status`, { // method: 'PATCH', // headers: { // 'Content-Type': 'application/json', // }, // body: JSON.stringify({ isActive: newStatus }), // }); // if (!response.ok) { // throw new Error(`状态切换失败: ${response.status}`); // } return json({ success: true, newStatus }); } return json({ success: false, error: "未知操作" }, { status: 400 }); } catch (error) { console.error('操作配置失败:', error); return json({ success: false, error: "操作失败" }, { status: 500 }); } } export function ErrorBoundary() { return (

出错了

加载配置列表时发生错误。请稍后再试,或联系管理员。

); } export default function ConfigListsIndex() { const { configs, totalCount, currentPage, pageSize } = useLoaderData(); const [searchParams, setSearchParams] = useSearchParams(); const submit = useSubmit(); const [showDetailModal, setShowDetailModal] = useState(false); const [selectedConfig, setSelectedConfig] = useState(null); const handleFilterChange = (e: React.ChangeEvent) => { const { name, value } = e.target; const newParams = new URLSearchParams(searchParams); if (value) { newParams.set(name, value); } else { newParams.delete(name); } // 切换筛选条件时,重置到第一页 newParams.set('page', '1'); setSearchParams(newParams); }; const handleConfigNameSearch = (value: string) => { const newParams = new URLSearchParams(searchParams); if (value) { newParams.set('configName', value); } else { newParams.delete('configName'); } // 搜索时,重置到第一页 newParams.set('page', '1'); setSearchParams(newParams); }; const handleToggleStatus = (config: ConfigItem) => { if (window.confirm(`确定要${config.isActive ? '禁用' : '启用'}该配置吗?`)) { const formData = new FormData(); formData.append('_action', 'toggleStatus'); formData.append('configId', config.id); formData.append('isActive', String(config.isActive)); submit(formData, { method: 'post' }); } }; const handleViewDetail = (config: ConfigItem) => { setSelectedConfig(config); setShowDetailModal(true); }; const handlePageChange = (page: number) => { const newParams = new URLSearchParams(searchParams); newParams.set('page', page.toString()); setSearchParams(newParams); }; const handlePageSizeChange = (size: number) => { const newParams = new URLSearchParams(searchParams); newParams.set('pageSize', size.toString()); newParams.set('page', '1'); // 更改每页条数时,重置到第一页 setSearchParams(newParams); }; // 处理重置筛选 const handleReset = () => { setSearchParams(new URLSearchParams()); }; // 关闭详情模态框 const closeDetailModal = () => { setShowDetailModal(false); setSelectedConfig(null); }; // 定义表格列配置 const columns = [ { title: "配置名称", dataIndex: "configName" as keyof ConfigItem, key: "configName", width: "20%" }, { title: "所属模块", key: "module", width: "10%", render: (_: unknown, record: ConfigItem) => MODULE_LABELS[record.module] }, { title: "环境", key: "environment", width: "15%", render: (_: unknown, record: ConfigItem) => { const envClass = `env-tag env-tag-${record.environment}`; return ( {ENVIRONMENT_LABELS[record.environment]} ); } }, { title: "状态", key: "isActive", width: "15%", render: (_: unknown, record: ConfigItem) => ( {record.isActive ? '已启用' : '已禁用'} ) }, { title: "最后更新时间", dataIndex: "updatedAt" as keyof ConfigItem, key: "updatedAt", width: "15%" }, { title: "操作", key: "operation", width: "25%", render: (_: unknown, record: ConfigItem) => (
编辑
) } ]; // 生成环境选项 const environmentOptions = Object.entries(ENVIRONMENT_LABELS).map(([value, label]) => ({ value, label })); // 生成模块选项 const moduleOptions = Object.entries(MODULE_LABELS).map(([value, label]) => ({ value, label })); return (
{/* 页面头部 */}

系统配置管理

{/* 搜索区域 */} } noActionDivider={true} > {/* 表格区域 */} {/* 分页区域 */} {totalCount > 0 && ( )} {/* 配置详情模态框 */} {showDetailModal && selectedConfig && (

查看配置详情

配置名称
{selectedConfig.configName}
所属模块
{MODULE_LABELS[selectedConfig.module]}
环境
{ENVIRONMENT_LABELS[selectedConfig.environment]}
状态
{selectedConfig.isActive ? '已启用' : '已禁用'}
配置数据
                  {JSON.stringify(selectedConfig.configData, null, 2)}
                
创建时间
{selectedConfig.createdAt}
更新时间
{selectedConfig.updatedAt}
)} ); }