Skip to content

Commit 2f899ad

Browse files
committed
feat(frontend): ✅ 增加修改游戏启动路径
#156
1 parent b815361 commit 2f899ad

File tree

4 files changed

+131
-65
lines changed

4 files changed

+131
-65
lines changed

locales/en_US.json

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@
119119
"batch_delete_prompt": "Note that this operation will delete all selected snapshots, please enter yes to confirm",
120120
"recover_failed": "Recovery failed",
121121
"size": "File size",
122-
"size_not_available": "Unrecorded"
122+
"size_not_available": "Unrecorded",
123+
"save_paths_updated": "Game settings are updated successfully"
123124
},
124125
"addgame": {
125126
"search_local": "Detect local games",
@@ -184,12 +185,14 @@
184185
"about": "About"
185186
},
186187
"save_location_drawer": {
187-
"drawer_title": "Below is the list of managed files",
188+
"drawer_title": "Modify configuration",
188189
"type": "Type",
189190
"prompt": "Path (click to copy)",
190191
"open_file_header": "Open file",
191192
"open": "Open",
192-
"delete_before_apply": "Delete before overwrite"
193+
"delete_before_apply": "Delete before overwrite",
194+
"launch_path": "Game launch path",
195+
"save_locations": "Save file locations"
193196
},
194197
"sync_settings": {
195198
"title": "Sync settings",
@@ -260,7 +263,9 @@
260263
"set_config_failed": "Failed to set config",
261264
"reset_settings_failed": "Failed to reset settings",
262265
"change_description_failed": "Failed to edit description",
263-
"open_log_folder_failed": "Cannot open log folder"
266+
"open_log_folder_failed": "Cannot open log folder",
267+
"game_not_found": "The corresponding game cannot be found",
268+
"save_config_failed": "Game settings failed to update"
264269
},
265270
"backend": {
266271
"config": {

locales/zh_SIMPLIFIED.json

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@
119119
"batch_delete_prompt": "注意,该操作会删除所有选中的快照,确定请输入yes",
120120
"recover_failed": "恢复失败",
121121
"size": "文件大小",
122-
"size_not_available": "未记录"
122+
"size_not_available": "未记录",
123+
"save_paths_updated": "游戏设置更新成功"
123124
},
124125
"addgame": {
125126
"search_local": "自动识别本地游戏",
@@ -186,15 +187,17 @@
186187
"about": "关于"
187188
},
188189
"save_location_drawer": {
189-
"drawer_title": "以下是受管理文件列表",
190+
"drawer_title": "修改配置",
190191
"type": "类别",
191192
"prompt": "路径",
192193
"open_file_header": "打开文件",
193194
"open": "打开",
194195
"delete_before_apply": "应用前删除",
195196
"select_device": "选择设备",
196197
"current_device": "当前设备",
197-
"copy": "复制"
198+
"copy": "复制",
199+
"launch_path": "启动路径",
200+
"save_locations": "存档路径"
198201
},
199202
"sync_settings": {
200203
"title": "同步设置",
@@ -267,7 +270,9 @@
267270
"set_config_failed": "设置配置失败",
268271
"reset_settings_failed": "重置设置失败",
269272
"change_description_failed": "编辑描述失败",
270-
"open_log_folder_failed": "无法打开日志文件夹"
273+
"open_log_folder_failed": "无法打开日志文件夹",
274+
"game_not_found": "找不到对应的游戏",
275+
"save_config_failed": "游戏设置更新失败"
271276
},
272277
"backend": {
273278
"config": {

src/components/SaveLocationDrawer.vue

Lines changed: 91 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script setup lang="ts">
22
import { $t } from "../i18n";
3-
import type { SaveUnit, Device } from "../bindings";
3+
import type { SaveUnit, Device, Game } from "../bindings";
44
import { commands } from "../bindings";
55
import { useNotification } from "../composables/useNotification";
66
import { ref, watch } from "vue";
@@ -9,12 +9,12 @@ import PathVariableSelector from "./PathVariableSelector.vue";
99
const { showSuccess, showError } = useNotification();
1010
1111
const props = defineProps({
12-
locations: Array<SaveUnit>,
12+
game: Object as () => Game,
1313
})
1414
1515
const emits = defineEmits<{
1616
(event: 'closed'): void
17-
(event: 'saveChanges', tempLocations: SaveUnit[]): void
17+
(event: 'saveChanges', game: Game): void
1818
}>()
1919
2020
// 当前设备信息
@@ -24,7 +24,7 @@ const availableDevices = ref<Device[]>([]);
2424
// 当前选中的设备ID
2525
const selectedDeviceId = ref<string>('');
2626
// 临时存储修改的数据
27-
const tempLocations = ref<SaveUnit[]>([]);
27+
const tempGame = ref<Game>({ name: "", save_paths: [], game_paths: {} });
2828
// 是否有未保存的修改
2929
const hasUnsavedChanges = ref(false);
3030
@@ -45,9 +45,9 @@ async function fetchCurrentDevice() {
4545
}
4646
}
4747
48-
// 从SaveUnit中提取所有设备ID
48+
// 从Game中提取所有设备ID
4949
function extractDeviceIdsFromSaveUnits() {
50-
if (!props.locations) return;
50+
if (!props.game) return;
5151
5252
// 收集所有设备ID
5353
const deviceIds = new Set<string>();
@@ -58,13 +58,22 @@ function extractDeviceIdsFromSaveUnits() {
5858
}
5959
6060
// 从所有SaveUnit的paths中提取设备ID
61-
props.locations.forEach(unit => {
62-
if (unit.paths) {
63-
Object.keys(unit.paths).forEach(deviceId => {
64-
deviceIds.add(deviceId);
65-
});
66-
}
67-
});
61+
if (props.game.save_paths) {
62+
props.game.save_paths.forEach(unit => {
63+
if (unit.paths) {
64+
Object.keys(unit.paths).forEach(deviceId => {
65+
deviceIds.add(deviceId);
66+
});
67+
}
68+
});
69+
}
70+
71+
// 从game_paths中提取设备ID
72+
if (props.game.game_paths) {
73+
Object.keys(props.game.game_paths).forEach(deviceId => {
74+
deviceIds.add(deviceId);
75+
});
76+
}
6877
6978
// 转换为设备对象数组
7079
availableDevices.value = Array.from(deviceIds).map(id => {
@@ -86,23 +95,23 @@ function extractDeviceIdsFromSaveUnits() {
8695
}
8796
}
8897
89-
// 监听locations变化,重新提取设备ID并初始化临时数据
90-
watch(() => props.locations, () => {
98+
// 监听game变化,重新提取设备ID并初始化临时数据
99+
watch(() => props.game, () => {
91100
extractDeviceIdsFromSaveUnits();
92-
initTempLocations();
101+
initTempGame();
93102
}, { deep: true });
94103
95104
// 初始化设备信息
96105
fetchCurrentDevice().then(() => {
97106
extractDeviceIdsFromSaveUnits();
98-
initTempLocations();
107+
initTempGame();
99108
});
100109
101-
// 初始化临时locations数据
102-
function initTempLocations() {
103-
if (!props.locations) return;
104-
// 深拷贝locations数据
105-
tempLocations.value = JSON.parse(JSON.stringify(props.locations));
110+
// 初始化临时game数据
111+
function initTempGame() {
112+
if (!props.game) return;
113+
// 深拷贝game数据
114+
tempGame.value = JSON.parse(JSON.stringify(props.game));
106115
hasUnsavedChanges.value = false;
107116
}
108117
@@ -112,11 +121,17 @@ function getDevicePath(unit: SaveUnit, deviceId: string): string {
112121
return unit.paths[deviceId] || '';
113122
}
114123
124+
// 获取当前设备的游戏启动路径
125+
function getGameLaunchPath(deviceId: string): string {
126+
if (!tempGame.value.game_paths) return '';
127+
return tempGame.value.game_paths[deviceId] || '';
128+
}
129+
115130
// 更新临时设备路径
116131
function updateDevicePath(index: number, deviceId: string, path: string) {
117-
if (!tempLocations.value) return;
132+
if (!tempGame.value || !tempGame.value.save_paths) return;
118133
119-
const unit = tempLocations.value[index];
134+
const unit = tempGame.value.save_paths[index];
120135
if (!unit.paths) {
121136
unit.paths = {};
122137
}
@@ -125,11 +140,23 @@ function updateDevicePath(index: number, deviceId: string, path: string) {
125140
hasUnsavedChanges.value = true;
126141
}
127142
143+
// 更新临时游戏启动路径
144+
function updateGameLaunchPath(deviceId: string, path: string) {
145+
if (!tempGame.value) return;
146+
147+
if (!tempGame.value.game_paths) {
148+
tempGame.value.game_paths = {};
149+
}
150+
151+
tempGame.value.game_paths[deviceId] = path;
152+
hasUnsavedChanges.value = true;
153+
}
154+
128155
// 在路径输入框中插入变量
129156
function insertPathVariable(variable: string, index: number, deviceId: string) {
130-
if (!tempLocations.value) return;
157+
if (!tempGame.value || !tempGame.value.save_paths) return;
131158
132-
const unit = tempLocations.value[index];
159+
const unit = tempGame.value.save_paths[index];
133160
if (!unit.paths) {
134161
unit.paths = {};
135162
}
@@ -139,6 +166,19 @@ function insertPathVariable(variable: string, index: number, deviceId: string) {
139166
hasUnsavedChanges.value = true;
140167
}
141168
169+
// 在游戏启动路径输入框中插入变量
170+
function insertGamePathVariable(variable: string, deviceId: string) {
171+
if (!tempGame.value) return;
172+
173+
if (!tempGame.value.game_paths) {
174+
tempGame.value.game_paths = {};
175+
}
176+
177+
const currentPath = tempGame.value.game_paths[deviceId] || '';
178+
tempGame.value.game_paths[deviceId] = currentPath + variable;
179+
hasUnsavedChanges.value = true;
180+
}
181+
142182
async function open(url: string) {
143183
let result = await commands.openUrl(url);
144184
if (result.status === "error") {
@@ -148,26 +188,24 @@ async function open(url: string) {
148188
149189
// 由父组件处理具体任务,此处只传递下标
150190
function switch_delete_before_apply(unit: SaveUnit) {
151-
const index = tempLocations.value?.indexOf(unit)
152-
if (index != undefined) {
153-
// 只在临时数据中切换状态,不触发父组件事件
154-
hasUnsavedChanges.value = true;
155-
}
191+
// 这里不需要特殊处理,直接修改tempGame中的值即可
192+
// 因为是引用类型,所以直接修改unit的属性会反映到tempGame中
193+
hasUnsavedChanges.value = true;
156194
}
157195
158196
// 保存修改
159197
function saveChanges() {
160-
if (!tempLocations.value) return;
198+
if (!tempGame.value) return;
161199
162200
// 将所有修改发送给父组件
163-
emits('saveChanges', tempLocations.value);
201+
emits('saveChanges', tempGame.value);
164202
165203
hasUnsavedChanges.value = false;
166204
}
167205
168206
// 取消修改
169207
function cancelChanges() {
170-
initTempLocations();
208+
initTempGame();
171209
}
172210
</script>
173211

@@ -198,8 +236,25 @@ function cancelChanges() {
198236
</el-tag>
199237
</div>
200238

201-
<!-- 路径表格 -->
202-
<el-table :data="tempLocations" style="width: 100%" :border="true">
239+
<!-- 游戏启动路径 -->
240+
<div class="launch-path-section">
241+
<h3>{{ $t('save_location_drawer.launch_path') }}</h3>
242+
<div class="path-input-container">
243+
<el-input :model-value="getGameLaunchPath(selectedDeviceId)" size="small"
244+
@update:model-value="(value) => updateGameLaunchPath(selectedDeviceId, value)">
245+
<template #append>
246+
<div class="path-actions">
247+
<path-variable-selector :current-path="getGameLaunchPath(selectedDeviceId)"
248+
@insert="(variable) => insertGamePathVariable(variable, selectedDeviceId)" />
249+
</div>
250+
</template>
251+
</el-input>
252+
</div>
253+
</div>
254+
255+
<!-- 存档路径表格 -->
256+
<h3>{{ $t('save_location_drawer.save_locations') }}</h3>
257+
<el-table :data="tempGame.save_paths" style="width: 100%" :border="true">
203258
<el-table-column prop="unit_type" :label="$t('save_location_drawer.type')" width="70" />
204259
<el-table-column :label="$t('save_location_drawer.prompt')" min-width="300">
205260
<template #default="scope">

src/pages/Management/[name].vue

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -334,26 +334,27 @@ async function set_quick_backup() {
334334
showSuccess({ message: $t('manage.set_quick_backup_success') });
335335
}
336336
337-
async function on_drawer_save_changes(save_units: SaveUnit[]) {
338-
try {
339-
// 更新当前游戏的 save_paths
340-
game.value.save_paths = save_units;
341-
342-
// 更新全局配置中的游戏信息
343-
const gameIndex = config.value.games.findIndex(g => g.name === game.value.name);
344-
if (gameIndex !== -1) {
345-
config.value.games[gameIndex].save_paths = save_units;
346-
347-
// 保存配置到文件
348-
await saveConfig();
349-
showSuccess({ message: $t('common.save_success') });
350-
} else {
351-
showError({ message: $t('common.save_failed') });
352-
}
353-
} catch (e) {
354-
error(`Error saving game paths: ${e}`);
355-
showError({ message: $t('common.save_failed') });
337+
// 处理抽屉组件保存游戏路径的事件
338+
async function on_drawer_save_changes(updatedGame: Game) {
339+
// 更新游戏信息(包括存档路径和启动路径)
340+
game.value = updatedGame;
341+
342+
// 保存到配置
343+
const index = config.value.games.findIndex(g => g.name === game.value.name);
344+
if (index !== -1) {
345+
config.value.games[index] = game.value;
346+
saveConfig().then(() => {
347+
showSuccess({ message: $t('manage.save_paths_updated') });
348+
}).catch((e) => {
349+
error(`Error saving config: ${e}`);
350+
showError({ message: $t('error.save_config_failed') });
351+
});
352+
} else {
353+
showError({ message: $t('error.game_not_found') });
356354
}
355+
356+
// 关闭侧栏
357+
drawer.value = false;
357358
}
358359
359360
const filter_table = computed(
@@ -443,8 +444,8 @@ const filter_table = computed(
443444
</el-table>
444445
</el-card>
445446
<!-- 下面是存档所在位置侧栏部分 -->
446-
<save-location-drawer v-if="game.save_paths" v-model="drawer" :locations="game.save_paths"
447-
@closed="drawer = false" @save-changes="on_drawer_save_changes" />
447+
<save-location-drawer v-if="game" v-model="drawer" :game="game" @closed="drawer = false"
448+
@save-changes="on_drawer_save_changes" />
448449
</div>
449450
</template>
450451

0 commit comments

Comments
 (0)