Explorar el Código

refine docker

welin hace 3 meses
padre
commit
00870caef6

+ 1 - 1
.env.local

@@ -1,4 +1,4 @@
 # .env.local
 # 如果你的后端在本地运行,通常是 http://127.0.0.1:8000
 # 如果已经部署到服务器,填写服务器地址,如 https://api.visafly.com
-NEXT_PUBLIC_API_URL=https://visafly.top
+NEXT_PUBLIC_API_URL=http://localhost:8888

+ 9 - 7
src/components/admin/remote-server/ConfigManager.tsx

@@ -18,10 +18,12 @@ interface ServerConfig {
 
 export default function ConfigManager({ 
   serverConfig,
-  serverId 
+  serverId,
+  projectPath
 }: { 
   serverConfig: ServerConfig;
   serverId?: string;
+  projectPath?: string;
 }) {
   const [configFile, setConfigFile] = useState<string>('config/troov_config.json');
   const [configData, setConfigData] = useState<any>(null);
@@ -66,8 +68,8 @@ export default function ConfigManager({
     try {
       const url = serverId ? '/api/remote/server/config/read' : '/api/remote/config/read';
       const payload = serverId 
-        ? { server_id: serverId, config_file: configFile }
-        : { ...serverConfig, config_file: configFile };
+        ? { server_id: serverId, config_file: configFile, project_path: projectPath }
+        : { ...serverConfig, config_file: configFile, project_path: projectPath };
 
       const response = await api.post(url, payload);
       if (response.data.code === 0) {
@@ -107,14 +109,14 @@ export default function ConfigManager({
           if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
              const url = serverId ? '/api/remote/server/config/update' : '/api/remote/config/update';
              const payload = serverId 
-              ? { server_id: serverId, config_file: configFile, key_path: fullPath, value: value }
-              : { ...serverConfig, config_file: configFile, key_path: fullPath, value: value };
+              ? { server_id: serverId, config_file: configFile, key_path: fullPath, value: value, project_path: projectPath }
+              : { ...serverConfig, config_file: configFile, key_path: fullPath, value: value, project_path: projectPath };
              updatePromises.push(api.post(url, payload));
           } else {
             const url = serverId ? '/api/remote/server/config/update' : '/api/remote/config/update';
             const payload = serverId 
-              ? { server_id: serverId, config_file: configFile, key_path: fullPath, value: value }
-              : { ...serverConfig, config_file: configFile, key_path: fullPath, value: value };
+              ? { server_id: serverId, config_file: configFile, key_path: fullPath, value: value, project_path: projectPath }
+              : { ...serverConfig, config_file: configFile, key_path: fullPath, value: value, project_path: projectPath };
             updatePromises.push(api.post(url, payload));
           }
         }

+ 10 - 8
src/components/admin/remote-server/DockerControl.tsx

@@ -21,10 +21,12 @@ interface ContainerStatus {
 
 export default function DockerControl({ 
   serverConfig, 
-  serverId 
+  serverId,
+  projectPath
 }: { 
   serverConfig: ServerConfig;
   serverId?: string;
+  projectPath?: string;
 }) {
   const [containers, setContainers] = useState<Record<string, ContainerStatus>>({});
   const [loading, setLoading] = useState(false);
@@ -38,7 +40,7 @@ export default function DockerControl({
     setError(null);
     try {
       const url = serverId ? '/api/remote/server/docker/status' : '/api/remote/docker/status';
-      const payload = serverId ? { server_id: serverId } : serverConfig;
+      const payload = serverId ? { server_id: serverId, project_path: projectPath } : { ...serverConfig, project_path: projectPath };
       const response = await api.post(url, payload);
       if (response.data.code === 0) {
         setContainers(response.data.data.containers || {});
@@ -54,7 +56,7 @@ export default function DockerControl({
 
   useEffect(() => {
     fetchStatus();
-  }, [serverId]);
+  }, [serverId, projectPath]);
 
   const handleDockerAction = async (action: 'start' | 'stop' | 'restart', containerName: string) => {
     setLoading(true);
@@ -62,8 +64,8 @@ export default function DockerControl({
     try {
       const url = serverId ? `/api/remote/server/docker/${action}` : `/api/remote/docker/${action}`;
       const payload = serverId 
-        ? { server_id: serverId, container_name: containerName }
-        : { ...serverConfig, container_name: containerName };
+        ? { server_id: serverId, container_name: containerName, project_path: projectPath }
+        : { ...serverConfig, container_name: containerName, project_path: projectPath };
         
       const response = await api.post(url, payload);
       if (response.data.code === 0) {
@@ -84,7 +86,7 @@ export default function DockerControl({
     setError(null);
     try {
       const url = serverId ? `/api/remote/server/docker/${action}` : `/api/remote/docker/${action}`;
-      const payload = serverId ? { server_id: serverId } : serverConfig;
+      const payload = serverId ? { server_id: serverId, project_path: projectPath } : { ...serverConfig, project_path: projectPath };
       const response = await api.post(url, payload);
       if (response.data.code === 0) {
         alert('操作成功');
@@ -105,8 +107,8 @@ export default function DockerControl({
     try {
       const url = serverId ? '/api/remote/server/docker/logs' : '/api/remote/docker/logs';
       const payload = serverId 
-        ? { server_id: serverId, container_name: containerName, lines: logsLines, follow: false }
-        : { ...serverConfig, container_name: containerName, lines: logsLines, follow: false };
+        ? { server_id: serverId, container_name: containerName, lines: logsLines, follow: false, project_path: projectPath }
+        : { ...serverConfig, container_name: containerName, lines: logsLines, follow: false, project_path: projectPath };
 
       const response = await api.post(url, payload);
       if (response.data.code === 0) {

+ 8 - 4
src/components/admin/remote-server/LogViewer.tsx

@@ -15,10 +15,12 @@ interface ServerConfig {
 
 export default function LogViewer({ 
   serverConfig,
-  serverId 
+  serverId,
+  projectPath
 }: { 
   serverConfig: ServerConfig;
   serverId?: string;
+  projectPath?: string;
 }) {
   const [logFiles, setLogFiles] = useState<string[]>([]);
   const [selectedLog, setSelectedLog] = useState<string>('');
@@ -34,7 +36,7 @@ export default function LogViewer({
     setError(null);
     try {
       const url = serverId ? '/api/remote/server/log/list' : '/api/remote/log/list';
-      const payload = serverId ? { server_id: serverId } : serverConfig;
+      const payload = serverId ? { server_id: serverId, project_path: projectPath } : { ...serverConfig, project_path: projectPath };
       const response = await api.post(url, payload);
       if (response.data.code === 0) {
         setLogFiles(response.data.data.log_files || []);
@@ -61,7 +63,8 @@ export default function LogViewer({
             log_file: selectedLog,
             lines: full ? 100 : lines,
             from_head: fromHead,
-            full: full
+            full: full,
+            project_path: projectPath
           }
         : {
             ...serverConfig,
@@ -69,6 +72,7 @@ export default function LogViewer({
             lines: full ? 100 : lines,
             from_head: fromHead,
             full: full,
+            project_path: projectPath,
           };
 
       const response = await api.post(url, payload);
@@ -86,7 +90,7 @@ export default function LogViewer({
 
   useEffect(() => {
     fetchLogList();
-  }, [serverId]);
+  }, [serverId, projectPath]);
 
   useEffect(() => {
     if (selectedLog) {

+ 73 - 39
src/components/admin/remote-server/RemoteServerControl.tsx

@@ -27,6 +27,7 @@ export default function RemoteServerControl() {
   const [usePreConfigured, setUsePreConfigured] = useState(true);
   const [preConfiguredServers, setPreConfiguredServers] = useState<PreConfiguredServer[]>([]);
   const [selectedServerId, setSelectedServerId] = useState<string>('');
+  const [selectedPath, setSelectedPath] = useState<string>('/root/troov-asyncio');
   const [serverConfig, setServerConfig] = useState<ServerConfig>({
     host: '',
     port: 22,
@@ -66,14 +67,20 @@ export default function RemoteServerControl() {
           setConnecting(false);
           return;
         }
-        response = await api.post('/api/remote/server/docker/status', { server_id: selectedServerId });
+        response = await api.post('/api/remote/server/docker/status', { 
+          server_id: selectedServerId,
+          project_path: selectedPath
+        });
       } else {
         if (!serverConfig.host || !serverConfig.username) {
           setConnectionError('请填写服务器地址和用户名');
           setConnecting(false);
           return;
         }
-        response = await api.post('/api/remote/docker/status', serverConfig);
+        response = await api.post('/api/remote/docker/status', {
+          ...serverConfig,
+          project_path: selectedPath
+        });
       }
       
       if (response.data.code === 0) {
@@ -144,53 +151,77 @@ export default function RemoteServerControl() {
         
         {/* 卡片内容 */}
         <div className="p-4 md:p-6 space-y-5">
-          {usePreConfigured ? (
-            <div>
-              <label className="block text-xs font-bold text-slate-500 uppercase mb-2">选择目标服务器</label>
+          <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
+            {usePreConfigured ? (
+              <div className="space-y-1">
+                <label className="block text-xs font-bold text-slate-500 uppercase mb-2">选择目标服务器</label>
+                <div className="relative">
+                  <select
+                    value={selectedServerId}
+                    onChange={(e) => setSelectedServerId(e.target.value)}
+                    className="w-full pl-4 pr-10 py-3 border border-slate-300 rounded-xl appearance-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none text-sm bg-white"
+                    disabled={isConnected}
+                  >
+                    <option value="">-- 请选择服务器 --</option>
+                    {preConfiguredServers.map((server) => (
+                      <option key={server.id} value={server.id}>
+                        {server.name} ({server.host})
+                      </option>
+                    ))}
+                  </select>
+                  <div className="absolute right-3 top-3.5 text-slate-400 pointer-events-none">
+                    <Search size={16} />
+                  </div>
+                </div>
+              </div>
+            ) : (
+              // 手动输入模式:移动端单列,桌面端双列
+              <>
+                <div className="space-y-1">
+                  <label className="text-xs font-bold text-slate-500">IP 地址</label>
+                  <input
+                    type="text"
+                    value={serverConfig.host}
+                    onChange={(e) => setServerConfig({ ...serverConfig, host: e.target.value })}
+                    placeholder="192.168.1.100"
+                    className="w-full px-3 py-2.5 border border-slate-300 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 outline-none"
+                    disabled={isConnected}
+                  />
+                </div>
+                <div className="space-y-1">
+                  <label className="text-xs font-bold text-slate-500">端口</label>
+                  <input
+                    type="number"
+                    value={serverConfig.port}
+                    onChange={(e) => setServerConfig({ ...serverConfig, port: parseInt(e.target.value) || 22 })}
+                    className="w-full px-3 py-2.5 border border-slate-300 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 outline-none"
+                    disabled={isConnected}
+                  />
+                </div>
+              </>
+            )}
+
+            <div className="space-y-1">
+              <label className="block text-xs font-bold text-slate-500 uppercase mb-2">项目路径</label>
               <div className="relative">
                 <select
-                  value={selectedServerId}
-                  onChange={(e) => setSelectedServerId(e.target.value)}
+                  value={selectedPath}
+                  onChange={(e) => setSelectedPath(e.target.value)}
                   className="w-full pl-4 pr-10 py-3 border border-slate-300 rounded-xl appearance-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500 outline-none text-sm bg-white"
                   disabled={isConnected}
                 >
-                  <option value="">-- 请选择服务器 --</option>
-                  {preConfiguredServers.map((server) => (
-                    <option key={server.id} value={server.id}>
-                      {server.name} ({server.host})
-                    </option>
-                  ))}
+                  <option value="/root/troov-asyncio">默认项目 (/root/troov-asyncio)</option>
+                  <option value="/root/germany_visa">德国签证 (/root/germany_visa)</option>
                 </select>
                 <div className="absolute right-3 top-3.5 text-slate-400 pointer-events-none">
-                  <Search size={16} />
+                  <Settings size={16} />
                 </div>
               </div>
             </div>
-          ) : (
-            // 手动输入模式:移动端单列,桌面端双列
-            <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
-              <div className="space-y-1">
-                <label className="text-xs font-bold text-slate-500">IP 地址</label>
-                <input
-                  type="text"
-                  value={serverConfig.host}
-                  onChange={(e) => setServerConfig({ ...serverConfig, host: e.target.value })}
-                  placeholder="192.168.1.100"
-                  className="w-full px-3 py-2.5 border border-slate-300 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 outline-none"
-                  disabled={isConnected}
-                />
-              </div>
-              <div className="space-y-1">
-                <label className="text-xs font-bold text-slate-500">端口</label>
-                <input
-                  type="number"
-                  value={serverConfig.port}
-                  onChange={(e) => setServerConfig({ ...serverConfig, port: parseInt(e.target.value) || 22 })}
-                  className="w-full px-3 py-2.5 border border-slate-300 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 outline-none"
-                  disabled={isConnected}
-                />
-              </div>
-              {/* 其他字段同理... */}
+          </div>
+
+          {!usePreConfigured && (
+            <div className="grid grid-cols-1 md:grid-cols-2 gap-4 pt-2 border-t border-slate-50">
               <div className="space-y-1">
                 <label className="text-xs font-bold text-slate-500">用户名</label>
                 <input
@@ -306,18 +337,21 @@ export default function RemoteServerControl() {
               <DockerControl 
                 serverConfig={serverConfig} 
                 serverId={usePreConfigured ? selectedServerId : undefined} 
+                projectPath={selectedPath}
               />
             )}
             {activeTab === 'logs' && (
               <LogViewer 
                 serverConfig={serverConfig} 
                 serverId={usePreConfigured ? selectedServerId : undefined} 
+                projectPath={selectedPath}
               />
             )}
             {activeTab === 'config' && (
               <ConfigManager 
                 serverConfig={serverConfig} 
                 serverId={usePreConfigured ? selectedServerId : undefined} 
+                projectPath={selectedPath}
               />
             )}
           </div>