zen-gitsync 2.0.5 → 2.0.7
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/README.md +31 -2
- package/package.json +3 -1
- package/src/ui/client/components.d.ts +1 -0
- package/src/ui/client/src/App.vue +417 -123
- package/src/ui/client/src/components/CommitForm.vue +553 -285
- package/src/ui/client/src/components/GitStatus.vue +954 -186
- package/src/ui/client/src/components/LogList.vue +1462 -169
- package/src/ui/client/src/stores/gitLogStore.ts +340 -17
- package/src/ui/client/src/stores/gitStore.ts +42 -1
- package/src/ui/client/stats.html +1 -1
- package/src/ui/client/vite.config.ts +2 -0
- package/src/ui/public/assets/index-B1vQ6PC_.js +20 -0
- package/src/ui/public/assets/index-CC5qWyQ-.css +1 -0
- package/src/ui/public/assets/vendor-BmPvvgTD.js +45 -0
- package/src/ui/public/index.html +3 -3
- package/src/ui/server/index.js +552 -54
- package/src/ui/public/assets/index-CALk9kKc.js +0 -9
- package/src/ui/public/assets/index-D3zIiSNw.css +0 -1
- package/src/ui/public/assets/vendor-BfXVsoKv.js +0 -45
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { ref, onMounted, computed } from 'vue'
|
|
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 } from '@element-plus/icons-vue'
|
|
5
|
+
import { Refresh, ArrowLeft, ArrowRight, Folder, Document, ArrowUp, RefreshRight, Check, Close } from '@element-plus/icons-vue'
|
|
6
6
|
import { useGitLogStore } from '../stores/gitLogStore'
|
|
7
7
|
import { useGitStore } from '../stores/gitStore'
|
|
8
8
|
|
|
@@ -56,6 +56,9 @@ async function loadStatus() {
|
|
|
56
56
|
// 使用gitLogStore获取Git状态
|
|
57
57
|
await gitLogStore.fetchStatus()
|
|
58
58
|
|
|
59
|
+
// 同时刷新分支状态信息,确保显示最新的领先/落后提交数
|
|
60
|
+
await gitStore.getBranchStatus()
|
|
61
|
+
|
|
59
62
|
ElMessage({
|
|
60
63
|
message: 'Git 状态已刷新',
|
|
61
64
|
type: 'success',
|
|
@@ -115,10 +118,41 @@ async function getFileDiff(filePath: string) {
|
|
|
115
118
|
selectedFile.value = filePath
|
|
116
119
|
// 设置当前文件索引
|
|
117
120
|
currentFileIndex.value = gitLogStore.fileList.findIndex(file => file.path === filePath)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
121
|
+
|
|
122
|
+
// 获取当前文件的状态类型
|
|
123
|
+
const currentFile = gitLogStore.fileList[currentFileIndex.value]
|
|
124
|
+
|
|
125
|
+
// 对未跟踪文件特殊处理
|
|
126
|
+
if (currentFile && currentFile.type === 'untracked') {
|
|
127
|
+
try {
|
|
128
|
+
// 获取未跟踪文件的内容
|
|
129
|
+
const response = await fetch(`/api/file-content?file=${encodeURIComponent(filePath)}`)
|
|
130
|
+
const data = await response.json()
|
|
131
|
+
|
|
132
|
+
if (data.success && data.content) {
|
|
133
|
+
// 构建一个类似diff的格式来显示新文件内容
|
|
134
|
+
diffContent.value = `diff --git a/${filePath} b/${filePath}\n` +
|
|
135
|
+
`新文件: ${filePath}\n` +
|
|
136
|
+
`--- /dev/null\n` +
|
|
137
|
+
`+++ b/${filePath}\n` +
|
|
138
|
+
`@@ -0,0 +1,${data.content.split('\n').length} @@\n` +
|
|
139
|
+
data.content.split('\n').map((line: string) => `+${line}`).join('\n')
|
|
140
|
+
} else {
|
|
141
|
+
diffContent.value = '这是一个新文件,尚未被Git跟踪。\n添加到暂存区后可以提交该文件。'
|
|
142
|
+
}
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.error('获取未跟踪文件内容失败:', error)
|
|
145
|
+
diffContent.value = '这是一个新文件,尚未被Git跟踪。\n添加到暂存区后可以提交该文件。'
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
diffDialogVisible.value = true
|
|
149
|
+
} else {
|
|
150
|
+
// 对于已跟踪的文件,获取常规差异
|
|
151
|
+
const response = await fetch(`/api/diff?file=${encodeURIComponent(filePath)}`)
|
|
152
|
+
const data = await response.json()
|
|
153
|
+
diffContent.value = data.diff || '没有变更'
|
|
154
|
+
diffDialogVisible.value = true
|
|
155
|
+
}
|
|
122
156
|
} catch (error) {
|
|
123
157
|
ElMessage({
|
|
124
158
|
message: '获取文件差异失败: ' + (error as Error).message,
|
|
@@ -303,15 +337,14 @@ function handleFileClick(file: {path: string, type: string}) {
|
|
|
303
337
|
getFileDiff(file.path)
|
|
304
338
|
}
|
|
305
339
|
|
|
306
|
-
//
|
|
307
|
-
function
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
}
|
|
340
|
+
// 暂存单个文件
|
|
341
|
+
async function stageFile(filePath: string) {
|
|
342
|
+
await gitLogStore.addFileToStage(filePath)
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// 取消暂存单个文件
|
|
346
|
+
async function unstageFile(filePath: string) {
|
|
347
|
+
await gitLogStore.unstageFile(filePath)
|
|
315
348
|
}
|
|
316
349
|
|
|
317
350
|
// 刷新Git状态的方法
|
|
@@ -349,26 +382,62 @@ async function revertFileChanges(filePath: string) {
|
|
|
349
382
|
// 刷新Git状态
|
|
350
383
|
await loadStatus()
|
|
351
384
|
} else {
|
|
352
|
-
|
|
385
|
+
// 使用自定义错误信息,避免显示undefined
|
|
386
|
+
ElMessage.error(result.error ? `撤回失败: ${result.error}` : '撤回文件修改失败,请重试')
|
|
353
387
|
}
|
|
354
388
|
} catch (error) {
|
|
355
|
-
//
|
|
356
|
-
if ((error as Error).message
|
|
357
|
-
|
|
389
|
+
// 用户取消操作不显示错误
|
|
390
|
+
if ((error as any) === 'cancel' || (error as Error).message === 'cancel') {
|
|
391
|
+
// 用户取消操作,不做任何处理,也不显示错误
|
|
392
|
+
return
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// 其他错误情况才显示错误消息
|
|
396
|
+
// 避免显示undefined错误信息
|
|
397
|
+
const errorMessage = (error as Error).message || '未知错误';
|
|
398
|
+
if (errorMessage !== 'undefined') {
|
|
399
|
+
ElMessage.error(`撤回文件修改失败: ${errorMessage}`)
|
|
400
|
+
} else {
|
|
401
|
+
ElMessage.error('撤回文件修改失败,请重试')
|
|
358
402
|
}
|
|
359
403
|
}
|
|
360
404
|
}
|
|
361
405
|
|
|
406
|
+
// 提取文件名和目录
|
|
407
|
+
function getFileName(path: string): string {
|
|
408
|
+
const parts = path.split('/')
|
|
409
|
+
return parts[parts.length - 1]
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function getFileDirectory(path: string): string {
|
|
413
|
+
const parts = path.split('/')
|
|
414
|
+
if (parts.length <= 1) return ''
|
|
415
|
+
|
|
416
|
+
// 保留所有除最后一个部分的路径
|
|
417
|
+
return parts.slice(0, -1).join('/')
|
|
418
|
+
}
|
|
419
|
+
|
|
362
420
|
onMounted(() => {
|
|
363
421
|
// App.vue已经加载了Git相关数据,此时只需加载状态
|
|
364
422
|
// 如果已有初始目录,则只需加载状态
|
|
365
423
|
loadStatus()
|
|
424
|
+
|
|
425
|
+
// 如果是Git仓库,确保分支状态也被加载
|
|
426
|
+
if (gitStore.isGitRepo) {
|
|
427
|
+
gitStore.getBranchStatus()
|
|
428
|
+
}
|
|
366
429
|
})
|
|
367
430
|
|
|
431
|
+
// 监听autoUpdateEnabled的变化,手动调用toggleAutoUpdate
|
|
432
|
+
watch(() => gitLogStore.autoUpdateEnabled, (newValue, oldValue) => {
|
|
433
|
+
console.log(`自动更新状态变更: ${oldValue} -> ${newValue}`)
|
|
434
|
+
// 调用store中的方法来实现服务器通信功能
|
|
435
|
+
gitLogStore.toggleAutoUpdate()
|
|
436
|
+
}, { immediate: false })
|
|
437
|
+
|
|
368
438
|
// onUnmounted(() => {
|
|
369
439
|
// socket.disconnect()
|
|
370
440
|
// })
|
|
371
|
-
|
|
372
441
|
// 暴露刷新方法给父组件
|
|
373
442
|
defineExpose({
|
|
374
443
|
refreshStatus
|
|
@@ -377,48 +446,219 @@ defineExpose({
|
|
|
377
446
|
|
|
378
447
|
<template>
|
|
379
448
|
<div class="card">
|
|
380
|
-
<div class="current-directory">
|
|
381
|
-
<el-icon><Folder /></el-icon>
|
|
382
|
-
<span>{{ currentDirectory }}</span>
|
|
383
|
-
<el-button type="primary" size="small" @click="openDirectoryDialog" plain>
|
|
384
|
-
切换目录
|
|
385
|
-
</el-button>
|
|
386
|
-
</div>
|
|
387
449
|
<div class="status-header">
|
|
388
|
-
<h2>Git
|
|
389
|
-
<
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
450
|
+
<h2>Git 状态</h2>
|
|
451
|
+
<div class="header-actions">
|
|
452
|
+
<el-tooltip
|
|
453
|
+
:content="gitLogStore.autoUpdateEnabled ? '禁用自动更新文件状态' : '启用自动更新文件状态'"
|
|
454
|
+
placement="top"
|
|
455
|
+
:hide-after="1000"
|
|
456
|
+
>
|
|
457
|
+
<el-switch
|
|
458
|
+
v-model="gitLogStore.autoUpdateEnabled"
|
|
459
|
+
style="--el-switch-on-color: #67C23A; --el-switch-off-color: #909399; margin-right: 10px;"
|
|
460
|
+
inline-prompt
|
|
461
|
+
:active-icon="Check"
|
|
462
|
+
:inactive-icon="Close"
|
|
463
|
+
class="auto-update-switch"
|
|
464
|
+
/>
|
|
465
|
+
</el-tooltip>
|
|
466
|
+
<el-tooltip content="刷新状态" placement="top" :hide-after="1000">
|
|
467
|
+
<el-button
|
|
468
|
+
type="primary"
|
|
469
|
+
:icon="Refresh"
|
|
470
|
+
circle
|
|
471
|
+
size="small"
|
|
472
|
+
@click="refreshStatus"
|
|
473
|
+
:loading="isRefreshing"
|
|
474
|
+
/>
|
|
475
|
+
</el-tooltip>
|
|
476
|
+
</div>
|
|
400
477
|
</div>
|
|
401
|
-
|
|
402
|
-
<div
|
|
403
|
-
<div
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
478
|
+
|
|
479
|
+
<div class="card-content">
|
|
480
|
+
<div class="current-directory">
|
|
481
|
+
<el-icon><Folder /></el-icon>
|
|
482
|
+
<span>{{ currentDirectory }}</span>
|
|
483
|
+
<el-button type="primary" size="small" @click="openDirectoryDialog" plain>
|
|
484
|
+
切换目录
|
|
485
|
+
</el-button>
|
|
486
|
+
</div>
|
|
487
|
+
|
|
488
|
+
<div v-if="!gitStore.isGitRepo" class="status-box">
|
|
489
|
+
<div class="empty-status">
|
|
490
|
+
<p>当前目录不是Git仓库</p>
|
|
491
|
+
<el-button type="primary" size="small" @click="openDirectoryDialog">
|
|
492
|
+
切换目录
|
|
493
|
+
</el-button>
|
|
411
494
|
</div>
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
495
|
+
</div>
|
|
496
|
+
|
|
497
|
+
<div v-else>
|
|
498
|
+
<!-- 分支同步状态信息 -->
|
|
499
|
+
<div v-if="gitStore.hasUpstream && (gitStore.branchAhead > 0 || gitStore.branchBehind > 0)" class="branch-sync-status">
|
|
500
|
+
<div class="sync-status-content">
|
|
501
|
+
<el-tooltip content="本地分支与远程分支的状态对比" placement="top">
|
|
502
|
+
<div class="status-badges">
|
|
503
|
+
<el-tag v-if="gitStore.branchAhead > 0" size="small" type="warning" class="status-badge">
|
|
504
|
+
<template #default>
|
|
505
|
+
<span class="badge-content">
|
|
506
|
+
<el-icon><ArrowUp /></el-icon> 你的分支领先 'origin/{{ gitStore.currentBranch }}' {{ gitStore.branchAhead }} 个提交
|
|
507
|
+
</span>
|
|
508
|
+
</template>
|
|
509
|
+
</el-tag>
|
|
510
|
+
<el-tag v-if="gitStore.branchBehind > 0" size="small" type="info" class="status-badge">
|
|
511
|
+
<template #default>
|
|
512
|
+
<span class="badge-content">
|
|
513
|
+
<el-icon><ArrowDown /></el-icon> 你的分支落后 'origin/{{ gitStore.currentBranch }}' {{ gitStore.branchBehind }} 个提交
|
|
514
|
+
</span>
|
|
515
|
+
</template>
|
|
516
|
+
</el-tag>
|
|
517
|
+
</div>
|
|
518
|
+
</el-tooltip>
|
|
519
|
+
</div>
|
|
520
|
+
</div>
|
|
521
|
+
|
|
522
|
+
<!-- 默认状态信息 -->
|
|
523
|
+
<div v-if="!gitStore.hasUpstream || (gitStore.branchAhead === 0 && gitStore.branchBehind === 0)" class="git-status-message">
|
|
524
|
+
<p>当前工作在 <el-tag size="small" type="success">{{ gitStore.currentBranch }}</el-tag> 分支</p>
|
|
525
|
+
</div>
|
|
526
|
+
|
|
527
|
+
<!-- 现代化、简洁的文件列表 -->
|
|
528
|
+
<div v-if="gitLogStore.fileList.length" class="file-list-container">
|
|
529
|
+
<!-- 分组显示文件 -->
|
|
530
|
+
<div v-if="gitLogStore.fileList.some(f => f.type === 'added')" class="file-group">
|
|
531
|
+
<div class="file-group-header">已暂存的更改</div>
|
|
532
|
+
<div class="file-list">
|
|
533
|
+
<div
|
|
534
|
+
v-for="file in gitLogStore.fileList.filter(f => f.type === 'added')"
|
|
535
|
+
:key="file.path"
|
|
536
|
+
class="file-item"
|
|
537
|
+
@click="handleFileClick(file)"
|
|
538
|
+
>
|
|
539
|
+
<div class="file-info">
|
|
540
|
+
<div class="file-path-container">
|
|
541
|
+
<span class="file-name">{{ getFileName(file.path) }}</span>
|
|
542
|
+
<span class="file-directory">{{ getFileDirectory(file.path) }}</span>
|
|
543
|
+
</div>
|
|
544
|
+
</div>
|
|
545
|
+
<div class="file-actions">
|
|
546
|
+
<el-tooltip content="取消暂存" placement="top" :hide-after="1000">
|
|
547
|
+
<el-button
|
|
548
|
+
type="warning"
|
|
549
|
+
size="small"
|
|
550
|
+
circle
|
|
551
|
+
@click.stop="unstageFile(file.path)"
|
|
552
|
+
>-</el-button>
|
|
553
|
+
</el-tooltip>
|
|
554
|
+
</div>
|
|
555
|
+
</div>
|
|
556
|
+
</div>
|
|
557
|
+
</div>
|
|
558
|
+
|
|
559
|
+
<div v-if="gitLogStore.fileList.some(f => f.type === 'modified' || f.type === 'deleted')" class="file-group">
|
|
560
|
+
<div class="file-group-header">未暂存的更改</div>
|
|
561
|
+
<div class="file-list">
|
|
562
|
+
<div
|
|
563
|
+
v-for="file in gitLogStore.fileList.filter(f => f.type === 'modified' || f.type === 'deleted')"
|
|
564
|
+
:key="file.path"
|
|
565
|
+
class="file-item"
|
|
566
|
+
@click="handleFileClick(file)"
|
|
567
|
+
>
|
|
568
|
+
<div class="file-info">
|
|
569
|
+
<div class="file-status-indicator" :class="file.type"></div>
|
|
570
|
+
<div class="file-path-container">
|
|
571
|
+
<span class="file-name">{{ getFileName(file.path) }}</span>
|
|
572
|
+
<span class="file-directory">{{ getFileDirectory(file.path) }}</span>
|
|
573
|
+
</div>
|
|
574
|
+
</div>
|
|
575
|
+
<div class="file-actions">
|
|
576
|
+
<el-tooltip content="添加到暂存区" placement="top" :hide-after="1000">
|
|
577
|
+
<el-button
|
|
578
|
+
type="success"
|
|
579
|
+
size="small"
|
|
580
|
+
circle
|
|
581
|
+
@click.stop="stageFile(file.path)"
|
|
582
|
+
>+</el-button>
|
|
583
|
+
</el-tooltip>
|
|
584
|
+
<el-tooltip content="撤回修改" placement="top" :hide-after="1000">
|
|
585
|
+
<el-button
|
|
586
|
+
type="danger"
|
|
587
|
+
size="small"
|
|
588
|
+
:icon="RefreshRight"
|
|
589
|
+
circle
|
|
590
|
+
@click.stop="revertFileChanges(file.path)"
|
|
591
|
+
/>
|
|
592
|
+
</el-tooltip>
|
|
593
|
+
</div>
|
|
594
|
+
</div>
|
|
595
|
+
</div>
|
|
596
|
+
</div>
|
|
597
|
+
|
|
598
|
+
<div v-if="gitLogStore.fileList.some(f => f.type === 'untracked')" class="file-group">
|
|
599
|
+
<div class="file-group-header">未跟踪的文件</div>
|
|
600
|
+
<div class="file-list">
|
|
601
|
+
<div
|
|
602
|
+
v-for="file in gitLogStore.fileList.filter(f => f.type === 'untracked')"
|
|
603
|
+
:key="file.path"
|
|
604
|
+
class="file-item"
|
|
605
|
+
@click="handleFileClick(file)"
|
|
606
|
+
>
|
|
607
|
+
<div class="file-info">
|
|
608
|
+
<div class="file-status-indicator untracked"></div>
|
|
609
|
+
<div class="file-path-container">
|
|
610
|
+
<span class="file-name">{{ getFileName(file.path) }}</span>
|
|
611
|
+
<span class="file-directory">{{ getFileDirectory(file.path) }}</span>
|
|
612
|
+
</div>
|
|
613
|
+
</div>
|
|
614
|
+
<div class="file-actions">
|
|
615
|
+
<el-tooltip content="添加到暂存区" placement="top" :hide-after="1000">
|
|
616
|
+
<el-button
|
|
617
|
+
type="success"
|
|
618
|
+
size="small"
|
|
619
|
+
circle
|
|
620
|
+
@click.stop="stageFile(file.path)"
|
|
621
|
+
>+</el-button>
|
|
622
|
+
</el-tooltip>
|
|
623
|
+
<el-tooltip content="删除文件" placement="top" :hide-after="1000">
|
|
624
|
+
<el-button
|
|
625
|
+
type="danger"
|
|
626
|
+
size="small"
|
|
627
|
+
:icon="Close"
|
|
628
|
+
circle
|
|
629
|
+
@click.stop="revertFileChanges(file.path)"
|
|
630
|
+
/>
|
|
631
|
+
</el-tooltip>
|
|
632
|
+
</div>
|
|
633
|
+
</div>
|
|
634
|
+
</div>
|
|
635
|
+
</div>
|
|
636
|
+
</div>
|
|
637
|
+
|
|
638
|
+
<div v-else-if="gitStore.isGitRepo" class="empty-status">
|
|
639
|
+
<div class="empty-icon">
|
|
640
|
+
<el-icon><Document /></el-icon>
|
|
641
|
+
</div>
|
|
642
|
+
<div class="empty-text">没有检测到任何更改</div>
|
|
643
|
+
<div class="empty-subtext">工作区是干净的</div>
|
|
644
|
+
|
|
645
|
+
<!-- 添加分支信息 -->
|
|
646
|
+
<div class="branch-info">
|
|
647
|
+
<p>当前工作在 <el-tag size="small" type="success">{{ gitStore.currentBranch }}</el-tag> 分支</p>
|
|
648
|
+
|
|
649
|
+
<!-- 显示分支同步状态 -->
|
|
650
|
+
<div v-if="gitStore.hasUpstream">
|
|
651
|
+
<span v-if="gitStore.branchAhead > 0" class="branch-sync-info warning">
|
|
652
|
+
<el-icon><ArrowUp /></el-icon> 你的分支领先 'origin/{{ gitStore.currentBranch }}' {{ gitStore.branchAhead }} 个提交
|
|
653
|
+
</span>
|
|
654
|
+
<span v-else-if="gitStore.branchBehind > 0" class="branch-sync-info info">
|
|
655
|
+
<el-icon><ArrowDown /></el-icon> 你的分支落后 'origin/{{ gitStore.currentBranch }}' {{ gitStore.branchBehind }} 个提交
|
|
656
|
+
</span>
|
|
657
|
+
<span v-else class="branch-sync-info success">
|
|
658
|
+
<el-icon><Check /></el-icon> 你的分支与 'origin/{{ gitStore.currentBranch }}' 同步
|
|
659
|
+
</span>
|
|
660
|
+
</div>
|
|
661
|
+
</div>
|
|
422
662
|
</div>
|
|
423
663
|
</div>
|
|
424
664
|
</div>
|
|
@@ -502,31 +742,72 @@ defineExpose({
|
|
|
502
742
|
<!-- 文件差异对话框 -->
|
|
503
743
|
<el-dialog
|
|
504
744
|
v-model="diffDialogVisible"
|
|
505
|
-
|
|
506
|
-
|
|
745
|
+
width="85%"
|
|
746
|
+
top="5vh"
|
|
507
747
|
destroy-on-close
|
|
748
|
+
class="diff-dialog"
|
|
749
|
+
:show-close="false"
|
|
750
|
+
style="height: calc(100vh - 150px);"
|
|
751
|
+
:modal-append-to-body="false"
|
|
752
|
+
:close-on-click-modal="false"
|
|
508
753
|
>
|
|
754
|
+
<template #header>
|
|
755
|
+
<div class="diff-dialog-header">
|
|
756
|
+
<div class="file-title">
|
|
757
|
+
<el-icon class="file-icon"><Document /></el-icon>
|
|
758
|
+
<span class="file-path">{{ selectedFile }}</span>
|
|
759
|
+
</div>
|
|
760
|
+
<div class="header-actions">
|
|
761
|
+
<el-button
|
|
762
|
+
@click="diffDialogVisible = false"
|
|
763
|
+
circle
|
|
764
|
+
size="small"
|
|
765
|
+
:icon="Close"
|
|
766
|
+
class="close-button"
|
|
767
|
+
/>
|
|
768
|
+
</div>
|
|
769
|
+
</div>
|
|
770
|
+
</template>
|
|
771
|
+
|
|
509
772
|
<div v-loading="isLoadingDiff" class="diff-content">
|
|
510
773
|
<div v-if="diffContent" v-html="formatDiff(diffContent)" class="diff-formatted"></div>
|
|
511
774
|
<div v-else class="no-diff">该文件没有差异或是新文件</div>
|
|
512
775
|
</div>
|
|
513
776
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
777
|
+
<template #footer>
|
|
778
|
+
<div class="file-navigation">
|
|
779
|
+
<el-button
|
|
780
|
+
type="primary"
|
|
781
|
+
:icon="ArrowLeft"
|
|
782
|
+
@click="goToPreviousFile"
|
|
783
|
+
:disabled="currentFileIndex <= 0 || gitLogStore.fileList.length === 0"
|
|
784
|
+
plain
|
|
785
|
+
class="nav-button"
|
|
786
|
+
>
|
|
787
|
+
上一个文件
|
|
788
|
+
</el-button>
|
|
789
|
+
|
|
790
|
+
<div class="file-counter">
|
|
791
|
+
<el-tag type="info" effect="plain" class="counter-tag">
|
|
792
|
+
{{ currentFileIndex + 1 }} / {{ gitLogStore.fileList.length }}
|
|
793
|
+
</el-tag>
|
|
794
|
+
</div>
|
|
795
|
+
|
|
796
|
+
<el-button
|
|
797
|
+
type="primary"
|
|
798
|
+
:icon="ArrowRight"
|
|
799
|
+
@click="goToNextFile"
|
|
800
|
+
:disabled="currentFileIndex >= gitLogStore.fileList.length - 1 || gitLogStore.fileList.length === 0"
|
|
801
|
+
plain
|
|
802
|
+
class="nav-button"
|
|
803
|
+
>
|
|
804
|
+
下一个文件
|
|
805
|
+
<template #icon>
|
|
806
|
+
<el-icon class="el-icon--right"><ArrowRight /></el-icon>
|
|
807
|
+
</template>
|
|
808
|
+
</el-button>
|
|
809
|
+
</div>
|
|
810
|
+
</template>
|
|
530
811
|
</el-dialog>
|
|
531
812
|
</div>
|
|
532
813
|
</template>
|
|
@@ -535,226 +816,487 @@ defineExpose({
|
|
|
535
816
|
.card {
|
|
536
817
|
background-color: #fff;
|
|
537
818
|
border-radius: 8px;
|
|
538
|
-
box-shadow: 0 2px
|
|
539
|
-
|
|
540
|
-
|
|
819
|
+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.03);
|
|
820
|
+
border: 1px solid rgba(0, 0, 0, 0.03);
|
|
821
|
+
height: 100%;
|
|
822
|
+
width: 100%;
|
|
823
|
+
display: flex;
|
|
824
|
+
flex-direction: column;
|
|
825
|
+
overflow: hidden;
|
|
541
826
|
}
|
|
542
827
|
|
|
543
828
|
.status-header {
|
|
544
829
|
display: flex;
|
|
545
830
|
justify-content: space-between;
|
|
546
831
|
align-items: center;
|
|
547
|
-
|
|
832
|
+
padding: 8px 16px;
|
|
833
|
+
border-bottom: 1px solid #f0f0f0;
|
|
834
|
+
height: 36px;
|
|
548
835
|
}
|
|
549
836
|
|
|
550
837
|
.status-header h2 {
|
|
551
838
|
margin: 0;
|
|
839
|
+
font-size: 16px;
|
|
840
|
+
font-weight: 500;
|
|
841
|
+
color: #303133;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
.header-actions {
|
|
845
|
+
display: flex;
|
|
846
|
+
align-items: center;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
.card-content {
|
|
850
|
+
padding: 15px;
|
|
851
|
+
overflow-y: auto;
|
|
852
|
+
flex: 1;
|
|
853
|
+
display: flex;
|
|
854
|
+
flex-direction: column;
|
|
855
|
+
min-height: 300px; /* 确保内容区有最小高度 */
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
.current-directory {
|
|
859
|
+
display: flex;
|
|
860
|
+
align-items: center;
|
|
861
|
+
margin-bottom: 16px;
|
|
862
|
+
padding: 10px;
|
|
863
|
+
background-color: #f8f9fa;
|
|
864
|
+
border-radius: 6px;
|
|
865
|
+
font-family: monospace;
|
|
866
|
+
border: 1px solid #f0f0f0;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
.current-directory .el-icon {
|
|
870
|
+
margin-right: 8px;
|
|
871
|
+
color: #409eff;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
.current-directory span {
|
|
875
|
+
flex-grow: 1;
|
|
876
|
+
word-break: break-all;
|
|
877
|
+
margin-right: 10px;
|
|
552
878
|
}
|
|
553
879
|
|
|
554
880
|
.status-box {
|
|
555
881
|
white-space: pre-wrap;
|
|
556
882
|
font-family: monospace;
|
|
557
|
-
background-color: #
|
|
558
|
-
padding:
|
|
559
|
-
border-radius:
|
|
560
|
-
margin-bottom:
|
|
561
|
-
max-height:
|
|
883
|
+
background-color: #f8f9fa;
|
|
884
|
+
padding: 16px;
|
|
885
|
+
border-radius: 6px;
|
|
886
|
+
margin-bottom: 20px;
|
|
887
|
+
max-height: 200px;
|
|
562
888
|
overflow-y: auto;
|
|
889
|
+
border: 1px solid #f0f0f0;
|
|
890
|
+
font-size: 14px;
|
|
891
|
+
line-height: 1.5;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
/* 现代化的文件列表容器 */
|
|
895
|
+
.file-list-container {
|
|
896
|
+
flex: 1;
|
|
897
|
+
overflow: hidden;
|
|
898
|
+
display: flex;
|
|
899
|
+
flex-direction: column;
|
|
900
|
+
margin-bottom: 0;
|
|
901
|
+
gap: 12px;
|
|
902
|
+
height: auto; /* 改为自适应高度,不固定高度 */
|
|
903
|
+
min-height: 100px; /* 设置最小高度 */
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
.file-group {
|
|
907
|
+
background-color: #f8f9fa;
|
|
908
|
+
border-radius: 6px;
|
|
909
|
+
overflow: hidden;
|
|
910
|
+
border: 1px solid #ebeef5;
|
|
911
|
+
margin-bottom: 12px;
|
|
912
|
+
display: flex;
|
|
913
|
+
flex-direction: column;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
/* 让每个文件组根据内容自动增长 */
|
|
917
|
+
.file-group {
|
|
918
|
+
flex: 0 1 auto; /* 不主动增长,但允许缩小,基于内容大小 */
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
/* 最后一个分组可以吸收剩余空间 */
|
|
922
|
+
.file-group:last-child {
|
|
923
|
+
margin-bottom: 0;
|
|
924
|
+
flex: 1 1 auto; /* 可以增长占用剩余空间 */
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
.file-group-header {
|
|
928
|
+
font-size: 14px;
|
|
929
|
+
font-weight: bold;
|
|
930
|
+
padding: 8px 12px;
|
|
931
|
+
background-color: #f0f2f5;
|
|
932
|
+
color: #606266;
|
|
933
|
+
border-bottom: 1px solid #ebeef5;
|
|
934
|
+
flex-shrink: 0; /* 防止header被压缩 */
|
|
563
935
|
}
|
|
564
936
|
|
|
565
937
|
.file-list {
|
|
566
|
-
max-height: 300px;
|
|
567
938
|
overflow-y: auto;
|
|
939
|
+
min-height: 40px; /* 最小高度 */
|
|
940
|
+
max-height: 200px; /* 最大高度限制,避免过长列表 */
|
|
941
|
+
flex-grow: 1; /* 允许文件列表在文件组内扩展 */
|
|
942
|
+
padding: 0;
|
|
943
|
+
margin: 0;
|
|
944
|
+
scrollbar-width: thin; /* Firefox */
|
|
945
|
+
scrollbar-color: rgba(144, 147, 153, 0.3) transparent; /* Firefox */
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
/* Webkit浏览器的滚动条样式 */
|
|
949
|
+
.file-list::-webkit-scrollbar {
|
|
950
|
+
width: 6px;
|
|
951
|
+
height: 6px;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
.file-list::-webkit-scrollbar-thumb {
|
|
955
|
+
background-color: rgba(144, 147, 153, 0.3);
|
|
956
|
+
border-radius: 4px;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
.file-list::-webkit-scrollbar-thumb:hover {
|
|
960
|
+
background-color: rgba(144, 147, 153, 0.5);
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
.file-list::-webkit-scrollbar-track {
|
|
964
|
+
background-color: transparent;
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
/* 让每个文件列表自适应高度,使其在容器中更好地分配空间 */
|
|
968
|
+
.file-list:empty {
|
|
969
|
+
display: none; /* 如果列表为空,不显示 */
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
/* 当没有足够的项目填充列表时,禁用滚动 */
|
|
973
|
+
.file-list:has(.empty-file-group) {
|
|
974
|
+
overflow-y: hidden;
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
/* 替换为更兼容的选择器 */
|
|
978
|
+
/* 改用直接为empty-file-group父容器添加样式 */
|
|
979
|
+
.empty-file-container {
|
|
980
|
+
overflow-y: hidden !important; /* 强制禁用滚动 */
|
|
981
|
+
display: flex;
|
|
982
|
+
flex-direction: column;
|
|
983
|
+
align-items: stretch;
|
|
984
|
+
flex: 1;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
.empty-file-group {
|
|
988
|
+
padding: 16px;
|
|
989
|
+
text-align: center;
|
|
990
|
+
color: #909399;
|
|
991
|
+
font-size: 13px;
|
|
992
|
+
font-style: italic;
|
|
993
|
+
display: flex;
|
|
994
|
+
align-items: center;
|
|
995
|
+
justify-content: center;
|
|
996
|
+
min-height: 50px; /* 增加最小高度 */
|
|
997
|
+
background-color: #f8f9fa;
|
|
998
|
+
border-radius: 4px;
|
|
999
|
+
margin: 8px;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
/* 自定义每个分组的展开逻辑 */
|
|
1003
|
+
/* 已暂存文件分组 - 保持小巧 */
|
|
1004
|
+
.file-group:nth-child(1) {
|
|
1005
|
+
flex: 0 1 auto;
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
/* 未暂存更改分组 - 稍微大一些 */
|
|
1009
|
+
.file-group:nth-child(2) {
|
|
1010
|
+
flex: 0 1 auto;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
/* 未跟踪文件分组 - 可以占据剩余空间 */
|
|
1014
|
+
.file-group:nth-child(3) {
|
|
1015
|
+
flex: 1 1 auto;
|
|
568
1016
|
}
|
|
569
1017
|
|
|
570
1018
|
.file-item {
|
|
571
1019
|
padding: 8px 12px;
|
|
572
|
-
margin-bottom: 5px;
|
|
573
|
-
border-radius: 4px;
|
|
574
|
-
cursor: pointer;
|
|
575
1020
|
display: flex;
|
|
576
1021
|
align-items: center;
|
|
577
1022
|
justify-content: space-between;
|
|
1023
|
+
border-bottom: 1px solid #ebeef5;
|
|
1024
|
+
cursor: pointer;
|
|
1025
|
+
transition: background-color 0.2s;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
.file-item:last-child {
|
|
1029
|
+
border-bottom: none;
|
|
578
1030
|
}
|
|
579
1031
|
|
|
580
1032
|
.file-item:hover {
|
|
581
|
-
background-color: #
|
|
1033
|
+
background-color: #ecf5ff;
|
|
582
1034
|
}
|
|
583
1035
|
|
|
584
1036
|
.file-info {
|
|
585
1037
|
display: flex;
|
|
586
1038
|
align-items: center;
|
|
587
1039
|
flex-grow: 1;
|
|
1040
|
+
overflow: hidden;
|
|
1041
|
+
white-space: nowrap;
|
|
1042
|
+
gap: 8px;
|
|
588
1043
|
}
|
|
589
1044
|
|
|
590
|
-
.file-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
1045
|
+
.file-status-indicator {
|
|
1046
|
+
width: 6px;
|
|
1047
|
+
height: 6px;
|
|
1048
|
+
border-radius: 50%;
|
|
1049
|
+
background-color: #409eff;
|
|
1050
|
+
flex-shrink: 0;
|
|
594
1051
|
}
|
|
595
1052
|
|
|
596
|
-
.file-
|
|
597
|
-
|
|
1053
|
+
.file-status-indicator.added {
|
|
1054
|
+
background-color: #67c23a;
|
|
598
1055
|
}
|
|
599
1056
|
|
|
600
|
-
.file-
|
|
601
|
-
|
|
602
|
-
padding: 2px 6px;
|
|
603
|
-
border-radius: 10px;
|
|
604
|
-
margin-right: 10px;
|
|
605
|
-
flex-shrink: 0;
|
|
1057
|
+
.file-status-indicator.modified {
|
|
1058
|
+
background-color: #409eff;
|
|
606
1059
|
}
|
|
607
1060
|
|
|
608
|
-
.
|
|
609
|
-
background-color: #
|
|
610
|
-
color: #67c23a;
|
|
1061
|
+
.file-status-indicator.deleted {
|
|
1062
|
+
background-color: #f56c6c;
|
|
611
1063
|
}
|
|
612
1064
|
|
|
613
|
-
.
|
|
614
|
-
background-color: #
|
|
615
|
-
color: #409eff;
|
|
1065
|
+
.file-status-indicator.untracked {
|
|
1066
|
+
background-color: #e6a23c;
|
|
616
1067
|
}
|
|
617
1068
|
|
|
618
|
-
.
|
|
619
|
-
|
|
620
|
-
|
|
1069
|
+
.file-path-container {
|
|
1070
|
+
display: flex;
|
|
1071
|
+
flex-direction: column;
|
|
1072
|
+
overflow: hidden;
|
|
621
1073
|
}
|
|
622
1074
|
|
|
623
|
-
.
|
|
624
|
-
|
|
625
|
-
color: #
|
|
1075
|
+
.file-name {
|
|
1076
|
+
font-weight: 500;
|
|
1077
|
+
color: #303133;
|
|
1078
|
+
overflow: hidden;
|
|
1079
|
+
text-overflow: ellipsis;
|
|
1080
|
+
line-height: 1.2;
|
|
626
1081
|
}
|
|
627
1082
|
|
|
628
|
-
.file-
|
|
629
|
-
font-
|
|
630
|
-
|
|
1083
|
+
.file-directory {
|
|
1084
|
+
font-size: 12px;
|
|
1085
|
+
color: #909399;
|
|
1086
|
+
max-width: 200px;
|
|
1087
|
+
overflow: hidden;
|
|
1088
|
+
white-space: nowrap;
|
|
1089
|
+
text-overflow: ellipsis;
|
|
631
1090
|
}
|
|
632
1091
|
|
|
633
|
-
.
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
padding: 10px;
|
|
639
|
-
background-color: #f5f7fa;
|
|
640
|
-
border-radius: 4px;
|
|
1092
|
+
.file-actions {
|
|
1093
|
+
display: flex;
|
|
1094
|
+
gap: 5px;
|
|
1095
|
+
opacity: 0;
|
|
1096
|
+
transition: opacity 0.2s;
|
|
641
1097
|
}
|
|
642
1098
|
|
|
643
|
-
.
|
|
644
|
-
|
|
645
|
-
line-height: 1.5;
|
|
1099
|
+
.file-item:hover .file-actions {
|
|
1100
|
+
opacity: 1;
|
|
646
1101
|
}
|
|
647
1102
|
|
|
648
|
-
.
|
|
1103
|
+
.empty-status {
|
|
649
1104
|
display: flex;
|
|
1105
|
+
flex-direction: column;
|
|
1106
|
+
align-items: center;
|
|
650
1107
|
justify-content: center;
|
|
1108
|
+
padding: 40px 20px;
|
|
1109
|
+
text-align: center;
|
|
1110
|
+
background-color: #f9f9f9;
|
|
1111
|
+
border-radius: 8px;
|
|
1112
|
+
margin-top: 10px;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
.empty-icon {
|
|
1116
|
+
width: 60px;
|
|
1117
|
+
height: 60px;
|
|
1118
|
+
display: flex;
|
|
651
1119
|
align-items: center;
|
|
1120
|
+
justify-content: center;
|
|
1121
|
+
background-color: #ebeef5;
|
|
1122
|
+
border-radius: 50%;
|
|
1123
|
+
margin-bottom: 15px;
|
|
1124
|
+
font-size: 24px;
|
|
1125
|
+
color: #909399;
|
|
1126
|
+
animation: pulse 2s infinite ease-in-out;
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
@keyframes pulse {
|
|
1130
|
+
0% { transform: scale(1); opacity: 0.7; }
|
|
1131
|
+
50% { transform: scale(1.05); opacity: 1; }
|
|
1132
|
+
100% { transform: scale(1); opacity: 0.7; }
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
.empty-text {
|
|
1136
|
+
font-size: 16px;
|
|
1137
|
+
font-weight: 500;
|
|
1138
|
+
color: #606266;
|
|
1139
|
+
margin-bottom: 5px;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
.empty-subtext {
|
|
1143
|
+
font-size: 14px;
|
|
1144
|
+
color: #909399;
|
|
1145
|
+
margin-bottom: 20px;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
/* 分支信息样式 */
|
|
1149
|
+
.branch-info {
|
|
652
1150
|
margin-top: 15px;
|
|
1151
|
+
padding: 10px 15px;
|
|
1152
|
+
background-color: #ebeef5;
|
|
1153
|
+
border-radius: 6px;
|
|
1154
|
+
text-align: left;
|
|
1155
|
+
width: 100%;
|
|
1156
|
+
max-width: 400px;
|
|
653
1157
|
}
|
|
654
1158
|
|
|
655
|
-
.
|
|
656
|
-
margin: 0
|
|
1159
|
+
.branch-info p {
|
|
1160
|
+
margin: 5px 0;
|
|
657
1161
|
font-size: 14px;
|
|
658
1162
|
color: #606266;
|
|
659
1163
|
}
|
|
660
1164
|
|
|
661
|
-
.
|
|
1165
|
+
.branch-sync-info {
|
|
662
1166
|
display: flex;
|
|
663
1167
|
align-items: center;
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
1168
|
+
gap: 5px;
|
|
1169
|
+
font-size: 13px;
|
|
1170
|
+
margin-top: 5px;
|
|
1171
|
+
padding: 5px 8px;
|
|
667
1172
|
border-radius: 4px;
|
|
668
|
-
|
|
1173
|
+
background-color: #f5f7fa;
|
|
669
1174
|
}
|
|
670
1175
|
|
|
671
|
-
.
|
|
672
|
-
|
|
673
|
-
color: #
|
|
1176
|
+
.branch-sync-info.warning {
|
|
1177
|
+
color: #e6a23c;
|
|
1178
|
+
background-color: #fdf6ec;
|
|
674
1179
|
}
|
|
675
1180
|
|
|
676
|
-
.
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
margin-right: 10px;
|
|
1181
|
+
.branch-sync-info.info {
|
|
1182
|
+
color: #909399;
|
|
1183
|
+
background-color: #f4f4f5;
|
|
680
1184
|
}
|
|
681
1185
|
|
|
682
|
-
.
|
|
683
|
-
|
|
1186
|
+
.branch-sync-info.success {
|
|
1187
|
+
color: #67c23a;
|
|
1188
|
+
background-color: #f0f9eb;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
/* 添加针对空内容区域的样式 */
|
|
1192
|
+
.card-content:empty {
|
|
1193
|
+
display: flex;
|
|
1194
|
+
align-items: center;
|
|
1195
|
+
justify-content: center;
|
|
1196
|
+
background-color: #f8f9fa;
|
|
1197
|
+
border-radius: 6px;
|
|
1198
|
+
border: 1px dashed #dcdfe6;
|
|
1199
|
+
color: #909399;
|
|
1200
|
+
height: 100%;
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
.card-content:empty::after {
|
|
1204
|
+
content: '没有Git状态信息可显示';
|
|
684
1205
|
font-size: 14px;
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
/* 添加目录浏览相关样式 */
|
|
1209
|
+
.browser-current-path {
|
|
689
1210
|
font-family: monospace;
|
|
690
|
-
|
|
1211
|
+
margin-bottom: 15px;
|
|
1212
|
+
padding: 10px;
|
|
1213
|
+
background-color: #f5f7fa;
|
|
1214
|
+
border-radius: 6px;
|
|
1215
|
+
overflow-x: auto;
|
|
1216
|
+
white-space: nowrap;
|
|
1217
|
+
border: 1px solid #ebeef5;
|
|
691
1218
|
}
|
|
692
1219
|
|
|
693
1220
|
.browser-error {
|
|
694
|
-
margin-bottom: 10px;
|
|
695
1221
|
color: #f56c6c;
|
|
696
|
-
|
|
1222
|
+
margin: 10px 0;
|
|
1223
|
+
padding: 10px;
|
|
697
1224
|
background-color: #fef0f0;
|
|
698
1225
|
border-radius: 4px;
|
|
1226
|
+
border-left: 3px solid #f56c6c;
|
|
699
1227
|
}
|
|
700
1228
|
|
|
701
|
-
.
|
|
702
|
-
padding: 10px;
|
|
703
|
-
height: 400px;
|
|
1229
|
+
.browser-nav {
|
|
704
1230
|
display: flex;
|
|
705
|
-
|
|
1231
|
+
gap: 10px;
|
|
1232
|
+
margin-bottom: 10px;
|
|
706
1233
|
}
|
|
707
1234
|
|
|
708
|
-
.
|
|
709
|
-
|
|
1235
|
+
.no-padding-left {
|
|
1236
|
+
padding-left: 12px;
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
.directory-browser {
|
|
1240
|
+
height: 400px;
|
|
1241
|
+
border: 1px solid #ebeef5;
|
|
1242
|
+
border-radius: 6px;
|
|
1243
|
+
overflow: hidden;
|
|
710
1244
|
display: flex;
|
|
711
|
-
|
|
712
|
-
position: sticky;
|
|
713
|
-
top: 0;
|
|
714
|
-
background-color: #fff;
|
|
715
|
-
z-index: 1;
|
|
716
|
-
padding: 10px 0;
|
|
1245
|
+
flex-direction: column;
|
|
717
1246
|
}
|
|
718
1247
|
|
|
719
1248
|
.directory-items-container {
|
|
720
1249
|
flex: 1;
|
|
721
1250
|
overflow-y: auto;
|
|
1251
|
+
background-color: #f8f9fa;
|
|
1252
|
+
padding: 10px;
|
|
722
1253
|
}
|
|
723
1254
|
|
|
724
1255
|
.directory-items {
|
|
725
1256
|
list-style: none;
|
|
726
1257
|
padding: 0;
|
|
727
1258
|
margin: 0;
|
|
1259
|
+
display: grid;
|
|
1260
|
+
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
|
|
1261
|
+
gap: 10px;
|
|
728
1262
|
}
|
|
729
1263
|
|
|
730
1264
|
.directory-item {
|
|
731
|
-
padding: 8px 12px;
|
|
732
|
-
margin-bottom: 5px;
|
|
733
|
-
border-radius: 4px;
|
|
734
|
-
cursor: pointer;
|
|
735
1265
|
display: flex;
|
|
736
1266
|
align-items: center;
|
|
1267
|
+
padding: 8px;
|
|
1268
|
+
cursor: pointer;
|
|
1269
|
+
border-radius: 4px;
|
|
1270
|
+
background-color: white;
|
|
1271
|
+
border: 1px solid #ebeef5;
|
|
1272
|
+
transition: all 0.2s;
|
|
1273
|
+
overflow: hidden;
|
|
1274
|
+
white-space: nowrap;
|
|
1275
|
+
text-overflow: ellipsis;
|
|
1276
|
+
gap: 5px;
|
|
737
1277
|
}
|
|
738
1278
|
|
|
739
1279
|
.directory-item:hover {
|
|
740
|
-
background-color: #
|
|
1280
|
+
background-color: #ecf5ff;
|
|
1281
|
+
border-color: #c6e2ff;
|
|
741
1282
|
}
|
|
742
1283
|
|
|
743
1284
|
.directory-item.directory {
|
|
1285
|
+
background-color: #f0f7ff;
|
|
744
1286
|
color: #409eff;
|
|
745
1287
|
}
|
|
746
1288
|
|
|
747
|
-
.directory-item.
|
|
748
|
-
|
|
1289
|
+
.directory-item .el-icon {
|
|
1290
|
+
margin-right: 5px;
|
|
1291
|
+
flex-shrink: 0;
|
|
749
1292
|
}
|
|
750
1293
|
|
|
751
|
-
.directory-item .el-icon {
|
|
752
|
-
|
|
1294
|
+
.directory-item.directory .el-icon {
|
|
1295
|
+
color: #409eff;
|
|
753
1296
|
}
|
|
754
1297
|
|
|
755
|
-
.directory-item
|
|
756
|
-
|
|
757
|
-
word-break: break-all;
|
|
1298
|
+
.directory-item.file .el-icon {
|
|
1299
|
+
color: #909399;
|
|
758
1300
|
}
|
|
759
1301
|
|
|
760
1302
|
.directory-buttons {
|
|
@@ -763,40 +1305,266 @@ defineExpose({
|
|
|
763
1305
|
margin-top: 10px;
|
|
764
1306
|
}
|
|
765
1307
|
|
|
766
|
-
/*
|
|
767
|
-
.
|
|
768
|
-
|
|
1308
|
+
/* 添加分支状态样式 */
|
|
1309
|
+
.branch-sync-status {
|
|
1310
|
+
display: flex;
|
|
1311
|
+
align-items: center;
|
|
1312
|
+
padding: 12px 15px;
|
|
1313
|
+
background-color: #f8f9fa;
|
|
1314
|
+
border-radius: 4px;
|
|
1315
|
+
margin-bottom: 15px;
|
|
1316
|
+
border-left: 3px solid #e6a23c;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
/* 添加默认分支状态信息样式 */
|
|
1320
|
+
.git-status-message {
|
|
1321
|
+
padding: 12px 15px;
|
|
1322
|
+
background-color: #f8f9fa;
|
|
1323
|
+
border-radius: 4px;
|
|
1324
|
+
margin-bottom: 15px;
|
|
1325
|
+
border-left: 3px solid #67c23a;
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
.git-status-message p {
|
|
1329
|
+
margin: 0;
|
|
1330
|
+
display: flex;
|
|
1331
|
+
align-items: center;
|
|
1332
|
+
gap: 8px;
|
|
1333
|
+
font-size: 14px;
|
|
1334
|
+
color: #606266;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
.sync-status-content {
|
|
1338
|
+
display: flex;
|
|
1339
|
+
align-items: center;
|
|
1340
|
+
flex-wrap: wrap;
|
|
1341
|
+
gap: 10px;
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
.status-badges {
|
|
1345
|
+
display: flex;
|
|
1346
|
+
flex-direction: column;
|
|
1347
|
+
gap: 8px;
|
|
1348
|
+
width: 100%;
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
.status-badge {
|
|
1352
|
+
display: flex;
|
|
1353
|
+
align-items: center;
|
|
1354
|
+
width: 100%;
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
.status-badge.el-tag--warning {
|
|
1358
|
+
background-color: #fdf6ec;
|
|
1359
|
+
border-color: #faecd8;
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
.status-badge.el-tag--info {
|
|
1363
|
+
background-color: #f4f4f5;
|
|
1364
|
+
border-color: #e9e9eb;
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
.badge-content {
|
|
1368
|
+
display: flex;
|
|
1369
|
+
align-items: center;
|
|
1370
|
+
gap: 6px;
|
|
1371
|
+
font-size: 13px;
|
|
1372
|
+
}
|
|
1373
|
+
.diff-dialog {
|
|
1374
|
+
height: calc(100vh - 150px);
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
.diff-dialog-header {
|
|
1378
|
+
display: flex;
|
|
1379
|
+
justify-content: space-between;
|
|
1380
|
+
align-items: center;
|
|
1381
|
+
padding: 16px 20px;
|
|
1382
|
+
border-bottom: 1px solid #ebeef5;
|
|
1383
|
+
background-color: #f9f9fb;
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
.file-title {
|
|
1387
|
+
display: flex;
|
|
1388
|
+
align-items: center;
|
|
1389
|
+
font-size: 16px;
|
|
1390
|
+
font-weight: 500;
|
|
1391
|
+
color: #303133;
|
|
1392
|
+
gap: 10px;
|
|
1393
|
+
overflow: hidden;
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
.file-icon {
|
|
1397
|
+
color: #409eff;
|
|
1398
|
+
font-size: 20px;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
.file-path {
|
|
1402
|
+
white-space: nowrap;
|
|
1403
|
+
overflow: hidden;
|
|
1404
|
+
text-overflow: ellipsis;
|
|
1405
|
+
font-family: monospace;
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
.diff-content {
|
|
1409
|
+
flex: 1;
|
|
1410
|
+
overflow-y: auto;
|
|
1411
|
+
padding: 10px 20px;
|
|
1412
|
+
background-color: #fafafa;
|
|
1413
|
+
/* height: 100%;
|
|
1414
|
+
overflow: auto; */
|
|
1415
|
+
}
|
|
1416
|
+
:deep(.el-dialog__body) {
|
|
1417
|
+
height: calc(100vh - 320px);
|
|
1418
|
+
overflow: auto;
|
|
1419
|
+
}
|
|
1420
|
+
.diff-formatted {
|
|
1421
|
+
font-family: 'Consolas', 'Courier New', monospace;
|
|
1422
|
+
font-size: 14px;
|
|
1423
|
+
line-height: 1.5;
|
|
1424
|
+
white-space: pre-wrap;
|
|
1425
|
+
padding-bottom: 20px;
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
.no-diff {
|
|
1429
|
+
display: flex;
|
|
1430
|
+
align-items: center;
|
|
1431
|
+
justify-content: center;
|
|
1432
|
+
height: 100%;
|
|
1433
|
+
color: #909399;
|
|
1434
|
+
font-size: 14px;
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
.file-navigation {
|
|
1438
|
+
display: flex;
|
|
1439
|
+
justify-content: space-between;
|
|
1440
|
+
align-items: center;
|
|
1441
|
+
padding: 10px 20px;
|
|
1442
|
+
border-top: 1px solid #ebeef5;
|
|
1443
|
+
background-color: #f9f9fb;
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1446
|
+
.counter-tag {
|
|
1447
|
+
font-family: monospace;
|
|
1448
|
+
font-size: 14px;
|
|
1449
|
+
padding: 6px 12px;
|
|
1450
|
+
min-width: 80px;
|
|
1451
|
+
text-align: center;
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
.nav-button {
|
|
1455
|
+
min-width: 120px;
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
/* 确保文件差异对话框里的内容滚动条样式一致 */
|
|
1459
|
+
.diff-formatted::-webkit-scrollbar,
|
|
1460
|
+
.diff-content::-webkit-scrollbar {
|
|
1461
|
+
width: 6px;
|
|
1462
|
+
height: 6px;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
.diff-formatted::-webkit-scrollbar-thumb,
|
|
1466
|
+
.diff-content::-webkit-scrollbar-thumb {
|
|
1467
|
+
background-color: rgba(144, 147, 153, 0.3);
|
|
1468
|
+
border-radius: 4px;
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
.diff-formatted::-webkit-scrollbar-thumb:hover,
|
|
1472
|
+
.diff-content::-webkit-scrollbar-thumb:hover {
|
|
1473
|
+
background-color: rgba(144, 147, 153, 0.5);
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
.diff-formatted::-webkit-scrollbar-track,
|
|
1477
|
+
.diff-content::-webkit-scrollbar-track {
|
|
1478
|
+
background-color: transparent;
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
/* 兼容Firefox滚动条样式 */
|
|
1482
|
+
.diff-formatted,
|
|
1483
|
+
.diff-content {
|
|
1484
|
+
scrollbar-width: thin;
|
|
1485
|
+
scrollbar-color: rgba(144, 147, 153, 0.3) transparent;
|
|
769
1486
|
}
|
|
770
1487
|
</style>
|
|
771
1488
|
|
|
772
|
-
<!--
|
|
1489
|
+
<!-- 非scoped样式,使diff格式化样式对动态内容生效 -->
|
|
773
1490
|
<style>
|
|
774
1491
|
.diff-header {
|
|
775
1492
|
font-weight: bold;
|
|
776
1493
|
background-color: #e6f1fc;
|
|
777
|
-
padding:
|
|
778
|
-
margin:
|
|
1494
|
+
padding: 5px;
|
|
1495
|
+
margin: 8px 0;
|
|
1496
|
+
border-radius: 4px;
|
|
1497
|
+
color: #0366d6;
|
|
1498
|
+
border-bottom: 1px solid #c8e1ff;
|
|
779
1499
|
}
|
|
780
1500
|
|
|
781
1501
|
.diff-old-file, .diff-new-file {
|
|
782
|
-
color: #
|
|
1502
|
+
color: #586069;
|
|
1503
|
+
padding: 2px 5px;
|
|
1504
|
+
font-family: monospace;
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
.diff-old-file {
|
|
1508
|
+
color: #cb2431;
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
.diff-new-file {
|
|
1512
|
+
color: #22863a;
|
|
783
1513
|
}
|
|
784
1514
|
|
|
785
1515
|
.diff-hunk-header {
|
|
786
1516
|
color: #6f42c1;
|
|
1517
|
+
background-color: #f1f8ff;
|
|
1518
|
+
padding: 2px 5px;
|
|
1519
|
+
margin: 5px 0;
|
|
1520
|
+
border-radius: 3px;
|
|
1521
|
+
font-family: monospace;
|
|
787
1522
|
}
|
|
788
1523
|
|
|
789
1524
|
.diff-added {
|
|
790
1525
|
background-color: #e6ffed;
|
|
791
|
-
color: #
|
|
1526
|
+
color: #22863a;
|
|
1527
|
+
padding: 0 5px;
|
|
1528
|
+
border-left: 4px solid #22863a;
|
|
1529
|
+
font-family: monospace;
|
|
1530
|
+
display: block;
|
|
1531
|
+
margin: 2px 0;
|
|
792
1532
|
}
|
|
793
1533
|
|
|
794
1534
|
.diff-removed {
|
|
795
1535
|
background-color: #ffeef0;
|
|
796
|
-
color: #
|
|
1536
|
+
color: #cb2431;
|
|
1537
|
+
padding: 0 5px;
|
|
1538
|
+
border-left: 4px solid #cb2431;
|
|
1539
|
+
font-family: monospace;
|
|
1540
|
+
display: block;
|
|
1541
|
+
margin: 2px 0;
|
|
797
1542
|
}
|
|
798
1543
|
|
|
799
1544
|
.diff-context {
|
|
800
1545
|
color: #444;
|
|
1546
|
+
padding: 0 5px;
|
|
1547
|
+
font-family: monospace;
|
|
1548
|
+
display: block;
|
|
1549
|
+
margin: 2px 0;
|
|
1550
|
+
background-color: #fafbfc;
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
/* 增加自动更新开关的样式 */
|
|
1554
|
+
.auto-update-switch .el-switch__core {
|
|
1555
|
+
transition: all 0.3s ease-in-out;
|
|
1556
|
+
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
.auto-update-switch .el-switch__core:hover {
|
|
1560
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
.auto-update-switch.is-checked .el-switch__core {
|
|
1564
|
+
box-shadow: 0 2px 5px rgba(103, 194, 58, 0.3);
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
.auto-update-switch.is-checked .el-switch__core:hover {
|
|
1568
|
+
box-shadow: 0 2px 8px rgba(103, 194, 58, 0.5);
|
|
801
1569
|
}
|
|
802
1570
|
</style>
|