feat(git): 在面板中显示当前Git分支并改进布局

- 新增获取当前分支的API接口和前端状态管理
- 在Git面板顶部显示当前分支名称和图标
- 重新组织操作按钮布局,将远程仓库和刷新按钮移至顶部工具栏
- 为状态列表添加文件数量统计
- 优化响应式布局,使拉取/推送按钮等宽显示
This commit is contained in:
cfq 2026-01-28 20:00:26 +08:00
parent 44a2c54da3
commit 18db27a22c
3 changed files with 92 additions and 13 deletions

View File

@ -176,6 +176,10 @@ window.services = {
return this.execGit("-c core.quotePath=false status --short", dirPath); return this.execGit("-c core.quotePath=false status --short", dirPath);
}, },
async gitBranch(dirPath) {
return this.execGit("branch --show-current", dirPath);
},
async gitAdd(dirPath, files = ".") { async gitAdd(dirPath, files = ".") {
return this.execGit(`add ${files}`, dirPath); return this.execGit(`add ${files}`, dirPath);
}, },

View File

@ -5,28 +5,39 @@
</div> </div>
<div v-else class="git-content"> <div v-else class="git-content">
<div class="git-header">
<div class="git-branch" v-if="state.branch">
<BranchesOutlined />
<span class="branch-name">{{ state.branch }}</span>
</div>
<div class="git-toolbar">
<a-button @click="openRemoteUrl" :disabled="!state.remoteUrl" title="打开 Git 仓库" size="small">
<template #icon><GithubOutlined /></template>
</a-button>
<a-button @click="handleRefresh" :loading="state.loading" size="small">
<template #icon><ReloadOutlined /></template>
</a-button>
</div>
</div>
<div class="git-actions"> <div class="git-actions">
<a-button-group> <a-button-group class="action-group">
<a-button @click="handlePull" :loading="state.loading"> <a-button @click="handlePull" :loading="state.loading" block>
<template #icon><ArrowDownOutlined /></template> <template #icon><ArrowDownOutlined /></template>
拉取 拉取
</a-button> </a-button>
<a-button @click="handlePush" :loading="state.loading"> <a-button @click="handlePush" :loading="state.loading" block>
<template #icon><ArrowUpOutlined /></template> <template #icon><ArrowUpOutlined /></template>
推送 推送
</a-button> </a-button>
<a-button @click="openRemoteUrl" :disabled="!state.remoteUrl" title="打开 Git 仓库">
<template #icon><GithubOutlined /></template>
</a-button>
</a-button-group> </a-button-group>
<a-button @click="handleRefresh" :loading="state.loading">
<template #icon><ReloadOutlined /></template>
</a-button>
</div> </div>
<div class="git-status"> <div class="git-status">
<h3>状态</h3> <div class="status-header">
<h3>状态</h3>
<span class="status-count" v-if="state.statusFiles.length">{{ state.statusFiles.length }}</span>
</div>
<div class="status-list" v-if="state.statusFiles.length > 0"> <div class="status-list" v-if="state.statusFiles.length > 0">
<div v-for="(file, index) in state.statusFiles" :key="index" class="status-item"> <div v-for="(file, index) in state.statusFiles" :key="index" class="status-item">
<span class="status-badge" :class="getStatusClass(file.status)">{{ file.status }}</span> <span class="status-badge" :class="getStatusClass(file.status)">{{ file.status }}</span>
@ -60,7 +71,7 @@
<script setup> <script setup>
import { ref, onMounted, watch } from 'vue'; import { ref, onMounted, watch } from 'vue';
import { ArrowDownOutlined, ArrowUpOutlined, ReloadOutlined, GithubOutlined } from '@ant-design/icons-vue'; import { ArrowDownOutlined, ArrowUpOutlined, ReloadOutlined, GithubOutlined, BranchesOutlined } from '@ant-design/icons-vue';
import { useGit } from '../composables/useGit'; import { useGit } from '../composables/useGit';
import { useFileTree } from '../composables/useFileTree'; import { useFileTree } from '../composables/useFileTree';
import { message } from 'ant-design-vue'; import { message } from 'ant-design-vue';
@ -143,16 +154,66 @@ const getStatusClass = (status) => {
text-align: center; text-align: center;
} }
.git-actions { .git-header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center;
margin-bottom: 16px;
padding-bottom: 8px;
border-bottom: 1px solid var(--border-color);
}
.git-branch {
display: flex;
align-items: center;
font-weight: bold;
color: var(--primary-color, #1890ff);
}
.branch-name {
margin-left: 6px;
}
.git-toolbar {
display: flex;
gap: 8px;
}
.git-actions {
margin-bottom: 20px; margin-bottom: 20px;
} }
.action-group {
display: flex;
width: 100%;
}
.action-group .ant-btn {
flex: 1;
}
.git-status { .git-status {
margin-bottom: 20px; margin-bottom: 20px;
} }
.status-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.status-header h3 {
margin: 0;
}
.status-count {
background-color: var(--border-color);
padding: 2px 6px;
border-radius: 10px;
font-size: 12px;
}
.status-list { .status-list {
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
border-radius: 4px; border-radius: 4px;

View File

@ -5,6 +5,7 @@ const state = reactive({
statusOutput: '', statusOutput: '',
statusFiles: [], statusFiles: [],
remoteUrl: '', remoteUrl: '',
branch: '',
loading: false loading: false
}); });
@ -17,6 +18,18 @@ export function useGit() {
// 自动获取一次状态 // 自动获取一次状态
await getStatus(rootDir); await getStatus(rootDir);
await getRemoteUrl(rootDir); await getRemoteUrl(rootDir);
await getBranch(rootDir);
}
};
const getBranch = async (rootDir) => {
try {
const res = await window.services.gitBranch(rootDir);
if (res.success) {
state.branch = res.stdout.trim();
}
} catch (e) {
console.error("Failed to get branch", e);
} }
}; };
@ -97,6 +110,7 @@ export function useGit() {
checkGitRepo, checkGitRepo,
getStatus, getStatus,
getRemoteUrl, getRemoteUrl,
getBranch,
openRemoteUrl, openRemoteUrl,
commit, commit,
push, push,