zen-gitsync 2.0.1 → 2.0.4

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.
@@ -1,17 +1,17 @@
1
1
  <script setup lang="ts">
2
- import { ref, onMounted, defineEmits, computed, watch } from "vue";
3
- import { ElMessage } from "element-plus";
4
- import { Setting } from "@element-plus/icons-vue";
5
-
6
- const emit = defineEmits(["commit-success", "push-success"]);
2
+ import { ref, onMounted, computed, watch } from "vue";
3
+ import { ElMessage, ElMessageBox } from "element-plus";
4
+ import { Setting, Plus, Upload, Refresh, Download, Edit } from "@element-plus/icons-vue";
5
+ import { useGitLogStore } from "../stores/gitLogStore";
6
+ import { useGitStore } from "../stores/gitStore";
7
+
8
+ const gitLogStore = useGitLogStore();
9
+ const gitStore = useGitStore();
10
+ const emit = defineEmits(["commit-success", "push-success", "status-update"]);
7
11
  const commitMessage = ref("");
8
- const commitBtnText = ref("提交");
9
- const pushBtnText = ref("推送到远程");
10
- const isCommitting = ref(false);
11
12
  const isPushing = ref(false);
12
13
  // 添加提交并推送的状态变量
13
14
  const isCommitAndPushing = ref(false);
14
- const commitAndPushBtnText = ref("提交并推送");
15
15
  const placeholder = ref("输入提交信息...");
16
16
  // 添加默认提交信息变量
17
17
  const defaultCommitMessage = ref("");
@@ -27,11 +27,19 @@ const descriptionTemplates = ref<string[]>([]);
27
27
  // 添加对话框可见性变量
28
28
  const descriptionDialogVisible = ref(false);
29
29
  const newTemplateName = ref("");
30
+ // 添加模板编辑相关变量
31
+ const isEditingDescription = ref(false);
32
+ const originalDescriptionTemplate = ref("");
33
+ const editingDescriptionIndex = ref(-1);
30
34
 
31
35
  // 作用域模板相关变量
32
36
  const scopeTemplates = ref<string[]>([]);
33
37
  const scopeDialogVisible = ref(false);
34
38
  const newScopeTemplate = ref("");
39
+ // 添加作用域模板编辑相关变量
40
+ const isEditingScope = ref(false);
41
+ const originalScopeTemplate = ref("");
42
+ const editingScopeIndex = ref(-1);
35
43
 
36
44
  // 跳过钩子
37
45
  const skipHooks = ref(false);
@@ -82,6 +90,19 @@ const finalCommitMessage = computed(() => {
82
90
  return message;
83
91
  });
84
92
 
93
+ // 计算Git命令预览
94
+ const gitCommandPreview = computed(() => {
95
+ // 基本命令
96
+ let command = `git commit -m "${finalCommitMessage.value}"`
97
+
98
+ // 如果跳过钩子开关打开,添加 --no-verify 参数
99
+ if (skipHooks.value) {
100
+ command += ' --no-verify'
101
+ }
102
+
103
+ return command
104
+ });
105
+
85
106
  // 加载配置
86
107
  async function loadConfig() {
87
108
  try {
@@ -119,51 +140,126 @@ async function saveDescriptionTemplate() {
119
140
  }
120
141
 
121
142
  try {
122
- // 检查是否已存在相同模板
123
- if (descriptionTemplates.value.includes(newTemplateName.value)) {
124
- ElMessage({
125
- message: "该模板已存在",
126
- type: "warning",
127
- });
128
- return;
129
- }
143
+ // 判断是编辑还是新建
144
+ if (isEditingDescription.value) {
145
+ // 编辑现有模板
146
+ await updateDescriptionTemplate();
147
+ } else {
148
+ // 新建模板
149
+ // 检查是否已存在相同模板
150
+ if (descriptionTemplates.value.includes(newTemplateName.value)) {
151
+ ElMessage({
152
+ message: "该模板已存在",
153
+ type: "warning",
154
+ });
155
+ return;
156
+ }
130
157
 
131
- // 添加到本地数组
132
- descriptionTemplates.value.push(newTemplateName.value);
158
+ // 添加到本地数组
159
+ descriptionTemplates.value.push(newTemplateName.value);
160
+
161
+ // 保存到服务器
162
+ const response = await fetch("/api/config/save-template", {
163
+ method: "POST",
164
+ headers: {
165
+ "Content-Type": "application/json",
166
+ },
167
+ body: JSON.stringify({
168
+ template: newTemplateName.value,
169
+ type: "description",
170
+ }),
171
+ });
133
172
 
134
- // 保存到服务器
135
- const response = await fetch("/api/config/save-template", {
136
- method: "POST",
137
- headers: {
138
- "Content-Type": "application/json",
139
- },
140
- body: JSON.stringify({
141
- template: newTemplateName.value,
142
- type: "description",
143
- }),
173
+ const result = await response.json();
174
+ if (result.success) {
175
+ ElMessage({
176
+ message: "模板保存成功!",
177
+ type: "success",
178
+ });
179
+ newTemplateName.value = "";
180
+ } else {
181
+ ElMessage({
182
+ message: "模板保存失败: " + result.error,
183
+ type: "error",
184
+ });
185
+ }
186
+ }
187
+ } catch (error) {
188
+ ElMessage({
189
+ message: "模板保存失败: " + (error as Error).message,
190
+ type: "error",
144
191
  });
192
+ }
193
+ }
145
194
 
146
- const result = await response.json();
147
- if (result.success) {
148
- ElMessage({
149
- message: "模板保存成功!",
150
- type: "success",
151
- });
152
- newTemplateName.value = "";
153
- } else {
154
- ElMessage({
155
- message: "模板保存失败: " + result.error,
156
- type: "error",
195
+ // 编辑描述模板
196
+ async function updateDescriptionTemplate() {
197
+ try {
198
+ // 先从本地数组中更新
199
+ if (editingDescriptionIndex.value >= 0) {
200
+ // 保存原模板和新模板
201
+ const oldTemplate = originalDescriptionTemplate.value;
202
+ const newTemplate = newTemplateName.value;
203
+
204
+ // 更新本地数组
205
+ descriptionTemplates.value[editingDescriptionIndex.value] = newTemplate;
206
+
207
+ // 调用API更新服务器
208
+ const response = await fetch("/api/config/update-template", {
209
+ method: "POST",
210
+ headers: {
211
+ "Content-Type": "application/json",
212
+ },
213
+ body: JSON.stringify({
214
+ oldTemplate,
215
+ newTemplate,
216
+ type: "description",
217
+ }),
157
218
  });
219
+
220
+ const result = await response.json();
221
+ if (result.success) {
222
+ ElMessage({
223
+ message: "模板更新成功!",
224
+ type: "success",
225
+ });
226
+
227
+ // 重置编辑状态
228
+ isEditingDescription.value = false;
229
+ originalDescriptionTemplate.value = "";
230
+ editingDescriptionIndex.value = -1;
231
+ newTemplateName.value = "";
232
+ } else {
233
+ ElMessage({
234
+ message: "模板更新失败: " + result.error,
235
+ type: "error",
236
+ });
237
+ }
158
238
  }
159
239
  } catch (error) {
160
240
  ElMessage({
161
- message: "模板保存失败: " + (error as Error).message,
241
+ message: "模板更新失败: " + (error as Error).message,
162
242
  type: "error",
163
243
  });
164
244
  }
165
245
  }
166
246
 
247
+ // 开始编辑描述模板
248
+ function startEditDescriptionTemplate(template: string, index: number) {
249
+ isEditingDescription.value = true;
250
+ originalDescriptionTemplate.value = template;
251
+ editingDescriptionIndex.value = index;
252
+ newTemplateName.value = template;
253
+ }
254
+
255
+ // 取消编辑描述模板
256
+ function cancelEditDescriptionTemplate() {
257
+ isEditingDescription.value = false;
258
+ originalDescriptionTemplate.value = "";
259
+ editingDescriptionIndex.value = -1;
260
+ newTemplateName.value = "";
261
+ }
262
+
167
263
  // 保存作用域模板
168
264
  async function saveScopeTemplate() {
169
265
  if (!newScopeTemplate.value.trim()) {
@@ -175,51 +271,126 @@ async function saveScopeTemplate() {
175
271
  }
176
272
 
177
273
  try {
178
- // 检查是否已存在相同模板
179
- if (scopeTemplates.value.includes(newScopeTemplate.value)) {
180
- ElMessage({
181
- message: "该模板已存在",
182
- type: "warning",
183
- });
184
- return;
185
- }
274
+ // 判断是编辑还是新建
275
+ if (isEditingScope.value) {
276
+ // 编辑现有模板
277
+ await updateScopeTemplate();
278
+ } else {
279
+ // 新建模板
280
+ // 检查是否已存在相同模板
281
+ if (scopeTemplates.value.includes(newScopeTemplate.value)) {
282
+ ElMessage({
283
+ message: "该模板已存在",
284
+ type: "warning",
285
+ });
286
+ return;
287
+ }
186
288
 
187
- // 添加到本地数组
188
- scopeTemplates.value.push(newScopeTemplate.value);
289
+ // 添加到本地数组
290
+ scopeTemplates.value.push(newScopeTemplate.value);
291
+
292
+ // 保存到服务器
293
+ const response = await fetch("/api/config/save-template", {
294
+ method: "POST",
295
+ headers: {
296
+ "Content-Type": "application/json",
297
+ },
298
+ body: JSON.stringify({
299
+ template: newScopeTemplate.value,
300
+ type: "scope",
301
+ }),
302
+ });
189
303
 
190
- // 保存到服务器
191
- const response = await fetch("/api/config/save-template", {
192
- method: "POST",
193
- headers: {
194
- "Content-Type": "application/json",
195
- },
196
- body: JSON.stringify({
197
- template: newScopeTemplate.value,
198
- type: "scope",
199
- }),
304
+ const result = await response.json();
305
+ if (result.success) {
306
+ ElMessage({
307
+ message: "作用域模板保存成功!",
308
+ type: "success",
309
+ });
310
+ newScopeTemplate.value = "";
311
+ } else {
312
+ ElMessage({
313
+ message: "作用域模板保存失败: " + result.error,
314
+ type: "error",
315
+ });
316
+ }
317
+ }
318
+ } catch (error) {
319
+ ElMessage({
320
+ message: "作用域模板保存失败: " + (error as Error).message,
321
+ type: "error",
200
322
  });
323
+ }
324
+ }
201
325
 
202
- const result = await response.json();
203
- if (result.success) {
204
- ElMessage({
205
- message: "作用域模板保存成功!",
206
- type: "success",
207
- });
208
- newScopeTemplate.value = "";
209
- } else {
210
- ElMessage({
211
- message: "作用域模板保存失败: " + result.error,
212
- type: "error",
326
+ // 更新作用域模板
327
+ async function updateScopeTemplate() {
328
+ try {
329
+ // 先从本地数组中更新
330
+ if (editingScopeIndex.value >= 0) {
331
+ // 保存原模板和新模板
332
+ const oldTemplate = originalScopeTemplate.value;
333
+ const newTemplate = newScopeTemplate.value;
334
+
335
+ // 更新本地数组
336
+ scopeTemplates.value[editingScopeIndex.value] = newTemplate;
337
+
338
+ // 调用API更新服务器
339
+ const response = await fetch("/api/config/update-template", {
340
+ method: "POST",
341
+ headers: {
342
+ "Content-Type": "application/json",
343
+ },
344
+ body: JSON.stringify({
345
+ oldTemplate,
346
+ newTemplate,
347
+ type: "scope",
348
+ }),
213
349
  });
350
+
351
+ const result = await response.json();
352
+ if (result.success) {
353
+ ElMessage({
354
+ message: "作用域模板更新成功!",
355
+ type: "success",
356
+ });
357
+
358
+ // 重置编辑状态
359
+ isEditingScope.value = false;
360
+ originalScopeTemplate.value = "";
361
+ editingScopeIndex.value = -1;
362
+ newScopeTemplate.value = "";
363
+ } else {
364
+ ElMessage({
365
+ message: "作用域模板更新失败: " + result.error,
366
+ type: "error",
367
+ });
368
+ }
214
369
  }
215
370
  } catch (error) {
216
371
  ElMessage({
217
- message: "作用域模板保存失败: " + (error as Error).message,
372
+ message: "作用域模板更新失败: " + (error as Error).message,
218
373
  type: "error",
219
374
  });
220
375
  }
221
376
  }
222
377
 
378
+ // 开始编辑作用域模板
379
+ function startEditScopeTemplate(template: string, index: number) {
380
+ isEditingScope.value = true;
381
+ originalScopeTemplate.value = template;
382
+ editingScopeIndex.value = index;
383
+ newScopeTemplate.value = template;
384
+ }
385
+
386
+ // 取消编辑作用域模板
387
+ function cancelEditScopeTemplate() {
388
+ isEditingScope.value = false;
389
+ originalScopeTemplate.value = "";
390
+ editingScopeIndex.value = -1;
391
+ newScopeTemplate.value = "";
392
+ }
393
+
223
394
  // 删除描述模板
224
395
  async function deleteDescriptionTemplate(template: string) {
225
396
  try {
@@ -324,231 +495,225 @@ function openScopeSettings() {
324
495
  scopeDialogVisible.value = true;
325
496
  }
326
497
 
327
-
328
- // 从localStorage加载标准化提交设置
329
- function loadCommitPreference() {
330
- const savedPreference = localStorage.getItem("zen-gitsync-standard-commit");
331
- if (savedPreference !== null) {
332
- isStandardCommit.value = savedPreference === "true";
333
- }
334
-
335
- // 加载跳过钩子设置
336
- const savedSkipHooks = localStorage.getItem("zen-gitsync-skip-hooks");
337
- if (savedSkipHooks !== null) {
338
- skipHooks.value = savedSkipHooks === "true";
498
+ // 添加文件到暂存区 (git add)
499
+ async function addToStage() {
500
+ try {
501
+ const result = await gitLogStore.addToStage();
502
+ if (result) {
503
+ // 触发状态更新事件
504
+ emit("status-update");
505
+ }
506
+ } catch (error) {
507
+ ElMessage({
508
+ message: `添加文件失败: ${(error as Error).message}`,
509
+ type: "error",
510
+ });
339
511
  }
340
512
  }
341
513
 
342
- // 提交更改
514
+ // 提交更改 (git commit)
343
515
  async function commitChanges() {
344
- const message = finalCommitMessage.value;
345
- if (!message && isStandardCommit.value && !commitDescription.value) {
516
+ if (!finalCommitMessage.value.trim()) {
346
517
  ElMessage({
347
- message: "请输入提交描述",
518
+ message: "提交信息不能为空",
348
519
  type: "warning",
349
520
  });
350
521
  return;
351
522
  }
352
523
 
353
524
  try {
354
- isCommitting.value = true;
355
- commitBtnText.value = "提交中...";
356
-
357
- // 先执行 git add .
358
- const addResponse = await fetch("/api/add", {
359
- method: "POST",
360
- });
525
+ // 使用Store提交更改
526
+ const result = await gitLogStore.commitChanges(finalCommitMessage.value, skipHooks.value);
361
527
 
362
- const addResult = await addResponse.json();
363
- if (!addResult.success) {
364
- ElMessage({
365
- message: "添加文件失败: " + addResult.error,
366
- type: "error",
367
- });
368
- return;
369
- }
370
-
371
- const response = await fetch("/api/commit", {
372
- method: "POST",
373
- headers: {
374
- "Content-Type": "application/json",
375
- },
376
- body: JSON.stringify({
377
- message,
378
- // 添加一个标志,表示消息包含换行符
379
- hasNewlines: message.includes("\n"),
380
- // 添加 no-verify 选项
381
- noVerify: skipHooks.value,
382
- }),
383
- });
384
-
385
- const result = await response.json();
386
- if (result.success) {
387
- // 清空输入
388
- if (isStandardCommit.value) {
389
- commitDescription.value = "";
390
- commitBody.value = "";
391
- commitFooter.value = "";
392
- } else {
393
- commitMessage.value = "";
394
- }
395
-
396
- ElMessage({
397
- message: "提交成功!",
398
- type: "success",
399
- });
400
- // 发出提交成功事件
528
+ if (result) {
529
+ // 清空提交信息
530
+ clearCommitFields();
531
+
532
+ // 触发成功事件
401
533
  emit("commit-success");
402
- } else {
403
- ElMessage({
404
- message: "提交失败: " + result.error,
405
- type: "error",
406
- });
534
+ // 触发状态更新事件
535
+ emit("status-update");
407
536
  }
408
537
  } catch (error) {
409
538
  ElMessage({
410
- message: "提交失败: " + (error as Error).message,
539
+ message: `提交失败: ${(error as Error).message}`,
411
540
  type: "error",
412
541
  });
413
- } finally {
414
- isCommitting.value = false;
415
- commitBtnText.value = "提交";
416
542
  }
417
543
  }
418
544
 
419
- // 推送更改
420
- async function pushChanges() {
545
+ // 推送到远程 (git push)
546
+ async function pushToRemote() {
421
547
  try {
422
- isPushing.value = true;
423
- pushBtnText.value = "推送中...";
424
-
425
- const response = await fetch("/api/push", {
426
- method: "POST",
427
- });
428
-
429
- const result = await response.json();
430
- if (result.success) {
431
- ElMessage({
432
- message: "推送成功!",
433
- type: "success",
434
- });
435
- // 发出推送成功事件
548
+ isPushing.value = true
549
+ // 使用Store推送更改
550
+ const result = await gitLogStore.pushToRemote();
551
+
552
+ if (result) {
553
+ // 触发成功事件
436
554
  emit("push-success");
437
- } else {
438
- ElMessage({
439
- message: "推送失败: " + result.error,
440
- type: "error",
441
- });
555
+ // 触发状态更新事件
556
+ emit("status-update");
442
557
  }
443
558
  } catch (error) {
444
559
  ElMessage({
445
- message: "推送失败: " + (error as Error).message,
560
+ message: `推送失败: ${(error as Error).message}`,
446
561
  type: "error",
447
562
  });
448
563
  } finally {
449
- isPushing.value = false;
450
- pushBtnText.value = "推送到远程";
564
+ isPushing.value = false
451
565
  }
452
566
  }
453
567
 
454
- // 提交并推送更改
455
- async function commitAndPush() {
456
- const message = finalCommitMessage.value;
457
- if (!message && isStandardCommit.value && !commitDescription.value) {
568
+ // 添加并提交 (git add + git commit)
569
+ async function addAndCommit() {
570
+ if (!finalCommitMessage.value.trim()) {
458
571
  ElMessage({
459
- message: "请输入提交描述",
572
+ message: "提交信息不能为空",
460
573
  type: "warning",
461
574
  });
462
575
  return;
463
576
  }
464
577
 
465
578
  try {
466
- isCommitAndPushing.value = true;
467
- commitAndPushBtnText.value = "处理中...";
579
+ const result = await gitLogStore.addAndCommit(finalCommitMessage.value, skipHooks.value);
580
+
581
+ if (result) {
582
+ // 清空提交信息
583
+ clearCommitFields();
584
+
585
+ // 触发成功事件
586
+ emit("commit-success");
587
+ // 触发状态更新事件
588
+ emit("status-update");
589
+ }
590
+ } catch (error) {
591
+ ElMessage({
592
+ message: `暂存并提交失败: ${(error as Error).message}`,
593
+ type: "error",
594
+ });
595
+ }
596
+ }
468
597
 
469
- // 先执行 git add .
470
- const addResponse = await fetch("/api/add", {
471
- method: "POST",
598
+ // 添加、提交并推送 (git add + git commit + git push)
599
+ async function addCommitAndPush() {
600
+ if (!finalCommitMessage.value.trim()) {
601
+ ElMessage({
602
+ message: "提交信息不能为空",
603
+ type: "warning",
472
604
  });
605
+ return;
606
+ }
607
+
608
+ try {
609
+ isCommitAndPushing.value = true
610
+ const result = await gitLogStore.addCommitAndPush(finalCommitMessage.value, skipHooks.value);
473
611
 
474
- const addResult = await addResponse.json();
475
- if (!addResult.success) {
476
- ElMessage({
477
- message: "添加文件失败: " + addResult.error,
478
- type: "error",
479
- });
480
- return;
612
+ if (result) {
613
+ // 清空提交信息
614
+ clearCommitFields();
615
+
616
+ // 触发成功事件
617
+ emit("commit-success");
618
+
619
+ // 添加小延迟后再触发推送成功事件,确保提交历史能够刷新
620
+ setTimeout(() => {
621
+ emit("push-success");
622
+ }, 300);
623
+
624
+ // 触发状态更新事件
625
+ emit("status-update");
481
626
  }
482
-
483
- // 再提交
484
- const commitResponse = await fetch("/api/commit", {
485
- method: "POST",
486
- headers: {
487
- "Content-Type": "application/json",
488
- },
489
- body: JSON.stringify({
490
- message,
491
- // 添加一个标志,表示消息包含换行符
492
- hasNewlines: message.includes("\n"),
493
- // 添加 no-verify 选项
494
- noVerify: skipHooks.value,
495
- }),
627
+ } catch (error) {
628
+ ElMessage({
629
+ message: `暂存、提交并推送失败: ${(error as Error).message}`,
630
+ type: "error",
496
631
  });
632
+ } finally {
633
+ isCommitAndPushing.value = false
634
+ }
635
+ }
497
636
 
498
- const commitResult = await commitResponse.json();
499
- if (!commitResult.success) {
637
+ // 重置暂存区 (git reset HEAD)
638
+ async function resetHead() {
639
+ try {
640
+ await ElMessageBox.confirm(
641
+ '确定要重置暂存区吗?这将取消所有已暂存的更改,但不会影响工作区的文件。',
642
+ '重置暂存区',
643
+ {
644
+ confirmButtonText: '确定',
645
+ cancelButtonText: '取消',
646
+ type: 'warning'
647
+ }
648
+ );
649
+
650
+ const result = await gitLogStore.resetHead();
651
+ if (result) {
652
+ // 触发状态更新事件
653
+ emit("status-update");
654
+ }
655
+ } catch (error) {
656
+ // 用户取消操作,不显示错误
657
+ if ((error as any) !== 'cancel') {
500
658
  ElMessage({
501
- message: "提交失败: " + commitResult.error,
502
- type: "error",
659
+ message: `重置暂存区失败: ${(error as Error).message}`,
660
+ type: 'error'
503
661
  });
504
- return;
505
662
  }
663
+ }
664
+ }
506
665
 
507
- // 清空输入
508
- if (isStandardCommit.value) {
509
- commitDescription.value = "";
510
- commitBody.value = "";
511
- commitFooter.value = "";
512
- } else {
513
- commitMessage.value = "";
666
+ // 重置到远程分支 (git reset --hard origin/branch)
667
+ async function resetToRemote() {
668
+ try {
669
+ await ElMessageBox.confirm(
670
+ `确定要重置当前分支 "${gitStore.currentBranch}" 到远程状态吗?这将丢失所有未推送的提交和本地更改。`,
671
+ '重置到远程分支',
672
+ {
673
+ confirmButtonText: '确定',
674
+ cancelButtonText: '取消',
675
+ type: 'warning'
676
+ }
677
+ );
678
+
679
+ const result = await gitLogStore.resetToRemote(gitStore.currentBranch);
680
+ if (result) {
681
+ // 触发状态更新事件
682
+ emit("status-update");
514
683
  }
515
-
516
- // 再推送
517
- const pushResponse = await fetch("/api/push", {
518
- method: "POST",
519
- });
520
-
521
- const pushResult = await pushResponse.json();
522
- if (pushResult.success) {
523
- commitMessage.value = "";
524
- ElMessage({
525
- message: "提交并推送成功!",
526
- type: "success",
527
- });
528
- // 发出提交和推送成功事件
529
- emit("commit-success");
530
- emit("push-success");
531
- } else {
684
+ } catch (error) {
685
+ // 用户取消操作,不显示错误
686
+ if ((error as any) !== 'cancel') {
532
687
  ElMessage({
533
- message: "推送失败: " + pushResult.error,
534
- type: "error",
688
+ message: `重置到远程分支失败: ${(error as Error).message}`,
689
+ type: 'error'
535
690
  });
536
691
  }
537
- } catch (error) {
538
- ElMessage({
539
- message: "操作失败: " + (error as Error).message,
540
- type: "error",
541
- });
542
- } finally {
543
- isCommitAndPushing.value = false;
544
- commitAndPushBtnText.value = "提交并推送";
545
692
  }
546
693
  }
547
694
 
695
+ // 清空提交字段
696
+ function clearCommitFields() {
697
+ commitMessage.value = "";
698
+ commitDescription.value = "";
699
+ commitBody.value = "";
700
+ commitFooter.value = "";
701
+ }
548
702
 
549
703
  onMounted(() => {
550
704
  loadConfig();
551
- loadCommitPreference();
705
+
706
+ // 从 localStorage 中获取标准化提交设置
707
+ const savedStandardCommit = localStorage.getItem("zen-gitsync-standard-commit");
708
+ if (savedStandardCommit !== null) {
709
+ isStandardCommit.value = savedStandardCommit === "true";
710
+ }
711
+
712
+ // 从 localStorage 中获取跳过钩子设置
713
+ const savedSkipHooks = localStorage.getItem("zen-gitsync-skip-hooks");
714
+ if (savedSkipHooks !== null) {
715
+ skipHooks.value = savedSkipHooks === "true";
716
+ }
552
717
  });
553
718
  </script>
554
719
 
@@ -557,30 +722,26 @@ onMounted(() => {
557
722
  <h2>提交更改</h2>
558
723
 
559
724
  <div class="commit-options">
560
- <div class="commit-mode-toggle">
561
- <el-switch
562
- v-model="isStandardCommit"
563
- active-text="标准化提交"
564
- inactive-text="普通提交"
565
- />
566
- </div>
725
+ <div class="options-row">
726
+ <div class="commit-mode-toggle">
727
+ <el-switch
728
+ v-model="isStandardCommit"
729
+ active-text="标准化提交"
730
+ inactive-text="普通提交"
731
+ />
732
+ </div>
567
733
 
568
- <div class="no-verify-toggle">
569
- <el-tooltip content="跳过 Git 钩子检查 (--no-verify)" placement="top">
570
- <el-switch v-model="skipHooks" active-text="跳过钩子 (--no-verify)" />
571
- </el-tooltip>
734
+ <div class="no-verify-toggle">
735
+ <el-tooltip content="跳过 Git 钩子检查 (--no-verify)" placement="top">
736
+ <el-switch v-model="skipHooks" active-text="跳过钩子 (--no-verify)" />
737
+ </el-tooltip>
738
+ </div>
572
739
  </div>
573
740
  </div>
574
741
 
575
742
  <!-- 普通提交表单 -->
576
743
  <div v-if="!isStandardCommit" class="commit-form">
577
744
  <el-input v-model="commitMessage" :placeholder="placeholder" clearable />
578
- <el-button
579
- type="primary"
580
- @click="commitChanges"
581
- :loading="isCommitting"
582
- >{{ commitBtnText }}</el-button
583
- >
584
745
  </div>
585
746
 
586
747
  <!-- 标准化提交表单 -->
@@ -654,28 +815,79 @@ onMounted(() => {
654
815
  />
655
816
 
656
817
  <div class="preview-section">
657
- <div class="preview-title">预览:</div>
818
+ <div class="preview-title">提交信息预览:</div>
658
819
  <pre class="preview-content">{{ finalCommitMessage }}</pre>
820
+
821
+ <div class="preview-title" style="margin-top: 10px;">Git命令预览:</div>
822
+ <pre class="preview-content code-command">{{ gitCommandPreview }}</pre>
659
823
  </div>
660
-
661
- <el-button
662
- type="primary"
663
- @click="commitChanges"
664
- :loading="isCommitting"
665
- >{{ commitBtnText }}</el-button
666
- >
667
824
  </div>
668
825
 
669
- <div class="button-group">
670
- <el-button type="success" @click="pushChanges" :loading="isPushing">{{
671
- pushBtnText
672
- }}</el-button>
673
- <el-button
674
- type="warning"
675
- @click="commitAndPush"
676
- :loading="isCommitAndPushing"
677
- >{{ commitAndPushBtnText }}</el-button
678
- >
826
+ <div class="git-actions">
827
+ <div class="action-row">
828
+ <el-button
829
+ type="primary"
830
+ @click="addToStage"
831
+ :loading="gitLogStore.isAddingFiles"
832
+ :icon="Plus"
833
+ >
834
+ 添加到暂存区(git add .)
835
+ </el-button>
836
+
837
+ <el-button
838
+ type="primary"
839
+ @click="commitChanges"
840
+ :loading="gitLogStore.isLoadingStatus"
841
+ >
842
+ 提交(git commit)
843
+ </el-button>
844
+
845
+ <el-button
846
+ type="success"
847
+ @click="pushToRemote"
848
+ :icon="Upload"
849
+ :loading="isPushing"
850
+ >
851
+ 推送(git push)
852
+ </el-button>
853
+ </div>
854
+
855
+ <div class="action-row">
856
+ <el-button
857
+ type="warning"
858
+ @click="addAndCommit"
859
+ >
860
+ 添加并提交(git add+commit)
861
+ </el-button>
862
+
863
+ <el-button
864
+ type="danger"
865
+ @click="addCommitAndPush"
866
+ :loading="isCommitAndPushing"
867
+ >
868
+ 添加、提交并推送(git add+commit+push)
869
+ </el-button>
870
+ </div>
871
+
872
+ <div class="action-row">
873
+ <el-button
874
+ type="info"
875
+ @click="resetHead"
876
+ :loading="gitLogStore.isResetting"
877
+ :icon="Refresh"
878
+ >
879
+ 重置暂存区(git reset HEAD)
880
+ </el-button>
881
+
882
+ <el-button
883
+ type="info"
884
+ @click="resetToRemote"
885
+ :loading="gitLogStore.isResetting"
886
+ :icon="Download"
887
+ >
888
+ 重置到远程(git reset --hard origin/branch)
889
+ </el-button>
890
+ </div>
679
891
  </div>
680
892
 
681
893
  <!-- 简短描述设置弹窗 -->
@@ -689,16 +901,23 @@ onMounted(() => {
689
901
  <div class="template-form">
690
902
  <el-input
691
903
  v-model="newTemplateName"
692
- placeholder="输入新模板内容"
904
+ :placeholder="isEditingDescription ? '编辑模板内容' : '输入新模板内容'"
693
905
  class="template-input"
694
906
  clearable
695
907
  />
696
- <el-button
697
- type="primary"
698
- @click="saveDescriptionTemplate"
699
- :disabled="!newTemplateName.trim()"
700
- >添加模板</el-button
701
- >
908
+ <div class="template-form-buttons">
909
+ <el-button
910
+ v-if="isEditingDescription"
911
+ @click="cancelEditDescriptionTemplate"
912
+ >取消</el-button
913
+ >
914
+ <el-button
915
+ type="primary"
916
+ @click="saveDescriptionTemplate"
917
+ :disabled="!newTemplateName.trim()"
918
+ >{{ isEditingDescription ? '更新模板' : '添加模板' }}</el-button
919
+ >
920
+ </div>
702
921
  </div>
703
922
 
704
923
  <div class="template-list">
@@ -722,6 +941,13 @@ onMounted(() => {
722
941
  @click="useTemplate(template)"
723
942
  >使用</el-button
724
943
  >
944
+ <el-button
945
+ type="warning"
946
+ size="small"
947
+ :icon="Edit"
948
+ @click="startEditDescriptionTemplate(template, index)"
949
+ >编辑</el-button
950
+ >
725
951
  <el-button
726
952
  type="danger"
727
953
  size="small"
@@ -746,16 +972,23 @@ onMounted(() => {
746
972
  <div class="template-form">
747
973
  <el-input
748
974
  v-model="newScopeTemplate"
749
- placeholder="输入新作用域模板"
975
+ :placeholder="isEditingScope ? '编辑作用域模板内容' : '输入新作用域模板'"
750
976
  class="template-input"
751
977
  clearable
752
978
  />
753
- <el-button
754
- type="primary"
755
- @click="saveScopeTemplate"
756
- :disabled="!newScopeTemplate.trim()"
757
- >添加模板</el-button
758
- >
979
+ <div class="template-form-buttons">
980
+ <el-button
981
+ v-if="isEditingScope"
982
+ @click="cancelEditScopeTemplate"
983
+ >取消</el-button
984
+ >
985
+ <el-button
986
+ type="primary"
987
+ @click="saveScopeTemplate"
988
+ :disabled="!newScopeTemplate.trim()"
989
+ >{{ isEditingScope ? '更新模板' : '添加模板' }}</el-button
990
+ >
991
+ </div>
759
992
  </div>
760
993
 
761
994
  <div class="template-list">
@@ -778,6 +1011,13 @@ onMounted(() => {
778
1011
  @click="useScopeTemplate(template)"
779
1012
  >使用</el-button
780
1013
  >
1014
+ <el-button
1015
+ type="warning"
1016
+ size="small"
1017
+ :icon="Edit"
1018
+ @click="startEditScopeTemplate(template, index)"
1019
+ >编辑</el-button
1020
+ >
781
1021
  <el-button
782
1022
  type="danger"
783
1023
  size="small"
@@ -794,33 +1034,55 @@ onMounted(() => {
794
1034
  </template>
795
1035
 
796
1036
  <style scoped>
1037
+ .card {
1038
+ background-color: white;
1039
+ border-radius: 5px;
1040
+ box-shadow: 0 2px 5px rgba(0,0,0,0.1);
1041
+ margin-bottom: 20px;
1042
+ padding: 20px;
1043
+ }
1044
+
797
1045
  .commit-form {
798
1046
  display: flex;
799
1047
  margin-bottom: 15px;
800
1048
  gap: 10px;
801
1049
  }
802
- .button-group {
1050
+
1051
+ .git-actions {
1052
+ margin-top: 20px;
1053
+ display: flex;
1054
+ flex-direction: column;
1055
+ gap: 10px;
1056
+ }
1057
+
1058
+ .action-row {
803
1059
  display: flex;
804
1060
  gap: 10px;
1061
+ flex-wrap: wrap;
805
1062
  }
1063
+
806
1064
  .commit-mode-toggle {
807
- margin-bottom: 15px;
1065
+ /* 移除margin-bottom */
808
1066
  }
1067
+
809
1068
  .standard-commit-form {
810
1069
  display: flex;
811
1070
  flex-direction: column;
812
1071
  gap: 15px;
813
1072
  margin-bottom: 15px;
814
1073
  }
1074
+
815
1075
  .standard-commit-header {
816
1076
  display: flex;
817
1077
  gap: 10px;
818
1078
  width: 100%;
819
1079
  }
1080
+
820
1081
  .type-select {
821
1082
  width: 120px;
822
1083
  flex-shrink: 0;
823
1084
  }
1085
+
824
1086
  .scope-container {
825
1087
  display: flex;
826
1088
  align-items: center;
@@ -828,31 +1090,38 @@ onMounted(() => {
828
1090
  flex-grow: 0;
829
1091
  width: 200px;
830
1092
  }
1093
+
831
1094
  .scope-input {
832
1095
  flex-grow: 1;
833
1096
  }
1097
+
834
1098
  .description-container {
835
1099
  display: flex;
836
1100
  align-items: center;
837
1101
  gap: 5px;
838
1102
  flex-grow: 1;
839
1103
  }
1104
+
840
1105
  .description-input {
841
1106
  flex-grow: 1;
842
1107
  min-width: 200px;
843
1108
  }
1109
+
844
1110
  .settings-button {
845
1111
  flex-shrink: 0;
846
1112
  }
1113
+
847
1114
  .preview-section {
848
1115
  background-color: #f5f7fa;
849
1116
  padding: 10px;
850
1117
  border-radius: 4px;
851
1118
  }
1119
+
852
1120
  .preview-title {
853
1121
  font-weight: bold;
854
1122
  margin-bottom: 5px;
855
1123
  }
1124
+
856
1125
  .preview-content {
857
1126
  white-space: pre-wrap;
858
1127
  font-family: monospace;
@@ -861,6 +1130,7 @@ onMounted(() => {
861
1130
  background-color: #ebeef5;
862
1131
  border-radius: 4px;
863
1132
  }
1133
+
864
1134
  .template-container {
865
1135
  display: flex;
866
1136
  flex-direction: column;
@@ -876,24 +1146,30 @@ onMounted(() => {
876
1146
  flex: 1;
877
1147
  overflow-y: auto;
878
1148
  }
1149
+
879
1150
  .template-input {
880
1151
  flex-grow: 1;
881
1152
  }
1153
+
882
1154
  .template-list {
883
1155
  overflow-y: auto;
884
1156
  height: 100%;
885
1157
  }
1158
+
886
1159
  .template-item {
887
1160
  margin-bottom: 10px;
888
1161
  }
1162
+
889
1163
  .template-item:hover {
890
1164
  background-color: #f5f7fa;
891
1165
  }
1166
+
892
1167
  .template-content {
893
1168
  flex-grow: 1;
894
1169
  margin-right: 10px;
895
1170
  word-break: break-all;
896
1171
  }
1172
+
897
1173
  .template-actions {
898
1174
  display: flex;
899
1175
  gap: 5px;
@@ -901,4 +1177,29 @@ onMounted(() => {
901
1177
  min-width: 120px;
902
1178
  flex-shrink: 0;
903
1179
  }
1180
+
1181
+ .options-row {
1182
+ display: flex;
1183
+ justify-content: space-between;
1184
+ align-items: center;
1185
+ margin-bottom: 15px;
1186
+ }
1187
+
1188
+ .code-command {
1189
+ background-color: #2d2d2d;
1190
+ color: #f8f8f2;
1191
+ font-family: 'Courier New', Courier, monospace;
1192
+ padding: 10px;
1193
+ border-radius: 4px;
1194
+ overflow-x: auto;
1195
+ white-space: pre;
1196
+ font-size: 14px;
1197
+ }
1198
+
1199
+ @media (max-width: 768px) {
1200
+ .action-row {
1201
+ flex-direction: column;
1202
+ }
1203
+ }
904
1204
  </style>
1205
+