zen-gitsync 2.0.6 → 2.0.8
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/components.d.ts +1 -0
- package/src/ui/client/src/components/CommitForm.vue +1032 -178
- package/src/ui/client/src/components/GitStatus.vue +572 -135
- package/src/ui/client/src/components/LogList.vue +907 -223
- package/src/ui/client/src/stores/gitLogStore.ts +25 -5
- package/src/ui/client/src/stores/gitStore.ts +129 -1
- package/src/ui/client/stats.html +1 -1
- package/src/ui/client/vite.config.ts +2 -0
- package/src/ui/public/assets/index-C3BbS3PG.css +1 -0
- package/src/ui/public/assets/index-P9BcPWc5.js +20 -0
- package/src/ui/public/assets/vendor-eqaTZKOh.js +45 -0
- package/src/ui/public/index.html +3 -3
- package/src/ui/server/index.js +473 -50
- package/src/ui/public/assets/index-DaPynzAr.js +0 -10
- package/src/ui/public/assets/index-qfIezZmd.css +0 -1
- package/src/ui/public/assets/vendor-BcSuWc8z.js +0 -45
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { ref, onMounted, computed, watch } from 'vue'
|
|
3
3
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
4
4
|
// import { io } from 'socket.io-client'
|
|
5
|
-
import { Refresh, ArrowLeft, ArrowRight, Folder, Document, ArrowUp, RefreshRight, Check, Close } from '@element-plus/icons-vue'
|
|
5
|
+
import { Refresh, ArrowLeft, ArrowRight, Folder, Document, ArrowUp, RefreshRight, Check, Close, Download, Connection } from '@element-plus/icons-vue'
|
|
6
6
|
import { useGitLogStore } from '../stores/gitLogStore'
|
|
7
7
|
import { useGitStore } from '../stores/gitStore'
|
|
8
8
|
|
|
@@ -38,6 +38,10 @@ const directoryItems = ref<{name: string, path: string, type: string}[]>([])
|
|
|
38
38
|
const isBrowsing = ref(false)
|
|
39
39
|
const browseErrorMessage = ref('')
|
|
40
40
|
|
|
41
|
+
// 添加git操作相关状态
|
|
42
|
+
const isGitPulling = ref(false)
|
|
43
|
+
const isGitFetching = ref(false)
|
|
44
|
+
|
|
41
45
|
const currentDirectory = ref(props.initialDirectory || '');
|
|
42
46
|
async function loadStatus() {
|
|
43
47
|
try {
|
|
@@ -56,6 +60,9 @@ async function loadStatus() {
|
|
|
56
60
|
// 使用gitLogStore获取Git状态
|
|
57
61
|
await gitLogStore.fetchStatus()
|
|
58
62
|
|
|
63
|
+
// 同时刷新分支状态信息,确保显示最新的领先/落后提交数
|
|
64
|
+
await gitStore.getBranchStatus()
|
|
65
|
+
|
|
59
66
|
ElMessage({
|
|
60
67
|
message: 'Git 状态已刷新',
|
|
61
68
|
type: 'success',
|
|
@@ -115,10 +122,41 @@ async function getFileDiff(filePath: string) {
|
|
|
115
122
|
selectedFile.value = filePath
|
|
116
123
|
// 设置当前文件索引
|
|
117
124
|
currentFileIndex.value = gitLogStore.fileList.findIndex(file => file.path === filePath)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
125
|
+
|
|
126
|
+
// 获取当前文件的状态类型
|
|
127
|
+
const currentFile = gitLogStore.fileList[currentFileIndex.value]
|
|
128
|
+
|
|
129
|
+
// 对未跟踪文件特殊处理
|
|
130
|
+
if (currentFile && currentFile.type === 'untracked') {
|
|
131
|
+
try {
|
|
132
|
+
// 获取未跟踪文件的内容
|
|
133
|
+
const response = await fetch(`/api/file-content?file=${encodeURIComponent(filePath)}`)
|
|
134
|
+
const data = await response.json()
|
|
135
|
+
|
|
136
|
+
if (data.success && data.content) {
|
|
137
|
+
// 构建一个类似diff的格式来显示新文件内容
|
|
138
|
+
diffContent.value = `diff --git a/${filePath} b/${filePath}\n` +
|
|
139
|
+
`新文件: ${filePath}\n` +
|
|
140
|
+
`--- /dev/null\n` +
|
|
141
|
+
`+++ b/${filePath}\n` +
|
|
142
|
+
`@@ -0,0 +1,${data.content.split('\n').length} @@\n` +
|
|
143
|
+
data.content.split('\n').map((line: string) => `+${line}`).join('\n')
|
|
144
|
+
} else {
|
|
145
|
+
diffContent.value = '这是一个新文件,尚未被Git跟踪。\n添加到暂存区后可以提交该文件。'
|
|
146
|
+
}
|
|
147
|
+
} catch (error) {
|
|
148
|
+
console.error('获取未跟踪文件内容失败:', error)
|
|
149
|
+
diffContent.value = '这是一个新文件,尚未被Git跟踪。\n添加到暂存区后可以提交该文件。'
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
diffDialogVisible.value = true
|
|
153
|
+
} else {
|
|
154
|
+
// 对于已跟踪的文件,获取常规差异
|
|
155
|
+
const response = await fetch(`/api/diff?file=${encodeURIComponent(filePath)}`)
|
|
156
|
+
const data = await response.json()
|
|
157
|
+
diffContent.value = data.diff || '没有变更'
|
|
158
|
+
diffDialogVisible.value = true
|
|
159
|
+
}
|
|
122
160
|
} catch (error) {
|
|
123
161
|
ElMessage({
|
|
124
162
|
message: '获取文件差异失败: ' + (error as Error).message,
|
|
@@ -318,6 +356,30 @@ async function refreshStatus() {
|
|
|
318
356
|
await loadStatus()
|
|
319
357
|
}
|
|
320
358
|
|
|
359
|
+
// 添加git pull操作方法
|
|
360
|
+
async function handleGitPull() {
|
|
361
|
+
isGitPulling.value = true
|
|
362
|
+
try {
|
|
363
|
+
await gitStore.gitPull()
|
|
364
|
+
// 刷新Git状态
|
|
365
|
+
await loadStatus()
|
|
366
|
+
} finally {
|
|
367
|
+
isGitPulling.value = false
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// 添加git fetch --all操作方法
|
|
372
|
+
async function handleGitFetchAll() {
|
|
373
|
+
isGitFetching.value = true
|
|
374
|
+
try {
|
|
375
|
+
await gitStore.gitFetchAll()
|
|
376
|
+
// 刷新Git状态
|
|
377
|
+
await loadStatus()
|
|
378
|
+
} finally {
|
|
379
|
+
isGitFetching.value = false
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
321
383
|
// 添加撤回文件修改的方法
|
|
322
384
|
async function revertFileChanges(filePath: string) {
|
|
323
385
|
try {
|
|
@@ -387,6 +449,11 @@ onMounted(() => {
|
|
|
387
449
|
// App.vue已经加载了Git相关数据,此时只需加载状态
|
|
388
450
|
// 如果已有初始目录,则只需加载状态
|
|
389
451
|
loadStatus()
|
|
452
|
+
|
|
453
|
+
// 如果是Git仓库,确保分支状态也被加载
|
|
454
|
+
if (gitStore.isGitRepo) {
|
|
455
|
+
gitStore.getBranchStatus()
|
|
456
|
+
}
|
|
390
457
|
})
|
|
391
458
|
|
|
392
459
|
// 监听autoUpdateEnabled的变化,手动调用toggleAutoUpdate
|
|
@@ -424,6 +491,32 @@ defineExpose({
|
|
|
424
491
|
class="auto-update-switch"
|
|
425
492
|
/>
|
|
426
493
|
</el-tooltip>
|
|
494
|
+
|
|
495
|
+
<!-- 添加Git Pull按钮 -->
|
|
496
|
+
<el-tooltip content="Git Pull (拉取远程更新)" placement="top" :hide-after="1000">
|
|
497
|
+
<el-button
|
|
498
|
+
type="primary"
|
|
499
|
+
:icon="Download"
|
|
500
|
+
circle
|
|
501
|
+
size="small"
|
|
502
|
+
@click="handleGitPull"
|
|
503
|
+
:loading="isGitPulling"
|
|
504
|
+
:disabled="!gitStore.hasUpstream"
|
|
505
|
+
/>
|
|
506
|
+
</el-tooltip>
|
|
507
|
+
|
|
508
|
+
<!-- 添加Git Fetch All按钮 -->
|
|
509
|
+
<el-tooltip content="Git Fetch All (获取所有远程分支)" placement="top" :hide-after="1000">
|
|
510
|
+
<el-button
|
|
511
|
+
type="info"
|
|
512
|
+
:icon="Connection"
|
|
513
|
+
circle
|
|
514
|
+
size="small"
|
|
515
|
+
@click="handleGitFetchAll"
|
|
516
|
+
:loading="isGitFetching"
|
|
517
|
+
/>
|
|
518
|
+
</el-tooltip>
|
|
519
|
+
|
|
427
520
|
<el-tooltip content="刷新状态" placement="top" :hide-after="1000">
|
|
428
521
|
<el-button
|
|
429
522
|
type="primary"
|
|
@@ -447,125 +540,180 @@ defineExpose({
|
|
|
447
540
|
</div>
|
|
448
541
|
|
|
449
542
|
<div v-if="!gitStore.isGitRepo" class="status-box">
|
|
450
|
-
|
|
543
|
+
<div class="empty-status">
|
|
544
|
+
<p>当前目录不是Git仓库</p>
|
|
545
|
+
<el-button type="primary" size="small" @click="openDirectoryDialog">
|
|
546
|
+
切换目录
|
|
547
|
+
</el-button>
|
|
548
|
+
</div>
|
|
451
549
|
</div>
|
|
452
550
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
<
|
|
467
|
-
<
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
<el-button
|
|
474
|
-
type="warning"
|
|
475
|
-
size="small"
|
|
476
|
-
circle
|
|
477
|
-
@click.stop="unstageFile(file.path)"
|
|
478
|
-
>-</el-button>
|
|
479
|
-
</el-tooltip>
|
|
551
|
+
<div v-else>
|
|
552
|
+
<!-- 分支同步状态信息 -->
|
|
553
|
+
<div v-if="gitStore.hasUpstream && (gitStore.branchAhead > 0 || gitStore.branchBehind > 0)" class="branch-sync-status">
|
|
554
|
+
<div class="sync-status-content">
|
|
555
|
+
<el-tooltip content="本地分支与远程分支的状态对比" placement="top">
|
|
556
|
+
<div class="status-badges">
|
|
557
|
+
<el-tag v-if="gitStore.branchAhead > 0" size="small" type="warning" class="status-badge">
|
|
558
|
+
<template #default>
|
|
559
|
+
<span class="badge-content">
|
|
560
|
+
<el-icon><ArrowUp /></el-icon> 你的分支领先 'origin/{{ gitStore.currentBranch }}' {{ gitStore.branchAhead }} 个提交
|
|
561
|
+
</span>
|
|
562
|
+
</template>
|
|
563
|
+
</el-tag>
|
|
564
|
+
<el-tag v-if="gitStore.branchBehind > 0" size="small" type="info" class="status-badge">
|
|
565
|
+
<template #default>
|
|
566
|
+
<span class="badge-content">
|
|
567
|
+
<el-icon><ArrowDown /></el-icon> 你的分支落后 'origin/{{ gitStore.currentBranch }}' {{ gitStore.branchBehind }} 个提交
|
|
568
|
+
</span>
|
|
569
|
+
</template>
|
|
570
|
+
</el-tag>
|
|
480
571
|
</div>
|
|
481
|
-
</
|
|
572
|
+
</el-tooltip>
|
|
482
573
|
</div>
|
|
483
574
|
</div>
|
|
484
575
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
<
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
576
|
+
<!-- 默认状态信息 -->
|
|
577
|
+
<div v-if="!gitStore.hasUpstream || (gitStore.branchAhead === 0 && gitStore.branchBehind === 0)" class="git-status-message">
|
|
578
|
+
<p>当前工作在 <el-tag size="small" type="success">{{ gitStore.currentBranch }}</el-tag> 分支</p>
|
|
579
|
+
</div>
|
|
580
|
+
|
|
581
|
+
<!-- 现代化、简洁的文件列表 -->
|
|
582
|
+
<div v-if="gitLogStore.fileList.length" class="file-list-container">
|
|
583
|
+
<!-- 分组显示文件 -->
|
|
584
|
+
<div v-if="gitLogStore.fileList.some(f => f.type === 'added')" class="file-group">
|
|
585
|
+
<div class="file-group-header">已暂存的更改</div>
|
|
586
|
+
<div class="file-list">
|
|
587
|
+
<div
|
|
588
|
+
v-for="file in gitLogStore.fileList.filter(f => f.type === 'added')"
|
|
589
|
+
:key="file.path"
|
|
590
|
+
class="file-item"
|
|
591
|
+
@click="handleFileClick(file)"
|
|
592
|
+
>
|
|
593
|
+
<div class="file-info">
|
|
594
|
+
<div class="file-path-container">
|
|
595
|
+
<span class="file-name">{{ getFileName(file.path) }}</span>
|
|
596
|
+
<span class="file-directory">{{ getFileDirectory(file.path) }}</span>
|
|
597
|
+
</div>
|
|
598
|
+
</div>
|
|
599
|
+
<div class="file-actions">
|
|
600
|
+
<el-tooltip content="取消暂存" placement="top" :hide-after="1000">
|
|
601
|
+
<el-button
|
|
602
|
+
type="warning"
|
|
603
|
+
size="small"
|
|
604
|
+
circle
|
|
605
|
+
@click.stop="unstageFile(file.path)"
|
|
606
|
+
>-</el-button>
|
|
607
|
+
</el-tooltip>
|
|
499
608
|
</div>
|
|
500
|
-
</div>
|
|
501
|
-
<div class="file-actions">
|
|
502
|
-
<el-tooltip content="添加到暂存区" placement="top" :hide-after="1000">
|
|
503
|
-
<el-button
|
|
504
|
-
type="success"
|
|
505
|
-
size="small"
|
|
506
|
-
circle
|
|
507
|
-
@click.stop="stageFile(file.path)"
|
|
508
|
-
>+</el-button>
|
|
509
|
-
</el-tooltip>
|
|
510
|
-
<el-tooltip content="撤回修改" placement="top" :hide-after="1000">
|
|
511
|
-
<el-button
|
|
512
|
-
type="danger"
|
|
513
|
-
size="small"
|
|
514
|
-
:icon="RefreshRight"
|
|
515
|
-
circle
|
|
516
|
-
@click.stop="revertFileChanges(file.path)"
|
|
517
|
-
/>
|
|
518
|
-
</el-tooltip>
|
|
519
609
|
</div>
|
|
520
610
|
</div>
|
|
521
611
|
</div>
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
612
|
+
|
|
613
|
+
<div v-if="gitLogStore.fileList.some(f => f.type === 'modified' || f.type === 'deleted')" class="file-group">
|
|
614
|
+
<div class="file-group-header">未暂存的更改</div>
|
|
615
|
+
<div class="file-list">
|
|
616
|
+
<div
|
|
617
|
+
v-for="file in gitLogStore.fileList.filter(f => f.type === 'modified' || f.type === 'deleted')"
|
|
618
|
+
:key="file.path"
|
|
619
|
+
class="file-item"
|
|
620
|
+
@click="handleFileClick(file)"
|
|
621
|
+
>
|
|
622
|
+
<div class="file-info">
|
|
623
|
+
<div class="file-status-indicator" :class="file.type"></div>
|
|
624
|
+
<div class="file-path-container">
|
|
625
|
+
<span class="file-name">{{ getFileName(file.path) }}</span>
|
|
626
|
+
<span class="file-directory">{{ getFileDirectory(file.path) }}</span>
|
|
627
|
+
</div>
|
|
628
|
+
</div>
|
|
629
|
+
<div class="file-actions">
|
|
630
|
+
<el-tooltip content="添加到暂存区" placement="top" :hide-after="1000">
|
|
631
|
+
<el-button
|
|
632
|
+
type="success"
|
|
633
|
+
size="small"
|
|
634
|
+
circle
|
|
635
|
+
@click.stop="stageFile(file.path)"
|
|
636
|
+
>+</el-button>
|
|
637
|
+
</el-tooltip>
|
|
638
|
+
<el-tooltip content="撤回修改" placement="top" :hide-after="1000">
|
|
639
|
+
<el-button
|
|
640
|
+
type="danger"
|
|
641
|
+
size="small"
|
|
642
|
+
:icon="RefreshRight"
|
|
643
|
+
circle
|
|
644
|
+
@click.stop="revertFileChanges(file.path)"
|
|
645
|
+
/>
|
|
646
|
+
</el-tooltip>
|
|
538
647
|
</div>
|
|
539
648
|
</div>
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
649
|
+
</div>
|
|
650
|
+
</div>
|
|
651
|
+
|
|
652
|
+
<div v-if="gitLogStore.fileList.some(f => f.type === 'untracked')" class="file-group">
|
|
653
|
+
<div class="file-group-header">未跟踪的文件</div>
|
|
654
|
+
<div class="file-list">
|
|
655
|
+
<div
|
|
656
|
+
v-for="file in gitLogStore.fileList.filter(f => f.type === 'untracked')"
|
|
657
|
+
:key="file.path"
|
|
658
|
+
class="file-item"
|
|
659
|
+
@click="handleFileClick(file)"
|
|
660
|
+
>
|
|
661
|
+
<div class="file-info">
|
|
662
|
+
<div class="file-status-indicator untracked"></div>
|
|
663
|
+
<div class="file-path-container">
|
|
664
|
+
<span class="file-name">{{ getFileName(file.path) }}</span>
|
|
665
|
+
<span class="file-directory">{{ getFileDirectory(file.path) }}</span>
|
|
666
|
+
</div>
|
|
667
|
+
</div>
|
|
668
|
+
<div class="file-actions">
|
|
669
|
+
<el-tooltip content="添加到暂存区" placement="top" :hide-after="1000">
|
|
670
|
+
<el-button
|
|
671
|
+
type="success"
|
|
672
|
+
size="small"
|
|
673
|
+
circle
|
|
674
|
+
@click.stop="stageFile(file.path)"
|
|
675
|
+
>+</el-button>
|
|
676
|
+
</el-tooltip>
|
|
677
|
+
<el-tooltip content="删除文件" placement="top" :hide-after="1000">
|
|
678
|
+
<el-button
|
|
679
|
+
type="danger"
|
|
680
|
+
size="small"
|
|
681
|
+
:icon="Close"
|
|
682
|
+
circle
|
|
683
|
+
@click.stop="revertFileChanges(file.path)"
|
|
684
|
+
/>
|
|
685
|
+
</el-tooltip>
|
|
686
|
+
</div>
|
|
558
687
|
</div>
|
|
559
688
|
</div>
|
|
560
689
|
</div>
|
|
561
690
|
</div>
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
691
|
+
|
|
692
|
+
<div v-else-if="gitStore.isGitRepo" class="empty-status">
|
|
693
|
+
<div class="empty-icon">
|
|
694
|
+
<el-icon><Document /></el-icon>
|
|
695
|
+
</div>
|
|
696
|
+
<div class="empty-text">没有检测到任何更改</div>
|
|
697
|
+
<div class="empty-subtext">工作区是干净的</div>
|
|
698
|
+
|
|
699
|
+
<!-- 添加分支信息 -->
|
|
700
|
+
<div class="branch-info">
|
|
701
|
+
<p>当前工作在 <el-tag size="small" type="success">{{ gitStore.currentBranch }}</el-tag> 分支</p>
|
|
702
|
+
|
|
703
|
+
<!-- 显示分支同步状态 -->
|
|
704
|
+
<div v-if="gitStore.hasUpstream">
|
|
705
|
+
<span v-if="gitStore.branchAhead > 0" class="branch-sync-info warning">
|
|
706
|
+
<el-icon><ArrowUp /></el-icon> 你的分支领先 'origin/{{ gitStore.currentBranch }}' {{ gitStore.branchAhead }} 个提交
|
|
707
|
+
</span>
|
|
708
|
+
<span v-else-if="gitStore.branchBehind > 0" class="branch-sync-info info">
|
|
709
|
+
<el-icon><ArrowDown /></el-icon> 你的分支落后 'origin/{{ gitStore.currentBranch }}' {{ gitStore.branchBehind }} 个提交
|
|
710
|
+
</span>
|
|
711
|
+
<span v-else class="branch-sync-info success">
|
|
712
|
+
<el-icon><Check /></el-icon> 你的分支与 'origin/{{ gitStore.currentBranch }}' 同步
|
|
713
|
+
</span>
|
|
714
|
+
</div>
|
|
715
|
+
</div>
|
|
567
716
|
</div>
|
|
568
|
-
<div class="empty-text">没有检测到任何更改</div>
|
|
569
717
|
</div>
|
|
570
718
|
</div>
|
|
571
719
|
|
|
@@ -648,32 +796,72 @@ defineExpose({
|
|
|
648
796
|
<!-- 文件差异对话框 -->
|
|
649
797
|
<el-dialog
|
|
650
798
|
v-model="diffDialogVisible"
|
|
651
|
-
|
|
652
|
-
|
|
799
|
+
width="80vw"
|
|
800
|
+
top="70px"
|
|
653
801
|
destroy-on-close
|
|
654
802
|
class="diff-dialog"
|
|
803
|
+
:show-close="false"
|
|
804
|
+
style="height: calc(100vh - 140px);"
|
|
805
|
+
:modal-append-to-body="false"
|
|
806
|
+
:close-on-click-modal="false"
|
|
655
807
|
>
|
|
808
|
+
<template #header>
|
|
809
|
+
<div class="diff-dialog-header">
|
|
810
|
+
<div class="file-title">
|
|
811
|
+
<el-icon class="file-icon"><Document /></el-icon>
|
|
812
|
+
<span class="file-path">{{ selectedFile }}</span>
|
|
813
|
+
</div>
|
|
814
|
+
<div class="header-actions">
|
|
815
|
+
<el-button
|
|
816
|
+
@click="diffDialogVisible = false"
|
|
817
|
+
circle
|
|
818
|
+
size="small"
|
|
819
|
+
:icon="Close"
|
|
820
|
+
class="close-button"
|
|
821
|
+
/>
|
|
822
|
+
</div>
|
|
823
|
+
</div>
|
|
824
|
+
</template>
|
|
825
|
+
|
|
656
826
|
<div v-loading="isLoadingDiff" class="diff-content">
|
|
657
827
|
<div v-if="diffContent" v-html="formatDiff(diffContent)" class="diff-formatted"></div>
|
|
658
828
|
<div v-else class="no-diff">该文件没有差异或是新文件</div>
|
|
659
829
|
</div>
|
|
660
830
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
831
|
+
<template #footer>
|
|
832
|
+
<div class="file-navigation">
|
|
833
|
+
<el-button
|
|
834
|
+
type="primary"
|
|
835
|
+
:icon="ArrowLeft"
|
|
836
|
+
@click="goToPreviousFile"
|
|
837
|
+
:disabled="currentFileIndex <= 0 || gitLogStore.fileList.length === 0"
|
|
838
|
+
plain
|
|
839
|
+
class="nav-button"
|
|
840
|
+
>
|
|
841
|
+
上一个文件
|
|
842
|
+
</el-button>
|
|
843
|
+
|
|
844
|
+
<div class="file-counter">
|
|
845
|
+
<el-tag type="info" effect="plain" class="counter-tag">
|
|
846
|
+
{{ currentFileIndex + 1 }} / {{ gitLogStore.fileList.length }}
|
|
847
|
+
</el-tag>
|
|
848
|
+
</div>
|
|
849
|
+
|
|
850
|
+
<el-button
|
|
851
|
+
type="primary"
|
|
852
|
+
:icon="ArrowRight"
|
|
853
|
+
@click="goToNextFile"
|
|
854
|
+
:disabled="currentFileIndex >= gitLogStore.fileList.length - 1 || gitLogStore.fileList.length === 0"
|
|
855
|
+
plain
|
|
856
|
+
class="nav-button"
|
|
857
|
+
>
|
|
858
|
+
下一个文件
|
|
859
|
+
<template #icon>
|
|
860
|
+
<el-icon class="el-icon--right"><ArrowRight /></el-icon>
|
|
861
|
+
</template>
|
|
862
|
+
</el-button>
|
|
863
|
+
</div>
|
|
864
|
+
</template>
|
|
677
865
|
</el-dialog>
|
|
678
866
|
</div>
|
|
679
867
|
</template>
|
|
@@ -718,6 +906,7 @@ defineExpose({
|
|
|
718
906
|
flex: 1;
|
|
719
907
|
display: flex;
|
|
720
908
|
flex-direction: column;
|
|
909
|
+
min-height: 300px; /* 确保内容区有最小高度 */
|
|
721
910
|
}
|
|
722
911
|
|
|
723
912
|
.current-directory {
|
|
@@ -764,7 +953,8 @@ defineExpose({
|
|
|
764
953
|
flex-direction: column;
|
|
765
954
|
margin-bottom: 0;
|
|
766
955
|
gap: 12px;
|
|
767
|
-
height:
|
|
956
|
+
height: auto; /* 改为自适应高度,不固定高度 */
|
|
957
|
+
min-height: 100px; /* 设置最小高度 */
|
|
768
958
|
}
|
|
769
959
|
|
|
770
960
|
.file-group {
|
|
@@ -801,6 +991,7 @@ defineExpose({
|
|
|
801
991
|
.file-list {
|
|
802
992
|
overflow-y: auto;
|
|
803
993
|
min-height: 40px; /* 最小高度 */
|
|
994
|
+
max-height: 200px; /* 最大高度限制,避免过长列表 */
|
|
804
995
|
flex-grow: 1; /* 允许文件列表在文件组内扩展 */
|
|
805
996
|
padding: 0;
|
|
806
997
|
margin: 0;
|
|
@@ -946,9 +1137,10 @@ defineExpose({
|
|
|
946
1137
|
.file-directory {
|
|
947
1138
|
font-size: 12px;
|
|
948
1139
|
color: #909399;
|
|
1140
|
+
max-width: 200px;
|
|
949
1141
|
overflow: hidden;
|
|
1142
|
+
white-space: nowrap;
|
|
950
1143
|
text-overflow: ellipsis;
|
|
951
|
-
line-height: 1.2;
|
|
952
1144
|
}
|
|
953
1145
|
|
|
954
1146
|
.file-actions {
|
|
@@ -967,22 +1159,87 @@ defineExpose({
|
|
|
967
1159
|
flex-direction: column;
|
|
968
1160
|
align-items: center;
|
|
969
1161
|
justify-content: center;
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
border:
|
|
974
|
-
margin-top:
|
|
1162
|
+
padding: 40px 20px;
|
|
1163
|
+
text-align: center;
|
|
1164
|
+
background-color: #f9f9f9;
|
|
1165
|
+
border-radius: 8px;
|
|
1166
|
+
margin-top: 10px;
|
|
975
1167
|
}
|
|
976
1168
|
|
|
977
1169
|
.empty-icon {
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
1170
|
+
width: 60px;
|
|
1171
|
+
height: 60px;
|
|
1172
|
+
display: flex;
|
|
1173
|
+
align-items: center;
|
|
1174
|
+
justify-content: center;
|
|
1175
|
+
background-color: #ebeef5;
|
|
1176
|
+
border-radius: 50%;
|
|
1177
|
+
margin-bottom: 15px;
|
|
1178
|
+
font-size: 24px;
|
|
1179
|
+
color: #909399;
|
|
1180
|
+
animation: pulse 2s infinite ease-in-out;
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
@keyframes pulse {
|
|
1184
|
+
0% { transform: scale(1); opacity: 0.7; }
|
|
1185
|
+
50% { transform: scale(1.05); opacity: 1; }
|
|
1186
|
+
100% { transform: scale(1); opacity: 0.7; }
|
|
981
1187
|
}
|
|
982
1188
|
|
|
983
1189
|
.empty-text {
|
|
1190
|
+
font-size: 16px;
|
|
1191
|
+
font-weight: 500;
|
|
1192
|
+
color: #606266;
|
|
1193
|
+
margin-bottom: 5px;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
.empty-subtext {
|
|
1197
|
+
font-size: 14px;
|
|
984
1198
|
color: #909399;
|
|
1199
|
+
margin-bottom: 20px;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
/* 分支信息样式 */
|
|
1203
|
+
.branch-info {
|
|
1204
|
+
margin-top: 15px;
|
|
1205
|
+
padding: 10px 15px;
|
|
1206
|
+
background-color: #ebeef5;
|
|
1207
|
+
border-radius: 6px;
|
|
1208
|
+
text-align: left;
|
|
1209
|
+
width: 100%;
|
|
1210
|
+
max-width: 400px;
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
.branch-info p {
|
|
1214
|
+
margin: 5px 0;
|
|
985
1215
|
font-size: 14px;
|
|
1216
|
+
color: #606266;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
.branch-sync-info {
|
|
1220
|
+
display: flex;
|
|
1221
|
+
align-items: center;
|
|
1222
|
+
gap: 5px;
|
|
1223
|
+
font-size: 13px;
|
|
1224
|
+
margin-top: 5px;
|
|
1225
|
+
padding: 5px 8px;
|
|
1226
|
+
border-radius: 4px;
|
|
1227
|
+
background-color: #f5f7fa;
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
.branch-sync-info.warning {
|
|
1231
|
+
color: #e6a23c;
|
|
1232
|
+
background-color: #fdf6ec;
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
.branch-sync-info.info {
|
|
1236
|
+
color: #909399;
|
|
1237
|
+
background-color: #f4f4f5;
|
|
1238
|
+
}
|
|
1239
|
+
|
|
1240
|
+
.branch-sync-info.success {
|
|
1241
|
+
color: #67c23a;
|
|
1242
|
+
background-color: #f0f9eb;
|
|
986
1243
|
}
|
|
987
1244
|
|
|
988
1245
|
/* 添加针对空内容区域的样式 */
|
|
@@ -1101,6 +1358,186 @@ defineExpose({
|
|
|
1101
1358
|
gap: 10px;
|
|
1102
1359
|
margin-top: 10px;
|
|
1103
1360
|
}
|
|
1361
|
+
|
|
1362
|
+
/* 添加分支状态样式 */
|
|
1363
|
+
.branch-sync-status {
|
|
1364
|
+
display: flex;
|
|
1365
|
+
align-items: center;
|
|
1366
|
+
padding: 12px 15px;
|
|
1367
|
+
background-color: #f8f9fa;
|
|
1368
|
+
border-radius: 4px;
|
|
1369
|
+
margin-bottom: 15px;
|
|
1370
|
+
border-left: 3px solid #e6a23c;
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
/* 添加默认分支状态信息样式 */
|
|
1374
|
+
.git-status-message {
|
|
1375
|
+
padding: 12px 15px;
|
|
1376
|
+
background-color: #f8f9fa;
|
|
1377
|
+
border-radius: 4px;
|
|
1378
|
+
margin-bottom: 15px;
|
|
1379
|
+
border-left: 3px solid #67c23a;
|
|
1380
|
+
}
|
|
1381
|
+
|
|
1382
|
+
.git-status-message p {
|
|
1383
|
+
margin: 0;
|
|
1384
|
+
display: flex;
|
|
1385
|
+
align-items: center;
|
|
1386
|
+
gap: 8px;
|
|
1387
|
+
font-size: 14px;
|
|
1388
|
+
color: #606266;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
.sync-status-content {
|
|
1392
|
+
display: flex;
|
|
1393
|
+
align-items: center;
|
|
1394
|
+
flex-wrap: wrap;
|
|
1395
|
+
gap: 10px;
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
.status-badges {
|
|
1399
|
+
display: flex;
|
|
1400
|
+
flex-direction: column;
|
|
1401
|
+
gap: 8px;
|
|
1402
|
+
width: 100%;
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
.status-badge {
|
|
1406
|
+
display: flex;
|
|
1407
|
+
align-items: center;
|
|
1408
|
+
width: 100%;
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
.status-badge.el-tag--warning {
|
|
1412
|
+
background-color: #fdf6ec;
|
|
1413
|
+
border-color: #faecd8;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
.status-badge.el-tag--info {
|
|
1417
|
+
background-color: #f4f4f5;
|
|
1418
|
+
border-color: #e9e9eb;
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
.badge-content {
|
|
1422
|
+
display: flex;
|
|
1423
|
+
align-items: center;
|
|
1424
|
+
gap: 6px;
|
|
1425
|
+
font-size: 13px;
|
|
1426
|
+
}
|
|
1427
|
+
.diff-dialog {
|
|
1428
|
+
height: calc(100vh - 150px);
|
|
1429
|
+
}
|
|
1430
|
+
|
|
1431
|
+
.diff-dialog-header {
|
|
1432
|
+
display: flex;
|
|
1433
|
+
justify-content: space-between;
|
|
1434
|
+
align-items: center;
|
|
1435
|
+
padding: 16px 20px;
|
|
1436
|
+
border-bottom: 1px solid #ebeef5;
|
|
1437
|
+
background-color: #f9f9fb;
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
.file-title {
|
|
1441
|
+
display: flex;
|
|
1442
|
+
align-items: center;
|
|
1443
|
+
font-size: 16px;
|
|
1444
|
+
font-weight: 500;
|
|
1445
|
+
color: #303133;
|
|
1446
|
+
gap: 10px;
|
|
1447
|
+
overflow: hidden;
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
.file-icon {
|
|
1451
|
+
color: #409eff;
|
|
1452
|
+
font-size: 20px;
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
.file-path {
|
|
1456
|
+
white-space: nowrap;
|
|
1457
|
+
overflow: hidden;
|
|
1458
|
+
text-overflow: ellipsis;
|
|
1459
|
+
font-family: monospace;
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
.diff-content {
|
|
1463
|
+
flex: 1;
|
|
1464
|
+
overflow-y: auto;
|
|
1465
|
+
padding: 10px 20px;
|
|
1466
|
+
background-color: #fafafa;
|
|
1467
|
+
/* height: 100%;
|
|
1468
|
+
overflow: auto; */
|
|
1469
|
+
}
|
|
1470
|
+
:deep(.el-dialog__body) {
|
|
1471
|
+
height: calc(100vh - 320px);
|
|
1472
|
+
overflow: auto;
|
|
1473
|
+
}
|
|
1474
|
+
.diff-formatted {
|
|
1475
|
+
font-family: 'Consolas', 'Courier New', monospace;
|
|
1476
|
+
font-size: 14px;
|
|
1477
|
+
line-height: 1.5;
|
|
1478
|
+
white-space: pre-wrap;
|
|
1479
|
+
padding-bottom: 20px;
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
.no-diff {
|
|
1483
|
+
display: flex;
|
|
1484
|
+
align-items: center;
|
|
1485
|
+
justify-content: center;
|
|
1486
|
+
height: 100%;
|
|
1487
|
+
color: #909399;
|
|
1488
|
+
font-size: 14px;
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
.file-navigation {
|
|
1492
|
+
display: flex;
|
|
1493
|
+
justify-content: space-between;
|
|
1494
|
+
align-items: center;
|
|
1495
|
+
padding: 10px 20px;
|
|
1496
|
+
border-top: 1px solid #ebeef5;
|
|
1497
|
+
background-color: #f9f9fb;
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
.counter-tag {
|
|
1501
|
+
font-family: monospace;
|
|
1502
|
+
font-size: 14px;
|
|
1503
|
+
padding: 6px 12px;
|
|
1504
|
+
min-width: 80px;
|
|
1505
|
+
text-align: center;
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
.nav-button {
|
|
1509
|
+
min-width: 120px;
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
/* 确保文件差异对话框里的内容滚动条样式一致 */
|
|
1513
|
+
.diff-formatted::-webkit-scrollbar,
|
|
1514
|
+
.diff-content::-webkit-scrollbar {
|
|
1515
|
+
width: 6px;
|
|
1516
|
+
height: 6px;
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
.diff-formatted::-webkit-scrollbar-thumb,
|
|
1520
|
+
.diff-content::-webkit-scrollbar-thumb {
|
|
1521
|
+
background-color: rgba(144, 147, 153, 0.3);
|
|
1522
|
+
border-radius: 4px;
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
.diff-formatted::-webkit-scrollbar-thumb:hover,
|
|
1526
|
+
.diff-content::-webkit-scrollbar-thumb:hover {
|
|
1527
|
+
background-color: rgba(144, 147, 153, 0.5);
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1530
|
+
.diff-formatted::-webkit-scrollbar-track,
|
|
1531
|
+
.diff-content::-webkit-scrollbar-track {
|
|
1532
|
+
background-color: transparent;
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
/* 兼容Firefox滚动条样式 */
|
|
1536
|
+
.diff-formatted,
|
|
1537
|
+
.diff-content {
|
|
1538
|
+
scrollbar-width: thin;
|
|
1539
|
+
scrollbar-color: rgba(144, 147, 153, 0.3) transparent;
|
|
1540
|
+
}
|
|
1104
1541
|
</style>
|
|
1105
1542
|
|
|
1106
1543
|
<!-- 非scoped样式,使diff格式化样式对动态内容生效 -->
|