11<template >
2- <div class =" launcher" @contextmenu =" handleRightClick" >
2+ <div class =" launcher" @contextmenu =" handleRightClick" >
33 <div class =" header" >
44 <span v-if =" !isEditing" class =" name" @dblclick =" editLauncherName" title =" 双击修改名称" >
55 {{ this.data.name }}
4949
5050 <div class =" data-row" v-for =" (item, index) in data.resources" :key =" item.id" :title =" item.path" >
5151 <span class =" data-text" >
52+ <!-- 名称编辑部分 -->
5253 <span v-if =" !editingResourceState.get(item.id)" @dblclick =" editResourceName(item)" title =" 双击修改名称" >
5354 <strong >{{ item.name }}:</strong >
5455 </span >
55- <input v-if =" editingResourceState.get(item.id)" v-model =" newResourceName" class =" name-input"
56- @blur =" saveResourceName(item)" @keyup.enter =" saveResourceName(item)" />
57- <span >
56+ <input
57+ v-if =" editingResourceState.get(item.id)"
58+ v-model =" resourceEditData.get(item.id).name"
59+ class =" name-input"
60+ @blur =" saveResourceName(item)"
61+ @keyup.enter =" saveResourceName(item)"
62+ ref =" getResourceNameInputRef(item.id)"
63+ />
64+
65+ <!-- 路径编辑部分 -->
66+ <span
67+ v-if =" !editingResourcePathState.get(item.id)"
68+ @dblclick =" editResourcePath(item)"
69+ title =" 双击修改路径"
70+ class =" path-text"
71+ >
5872 {{ item.path }}
5973 </span >
74+ <input
75+ v-if =" editingResourcePathState.get(item.id)"
76+ v-model =" resourceEditData.get(item.id).path"
77+ class =" path-input"
78+ @blur =" saveResourcePath(item)"
79+ @keyup.enter =" saveResourcePath(item)"
80+ ref =" getResourcePathInputRef(item.id)"
81+ />
6082 </span >
6183 <Press class =" press" theme =" outline" size =" 19" @click =" openPath(item)" />
6284 <el-popconfirm title =" 确定要删除吗?" confirm-button-text =" 确认" cancel-button-text =" 取消"
@@ -124,48 +146,161 @@ export default {
124146 const addUrlNamePlaceholder = ref (" 网页" );
125147 // 是否正在启动
126148 const isLaunching = ref (false );
127- const editingResourceState = ref (new Map ());
128- const newResourceName = ref (" " );
149+ // 编辑状态管理 - 使用Map存储每个资源的编辑状态
150+ const editingResourceState = ref (new Map ()); // 名称编辑状态
151+ const editingResourcePathState = ref (new Map ()); // 路径编辑状态
152+
153+ // 核心修复:使用Map为每个资源存储独立的编辑数据
154+ const resourceEditData = ref (new Map ()); // 存储格式: { 资源ID => { name: '', path: '' } }
155+
156+ // 输入框引用管理
129157 const launcherNameInputRef = ref (null );
130- const resourceNameInputRef = ref (null );
158+ const resourceNameInputRefs = ref (new Map ()); // 名称输入框引用
159+ const resourcePathInputRefs = ref (new Map ()); // 路径输入框引用
160+
131161 const debouncedLaunch = ref (null );
162+
163+ // 获取名称输入框引用
164+ const getResourceNameInputRef = (id ) => {
165+ return (el ) => {
166+ if (el) {
167+ resourceNameInputRefs .value .set (id, el);
168+ } else {
169+ resourceNameInputRefs .value .delete (id);
170+ }
171+ };
172+ };
173+
174+ // 获取路径输入框引用
175+ const getResourcePathInputRef = (id ) => {
176+ return (el ) => {
177+ if (el) {
178+ resourcePathInputRefs .value .set (id, el);
179+ } else {
180+ resourcePathInputRefs .value .delete (id);
181+ }
182+ };
183+ };
132184
133185 const editLauncherName = () => {
134- isEditing .value = true ; // 进入编辑模式
135- newLauncherName .value = props .launcherData .name ; // 预填当前名称
186+ isEditing .value = true ;
187+ newLauncherName .value = props .launcherData .name ;
136188 nextTick (() => {
137189 launcherNameInputRef .value && launcherNameInputRef .value .focus ();
138190 });
139191 };
192+
140193 const saveLauncherName = async () => {
141194 if (newLauncherName .value .trim ()) {
142- newLauncherName .value = newLauncherName .value .trim (); // 保存修改后的名称
195+ newLauncherName .value = newLauncherName .value .trim ();
143196 }
144197 await invoke (" modify_launcher_name" , { launcherId: props .launcherData .id , name: newLauncherName .value });
145- isEditing .value = false ; // 退出编辑模式
198+ isEditing .value = false ;
146199 emit (" launcher-updated" , props .launcherData .id );
147200 };
201+
148202 const editResourceName = (item ) => {
149- editingResourceState .value .set (item .id , true ); // 进入编辑模式
150- newResourceName .value = item .name ; // 预填当前名称
203+ // 关闭当前资源的路径编辑状态(避免冲突)
204+ editingResourcePathState .value .set (item .id , false );
205+
206+ // 标记为名称编辑状态
207+ editingResourceState .value .set (item .id , true );
208+
209+ // 初始化该资源的编辑数据(确保每个资源有独立存储)
210+ const currentData = resourceEditData .value .get (item .id ) || { name: ' ' , path: ' ' };
211+ currentData .name = item .name ; // 仅更新名称字段
212+ resourceEditData .value .set (item .id , currentData);
213+
214+ // 自动聚焦
151215 nextTick (() => {
152- // 自动聚焦到输入框
153- resourceNameInputRef . value && resourceNameInputRef . value .focus ();
216+ const inputRef = resourceNameInputRefs . value . get ( item . id );
217+ inputRef && inputRef .focus ();
154218 });
155219 };
220+
156221 const saveResourceName = async (item ) => {
157- if (newResourceName .value .trim ()) {
158- const trimName = newResourceName .value .trim ();
159- if (item .name === trimName) {
160- editingResourceState .value .set (item .id , false ); // 退出编辑模式
161- return ;
162- }
163- newResourceName .value = trimName; // 保存修改后的名称
222+ // 获取该资源的独立编辑数据
223+ const editData = resourceEditData .value .get (item .id );
224+ if (! editData) return ;
225+
226+ const trimmedName = editData .name .trim ();
227+
228+ // 验证和退出编辑状态
229+ if (! trimmedName) {
230+ editingResourceState .value .set (item .id , false );
231+ toast .warning (" 名称不能为空!" );
232+ return ;
233+ }
234+
235+ if (trimmedName === item .name ) {
236+ editingResourceState .value .set (item .id , false );
237+ return ;
238+ }
239+
240+ // 保存修改
241+ try {
242+ await invoke (" modify_resource_name" , {
243+ resourceId: item .id ,
244+ name: trimmedName
245+ });
246+ editingResourceState .value .set (item .id , false );
247+ emit (" launcher-updated" , props .launcherData .id );
248+ } catch (error) {
249+ console .error (" 修改资源名称失败:" , error);
164250 }
165- await invoke (" modify_resource_name" , { resourceId: item .id , name: newResourceName .value });
166- editingResourceState .value .set (item .id , false ); // 退出编辑模式
167- emit (" launcher-updated" , props .launcherData .id );
168251 };
252+
253+ const editResourcePath = (item ) => {
254+ // 关闭当前资源的名称编辑状态(避免冲突)
255+ editingResourceState .value .set (item .id , false );
256+
257+ // 标记为路径编辑状态
258+ editingResourcePathState .value .set (item .id , true );
259+
260+ // 初始化该资源的编辑数据
261+ const currentData = resourceEditData .value .get (item .id ) || { name: ' ' , path: ' ' };
262+ currentData .path = item .path ; // 仅更新路径字段
263+ resourceEditData .value .set (item .id , currentData);
264+
265+ // 自动聚焦
266+ nextTick (() => {
267+ const inputRef = resourcePathInputRefs .value .get (item .id );
268+ inputRef && inputRef .focus ();
269+ });
270+ };
271+
272+ const saveResourcePath = async (item ) => {
273+ // 获取该资源的独立编辑数据
274+ const editData = resourceEditData .value .get (item .id );
275+ if (! editData) return ;
276+
277+ const trimmedPath = editData .path .trim ();
278+
279+ // 验证和退出编辑状态
280+ if (! trimmedPath) {
281+ editingResourcePathState .value .set (item .id , false );
282+ toast .warning (" 路径不能为空!" );
283+ return ;
284+ }
285+
286+ if (trimmedPath === item .path ) {
287+ editingResourcePathState .value .set (item .id , false );
288+ return ;
289+ }
290+
291+ // 保存修改
292+ try {
293+ await invoke (" modify_resource_path" , {
294+ resourceId: item .id ,
295+ path: trimmedPath
296+ });
297+ editingResourcePathState .value .set (item .id , false );
298+ emit (" launcher-updated" , props .launcherData .id );
299+ } catch (error) {
300+ console .error (" 修改资源路径失败:" , error);
301+ }
302+ };
303+
169304 const addRow = async (directory ) => {
170305 try {
171306
@@ -260,6 +395,7 @@ export default {
260395 timer = setTimeout (() => func .apply (this , args), delay);
261396 };
262397 };
398+
263399 onBeforeMount (() => {
264400 // 包装 launch 方法为防抖函数
265401 debouncedLaunch .value = debounce (launch, 2000 ); // 2秒防抖
@@ -275,8 +411,6 @@ export default {
275411 addUrlContent,
276412 addUrlNamePlaceholder,
277413 isLaunching,
278- editingResourceState,
279- newResourceName,
280414 editLauncherName,
281415 saveLauncherName,
282416 editResourceName,
@@ -293,7 +427,15 @@ export default {
293427 debounce,
294428 debouncedLaunch,
295429 openPath,
296- handleRightClick
430+ handleRightClick,
431+ editResourcePath,
432+ saveResourcePath,
433+ editingResourceState,
434+ editingResourcePathState,
435+ resourceEditData,
436+ launcherNameInputRef,
437+ resourceNameInputRefs,
438+ resourcePathInputRefs
297439 };
298440 }
299441};
584726 /* 取消 active 缩小 */
585727 transform : none ;
586728}
587-
588729 </style >
0 commit comments