优化: 项目文件树/依赖图组件 + 灵感对抗校验 + 小程序脚本 + 模块管理
This commit is contained in:
@@ -130,7 +130,7 @@
|
||||
</div>
|
||||
<div v-if="commitDetailLoading" class="gc-loading"><span class="spinner"></span></div>
|
||||
<template v-else-if="commitDetail">
|
||||
<!-- 变更文件列表 -->
|
||||
<!-- 变更文件列表(点击文件 → diff 渲染到右侧宽预览区,见 emit select-file) -->
|
||||
<div class="gc-commit-files">
|
||||
<div
|
||||
v-for="f in commitDetail.files"
|
||||
@@ -143,25 +143,6 @@
|
||||
<span class="gc-file-path">{{ f.path }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Diff 预览(可收起,占更宽空间) -->
|
||||
<div v-if="commitSelectedFile" class="gc-commit-diff">
|
||||
<div class="gc-commit-diff-header">
|
||||
<span class="gc-commit-diff-path">{{ commitSelectedFile }}</span>
|
||||
<button class="gc-commit-diff-toggle" @click="commitDiffCollapsed = !commitDiffCollapsed">
|
||||
{{ commitDiffCollapsed ? $t('gitChanges.expand') : $t('gitChanges.collapse') }}
|
||||
</button>
|
||||
</div>
|
||||
<div v-show="!commitDiffCollapsed" class="gc-diff-content">
|
||||
<div v-if="!commitDiff" class="gc-diff-empty">{{ $t('gitChanges.noDiff') }}</div>
|
||||
<div v-for="(ln, idx) in commitDiffLines" :key="idx" class="diff-line" :class="'diff-' + ln.type">
|
||||
<span class="diff-hdr-text" v-if="ln.type === 'hdr'">{{ ln.text }}</span>
|
||||
<template v-else>
|
||||
<span class="diff-line-prefix">{{ ln.prefix }}</span>
|
||||
<span class="diff-line-text">{{ ln.text }}</span>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</transition>
|
||||
@@ -172,8 +153,9 @@
|
||||
/**
|
||||
* Git 变更查看器 — 变更文件列表(按目录树分组) + 提交历史(分页/搜索) + 文件 diff 预览。
|
||||
*
|
||||
* 历史 Tab 布局:列表始终可见,选中提交的详情从底部滑出(可收起),diff 在更宽容器渲染,
|
||||
* 避免几百行 diff 把列表挤走、或在 30% 窄栏内挤压。
|
||||
* 布局:变更 Tab 点文件 / 提交历史点文件 → emit select-file,把该文件 diff 注入右侧 FilePreview
|
||||
* 宽预览区渲染;本组件窄栏只保留文件列表与提交详情(文件清单),不再内嵌 diff —— 几百行 diff
|
||||
* 在 30% 窄栏内渲染会被挤压/截断,故 diff 展示统一走右侧宽区。
|
||||
*/
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { moduleApi, type GitStatusResult } from '@/api/module'
|
||||
@@ -188,7 +170,8 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'select-file', path: string): void
|
||||
/** 选择文件 → 在右侧宽预览区展示其 diff(第二个参数为可选注入的 diff 内容)。 */
|
||||
(e: 'select-file', path: string, diff?: string): void
|
||||
}>()
|
||||
|
||||
const loading = ref(false)
|
||||
@@ -231,8 +214,6 @@ const selectedCommit = ref<CommitItem | null>(null)
|
||||
const commitDetail = ref<{ files: { status: string; path: string }[]; diff: string } | null>(null)
|
||||
const commitDetailLoading = ref(false)
|
||||
const commitSelectedFile = ref('')
|
||||
const commitDiff = ref('')
|
||||
const commitDiffCollapsed = ref(false)
|
||||
|
||||
const branchName = computed(() => gitStatus.value?.branch || '')
|
||||
|
||||
@@ -271,33 +252,6 @@ const groupedChanges = computed<FileGroup[]>(() => {
|
||||
return groups.filter(g => g.files.length > 0)
|
||||
})
|
||||
|
||||
interface DiffLine {
|
||||
type: 'add' | 'del' | 'ctx' | 'hdr'
|
||||
prefix: string
|
||||
text: string
|
||||
}
|
||||
|
||||
const commitDiffLines = computed<DiffLine[]>(() => parseDiff(commitDiff.value))
|
||||
|
||||
function parseDiff(text: string): DiffLine[] {
|
||||
if (!text) return []
|
||||
const lines: DiffLine[] = []
|
||||
for (const raw of text.split('\n')) {
|
||||
if (raw.startsWith('@@')) {
|
||||
lines.push({ type: 'hdr', prefix: '', text: raw })
|
||||
} else if (raw.startsWith('+')) {
|
||||
lines.push({ type: 'add', prefix: '+', text: raw.slice(1) })
|
||||
} else if (raw.startsWith('-')) {
|
||||
lines.push({ type: 'del', prefix: '-', text: raw.slice(1) })
|
||||
} else if (raw.startsWith('\\')) {
|
||||
continue
|
||||
} else {
|
||||
lines.push({ type: 'ctx', prefix: ' ', text: raw })
|
||||
}
|
||||
}
|
||||
return lines
|
||||
}
|
||||
|
||||
function statusLabel(s: string): string {
|
||||
const x = s.trim()
|
||||
if (x === '??') return 'U'
|
||||
@@ -478,6 +432,7 @@ async function switchToHistory() {
|
||||
|
||||
async function selectFile(path: string) {
|
||||
selectedFile.value = path
|
||||
// 先切预览到该文件(内容视图),diff 拉到后回填,点文件即展示变化
|
||||
emit('select-file', path)
|
||||
diffContent.value = ''
|
||||
diffLoading.value = true
|
||||
@@ -489,6 +444,10 @@ async function selectFile(path: string) {
|
||||
} finally {
|
||||
diffLoading.value = false
|
||||
}
|
||||
// 仅当仍是当前选中文件时才回填 diff,防快速切换时旧响应覆盖新文件
|
||||
if (selectedFile.value === path) {
|
||||
emit('select-file', path, diffContent.value)
|
||||
}
|
||||
}
|
||||
|
||||
/** 点击提交行 → 加载该提交的变更文件列表 */
|
||||
@@ -501,8 +460,8 @@ async function selectCommit(c: CommitItem) {
|
||||
selectedCommit.value = c
|
||||
commitDetail.value = null
|
||||
commitSelectedFile.value = ''
|
||||
commitDiff.value = ''
|
||||
commitDiffCollapsed.value = false
|
||||
// 切换提交 → 清空右侧宽预览,避免残留上一个提交文件的 diff 与当前提交错位
|
||||
emit('select-file', '', '')
|
||||
commitDetailLoading.value = true
|
||||
try {
|
||||
const res = await moduleApi.getCommitDetail(props.moduleId, c.hash)
|
||||
@@ -518,18 +477,17 @@ function closeCommitDetail() {
|
||||
selectedCommit.value = null
|
||||
commitDetail.value = null
|
||||
commitSelectedFile.value = ''
|
||||
commitDiff.value = ''
|
||||
emit('select-file', '', '')
|
||||
}
|
||||
|
||||
/** 在提交详情中点击文件 → 精确提取该文件的 diff 块(按 diff --git 头切块) */
|
||||
/** 在提交详情中点击文件 → 精确提取该文件的 diff 块(按 diff --git 头切块),路由到右侧宽预览区渲染 */
|
||||
function showCommitFileDiff(path: string) {
|
||||
commitSelectedFile.value = path
|
||||
commitDiffCollapsed.value = false
|
||||
if (!commitDetail.value) {
|
||||
commitDiff.value = ''
|
||||
emit('select-file', path, '')
|
||||
return
|
||||
}
|
||||
commitDiff.value = extractFileDiff(commitDetail.value.diff, path)
|
||||
emit('select-file', path, extractFileDiff(commitDetail.value.diff, path))
|
||||
}
|
||||
|
||||
watch(() => props.moduleId, loadStatus, { immediate: true })
|
||||
@@ -599,23 +557,7 @@ watch(() => props.refreshKey, () => {
|
||||
position: sticky; top: 0; z-index: 1;
|
||||
}
|
||||
|
||||
/* Diff 预览 */
|
||||
.gc-diff-content {
|
||||
font-family: var(--df-font-mono, Consolas, monospace);
|
||||
font-size: 12px; line-height: 1.5; overflow: auto; scrollbar-width: thin;
|
||||
}
|
||||
.diff-line { display: flex; padding: 0 14px; }
|
||||
.diff-line-prefix { width: 16px; flex-shrink: 0; text-align: center; user-select: none; }
|
||||
.diff-line-text { flex: 1; white-space: pre; overflow: hidden; }
|
||||
.diff-hdr-text {
|
||||
padding: 4px 14px; background: rgba(60,140,220,0.08);
|
||||
color: var(--df-text-dim); font-weight: 500; font-size: 11px; display: block;
|
||||
}
|
||||
.diff-add { background: rgba(40,160,70,0.12); }
|
||||
.diff-add .diff-line-prefix { color: #4caf50; }
|
||||
.diff-del { background: rgba(220,60,60,0.12); }
|
||||
.diff-del .diff-line-prefix { color: #e05050; }
|
||||
.diff-ctx { color: var(--df-text); }
|
||||
/* Diff 预览样式已随窄栏内 diff 面板移除(diff 统一在右侧 FilePreview 宽区渲染) */
|
||||
|
||||
/* ====== 提交历史 ====== */
|
||||
.gc-history { display: flex; flex-direction: column; min-height: 0; }
|
||||
@@ -714,31 +656,6 @@ watch(() => props.refreshKey, () => {
|
||||
.gc-commit-file-row:hover { background: rgba(255,255,255,0.04); }
|
||||
.gc-commit-file-row.active { background: rgba(255,255,255,0.06); }
|
||||
|
||||
/* 提交 diff(可收起,占更宽空间) */
|
||||
.gc-commit-diff {
|
||||
flex: 1; min-height: 0;
|
||||
display: flex; flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
.gc-commit-diff-header {
|
||||
display: flex; align-items: center; gap: 8px;
|
||||
padding: 5px 14px; background: rgba(255,255,255,0.03);
|
||||
border-bottom: 0.5px solid var(--df-border); flex-shrink: 0;
|
||||
}
|
||||
.gc-commit-diff-path {
|
||||
flex: 1; min-width: 0;
|
||||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
||||
font-family: var(--df-font-mono, Consolas, monospace); font-size: 11px;
|
||||
color: var(--df-text);
|
||||
}
|
||||
.gc-commit-diff-toggle {
|
||||
background: none; border: 0.5px solid var(--df-border);
|
||||
color: var(--df-text-dim); cursor: pointer; font-size: 11px;
|
||||
padding: 2px 8px; border-radius: 4px;
|
||||
}
|
||||
.gc-commit-diff-toggle:hover { color: var(--df-text); border-color: var(--df-accent); }
|
||||
.gc-commit-diff .gc-diff-content { flex: 1; min-height: 0; }
|
||||
|
||||
/* 滑出动画 */
|
||||
.gc-detail-slide-enter-active, .gc-detail-slide-leave-active {
|
||||
transition: transform 0.18s ease, opacity 0.18s ease;
|
||||
@@ -851,8 +768,6 @@ watch(() => props.refreshKey, () => {
|
||||
padding: 40px 0; color: var(--df-text-dim); font-size: 13px;
|
||||
}
|
||||
.gc-empty-inline { padding: 24px 0; }
|
||||
.gc-diff-loading { display: flex; justify-content: center; padding: 20px; }
|
||||
.gc-diff-empty { padding: 20px 14px; color: var(--df-text-dim); font-size: 12px; text-align: center; }
|
||||
.spinner {
|
||||
width: 16px; height: 16px;
|
||||
border: 2px solid var(--df-border); border-top-color: var(--df-accent);
|
||||
|
||||
Reference in New Issue
Block a user