@@ -80,7 +86,8 @@
diff --git a/src/locales/de.ts b/src/locales/de.ts
index 9d525da..cc53f9e 100644
--- a/src/locales/de.ts
+++ b/src/locales/de.ts
@@ -549,6 +549,8 @@ export default {
}
},
recycle: 'Recyceln',
+ harvestDarkMatter: 'Dunkle Materie ernten',
+ station: 'Stationieren',
transportResources: 'Ressourcen transportieren',
totalCargoCapacity: 'Gesamtladekapazität',
used: 'Verwendet',
@@ -1823,6 +1825,27 @@ export default {
reputationBonusDesc: 'Dein Verbündeter {npcName} spricht gut von dir zu {targetNpc}'
}
},
+ webdav: {
+ connectionSuccess: 'WebDAV-Verbindung erfolgreich',
+ connectionSuccessDirectoryCreated: 'WebDAV-Verbindung erfolgreich, Speicherverzeichnis erstellt',
+ authFailed: 'Authentifizierung fehlgeschlagen, bitte Benutzername und Passwort überprüfen',
+ directoryNotExist: 'Verzeichnis existiert nicht und konnte nicht erstellt werden',
+ networkError: 'Netzwerkfehler, bitte Serveradresse und Netzwerk überprüfen',
+ unknownError: 'Unbekannter Fehler',
+ uploadSuccess: 'Spielstand erfolgreich hochgeladen',
+ uploadFailed: 'Hochladen fehlgeschlagen',
+ downloadSuccess: 'Spielstand erfolgreich heruntergeladen',
+ downloadFailed: 'Herunterladen fehlgeschlagen',
+ noSaveFiles: 'Keine Spielstände auf dem Server',
+ fileListSuccess: 'Spielstandliste erfolgreich abgerufen',
+ fileListFailed: 'Abrufen der Spielstandliste fehlgeschlagen',
+ deleteSuccess: 'Spielstand erfolgreich gelöscht',
+ deleteFailed: 'Löschen fehlgeschlagen',
+ serverError: 'Serverfehler',
+ notConfigured: 'WebDAV nicht konfiguriert',
+ invalidUrl: 'Ungültige WebDAV-URL',
+ timeout: 'Verbindungszeitüberschreitung'
+ },
campaign: {
name: 'Kampagne',
description: 'Erkunde die mysteriöse Galaxie und entdecke antike Geheimnisse',
@@ -1849,6 +1872,8 @@ export default {
branchUnlocked: 'Neuer Storyzweig freigeschaltet!'
},
dialogue: {
+ title: 'Story-Dialog',
+ description: 'Kampagnen-Story-Dialoginhalt',
skip: 'Überspringen',
continue: 'Weiter',
finish: 'Beenden',
diff --git a/src/locales/en.ts b/src/locales/en.ts
index aca2ea4..62648e4 100644
--- a/src/locales/en.ts
+++ b/src/locales/en.ts
@@ -532,6 +532,8 @@ export default {
},
recycle: 'Recycle',
destroy: 'Planet Destruction',
+ harvestDarkMatter: 'Harvest Dark Matter',
+ station: 'Station',
transportResources: 'Transport Resources',
totalCargoCapacity: 'Total Cargo Capacity',
used: 'Used',
@@ -1781,6 +1783,8 @@ export default {
branchUnlocked: 'New story branch unlocked!'
},
dialogue: {
+ title: 'Story Dialogue',
+ description: 'Campaign story dialogue content',
skip: 'Skip',
continue: 'Continue',
finish: 'Finish',
@@ -2207,5 +2211,31 @@ export default {
reputationBonus: 'Reputation Bonus',
reputationBonusDesc: 'Your ally {npcName} speaks well of you to {targetNpc}'
}
+ },
+ webdav: {
+ // Connection
+ connectionSuccess: 'WebDAV connection successful',
+ connectionSuccessDirectoryCreated: 'WebDAV connection successful, save directory created',
+ authFailed: 'Authentication failed, please check username and password',
+ directoryNotExist: 'Directory does not exist and cannot be created',
+ connectionFailedHttp: 'Connection failed: HTTP {status}',
+ networkError: 'Network error, possibly CORS restriction. Try using a CORS-enabled WebDAV service or proxy.',
+ connectionError: 'Connection error: {error}',
+ // Upload
+ uploadSuccess: 'Upload successful',
+ noWritePermission: 'No write permission',
+ insufficientStorage: 'Insufficient storage space',
+ uploadFailedHttp: 'Upload failed: HTTP {status}',
+ uploadError: 'Upload error: {error}',
+ // Download
+ fileNotExist: 'File does not exist',
+ downloadFailedHttp: 'Download failed: HTTP {status}',
+ downloadError: 'Download error: {error}',
+ // List
+ listFailedHttp: 'Failed to get file list: HTTP {status}',
+ listError: 'Error getting file list: {error}',
+ // Delete
+ deleteFailedHttp: 'Delete failed: HTTP {status}',
+ deleteError: 'Delete error: {error}'
}
}
diff --git a/src/locales/es-LA.ts b/src/locales/es-LA.ts
index 9391954..6d802b1 100644
--- a/src/locales/es-LA.ts
+++ b/src/locales/es-LA.ts
@@ -538,6 +538,8 @@ export default {
},
recycle: 'Reciclar',
destroy: 'Destrucción Planetaria',
+ harvestDarkMatter: 'Recolectar Materia Oscura',
+ station: 'Estacionar',
transportResources: 'Transportar Recursos',
totalCargoCapacity: 'Capacidad de Carga Total',
used: 'Usado',
@@ -1785,6 +1787,8 @@ export default {
branchUnlocked: '¡Nueva rama de historia desbloqueada!'
},
dialogue: {
+ title: 'Diálogo de historia',
+ description: 'Contenido del diálogo de la campaña',
skip: 'Saltar',
continue: 'Continuar',
finish: 'Finalizar',
@@ -2215,5 +2219,26 @@ export default {
reputationBonus: 'Bonificación de Reputación',
reputationBonusDesc: 'Tu aliado {npcName} habla bien de ti ante {targetNpc}'
}
+ },
+ webdav: {
+ connectionSuccess: 'Conexión WebDAV exitosa',
+ connectionSuccessDirectoryCreated: 'Conexión WebDAV exitosa, directorio de guardado creado',
+ authFailed: 'Autenticación fallida, verifica el nombre de usuario y contraseña',
+ directoryNotExist: 'El directorio no existe y no se puede crear',
+ networkError: 'Error de red, verifica la dirección del servidor y la red',
+ unknownError: 'Error desconocido',
+ uploadSuccess: 'Guardado subido exitosamente',
+ uploadFailed: 'Error al subir',
+ downloadSuccess: 'Guardado descargado exitosamente',
+ downloadFailed: 'Error al descargar',
+ noSaveFiles: 'No hay archivos de guardado en el servidor',
+ fileListSuccess: 'Lista de guardados obtenida exitosamente',
+ fileListFailed: 'Error al obtener la lista de guardados',
+ deleteSuccess: 'Guardado eliminado exitosamente',
+ deleteFailed: 'Error al eliminar',
+ serverError: 'Error del servidor',
+ notConfigured: 'WebDAV no configurado',
+ invalidUrl: 'URL de WebDAV inválida',
+ timeout: 'Tiempo de conexión agotado'
}
}
diff --git a/src/locales/ja.ts b/src/locales/ja.ts
index cf7c0be..54a68ed 100644
--- a/src/locales/ja.ts
+++ b/src/locales/ja.ts
@@ -641,7 +641,9 @@ export default {
jumpGateSuccessMessage: '艦隊は{target}へ瞬時に転送されました',
jumpGateFailed: 'ジャンプゲート転送失敗',
jumpGateFailedMessage: 'ジャンプゲートの状態と艦隊構成を確認してください',
- destroy: '破壊'
+ destroy: '破壊',
+ harvestDarkMatter: 'ダークマター採取',
+ station: '駐留'
},
officersView: {
title: '士官',
@@ -1854,6 +1856,27 @@ export default {
reputationBonusDesc: '同盟の{npcName}が{targetNpc}にあなたのことを良く言っています'
}
},
+ webdav: {
+ connectionSuccess: 'WebDAV接続成功',
+ connectionSuccessDirectoryCreated: 'WebDAV接続成功、保存ディレクトリを作成しました',
+ authFailed: '認証失敗、ユーザー名とパスワードを確認してください',
+ directoryNotExist: 'ディレクトリが存在せず、作成できませんでした',
+ networkError: 'ネットワークエラー、サーバーアドレスとネットワークを確認してください',
+ unknownError: '不明なエラー',
+ uploadSuccess: 'セーブデータのアップロード成功',
+ uploadFailed: 'アップロード失敗',
+ downloadSuccess: 'セーブデータのダウンロード成功',
+ downloadFailed: 'ダウンロード失敗',
+ noSaveFiles: 'サーバーにセーブデータがありません',
+ fileListSuccess: 'セーブデータリストの取得成功',
+ fileListFailed: 'セーブデータリストの取得失敗',
+ deleteSuccess: 'セーブデータの削除成功',
+ deleteFailed: '削除失敗',
+ serverError: 'サーバーエラー',
+ notConfigured: 'WebDAVが設定されていません',
+ invalidUrl: '無効なWebDAV URL',
+ timeout: '接続タイムアウト'
+ },
campaign: {
name: 'キャンペーン',
description: '神秘的な銀河を探索し、古代の秘密を解き明かす',
@@ -1881,6 +1904,8 @@ export default {
branchUnlocked: '新しいストーリー分岐が解放されました!'
},
dialogue: {
+ title: 'ストーリー対話',
+ description: 'キャンペーンストーリーの対話内容',
skip: 'スキップ',
continue: '続ける',
finish: '完了',
diff --git a/src/locales/ko.ts b/src/locales/ko.ts
index c007952..0bbb3e8 100644
--- a/src/locales/ko.ts
+++ b/src/locales/ko.ts
@@ -532,6 +532,8 @@ export default {
},
recycle: '회수',
destroy: '행성 파괴',
+ harvestDarkMatter: '암흑 물질 수확',
+ station: '주둔',
transportResources: '자원 수송',
totalCargoCapacity: '총 적재량',
used: '사용됨',
@@ -1795,6 +1797,27 @@ export default {
reputationBonusDesc: '동맹 {npcName}이(가) {targetNpc}에게 당신을 좋게 말하고 있습니다'
}
},
+ webdav: {
+ connectionSuccess: 'WebDAV 연결 성공',
+ connectionSuccessDirectoryCreated: 'WebDAV 연결 성공, 저장 디렉토리 생성됨',
+ authFailed: '인증 실패, 사용자 이름과 비밀번호를 확인하세요',
+ directoryNotExist: '디렉토리가 존재하지 않으며 생성할 수 없습니다',
+ networkError: '네트워크 오류, 서버 주소와 네트워크를 확인하세요',
+ unknownError: '알 수 없는 오류',
+ uploadSuccess: '저장 파일 업로드 성공',
+ uploadFailed: '업로드 실패',
+ downloadSuccess: '저장 파일 다운로드 성공',
+ downloadFailed: '다운로드 실패',
+ noSaveFiles: '서버에 저장 파일이 없습니다',
+ fileListSuccess: '저장 파일 목록 가져오기 성공',
+ fileListFailed: '저장 파일 목록 가져오기 실패',
+ deleteSuccess: '저장 파일 삭제 성공',
+ deleteFailed: '삭제 실패',
+ serverError: '서버 오류',
+ notConfigured: 'WebDAV가 구성되지 않았습니다',
+ invalidUrl: '잘못된 WebDAV URL',
+ timeout: '연결 시간 초과'
+ },
campaign: {
name: '캠페인',
description: '신비로운 은하를 탐험하고 고대의 비밀을 밝혀내세요',
@@ -1821,6 +1844,8 @@ export default {
branchUnlocked: '새로운 스토리 분기가 해금되었습니다!'
},
dialogue: {
+ title: '스토리 대화',
+ description: '캠페인 스토리 대화 내용',
skip: '건너뛰기',
continue: '계속',
finish: '완료',
diff --git a/src/locales/ru.ts b/src/locales/ru.ts
index 2cf4892..3c2f2ea 100644
--- a/src/locales/ru.ts
+++ b/src/locales/ru.ts
@@ -622,7 +622,9 @@ export default {
jumpGateSuccessMessage: 'Флот мгновенно переброшен к {target}',
jumpGateFailed: 'Переброска через ворота не удалась',
jumpGateFailedMessage: 'Проверьте состояние ворот и конфигурацию флота',
- destroy: 'Уничтожение'
+ destroy: 'Уничтожение',
+ harvestDarkMatter: 'Сбор тёмной материи',
+ station: 'Расположение'
},
officersView: {
title: 'Офицеры',
@@ -1851,6 +1853,27 @@ export default {
reputationBonusDesc: 'Ваш союзник {npcName} хорошо отзывается о вас {targetNpc}'
}
},
+ webdav: {
+ connectionSuccess: 'Подключение WebDAV успешно',
+ connectionSuccessDirectoryCreated: 'Подключение WebDAV успешно, каталог сохранений создан',
+ authFailed: 'Ошибка аутентификации, проверьте имя пользователя и пароль',
+ directoryNotExist: 'Каталог не существует и не может быть создан',
+ networkError: 'Ошибка сети, проверьте адрес сервера и сеть',
+ unknownError: 'Неизвестная ошибка',
+ uploadSuccess: 'Сохранение успешно загружено',
+ uploadFailed: 'Ошибка загрузки',
+ downloadSuccess: 'Сохранение успешно скачано',
+ downloadFailed: 'Ошибка скачивания',
+ noSaveFiles: 'На сервере нет сохранений',
+ fileListSuccess: 'Список сохранений получен',
+ fileListFailed: 'Ошибка получения списка сохранений',
+ deleteSuccess: 'Сохранение успешно удалено',
+ deleteFailed: 'Ошибка удаления',
+ serverError: 'Ошибка сервера',
+ notConfigured: 'WebDAV не настроен',
+ invalidUrl: 'Недействительный URL WebDAV',
+ timeout: 'Превышено время ожидания'
+ },
campaign: {
name: 'Кампания',
description: 'Исследуйте загадочную галактику и раскройте древние тайны',
@@ -1878,6 +1901,8 @@ export default {
branchUnlocked: 'Новая сюжетная ветка разблокирована!'
},
dialogue: {
+ title: 'Сюжетный диалог',
+ description: 'Содержание сюжетного диалога кампании',
skip: 'Пропустить',
continue: 'Продолжить',
finish: 'Завершить',
diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts
index eee41cd..926671b 100644
--- a/src/locales/zh-CN.ts
+++ b/src/locales/zh-CN.ts
@@ -32,7 +32,8 @@ export default {
exitConfirmTitle: '退出游戏',
exitConfirmMessage: '确定要退出游戏吗?游戏进度会自动保存。',
points: '积分',
- retry: '重试'
+ retry: '重试',
+ playerName: '玩家名称'
},
errors: {
requirementsNotMet: '不满足前置条件',
@@ -525,6 +526,8 @@ export default {
},
recycle: '回收',
destroy: '行星毁灭',
+ harvestDarkMatter: '暗物质采集',
+ station: '驻守协防',
transportResources: '运输资源',
totalCargoCapacity: '总载货量',
used: '已用',
@@ -1796,6 +1799,8 @@ export default {
branchUnlocked: '新的故事分支已解锁!'
},
dialogue: {
+ title: '剧情对话',
+ description: '战役剧情对话内容',
skip: '跳过',
continue: '继续',
finish: '完成',
@@ -2106,5 +2111,31 @@ export default {
epilogue_1: '银河系广阔无垠,还有无数秘密等待你去发现...'
}
}
+ },
+ webdav: {
+ // 连接相关
+ connectionSuccess: 'WebDAV 连接成功',
+ connectionSuccessDirectoryCreated: 'WebDAV 连接成功,已创建存档目录',
+ authFailed: '认证失败,请检查用户名和密码',
+ directoryNotExist: '目录不存在且无法创建',
+ connectionFailedHttp: '连接失败: HTTP {status}',
+ networkError: '网络错误,可能是 CORS 限制。建议使用支持 CORS 的 WebDAV 服务或通过代理访问。',
+ connectionError: '连接错误: {error}',
+ // 上传相关
+ uploadSuccess: '上传成功',
+ noWritePermission: '没有写入权限',
+ insufficientStorage: '存储空间不足',
+ uploadFailedHttp: '上传失败: HTTP {status}',
+ uploadError: '上传错误: {error}',
+ // 下载相关
+ fileNotExist: '文件不存在',
+ downloadFailedHttp: '下载失败: HTTP {status}',
+ downloadError: '下载错误: {error}',
+ // 列表相关
+ listFailedHttp: '获取文件列表失败: HTTP {status}',
+ listError: '获取文件列表错误: {error}',
+ // 删除相关
+ deleteFailedHttp: '删除失败: HTTP {status}',
+ deleteError: '删除错误: {error}'
}
}
diff --git a/src/locales/zh-TW.ts b/src/locales/zh-TW.ts
index b82f6c1..e493462 100644
--- a/src/locales/zh-TW.ts
+++ b/src/locales/zh-TW.ts
@@ -542,6 +542,8 @@ export default {
},
recycle: '回收',
destroy: '行星毀滅',
+ harvestDarkMatter: '暗物質採集',
+ station: '駐守協防',
transportResources: '運輸資源',
totalCargoCapacity: '總載貨量',
used: '已用',
@@ -1945,6 +1947,27 @@ export default {
reputationBonusDesc: '你的盟友{npcName}向{targetNpc}說了你的好話'
}
},
+ webdav: {
+ connectionSuccess: 'WebDAV 連線成功',
+ connectionSuccessDirectoryCreated: 'WebDAV 連線成功,已建立存檔目錄',
+ authFailed: '認證失敗,請檢查使用者名稱和密碼',
+ directoryNotExist: '目錄不存在且無法建立',
+ networkError: '網路錯誤,請檢查伺服器位址和網路連線',
+ unknownError: '未知錯誤',
+ uploadSuccess: '存檔上傳成功',
+ uploadFailed: '上傳失敗',
+ downloadSuccess: '存檔下載成功',
+ downloadFailed: '下載失敗',
+ noSaveFiles: '伺服器上沒有存檔',
+ fileListSuccess: '取得存檔列表成功',
+ fileListFailed: '取得存檔列表失敗',
+ deleteSuccess: '存檔刪除成功',
+ deleteFailed: '刪除失敗',
+ serverError: '伺服器錯誤',
+ notConfigured: 'WebDAV 未設定',
+ invalidUrl: '無效的 WebDAV URL',
+ timeout: '連線逾時'
+ },
campaign: {
name: '戰役',
description: '探索神秘的銀河系,揭開古代文明的秘密',
@@ -1972,6 +1995,8 @@ export default {
branchUnlocked: '新的故事分支已解鎖!'
},
dialogue: {
+ title: '劇情對話',
+ description: '戰役劇情對話內容',
skip: '跳過',
continue: '繼續',
finish: '完成',
diff --git a/src/services/webdavService.ts b/src/services/webdavService.ts
index 028a453..7e87fef 100644
--- a/src/services/webdavService.ts
+++ b/src/services/webdavService.ts
@@ -4,10 +4,10 @@
*/
export interface WebDAVConfig {
- serverUrl: string // WebDAV 服务器地址,如 https://dav.jianguoyun.com/dav/
+ serverUrl: string // WebDAV 服务器地址
username: string // 用户名
password: string // 密码或应用专用密码
- basePath: string // 存档存放路径,如 /ogame-saves/
+ basePath: string // 存档存放路径
}
export interface WebDAVFile {
@@ -18,6 +18,49 @@ export interface WebDAVFile {
isDirectory: boolean
}
+// WebDAV 消息 key(用于 i18n)
+export const WebDAVMessageKey = {
+ // 连接相关
+ connectionSuccess: 'webdav.connectionSuccess',
+ connectionSuccessDirectoryCreated: 'webdav.connectionSuccessDirectoryCreated',
+ authFailed: 'webdav.authFailed',
+ directoryNotExist: 'webdav.directoryNotExist',
+ connectionFailedHttp: 'webdav.connectionFailedHttp',
+ networkError: 'webdav.networkError',
+ connectionError: 'webdav.connectionError',
+
+ // 上传相关
+ uploadSuccess: 'webdav.uploadSuccess',
+ noWritePermission: 'webdav.noWritePermission',
+ insufficientStorage: 'webdav.insufficientStorage',
+ uploadFailedHttp: 'webdav.uploadFailedHttp',
+ uploadError: 'webdav.uploadError',
+
+ // 下载相关
+ fileNotExist: 'webdav.fileNotExist',
+ downloadFailedHttp: 'webdav.downloadFailedHttp',
+ downloadError: 'webdav.downloadError',
+
+ // 列表相关
+ listFailedHttp: 'webdav.listFailedHttp',
+ listError: 'webdav.listError',
+
+ // 删除相关
+ deleteFailedHttp: 'webdav.deleteFailedHttp',
+ deleteError: 'webdav.deleteError'
+} as const
+
+export type WebDAVMessageKeyType = (typeof WebDAVMessageKey)[keyof typeof WebDAVMessageKey]
+
+export interface WebDAVResult {
+ success: boolean
+ messageKey: WebDAVMessageKeyType
+ messageParams?: Record
+ fileName?: string
+ data?: string
+ files?: WebDAVFile[]
+}
+
const STORAGE_KEY = 'ogame-webdav-config'
// 获取保存的 WebDAV 配置
@@ -66,7 +109,7 @@ const normalizePath = (serverUrl: string, basePath: string, fileName?: string):
}
// 测试 WebDAV 连接
-export const testWebDAVConnection = async (config: WebDAVConfig): Promise<{ success: boolean; message: string }> => {
+export const testWebDAVConnection = async (config: WebDAVConfig): Promise => {
try {
const url = normalizePath(config.serverUrl, config.basePath)
@@ -80,33 +123,30 @@ export const testWebDAVConnection = async (config: WebDAVConfig): Promise<{ succ
})
if (response.ok || response.status === 207) {
- return { success: true, message: 'WebDAV 连接成功' }
+ return { success: true, messageKey: WebDAVMessageKey.connectionSuccess }
}
if (response.status === 401) {
- return { success: false, message: '认证失败,请检查用户名和密码' }
+ return { success: false, messageKey: WebDAVMessageKey.authFailed }
}
if (response.status === 404) {
// 尝试创建目录
const createResult = await createDirectory(config, config.basePath)
if (createResult) {
- return { success: true, message: 'WebDAV 连接成功,已创建存档目录' }
+ return { success: true, messageKey: WebDAVMessageKey.connectionSuccessDirectoryCreated }
}
- return { success: false, message: '目录不存在且无法创建' }
+ return { success: false, messageKey: WebDAVMessageKey.directoryNotExist }
}
- return { success: false, message: `连接失败: HTTP ${response.status}` }
+ return { success: false, messageKey: WebDAVMessageKey.connectionFailedHttp, messageParams: { status: response.status } }
} catch (error) {
- const message = error instanceof Error ? error.message : String(error)
+ const errorMessage = error instanceof Error ? error.message : String(error)
// CORS 错误的处理
- if (message.includes('Failed to fetch') || message.includes('NetworkError')) {
- return {
- success: false,
- message: '网络错误,可能是 CORS 限制。建议使用支持 CORS 的 WebDAV 服务或通过代理访问。'
- }
+ if (errorMessage.includes('Failed to fetch') || errorMessage.includes('NetworkError')) {
+ return { success: false, messageKey: WebDAVMessageKey.networkError }
}
- return { success: false, message: `连接错误: ${message}` }
+ return { success: false, messageKey: WebDAVMessageKey.connectionError, messageParams: { error: errorMessage } }
}
}
@@ -130,11 +170,7 @@ const createDirectory = async (config: WebDAVConfig, path: string): Promise => {
+export const uploadToWebDAV = async (config: WebDAVConfig, data: string, fileName?: string): Promise => {
try {
// 生成带时间戳的文件名
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19)
@@ -151,25 +187,25 @@ export const uploadToWebDAV = async (
})
if (response.ok || response.status === 201 || response.status === 204) {
- return { success: true, message: '上传成功', fileName: actualFileName }
+ return { success: true, messageKey: WebDAVMessageKey.uploadSuccess, fileName: actualFileName }
}
if (response.status === 401) {
- return { success: false, message: '认证失败' }
+ return { success: false, messageKey: WebDAVMessageKey.authFailed }
}
if (response.status === 403) {
- return { success: false, message: '没有写入权限' }
+ return { success: false, messageKey: WebDAVMessageKey.noWritePermission }
}
if (response.status === 507) {
- return { success: false, message: '存储空间不足' }
+ return { success: false, messageKey: WebDAVMessageKey.insufficientStorage }
}
- return { success: false, message: `上传失败: HTTP ${response.status}` }
+ return { success: false, messageKey: WebDAVMessageKey.uploadFailedHttp, messageParams: { status: response.status } }
} catch (error) {
- const message = error instanceof Error ? error.message : String(error)
- return { success: false, message: `上传错误: ${message}` }
+ const errorMessage = error instanceof Error ? error.message : String(error)
+ return { success: false, messageKey: WebDAVMessageKey.uploadError, messageParams: { error: errorMessage } }
}
}
@@ -212,7 +248,7 @@ const parsePropfindResponse = (xml: string, _basePath: string): WebDAVFile[] =>
}
// 列出 WebDAV 目录中的存档文件
-export const listWebDAVFiles = async (config: WebDAVConfig): Promise<{ success: boolean; files?: WebDAVFile[]; message?: string }> => {
+export const listWebDAVFiles = async (config: WebDAVConfig): Promise => {
try {
const url = normalizePath(config.serverUrl, config.basePath)
@@ -227,29 +263,26 @@ export const listWebDAVFiles = async (config: WebDAVConfig): Promise<{ success:
if (!response.ok && response.status !== 207) {
if (response.status === 401) {
- return { success: false, message: '认证失败' }
+ return { success: false, messageKey: WebDAVMessageKey.authFailed }
}
if (response.status === 404) {
- return { success: false, message: '目录不存在' }
+ return { success: false, messageKey: WebDAVMessageKey.directoryNotExist }
}
- return { success: false, message: `获取文件列表失败: HTTP ${response.status}` }
+ return { success: false, messageKey: WebDAVMessageKey.listFailedHttp, messageParams: { status: response.status } }
}
const xml = await response.text()
const files = parsePropfindResponse(xml, config.basePath)
- return { success: true, files }
+ return { success: true, messageKey: WebDAVMessageKey.connectionSuccess, files }
} catch (error) {
- const message = error instanceof Error ? error.message : String(error)
- return { success: false, message: `获取文件列表错误: ${message}` }
+ const errorMessage = error instanceof Error ? error.message : String(error)
+ return { success: false, messageKey: WebDAVMessageKey.listError, messageParams: { error: errorMessage } }
}
}
// 从 WebDAV 下载存档
-export const downloadFromWebDAV = async (
- config: WebDAVConfig,
- fileName: string
-): Promise<{ success: boolean; data?: string; message?: string }> => {
+export const downloadFromWebDAV = async (config: WebDAVConfig, fileName: string): Promise => {
try {
const url = normalizePath(config.serverUrl, config.basePath, fileName)
@@ -262,27 +295,24 @@ export const downloadFromWebDAV = async (
if (!response.ok) {
if (response.status === 401) {
- return { success: false, message: '认证失败' }
+ return { success: false, messageKey: WebDAVMessageKey.authFailed }
}
if (response.status === 404) {
- return { success: false, message: '文件不存在' }
+ return { success: false, messageKey: WebDAVMessageKey.fileNotExist }
}
- return { success: false, message: `下载失败: HTTP ${response.status}` }
+ return { success: false, messageKey: WebDAVMessageKey.downloadFailedHttp, messageParams: { status: response.status } }
}
const data = await response.text()
- return { success: true, data }
+ return { success: true, messageKey: WebDAVMessageKey.connectionSuccess, data }
} catch (error) {
- const message = error instanceof Error ? error.message : String(error)
- return { success: false, message: `下载错误: ${message}` }
+ const errorMessage = error instanceof Error ? error.message : String(error)
+ return { success: false, messageKey: WebDAVMessageKey.downloadError, messageParams: { error: errorMessage } }
}
}
// 删除 WebDAV 文件
-export const deleteFromWebDAV = async (
- config: WebDAVConfig,
- fileName: string
-): Promise<{ success: boolean; message?: string }> => {
+export const deleteFromWebDAV = async (config: WebDAVConfig, fileName: string): Promise => {
try {
const url = normalizePath(config.serverUrl, config.basePath, fileName)
@@ -294,20 +324,20 @@ export const deleteFromWebDAV = async (
})
if (response.ok || response.status === 204) {
- return { success: true }
+ return { success: true, messageKey: WebDAVMessageKey.connectionSuccess }
}
if (response.status === 401) {
- return { success: false, message: '认证失败' }
+ return { success: false, messageKey: WebDAVMessageKey.authFailed }
}
if (response.status === 404) {
- return { success: true } // 文件不存在也视为删除成功
+ return { success: true, messageKey: WebDAVMessageKey.connectionSuccess } // 文件不存在也视为删除成功
}
- return { success: false, message: `删除失败: HTTP ${response.status}` }
+ return { success: false, messageKey: WebDAVMessageKey.deleteFailedHttp, messageParams: { status: response.status } }
} catch (error) {
- const message = error instanceof Error ? error.message : String(error)
- return { success: false, message: `删除错误: ${message}` }
+ const errorMessage = error instanceof Error ? error.message : String(error)
+ return { success: false, messageKey: WebDAVMessageKey.deleteError, messageParams: { error: errorMessage } }
}
}
diff --git a/src/views/DiplomacyView.vue b/src/views/DiplomacyView.vue
index 6663120..1a44377 100644
--- a/src/views/DiplomacyView.vue
+++ b/src/views/DiplomacyView.vue
@@ -181,133 +181,6 @@
-
-
-
-
-
-
- {{ t('npcBehavior.trade.title') }} & {{ t('npcBehavior.intel.title') }}
- {{ totalInteractionCount }}
-
-
-
-
-
-
-
-
- {{ t('npcBehavior.trade.title') }} ({{ activeTradeOffers.length }})
-
-
-
-
-
-
{{ getNpcName(offer.npcId) }}
-
- {{ t('npcBehavior.trade.offers') }}:
- {{ formatResources(offer.offeredResources) }}
-
-
- {{ t('npcBehavior.trade.requests') }}:
- {{ formatResources(offer.requestedResources) }}
-
-
- {{ t('npcBehavior.trade.expiresIn') }}: {{ formatTimeRemaining(offer.expiresAt) }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ t('npcBehavior.intel.title') }} ({{ unreadIntelReports.length }})
-
-
-
-
-
-
{{ t('npcBehavior.intel.from') }}: {{ getNpcName(intel.fromNpcId) }}
-
- {{ t('npcBehavior.intel.target') }}: {{ getNpcName(intel.targetNpcId) }}
-
-
- {{ t(`npcBehavior.intel.types.${intel.intelType}`) }}
-
-
- {{ t('npcBehavior.intel.fleetInfo') }}: {{ formatFleetInfo(intel.data.fleet) }}
-
-
- {{ t('npcBehavior.intel.resourceInfo') }}: {{ formatResources(intel.data.resources as Resources) }}
-
-
-
-
-
-
-
-
-
-
-
-
- {{ t('npcBehavior.jointAttack.title') }} ({{ activeJointAttackInvites.length }})
-
-
-
-
-
-
{{ t('npcBehavior.jointAttack.from') }}: {{ getNpcName(invite.fromNpcId) }}
-
- {{ t('npcBehavior.jointAttack.target') }}: {{ getNpcName(invite.targetNpcId) }}
-
-
- {{ t('npcBehavior.jointAttack.targetPlanet') }}: [{{ invite.targetPosition.galaxy }}:{{
- invite.targetPosition.system
- }}:{{ invite.targetPosition.position }}]
-
-
- {{ t('npcBehavior.jointAttack.lootShare') }}: {{ (invite.expectedLootRatio * 100).toFixed(0) }}%
-
-
- {{ t('npcBehavior.jointAttack.expiresIn') }}: {{ formatTimeRemaining(invite.expiresAt) }}
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ t('npcBehavior.trade.noOffers') }}
-
-
-
-
-
@@ -503,14 +376,11 @@
import { useGameStore } from '@/stores/gameStore'
import { useNPCStore } from '@/stores/npcStore'
import { useI18n } from '@/composables/useI18n'
- import { toast } from 'vue-sonner'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
- import { Card } from '@/components/ui/card'
import { Dialog, DialogDescription, DialogTitle } from '@/components/ui/dialog'
import ScrollableDialogContent from '@/components/ui/dialog/ScrollableDialogContent.vue'
- import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'
import {
FixedPagination,
Pagination,
@@ -523,7 +393,7 @@
import NpcRelationCard from '@/components/npc/NpcRelationCard.vue'
import NpcRelationRow from '@/components/npc/NpcRelationRow.vue'
import { RelationStatus } from '@/types/game'
- import type { DiplomaticRelation, TradeOffer, IntelReport, JointAttackInvite, Resources } from '@/types/game'
+ import type { DiplomaticRelation } from '@/types/game'
import * as npcBehaviorLogic from '@/logic/npcBehaviorLogic'
import {
Search,
@@ -533,11 +403,7 @@
Swords,
Activity,
LayoutGrid,
- List,
- Handshake,
- ChevronDown,
- ArrowLeftRight,
- Eye
+ List
} from 'lucide-vue-next'
import { Empty, EmptyContent, EmptyDescription } from '@/components/ui/empty'
@@ -548,9 +414,6 @@
const activeTab = ref('all')
- // NPC互动面板状态
- const interactionPanelOpen = ref(true)
-
// 视图模式: 'card' | 'list'
const viewMode = ref<'card' | 'list'>('list')
@@ -864,188 +727,6 @@
currentPage.value[activeTab.value] = val
}
})
-
- // ========== NPC互动面板相关 ==========
-
- // 获取当前时间戳
- const now = computed(() => Date.now())
-
- // 有效的贸易提议(未过期)
- const activeTradeOffers = computed(() => {
- return (gameStore.player.tradeOffers || []).filter(offer => offer.expiresAt > now.value)
- })
-
- // 未读的情报报告
- const unreadIntelReports = computed(() => {
- return (gameStore.player.intelReports || []).filter(report => !report.read)
- })
-
- // 有效的联合攻击邀请(未过期)
- const activeJointAttackInvites = computed(() => {
- return (gameStore.player.jointAttackInvites || []).filter(invite => invite.expiresAt > now.value)
- })
-
- // 是否有NPC互动数据
- const hasNpcInteractions = computed(() => {
- return (
- (gameStore.player.tradeOffers?.length || 0) > 0 ||
- (gameStore.player.intelReports?.length || 0) > 0 ||
- (gameStore.player.jointAttackInvites?.length || 0) > 0
- )
- })
-
- // 是否有有效的互动内容
- const hasActiveInteractions = computed(() => {
- return activeTradeOffers.value.length > 0 || unreadIntelReports.value.length > 0 || activeJointAttackInvites.value.length > 0
- })
-
- // 总互动数量(用于显示徽章)
- const totalInteractionCount = computed(() => {
- return activeTradeOffers.value.length + unreadIntelReports.value.length + activeJointAttackInvites.value.length
- })
-
- // 获取NPC名称
- const getNpcName = (npcId: string): string => {
- const npc = npcStore.npcs.find(n => n.id === npcId)
- return npc?.name || npcId
- }
-
- // 格式化资源显示
- // 格式化资源(兼容新旧格式)
- const formatResources = (resources: Resources | { type: string; amount: number }): string => {
- // 新格式:{ type: 'metal', amount: 1000 }
- if ('type' in resources && 'amount' in resources) {
- const typeLabels: Record = {
- metal: 'M',
- crystal: 'C',
- deuterium: 'D'
- }
- return `${Math.floor(resources.amount).toLocaleString()} ${typeLabels[resources.type] || resources.type}`
- }
- // 旧格式:{ metal: 1000, crystal: 0, deuterium: 0 }
- const parts: string[] = []
- if ((resources as Resources).metal > 0) parts.push(`${Math.floor((resources as Resources).metal).toLocaleString()} M`)
- if ((resources as Resources).crystal > 0) parts.push(`${Math.floor((resources as Resources).crystal).toLocaleString()} C`)
- if ((resources as Resources).deuterium > 0) parts.push(`${Math.floor((resources as Resources).deuterium).toLocaleString()} D`)
- return parts.join(' / ') || '-'
- }
-
- // 格式化舰队信息
- const formatFleetInfo = (fleetInfo: Record): string => {
- const parts: string[] = []
- for (const [shipType, count] of Object.entries(fleetInfo)) {
- if (count > 0) {
- parts.push(`${shipType}: ${count}`)
- }
- }
- return parts.join(', ') || '-'
- }
-
- // 格式化剩余时间
- const formatTimeRemaining = (expiresAt: number): string => {
- const remaining = expiresAt - now.value
- if (remaining <= 0) return t('npcBehavior.trade.expired')
-
- const minutes = Math.floor(remaining / 60000)
- const hours = Math.floor(minutes / 60)
- const mins = minutes % 60
-
- if (hours > 0) {
- return `${hours}h ${mins}m`
- }
- return `${mins}m`
- }
-
- // 检查是否可以接受贸易(兼容新格式 { type, amount })
- const canAcceptTrade = (offer: TradeOffer): boolean => {
- const planet = gameStore.player.planets[0]
- if (!planet) return false
-
- // 新格式:{ type: 'metal', amount: 1000 }
- const requestedType = offer.requestedResources.type
- const requestedAmount = offer.requestedResources.amount
- return planet.resources[requestedType] >= requestedAmount
- }
-
- // 接受贸易提议
- const acceptTradeOffer = (offer: TradeOffer) => {
- if (!canAcceptTrade(offer)) {
- toast.error(t('npcBehavior.trade.acceptFailed'))
- return
- }
-
- const planet = gameStore.player.planets[0]
- if (!planet) return
-
- // 新格式:{ type: 'metal', amount: 1000 }
- const requestedType = offer.requestedResources.type
- const requestedAmount = offer.requestedResources.amount
- const offeredType = offer.offeredResources.type
- const offeredAmount = offer.offeredResources.amount
-
- // 扣除请求的资源
- planet.resources[requestedType] -= requestedAmount
-
- // 添加获得的资源
- planet.resources[offeredType] += offeredAmount
-
- // 移除贸易提议
- const index = gameStore.player.tradeOffers?.indexOf(offer)
- if (index !== undefined && index >= 0) {
- gameStore.player.tradeOffers?.splice(index, 1)
- }
-
- // 提高与该NPC的好感度(使用 npcId 而不是 fromNpcId)
- const npcRelation = npcStore.npcs.find(n => n.id === offer.npcId)?.relations?.[gameStore.player.id]
- if (npcRelation) {
- npcRelation.reputation += 10
- }
-
- toast.success(t('npcBehavior.trade.acceptSuccess'))
- }
-
- // 拒绝贸易提议
- const declineTradeOffer = (offer: TradeOffer) => {
- const index = gameStore.player.tradeOffers?.indexOf(offer)
- if (index !== undefined && index >= 0) {
- gameStore.player.tradeOffers?.splice(index, 1)
- }
-
- toast.info(t('npcBehavior.trade.declined'))
- }
-
- // 标记情报为已读
- const markIntelAsRead = (intel: IntelReport) => {
- intel.read = true
- }
-
- // 接受联合攻击邀请
- const acceptJointAttack = (invite: JointAttackInvite) => {
- // 这里可以添加联合攻击的逻辑
- // 目前只是简单地移除邀请并显示提示
- const index = gameStore.player.jointAttackInvites?.indexOf(invite)
- if (index !== undefined && index >= 0) {
- gameStore.player.jointAttackInvites?.splice(index, 1)
- }
-
- // 提高与该NPC的好感度(使用 npcStore)
- const npcRelation = npcStore.npcs.find(n => n.id === invite.fromNpcId)?.relations?.[gameStore.player.id]
- if (npcRelation) {
- npcRelation.reputation += 15
- }
-
- toast.success(t('npcBehavior.jointAttack.acceptSuccess'))
- }
-
- // 拒绝联合攻击邀请
- const declineJointAttack = (invite: JointAttackInvite) => {
- const index = gameStore.player.jointAttackInvites?.indexOf(invite)
- if (index !== undefined && index >= 0) {
- gameStore.player.jointAttackInvites?.splice(index, 1)
- }
-
- toast.info(t('npcBehavior.jointAttack.declined'))
- }