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
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import { defineStore } from 'pinia'
|
|
2
|
-
import { ref } from 'vue'
|
|
2
|
+
import { ref, onMounted, onUnmounted } from 'vue'
|
|
3
3
|
import { ElMessage } from 'element-plus'
|
|
4
4
|
import { useGitStore } from './gitStore'
|
|
5
|
+
import { io, Socket } from 'socket.io-client'
|
|
6
|
+
|
|
7
|
+
// 定义Git操作间隔时间(毫秒)
|
|
8
|
+
const GIT_OPERATION_DELAY = 300
|
|
5
9
|
|
|
6
10
|
export const useGitLogStore = defineStore('gitLog', () => {
|
|
7
11
|
// 引用gitStore获取仓库状态
|
|
8
12
|
const gitStore = useGitStore()
|
|
9
13
|
|
|
14
|
+
// 定义socket连接
|
|
15
|
+
let socket: Socket | null = null
|
|
16
|
+
// 自动更新状态开关
|
|
17
|
+
const autoUpdateEnabled = ref(true)
|
|
18
|
+
|
|
10
19
|
// 状态
|
|
11
20
|
const log = ref<any[]>([])
|
|
12
21
|
const status = ref<{ staged: string[], unstaged: string[], untracked: string[] }>({
|
|
@@ -14,13 +23,229 @@ export const useGitLogStore = defineStore('gitLog', () => {
|
|
|
14
23
|
unstaged: [],
|
|
15
24
|
untracked: []
|
|
16
25
|
})
|
|
26
|
+
// 添加Git状态文本
|
|
27
|
+
const statusText = ref('')
|
|
28
|
+
// 添加fileList状态用于保存porcelain格式的状态
|
|
29
|
+
const fileList = ref<{path: string, type: string}[]>([])
|
|
17
30
|
const isLoadingLog = ref(false)
|
|
18
31
|
const isLoadingStatus = ref(false)
|
|
19
32
|
const isAddingFiles = ref(false)
|
|
33
|
+
const isCommiting = ref(false)
|
|
34
|
+
const isPushing = ref(false)
|
|
20
35
|
const isResetting = ref(false)
|
|
21
36
|
|
|
37
|
+
// Socket.io连接处理
|
|
38
|
+
function initSocketConnection() {
|
|
39
|
+
// 如果已经有socket连接,先断开
|
|
40
|
+
if (socket) {
|
|
41
|
+
socket.disconnect()
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 创建新连接
|
|
45
|
+
try {
|
|
46
|
+
// 修正Socket.IO连接URL,使用固定的后端服务器端口3000
|
|
47
|
+
const backendUrl = 'http://localhost:3000'
|
|
48
|
+
|
|
49
|
+
console.log('尝试连接Socket.IO服务器:', backendUrl)
|
|
50
|
+
|
|
51
|
+
socket = io(backendUrl, {
|
|
52
|
+
reconnectionDelayMax: 10000,
|
|
53
|
+
reconnection: true,
|
|
54
|
+
reconnectionAttempts: 10,
|
|
55
|
+
reconnectionDelay: 1000, // 初始重连延迟1秒
|
|
56
|
+
timeout: 20000, // 连接超时时间
|
|
57
|
+
autoConnect: true, // 自动连接
|
|
58
|
+
forceNew: true, // 强制创建新连接
|
|
59
|
+
transports: ['websocket', 'polling'] // 优先使用WebSocket
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
// 检查socket是否成功创建
|
|
63
|
+
if (!socket) {
|
|
64
|
+
console.error('Socket.IO初始化失败: socket为null')
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
console.log('Socket.IO初始化成功,socket ID:', socket.id || '未连接')
|
|
68
|
+
|
|
69
|
+
// 监听连接事件
|
|
70
|
+
socket.on('connect', () => {
|
|
71
|
+
console.log('成功连接到Socket.IO服务器')
|
|
72
|
+
|
|
73
|
+
// 如果自动更新开启,向服务器请求开始监控
|
|
74
|
+
if (autoUpdateEnabled.value && socket) {
|
|
75
|
+
socket.emit('start_monitoring')
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
// 监听断开连接事件
|
|
80
|
+
socket.on('disconnect', (reason) => {
|
|
81
|
+
console.log('与Socket.IO服务器断开连接:', reason)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
// 监听Git状态更新事件
|
|
85
|
+
socket.on('git_status_update', (data) => {
|
|
86
|
+
if (!autoUpdateEnabled.value) return
|
|
87
|
+
|
|
88
|
+
console.log('收到Git状态更新通知:', new Date().toLocaleTimeString())
|
|
89
|
+
|
|
90
|
+
// 更新状态文本
|
|
91
|
+
if (data.status) {
|
|
92
|
+
statusText.value = data.status
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 更新文件列表
|
|
96
|
+
if (data.porcelain !== undefined) {
|
|
97
|
+
parseStatusPorcelain(data.porcelain)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 根据文件列表判断是否需要更新日志
|
|
101
|
+
const hasChanges = fileList.value.length > 0
|
|
102
|
+
|
|
103
|
+
// 如果有变化,更新状态
|
|
104
|
+
if (hasChanges) {
|
|
105
|
+
// 自动刷新日志,但不要显示消息通知
|
|
106
|
+
fetchLog(false)
|
|
107
|
+
}
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
// 监听监控状态
|
|
111
|
+
socket.on('monitoring_status', (data) => {
|
|
112
|
+
console.log('文件监控状态:', data.active ? '已启动' : '已停止')
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
// 添加额外的连接问题诊断
|
|
116
|
+
socket.on('connect_error', (error) => {
|
|
117
|
+
console.error('Socket连接错误:', error.message)
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
socket.on('connect_timeout', () => {
|
|
121
|
+
console.error('Socket连接超时')
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
socket.on('reconnect', (attemptNumber) => {
|
|
125
|
+
console.log(`Socket重连成功,尝试次数: ${attemptNumber}`)
|
|
126
|
+
|
|
127
|
+
// 重连后检查自动更新状态
|
|
128
|
+
if (autoUpdateEnabled.value) {
|
|
129
|
+
console.log('重连后重新发送start_monitoring请求')
|
|
130
|
+
socket?.emit('start_monitoring')
|
|
131
|
+
}
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
socket.on('reconnect_attempt', (attemptNumber) => {
|
|
135
|
+
console.log(`Socket尝试重连,第 ${attemptNumber} 次尝试`)
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
socket.on('reconnect_error', (error) => {
|
|
139
|
+
console.error('Socket重连错误:', error.message)
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
socket.on('reconnect_failed', () => {
|
|
143
|
+
console.error('Socket重连失败,已达到最大重试次数')
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
// 手动尝试连接
|
|
147
|
+
if (socket && !socket.connected) {
|
|
148
|
+
console.log('Socket未连接,尝试手动连接...')
|
|
149
|
+
socket.connect()
|
|
150
|
+
}
|
|
151
|
+
} catch (error) {
|
|
152
|
+
console.error('Socket.IO连接初始化失败:', error)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// 切换自动更新状态
|
|
157
|
+
function toggleAutoUpdate() {
|
|
158
|
+
// autoUpdateEnabled.value = !autoUpdateEnabled.value
|
|
159
|
+
console.log('toggleAutoUpdate调用,当前值:', autoUpdateEnabled.value)
|
|
160
|
+
|
|
161
|
+
if (!socket) {
|
|
162
|
+
console.error('无法切换自动更新状态: socket连接不存在')
|
|
163
|
+
ElMessage.error('无法连接到服务器,自动更新可能不会生效')
|
|
164
|
+
|
|
165
|
+
// 尝试重新初始化socket连接
|
|
166
|
+
console.log('尝试重新建立socket连接...')
|
|
167
|
+
initSocketConnection()
|
|
168
|
+
|
|
169
|
+
// 即使socket可能不存在,也保存设置
|
|
170
|
+
localStorage.setItem('zen-gitsync-auto-update', autoUpdateEnabled.value.toString())
|
|
171
|
+
return
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
if (autoUpdateEnabled.value) {
|
|
176
|
+
console.log('发送start_monitoring命令...')
|
|
177
|
+
socket.emit('start_monitoring')
|
|
178
|
+
ElMessage.success('自动更新已启用')
|
|
179
|
+
} else {
|
|
180
|
+
console.log('发送stop_monitoring命令...')
|
|
181
|
+
socket.emit('stop_monitoring')
|
|
182
|
+
ElMessage.info('自动更新已禁用')
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// 保存设置到localStorage
|
|
186
|
+
localStorage.setItem('zen-gitsync-auto-update', autoUpdateEnabled.value.toString())
|
|
187
|
+
console.log('已保存自动更新设置到本地存储:', autoUpdateEnabled.value)
|
|
188
|
+
} catch (error) {
|
|
189
|
+
console.error('切换自动更新状态时出错:', error)
|
|
190
|
+
ElMessage.error(`切换自动更新失败: ${(error as Error).message}`)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// 解析 git status --porcelain 输出,提取文件及类型
|
|
195
|
+
function parseStatusPorcelain(statusText: string) {
|
|
196
|
+
if (statusText === undefined || statusText === '') {
|
|
197
|
+
// 如果状态为空字符串,清空文件列表
|
|
198
|
+
fileList.value = []
|
|
199
|
+
return
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const lines = statusText.split('\n')
|
|
203
|
+
const files: {path: string, type: string}[] = []
|
|
204
|
+
for (const line of lines) {
|
|
205
|
+
// 匹配常见的 git status --porcelain 格式
|
|
206
|
+
// M: 修改, A: 新增, D: 删除, ??: 未跟踪
|
|
207
|
+
const match = line.match(/^([ MADRCU\?]{2})\s+(.+)$/)
|
|
208
|
+
if (match) {
|
|
209
|
+
let type = ''
|
|
210
|
+
const code = match[1]
|
|
211
|
+
const indexStatus = code.charAt(0)
|
|
212
|
+
const workTreeStatus = code.charAt(1)
|
|
213
|
+
|
|
214
|
+
// 根据暂存区状态和工作区状态确定文件类型
|
|
215
|
+
if (indexStatus === 'A') {
|
|
216
|
+
// 已暂存的新文件
|
|
217
|
+
type = 'added'
|
|
218
|
+
} else if (indexStatus === 'M') {
|
|
219
|
+
// 已暂存的修改文件
|
|
220
|
+
type = 'added'
|
|
221
|
+
} else if (indexStatus === 'D') {
|
|
222
|
+
// 已暂存的删除文件
|
|
223
|
+
type = 'added'
|
|
224
|
+
} else if (indexStatus === 'R') {
|
|
225
|
+
// 已暂存的重命名文件
|
|
226
|
+
type = 'added'
|
|
227
|
+
} else if (indexStatus === ' ' && workTreeStatus === 'M') {
|
|
228
|
+
// 已修改未暂存的文件
|
|
229
|
+
type = 'modified'
|
|
230
|
+
} else if (indexStatus === ' ' && workTreeStatus === 'D') {
|
|
231
|
+
// 已删除未暂存的文件
|
|
232
|
+
type = 'deleted'
|
|
233
|
+
} else if (code === '??') {
|
|
234
|
+
// 未跟踪的文件
|
|
235
|
+
type = 'untracked'
|
|
236
|
+
} else {
|
|
237
|
+
// 其他情况
|
|
238
|
+
type = 'other'
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
files.push({ path: match[2], type })
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
fileList.value = files
|
|
245
|
+
}
|
|
246
|
+
|
|
22
247
|
// 获取提交日志
|
|
23
|
-
async function fetchLog() {
|
|
248
|
+
async function fetchLog(showMessage = true) {
|
|
24
249
|
// 检查是否是Git仓库
|
|
25
250
|
if (!gitStore.isGitRepo) {
|
|
26
251
|
console.log('当前目录不是Git仓库,跳过加载提交历史')
|
|
@@ -32,16 +257,25 @@ export const useGitLogStore = defineStore('gitLog', () => {
|
|
|
32
257
|
console.log('开始加载提交历史...')
|
|
33
258
|
const response = await fetch('/api/log')
|
|
34
259
|
const data = await response.json()
|
|
35
|
-
if (data
|
|
36
|
-
log.value = data
|
|
260
|
+
if (data && Array.isArray(data)) {
|
|
261
|
+
log.value = data
|
|
37
262
|
}
|
|
38
263
|
console.log(`提交历史加载完成,共 ${log.value.length} 条记录`)
|
|
264
|
+
|
|
265
|
+
if (showMessage) {
|
|
266
|
+
ElMessage({
|
|
267
|
+
message: '提交历史已更新',
|
|
268
|
+
type: 'success'
|
|
269
|
+
})
|
|
270
|
+
}
|
|
39
271
|
} catch (error) {
|
|
40
272
|
console.error('获取提交历史失败:', error)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
273
|
+
if (showMessage) {
|
|
274
|
+
ElMessage({
|
|
275
|
+
message: `获取提交历史失败: ${(error as Error).message}`,
|
|
276
|
+
type: 'error'
|
|
277
|
+
})
|
|
278
|
+
}
|
|
45
279
|
} finally {
|
|
46
280
|
isLoadingLog.value = false
|
|
47
281
|
}
|
|
@@ -60,12 +294,17 @@ export const useGitLogStore = defineStore('gitLog', () => {
|
|
|
60
294
|
const response = await fetch('/api/status')
|
|
61
295
|
const data = await response.json()
|
|
62
296
|
if (data.status) {
|
|
297
|
+
// 更新状态文本
|
|
298
|
+
statusText.value = data.status
|
|
63
299
|
status.value = {
|
|
64
300
|
staged: data.status.staged || [],
|
|
65
301
|
unstaged: data.status.unstaged || [],
|
|
66
302
|
untracked: data.status.untracked || []
|
|
67
303
|
}
|
|
68
304
|
}
|
|
305
|
+
|
|
306
|
+
// 同时获取porcelain格式的状态
|
|
307
|
+
await fetchStatusPorcelain()
|
|
69
308
|
} catch (error) {
|
|
70
309
|
console.error('获取Git状态失败:', error)
|
|
71
310
|
ElMessage({
|
|
@@ -77,6 +316,35 @@ export const useGitLogStore = defineStore('gitLog', () => {
|
|
|
77
316
|
}
|
|
78
317
|
}
|
|
79
318
|
|
|
319
|
+
// 获取Git状态 (porcelain格式)
|
|
320
|
+
async function fetchStatusPorcelain() {
|
|
321
|
+
console.log('开始获取Git状态(porcelain格式)...')
|
|
322
|
+
// 检查是否是Git仓库
|
|
323
|
+
if (!gitStore.isGitRepo) {
|
|
324
|
+
console.log('当前目录不是Git仓库,跳过加载Git状态')
|
|
325
|
+
return
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
try {
|
|
329
|
+
const response = await fetch('/api/status_porcelain')
|
|
330
|
+
const data = await response.json()
|
|
331
|
+
if (data.status !== undefined) {
|
|
332
|
+
parseStatusPorcelain(data.status)
|
|
333
|
+
} else {
|
|
334
|
+
// 如果没有收到有效的 status 字段,清空文件列表
|
|
335
|
+
fileList.value = []
|
|
336
|
+
}
|
|
337
|
+
} catch (error) {
|
|
338
|
+
console.error('获取Git状态(porcelain)失败:', error)
|
|
339
|
+
ElMessage({
|
|
340
|
+
message: `获取Git状态(porcelain)失败: ${(error as Error).message}`,
|
|
341
|
+
type: 'error'
|
|
342
|
+
})
|
|
343
|
+
// 清空文件列表
|
|
344
|
+
fileList.value = []
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
80
348
|
// 添加文件到暂存区 (git add .)
|
|
81
349
|
async function addToStage() {
|
|
82
350
|
// 检查是否是Git仓库
|
|
@@ -120,8 +388,8 @@ export const useGitLogStore = defineStore('gitLog', () => {
|
|
|
120
388
|
}
|
|
121
389
|
}
|
|
122
390
|
|
|
123
|
-
//
|
|
124
|
-
async function
|
|
391
|
+
// 添加单个文件到暂存区
|
|
392
|
+
async function addFileToStage(filePath: string) {
|
|
125
393
|
// 检查是否是Git仓库
|
|
126
394
|
if (!gitStore.isGitRepo) {
|
|
127
395
|
ElMessage.warning('当前目录不是Git仓库')
|
|
@@ -129,48 +397,46 @@ export const useGitLogStore = defineStore('gitLog', () => {
|
|
|
129
397
|
}
|
|
130
398
|
|
|
131
399
|
try {
|
|
132
|
-
|
|
400
|
+
isAddingFiles.value = true
|
|
401
|
+
const response = await fetch('/api/add-file', {
|
|
133
402
|
method: 'POST',
|
|
134
403
|
headers: {
|
|
135
404
|
'Content-Type': 'application/json'
|
|
136
405
|
},
|
|
137
|
-
body: JSON.stringify({
|
|
138
|
-
message,
|
|
139
|
-
hasNewlines: message.includes('\n'),
|
|
140
|
-
noVerify
|
|
141
|
-
})
|
|
406
|
+
body: JSON.stringify({ filePath })
|
|
142
407
|
})
|
|
143
408
|
|
|
144
409
|
const result = await response.json()
|
|
145
410
|
if (result.success) {
|
|
146
411
|
ElMessage({
|
|
147
|
-
message: '
|
|
412
|
+
message: '文件已暂存',
|
|
148
413
|
type: 'success'
|
|
149
414
|
})
|
|
150
415
|
|
|
151
|
-
//
|
|
416
|
+
// 刷新状态
|
|
152
417
|
fetchStatus()
|
|
153
|
-
fetchLog()
|
|
154
418
|
|
|
155
419
|
return true
|
|
156
420
|
} else {
|
|
157
421
|
ElMessage({
|
|
158
|
-
message:
|
|
422
|
+
message: `暂存文件失败: ${result.error}`,
|
|
159
423
|
type: 'error'
|
|
160
424
|
})
|
|
161
425
|
return false
|
|
162
426
|
}
|
|
163
427
|
} catch (error) {
|
|
164
428
|
ElMessage({
|
|
165
|
-
message:
|
|
429
|
+
message: `暂存文件失败: ${(error as Error).message}`,
|
|
166
430
|
type: 'error'
|
|
167
431
|
})
|
|
168
432
|
return false
|
|
433
|
+
} finally {
|
|
434
|
+
isAddingFiles.value = false
|
|
169
435
|
}
|
|
170
436
|
}
|
|
171
437
|
|
|
172
|
-
//
|
|
173
|
-
async function
|
|
438
|
+
// 取消暂存单个文件
|
|
439
|
+
async function unstageFile(filePath: string) {
|
|
174
440
|
// 检查是否是Git仓库
|
|
175
441
|
if (!gitStore.isGitRepo) {
|
|
176
442
|
ElMessage.warning('当前目录不是Git仓库')
|
|
@@ -178,90 +444,51 @@ export const useGitLogStore = defineStore('gitLog', () => {
|
|
|
178
444
|
}
|
|
179
445
|
|
|
180
446
|
try {
|
|
181
|
-
|
|
182
|
-
|
|
447
|
+
isResetting.value = true
|
|
448
|
+
const response = await fetch('/api/unstage-file', {
|
|
449
|
+
method: 'POST',
|
|
450
|
+
headers: {
|
|
451
|
+
'Content-Type': 'application/json'
|
|
452
|
+
},
|
|
453
|
+
body: JSON.stringify({ filePath })
|
|
183
454
|
})
|
|
184
455
|
|
|
185
456
|
const result = await response.json()
|
|
186
457
|
if (result.success) {
|
|
187
458
|
ElMessage({
|
|
188
|
-
message: '
|
|
459
|
+
message: '已取消暂存文件',
|
|
189
460
|
type: 'success'
|
|
190
461
|
})
|
|
191
462
|
|
|
192
|
-
//
|
|
193
|
-
|
|
463
|
+
// 刷新状态
|
|
464
|
+
fetchStatus()
|
|
194
465
|
|
|
195
466
|
return true
|
|
196
467
|
} else {
|
|
197
468
|
ElMessage({
|
|
198
|
-
message:
|
|
469
|
+
message: `取消暂存失败: ${result.error}`,
|
|
199
470
|
type: 'error'
|
|
200
471
|
})
|
|
201
472
|
return false
|
|
202
473
|
}
|
|
203
474
|
} catch (error) {
|
|
204
475
|
ElMessage({
|
|
205
|
-
message:
|
|
206
|
-
type: 'error'
|
|
207
|
-
})
|
|
208
|
-
return false
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// 暂存并提交
|
|
213
|
-
async function addAndCommit(message: string, noVerify = false) {
|
|
214
|
-
try {
|
|
215
|
-
// 先添加到暂存区
|
|
216
|
-
const addResult = await addToStage()
|
|
217
|
-
if (!addResult) {
|
|
218
|
-
return false
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// 再提交
|
|
222
|
-
return await commitChanges(message, noVerify)
|
|
223
|
-
} catch (error) {
|
|
224
|
-
ElMessage({
|
|
225
|
-
message: `暂存并提交失败: ${(error as Error).message}`,
|
|
476
|
+
message: `取消暂存失败: ${(error as Error).message}`,
|
|
226
477
|
type: 'error'
|
|
227
478
|
})
|
|
228
479
|
return false
|
|
480
|
+
} finally {
|
|
481
|
+
isResetting.value = false
|
|
229
482
|
}
|
|
230
483
|
}
|
|
231
484
|
|
|
232
|
-
//
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
// 先添加并提交
|
|
236
|
-
const commitResult = await addAndCommit(message, noVerify)
|
|
237
|
-
if (!commitResult) {
|
|
238
|
-
return false
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// 再推送
|
|
242
|
-
const pushResult = await pushToRemote()
|
|
243
|
-
|
|
244
|
-
// 推送成功后,确保刷新日志
|
|
245
|
-
if (pushResult) {
|
|
246
|
-
// 添加延迟以确保服务器处理完成
|
|
247
|
-
setTimeout(() => {
|
|
248
|
-
console.log('刷新提交历史...')
|
|
249
|
-
fetchLog()
|
|
250
|
-
}, 300)
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
return pushResult
|
|
254
|
-
} catch (error) {
|
|
255
|
-
ElMessage({
|
|
256
|
-
message: `暂存、提交并推送失败: ${(error as Error).message}`,
|
|
257
|
-
type: 'error'
|
|
258
|
-
})
|
|
259
|
-
return false
|
|
260
|
-
}
|
|
485
|
+
// 添加延时函数
|
|
486
|
+
function delay(ms: number) {
|
|
487
|
+
return new Promise(resolve => setTimeout(resolve, ms))
|
|
261
488
|
}
|
|
262
489
|
|
|
263
|
-
//
|
|
264
|
-
async function
|
|
490
|
+
// 提交更改
|
|
491
|
+
async function commitChanges(message: string, noVerify = false) {
|
|
265
492
|
// 检查是否是Git仓库
|
|
266
493
|
if (!gitStore.isGitRepo) {
|
|
267
494
|
ElMessage.warning('当前目录不是Git仓库')
|
|
@@ -269,42 +496,51 @@ export const useGitLogStore = defineStore('gitLog', () => {
|
|
|
269
496
|
}
|
|
270
497
|
|
|
271
498
|
try {
|
|
272
|
-
|
|
273
|
-
const response = await fetch('/api/
|
|
274
|
-
method: 'POST'
|
|
499
|
+
isCommiting.value = true
|
|
500
|
+
const response = await fetch('/api/commit', {
|
|
501
|
+
method: 'POST',
|
|
502
|
+
headers: {
|
|
503
|
+
'Content-Type': 'application/json'
|
|
504
|
+
},
|
|
505
|
+
body: JSON.stringify({
|
|
506
|
+
message,
|
|
507
|
+
hasNewlines: message.includes('\n'),
|
|
508
|
+
noVerify
|
|
509
|
+
})
|
|
275
510
|
})
|
|
276
511
|
|
|
277
512
|
const result = await response.json()
|
|
278
513
|
if (result.success) {
|
|
279
514
|
ElMessage({
|
|
280
|
-
message: '
|
|
515
|
+
message: '提交成功',
|
|
281
516
|
type: 'success'
|
|
282
517
|
})
|
|
283
518
|
|
|
284
|
-
//
|
|
519
|
+
// 刷新状态和日志
|
|
285
520
|
fetchStatus()
|
|
521
|
+
fetchLog()
|
|
286
522
|
|
|
287
523
|
return true
|
|
288
524
|
} else {
|
|
289
525
|
ElMessage({
|
|
290
|
-
message:
|
|
526
|
+
message: `提交失败: ${result.error}`,
|
|
291
527
|
type: 'error'
|
|
292
528
|
})
|
|
293
529
|
return false
|
|
294
530
|
}
|
|
295
531
|
} catch (error) {
|
|
296
532
|
ElMessage({
|
|
297
|
-
message:
|
|
533
|
+
message: `提交失败: ${(error as Error).message}`,
|
|
298
534
|
type: 'error'
|
|
299
535
|
})
|
|
300
536
|
return false
|
|
301
537
|
} finally {
|
|
302
|
-
|
|
538
|
+
isCommiting.value = false
|
|
303
539
|
}
|
|
304
540
|
}
|
|
305
541
|
|
|
306
|
-
//
|
|
307
|
-
async function
|
|
542
|
+
// 推送到远程
|
|
543
|
+
async function pushToRemote() {
|
|
308
544
|
// 检查是否是Git仓库
|
|
309
545
|
if (!gitStore.isGitRepo) {
|
|
310
546
|
ElMessage.warning('当前目录不是Git仓库')
|
|
@@ -312,47 +548,96 @@ export const useGitLogStore = defineStore('gitLog', () => {
|
|
|
312
548
|
}
|
|
313
549
|
|
|
314
550
|
try {
|
|
315
|
-
|
|
316
|
-
const response = await fetch('/api/
|
|
317
|
-
method: 'POST'
|
|
318
|
-
headers: {
|
|
319
|
-
'Content-Type': 'application/json'
|
|
320
|
-
},
|
|
321
|
-
body: JSON.stringify({ branch })
|
|
551
|
+
isPushing.value = true
|
|
552
|
+
const response = await fetch('/api/push', {
|
|
553
|
+
method: 'POST'
|
|
322
554
|
})
|
|
323
555
|
|
|
324
556
|
const result = await response.json()
|
|
325
557
|
if (result.success) {
|
|
326
558
|
ElMessage({
|
|
327
|
-
message:
|
|
559
|
+
message: '推送成功',
|
|
328
560
|
type: 'success'
|
|
329
561
|
})
|
|
330
|
-
|
|
331
|
-
// 刷新状态和日志
|
|
562
|
+
// 刷新状态
|
|
332
563
|
fetchStatus()
|
|
564
|
+
|
|
565
|
+
// 刷新日志
|
|
333
566
|
fetchLog()
|
|
334
567
|
|
|
335
568
|
return true
|
|
336
569
|
} else {
|
|
337
570
|
ElMessage({
|
|
338
|
-
message:
|
|
571
|
+
message: `推送失败: ${result.error}`,
|
|
339
572
|
type: 'error'
|
|
340
573
|
})
|
|
341
574
|
return false
|
|
342
575
|
}
|
|
343
576
|
} catch (error) {
|
|
344
577
|
ElMessage({
|
|
345
|
-
message:
|
|
578
|
+
message: `推送失败: ${(error as Error).message}`,
|
|
346
579
|
type: 'error'
|
|
347
580
|
})
|
|
348
581
|
return false
|
|
349
582
|
} finally {
|
|
350
|
-
|
|
583
|
+
isPushing.value = false
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// 暂存并提交
|
|
588
|
+
async function addAndCommit(message: string, noVerify = false) {
|
|
589
|
+
const addResult = await addToStage()
|
|
590
|
+
if (!addResult) return false
|
|
591
|
+
|
|
592
|
+
// 使用新的延时常量
|
|
593
|
+
await delay(GIT_OPERATION_DELAY)
|
|
594
|
+
|
|
595
|
+
return await commitChanges(message, noVerify)
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// 暂存、提交并推送
|
|
599
|
+
async function addCommitAndPush(message: string, noVerify = false) {
|
|
600
|
+
try {
|
|
601
|
+
const addResult = await addToStage()
|
|
602
|
+
if (!addResult) return false
|
|
603
|
+
|
|
604
|
+
// 使用新的延时常量
|
|
605
|
+
await delay(GIT_OPERATION_DELAY)
|
|
606
|
+
|
|
607
|
+
const commitResult = await commitChanges(message, noVerify)
|
|
608
|
+
if (!commitResult) return false
|
|
609
|
+
|
|
610
|
+
// 使用新的延时常量
|
|
611
|
+
await delay(GIT_OPERATION_DELAY)
|
|
612
|
+
|
|
613
|
+
return await pushToRemote()
|
|
614
|
+
} catch (error) {
|
|
615
|
+
// 如果发生错误,尝试删除 index.lock 文件
|
|
616
|
+
try {
|
|
617
|
+
const response = await fetch('/api/remove-lock', {
|
|
618
|
+
method: 'POST'
|
|
619
|
+
})
|
|
620
|
+
const result = await response.json()
|
|
621
|
+
if (result.success) {
|
|
622
|
+
ElMessage({
|
|
623
|
+
message: '已清理锁定文件,请重试操作',
|
|
624
|
+
type: 'warning'
|
|
625
|
+
})
|
|
626
|
+
}
|
|
627
|
+
} catch (e) {
|
|
628
|
+
console.error('清理锁定文件失败:', e)
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
ElMessage({
|
|
632
|
+
message: `操作失败: ${(error as Error).message}`,
|
|
633
|
+
type: 'error'
|
|
634
|
+
})
|
|
635
|
+
return false
|
|
351
636
|
}
|
|
352
637
|
}
|
|
353
638
|
|
|
354
|
-
//
|
|
355
|
-
async function
|
|
639
|
+
// 重置暂存区 (git reset HEAD)
|
|
640
|
+
async function resetHead() {
|
|
356
641
|
// 检查是否是Git仓库
|
|
357
642
|
if (!gitStore.isGitRepo) {
|
|
358
643
|
ElMessage.warning('当前目录不是Git仓库')
|
|
@@ -360,18 +645,15 @@ export const useGitLogStore = defineStore('gitLog', () => {
|
|
|
360
645
|
}
|
|
361
646
|
|
|
362
647
|
try {
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
'Content-Type': 'application/json'
|
|
367
|
-
},
|
|
368
|
-
body: JSON.stringify({ files })
|
|
648
|
+
isResetting.value = true
|
|
649
|
+
const response = await fetch('/api/reset-head', {
|
|
650
|
+
method: 'POST'
|
|
369
651
|
})
|
|
370
652
|
|
|
371
653
|
const result = await response.json()
|
|
372
654
|
if (result.success) {
|
|
373
655
|
ElMessage({
|
|
374
|
-
message: '
|
|
656
|
+
message: '已重置暂存区',
|
|
375
657
|
type: 'success'
|
|
376
658
|
})
|
|
377
659
|
|
|
@@ -381,22 +663,24 @@ export const useGitLogStore = defineStore('gitLog', () => {
|
|
|
381
663
|
return true
|
|
382
664
|
} else {
|
|
383
665
|
ElMessage({
|
|
384
|
-
message:
|
|
666
|
+
message: `重置暂存区失败: ${result.error}`,
|
|
385
667
|
type: 'error'
|
|
386
668
|
})
|
|
387
669
|
return false
|
|
388
670
|
}
|
|
389
671
|
} catch (error) {
|
|
390
672
|
ElMessage({
|
|
391
|
-
message:
|
|
673
|
+
message: `重置暂存区失败: ${(error as Error).message}`,
|
|
392
674
|
type: 'error'
|
|
393
675
|
})
|
|
394
676
|
return false
|
|
677
|
+
} finally {
|
|
678
|
+
isResetting.value = false
|
|
395
679
|
}
|
|
396
680
|
}
|
|
397
681
|
|
|
398
|
-
//
|
|
399
|
-
async function
|
|
682
|
+
// 重置当前分支到远程状态
|
|
683
|
+
async function resetToRemote(branch: string) {
|
|
400
684
|
// 检查是否是Git仓库
|
|
401
685
|
if (!gitStore.isGitRepo) {
|
|
402
686
|
ElMessage.warning('当前目录不是Git仓库')
|
|
@@ -404,61 +688,92 @@ export const useGitLogStore = defineStore('gitLog', () => {
|
|
|
404
688
|
}
|
|
405
689
|
|
|
406
690
|
try {
|
|
407
|
-
|
|
691
|
+
isResetting.value = true
|
|
692
|
+
const response = await fetch('/api/reset-to-remote', {
|
|
408
693
|
method: 'POST',
|
|
409
694
|
headers: {
|
|
410
695
|
'Content-Type': 'application/json'
|
|
411
696
|
},
|
|
412
|
-
body: JSON.stringify({
|
|
697
|
+
body: JSON.stringify({ branch })
|
|
413
698
|
})
|
|
414
699
|
|
|
415
700
|
const result = await response.json()
|
|
416
701
|
if (result.success) {
|
|
417
702
|
ElMessage({
|
|
418
|
-
message:
|
|
703
|
+
message: `已重置分支 ${branch} 到远程状态`,
|
|
419
704
|
type: 'success'
|
|
420
705
|
})
|
|
421
706
|
|
|
422
|
-
//
|
|
707
|
+
// 刷新状态和日志
|
|
423
708
|
fetchStatus()
|
|
709
|
+
fetchLog()
|
|
424
710
|
|
|
425
711
|
return true
|
|
426
712
|
} else {
|
|
427
713
|
ElMessage({
|
|
428
|
-
message:
|
|
714
|
+
message: `重置分支失败: ${result.error}`,
|
|
429
715
|
type: 'error'
|
|
430
716
|
})
|
|
431
717
|
return false
|
|
432
718
|
}
|
|
433
719
|
} catch (error) {
|
|
434
720
|
ElMessage({
|
|
435
|
-
message:
|
|
721
|
+
message: `重置分支失败: ${(error as Error).message}`,
|
|
436
722
|
type: 'error'
|
|
437
723
|
})
|
|
438
724
|
return false
|
|
725
|
+
} finally {
|
|
726
|
+
isResetting.value = false
|
|
439
727
|
}
|
|
440
728
|
}
|
|
441
729
|
|
|
730
|
+
// 在组件挂载时初始化socket连接
|
|
731
|
+
onMounted(() => {
|
|
732
|
+
// 从localStorage加载自动更新设置
|
|
733
|
+
const savedAutoUpdate = localStorage.getItem('zen-gitsync-auto-update')
|
|
734
|
+
if (savedAutoUpdate !== null) {
|
|
735
|
+
autoUpdateEnabled.value = savedAutoUpdate === 'true'
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
initSocketConnection()
|
|
739
|
+
})
|
|
740
|
+
|
|
741
|
+
// 在组件卸载时断开socket连接
|
|
742
|
+
onUnmounted(() => {
|
|
743
|
+
if (socket) {
|
|
744
|
+
socket.disconnect()
|
|
745
|
+
socket = null
|
|
746
|
+
}
|
|
747
|
+
})
|
|
748
|
+
|
|
442
749
|
return {
|
|
443
750
|
// 状态
|
|
444
751
|
log,
|
|
445
752
|
status,
|
|
753
|
+
statusText,
|
|
754
|
+
fileList,
|
|
446
755
|
isLoadingLog,
|
|
447
756
|
isLoadingStatus,
|
|
448
757
|
isAddingFiles,
|
|
449
758
|
isResetting,
|
|
759
|
+
isCommiting,
|
|
760
|
+
isPushing,
|
|
761
|
+
autoUpdateEnabled,
|
|
450
762
|
|
|
451
763
|
// 方法
|
|
452
764
|
fetchLog,
|
|
453
765
|
fetchStatus,
|
|
766
|
+
fetchStatusPorcelain,
|
|
767
|
+
parseStatusPorcelain,
|
|
454
768
|
addToStage,
|
|
769
|
+
addFileToStage,
|
|
770
|
+
unstageFile,
|
|
455
771
|
commitChanges,
|
|
456
772
|
pushToRemote,
|
|
457
773
|
addAndCommit,
|
|
458
774
|
addCommitAndPush,
|
|
459
775
|
resetHead,
|
|
460
776
|
resetToRemote,
|
|
461
|
-
|
|
462
|
-
unstageFiles
|
|
777
|
+
toggleAutoUpdate
|
|
463
778
|
}
|
|
464
779
|
})
|