// ============================================================ // StoragePathSetting — 存储路径设置区块 // // 个人版:仅"大模型产物存储仓库路径" // 企业版:额外"团队创作存储仓库路径" // ============================================================ import { useState, useCallback } from 'react'; import { Card, Button, Input, Typography, Space, App } from 'antd'; import { FolderOpenOutlined, DeleteOutlined, EditOutlined } from '@ant-design/icons'; import type { Edition } from '@shared/types'; import { useSettings } from '@/components/providers/SettingsProvider'; import { hasIpc, safeIpcInvoke } from '@/utils/ipc'; import { BIDIRECTIONAL } from '@shared/constants/ipc-channels'; const { Text, Paragraph } = Typography; interface StoragePathSettingProps { edition: Edition; } /** 单行路径选择器 */ function PathRow({ label, path, onChange, onClear, }: { label: string; path: string; onChange: (path: string) => void; onClear: () => void; }) { const [editing, setEditing] = useState(false); const [inputValue, setInputValue] = useState(path); const { message } = App.useApp(); const handleSelectFolder = useCallback(async () => { if (!hasIpc()) { // 非 Electron 环境 → 切换为手动输入模式 setInputValue(path); setEditing(true); return; } try { const result = (await safeIpcInvoke(BIDIRECTIONAL.FILE_DIALOG, { title: label, defaultPath: path || undefined, properties: ['openDirectory'], })) as { canceled: boolean; filePaths: string[] } | undefined; if (!result || result.canceled || result.filePaths.length === 0) return; const selectedPath = result.filePaths[0]; onChange(selectedPath); message.success('路径已更新'); } catch { message.error('选择文件夹失败'); } }, [label, path, onChange, message]); const handleSaveInput = useCallback(() => { onChange(inputValue.trim()); setEditing(false); if (inputValue.trim()) { message.success('路径已更新'); } }, [inputValue, onChange, message]); const handleCancelEdit = useCallback(() => { setInputValue(path); setEditing(false); }, [path]); return (