zen-gitsync 2.0.3 → 2.0.5
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/package.json +1 -0
- package/src/ui/client/src/App.vue +368 -219
- package/src/ui/client/src/components/CommitForm.vue +777 -442
- package/src/ui/client/src/components/GitStatus.vue +89 -86
- package/src/ui/client/src/components/LogList.vue +393 -85
- package/src/ui/client/src/main.ts +3 -0
- package/src/ui/client/src/stores/gitLogStore.ts +464 -0
- package/src/ui/client/src/stores/gitStore.ts +301 -0
- package/src/ui/client/stats.html +1 -1
- package/src/ui/public/assets/index-CALk9kKc.js +9 -0
- package/src/ui/public/assets/index-D3zIiSNw.css +1 -0
- package/src/ui/public/assets/vendor-BfXVsoKv.js +45 -0
- package/src/ui/public/index.html +3 -3
- package/src/ui/server/index.js +197 -8
- package/src/ui/public/assets/index-BHmYZROy.css +0 -1
- package/src/ui/public/assets/index-kfMX1bxz.js +0 -9
- package/src/ui/public/assets/vendor-DxvF30ca.js +0 -41
|
@@ -1,105 +1,200 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { ref, onMounted,
|
|
3
|
-
import { ElTable, ElTableColumn, ElTag, ElButton } from 'element-plus'
|
|
4
|
-
import { RefreshRight } from '@element-plus/icons-vue'
|
|
2
|
+
import { ref, onMounted, computed, watch } from 'vue'
|
|
3
|
+
import { ElTable, ElTableColumn, ElTag, ElButton, ElSlider } from 'element-plus'
|
|
4
|
+
import { RefreshRight, ZoomIn, ZoomOut } from '@element-plus/icons-vue'
|
|
5
5
|
import 'element-plus/dist/index.css'
|
|
6
6
|
import { createGitgraph } from '@gitgraph/js'
|
|
7
|
+
import { useGitLogStore } from '../stores/gitLogStore'
|
|
8
|
+
import { useGitStore } from '../stores/gitStore'
|
|
7
9
|
|
|
8
10
|
interface LogItem {
|
|
9
11
|
hash: string
|
|
10
12
|
date: string
|
|
11
13
|
author: string
|
|
12
|
-
email: string
|
|
14
|
+
email: string
|
|
13
15
|
message: string
|
|
14
|
-
branch?: string
|
|
15
|
-
parents?: string[]
|
|
16
|
+
branch?: string
|
|
17
|
+
parents?: string[]
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
// 使用Git状态和日志Store
|
|
21
|
+
const gitLogStore = useGitLogStore()
|
|
22
|
+
const gitStore = useGitStore()
|
|
23
|
+
|
|
24
|
+
// 获取日志数据
|
|
25
|
+
let logsData: LogItem[] = []
|
|
26
|
+
const logs = ref<LogItem[]>(logsData)
|
|
19
27
|
const errorMessage = ref('')
|
|
20
|
-
|
|
28
|
+
// 定义本地加载状态,而不是依赖于computed
|
|
29
|
+
const localLoading = ref(false)
|
|
30
|
+
const isLoading = computed(() => gitLogStore.isLoadingLog || localLoading.value)
|
|
21
31
|
const showAllCommits = ref(false)
|
|
22
32
|
const totalCommits = ref(0)
|
|
23
|
-
const showGraphView = ref(true)
|
|
33
|
+
const showGraphView = ref(true)
|
|
24
34
|
const graphContainer = ref<HTMLElement | null>(null)
|
|
25
35
|
|
|
36
|
+
// 添加图表缩放控制
|
|
37
|
+
const graphScale = ref(1)
|
|
38
|
+
const minScale = 0.5
|
|
39
|
+
const maxScale = 1.5
|
|
40
|
+
const scaleStep = 0.1
|
|
41
|
+
|
|
42
|
+
// 添加日志被刷新的提示状态
|
|
43
|
+
const logRefreshed = ref(false)
|
|
44
|
+
|
|
26
45
|
// 加载提交历史
|
|
27
46
|
async function loadLog(all = false) {
|
|
47
|
+
// 从gitStore获取仓库状态
|
|
48
|
+
const gitStore = useGitStore()
|
|
49
|
+
|
|
50
|
+
// 检查是否是Git仓库
|
|
51
|
+
if (!gitStore.isGitRepo) {
|
|
52
|
+
errorMessage.value = '当前目录不是Git仓库'
|
|
53
|
+
return
|
|
54
|
+
}
|
|
55
|
+
|
|
28
56
|
try {
|
|
29
|
-
isLoading.value = true
|
|
30
57
|
showAllCommits.value = all
|
|
31
|
-
|
|
58
|
+
|
|
59
|
+
// 设置本地加载状态
|
|
60
|
+
localLoading.value = true
|
|
61
|
+
|
|
62
|
+
// 保留graph参数,但服务器端其实不做特殊处理
|
|
63
|
+
// 这样可以兼容之前的代码,避免大量修改
|
|
32
64
|
const url = all ? '/api/log?all=true&graph=true' : '/api/log?graph=true'
|
|
65
|
+
console.log(`加载日志数据: ${url}`)
|
|
66
|
+
|
|
33
67
|
const response = await fetch(url)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
68
|
+
const data = await response.json()
|
|
69
|
+
|
|
70
|
+
// 清空现有数据
|
|
71
|
+
logsData.length = 0
|
|
72
|
+
|
|
73
|
+
// 更新本地数据
|
|
74
|
+
if (Array.isArray(data)) {
|
|
75
|
+
// 新的API格式,直接返回数组
|
|
76
|
+
console.log(`日志加载完成: 共${data.length}条记录`)
|
|
77
|
+
|
|
78
|
+
// 填充logsData
|
|
79
|
+
data.forEach((item: LogItem) => logsData.push(item))
|
|
80
|
+
|
|
81
|
+
totalCommits.value = data.length
|
|
82
|
+
} else if (data.log && Array.isArray(data.log)) {
|
|
83
|
+
// 旧版API格式,兼容处理
|
|
84
|
+
console.log(`日志加载完成: 共${data.log.length}条记录`)
|
|
85
|
+
|
|
86
|
+
// 填充logsData
|
|
87
|
+
data.log.forEach((item: LogItem) => logsData.push(item))
|
|
88
|
+
|
|
89
|
+
totalCommits.value = data.log.length
|
|
90
|
+
} else {
|
|
91
|
+
console.error('未知的日志数据格式:', data)
|
|
92
|
+
errorMessage.value = '日志数据格式错误'
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// 确保logs.value也更新
|
|
97
|
+
logs.value = [...logsData]
|
|
98
|
+
|
|
99
|
+
console.log(`logsData长度: ${logsData.length}`) // 添加调试日志
|
|
100
|
+
|
|
101
|
+
// 设置刷新提示状态
|
|
102
|
+
logRefreshed.value = true
|
|
103
|
+
// 2秒后隐藏提示
|
|
104
|
+
setTimeout(() => { logRefreshed.value = false }, 2000)
|
|
37
105
|
|
|
38
106
|
// 加载完数据后渲染图表
|
|
39
107
|
if (showGraphView.value) {
|
|
40
108
|
setTimeout(renderGraph, 0)
|
|
41
109
|
}
|
|
110
|
+
|
|
111
|
+
errorMessage.value = ''
|
|
42
112
|
} catch (error) {
|
|
43
|
-
errorMessage.value = '加载提交历史失败: ' + (error
|
|
113
|
+
errorMessage.value = '加载提交历史失败: ' + (error instanceof Error ? error.message : String(error))
|
|
114
|
+
console.error('加载日志失败:', error)
|
|
44
115
|
} finally {
|
|
45
|
-
|
|
116
|
+
// 重置本地加载状态
|
|
117
|
+
localLoading.value = false
|
|
46
118
|
}
|
|
47
119
|
}
|
|
48
120
|
|
|
49
121
|
// 渲染Git图表
|
|
50
122
|
async function renderGraph() {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
// 清空容器
|
|
54
|
-
graphContainer.value.innerHTML = ''
|
|
123
|
+
console.log(`开始渲染图表...数据长度: ${logsData.length}`)
|
|
55
124
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
// 创建gitgraph实例
|
|
61
|
-
const gitgraph = createGitgraph(graphContainer.value, {
|
|
62
|
-
// 自定义选项
|
|
63
|
-
// @ts-ignore: true
|
|
64
|
-
orientation: 'vertical-reverse', // 从上到下的方向
|
|
65
|
-
// @ts-ignore: true
|
|
66
|
-
template: 'metro', // 使用metro模板
|
|
67
|
-
author: '提交者 <committer@example.com>'
|
|
68
|
-
})
|
|
125
|
+
if (!graphContainer.value) {
|
|
126
|
+
console.error('图表容器未找到')
|
|
127
|
+
return
|
|
128
|
+
}
|
|
69
129
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
branches[currentBranch || 'main'] = mainBranch
|
|
130
|
+
if (logsData.length === 0) {
|
|
131
|
+
console.error('没有日志数据可渲染')
|
|
132
|
+
return
|
|
133
|
+
}
|
|
75
134
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
let currentBranch = mainBranch
|
|
135
|
+
try {
|
|
136
|
+
// 清空容器
|
|
137
|
+
graphContainer.value.innerHTML = ''
|
|
80
138
|
|
|
81
|
-
|
|
82
|
-
if (commit.branch) {
|
|
83
|
-
const branchName = formatBranchName(commit.branch.split(',')[0])
|
|
84
|
-
if (!branches[branchName]) {
|
|
85
|
-
branches[branchName] = gitgraph.branch(branchName)
|
|
86
|
-
}
|
|
87
|
-
currentBranch = branches[branchName]
|
|
88
|
-
}
|
|
139
|
+
console.log(`创建gitgraph实例,分支: ${gitStore.currentBranch || 'main'}`)
|
|
89
140
|
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
141
|
+
// 创建gitgraph实例
|
|
142
|
+
const gitgraph = createGitgraph(graphContainer.value, {
|
|
143
|
+
// 自定义选项
|
|
144
|
+
orientation: 'vertical-reverse' as any, // 使用类型断言解决类型错误
|
|
145
|
+
template: 'metro' as any, // 使用类型断言解决类型错误
|
|
146
|
+
author: '提交者 <committer@example.com>'
|
|
95
147
|
})
|
|
96
|
-
|
|
148
|
+
|
|
149
|
+
// 处理分支和提交数据
|
|
150
|
+
const branches: Record<string, any> = {}
|
|
151
|
+
const mainBranch = gitgraph.branch(gitStore.currentBranch || 'main')
|
|
152
|
+
branches[gitStore.currentBranch || 'main'] = mainBranch
|
|
153
|
+
|
|
154
|
+
console.log(`开始创建提交图...共${logsData.length}条提交`)
|
|
155
|
+
|
|
156
|
+
// 简化示例 - 实际实现需要根据API返回的数据结构调整
|
|
157
|
+
logsData.forEach((commit, index) => {
|
|
158
|
+
// 这里需要根据实际数据结构构建分支图
|
|
159
|
+
let currentBranch = mainBranch
|
|
160
|
+
|
|
161
|
+
// 如果有分支信息,使用对应的分支
|
|
162
|
+
if (commit.branch) {
|
|
163
|
+
const branchName = formatBranchName(commit.branch.split(',')[0])
|
|
164
|
+
if (!branches[branchName]) {
|
|
165
|
+
branches[branchName] = gitgraph.branch(branchName)
|
|
166
|
+
}
|
|
167
|
+
currentBranch = branches[branchName]
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// 创建提交,添加邮箱信息
|
|
171
|
+
currentBranch.commit({
|
|
172
|
+
hash: commit.hash,
|
|
173
|
+
subject: commit.message,
|
|
174
|
+
author: `${commit.author} <${commit.email}>`
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
if (index % 10 === 0) {
|
|
178
|
+
console.log(`已渲染 ${index + 1}/${logsData.length} 个提交`)
|
|
179
|
+
}
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
console.log('图表渲染完成')
|
|
183
|
+
|
|
184
|
+
// 确保渲染完成后调用自适应缩放
|
|
185
|
+
setTimeout(() => {
|
|
186
|
+
fitGraphToContainer()
|
|
187
|
+
}, 100)
|
|
188
|
+
} catch (error) {
|
|
189
|
+
console.error('渲染图表失败:', error)
|
|
190
|
+
errorMessage.value = '渲染图表失败: ' + (error instanceof Error ? error.message : String(error))
|
|
191
|
+
}
|
|
97
192
|
}
|
|
98
193
|
|
|
99
194
|
// 切换视图模式
|
|
100
195
|
function toggleViewMode() {
|
|
101
196
|
showGraphView.value = !showGraphView.value
|
|
102
|
-
if (showGraphView.value &&
|
|
197
|
+
if (showGraphView.value && logsData.length > 0) {
|
|
103
198
|
// 延迟执行以确保DOM已更新
|
|
104
199
|
setTimeout(renderGraph, 0)
|
|
105
200
|
}
|
|
@@ -110,14 +205,146 @@ function toggleAllCommits() {
|
|
|
110
205
|
loadLog(!showAllCommits.value)
|
|
111
206
|
}
|
|
112
207
|
|
|
208
|
+
// 格式化分支名(实现该函数,因为在模板中调用了)
|
|
209
|
+
function formatBranchName(ref: string) {
|
|
210
|
+
// 处理HEAD、远程分支等情况
|
|
211
|
+
if (ref.includes('HEAD -> ')) {
|
|
212
|
+
return ref.replace('HEAD -> ', '')
|
|
213
|
+
}
|
|
214
|
+
if (ref.includes('origin/')) {
|
|
215
|
+
return ref
|
|
216
|
+
}
|
|
217
|
+
return ref.trim()
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// 获取分支标签类型(实现该函数,因为在模板中调用了)
|
|
221
|
+
function getBranchTagType(ref: string) {
|
|
222
|
+
if (ref.includes('HEAD')) return 'success'
|
|
223
|
+
if (ref.includes('origin/')) return 'warning'
|
|
224
|
+
return 'info'
|
|
225
|
+
}
|
|
226
|
+
|
|
113
227
|
onMounted(() => {
|
|
114
|
-
|
|
228
|
+
// 检查gitLogStore中是否已有数据
|
|
229
|
+
if (gitStore.isGitRepo) {
|
|
230
|
+
if (gitLogStore.log.length > 0) {
|
|
231
|
+
// 如果已经有数据,直接使用现有数据
|
|
232
|
+
console.log('使用已加载的日志数据')
|
|
233
|
+
|
|
234
|
+
// 清空并填充logsData
|
|
235
|
+
logsData.length = 0
|
|
236
|
+
gitLogStore.log.forEach(item => logsData.push(item))
|
|
237
|
+
|
|
238
|
+
// 由于TypeScript类型错误,我们直接设置totalCommits而不是使用logs.value.length
|
|
239
|
+
totalCommits.value = gitLogStore.log.length
|
|
240
|
+
|
|
241
|
+
// 确保视图被渲染
|
|
242
|
+
if (showGraphView.value) {
|
|
243
|
+
setTimeout(() => {
|
|
244
|
+
console.log(`准备渲染图表,数据长度: ${logsData.length}`)
|
|
245
|
+
renderGraph()
|
|
246
|
+
}, 100)
|
|
247
|
+
}
|
|
248
|
+
} else {
|
|
249
|
+
// 否则加载数据
|
|
250
|
+
console.log('初始加载日志数据')
|
|
251
|
+
loadLog()
|
|
252
|
+
}
|
|
253
|
+
} else {
|
|
254
|
+
errorMessage.value = '当前目录不是Git仓库'
|
|
255
|
+
}
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
// 简化刷新函数,只需调用loadLog即可
|
|
259
|
+
const refreshLog = () => {
|
|
260
|
+
if (!gitStore.isGitRepo) {
|
|
261
|
+
errorMessage.value = '当前目录不是Git仓库'
|
|
262
|
+
return
|
|
263
|
+
}
|
|
264
|
+
loadLog(showAllCommits.value)
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// 监听store中的日志变化
|
|
268
|
+
watch(() => gitLogStore.log, (newLogs) => {
|
|
269
|
+
console.log('监听到gitLogStore.log变化,更新图表数据')
|
|
270
|
+
|
|
271
|
+
// 清空logsData
|
|
272
|
+
logsData.length = 0
|
|
273
|
+
|
|
274
|
+
// 重新填充数据
|
|
275
|
+
newLogs.forEach((item: LogItem) => logsData.push(item))
|
|
276
|
+
|
|
277
|
+
// 更新计数器
|
|
278
|
+
totalCommits.value = newLogs.length
|
|
279
|
+
|
|
280
|
+
// 尝试解决logs.value赋值问题
|
|
281
|
+
try {
|
|
282
|
+
// @ts-ignore - 忽略TypeScript错误
|
|
283
|
+
logs.value = [...logsData]
|
|
284
|
+
} catch (error) {
|
|
285
|
+
console.warn('无法更新logs.value:', error)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
console.log(`数据更新完成,准备渲染图表(${logsData.length}条记录)`)
|
|
289
|
+
|
|
290
|
+
if (showGraphView.value && logsData.length > 0) {
|
|
291
|
+
setTimeout(renderGraph, 0)
|
|
292
|
+
}
|
|
115
293
|
})
|
|
116
|
-
|
|
294
|
+
|
|
117
295
|
// 暴露方法给父组件
|
|
118
296
|
defineExpose({
|
|
119
297
|
refreshLog
|
|
120
298
|
})
|
|
299
|
+
|
|
300
|
+
// 增加/减少缩放比例
|
|
301
|
+
function zoomIn() {
|
|
302
|
+
if (graphScale.value < maxScale) {
|
|
303
|
+
graphScale.value = Math.min(maxScale, graphScale.value + scaleStep)
|
|
304
|
+
applyScale()
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function zoomOut() {
|
|
309
|
+
if (graphScale.value > minScale) {
|
|
310
|
+
graphScale.value = Math.max(minScale, graphScale.value - scaleStep)
|
|
311
|
+
applyScale()
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// 应用缩放比例
|
|
316
|
+
function applyScale() {
|
|
317
|
+
if (!graphContainer.value) return
|
|
318
|
+
|
|
319
|
+
const svgElement = graphContainer.value.querySelector('svg')
|
|
320
|
+
if (svgElement) {
|
|
321
|
+
svgElement.style.transform = `scale(${graphScale.value})`
|
|
322
|
+
svgElement.style.transformOrigin = 'top left'
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// 自适应图表大小
|
|
327
|
+
function fitGraphToContainer() {
|
|
328
|
+
if (!graphContainer.value) return
|
|
329
|
+
|
|
330
|
+
const svgElement = graphContainer.value.querySelector('svg')
|
|
331
|
+
if (!svgElement) return
|
|
332
|
+
|
|
333
|
+
// 获取SVG和容器的宽度
|
|
334
|
+
const svgWidth = svgElement.getBoundingClientRect().width / graphScale.value
|
|
335
|
+
const containerWidth = graphContainer.value.clientWidth
|
|
336
|
+
|
|
337
|
+
// 计算合适的缩放比例
|
|
338
|
+
if (svgWidth > containerWidth) {
|
|
339
|
+
// 如果SVG宽度大于容器,需要缩小
|
|
340
|
+
graphScale.value = Math.max(minScale, containerWidth / svgWidth)
|
|
341
|
+
} else {
|
|
342
|
+
// 否则恢复到默认比例
|
|
343
|
+
graphScale.value = 1
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
applyScale()
|
|
347
|
+
}
|
|
121
348
|
</script>
|
|
122
349
|
|
|
123
350
|
<template>
|
|
@@ -138,7 +365,7 @@ defineExpose({
|
|
|
138
365
|
@click="toggleAllCommits"
|
|
139
366
|
:loading="isLoading"
|
|
140
367
|
>
|
|
141
|
-
{{ showAllCommits ? '显示最近
|
|
368
|
+
{{ showAllCommits ? '显示最近30条' : '显示所有提交' }}
|
|
142
369
|
</el-button>
|
|
143
370
|
<el-button
|
|
144
371
|
:icon="RefreshRight"
|
|
@@ -146,23 +373,74 @@ defineExpose({
|
|
|
146
373
|
size="small"
|
|
147
374
|
@click="refreshLog()"
|
|
148
375
|
:loading="isLoading"
|
|
376
|
+
:class="{ 'refresh-button-animated': logRefreshed }"
|
|
149
377
|
/>
|
|
150
378
|
</div>
|
|
151
379
|
</div>
|
|
152
380
|
<div v-if="errorMessage">{{ errorMessage }}</div>
|
|
153
381
|
<div v-else>
|
|
382
|
+
<!-- 添加刷新提示 -->
|
|
383
|
+
<div v-if="logRefreshed" class="refresh-notification">
|
|
384
|
+
提交历史已刷新
|
|
385
|
+
</div>
|
|
386
|
+
|
|
154
387
|
<!-- 图表视图 -->
|
|
155
388
|
<div v-if="showGraphView" class="graph-view">
|
|
156
|
-
<div class="commit-count" v-if="
|
|
157
|
-
显示 {{
|
|
389
|
+
<div class="commit-count" v-if="logsData.length > 0">
|
|
390
|
+
显示 {{ logsData.length }} 条提交记录 {{ showAllCommits ? '(全部)' : '(最近30条)' }}
|
|
158
391
|
</div>
|
|
392
|
+
|
|
393
|
+
<!-- 添加缩放控制 -->
|
|
394
|
+
<div class="graph-controls">
|
|
395
|
+
<div class="zoom-controls">
|
|
396
|
+
<el-button
|
|
397
|
+
type="primary"
|
|
398
|
+
:icon="ZoomOut"
|
|
399
|
+
circle
|
|
400
|
+
size="small"
|
|
401
|
+
@click="zoomOut"
|
|
402
|
+
:disabled="graphScale <= minScale"
|
|
403
|
+
/>
|
|
404
|
+
|
|
405
|
+
<el-slider
|
|
406
|
+
v-model="graphScale"
|
|
407
|
+
:min="minScale"
|
|
408
|
+
:max="maxScale"
|
|
409
|
+
:step="scaleStep"
|
|
410
|
+
@change="applyScale"
|
|
411
|
+
class="zoom-slider"
|
|
412
|
+
/>
|
|
413
|
+
|
|
414
|
+
<el-button
|
|
415
|
+
type="primary"
|
|
416
|
+
:icon="ZoomIn"
|
|
417
|
+
circle
|
|
418
|
+
size="small"
|
|
419
|
+
@click="zoomIn"
|
|
420
|
+
:disabled="graphScale >= maxScale"
|
|
421
|
+
/>
|
|
422
|
+
|
|
423
|
+
<el-button
|
|
424
|
+
type="primary"
|
|
425
|
+
size="small"
|
|
426
|
+
@click="fitGraphToContainer"
|
|
427
|
+
>
|
|
428
|
+
自适应大小
|
|
429
|
+
</el-button>
|
|
430
|
+
</div>
|
|
431
|
+
|
|
432
|
+
<div class="scale-info">
|
|
433
|
+
缩放: {{ Math.round(graphScale * 100) }}%
|
|
434
|
+
</div>
|
|
435
|
+
</div>
|
|
436
|
+
|
|
159
437
|
<div ref="graphContainer" class="graph-container"></div>
|
|
160
438
|
</div>
|
|
161
439
|
|
|
162
440
|
<!-- 表格视图 -->
|
|
163
441
|
<div v-else>
|
|
164
442
|
<div class="commit-count" v-if="logs.length > 0">
|
|
165
|
-
显示 {{ logs.length }} 条提交记录 {{ showAllCommits ? '(全部)' : '(最近
|
|
443
|
+
显示 {{ logs.length }} 条提交记录 {{ showAllCommits ? '(全部)' : '(最近30条)' }}
|
|
166
444
|
</div>
|
|
167
445
|
<el-table :data="logs" style="width: 100%" stripe border v-loading="isLoading">
|
|
168
446
|
<el-table-column prop="hash" label="提交哈希" width="100" resizable />
|
|
@@ -232,37 +510,67 @@ defineExpose({
|
|
|
232
510
|
border-radius: 4px;
|
|
233
511
|
padding: 10px;
|
|
234
512
|
background-color: #fff;
|
|
235
|
-
|
|
513
|
+
position: relative;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
.graph-container svg {
|
|
517
|
+
transform-origin: top left;
|
|
518
|
+
transition: transform 0.2s ease;
|
|
236
519
|
}
|
|
237
520
|
|
|
238
521
|
.graph-view {
|
|
239
522
|
width: 100%;
|
|
240
523
|
}
|
|
241
|
-
</style>
|
|
242
524
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
// 移除 "origin/" 前缀
|
|
250
|
-
ref = ref.replace(/^origin\//, '')
|
|
251
|
-
|
|
252
|
-
// 移除 "tag: " 前缀,但保留标签名
|
|
253
|
-
ref = ref.replace(/^tag:\s*/, '')
|
|
254
|
-
|
|
255
|
-
return ref.trim()
|
|
525
|
+
.graph-controls {
|
|
526
|
+
display: flex;
|
|
527
|
+
justify-content: space-between;
|
|
528
|
+
align-items: center;
|
|
529
|
+
margin-bottom: 10px;
|
|
256
530
|
}
|
|
257
531
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
if (ref.includes('tag:')) return 'warning'
|
|
262
|
-
if (ref.includes('origin/')) return 'info'
|
|
263
|
-
return 'primary' // 修改空字符串为有效的type值
|
|
532
|
+
.zoom-controls {
|
|
533
|
+
display: flex;
|
|
534
|
+
gap: 8px;
|
|
264
535
|
}
|
|
265
|
-
|
|
536
|
+
|
|
537
|
+
.zoom-slider {
|
|
538
|
+
width: 200px;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
.scale-info {
|
|
542
|
+
font-size: 14px;
|
|
543
|
+
color: #606266;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
.refresh-button-animated {
|
|
547
|
+
animation: pulse 1s;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
.refresh-notification {
|
|
551
|
+
background-color: #f0f9eb;
|
|
552
|
+
color: #67c23a;
|
|
553
|
+
padding: 8px;
|
|
554
|
+
border-radius: 4px;
|
|
555
|
+
margin-bottom: 10px;
|
|
556
|
+
text-align: center;
|
|
557
|
+
font-size: 14px;
|
|
558
|
+
border-left: 4px solid #67c23a;
|
|
559
|
+
animation: fadeOut 2s forwards;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
@keyframes pulse {
|
|
563
|
+
0% { transform: scale(1); }
|
|
564
|
+
50% { transform: scale(1.2); }
|
|
565
|
+
100% { transform: scale(1); }
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
@keyframes fadeOut {
|
|
569
|
+
0% { opacity: 1; }
|
|
570
|
+
70% { opacity: 1; }
|
|
571
|
+
100% { opacity: 0; }
|
|
572
|
+
}
|
|
573
|
+
</style>
|
|
266
574
|
|
|
267
575
|
/* 添加表格列调整样式 */
|
|
268
576
|
.el-table .el-table__cell .cell {
|