mirror of
https://github.com/GSManagerXZ/GameServerManager.git
synced 2026-06-05 20:39:44 +08:00
修复终端6
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { Modal, Input, Form, Upload, Button, message } from 'antd'
|
||||
import { InboxOutlined } from '@ant-design/icons'
|
||||
import type { UploadProps } from 'antd'
|
||||
import type { UploadProps, UploadFile } from 'antd'
|
||||
|
||||
const { Dragger } = Upload
|
||||
|
||||
@@ -156,25 +156,26 @@ export const UploadDialog: React.FC<UploadDialogProps> = ({
|
||||
onConfirm,
|
||||
onCancel
|
||||
}) => {
|
||||
const [fileList, setFileList] = useState<File[]>([])
|
||||
const [fileList, setFileList] = useState<UploadFile[]>([])
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const uploadProps: UploadProps = {
|
||||
name: 'files',
|
||||
multiple: true,
|
||||
beforeUpload: (file) => {
|
||||
setFileList(prev => [...prev, file])
|
||||
const uploadFile: UploadFile = {
|
||||
uid: file.name + file.size + Date.now(),
|
||||
name: file.name,
|
||||
status: 'done',
|
||||
originFileObj: file as any
|
||||
}
|
||||
setFileList(prev => [...prev, uploadFile])
|
||||
return false // 阻止自动上传
|
||||
},
|
||||
onRemove: (file) => {
|
||||
setFileList(prev => prev.filter(f => f.uid !== file.uid))
|
||||
},
|
||||
fileList: fileList.map(file => ({
|
||||
uid: file.name + file.size,
|
||||
name: file.name,
|
||||
status: 'done' as const,
|
||||
originFileObj: file
|
||||
}))
|
||||
fileList: fileList
|
||||
}
|
||||
|
||||
const handleOk = async () => {
|
||||
@@ -187,8 +188,10 @@ export const UploadDialog: React.FC<UploadDialogProps> = ({
|
||||
try {
|
||||
// 创建一个真正的FileList对象
|
||||
const dataTransfer = new DataTransfer()
|
||||
fileList.forEach(file => {
|
||||
dataTransfer.items.add(file)
|
||||
fileList.forEach(uploadFile => {
|
||||
if (uploadFile.originFileObj) {
|
||||
dataTransfer.items.add(uploadFile.originFileObj as File)
|
||||
}
|
||||
})
|
||||
const files = dataTransfer.files
|
||||
|
||||
|
||||
@@ -40,9 +40,9 @@ const TerminalPage: React.FC = () => {
|
||||
const [editingSessionId, setEditingSessionId] = useState<string | null>(null)
|
||||
const [editingName, setEditingName] = useState('')
|
||||
const [isFullscreen, setIsFullscreen] = useState(false)
|
||||
const [sessionsLoaded, setSessionsLoaded] = useState(false)
|
||||
|
||||
const terminalContainerRef = useRef<HTMLDivElement>(null)
|
||||
const isSessionsLoadedRef = useRef(false)
|
||||
const { addNotification } = useNotificationStore()
|
||||
|
||||
// 创建新的终端会话
|
||||
@@ -279,21 +279,18 @@ const TerminalPage: React.FC = () => {
|
||||
// 检查URL参数中的cwd,如果存在则创建终端
|
||||
useEffect(() => {
|
||||
const cwd = searchParams.get('cwd')
|
||||
if (cwd && sessions.length === 0 && isSessionsLoadedRef.current) {
|
||||
if (cwd && sessionsLoaded) {
|
||||
createTerminalSession(cwd)
|
||||
// 清除URL参数,避免重复创建
|
||||
const newSearchParams = new URLSearchParams(searchParams)
|
||||
newSearchParams.delete('cwd')
|
||||
setSearchParams(newSearchParams, { replace: true })
|
||||
}
|
||||
}, [searchParams, sessions.length, setSearchParams])
|
||||
}, [searchParams, sessions.length, setSearchParams, sessionsLoaded])
|
||||
|
||||
// 页面加载时获取现有终端会话
|
||||
useEffect(() => {
|
||||
const loadExistingSessions = async () => {
|
||||
if (isSessionsLoadedRef.current) return
|
||||
isSessionsLoadedRef.current = true
|
||||
|
||||
try {
|
||||
const response = await apiClient.getTerminalSessions()
|
||||
if (response.success && response.data) {
|
||||
@@ -404,6 +401,8 @@ const TerminalPage: React.FC = () => {
|
||||
title: '加载会话失败',
|
||||
message: '无法从服务器获取现有的终端会话。'
|
||||
})
|
||||
} finally {
|
||||
setSessionsLoaded(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ export const useFileStore = create<FileStore>((set, get) => ({
|
||||
try {
|
||||
await fileApiClient.createFile(newPath, content)
|
||||
await get().loadFiles()
|
||||
return newPath
|
||||
return true
|
||||
} catch (error: any) {
|
||||
set({ error: error.message || '创建文件失败' })
|
||||
return false
|
||||
|
||||
@@ -47,6 +47,10 @@ async function createPackage() {
|
||||
path.join(packageDir, '.env.example')
|
||||
)
|
||||
|
||||
// 创建uploads目录
|
||||
await fs.ensureDir(path.join(packageDir, 'server', 'uploads'))
|
||||
console.log('📁 创建uploads目录...')
|
||||
|
||||
console.log('📥 安装服务端生产依赖...')
|
||||
// 在打包的服务端目录中安装生产依赖
|
||||
try {
|
||||
|
||||
@@ -8,6 +8,7 @@ import dotenv from 'dotenv'
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
import winston from 'winston'
|
||||
import { promises as fs } from 'fs'
|
||||
|
||||
import { TerminalManager } from './modules/terminal/TerminalManager.js'
|
||||
import { GameManager } from './modules/game/GameManager.js'
|
||||
@@ -212,6 +213,15 @@ process.on('unhandledRejection', (reason, promise) => {
|
||||
// 启动服务器
|
||||
async function startServer() {
|
||||
try {
|
||||
// 确保uploads目录存在
|
||||
const uploadsDir = path.join(process.cwd(), 'uploads')
|
||||
try {
|
||||
await fs.access(uploadsDir)
|
||||
} catch {
|
||||
await fs.mkdir(uploadsDir, { recursive: true })
|
||||
logger.info(`创建uploads目录: ${uploadsDir}`)
|
||||
}
|
||||
|
||||
// 初始化管理器
|
||||
configManager = new ConfigManager(logger)
|
||||
authManager = new AuthManager(configManager, logger)
|
||||
|
||||
@@ -5,7 +5,7 @@ import winston from 'winston'
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
import os from 'os'
|
||||
import { TerminalSessionManager } from './TerminalSessionManager.js'
|
||||
import { TerminalSessionManager, PersistedTerminalSession } from './TerminalSessionManager.js'
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url)
|
||||
const __dirname = path.dirname(__filename)
|
||||
@@ -58,10 +58,10 @@ export class TerminalManager {
|
||||
const platform = os.platform()
|
||||
if (platform === 'win32') {
|
||||
this.ptyPath = path.resolve(__dirname, '../../../PTY/pty_win32_x64.exe')
|
||||
//this.ptyPath = path.resolve(__dirname, '../../PTY/pty_win32_x64.exe')
|
||||
// this.ptyPath = path.resolve(__dirname, '../../PTY/pty_win32_x64.exe')
|
||||
} else {
|
||||
this.ptyPath = path.resolve(__dirname, '../../../PTY/pty_linux_x64')
|
||||
//this.ptyPath = path.resolve(__dirname, '../../PTY/pty_linux_x64')
|
||||
// this.ptyPath = path.resolve(__dirname, '../../PTY/pty_linux_x64')
|
||||
}
|
||||
|
||||
this.logger.info(`终端管理器初始化完成,PTY路径: ${this.ptyPath}`)
|
||||
@@ -551,7 +551,7 @@ export class TerminalManager {
|
||||
/**
|
||||
* 获取保存的会话列表
|
||||
*/
|
||||
public getSavedSessions() {
|
||||
public getSavedSessions(): PersistedTerminalSession[] {
|
||||
return this.sessionManager.getSavedSessions()
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import path from 'path'
|
||||
import winston from 'winston'
|
||||
|
||||
// 终端会话持久化数据接口
|
||||
interface PersistedTerminalSession {
|
||||
export interface PersistedTerminalSession {
|
||||
id: string
|
||||
name: string
|
||||
workingDirectory: string
|
||||
|
||||
37
报错.txt
37
报错.txt
@@ -0,0 +1,37 @@
|
||||
src/components/FileDialogs.tsx:170:46 - error TS2339: Property 'uid' does not exist on type 'File'.
|
||||
|
||||
170 setFileList(prev => prev.filter(f => f.uid !== file.uid))
|
||||
~~~
|
||||
|
||||
src/components/FileDialogs.tsx:172:5 - error TS2322: Type '{ uid: string; name: string; status: "done"; originFileObj: File; }[]' is not assignable to type 'UploadFile<any>[]'.
|
||||
Type '{ uid: string; name: string; status: "done"; originFileObj: File; }' is not assignable to type 'UploadFile<any>'.
|
||||
Types of property 'originFileObj' are incompatible.
|
||||
Type 'File' is missing the following properties from type 'RcFile': lastModifiedDate, uid
|
||||
|
||||
172 fileList: fileList.map(file => ({
|
||||
~~~~~~~~
|
||||
|
||||
node_modules/antd/es/upload/interface.d.ts:72:5
|
||||
72 fileList?: Array<UploadFile<T>>;
|
||||
~~~~~~~~
|
||||
The expected type comes from property 'fileList' which is declared here on type 'UploadProps<any>'
|
||||
|
||||
src/stores/fileStore.ts:151:3 - error TS2322: Type '(name: string, content?: string) => Promise<string | false>' is not assignable to type '(name: string, content?: string) => Promise<boolean>'.
|
||||
Type 'Promise<string | false>' is not assignable to type 'Promise<boolean>'.
|
||||
Type 'string | false' is not assignable to type 'boolean'.
|
||||
Type 'string' is not assignable to type 'boolean'.
|
||||
|
||||
151 createFile: async (name: string, content: string = '') => {
|
||||
~~~~~~~~~~
|
||||
|
||||
src/stores/fileStore.ts:34:3
|
||||
34 createFile: (name: string, content?: string) => Promise<boolean>
|
||||
~~~~~~~~~~
|
||||
The expected type comes from property 'createFile' which is declared here on type 'FileStore'
|
||||
|
||||
|
||||
Found 3 errors in 2 files.
|
||||
|
||||
Errors Files
|
||||
2 src/components/FileDialogs.tsx:170
|
||||
1 src/stores/fileStore.ts:151
|
||||
Reference in New Issue
Block a user