zen-gitsync 2.0.4 → 2.0.6
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 +626 -186
- package/src/ui/client/src/components/CommitForm.vue +508 -401
- package/src/ui/client/src/components/GitStatus.vue +590 -224
- package/src/ui/client/src/components/LogList.vue +809 -83
- package/src/ui/client/src/stores/gitLogStore.ts +440 -125
- package/src/ui/client/src/stores/gitStore.ts +86 -1
- package/src/ui/client/stats.html +1 -1
- package/src/ui/public/assets/index-DaPynzAr.js +10 -0
- package/src/ui/public/assets/index-qfIezZmd.css +1 -0
- package/src/ui/public/assets/vendor-BcSuWc8z.js +45 -0
- package/src/ui/public/index.html +3 -3
- package/src/ui/server/index.js +375 -44
- package/src/ui/public/assets/index-D5irnfho.css +0 -1
- package/src/ui/public/assets/index-DBck3u67.js +0 -8
- package/src/ui/public/assets/vendor-CdJ34PvS.js +0 -45
|
@@ -4,7 +4,7 @@ import GitStatus from './components/GitStatus.vue'
|
|
|
4
4
|
import CommitForm from './components/CommitForm.vue'
|
|
5
5
|
import LogList from './components/LogList.vue'
|
|
6
6
|
import { ElMessage } from 'element-plus'
|
|
7
|
-
import { Plus } from '@element-plus/icons-vue'
|
|
7
|
+
import { Plus, Setting } from '@element-plus/icons-vue'
|
|
8
8
|
import logo from './assets/logo.svg'
|
|
9
9
|
import { useGitStore } from './stores/gitStore'
|
|
10
10
|
|
|
@@ -68,7 +68,6 @@ onMounted(async () => {
|
|
|
68
68
|
])
|
|
69
69
|
|
|
70
70
|
// 日志信息通过LogList组件直接加载即可,避免重复调用
|
|
71
|
-
// 移除 gitLogStore.fetchLog() 调用
|
|
72
71
|
} else {
|
|
73
72
|
ElMessage.warning('当前目录不是Git仓库,部分功能将不可用')
|
|
74
73
|
}
|
|
@@ -78,43 +77,15 @@ onMounted(async () => {
|
|
|
78
77
|
// 标记初始化完成
|
|
79
78
|
initCompleted.value = true
|
|
80
79
|
console.log('---------- 页面初始化完成 ----------')
|
|
80
|
+
|
|
81
|
+
// 无论是否是Git仓库,都应该加载布局比例
|
|
82
|
+
// 使用短延时确保DOM已完全渲染
|
|
83
|
+
setTimeout(() => {
|
|
84
|
+
loadLayoutRatios();
|
|
85
|
+
}, 100);
|
|
81
86
|
}
|
|
82
87
|
})
|
|
83
88
|
|
|
84
|
-
// 处理提交成功事件
|
|
85
|
-
function handleCommitSuccess() {
|
|
86
|
-
// 不再调用gitLogStore.fetchLog(),改用更新LogList组件
|
|
87
|
-
|
|
88
|
-
// 刷新Git状态
|
|
89
|
-
if (gitStatusRef.value) {
|
|
90
|
-
gitStatusRef.value.refreshStatus()
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// 直接刷新提交历史
|
|
94
|
-
if (logListRef.value) {
|
|
95
|
-
logListRef.value.refreshLog()
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// 处理推送成功事件
|
|
100
|
-
function handlePushSuccess() {
|
|
101
|
-
// 不再调用gitLogStore.fetchLog(),改用更新LogList组件
|
|
102
|
-
gitStore.getCurrentBranch()
|
|
103
|
-
|
|
104
|
-
// 直接刷新提交历史
|
|
105
|
-
if (logListRef.value) {
|
|
106
|
-
logListRef.value.refreshLog()
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// 处理状态更新事件
|
|
111
|
-
function handleStatusUpdate() {
|
|
112
|
-
// 刷新Git状态
|
|
113
|
-
if (gitStatusRef.value) {
|
|
114
|
-
gitStatusRef.value.refreshStatus()
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
89
|
const createBranchDialogVisible = ref(false)
|
|
119
90
|
const newBranchName = ref('')
|
|
120
91
|
const selectedBaseBranch = ref('')
|
|
@@ -164,6 +135,227 @@ async function handleBranchChange(branch: string) {
|
|
|
164
135
|
}
|
|
165
136
|
}
|
|
166
137
|
}
|
|
138
|
+
|
|
139
|
+
// 添加用户设置相关状态
|
|
140
|
+
const userSettingsDialogVisible = ref(false)
|
|
141
|
+
const tempUserName = ref('')
|
|
142
|
+
const tempUserEmail = ref('')
|
|
143
|
+
|
|
144
|
+
// 打开用户设置对话框
|
|
145
|
+
function openUserSettingsDialog() {
|
|
146
|
+
tempUserName.value = gitStore.userName
|
|
147
|
+
tempUserEmail.value = gitStore.userEmail
|
|
148
|
+
userSettingsDialogVisible.value = true
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// 保存用户设置
|
|
152
|
+
async function saveUserSettings() {
|
|
153
|
+
if (!tempUserName.value || !tempUserEmail.value) {
|
|
154
|
+
ElMessage.warning('用户名和邮箱不能为空')
|
|
155
|
+
return
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const success = await gitStore.restoreUserConfig(tempUserName.value, tempUserEmail.value)
|
|
159
|
+
if (success) {
|
|
160
|
+
userSettingsDialogVisible.value = false
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// 清除用户配置
|
|
165
|
+
async function clearUserSettings() {
|
|
166
|
+
const success = await gitStore.clearUserConfig()
|
|
167
|
+
if (success) {
|
|
168
|
+
tempUserName.value = ''
|
|
169
|
+
tempUserEmail.value = ''
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// 添加分隔条相关逻辑
|
|
174
|
+
let isVResizing = false;
|
|
175
|
+
let isHResizing = false;
|
|
176
|
+
let initialX = 0;
|
|
177
|
+
let initialY = 0;
|
|
178
|
+
let initialGridTemplateColumns = '';
|
|
179
|
+
let initialGridTemplateRows = '';
|
|
180
|
+
|
|
181
|
+
// 保存布局比例到localStorage
|
|
182
|
+
function saveLayoutRatios() {
|
|
183
|
+
const gridLayout = document.querySelector('.grid-layout') as HTMLElement;
|
|
184
|
+
if (!gridLayout) return;
|
|
185
|
+
|
|
186
|
+
// 获取当前的列和行比例
|
|
187
|
+
const columns = getComputedStyle(gridLayout).gridTemplateColumns.split(' ');
|
|
188
|
+
const rows = getComputedStyle(gridLayout).gridTemplateRows.split(' ');
|
|
189
|
+
|
|
190
|
+
if (columns.length >= 3 && rows.length >= 3) {
|
|
191
|
+
// 解析左右区域比例
|
|
192
|
+
const leftColWidth = parseFloat(columns[0]);
|
|
193
|
+
const rightColWidth = parseFloat(columns[2]);
|
|
194
|
+
const totalWidth = leftColWidth + rightColWidth;
|
|
195
|
+
const leftRatio = leftColWidth / totalWidth;
|
|
196
|
+
|
|
197
|
+
// 解析上下区域比例
|
|
198
|
+
const topRowHeight = parseFloat(rows[0]);
|
|
199
|
+
const bottomRowHeight = parseFloat(rows[2]);
|
|
200
|
+
const totalHeight = topRowHeight + bottomRowHeight;
|
|
201
|
+
const topRatio = topRowHeight / totalHeight;
|
|
202
|
+
|
|
203
|
+
// 保存到localStorage
|
|
204
|
+
localStorage.setItem('zen-gitsync-layout-left-ratio', leftRatio.toString());
|
|
205
|
+
localStorage.setItem('zen-gitsync-layout-top-ratio', topRatio.toString());
|
|
206
|
+
|
|
207
|
+
console.log(`布局比例已保存 - 左侧: ${(leftRatio * 100).toFixed(0)}%, 上方: ${(topRatio * 100).toFixed(0)}%`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// 加载布局比例
|
|
212
|
+
function loadLayoutRatios() {
|
|
213
|
+
const gridLayout = document.querySelector('.grid-layout') as HTMLElement;
|
|
214
|
+
if (!gridLayout) return;
|
|
215
|
+
|
|
216
|
+
// 从localStorage获取保存的比例
|
|
217
|
+
const savedLeftRatio = localStorage.getItem('zen-gitsync-layout-left-ratio');
|
|
218
|
+
const savedTopRatio = localStorage.getItem('zen-gitsync-layout-top-ratio');
|
|
219
|
+
|
|
220
|
+
// 应用左右区域比例
|
|
221
|
+
if (savedLeftRatio) {
|
|
222
|
+
const leftRatio = parseFloat(savedLeftRatio);
|
|
223
|
+
const rightRatio = 1 - leftRatio;
|
|
224
|
+
gridLayout.style.gridTemplateColumns = `${leftRatio}fr 8px ${rightRatio}fr`;
|
|
225
|
+
console.log(`已恢复左侧比例: ${(leftRatio * 100).toFixed(0)}%`);
|
|
226
|
+
} else {
|
|
227
|
+
// 默认比例 1:3
|
|
228
|
+
gridLayout.style.gridTemplateColumns = "1fr 8px 3fr";
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// 应用上下区域比例
|
|
232
|
+
if (savedTopRatio) {
|
|
233
|
+
const topRatio = parseFloat(savedTopRatio);
|
|
234
|
+
const bottomRatio = 1 - topRatio;
|
|
235
|
+
gridLayout.style.gridTemplateRows = `${topRatio}fr 8px ${bottomRatio}fr`;
|
|
236
|
+
console.log(`已恢复上方比例: ${(topRatio * 100).toFixed(0)}%`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function startVResize(event: MouseEvent) {
|
|
241
|
+
isVResizing = true;
|
|
242
|
+
initialX = event.clientX;
|
|
243
|
+
|
|
244
|
+
const gridLayout = document.querySelector('.grid-layout') as HTMLElement;
|
|
245
|
+
initialGridTemplateColumns = getComputedStyle(gridLayout).gridTemplateColumns;
|
|
246
|
+
|
|
247
|
+
document.getElementById('v-resizer')?.classList.add('active');
|
|
248
|
+
|
|
249
|
+
document.addEventListener('mousemove', handleVResize);
|
|
250
|
+
document.addEventListener('mouseup', stopVResize);
|
|
251
|
+
|
|
252
|
+
// 防止文本选择
|
|
253
|
+
event.preventDefault();
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function handleVResize(event: MouseEvent) {
|
|
257
|
+
if (!isVResizing) return;
|
|
258
|
+
|
|
259
|
+
const gridLayout = document.querySelector('.grid-layout') as HTMLElement;
|
|
260
|
+
const delta = event.clientX - initialX;
|
|
261
|
+
|
|
262
|
+
// 解析当前的网格模板列值
|
|
263
|
+
const columns = initialGridTemplateColumns.split(' ');
|
|
264
|
+
|
|
265
|
+
// 确保我们有足够的列
|
|
266
|
+
if (columns.length >= 3) {
|
|
267
|
+
// 计算新的左列宽度
|
|
268
|
+
const leftColWidth = parseFloat(columns[0]);
|
|
269
|
+
const rightColWidth = parseFloat(columns[2]);
|
|
270
|
+
|
|
271
|
+
// 计算新的左右列比例
|
|
272
|
+
const totalWidth = leftColWidth + rightColWidth;
|
|
273
|
+
const newLeftRatio = (leftColWidth + delta / gridLayout.clientWidth * totalWidth) / totalWidth;
|
|
274
|
+
const newRightRatio = 1 - newLeftRatio;
|
|
275
|
+
|
|
276
|
+
// 确保左侧宽度不小于总宽度的10%且不大于50%
|
|
277
|
+
const minLeftRatio = 0.1;
|
|
278
|
+
const maxLeftRatio = 0.5;
|
|
279
|
+
|
|
280
|
+
if (newLeftRatio < minLeftRatio) {
|
|
281
|
+
gridLayout.style.gridTemplateColumns = `${minLeftRatio}fr 8px ${1 - minLeftRatio}fr`;
|
|
282
|
+
} else if (newLeftRatio > maxLeftRatio) {
|
|
283
|
+
gridLayout.style.gridTemplateColumns = `${maxLeftRatio}fr 8px ${1 - maxLeftRatio}fr`;
|
|
284
|
+
} else {
|
|
285
|
+
gridLayout.style.gridTemplateColumns = `${newLeftRatio}fr 8px ${newRightRatio}fr`;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function stopVResize() {
|
|
291
|
+
isVResizing = false;
|
|
292
|
+
document.getElementById('v-resizer')?.classList.remove('active');
|
|
293
|
+
document.removeEventListener('mousemove', handleVResize);
|
|
294
|
+
document.removeEventListener('mouseup', stopVResize);
|
|
295
|
+
|
|
296
|
+
// 保存布局比例
|
|
297
|
+
saveLayoutRatios();
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function startHResize(event: MouseEvent) {
|
|
301
|
+
isHResizing = true;
|
|
302
|
+
initialY = event.clientY;
|
|
303
|
+
|
|
304
|
+
const gridLayout = document.querySelector('.grid-layout') as HTMLElement;
|
|
305
|
+
initialGridTemplateRows = getComputedStyle(gridLayout).gridTemplateRows;
|
|
306
|
+
|
|
307
|
+
document.getElementById('h-resizer')?.classList.add('active');
|
|
308
|
+
|
|
309
|
+
document.addEventListener('mousemove', handleHResize);
|
|
310
|
+
document.addEventListener('mouseup', stopHResize);
|
|
311
|
+
|
|
312
|
+
// 防止文本选择
|
|
313
|
+
event.preventDefault();
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function handleHResize(event: MouseEvent) {
|
|
317
|
+
if (!isHResizing) return;
|
|
318
|
+
|
|
319
|
+
const gridLayout = document.querySelector('.grid-layout') as HTMLElement;
|
|
320
|
+
const delta = event.clientY - initialY;
|
|
321
|
+
|
|
322
|
+
// 解析当前的网格模板行值
|
|
323
|
+
const rows = initialGridTemplateRows.split(' ');
|
|
324
|
+
|
|
325
|
+
// 确保我们有足够的行
|
|
326
|
+
if (rows.length >= 3) {
|
|
327
|
+
// 计算新的上行高度
|
|
328
|
+
const topRowHeight = parseFloat(rows[0]);
|
|
329
|
+
const bottomRowHeight = parseFloat(rows[2]);
|
|
330
|
+
|
|
331
|
+
// 计算新的上下行比例
|
|
332
|
+
const totalHeight = topRowHeight + bottomRowHeight;
|
|
333
|
+
const newTopRatio = (topRowHeight + delta / gridLayout.clientHeight * totalHeight) / totalHeight;
|
|
334
|
+
const newBottomRatio = 1 - newTopRatio;
|
|
335
|
+
|
|
336
|
+
// 确保上方区域不小于总高度的20%且不大于80%
|
|
337
|
+
const minTopRatio = 0.2;
|
|
338
|
+
const maxTopRatio = 0.8;
|
|
339
|
+
|
|
340
|
+
if (newTopRatio < minTopRatio) {
|
|
341
|
+
gridLayout.style.gridTemplateRows = `${minTopRatio}fr 8px ${1 - minTopRatio}fr`;
|
|
342
|
+
} else if (newTopRatio > maxTopRatio) {
|
|
343
|
+
gridLayout.style.gridTemplateRows = `${maxTopRatio}fr 8px ${1 - maxTopRatio}fr`;
|
|
344
|
+
} else {
|
|
345
|
+
gridLayout.style.gridTemplateRows = `${newTopRatio}fr 8px ${newBottomRatio}fr`;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function stopHResize() {
|
|
351
|
+
isHResizing = false;
|
|
352
|
+
document.getElementById('h-resizer')?.classList.remove('active');
|
|
353
|
+
document.removeEventListener('mousemove', handleHResize);
|
|
354
|
+
document.removeEventListener('mouseup', stopHResize);
|
|
355
|
+
|
|
356
|
+
// 保存布局比例
|
|
357
|
+
saveLayoutRatios();
|
|
358
|
+
}
|
|
167
359
|
</script>
|
|
168
360
|
|
|
169
361
|
<template>
|
|
@@ -177,12 +369,33 @@ async function handleBranchChange(branch: string) {
|
|
|
177
369
|
<span class="user-label">用户:</span>
|
|
178
370
|
<span class="user-name">{{ gitStore.userName }}</span>
|
|
179
371
|
<span class="user-email"><{{ gitStore.userEmail }}></span>
|
|
372
|
+
<el-button
|
|
373
|
+
type="primary"
|
|
374
|
+
size="small"
|
|
375
|
+
@click="openUserSettingsDialog"
|
|
376
|
+
class="user-settings-btn"
|
|
377
|
+
circle
|
|
378
|
+
>
|
|
379
|
+
<el-icon><Setting /></el-icon>
|
|
380
|
+
</el-button>
|
|
381
|
+
</div>
|
|
382
|
+
<div id="user-info" v-else>
|
|
383
|
+
<span class="user-label">用户: </span>
|
|
384
|
+
<span class="user-warning">未配置</span>
|
|
385
|
+
<el-button
|
|
386
|
+
type="primary"
|
|
387
|
+
size="small"
|
|
388
|
+
@click="openUserSettingsDialog"
|
|
389
|
+
class="user-settings-btn"
|
|
390
|
+
circle
|
|
391
|
+
>
|
|
392
|
+
<el-icon><Setting /></el-icon>
|
|
393
|
+
</el-button>
|
|
180
394
|
</div>
|
|
181
|
-
<!-- <div id="config-info">{{ configInfo }}</div> -->
|
|
182
395
|
</div>
|
|
183
396
|
</header>
|
|
184
397
|
|
|
185
|
-
<
|
|
398
|
+
<main class="main-container">
|
|
186
399
|
<div v-if="!initCompleted" class="loading-container">
|
|
187
400
|
<el-card class="loading-card">
|
|
188
401
|
<div class="loading-spinner">
|
|
@@ -192,25 +405,48 @@ async function handleBranchChange(branch: string) {
|
|
|
192
405
|
</el-card>
|
|
193
406
|
</div>
|
|
194
407
|
|
|
195
|
-
<div v-else class="layout
|
|
196
|
-
<!--
|
|
197
|
-
<div class="
|
|
408
|
+
<div v-else class="grid-layout">
|
|
409
|
+
<!-- 上方左侧Git状态 -->
|
|
410
|
+
<div class="git-status-panel">
|
|
198
411
|
<GitStatus
|
|
199
412
|
ref="gitStatusRef"
|
|
200
413
|
:initial-directory="currentDirectory"
|
|
201
414
|
/>
|
|
202
415
|
</div>
|
|
203
416
|
|
|
204
|
-
<!--
|
|
205
|
-
<div class="
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
417
|
+
<!-- 垂直分隔条 -->
|
|
418
|
+
<div class="vertical-resizer" id="v-resizer" @mousedown="startVResize"></div>
|
|
419
|
+
|
|
420
|
+
<!-- 上方右侧提交表单 -->
|
|
421
|
+
<div class="commit-form-panel" v-if="gitStore.isGitRepo">
|
|
422
|
+
<!-- 当用户未配置时显示配置提示 -->
|
|
423
|
+
<div v-if="!gitStore.userName || !gitStore.userEmail" class="card">
|
|
424
|
+
<h2>Git用户未配置</h2>
|
|
425
|
+
<p>请先配置Git用户信息才能进行提交操作。</p>
|
|
426
|
+
<div class="tips">
|
|
427
|
+
<h3>您可以通过以下方式配置:</h3>
|
|
428
|
+
<ol>
|
|
429
|
+
<li>点击右上角的设置按钮,配置用户名和邮箱</li>
|
|
430
|
+
<li>或者使用命令行配置:</li>
|
|
431
|
+
<div class="code-block">
|
|
432
|
+
git config --global user.name "您的用户名"<br>
|
|
433
|
+
git config --global user.email "您的邮箱"
|
|
434
|
+
</div>
|
|
435
|
+
</ol>
|
|
436
|
+
<el-button
|
|
437
|
+
type="primary"
|
|
438
|
+
@click="openUserSettingsDialog"
|
|
439
|
+
>
|
|
440
|
+
立即配置
|
|
441
|
+
</el-button>
|
|
442
|
+
</div>
|
|
443
|
+
</div>
|
|
444
|
+
<!-- 用户已配置显示提交表单 -->
|
|
445
|
+
<template v-else>
|
|
446
|
+
<CommitForm />
|
|
447
|
+
</template>
|
|
212
448
|
</div>
|
|
213
|
-
<div class="
|
|
449
|
+
<div class="commit-form-panel" v-else>
|
|
214
450
|
<div class="card">
|
|
215
451
|
<h2>Git仓库初始化</h2>
|
|
216
452
|
<p>当前目录不是Git仓库,请先初始化Git仓库或切换到Git仓库目录。</p>
|
|
@@ -221,6 +457,14 @@ async function handleBranchChange(branch: string) {
|
|
|
221
457
|
</div>
|
|
222
458
|
</div>
|
|
223
459
|
</div>
|
|
460
|
+
|
|
461
|
+
<!-- 水平分隔条 -->
|
|
462
|
+
<div class="horizontal-resizer" id="h-resizer" @mousedown="startHResize"></div>
|
|
463
|
+
|
|
464
|
+
<!-- 下方提交历史 -->
|
|
465
|
+
<div class="log-list-panel" v-if="gitStore.isGitRepo">
|
|
466
|
+
<LogList ref="logListRef" />
|
|
467
|
+
</div>
|
|
224
468
|
|
|
225
469
|
<!-- 创建分支对话框 -->
|
|
226
470
|
<el-dialog
|
|
@@ -259,38 +503,84 @@ async function handleBranchChange(branch: string) {
|
|
|
259
503
|
</el-dialog>
|
|
260
504
|
|
|
261
505
|
</div>
|
|
262
|
-
</
|
|
506
|
+
</main>
|
|
263
507
|
|
|
264
508
|
<footer class="main-footer">
|
|
265
509
|
<div class="branch-info" v-if="gitStore.currentBranch">
|
|
266
|
-
<
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
510
|
+
<div class="branch-wrapper">
|
|
511
|
+
<span class="branch-label">当前分支:</span>
|
|
512
|
+
<el-select
|
|
513
|
+
v-model="gitStore.currentBranch"
|
|
514
|
+
size="small"
|
|
515
|
+
@change="handleBranchChange"
|
|
516
|
+
:loading="gitStore.isChangingBranch"
|
|
517
|
+
class="branch-select"
|
|
518
|
+
>
|
|
519
|
+
<el-option
|
|
520
|
+
v-for="branch in gitStore.allBranches"
|
|
521
|
+
:key="branch"
|
|
522
|
+
:label="branch"
|
|
523
|
+
:value="branch"
|
|
524
|
+
/>
|
|
525
|
+
</el-select>
|
|
526
|
+
<el-button
|
|
527
|
+
type="primary"
|
|
528
|
+
size="small"
|
|
529
|
+
@click="openCreateBranchDialog"
|
|
530
|
+
class="create-branch-btn"
|
|
531
|
+
>
|
|
532
|
+
<el-icon><Plus /></el-icon>
|
|
533
|
+
新建分支
|
|
534
|
+
</el-button>
|
|
535
|
+
</div>
|
|
289
536
|
</div>
|
|
290
537
|
<div class="footer-right">
|
|
291
538
|
<!-- <span>Zen GitSync © 2024</span> -->
|
|
292
539
|
</div>
|
|
293
540
|
</footer>
|
|
541
|
+
|
|
542
|
+
<!-- 用户设置对话框 -->
|
|
543
|
+
<el-dialog
|
|
544
|
+
v-model="userSettingsDialogVisible"
|
|
545
|
+
title="Git用户设置"
|
|
546
|
+
width="30%"
|
|
547
|
+
destroy-on-close
|
|
548
|
+
>
|
|
549
|
+
<el-form>
|
|
550
|
+
<el-form-item label="用户名">
|
|
551
|
+
<el-input v-model="tempUserName" placeholder="请输入Git用户名" />
|
|
552
|
+
</el-form-item>
|
|
553
|
+
<el-form-item label="邮箱">
|
|
554
|
+
<el-input v-model="tempUserEmail" placeholder="请输入Git邮箱" />
|
|
555
|
+
</el-form-item>
|
|
556
|
+
<el-form-item>
|
|
557
|
+
<el-alert
|
|
558
|
+
type="info"
|
|
559
|
+
:closable="false"
|
|
560
|
+
show-icon
|
|
561
|
+
>
|
|
562
|
+
这些设置将影响全局Git配置,对所有Git仓库生效。
|
|
563
|
+
</el-alert>
|
|
564
|
+
</el-form-item>
|
|
565
|
+
</el-form>
|
|
566
|
+
<template #footer>
|
|
567
|
+
<span class="dialog-footer">
|
|
568
|
+
<el-button
|
|
569
|
+
type="danger"
|
|
570
|
+
@click="clearUserSettings"
|
|
571
|
+
>
|
|
572
|
+
清除配置
|
|
573
|
+
</el-button>
|
|
574
|
+
<el-button @click="userSettingsDialogVisible = false">取消</el-button>
|
|
575
|
+
<el-button
|
|
576
|
+
type="primary"
|
|
577
|
+
@click="saveUserSettings"
|
|
578
|
+
>
|
|
579
|
+
保存
|
|
580
|
+
</el-button>
|
|
581
|
+
</span>
|
|
582
|
+
</template>
|
|
583
|
+
</el-dialog>
|
|
294
584
|
</template>
|
|
295
585
|
|
|
296
586
|
<style>
|
|
@@ -299,11 +589,65 @@ body {
|
|
|
299
589
|
margin: 0;
|
|
300
590
|
padding: 0;
|
|
301
591
|
background-color: #f5f5f5;
|
|
592
|
+
overflow: hidden; /* 防止出现滚动条 */
|
|
593
|
+
height: 100vh;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
.main-container {
|
|
597
|
+
position: fixed;
|
|
598
|
+
top: 60px; /* 顶部导航栏高度 */
|
|
599
|
+
bottom: 60px; /* 底部footer高度 */
|
|
600
|
+
left: 0;
|
|
601
|
+
right: 0;
|
|
602
|
+
padding: 10px;
|
|
603
|
+
overflow: hidden; /* 防止整体滚动 */
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
.grid-layout {
|
|
607
|
+
display: grid;
|
|
608
|
+
grid-template-columns: 1fr 8px 3fr; /* 左右区域比例为1:3 */
|
|
609
|
+
grid-template-rows: 1fr 8px 1fr;
|
|
610
|
+
grid-template-areas:
|
|
611
|
+
"git-status v-resizer commit-form"
|
|
612
|
+
"h-resizer h-resizer h-resizer"
|
|
613
|
+
"log-list log-list log-list";
|
|
614
|
+
gap: 10px;
|
|
615
|
+
height: 100%;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
.git-status-panel {
|
|
619
|
+
grid-area: git-status;
|
|
620
|
+
overflow: hidden;
|
|
621
|
+
max-height: 100%;
|
|
622
|
+
padding: 0;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
.commit-form-panel {
|
|
626
|
+
grid-area: commit-form;
|
|
627
|
+
overflow: hidden;
|
|
628
|
+
max-height: 100%;
|
|
629
|
+
padding: 0;
|
|
302
630
|
}
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
631
|
+
|
|
632
|
+
.log-list-panel {
|
|
633
|
+
grid-area: log-list;
|
|
634
|
+
overflow: hidden;
|
|
635
|
+
max-height: 100%;
|
|
636
|
+
padding: 0;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/* 确保每个卡片内部可以滚动 */
|
|
640
|
+
.card {
|
|
641
|
+
background-color: white;
|
|
642
|
+
border-radius: 8px;
|
|
643
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
|
|
644
|
+
border: 1px solid rgba(0, 0, 0, 0.03);
|
|
645
|
+
height: 100%;
|
|
646
|
+
overflow: hidden;
|
|
647
|
+
display: flex;
|
|
648
|
+
flex-direction: column;
|
|
306
649
|
}
|
|
650
|
+
|
|
307
651
|
.main-header {
|
|
308
652
|
background-color: #24292e;
|
|
309
653
|
color: white;
|
|
@@ -311,53 +655,64 @@ body {
|
|
|
311
655
|
display: flex;
|
|
312
656
|
justify-content: space-between;
|
|
313
657
|
align-items: center;
|
|
658
|
+
position: fixed;
|
|
659
|
+
top: 0;
|
|
660
|
+
left: 0;
|
|
661
|
+
right: 0;
|
|
662
|
+
z-index: 1000;
|
|
663
|
+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
|
|
664
|
+
height: 60px;
|
|
665
|
+
box-sizing: border-box;
|
|
314
666
|
}
|
|
667
|
+
|
|
315
668
|
.header-left {
|
|
316
669
|
display: flex;
|
|
317
670
|
align-items: center;
|
|
318
671
|
gap: 10px;
|
|
319
672
|
}
|
|
673
|
+
|
|
320
674
|
.logo {
|
|
321
675
|
height: 32px;
|
|
322
676
|
width: auto;
|
|
323
677
|
}
|
|
678
|
+
|
|
324
679
|
h1 {
|
|
325
680
|
margin: 0;
|
|
326
681
|
font-size: 24px;
|
|
327
682
|
}
|
|
683
|
+
|
|
328
684
|
.header-info {
|
|
329
685
|
display: flex;
|
|
330
686
|
flex-direction: column;
|
|
331
687
|
align-items: flex-end;
|
|
332
688
|
gap: 5px;
|
|
333
689
|
}
|
|
690
|
+
|
|
334
691
|
#branch-info, #user-info {
|
|
335
692
|
background-color: rgba(255, 255, 255, 0.1);
|
|
336
693
|
padding: 4px 8px;
|
|
337
694
|
border-radius: 4px;
|
|
338
695
|
font-size: 14px;
|
|
339
696
|
}
|
|
697
|
+
|
|
340
698
|
.branch-label, .user-label {
|
|
341
699
|
font-weight: bold;
|
|
342
700
|
margin-right: 5px;
|
|
343
701
|
}
|
|
702
|
+
|
|
344
703
|
.user-name {
|
|
345
704
|
font-weight: bold;
|
|
346
705
|
margin-right: 5px;
|
|
347
706
|
}
|
|
707
|
+
|
|
348
708
|
.user-email {
|
|
349
709
|
color: #e0e0e0;
|
|
350
710
|
}
|
|
711
|
+
|
|
351
712
|
.branch-name {
|
|
352
713
|
font-family: monospace;
|
|
353
714
|
}
|
|
354
|
-
|
|
355
|
-
background-color: white;
|
|
356
|
-
border-radius: 5px;
|
|
357
|
-
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
|
|
358
|
-
margin-bottom: 20px;
|
|
359
|
-
padding: 20px;
|
|
360
|
-
}
|
|
715
|
+
|
|
361
716
|
.status-box {
|
|
362
717
|
background-color: #f6f8fa;
|
|
363
718
|
border: 1px solid #e1e4e8;
|
|
@@ -365,100 +720,9 @@ h1 {
|
|
|
365
720
|
padding: 15px;
|
|
366
721
|
white-space: pre-wrap;
|
|
367
722
|
font-family: monospace;
|
|
368
|
-
max-height: 300px;
|
|
369
723
|
overflow-y: auto;
|
|
370
724
|
}
|
|
371
725
|
|
|
372
|
-
/* 新增布局样式 */
|
|
373
|
-
.layout-container {
|
|
374
|
-
display: flex;
|
|
375
|
-
gap: 20px;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
.left-panel {
|
|
379
|
-
flex: 0 0 30%;
|
|
380
|
-
max-width: 30%;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
.right-panel {
|
|
384
|
-
flex: 0 0 70%;
|
|
385
|
-
max-width: 70%;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
/* 响应式布局 */
|
|
389
|
-
@media (max-width: 768px) {
|
|
390
|
-
.layout-container {
|
|
391
|
-
flex-direction: column;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
.left-panel, .right-panel {
|
|
395
|
-
flex: 0 0 100%;
|
|
396
|
-
max-width: 100%;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
.header-left {
|
|
400
|
-
gap: 8px;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
.logo {
|
|
404
|
-
height: 24px;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
h1 {
|
|
408
|
-
font-size: 20px;
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
.commit-form {
|
|
412
|
-
display: flex;
|
|
413
|
-
margin-bottom: 15px;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
.log-item {
|
|
417
|
-
padding: 10px 0;
|
|
418
|
-
border-bottom: 1px solid #eee;
|
|
419
|
-
}
|
|
420
|
-
.log-item:last-child {
|
|
421
|
-
border-bottom: none;
|
|
422
|
-
}
|
|
423
|
-
.log-hash {
|
|
424
|
-
color: #6f42c1;
|
|
425
|
-
font-family: monospace;
|
|
426
|
-
}
|
|
427
|
-
.log-author {
|
|
428
|
-
color: #6a737d;
|
|
429
|
-
}
|
|
430
|
-
.log-date {
|
|
431
|
-
color: #6a737d;
|
|
432
|
-
}
|
|
433
|
-
.log-message {
|
|
434
|
-
font-weight: bold;
|
|
435
|
-
}
|
|
436
|
-
.log-branch {
|
|
437
|
-
display: inline-block;
|
|
438
|
-
background-color: #0366d6;
|
|
439
|
-
color: white;
|
|
440
|
-
border-radius: 3px;
|
|
441
|
-
padding: 2px 6px;
|
|
442
|
-
margin-left: 8px;
|
|
443
|
-
font-size: 12px;
|
|
444
|
-
}
|
|
445
|
-
/* 添加分支选择框样式 */
|
|
446
|
-
.branch-select {
|
|
447
|
-
width: 150px;
|
|
448
|
-
margin-left: 5px;
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
/* 调整下拉选择框在深色背景下的样式 */
|
|
452
|
-
.branch-select :deep(.el-input__inner) {
|
|
453
|
-
background-color: rgba(255, 255, 255, 0.1);
|
|
454
|
-
color: white;
|
|
455
|
-
border: none;
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
.branch-select :deep(.el-input__suffix) {
|
|
459
|
-
color: white;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
726
|
.tips {
|
|
463
727
|
margin-top: 20px;
|
|
464
728
|
padding: 15px;
|
|
@@ -482,12 +746,12 @@ h1 {
|
|
|
482
746
|
margin-bottom: 10px;
|
|
483
747
|
}
|
|
484
748
|
|
|
485
|
-
/*
|
|
749
|
+
/* 加载中样式 */
|
|
486
750
|
.loading-container {
|
|
487
751
|
display: flex;
|
|
488
752
|
justify-content: center;
|
|
489
753
|
align-items: center;
|
|
490
|
-
|
|
754
|
+
height: 100%;
|
|
491
755
|
}
|
|
492
756
|
|
|
493
757
|
.loading-card {
|
|
@@ -506,16 +770,16 @@ h1 {
|
|
|
506
770
|
font-size: 18px;
|
|
507
771
|
color: #606266;
|
|
508
772
|
}
|
|
509
|
-
</style>
|
|
510
773
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
will-change: filter;
|
|
514
|
-
transition: filter 300ms;
|
|
774
|
+
.user-settings-btn {
|
|
775
|
+
margin-left: 10px;
|
|
515
776
|
}
|
|
516
|
-
|
|
517
|
-
|
|
777
|
+
|
|
778
|
+
.user-warning {
|
|
779
|
+
color: #E6A23C;
|
|
780
|
+
font-weight: bold;
|
|
518
781
|
}
|
|
782
|
+
|
|
519
783
|
.main-footer {
|
|
520
784
|
background-color: #24292e;
|
|
521
785
|
color: white;
|
|
@@ -528,15 +792,191 @@ h1 {
|
|
|
528
792
|
left: 0;
|
|
529
793
|
right: 0;
|
|
530
794
|
z-index: 100;
|
|
795
|
+
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.1);
|
|
796
|
+
height: 60px;
|
|
797
|
+
box-sizing: border-box;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
/* 响应式布局 */
|
|
801
|
+
@media (max-width: 768px) {
|
|
802
|
+
.grid-layout {
|
|
803
|
+
grid-template-columns: 1fr;
|
|
804
|
+
grid-template-rows: auto auto auto auto auto;
|
|
805
|
+
grid-template-areas:
|
|
806
|
+
"git-status"
|
|
807
|
+
"v-resizer"
|
|
808
|
+
"commit-form"
|
|
809
|
+
"h-resizer"
|
|
810
|
+
"log-list";
|
|
811
|
+
gap: 10px;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
.vertical-resizer {
|
|
815
|
+
height: 10px;
|
|
816
|
+
cursor: row-resize;
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
.vertical-resizer::after {
|
|
820
|
+
width: 30px;
|
|
821
|
+
height: 4px;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
.git-status-panel,
|
|
825
|
+
.commit-form-panel,
|
|
826
|
+
.log-list-panel {
|
|
827
|
+
padding: 0;
|
|
828
|
+
max-height: none;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
.git-status-panel {
|
|
832
|
+
max-height: 30vh;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
.commit-form-panel {
|
|
836
|
+
max-height: 30vh;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
.log-list-panel {
|
|
840
|
+
max-height: 40vh;
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
</style>
|
|
844
|
+
|
|
845
|
+
<style scoped>
|
|
846
|
+
.logo {
|
|
847
|
+
will-change: filter;
|
|
848
|
+
transition: filter 300ms;
|
|
849
|
+
}
|
|
850
|
+
.logo:hover {
|
|
851
|
+
filter: drop-shadow(0 0 2em #42b883aa);
|
|
531
852
|
}
|
|
532
853
|
|
|
533
854
|
.branch-info {
|
|
534
855
|
display: flex;
|
|
535
856
|
align-items: center;
|
|
857
|
+
gap: 10px;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
.branch-wrapper {
|
|
861
|
+
display: flex;
|
|
862
|
+
align-items: center;
|
|
863
|
+
background-color: rgba(255, 255, 255, 0.15);
|
|
864
|
+
border-radius: 4px;
|
|
865
|
+
padding: 8px 12px;
|
|
866
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
|
867
|
+
transition: all 0.3s;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
.branch-wrapper:hover {
|
|
871
|
+
background-color: rgba(255, 255, 255, 0.2);
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
.branch-label {
|
|
875
|
+
font-weight: bold;
|
|
876
|
+
margin-right: 10px;
|
|
877
|
+
color: #ffffff;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
.branch-select {
|
|
881
|
+
width: 200px;
|
|
882
|
+
margin-right: 10px;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
.create-branch-btn {
|
|
886
|
+
background-color: #2ea44f;
|
|
887
|
+
border-color: #2ea44f;
|
|
888
|
+
transition: all 0.3s;
|
|
889
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
.create-branch-btn:hover {
|
|
893
|
+
background-color: #3bbc63;
|
|
894
|
+
border-color: #3bbc63;
|
|
895
|
+
transform: translateY(-2px);
|
|
896
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
|
536
897
|
}
|
|
537
898
|
|
|
538
899
|
.footer-right {
|
|
539
|
-
|
|
540
|
-
|
|
900
|
+
display: flex;
|
|
901
|
+
align-items: center;
|
|
902
|
+
gap: 10px;
|
|
903
|
+
color: rgba(255, 255, 255, 0.9);
|
|
904
|
+
font-size: 13px;
|
|
905
|
+
background-color: rgba(255, 255, 255, 0.1);
|
|
906
|
+
padding: 8px 12px;
|
|
907
|
+
border-radius: 4px;
|
|
908
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
/* 垂直分隔条样式 */
|
|
912
|
+
.vertical-resizer {
|
|
913
|
+
grid-area: v-resizer;
|
|
914
|
+
background-color: #e8e8e8;
|
|
915
|
+
cursor: col-resize;
|
|
916
|
+
transition: background-color 0.2s, box-shadow 0.2s;
|
|
917
|
+
position: relative;
|
|
918
|
+
z-index: 10;
|
|
919
|
+
border-radius: 8px; /* 增加圆角 */
|
|
920
|
+
box-shadow: 0 0 3px rgba(0, 0, 0, 0.1);
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
.vertical-resizer::after {
|
|
924
|
+
content: '';
|
|
925
|
+
position: absolute;
|
|
926
|
+
top: 50%;
|
|
927
|
+
left: 50%;
|
|
928
|
+
transform: translate(-50%, -50%);
|
|
929
|
+
width: 4px;
|
|
930
|
+
height: 50px;
|
|
931
|
+
background-color: #a0a0a0;
|
|
932
|
+
border-radius: 4px; /* 增加圆角 */
|
|
933
|
+
transition: background-color 0.2s, width 0.2s, box-shadow 0.2s;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
.vertical-resizer:hover, .vertical-resizer.active {
|
|
937
|
+
background-color: #d0d0d0;
|
|
938
|
+
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
.vertical-resizer:hover::after, .vertical-resizer.active::after {
|
|
942
|
+
background-color: #409EFF;
|
|
943
|
+
width: 6px;
|
|
944
|
+
box-shadow: 0 0 8px rgba(64, 158, 255, 0.6);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
/* 水平分隔条样式 */
|
|
948
|
+
.horizontal-resizer {
|
|
949
|
+
grid-area: h-resizer;
|
|
950
|
+
background-color: #e8e8e8;
|
|
951
|
+
cursor: row-resize;
|
|
952
|
+
transition: background-color 0.2s, box-shadow 0.2s;
|
|
953
|
+
position: relative;
|
|
954
|
+
z-index: 10;
|
|
955
|
+
border-radius: 8px; /* 增加圆角 */
|
|
956
|
+
box-shadow: 0 0 3px rgba(0, 0, 0, 0.1);
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
.horizontal-resizer::after {
|
|
960
|
+
content: '';
|
|
961
|
+
position: absolute;
|
|
962
|
+
top: 50%;
|
|
963
|
+
left: 50%;
|
|
964
|
+
transform: translate(-50%, -50%);
|
|
965
|
+
width: 50px;
|
|
966
|
+
height: 4px;
|
|
967
|
+
background-color: #a0a0a0;
|
|
968
|
+
border-radius: 4px; /* 增加圆角 */
|
|
969
|
+
transition: background-color 0.2s, height 0.2s, box-shadow 0.2s;
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
.horizontal-resizer:hover, .horizontal-resizer.active {
|
|
973
|
+
background-color: #d0d0d0;
|
|
974
|
+
box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
.horizontal-resizer:hover::after, .horizontal-resizer.active::after {
|
|
978
|
+
background-color: #409EFF;
|
|
979
|
+
height: 6px;
|
|
980
|
+
box-shadow: 0 0 8px rgba(64, 158, 255, 0.6);
|
|
541
981
|
}
|
|
542
982
|
</style>
|