zen-gitsync 2.0.9 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/ui/client/src/App.vue +11 -9
- package/src/ui/client/src/components/CommitForm.vue +266 -265
- package/src/ui/client/src/components/GitStatus.vue +0 -6
- package/src/ui/client/src/components/LogList.vue +19 -8
- package/src/ui/client/src/stores/configStore.ts +212 -0
- package/src/ui/client/src/stores/gitStore.ts +48 -34
- package/src/ui/server/index.js +16 -1
package/package.json
CHANGED
|
@@ -7,6 +7,7 @@ import { ElMessage } from 'element-plus'
|
|
|
7
7
|
import { Plus, Setting } from '@element-plus/icons-vue'
|
|
8
8
|
import logo from './assets/logo.svg'
|
|
9
9
|
import { useGitStore } from './stores/gitStore'
|
|
10
|
+
import { useConfigStore } from './stores/configStore'
|
|
10
11
|
|
|
11
12
|
const configInfo = ref('')
|
|
12
13
|
// 添加组件实例类型
|
|
@@ -15,6 +16,8 @@ const gitStatusRef = ref<InstanceType<typeof GitStatus> | null>(null)
|
|
|
15
16
|
|
|
16
17
|
// 使用Git Store
|
|
17
18
|
const gitStore = useGitStore()
|
|
19
|
+
// 使用Config Store
|
|
20
|
+
const configStore = useConfigStore()
|
|
18
21
|
|
|
19
22
|
// 添加初始化完成状态
|
|
20
23
|
const initCompleted = ref(false)
|
|
@@ -23,9 +26,10 @@ const currentDirectory = ref('')
|
|
|
23
26
|
// 加载配置
|
|
24
27
|
async function loadConfig() {
|
|
25
28
|
try {
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
const config = await configStore.loadConfig()
|
|
30
|
+
if (config) {
|
|
31
|
+
configInfo.value = `默认提交信息: ${config.defaultCommitMessage}`
|
|
32
|
+
}
|
|
29
33
|
} catch (error) {
|
|
30
34
|
console.error('加载配置失败:', error)
|
|
31
35
|
}
|
|
@@ -60,14 +64,12 @@ onMounted(async () => {
|
|
|
60
64
|
|
|
61
65
|
// 只有是Git仓库的情况下才加载Git相关信息
|
|
62
66
|
if (gitStore.isGitRepo) {
|
|
63
|
-
//
|
|
67
|
+
// 并行获取所有Git信息,确保每个API只调用一次
|
|
64
68
|
await Promise.all([
|
|
65
|
-
gitStore.getCurrentBranch(),
|
|
66
|
-
gitStore.getAllBranches(),
|
|
67
|
-
gitStore.getUserInfo()
|
|
69
|
+
gitStore.getCurrentBranch(), // 获取当前分支
|
|
70
|
+
gitStore.getAllBranches(), // 获取所有分支
|
|
71
|
+
gitStore.getUserInfo() // 获取用户信息
|
|
68
72
|
])
|
|
69
|
-
|
|
70
|
-
// 日志信息通过LogList组件直接加载即可,避免重复调用
|
|
71
73
|
} else {
|
|
72
74
|
ElMessage.warning('当前目录不是Git仓库,部分功能将不可用')
|
|
73
75
|
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { ref, onMounted, computed, watch } from "vue";
|
|
3
3
|
import { ElMessage, ElMessageBox } from "element-plus";
|
|
4
|
-
import { Setting, Edit, Check, Upload, RefreshRight, Delete, Position, Download, Connection } from "@element-plus/icons-vue";
|
|
4
|
+
import { Setting, Edit, Check, Upload, RefreshRight, Delete, Position, Download, Connection, ArrowDown } from "@element-plus/icons-vue";
|
|
5
5
|
import { useGitLogStore } from "../stores/gitLogStore";
|
|
6
6
|
import { useGitStore } from "../stores/gitStore";
|
|
7
|
+
import { useConfigStore } from "../stores/configStore";
|
|
7
8
|
|
|
8
9
|
const gitLogStore = useGitLogStore();
|
|
9
10
|
const gitStore = useGitStore();
|
|
11
|
+
const configStore = useConfigStore();
|
|
10
12
|
const commitMessage = ref("");
|
|
11
13
|
const isPushing = ref(false);
|
|
12
14
|
// 添加提交并推送的状态变量
|
|
@@ -51,6 +53,9 @@ const newDefaultMessage = ref("");
|
|
|
51
53
|
// 跳过钩子
|
|
52
54
|
const skipHooks = ref(false);
|
|
53
55
|
|
|
56
|
+
// 添加控制正文和页脚显示的状态变量
|
|
57
|
+
const showAdvancedFields = ref(false);
|
|
58
|
+
|
|
54
59
|
// 提交类型选项
|
|
55
60
|
const commitTypeOptions = [
|
|
56
61
|
{ value: "feat", label: "feat: 新功能" },
|
|
@@ -119,28 +124,29 @@ const gitCommandPreview = computed(() => {
|
|
|
119
124
|
// 加载配置
|
|
120
125
|
async function loadConfig() {
|
|
121
126
|
try {
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
127
|
+
const config = await configStore.loadConfig();
|
|
128
|
+
if (config) {
|
|
129
|
+
placeholder.value = `输入提交信息 (默认: ${config.defaultCommitMessage})`;
|
|
130
|
+
// 保存默认提交信息到变量中,以便后续使用
|
|
131
|
+
defaultCommitMessage.value = config.defaultCommitMessage || "";
|
|
132
|
+
|
|
133
|
+
// 加载描述模板
|
|
134
|
+
if (
|
|
135
|
+
config.descriptionTemplates &&
|
|
136
|
+
Array.isArray(config.descriptionTemplates)
|
|
137
|
+
) {
|
|
138
|
+
descriptionTemplates.value = config.descriptionTemplates;
|
|
139
|
+
}
|
|
135
140
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
141
|
+
// 加载作用域模板
|
|
142
|
+
if (config.scopeTemplates && Array.isArray(config.scopeTemplates)) {
|
|
143
|
+
scopeTemplates.value = config.scopeTemplates;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// 加载提交信息模板
|
|
147
|
+
if (config.messageTemplates && Array.isArray(config.messageTemplates)) {
|
|
148
|
+
messageTemplates.value = config.messageTemplates;
|
|
149
|
+
}
|
|
144
150
|
}
|
|
145
151
|
} catch (error) {
|
|
146
152
|
console.error("加载配置失败:", error);
|
|
@@ -173,90 +179,67 @@ async function saveDescriptionTemplate() {
|
|
|
173
179
|
return;
|
|
174
180
|
}
|
|
175
181
|
|
|
176
|
-
//
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
const result = await response.json();
|
|
192
|
-
if (result.success) {
|
|
193
|
-
ElMessage({
|
|
194
|
-
message: "模板保存成功!",
|
|
195
|
-
type: "success",
|
|
196
|
-
});
|
|
197
|
-
newTemplateName.value = "";
|
|
198
|
-
} else {
|
|
199
|
-
ElMessage({
|
|
200
|
-
message: "模板保存失败: " + result.error,
|
|
201
|
-
type: "error",
|
|
202
|
-
});
|
|
182
|
+
// 使用 configStore 保存模板
|
|
183
|
+
const success = await configStore.saveTemplate(newTemplateName.value, 'description');
|
|
184
|
+
|
|
185
|
+
if (success) {
|
|
186
|
+
// 确保本地数组同步更新
|
|
187
|
+
if (!descriptionTemplates.value.includes(newTemplateName.value)) {
|
|
188
|
+
descriptionTemplates.value.push(newTemplateName.value);
|
|
189
|
+
}
|
|
190
|
+
// 强制更新视图
|
|
191
|
+
descriptionTemplates.value = [...descriptionTemplates.value];
|
|
192
|
+
|
|
193
|
+
// configStore已经显示了成功消息,这里不需要重复操作
|
|
194
|
+
newTemplateName.value = ""; // 清空输入框,但不关闭弹窗
|
|
203
195
|
}
|
|
204
196
|
}
|
|
205
197
|
} catch (error) {
|
|
206
198
|
ElMessage({
|
|
207
|
-
message:
|
|
199
|
+
message: `保存模板失败: ${(error as Error).message}`,
|
|
208
200
|
type: "error",
|
|
209
201
|
});
|
|
210
202
|
}
|
|
211
203
|
}
|
|
212
204
|
|
|
213
|
-
//
|
|
205
|
+
// 更新描述模板
|
|
214
206
|
async function updateDescriptionTemplate() {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
// 更新本地数组
|
|
223
|
-
descriptionTemplates.value[editingDescriptionIndex.value] = newTemplate;
|
|
224
|
-
|
|
225
|
-
// 调用API更新服务器
|
|
226
|
-
const response = await fetch("/api/config/update-template", {
|
|
227
|
-
method: "POST",
|
|
228
|
-
headers: {
|
|
229
|
-
"Content-Type": "application/json",
|
|
230
|
-
},
|
|
231
|
-
body: JSON.stringify({
|
|
232
|
-
oldTemplate,
|
|
233
|
-
newTemplate,
|
|
234
|
-
type: "description",
|
|
235
|
-
}),
|
|
236
|
-
});
|
|
207
|
+
if (!newTemplateName.value.trim()) {
|
|
208
|
+
ElMessage({
|
|
209
|
+
message: "请输入模板内容",
|
|
210
|
+
type: "warning",
|
|
211
|
+
});
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
237
214
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
215
|
+
try {
|
|
216
|
+
// 使用 configStore 更新模板
|
|
217
|
+
const success = await configStore.updateTemplate(
|
|
218
|
+
originalDescriptionTemplate.value,
|
|
219
|
+
newTemplateName.value,
|
|
220
|
+
'description'
|
|
221
|
+
);
|
|
244
222
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
} else {
|
|
251
|
-
ElMessage({
|
|
252
|
-
message: "模板更新失败: " + result.error,
|
|
253
|
-
type: "error",
|
|
254
|
-
});
|
|
223
|
+
if (success) {
|
|
224
|
+
// 确保本地数组同步更新
|
|
225
|
+
const index = descriptionTemplates.value.indexOf(originalDescriptionTemplate.value);
|
|
226
|
+
if (index !== -1) {
|
|
227
|
+
descriptionTemplates.value[index] = newTemplateName.value;
|
|
255
228
|
}
|
|
229
|
+
// 强制更新视图
|
|
230
|
+
descriptionTemplates.value = [...descriptionTemplates.value];
|
|
231
|
+
|
|
232
|
+
// configStore已经更新了本地数组并显示了成功消息,这里不需要重复操作
|
|
233
|
+
|
|
234
|
+
// 重置编辑状态
|
|
235
|
+
isEditingDescription.value = false;
|
|
236
|
+
originalDescriptionTemplate.value = "";
|
|
237
|
+
editingDescriptionIndex.value = -1;
|
|
238
|
+
newTemplateName.value = "";
|
|
256
239
|
}
|
|
257
240
|
} catch (error) {
|
|
258
241
|
ElMessage({
|
|
259
|
-
message:
|
|
242
|
+
message: `更新模板失败: ${(error as Error).message}`,
|
|
260
243
|
type: "error",
|
|
261
244
|
});
|
|
262
245
|
}
|
|
@@ -304,38 +287,24 @@ async function saveScopeTemplate() {
|
|
|
304
287
|
return;
|
|
305
288
|
}
|
|
306
289
|
|
|
307
|
-
//
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
const result = await response.json();
|
|
323
|
-
if (result.success) {
|
|
324
|
-
ElMessage({
|
|
325
|
-
message: "作用域模板保存成功!",
|
|
326
|
-
type: "success",
|
|
327
|
-
});
|
|
328
|
-
newScopeTemplate.value = "";
|
|
329
|
-
} else {
|
|
330
|
-
ElMessage({
|
|
331
|
-
message: "作用域模板保存失败: " + result.error,
|
|
332
|
-
type: "error",
|
|
333
|
-
});
|
|
290
|
+
// 使用 configStore 保存模板
|
|
291
|
+
const success = await configStore.saveTemplate(newScopeTemplate.value, 'scope');
|
|
292
|
+
|
|
293
|
+
if (success) {
|
|
294
|
+
// 确保本地数组同步更新
|
|
295
|
+
if (!scopeTemplates.value.includes(newScopeTemplate.value)) {
|
|
296
|
+
scopeTemplates.value.push(newScopeTemplate.value);
|
|
297
|
+
}
|
|
298
|
+
// 强制更新视图
|
|
299
|
+
scopeTemplates.value = [...scopeTemplates.value];
|
|
300
|
+
|
|
301
|
+
// configStore已经显示了成功消息,这里不需要重复操作
|
|
302
|
+
newScopeTemplate.value = ""; // 清空输入框,但不关闭弹窗
|
|
334
303
|
}
|
|
335
304
|
}
|
|
336
305
|
} catch (error) {
|
|
337
306
|
ElMessage({
|
|
338
|
-
message:
|
|
307
|
+
message: `保存模板失败: ${(error as Error).message}`,
|
|
339
308
|
type: "error",
|
|
340
309
|
});
|
|
341
310
|
}
|
|
@@ -343,51 +312,42 @@ async function saveScopeTemplate() {
|
|
|
343
312
|
|
|
344
313
|
// 更新作用域模板
|
|
345
314
|
async function updateScopeTemplate() {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
// 更新本地数组
|
|
354
|
-
scopeTemplates.value[editingScopeIndex.value] = newTemplate;
|
|
355
|
-
|
|
356
|
-
// 调用API更新服务器
|
|
357
|
-
const response = await fetch("/api/config/update-template", {
|
|
358
|
-
method: "POST",
|
|
359
|
-
headers: {
|
|
360
|
-
"Content-Type": "application/json",
|
|
361
|
-
},
|
|
362
|
-
body: JSON.stringify({
|
|
363
|
-
oldTemplate,
|
|
364
|
-
newTemplate,
|
|
365
|
-
type: "scope",
|
|
366
|
-
}),
|
|
367
|
-
});
|
|
315
|
+
if (!newScopeTemplate.value.trim()) {
|
|
316
|
+
ElMessage({
|
|
317
|
+
message: "请输入模板内容",
|
|
318
|
+
type: "warning",
|
|
319
|
+
});
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
368
322
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
323
|
+
try {
|
|
324
|
+
// 使用 configStore 更新模板
|
|
325
|
+
const success = await configStore.updateTemplate(
|
|
326
|
+
originalScopeTemplate.value,
|
|
327
|
+
newScopeTemplate.value,
|
|
328
|
+
'scope'
|
|
329
|
+
);
|
|
375
330
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
} else {
|
|
382
|
-
ElMessage({
|
|
383
|
-
message: "作用域模板更新失败: " + result.error,
|
|
384
|
-
type: "error",
|
|
385
|
-
});
|
|
331
|
+
if (success) {
|
|
332
|
+
// 确保本地数组同步更新
|
|
333
|
+
const index = scopeTemplates.value.indexOf(originalScopeTemplate.value);
|
|
334
|
+
if (index !== -1) {
|
|
335
|
+
scopeTemplates.value[index] = newScopeTemplate.value;
|
|
386
336
|
}
|
|
337
|
+
// 强制更新视图
|
|
338
|
+
scopeTemplates.value = [...scopeTemplates.value];
|
|
339
|
+
|
|
340
|
+
// configStore已经更新了本地数组并显示了成功消息,这里不需要重复操作
|
|
341
|
+
|
|
342
|
+
// 重置编辑状态
|
|
343
|
+
isEditingScope.value = false;
|
|
344
|
+
originalScopeTemplate.value = "";
|
|
345
|
+
editingScopeIndex.value = -1;
|
|
346
|
+
newScopeTemplate.value = "";
|
|
387
347
|
}
|
|
388
348
|
} catch (error) {
|
|
389
349
|
ElMessage({
|
|
390
|
-
message:
|
|
350
|
+
message: `更新模板失败: ${(error as Error).message}`,
|
|
391
351
|
type: "error",
|
|
392
352
|
});
|
|
393
353
|
}
|
|
@@ -412,39 +372,37 @@ function cancelEditScopeTemplate() {
|
|
|
412
372
|
// 删除描述模板
|
|
413
373
|
async function deleteDescriptionTemplate(template: string) {
|
|
414
374
|
try {
|
|
415
|
-
//
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
"Content-Type": "application/json",
|
|
426
|
-
},
|
|
427
|
-
body: JSON.stringify({
|
|
428
|
-
template,
|
|
429
|
-
type: "description",
|
|
430
|
-
}),
|
|
431
|
-
});
|
|
375
|
+
// 确认删除
|
|
376
|
+
await ElMessageBox.confirm(
|
|
377
|
+
`确定要删除描述模板 "${template}" 吗?`,
|
|
378
|
+
"删除确认",
|
|
379
|
+
{
|
|
380
|
+
confirmButtonText: "确定",
|
|
381
|
+
cancelButtonText: "取消",
|
|
382
|
+
type: "warning",
|
|
383
|
+
}
|
|
384
|
+
);
|
|
432
385
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
386
|
+
// 使用 configStore 删除模板
|
|
387
|
+
const success = await configStore.deleteTemplate(template, 'description');
|
|
388
|
+
|
|
389
|
+
if (success) {
|
|
390
|
+
// 确保本地数组同步更新
|
|
391
|
+
const index = descriptionTemplates.value.indexOf(template);
|
|
392
|
+
if (index !== -1) {
|
|
393
|
+
descriptionTemplates.value.splice(index, 1);
|
|
394
|
+
}
|
|
395
|
+
// 强制更新视图
|
|
396
|
+
descriptionTemplates.value = [...descriptionTemplates.value];
|
|
444
397
|
}
|
|
445
398
|
} catch (error) {
|
|
399
|
+
if (error === "cancel") {
|
|
400
|
+
// 用户取消删除,不做任何操作
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
|
|
446
404
|
ElMessage({
|
|
447
|
-
message:
|
|
405
|
+
message: `删除模板失败: ${(error as Error).message}`,
|
|
448
406
|
type: "error",
|
|
449
407
|
});
|
|
450
408
|
}
|
|
@@ -453,39 +411,37 @@ async function deleteDescriptionTemplate(template: string) {
|
|
|
453
411
|
// 删除作用域模板
|
|
454
412
|
async function deleteScopeTemplate(template: string) {
|
|
455
413
|
try {
|
|
456
|
-
//
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
"Content-Type": "application/json",
|
|
467
|
-
},
|
|
468
|
-
body: JSON.stringify({
|
|
469
|
-
template,
|
|
470
|
-
type: "scope",
|
|
471
|
-
}),
|
|
472
|
-
});
|
|
414
|
+
// 确认删除
|
|
415
|
+
await ElMessageBox.confirm(
|
|
416
|
+
`确定要删除作用域模板 "${template}" 吗?`,
|
|
417
|
+
"删除确认",
|
|
418
|
+
{
|
|
419
|
+
confirmButtonText: "确定",
|
|
420
|
+
cancelButtonText: "取消",
|
|
421
|
+
type: "warning",
|
|
422
|
+
}
|
|
423
|
+
);
|
|
473
424
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
425
|
+
// 使用 configStore 删除模板
|
|
426
|
+
const success = await configStore.deleteTemplate(template, 'scope');
|
|
427
|
+
|
|
428
|
+
if (success) {
|
|
429
|
+
// 确保本地数组同步更新
|
|
430
|
+
const index = scopeTemplates.value.indexOf(template);
|
|
431
|
+
if (index !== -1) {
|
|
432
|
+
scopeTemplates.value.splice(index, 1);
|
|
433
|
+
}
|
|
434
|
+
// 强制更新视图
|
|
435
|
+
scopeTemplates.value = [...scopeTemplates.value];
|
|
485
436
|
}
|
|
486
437
|
} catch (error) {
|
|
438
|
+
if (error === "cancel") {
|
|
439
|
+
// 用户取消删除,不做任何操作
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
|
|
487
443
|
ElMessage({
|
|
488
|
-
message:
|
|
444
|
+
message: `删除模板失败: ${(error as Error).message}`,
|
|
489
445
|
type: "error",
|
|
490
446
|
});
|
|
491
447
|
}
|
|
@@ -746,39 +702,26 @@ async function saveDefaultMessage() {
|
|
|
746
702
|
}
|
|
747
703
|
|
|
748
704
|
try {
|
|
749
|
-
//
|
|
750
|
-
const
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
},
|
|
755
|
-
body: JSON.stringify({
|
|
756
|
-
defaultCommitMessage: newDefaultMessage.value,
|
|
757
|
-
}),
|
|
758
|
-
});
|
|
759
|
-
|
|
760
|
-
const result = await response.json();
|
|
761
|
-
if (result.success) {
|
|
762
|
-
// 更新本地状态
|
|
705
|
+
// 使用 configStore 保存默认提交信息
|
|
706
|
+
const success = await configStore.saveDefaultMessage(newDefaultMessage.value);
|
|
707
|
+
|
|
708
|
+
if (success) {
|
|
709
|
+
// 更新本地默认提交信息
|
|
763
710
|
defaultCommitMessage.value = newDefaultMessage.value;
|
|
764
|
-
placeholder.value = `输入提交信息 (默认: ${
|
|
711
|
+
placeholder.value = `输入提交信息 (默认: ${newDefaultMessage.value})`;
|
|
765
712
|
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
713
|
+
// configStore 已经显示了成功消息,这里不需要重复显示
|
|
714
|
+
// ElMessage({
|
|
715
|
+
// message: "默认提交信息已保存",
|
|
716
|
+
// type: "success",
|
|
717
|
+
// });
|
|
770
718
|
|
|
771
|
-
//
|
|
772
|
-
|
|
773
|
-
} else {
|
|
774
|
-
ElMessage({
|
|
775
|
-
message: "保存失败: " + result.error,
|
|
776
|
-
type: "error",
|
|
777
|
-
});
|
|
719
|
+
// 关闭对话框
|
|
720
|
+
defaultMessageDialogVisible.value = false;
|
|
778
721
|
}
|
|
779
722
|
} catch (error) {
|
|
780
723
|
ElMessage({
|
|
781
|
-
message:
|
|
724
|
+
message: `保存默认提交信息失败: ${(error as Error).message}`,
|
|
782
725
|
type: "error",
|
|
783
726
|
});
|
|
784
727
|
}
|
|
@@ -1026,8 +969,6 @@ onMounted(() => {
|
|
|
1026
969
|
skipHooks.value = savedSkipHooks === "true";
|
|
1027
970
|
}
|
|
1028
971
|
|
|
1029
|
-
// 获取一次分支状态
|
|
1030
|
-
gitStore.getBranchStatus();
|
|
1031
972
|
});
|
|
1032
973
|
</script>
|
|
1033
974
|
|
|
@@ -1119,15 +1060,17 @@ git config --global user.email "your.email@example.com"</pre>
|
|
|
1119
1060
|
<!-- 标准化提交表单 -->
|
|
1120
1061
|
<div v-else class="standard-commit-form">
|
|
1121
1062
|
<div class="standard-commit-header">
|
|
1122
|
-
<
|
|
1123
|
-
<el-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
<
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1063
|
+
<div class="type-scope-container">
|
|
1064
|
+
<el-select v-model="commitType" placeholder="提交类型" class="type-select" clearable>
|
|
1065
|
+
<el-option v-for="item in commitTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
|
1066
|
+
</el-select>
|
|
1067
|
+
|
|
1068
|
+
<div class="scope-wrapper">
|
|
1069
|
+
<el-input v-model="commitScope" placeholder="作用域(可选)" class="scope-input" clearable />
|
|
1070
|
+
<el-button type="primary" :icon="Setting" circle size="small" class="settings-button"
|
|
1071
|
+
@click="openScopeSettings">
|
|
1072
|
+
</el-button>
|
|
1073
|
+
</div>
|
|
1131
1074
|
</div>
|
|
1132
1075
|
|
|
1133
1076
|
<div class="description-container">
|
|
@@ -1138,10 +1081,21 @@ git config --global user.email "your.email@example.com"</pre>
|
|
|
1138
1081
|
</div>
|
|
1139
1082
|
</div>
|
|
1140
1083
|
|
|
1141
|
-
|
|
1142
|
-
|
|
1084
|
+
<!-- 添加展开/收起高级选项的控制按钮 -->
|
|
1085
|
+
<div class="advanced-options-toggle" @click="showAdvancedFields = !showAdvancedFields">
|
|
1086
|
+
<span>{{ showAdvancedFields ? '收起' : '正文及页脚' }}</span>
|
|
1087
|
+
<el-icon class="toggle-icon" :class="{ 'is-active': showAdvancedFields }">
|
|
1088
|
+
<arrow-down />
|
|
1089
|
+
</el-icon>
|
|
1090
|
+
</div>
|
|
1091
|
+
|
|
1092
|
+
<!-- 使用过渡效果包装高级字段 -->
|
|
1093
|
+
<div v-show="showAdvancedFields" class="advanced-fields">
|
|
1094
|
+
<el-input v-model="commitBody" type="textarea" :rows="4" placeholder="正文(可选):详细描述本次提交的内容和原因" class="body-input"
|
|
1095
|
+
clearable />
|
|
1143
1096
|
|
|
1144
|
-
|
|
1097
|
+
<el-input v-model="commitFooter" placeholder="页脚(可选):如 Closes #123" class="footer-input" clearable />
|
|
1098
|
+
</div>
|
|
1145
1099
|
|
|
1146
1100
|
<div class="preview-section">
|
|
1147
1101
|
<div class="preview-title">提交信息预览:</div>
|
|
@@ -1631,19 +1585,22 @@ git config --global user.email "your.email@example.com"</pre>
|
|
|
1631
1585
|
width: 100%;
|
|
1632
1586
|
}
|
|
1633
1587
|
|
|
1634
|
-
.type-
|
|
1588
|
+
.type-scope-container {
|
|
1589
|
+
display: flex;
|
|
1590
|
+
gap: 10px;
|
|
1635
1591
|
width: 100%;
|
|
1592
|
+
margin-bottom: 10px;
|
|
1636
1593
|
}
|
|
1637
1594
|
|
|
1638
|
-
.
|
|
1595
|
+
.type-select {
|
|
1596
|
+
width: 35%; /* 提交类型占35%宽度 */
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
.scope-wrapper {
|
|
1639
1600
|
display: flex;
|
|
1640
1601
|
align-items: center;
|
|
1641
1602
|
gap: 5px;
|
|
1642
|
-
width:
|
|
1643
|
-
}
|
|
1644
|
-
|
|
1645
|
-
.scope-input {
|
|
1646
|
-
flex-grow: 1;
|
|
1603
|
+
width: 65%; /* 作用域占65%宽度 */
|
|
1647
1604
|
}
|
|
1648
1605
|
|
|
1649
1606
|
.description-container {
|
|
@@ -1653,7 +1610,7 @@ git config --global user.email "your.email@example.com"</pre>
|
|
|
1653
1610
|
width: 100%;
|
|
1654
1611
|
}
|
|
1655
1612
|
|
|
1656
|
-
.description-input {
|
|
1613
|
+
.scope-input, .description-input {
|
|
1657
1614
|
flex-grow: 1;
|
|
1658
1615
|
}
|
|
1659
1616
|
|
|
@@ -1665,7 +1622,6 @@ git config --global user.email "your.email@example.com"</pre>
|
|
|
1665
1622
|
background-color: #f5f7fa;
|
|
1666
1623
|
padding: 10px;
|
|
1667
1624
|
border-radius: 4px;
|
|
1668
|
-
margin-top: 10px;
|
|
1669
1625
|
}
|
|
1670
1626
|
|
|
1671
1627
|
.preview-title {
|
|
@@ -2091,6 +2047,51 @@ git config --global user.email "your.email@example.com"</pre>
|
|
|
2091
2047
|
margin: 8px 0;
|
|
2092
2048
|
line-height: 1.5;
|
|
2093
2049
|
}
|
|
2050
|
+
|
|
2051
|
+
.advanced-options-toggle {
|
|
2052
|
+
display: flex;
|
|
2053
|
+
align-items: center;
|
|
2054
|
+
justify-content: center;
|
|
2055
|
+
padding: 8px 0;
|
|
2056
|
+
background-color: #f5f7fa;
|
|
2057
|
+
border-radius: 4px;
|
|
2058
|
+
cursor: pointer;
|
|
2059
|
+
transition: all 0.3s ease;
|
|
2060
|
+
user-select: none;
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
.advanced-options-toggle:hover {
|
|
2064
|
+
background-color: #ebeef5;
|
|
2065
|
+
color: #409EFF;
|
|
2066
|
+
}
|
|
2067
|
+
|
|
2068
|
+
.toggle-icon {
|
|
2069
|
+
margin-left: 8px;
|
|
2070
|
+
transition: transform 0.3s ease;
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
.toggle-icon.is-active {
|
|
2074
|
+
transform: rotate(180deg);
|
|
2075
|
+
}
|
|
2076
|
+
|
|
2077
|
+
.advanced-fields {
|
|
2078
|
+
margin-top: 10px;
|
|
2079
|
+
display: flex;
|
|
2080
|
+
flex-direction: column;
|
|
2081
|
+
gap: 15px;
|
|
2082
|
+
animation: fade-in 0.3s ease-in-out;
|
|
2083
|
+
}
|
|
2084
|
+
|
|
2085
|
+
@keyframes fade-in {
|
|
2086
|
+
from {
|
|
2087
|
+
opacity: 0;
|
|
2088
|
+
transform: translateY(-10px);
|
|
2089
|
+
}
|
|
2090
|
+
to {
|
|
2091
|
+
opacity: 1;
|
|
2092
|
+
transform: translateY(0);
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2094
2095
|
</style>
|
|
2095
2096
|
|
|
2096
2097
|
<!-- 添加全局样式 -->
|
|
@@ -447,13 +447,7 @@ function getFileDirectory(path: string): string {
|
|
|
447
447
|
|
|
448
448
|
onMounted(() => {
|
|
449
449
|
// App.vue已经加载了Git相关数据,此时只需加载状态
|
|
450
|
-
// 如果已有初始目录,则只需加载状态
|
|
451
450
|
loadStatus()
|
|
452
|
-
|
|
453
|
-
// 如果是Git仓库,确保分支状态也被加载
|
|
454
|
-
if (gitStore.isGitRepo) {
|
|
455
|
-
gitStore.getBranchStatus()
|
|
456
|
-
}
|
|
457
451
|
})
|
|
458
452
|
|
|
459
453
|
// 监听autoUpdateEnabled的变化,手动调用toggleAutoUpdate
|
|
@@ -395,8 +395,7 @@ onMounted(() => {
|
|
|
395
395
|
// 加载所有可能的作者列表
|
|
396
396
|
fetchAllAuthors()
|
|
397
397
|
|
|
398
|
-
//
|
|
399
|
-
fetchAllBranches()
|
|
398
|
+
// 不再在这里直接设置 availableBranches,改为通过 watch 监听 gitStore.allBranches 的变化
|
|
400
399
|
} else {
|
|
401
400
|
errorMessage.value = '当前目录不是Git仓库'
|
|
402
401
|
}
|
|
@@ -409,6 +408,17 @@ onMounted(() => {
|
|
|
409
408
|
})
|
|
410
409
|
})
|
|
411
410
|
|
|
411
|
+
// 添加对 gitStore.allBranches 的监听
|
|
412
|
+
watch(() => gitStore.allBranches, (newBranches) => {
|
|
413
|
+
if (newBranches && newBranches.length > 0) {
|
|
414
|
+
availableBranches.value = [...newBranches].sort()
|
|
415
|
+
console.log(`分支数据更新,共 ${availableBranches.value.length} 个分支`)
|
|
416
|
+
} else {
|
|
417
|
+
availableBranches.value = []
|
|
418
|
+
console.warn('gitStore 中没有分支数据')
|
|
419
|
+
}
|
|
420
|
+
}, { immediate: true }) // immediate: true 确保组件创建时立即执行一次
|
|
421
|
+
|
|
412
422
|
onBeforeUnmount(() => {
|
|
413
423
|
// 清除表格滚动监听
|
|
414
424
|
removeTableScrollListener()
|
|
@@ -725,16 +735,17 @@ function extractAuthorsFromLogs() {
|
|
|
725
735
|
async function fetchAllBranches() {
|
|
726
736
|
try {
|
|
727
737
|
console.log('获取所有可用分支...')
|
|
728
|
-
const response = await fetch('/api/branches')
|
|
729
|
-
const result = await response.json()
|
|
730
738
|
|
|
731
|
-
|
|
739
|
+
// 直接调用 gitStore 中的方法获取分支列表
|
|
740
|
+
await gitStore.getAllBranches()
|
|
741
|
+
|
|
742
|
+
// 从 gitStore 中获取分支列表
|
|
743
|
+
if (gitStore.allBranches.length > 0) {
|
|
732
744
|
// 更新可用分支列表
|
|
733
|
-
availableBranches.value =
|
|
745
|
+
availableBranches.value = [...gitStore.allBranches].sort()
|
|
734
746
|
console.log(`获取到${availableBranches.value.length}个分支`)
|
|
735
747
|
} else {
|
|
736
|
-
console.warn('
|
|
737
|
-
extractBranchesFromLogs()
|
|
748
|
+
console.warn('gitStore中没有分支数据')
|
|
738
749
|
}
|
|
739
750
|
} catch (error) {
|
|
740
751
|
console.error('获取分支列表失败:', error)
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { defineStore } from 'pinia'
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import { ElMessage } from 'element-plus'
|
|
4
|
+
|
|
5
|
+
export const useConfigStore = defineStore('config', () => {
|
|
6
|
+
// 配置状态
|
|
7
|
+
const defaultCommitMessage = ref('')
|
|
8
|
+
const descriptionTemplates = ref<string[]>([])
|
|
9
|
+
const scopeTemplates = ref<string[]>([])
|
|
10
|
+
const messageTemplates = ref<string[]>([])
|
|
11
|
+
const isLoading = ref(false)
|
|
12
|
+
const isLoaded = ref(false)
|
|
13
|
+
|
|
14
|
+
// 加载配置
|
|
15
|
+
async function loadConfig() {
|
|
16
|
+
// 如果已经加载过,则不再重复加载
|
|
17
|
+
if (isLoaded.value && !isLoading.value) {
|
|
18
|
+
console.log('使用缓存的配置信息')
|
|
19
|
+
return {
|
|
20
|
+
defaultCommitMessage: defaultCommitMessage.value,
|
|
21
|
+
descriptionTemplates: descriptionTemplates.value,
|
|
22
|
+
scopeTemplates: scopeTemplates.value,
|
|
23
|
+
messageTemplates: messageTemplates.value
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
isLoading.value = true
|
|
29
|
+
console.log('加载配置信息...')
|
|
30
|
+
const response = await fetch('/api/config/getConfig')
|
|
31
|
+
const config = await response.json()
|
|
32
|
+
|
|
33
|
+
// 更新状态
|
|
34
|
+
defaultCommitMessage.value = config.defaultCommitMessage || ''
|
|
35
|
+
descriptionTemplates.value = config.descriptionTemplates || []
|
|
36
|
+
scopeTemplates.value = config.scopeTemplates || []
|
|
37
|
+
messageTemplates.value = config.messageTemplates || []
|
|
38
|
+
|
|
39
|
+
// 标记为已加载
|
|
40
|
+
isLoaded.value = true
|
|
41
|
+
|
|
42
|
+
console.log('配置信息加载完成')
|
|
43
|
+
return config
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error('加载配置失败:', error)
|
|
46
|
+
ElMessage.error(`加载配置失败: ${(error as Error).message}`)
|
|
47
|
+
return null
|
|
48
|
+
} finally {
|
|
49
|
+
isLoading.value = false
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// 保存默认提交信息
|
|
54
|
+
async function saveDefaultMessage(message: string) {
|
|
55
|
+
try {
|
|
56
|
+
const response = await fetch('/api/config/saveDefaultMessage', {
|
|
57
|
+
method: 'POST',
|
|
58
|
+
headers: {
|
|
59
|
+
'Content-Type': 'application/json'
|
|
60
|
+
},
|
|
61
|
+
body: JSON.stringify({ defaultCommitMessage: message })
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
const result = await response.json()
|
|
65
|
+
if (result.success) {
|
|
66
|
+
defaultCommitMessage.value = message
|
|
67
|
+
ElMessage.success('默认提交信息已保存')
|
|
68
|
+
return true
|
|
69
|
+
} else {
|
|
70
|
+
ElMessage.error(`保存失败: ${result.error}`)
|
|
71
|
+
return false
|
|
72
|
+
}
|
|
73
|
+
} catch (error) {
|
|
74
|
+
ElMessage.error(`保存失败: ${(error as Error).message}`)
|
|
75
|
+
return false
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// 保存模板
|
|
80
|
+
async function saveTemplate(template: string, type: 'description' | 'scope' | 'message') {
|
|
81
|
+
try {
|
|
82
|
+
const response = await fetch('/api/config/save-template', {
|
|
83
|
+
method: 'POST',
|
|
84
|
+
headers: {
|
|
85
|
+
'Content-Type': 'application/json'
|
|
86
|
+
},
|
|
87
|
+
body: JSON.stringify({ template, type })
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
const result = await response.json()
|
|
91
|
+
if (result.success) {
|
|
92
|
+
// 更新本地模板列表
|
|
93
|
+
if (type === 'description') {
|
|
94
|
+
if (!descriptionTemplates.value.includes(template)) {
|
|
95
|
+
descriptionTemplates.value.push(template)
|
|
96
|
+
}
|
|
97
|
+
} else if (type === 'scope') {
|
|
98
|
+
if (!scopeTemplates.value.includes(template)) {
|
|
99
|
+
scopeTemplates.value.push(template)
|
|
100
|
+
}
|
|
101
|
+
} else if (type === 'message') {
|
|
102
|
+
if (!messageTemplates.value.includes(template)) {
|
|
103
|
+
messageTemplates.value.push(template)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
ElMessage.success('模板已保存')
|
|
108
|
+
return true
|
|
109
|
+
} else {
|
|
110
|
+
ElMessage.error(`保存模板失败: ${result.error}`)
|
|
111
|
+
return false
|
|
112
|
+
}
|
|
113
|
+
} catch (error) {
|
|
114
|
+
ElMessage.error(`保存模板失败: ${(error as Error).message}`)
|
|
115
|
+
return false
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// 删除模板
|
|
120
|
+
async function deleteTemplate(template: string, type: 'description' | 'scope' | 'message') {
|
|
121
|
+
try {
|
|
122
|
+
const response = await fetch('/api/config/delete-template', {
|
|
123
|
+
method: 'POST',
|
|
124
|
+
headers: {
|
|
125
|
+
'Content-Type': 'application/json'
|
|
126
|
+
},
|
|
127
|
+
body: JSON.stringify({ template, type })
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
const result = await response.json()
|
|
131
|
+
if (result.success) {
|
|
132
|
+
// 更新本地模板列表
|
|
133
|
+
if (type === 'description') {
|
|
134
|
+
descriptionTemplates.value = descriptionTemplates.value.filter(t => t !== template)
|
|
135
|
+
} else if (type === 'scope') {
|
|
136
|
+
scopeTemplates.value = scopeTemplates.value.filter(t => t !== template)
|
|
137
|
+
} else if (type === 'message') {
|
|
138
|
+
messageTemplates.value = messageTemplates.value.filter(t => t !== template)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
ElMessage.success('模板已删除')
|
|
142
|
+
return true
|
|
143
|
+
} else {
|
|
144
|
+
ElMessage.error(`删除模板失败: ${result.error}`)
|
|
145
|
+
return false
|
|
146
|
+
}
|
|
147
|
+
} catch (error) {
|
|
148
|
+
ElMessage.error(`删除模板失败: ${(error as Error).message}`)
|
|
149
|
+
return false
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 更新模板
|
|
154
|
+
async function updateTemplate(oldTemplate: string, newTemplate: string, type: 'description' | 'scope' | 'message') {
|
|
155
|
+
try {
|
|
156
|
+
const response = await fetch('/api/config/update-template', {
|
|
157
|
+
method: 'POST',
|
|
158
|
+
headers: {
|
|
159
|
+
'Content-Type': 'application/json'
|
|
160
|
+
},
|
|
161
|
+
body: JSON.stringify({ oldTemplate, newTemplate, type })
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
const result = await response.json()
|
|
165
|
+
if (result.success) {
|
|
166
|
+
// 更新本地模板列表
|
|
167
|
+
if (type === 'description') {
|
|
168
|
+
const index = descriptionTemplates.value.indexOf(oldTemplate)
|
|
169
|
+
if (index !== -1) {
|
|
170
|
+
descriptionTemplates.value[index] = newTemplate
|
|
171
|
+
}
|
|
172
|
+
} else if (type === 'scope') {
|
|
173
|
+
const index = scopeTemplates.value.indexOf(oldTemplate)
|
|
174
|
+
if (index !== -1) {
|
|
175
|
+
scopeTemplates.value[index] = newTemplate
|
|
176
|
+
}
|
|
177
|
+
} else if (type === 'message') {
|
|
178
|
+
const index = messageTemplates.value.indexOf(oldTemplate)
|
|
179
|
+
if (index !== -1) {
|
|
180
|
+
messageTemplates.value[index] = newTemplate
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
ElMessage.success('模板已更新')
|
|
185
|
+
return true
|
|
186
|
+
} else {
|
|
187
|
+
ElMessage.error(`更新模板失败: ${result.error}`)
|
|
188
|
+
return false
|
|
189
|
+
}
|
|
190
|
+
} catch (error) {
|
|
191
|
+
ElMessage.error(`更新模板失败: ${(error as Error).message}`)
|
|
192
|
+
return false
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return {
|
|
197
|
+
// 状态
|
|
198
|
+
defaultCommitMessage,
|
|
199
|
+
descriptionTemplates,
|
|
200
|
+
scopeTemplates,
|
|
201
|
+
messageTemplates,
|
|
202
|
+
isLoading,
|
|
203
|
+
isLoaded,
|
|
204
|
+
|
|
205
|
+
// 方法
|
|
206
|
+
loadConfig,
|
|
207
|
+
saveDefaultMessage,
|
|
208
|
+
saveTemplate,
|
|
209
|
+
deleteTemplate,
|
|
210
|
+
updateTemplate
|
|
211
|
+
}
|
|
212
|
+
})
|
|
@@ -2,6 +2,10 @@ import { defineStore } from 'pinia'
|
|
|
2
2
|
import { ref } from 'vue'
|
|
3
3
|
import { ElMessage } from 'element-plus'
|
|
4
4
|
|
|
5
|
+
// 删除防抖变量
|
|
6
|
+
// let branchStatusDebounceTimer: ReturnType<typeof setTimeout> | null = null;
|
|
7
|
+
// const BRANCH_STATUS_DEBOUNCE_DELAY = 1000; // 1秒防抖延迟
|
|
8
|
+
|
|
5
9
|
export const useGitStore = defineStore('git', () => {
|
|
6
10
|
// 状态
|
|
7
11
|
const currentBranch = ref('')
|
|
@@ -18,6 +22,10 @@ export const useGitStore = defineStore('git', () => {
|
|
|
18
22
|
const branchBehind = ref(0) // 当前分支落后远程分支的提交数
|
|
19
23
|
const hasUpstream = ref(false) // 当前分支是否有上游分支
|
|
20
24
|
const upstreamBranch = ref('') // 上游分支名称
|
|
25
|
+
// 添加上次获取分支状态的时间戳
|
|
26
|
+
const lastBranchStatusTime = ref(0)
|
|
27
|
+
// 添加上次获取分支列表的时间戳
|
|
28
|
+
const lastBranchesTime = ref(0)
|
|
21
29
|
|
|
22
30
|
// 添加重置方法
|
|
23
31
|
function $reset() {
|
|
@@ -33,13 +41,17 @@ export const useGitStore = defineStore('git', () => {
|
|
|
33
41
|
branchBehind.value = 0
|
|
34
42
|
hasUpstream.value = false
|
|
35
43
|
upstreamBranch.value = ''
|
|
44
|
+
lastBranchStatusTime.value = 0
|
|
45
|
+
lastBranchesTime.value = 0
|
|
36
46
|
}
|
|
37
47
|
|
|
38
48
|
// 获取分支状态(领先/落后远程)
|
|
39
|
-
async function getBranchStatus() {
|
|
49
|
+
async function getBranchStatus(force = false) {
|
|
40
50
|
if (!isGitRepo.value) return;
|
|
41
51
|
|
|
52
|
+
// 移除时间戳缓存判断,简化逻辑
|
|
42
53
|
try {
|
|
54
|
+
console.log('获取分支状态...');
|
|
43
55
|
const response = await fetch('/api/branch-status');
|
|
44
56
|
const data = await response.json();
|
|
45
57
|
|
|
@@ -49,6 +61,9 @@ export const useGitStore = defineStore('git', () => {
|
|
|
49
61
|
hasUpstream.value = data.hasUpstream || false;
|
|
50
62
|
upstreamBranch.value = data.upstreamBranch || '';
|
|
51
63
|
|
|
64
|
+
// 更新获取时间戳
|
|
65
|
+
lastBranchStatusTime.value = Date.now();
|
|
66
|
+
|
|
52
67
|
// 添加调试日志
|
|
53
68
|
console.log(`分支状态更新:领先 ${branchAhead.value} 个提交,落后 ${branchBehind.value} 个提交,上游分支:${hasUpstream.value ? upstreamBranch.value : '无'}`);
|
|
54
69
|
}
|
|
@@ -87,14 +102,13 @@ export const useGitStore = defineStore('git', () => {
|
|
|
87
102
|
}
|
|
88
103
|
|
|
89
104
|
// 获取当前分支
|
|
90
|
-
async function getCurrentBranch() {
|
|
105
|
+
async function getCurrentBranch(skipBranchStatus = false) {
|
|
91
106
|
try {
|
|
92
107
|
const response = await fetch('/api/branch')
|
|
93
108
|
const data = await response.json()
|
|
94
109
|
if (data.branch) {
|
|
95
110
|
currentBranch.value = data.branch
|
|
96
|
-
//
|
|
97
|
-
await getBranchStatus();
|
|
111
|
+
// 不再在这里调用 getBranchStatus
|
|
98
112
|
}
|
|
99
113
|
} catch (error) {
|
|
100
114
|
console.error('获取分支信息失败:', error)
|
|
@@ -102,12 +116,19 @@ export const useGitStore = defineStore('git', () => {
|
|
|
102
116
|
}
|
|
103
117
|
|
|
104
118
|
// 获取所有分支
|
|
105
|
-
async function getAllBranches() {
|
|
119
|
+
async function getAllBranches(force = false) {
|
|
120
|
+
if (!isGitRepo.value) return;
|
|
121
|
+
|
|
122
|
+
// 移除时间戳缓存判断,简化逻辑
|
|
106
123
|
try {
|
|
124
|
+
console.log('获取所有分支...');
|
|
107
125
|
const response = await fetch('/api/branches')
|
|
108
126
|
const data = await response.json()
|
|
109
127
|
if (data.branches && Array.isArray(data.branches)) {
|
|
110
128
|
allBranches.value = data.branches
|
|
129
|
+
// 更新获取时间戳
|
|
130
|
+
lastBranchesTime.value = Date.now();
|
|
131
|
+
console.log(`获取到${data.branches.length}个分支`);
|
|
111
132
|
}
|
|
112
133
|
} catch (error) {
|
|
113
134
|
console.error('获取所有分支信息失败:', error)
|
|
@@ -135,8 +156,9 @@ export const useGitStore = defineStore('git', () => {
|
|
|
135
156
|
type: 'success'
|
|
136
157
|
})
|
|
137
158
|
|
|
138
|
-
//
|
|
139
|
-
getCurrentBranch()
|
|
159
|
+
// 分别刷新分支信息和分支状态
|
|
160
|
+
await getCurrentBranch()
|
|
161
|
+
await getBranchStatus()
|
|
140
162
|
|
|
141
163
|
return true
|
|
142
164
|
} else {
|
|
@@ -202,9 +224,10 @@ export const useGitStore = defineStore('git', () => {
|
|
|
202
224
|
type: 'success'
|
|
203
225
|
})
|
|
204
226
|
|
|
205
|
-
//
|
|
206
|
-
getCurrentBranch()
|
|
207
|
-
|
|
227
|
+
// 分别刷新分支信息和状态
|
|
228
|
+
await getCurrentBranch()
|
|
229
|
+
await getBranchStatus()
|
|
230
|
+
await getAllBranches()
|
|
208
231
|
|
|
209
232
|
return true
|
|
210
233
|
} else {
|
|
@@ -225,25 +248,6 @@ export const useGitStore = defineStore('git', () => {
|
|
|
225
248
|
}
|
|
226
249
|
}
|
|
227
250
|
|
|
228
|
-
// 初始化加载
|
|
229
|
-
async function loadInitialData() {
|
|
230
|
-
// 先检查当前目录是否是Git仓库
|
|
231
|
-
const isRepo = await checkGitRepo()
|
|
232
|
-
|
|
233
|
-
// 只有是Git仓库的情况下才加载Git相关信息
|
|
234
|
-
if (isRepo) {
|
|
235
|
-
getCurrentBranch()
|
|
236
|
-
getAllBranches()
|
|
237
|
-
getUserInfo()
|
|
238
|
-
} else {
|
|
239
|
-
// 清空所有Git相关状态
|
|
240
|
-
currentBranch.value = ''
|
|
241
|
-
allBranches.value = []
|
|
242
|
-
userName.value = ''
|
|
243
|
-
userEmail.value = ''
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
|
|
247
251
|
// 清除Git用户配置
|
|
248
252
|
async function clearUserConfig() {
|
|
249
253
|
try {
|
|
@@ -340,10 +344,19 @@ export const useGitStore = defineStore('git', () => {
|
|
|
340
344
|
await getBranchStatus();
|
|
341
345
|
return true;
|
|
342
346
|
} else {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
+
// 改进错误提示
|
|
348
|
+
if (result.needsMerge) {
|
|
349
|
+
ElMessage({
|
|
350
|
+
message: `需要合并更改: ${result.pullOutput || '存在冲突需要手动解决'}`,
|
|
351
|
+
type: 'warning',
|
|
352
|
+
duration: 5000
|
|
353
|
+
});
|
|
354
|
+
} else {
|
|
355
|
+
ElMessage({
|
|
356
|
+
message: `拉取失败: ${result.error}`,
|
|
357
|
+
type: 'error'
|
|
358
|
+
});
|
|
359
|
+
}
|
|
347
360
|
return false;
|
|
348
361
|
}
|
|
349
362
|
} catch (error) {
|
|
@@ -410,6 +423,8 @@ export const useGitStore = defineStore('git', () => {
|
|
|
410
423
|
branchBehind,
|
|
411
424
|
hasUpstream,
|
|
412
425
|
upstreamBranch,
|
|
426
|
+
lastBranchStatusTime,
|
|
427
|
+
lastBranchesTime,
|
|
413
428
|
|
|
414
429
|
// 方法
|
|
415
430
|
$reset,
|
|
@@ -419,7 +434,6 @@ export const useGitStore = defineStore('git', () => {
|
|
|
419
434
|
changeBranch,
|
|
420
435
|
getUserInfo,
|
|
421
436
|
createBranch,
|
|
422
|
-
loadInitialData,
|
|
423
437
|
clearUserConfig,
|
|
424
438
|
restoreUserConfig,
|
|
425
439
|
getBranchStatus,
|
package/src/ui/server/index.js
CHANGED
|
@@ -659,7 +659,22 @@ async function startUIServer() {
|
|
|
659
659
|
const { stdout } = await execGitCommand('git pull');
|
|
660
660
|
res.json({ success: true, message: stdout });
|
|
661
661
|
} catch (error) {
|
|
662
|
-
|
|
662
|
+
// 改进错误处理,检查是否需要合并
|
|
663
|
+
const errorMsg = error.message || '';
|
|
664
|
+
const needsMerge = errorMsg.includes('merge') ||
|
|
665
|
+
errorMsg.includes('需要合并') ||
|
|
666
|
+
errorMsg.includes('CONFLICT') ||
|
|
667
|
+
errorMsg.includes('冲突');
|
|
668
|
+
|
|
669
|
+
// 返回更详细的错误信息和标记
|
|
670
|
+
res.status(500).json({
|
|
671
|
+
success: false,
|
|
672
|
+
error: error.message,
|
|
673
|
+
needsMerge: needsMerge,
|
|
674
|
+
// 包含完整的错误输出
|
|
675
|
+
fullError: error.stderr || error.message,
|
|
676
|
+
pullOutput: error.stdout || ''
|
|
677
|
+
});
|
|
663
678
|
}
|
|
664
679
|
});
|
|
665
680
|
|