feat(GMView): 添加预设管理功能,支持删除和覆盖确认

- 为所有语言文件添加删除预设、确认覆盖等翻译键
- 在预设选择器旁添加删除按钮,允许删除自定义预设
- 保存同名预设时弹出确认对话框,防止意外覆盖
- 禁止删除默认预设,并提供相应的错误提示
This commit is contained in:
wenyu
2026-03-18 18:47:22 +08:00
parent b0a7b5ce90
commit 28c3da2582
9 changed files with 131 additions and 1 deletions

View File

@@ -1094,6 +1094,11 @@ export default {
presetNameRequired: 'Bitte geben Sie einen Namen ein',
presetSaved: 'Vorlage gespeichert',
presetApplied: 'Vorlage angewendet',
deletePreset: 'Vorlage löschen',
presetDeleted: 'Vorlage gelöscht',
confirmOverwriteTitle: 'Vorlage existiert bereits',
confirmOverwriteMessage: 'Eine Vorlage mit dem Namen "{name}" existiert bereits. Überschreiben?',
cannotDeleteDefault: 'Standardvorlage kann nicht gelöscht werden',
adminOnly: 'Nur Admin',
selectPlanet: 'Planet auswählen',
choosePlanet: 'Einen Planeten auswählen',

View File

@@ -1110,6 +1110,11 @@ export default {
presetNameRequired: 'Please enter a preset name',
presetSaved: 'Preset saved',
presetApplied: 'Preset applied',
deletePreset: 'Delete Preset',
presetDeleted: 'Preset deleted',
confirmOverwriteTitle: 'Preset Already Exists',
confirmOverwriteMessage: 'Preset with name "{name}" already exists. Overwrite?',
cannotDeleteDefault: 'Cannot delete default preset',
adminOnly: 'Admin Only',
selectPlanet: 'Select Planet',
choosePlanet: 'Choose a planet',

View File

@@ -1102,6 +1102,11 @@ export default {
presetNameRequired: 'Ingrese el nombre del preajuste',
presetSaved: 'Preajuste guardado',
presetApplied: 'Preajuste aplicado',
deletePreset: 'Eliminar preajuste',
presetDeleted: 'Preajuste eliminado',
confirmOverwriteTitle: 'El preajuste ya existe',
confirmOverwriteMessage: 'El preajuste con el nombre "{name}" ya existe. ¿Sobrescribir?',
cannotDeleteDefault: 'No se puede eliminar el preajuste predeterminado',
adminOnly: 'Solo Administrador',
selectPlanet: 'Seleccionar Planeta',
choosePlanet: 'Elige un planeta',

View File

@@ -1120,6 +1120,11 @@ export default {
presetNameRequired: 'プリセット名を入力してください',
presetSaved: '保存しました',
presetApplied: '適用しました',
deletePreset: 'プリセット削除',
presetDeleted: 'プリセットを削除しました',
confirmOverwriteTitle: 'プリセットは既に存在します',
confirmOverwriteMessage: 'プリセット名 "{name}" は既に存在します。上書きしますか?',
cannotDeleteDefault: 'デフォルトプリセットは削除できません',
adminOnly: '管理者専用',
selectPlanet: '惑星を選択',
choosePlanet: '惑星を選択してください',

View File

@@ -1070,6 +1070,11 @@ export default {
presetNameRequired: '프리셋 이름을 입력하세요',
presetSaved: '프리셋 저장됨',
presetApplied: '프리셋 적용됨',
deletePreset: '프리셋 삭제',
presetDeleted: '프리셋 삭제됨',
confirmOverwriteTitle: '프리셋이 이미 존재함',
confirmOverwriteMessage: '"{name}" 이름의 프리셋이 이미 존재합니다. 덮어쓰시겠습니까?',
cannotDeleteDefault: '기본 프리셋은 삭제할 수 없습니다',
adminOnly: '관리자 전용',
selectPlanet: '행성 선택',
choosePlanet: '행성을 선택하세요',

View File

@@ -1096,6 +1096,11 @@ export default {
presetNameRequired: 'Введите название',
presetSaved: 'Сохранено',
presetApplied: 'Применено',
deletePreset: 'Удалить',
presetDeleted: 'Удалено',
confirmOverwriteTitle: 'Уже существует',
confirmOverwriteMessage: 'Предустановка с именем "{name}" уже существует. Перезаписать?',
cannotDeleteDefault: 'Нельзя удалить стандартную предустановку',
adminOnly: 'Только для администратора',
selectPlanet: 'Выбрать планету',
choosePlanet: 'Выберите планету',

View File

@@ -1104,6 +1104,11 @@ export default {
presetNameRequired: '请输入预设名称',
presetSaved: '预设保存成功',
presetApplied: '预设应用成功',
deletePreset: '删除预设',
presetDeleted: '预设已删除',
confirmOverwriteTitle: '预设已存在',
confirmOverwriteMessage: '名为 "{name}" 的预设已存在,是否覆盖?',
cannotDeleteDefault: '无法删除默认预设',
npcTesting: 'NPC 测试',
npcTestingDesc: '测试NPC侦查和攻击行为',
selectNPC: '选择NPC',

View File

@@ -1089,6 +1089,11 @@ export default {
presetNameRequired: '請輸入預設名稱',
presetSaved: '預設已儲存',
presetApplied: '預設已套用',
deletePreset: '刪除預設',
presetDeleted: '預設已刪除',
confirmOverwriteTitle: '預設已存在',
confirmOverwriteMessage: '名為 "{name}" 的預設已存在,是否覆蓋?',
cannotDeleteDefault: '無法刪除預設範本',
adminOnly: '僅管理員',
selectPlanet: '選擇星球',
choosePlanet: '選擇一個星球',

View File

@@ -99,6 +99,15 @@
</SelectContent>
</Select>
<Button @click="handleApplyPreset(section)">{{ t('gmView.applyPreset') || 'Apply' }}</Button>
<Button
v-if="selectedPresets[section.tabValue] !== 'default'"
@click="handleDeletePreset(section)"
variant="destructive"
size="icon"
:title="t('gmView.deletePreset') || 'Delete Preset'"
>
<Trash2 class="h-4 w-4" />
</Button>
</div>
<div class="flex gap-2 w-full sm:w-auto ml-auto">
<Input v-model="presetNames[section.tabValue]" :placeholder="t('gmView.presetName') || 'Preset Name'" class="w-[150px]" />
@@ -242,6 +251,22 @@
</AlertDialogContent>
</AlertDialog>
<!-- 预设覆盖确认对话框 -->
<AlertDialog :open="presetOverwriteDialogOpen" @update:open="presetOverwriteDialogOpen = $event">
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>{{ t('gmView.confirmOverwriteTitle') || 'Preset Already Exists' }}</AlertDialogTitle>
<AlertDialogDescription>
{{ t('gmView.confirmOverwriteMessage', { name: pendingPresetToOverwrite?.name || '' }) || `Preset with name "${pendingPresetToOverwrite?.name}" already exists. Overwrite?` }}
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel @click="presetOverwriteDialogOpen = false">{{ t('common.cancel') }}</AlertDialogCancel>
<AlertDialogAction @click="handleConfirmOverwrite">{{ t('common.confirm') }}</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
<!-- AlertDialog 提示对话框 -->
<AlertDialog :open="alertDialogOpen" @update:open="alertDialogOpen = $event">
<AlertDialogContent>
@@ -293,7 +318,7 @@
import * as npcBehaviorLogic from '@/logic/npcBehaviorLogic'
import * as publicLogic from '@/logic/publicLogic'
import { calculateMaxFleetStorage } from '@/logic/fleetStorageLogic'
import { Home } from 'lucide-vue-next'
import { Home, Trash2 } from 'lucide-vue-next'
// --- 预设系统 ---
interface GMPreset {
@@ -302,6 +327,14 @@
values: Record<string, number>
}
const presetOverwriteDialogOpen = ref(false)
const pendingPresetToOverwrite = ref<{
section: any
name: string
values: Record<string, number>
existingIndex: number
} | null>(null)
const getPresets = (type: string): GMPreset[] => {
const data = localStorage.getItem(`gm_presets_${type}`)
return data ? JSON.parse(data) : []
@@ -343,6 +376,20 @@
section.items.forEach((item: string) => {
values[item] = section.getValue(item)
})
// 检查是否存在同名预设
const existingIndex = customPresets.value[section.tabValue]?.findIndex(p => p.name === name) ?? -1
if (existingIndex !== -1) {
pendingPresetToOverwrite.value = {
section,
name,
values,
existingIndex
}
presetOverwriteDialogOpen.value = true
return
}
const newPreset: GMPreset = {
id: Date.now().toString(),
@@ -360,6 +407,49 @@
toast.success(t('gmView.presetSaved') || '预设保存成功')
}
const handleConfirmOverwrite = () => {
if (!pendingPresetToOverwrite.value) return
const { section, values, existingIndex } = pendingPresetToOverwrite.value
if (customPresets.value[section.tabValue]) {
const presets = customPresets.value[section.tabValue]!
if (presets[existingIndex]) {
// 更新现有预设的值保持ID不变
presets[existingIndex].values = values
savePresets(section.tabValue, presets)
presetNames.value[section.tabValue] = ''
selectedPresets.value[section.tabValue] = presets[existingIndex].id
toast.success(t('gmView.presetSaved') || '预设保存成功')
}
}
presetOverwriteDialogOpen.value = false
pendingPresetToOverwrite.value = null
}
const handleDeletePreset = (section: any) => {
const presetId = selectedPresets.value[section.tabValue]
if (!presetId || presetId === 'default') {
toast.error(t('gmView.cannotDeleteDefault') || '无法删除默认预设')
return
}
const presets = customPresets.value[section.tabValue] || []
const index = presets.findIndex(p => p.id === presetId)
if (index !== -1) {
presets.splice(index, 1)
savePresets(section.tabValue, presets)
selectedPresets.value[section.tabValue] = 'default'
toast.success(t('gmView.presetDeleted') || '预设已删除')
}
}
const handleApplyPreset = (section: any) => {
const presetId = selectedPresets.value[section.tabValue]
if (!presetId) return