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,17 +1,15 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { ref, onMounted,
|
|
3
|
-
import { ElMessage } from "element-plus";
|
|
4
|
-
import { Setting } from "@element-plus/icons-vue";
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
import { ref, onMounted, computed, watch } from "vue";
|
|
3
|
+
import { ElMessage, ElMessageBox } from "element-plus";
|
|
4
|
+
import { Setting, Edit } from "@element-plus/icons-vue";
|
|
5
|
+
import { useGitLogStore } from "../stores/gitLogStore";
|
|
6
|
+
import { useGitStore } from "../stores/gitStore";
|
|
7
|
+
|
|
8
|
+
const gitLogStore = useGitLogStore();
|
|
9
|
+
const gitStore = useGitStore();
|
|
7
10
|
const commitMessage = ref("");
|
|
8
|
-
const commitBtnText = ref("提交");
|
|
9
|
-
const pushBtnText = ref("推送到远程");
|
|
10
|
-
const isCommitting = ref(false);
|
|
11
11
|
const isPushing = ref(false);
|
|
12
12
|
// 添加提交并推送的状态变量
|
|
13
|
-
const isCommitAndPushing = ref(false);
|
|
14
|
-
const commitAndPushBtnText = ref("提交并推送");
|
|
15
13
|
const placeholder = ref("输入提交信息...");
|
|
16
14
|
// 添加默认提交信息变量
|
|
17
15
|
const defaultCommitMessage = ref("");
|
|
@@ -27,11 +25,19 @@ const descriptionTemplates = ref<string[]>([]);
|
|
|
27
25
|
// 添加对话框可见性变量
|
|
28
26
|
const descriptionDialogVisible = ref(false);
|
|
29
27
|
const newTemplateName = ref("");
|
|
28
|
+
// 添加模板编辑相关变量
|
|
29
|
+
const isEditingDescription = ref(false);
|
|
30
|
+
const originalDescriptionTemplate = ref("");
|
|
31
|
+
const editingDescriptionIndex = ref(-1);
|
|
30
32
|
|
|
31
33
|
// 作用域模板相关变量
|
|
32
34
|
const scopeTemplates = ref<string[]>([]);
|
|
33
35
|
const scopeDialogVisible = ref(false);
|
|
34
36
|
const newScopeTemplate = ref("");
|
|
37
|
+
// 添加作用域模板编辑相关变量
|
|
38
|
+
const isEditingScope = ref(false);
|
|
39
|
+
const originalScopeTemplate = ref("");
|
|
40
|
+
const editingScopeIndex = ref(-1);
|
|
35
41
|
|
|
36
42
|
// 跳过钩子
|
|
37
43
|
const skipHooks = ref(false);
|
|
@@ -82,6 +88,19 @@ const finalCommitMessage = computed(() => {
|
|
|
82
88
|
return message;
|
|
83
89
|
});
|
|
84
90
|
|
|
91
|
+
// 计算Git命令预览
|
|
92
|
+
const gitCommandPreview = computed(() => {
|
|
93
|
+
// 基本命令
|
|
94
|
+
let command = `git commit -m "${finalCommitMessage.value}"`
|
|
95
|
+
|
|
96
|
+
// 如果跳过钩子开关打开,添加 --no-verify 参数
|
|
97
|
+
if (skipHooks.value) {
|
|
98
|
+
command += ' --no-verify'
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return command
|
|
102
|
+
});
|
|
103
|
+
|
|
85
104
|
// 加载配置
|
|
86
105
|
async function loadConfig() {
|
|
87
106
|
try {
|
|
@@ -119,51 +138,126 @@ async function saveDescriptionTemplate() {
|
|
|
119
138
|
}
|
|
120
139
|
|
|
121
140
|
try {
|
|
122
|
-
//
|
|
123
|
-
if (
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
141
|
+
// 判断是编辑还是新建
|
|
142
|
+
if (isEditingDescription.value) {
|
|
143
|
+
// 编辑现有模板
|
|
144
|
+
await updateDescriptionTemplate();
|
|
145
|
+
} else {
|
|
146
|
+
// 新建模板
|
|
147
|
+
// 检查是否已存在相同模板
|
|
148
|
+
if (descriptionTemplates.value.includes(newTemplateName.value)) {
|
|
149
|
+
ElMessage({
|
|
150
|
+
message: "该模板已存在",
|
|
151
|
+
type: "warning",
|
|
152
|
+
});
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
130
155
|
|
|
131
|
-
|
|
132
|
-
|
|
156
|
+
// 添加到本地数组
|
|
157
|
+
descriptionTemplates.value.push(newTemplateName.value);
|
|
158
|
+
|
|
159
|
+
// 保存到服务器
|
|
160
|
+
const response = await fetch("/api/config/save-template", {
|
|
161
|
+
method: "POST",
|
|
162
|
+
headers: {
|
|
163
|
+
"Content-Type": "application/json",
|
|
164
|
+
},
|
|
165
|
+
body: JSON.stringify({
|
|
166
|
+
template: newTemplateName.value,
|
|
167
|
+
type: "description",
|
|
168
|
+
}),
|
|
169
|
+
});
|
|
133
170
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
171
|
+
const result = await response.json();
|
|
172
|
+
if (result.success) {
|
|
173
|
+
ElMessage({
|
|
174
|
+
message: "模板保存成功!",
|
|
175
|
+
type: "success",
|
|
176
|
+
});
|
|
177
|
+
newTemplateName.value = "";
|
|
178
|
+
} else {
|
|
179
|
+
ElMessage({
|
|
180
|
+
message: "模板保存失败: " + result.error,
|
|
181
|
+
type: "error",
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
} catch (error) {
|
|
186
|
+
ElMessage({
|
|
187
|
+
message: "模板保存失败: " + (error as Error).message,
|
|
188
|
+
type: "error",
|
|
144
189
|
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
145
192
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
193
|
+
// 编辑描述模板
|
|
194
|
+
async function updateDescriptionTemplate() {
|
|
195
|
+
try {
|
|
196
|
+
// 先从本地数组中更新
|
|
197
|
+
if (editingDescriptionIndex.value >= 0) {
|
|
198
|
+
// 保存原模板和新模板
|
|
199
|
+
const oldTemplate = originalDescriptionTemplate.value;
|
|
200
|
+
const newTemplate = newTemplateName.value;
|
|
201
|
+
|
|
202
|
+
// 更新本地数组
|
|
203
|
+
descriptionTemplates.value[editingDescriptionIndex.value] = newTemplate;
|
|
204
|
+
|
|
205
|
+
// 调用API更新服务器
|
|
206
|
+
const response = await fetch("/api/config/update-template", {
|
|
207
|
+
method: "POST",
|
|
208
|
+
headers: {
|
|
209
|
+
"Content-Type": "application/json",
|
|
210
|
+
},
|
|
211
|
+
body: JSON.stringify({
|
|
212
|
+
oldTemplate,
|
|
213
|
+
newTemplate,
|
|
214
|
+
type: "description",
|
|
215
|
+
}),
|
|
157
216
|
});
|
|
217
|
+
|
|
218
|
+
const result = await response.json();
|
|
219
|
+
if (result.success) {
|
|
220
|
+
ElMessage({
|
|
221
|
+
message: "模板更新成功!",
|
|
222
|
+
type: "success",
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// 重置编辑状态
|
|
226
|
+
isEditingDescription.value = false;
|
|
227
|
+
originalDescriptionTemplate.value = "";
|
|
228
|
+
editingDescriptionIndex.value = -1;
|
|
229
|
+
newTemplateName.value = "";
|
|
230
|
+
} else {
|
|
231
|
+
ElMessage({
|
|
232
|
+
message: "模板更新失败: " + result.error,
|
|
233
|
+
type: "error",
|
|
234
|
+
});
|
|
235
|
+
}
|
|
158
236
|
}
|
|
159
237
|
} catch (error) {
|
|
160
238
|
ElMessage({
|
|
161
|
-
message: "
|
|
239
|
+
message: "模板更新失败: " + (error as Error).message,
|
|
162
240
|
type: "error",
|
|
163
241
|
});
|
|
164
242
|
}
|
|
165
243
|
}
|
|
166
244
|
|
|
245
|
+
// 开始编辑描述模板
|
|
246
|
+
function startEditDescriptionTemplate(template: string, index: number) {
|
|
247
|
+
isEditingDescription.value = true;
|
|
248
|
+
originalDescriptionTemplate.value = template;
|
|
249
|
+
editingDescriptionIndex.value = index;
|
|
250
|
+
newTemplateName.value = template;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// 取消编辑描述模板
|
|
254
|
+
function cancelEditDescriptionTemplate() {
|
|
255
|
+
isEditingDescription.value = false;
|
|
256
|
+
originalDescriptionTemplate.value = "";
|
|
257
|
+
editingDescriptionIndex.value = -1;
|
|
258
|
+
newTemplateName.value = "";
|
|
259
|
+
}
|
|
260
|
+
|
|
167
261
|
// 保存作用域模板
|
|
168
262
|
async function saveScopeTemplate() {
|
|
169
263
|
if (!newScopeTemplate.value.trim()) {
|
|
@@ -175,51 +269,126 @@ async function saveScopeTemplate() {
|
|
|
175
269
|
}
|
|
176
270
|
|
|
177
271
|
try {
|
|
178
|
-
//
|
|
179
|
-
if (
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
272
|
+
// 判断是编辑还是新建
|
|
273
|
+
if (isEditingScope.value) {
|
|
274
|
+
// 编辑现有模板
|
|
275
|
+
await updateScopeTemplate();
|
|
276
|
+
} else {
|
|
277
|
+
// 新建模板
|
|
278
|
+
// 检查是否已存在相同模板
|
|
279
|
+
if (scopeTemplates.value.includes(newScopeTemplate.value)) {
|
|
280
|
+
ElMessage({
|
|
281
|
+
message: "该模板已存在",
|
|
282
|
+
type: "warning",
|
|
283
|
+
});
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
186
286
|
|
|
187
|
-
|
|
188
|
-
|
|
287
|
+
// 添加到本地数组
|
|
288
|
+
scopeTemplates.value.push(newScopeTemplate.value);
|
|
289
|
+
|
|
290
|
+
// 保存到服务器
|
|
291
|
+
const response = await fetch("/api/config/save-template", {
|
|
292
|
+
method: "POST",
|
|
293
|
+
headers: {
|
|
294
|
+
"Content-Type": "application/json",
|
|
295
|
+
},
|
|
296
|
+
body: JSON.stringify({
|
|
297
|
+
template: newScopeTemplate.value,
|
|
298
|
+
type: "scope",
|
|
299
|
+
}),
|
|
300
|
+
});
|
|
189
301
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
302
|
+
const result = await response.json();
|
|
303
|
+
if (result.success) {
|
|
304
|
+
ElMessage({
|
|
305
|
+
message: "作用域模板保存成功!",
|
|
306
|
+
type: "success",
|
|
307
|
+
});
|
|
308
|
+
newScopeTemplate.value = "";
|
|
309
|
+
} else {
|
|
310
|
+
ElMessage({
|
|
311
|
+
message: "作用域模板保存失败: " + result.error,
|
|
312
|
+
type: "error",
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
} catch (error) {
|
|
317
|
+
ElMessage({
|
|
318
|
+
message: "作用域模板保存失败: " + (error as Error).message,
|
|
319
|
+
type: "error",
|
|
200
320
|
});
|
|
321
|
+
}
|
|
322
|
+
}
|
|
201
323
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
324
|
+
// 更新作用域模板
|
|
325
|
+
async function updateScopeTemplate() {
|
|
326
|
+
try {
|
|
327
|
+
// 先从本地数组中更新
|
|
328
|
+
if (editingScopeIndex.value >= 0) {
|
|
329
|
+
// 保存原模板和新模板
|
|
330
|
+
const oldTemplate = originalScopeTemplate.value;
|
|
331
|
+
const newTemplate = newScopeTemplate.value;
|
|
332
|
+
|
|
333
|
+
// 更新本地数组
|
|
334
|
+
scopeTemplates.value[editingScopeIndex.value] = newTemplate;
|
|
335
|
+
|
|
336
|
+
// 调用API更新服务器
|
|
337
|
+
const response = await fetch("/api/config/update-template", {
|
|
338
|
+
method: "POST",
|
|
339
|
+
headers: {
|
|
340
|
+
"Content-Type": "application/json",
|
|
341
|
+
},
|
|
342
|
+
body: JSON.stringify({
|
|
343
|
+
oldTemplate,
|
|
344
|
+
newTemplate,
|
|
345
|
+
type: "scope",
|
|
346
|
+
}),
|
|
213
347
|
});
|
|
348
|
+
|
|
349
|
+
const result = await response.json();
|
|
350
|
+
if (result.success) {
|
|
351
|
+
ElMessage({
|
|
352
|
+
message: "作用域模板更新成功!",
|
|
353
|
+
type: "success",
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
// 重置编辑状态
|
|
357
|
+
isEditingScope.value = false;
|
|
358
|
+
originalScopeTemplate.value = "";
|
|
359
|
+
editingScopeIndex.value = -1;
|
|
360
|
+
newScopeTemplate.value = "";
|
|
361
|
+
} else {
|
|
362
|
+
ElMessage({
|
|
363
|
+
message: "作用域模板更新失败: " + result.error,
|
|
364
|
+
type: "error",
|
|
365
|
+
});
|
|
366
|
+
}
|
|
214
367
|
}
|
|
215
368
|
} catch (error) {
|
|
216
369
|
ElMessage({
|
|
217
|
-
message: "
|
|
370
|
+
message: "作用域模板更新失败: " + (error as Error).message,
|
|
218
371
|
type: "error",
|
|
219
372
|
});
|
|
220
373
|
}
|
|
221
374
|
}
|
|
222
375
|
|
|
376
|
+
// 开始编辑作用域模板
|
|
377
|
+
function startEditScopeTemplate(template: string, index: number) {
|
|
378
|
+
isEditingScope.value = true;
|
|
379
|
+
originalScopeTemplate.value = template;
|
|
380
|
+
editingScopeIndex.value = index;
|
|
381
|
+
newScopeTemplate.value = template;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// 取消编辑作用域模板
|
|
385
|
+
function cancelEditScopeTemplate() {
|
|
386
|
+
isEditingScope.value = false;
|
|
387
|
+
originalScopeTemplate.value = "";
|
|
388
|
+
editingScopeIndex.value = -1;
|
|
389
|
+
newScopeTemplate.value = "";
|
|
390
|
+
}
|
|
391
|
+
|
|
223
392
|
// 删除描述模板
|
|
224
393
|
async function deleteDescriptionTemplate(template: string) {
|
|
225
394
|
try {
|
|
@@ -324,231 +493,184 @@ function openScopeSettings() {
|
|
|
324
493
|
scopeDialogVisible.value = true;
|
|
325
494
|
}
|
|
326
495
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
496
|
+
// 添加文件到暂存区 (git add)
|
|
497
|
+
async function addToStage() {
|
|
498
|
+
try {
|
|
499
|
+
const result = await gitLogStore.addToStage();
|
|
500
|
+
if (result) {
|
|
501
|
+
// 触发状态更新事件
|
|
502
|
+
gitLogStore.fetchStatus();
|
|
503
|
+
}
|
|
504
|
+
} catch (error) {
|
|
505
|
+
ElMessage({
|
|
506
|
+
message: `添加文件失败: ${(error as Error).message}`,
|
|
507
|
+
type: "error",
|
|
508
|
+
});
|
|
339
509
|
}
|
|
340
510
|
}
|
|
341
511
|
|
|
342
|
-
// 提交更改
|
|
512
|
+
// 提交更改 (git commit)
|
|
343
513
|
async function commitChanges() {
|
|
344
|
-
|
|
345
|
-
if (!message && isStandardCommit.value && !commitDescription.value) {
|
|
514
|
+
if (!finalCommitMessage.value.trim()) {
|
|
346
515
|
ElMessage({
|
|
347
|
-
message: "
|
|
516
|
+
message: "提交信息不能为空",
|
|
348
517
|
type: "warning",
|
|
349
518
|
});
|
|
350
519
|
return;
|
|
351
520
|
}
|
|
352
521
|
|
|
353
522
|
try {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
// 先执行 git add .
|
|
358
|
-
const addResponse = await fetch("/api/add", {
|
|
359
|
-
method: "POST",
|
|
360
|
-
});
|
|
361
|
-
|
|
362
|
-
const addResult = await addResponse.json();
|
|
363
|
-
if (!addResult.success) {
|
|
364
|
-
ElMessage({
|
|
365
|
-
message: "添加文件失败: " + addResult.error,
|
|
366
|
-
type: "error",
|
|
367
|
-
});
|
|
368
|
-
return;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
const response = await fetch("/api/commit", {
|
|
372
|
-
method: "POST",
|
|
373
|
-
headers: {
|
|
374
|
-
"Content-Type": "application/json",
|
|
375
|
-
},
|
|
376
|
-
body: JSON.stringify({
|
|
377
|
-
message,
|
|
378
|
-
// 添加一个标志,表示消息包含换行符
|
|
379
|
-
hasNewlines: message.includes("\n"),
|
|
380
|
-
// 添加 no-verify 选项
|
|
381
|
-
noVerify: skipHooks.value,
|
|
382
|
-
}),
|
|
383
|
-
});
|
|
523
|
+
// 使用Store提交更改
|
|
524
|
+
const result = await gitLogStore.commitChanges(finalCommitMessage.value, skipHooks.value);
|
|
384
525
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
if (isStandardCommit.value) {
|
|
389
|
-
commitDescription.value = "";
|
|
390
|
-
commitBody.value = "";
|
|
391
|
-
commitFooter.value = "";
|
|
392
|
-
} else {
|
|
393
|
-
commitMessage.value = "";
|
|
394
|
-
}
|
|
526
|
+
if (result) {
|
|
527
|
+
// 清空提交信息
|
|
528
|
+
clearCommitFields();
|
|
395
529
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
});
|
|
400
|
-
// 发出提交成功事件
|
|
401
|
-
emit("commit-success");
|
|
402
|
-
} else {
|
|
403
|
-
ElMessage({
|
|
404
|
-
message: "提交失败: " + result.error,
|
|
405
|
-
type: "error",
|
|
406
|
-
});
|
|
530
|
+
// 触发成功事件
|
|
531
|
+
gitLogStore.fetchStatus();
|
|
532
|
+
gitLogStore.fetchLog();
|
|
407
533
|
}
|
|
408
534
|
} catch (error) {
|
|
409
535
|
ElMessage({
|
|
410
|
-
message:
|
|
536
|
+
message: `提交失败: ${(error as Error).message}`,
|
|
411
537
|
type: "error",
|
|
412
538
|
});
|
|
413
|
-
} finally {
|
|
414
|
-
isCommitting.value = false;
|
|
415
|
-
commitBtnText.value = "提交";
|
|
416
539
|
}
|
|
417
540
|
}
|
|
418
541
|
|
|
419
|
-
//
|
|
420
|
-
async function
|
|
542
|
+
// 推送到远程 (git push)
|
|
543
|
+
async function pushToRemote() {
|
|
421
544
|
try {
|
|
422
|
-
isPushing.value = true
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
if (result.success) {
|
|
431
|
-
ElMessage({
|
|
432
|
-
message: "推送成功!",
|
|
433
|
-
type: "success",
|
|
434
|
-
});
|
|
435
|
-
// 发出推送成功事件
|
|
436
|
-
emit("push-success");
|
|
437
|
-
} else {
|
|
438
|
-
ElMessage({
|
|
439
|
-
message: "推送失败: " + result.error,
|
|
440
|
-
type: "error",
|
|
441
|
-
});
|
|
545
|
+
isPushing.value = true
|
|
546
|
+
// 使用Store推送更改
|
|
547
|
+
const result = await gitLogStore.pushToRemote();
|
|
548
|
+
|
|
549
|
+
if (result) {
|
|
550
|
+
// 触发成功事件
|
|
551
|
+
gitStore.getCurrentBranch();
|
|
552
|
+
gitLogStore.fetchLog();
|
|
442
553
|
}
|
|
443
554
|
} catch (error) {
|
|
444
555
|
ElMessage({
|
|
445
|
-
message:
|
|
556
|
+
message: `推送失败: ${(error as Error).message}`,
|
|
446
557
|
type: "error",
|
|
447
558
|
});
|
|
448
559
|
} finally {
|
|
449
|
-
isPushing.value = false
|
|
450
|
-
pushBtnText.value = "推送到远程";
|
|
560
|
+
isPushing.value = false
|
|
451
561
|
}
|
|
452
562
|
}
|
|
453
563
|
|
|
454
|
-
//
|
|
455
|
-
async function
|
|
456
|
-
|
|
457
|
-
if (!message && isStandardCommit.value && !commitDescription.value) {
|
|
564
|
+
// 添加并提交 (git add + git commit)
|
|
565
|
+
async function addAndCommit() {
|
|
566
|
+
if (!finalCommitMessage.value.trim()) {
|
|
458
567
|
ElMessage({
|
|
459
|
-
message: "
|
|
568
|
+
message: "提交信息不能为空",
|
|
460
569
|
type: "warning",
|
|
461
570
|
});
|
|
462
571
|
return;
|
|
463
572
|
}
|
|
464
573
|
|
|
465
574
|
try {
|
|
466
|
-
|
|
467
|
-
commitAndPushBtnText.value = "处理中...";
|
|
575
|
+
await gitLogStore.addAndCommit(finalCommitMessage.value, skipHooks.value);
|
|
468
576
|
|
|
469
|
-
//
|
|
470
|
-
|
|
471
|
-
|
|
577
|
+
// 清空提交信息
|
|
578
|
+
clearCommitFields();
|
|
579
|
+
|
|
580
|
+
// 触发成功事件
|
|
581
|
+
gitLogStore.fetchStatus();
|
|
582
|
+
gitLogStore.fetchLog();
|
|
583
|
+
} catch (error) {
|
|
584
|
+
ElMessage({
|
|
585
|
+
message: `暂存并提交失败: ${(error as Error).message}`,
|
|
586
|
+
type: "error",
|
|
472
587
|
});
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
if (!addResult.success) {
|
|
476
|
-
ElMessage({
|
|
477
|
-
message: "添加文件失败: " + addResult.error,
|
|
478
|
-
type: "error",
|
|
479
|
-
});
|
|
480
|
-
return;
|
|
481
|
-
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
482
590
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
body: JSON.stringify({
|
|
490
|
-
message,
|
|
491
|
-
// 添加一个标志,表示消息包含换行符
|
|
492
|
-
hasNewlines: message.includes("\n"),
|
|
493
|
-
// 添加 no-verify 选项
|
|
494
|
-
noVerify: skipHooks.value,
|
|
495
|
-
}),
|
|
591
|
+
// 添加、提交并推送 (git add + git commit + git push)
|
|
592
|
+
async function addCommitAndPush() {
|
|
593
|
+
if (!finalCommitMessage.value.trim()) {
|
|
594
|
+
ElMessage({
|
|
595
|
+
message: "提交信息不能为空",
|
|
596
|
+
type: "warning",
|
|
496
597
|
});
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
497
600
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
ElMessage({
|
|
501
|
-
message: "提交失败: " + commitResult.error,
|
|
502
|
-
type: "error",
|
|
503
|
-
});
|
|
504
|
-
return;
|
|
505
|
-
}
|
|
601
|
+
try {
|
|
602
|
+
await gitLogStore.addCommitAndPush(finalCommitMessage.value, skipHooks.value);
|
|
506
603
|
|
|
507
|
-
// 清空输入
|
|
508
|
-
if (isStandardCommit.value) {
|
|
509
|
-
commitDescription.value = "";
|
|
510
|
-
commitBody.value = "";
|
|
511
|
-
commitFooter.value = "";
|
|
512
|
-
} else {
|
|
513
|
-
commitMessage.value = "";
|
|
514
|
-
}
|
|
515
604
|
|
|
516
|
-
//
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
605
|
+
// 清空提交信息
|
|
606
|
+
clearCommitFields();
|
|
607
|
+
|
|
608
|
+
// 触发成功事件
|
|
609
|
+
gitStore.getCurrentBranch();
|
|
610
|
+
gitLogStore.fetchLog();
|
|
520
611
|
|
|
521
|
-
const pushResult = await pushResponse.json();
|
|
522
|
-
if (pushResult.success) {
|
|
523
|
-
commitMessage.value = "";
|
|
524
|
-
ElMessage({
|
|
525
|
-
message: "提交并推送成功!",
|
|
526
|
-
type: "success",
|
|
527
|
-
});
|
|
528
|
-
// 发出提交和推送成功事件
|
|
529
|
-
emit("commit-success");
|
|
530
|
-
emit("push-success");
|
|
531
|
-
} else {
|
|
532
|
-
ElMessage({
|
|
533
|
-
message: "推送失败: " + pushResult.error,
|
|
534
|
-
type: "error",
|
|
535
|
-
});
|
|
536
|
-
}
|
|
537
612
|
} catch (error) {
|
|
538
613
|
ElMessage({
|
|
539
|
-
message:
|
|
614
|
+
message: `暂存、提交并推送失败: ${(error as Error).message}`,
|
|
540
615
|
type: "error",
|
|
541
616
|
});
|
|
542
617
|
} finally {
|
|
543
|
-
isCommitAndPushing.value = false;
|
|
544
|
-
commitAndPushBtnText.value = "提交并推送";
|
|
545
618
|
}
|
|
546
619
|
}
|
|
547
620
|
|
|
621
|
+
// 重置到远程分支 (git reset --hard origin/branch)
|
|
622
|
+
async function resetToRemote() {
|
|
623
|
+
try {
|
|
624
|
+
await ElMessageBox.confirm(
|
|
625
|
+
`确定要重置当前分支 "${gitStore.currentBranch}" 到远程状态吗?这将丢失所有未推送的提交和本地更改。`,
|
|
626
|
+
'重置到远程分支',
|
|
627
|
+
{
|
|
628
|
+
confirmButtonText: '确定',
|
|
629
|
+
cancelButtonText: '取消',
|
|
630
|
+
type: 'warning'
|
|
631
|
+
}
|
|
632
|
+
);
|
|
633
|
+
|
|
634
|
+
const result = await gitLogStore.resetToRemote(gitStore.currentBranch);
|
|
635
|
+
if (result) {
|
|
636
|
+
// 触发状态更新事件
|
|
637
|
+
gitLogStore.fetchStatus();
|
|
638
|
+
// 更新提交历史
|
|
639
|
+
gitLogStore.fetchLog();
|
|
640
|
+
}
|
|
641
|
+
} catch (error) {
|
|
642
|
+
// 用户取消操作,不显示错误
|
|
643
|
+
if ((error as any) !== 'cancel') {
|
|
644
|
+
ElMessage({
|
|
645
|
+
message: `重置到远程分支失败: ${(error as Error).message}`,
|
|
646
|
+
type: 'error'
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// 清空提交字段
|
|
653
|
+
function clearCommitFields() {
|
|
654
|
+
commitMessage.value = "";
|
|
655
|
+
commitDescription.value = "";
|
|
656
|
+
commitBody.value = "";
|
|
657
|
+
commitFooter.value = "";
|
|
658
|
+
}
|
|
548
659
|
|
|
549
660
|
onMounted(() => {
|
|
550
661
|
loadConfig();
|
|
551
|
-
|
|
662
|
+
|
|
663
|
+
// 从 localStorage 中获取标准化提交设置
|
|
664
|
+
const savedStandardCommit = localStorage.getItem("zen-gitsync-standard-commit");
|
|
665
|
+
if (savedStandardCommit !== null) {
|
|
666
|
+
isStandardCommit.value = savedStandardCommit === "true";
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// 从 localStorage 中获取跳过钩子设置
|
|
670
|
+
const savedSkipHooks = localStorage.getItem("zen-gitsync-skip-hooks");
|
|
671
|
+
if (savedSkipHooks !== null) {
|
|
672
|
+
skipHooks.value = savedSkipHooks === "true";
|
|
673
|
+
}
|
|
552
674
|
});
|
|
553
675
|
</script>
|
|
554
676
|
|
|
@@ -556,178 +678,200 @@ onMounted(() => {
|
|
|
556
678
|
<div class="card">
|
|
557
679
|
<h2>提交更改</h2>
|
|
558
680
|
|
|
559
|
-
<div class="
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
681
|
+
<div class="layout-container">
|
|
682
|
+
<!-- 如果没有配置Git用户信息,显示提示 -->
|
|
683
|
+
<div v-if="gitStore.userName === '' || gitStore.userEmail === ''" class="git-config-warning">
|
|
684
|
+
<el-alert
|
|
685
|
+
title="Git用户信息未配置"
|
|
686
|
+
type="warning"
|
|
687
|
+
:closable="false"
|
|
688
|
+
show-icon
|
|
689
|
+
>
|
|
690
|
+
<p>您需要配置Git用户名和邮箱才能提交代码。请使用以下命令配置:</p>
|
|
691
|
+
<pre class="config-command">git config --global user.name "Your Name"
|
|
692
|
+
git config --global user.email "your.email@example.com"</pre>
|
|
693
|
+
</el-alert>
|
|
566
694
|
</div>
|
|
695
|
+
|
|
696
|
+
<!-- 正常的提交区域,仅在Git用户信息已配置时显示 -->
|
|
697
|
+
<template v-else>
|
|
698
|
+
<!-- 左侧:提交表单 -->
|
|
699
|
+
<div class="commit-section">
|
|
700
|
+
<div class="commit-options">
|
|
701
|
+
<div class="options-row">
|
|
702
|
+
<div class="commit-mode-toggle">
|
|
703
|
+
<el-switch v-model="isStandardCommit" active-text="标准化提交" inactive-text="普通提交" />
|
|
704
|
+
</div>
|
|
567
705
|
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
706
|
+
<div class="no-verify-toggle">
|
|
707
|
+
<el-tooltip content="跳过 Git 钩子检查 (--no-verify)" placement="top">
|
|
708
|
+
<el-switch v-model="skipHooks" active-text="跳过钩子 (--no-verify)" />
|
|
709
|
+
</el-tooltip>
|
|
710
|
+
</div>
|
|
711
|
+
</div>
|
|
712
|
+
</div>
|
|
713
|
+
|
|
714
|
+
<!-- 普通提交表单 -->
|
|
715
|
+
<div v-if="!isStandardCommit" class="commit-form">
|
|
716
|
+
<el-input v-model="commitMessage" :placeholder="placeholder" clearable />
|
|
717
|
+
</div>
|
|
718
|
+
|
|
719
|
+
<!-- 标准化提交表单 -->
|
|
720
|
+
<div v-else class="standard-commit-form">
|
|
721
|
+
<div class="standard-commit-header">
|
|
722
|
+
<el-select v-model="commitType" placeholder="提交类型" class="type-select" clearable>
|
|
723
|
+
<el-option v-for="item in commitTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
|
724
|
+
</el-select>
|
|
725
|
+
|
|
726
|
+
<div class="scope-container">
|
|
727
|
+
<el-input v-model="commitScope" placeholder="作用域(可选)" class="scope-input" clearable />
|
|
728
|
+
<el-button type="primary" :icon="Setting" circle size="small" class="settings-button"
|
|
729
|
+
@click="openScopeSettings">
|
|
730
|
+
</el-button>
|
|
731
|
+
</div>
|
|
574
732
|
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
>{{ commitBtnText }}</el-button
|
|
583
|
-
>
|
|
584
|
-
</div>
|
|
733
|
+
<div class="description-container">
|
|
734
|
+
<el-input v-model="commitDescription" placeholder="简短描述(必填)" class="description-input" clearable />
|
|
735
|
+
<el-button type="primary" :icon="Setting" circle size="small" class="settings-button"
|
|
736
|
+
@click="openDescriptionSettings">
|
|
737
|
+
</el-button>
|
|
738
|
+
</div>
|
|
739
|
+
</div>
|
|
585
740
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
<div class="standard-commit-header">
|
|
589
|
-
<el-select
|
|
590
|
-
v-model="commitType"
|
|
591
|
-
placeholder="提交类型"
|
|
592
|
-
class="type-select"
|
|
593
|
-
clearable
|
|
594
|
-
>
|
|
595
|
-
<el-option
|
|
596
|
-
v-for="item in commitTypeOptions"
|
|
597
|
-
:key="item.value"
|
|
598
|
-
:label="item.label"
|
|
599
|
-
:value="item.value"
|
|
600
|
-
/>
|
|
601
|
-
</el-select>
|
|
602
|
-
|
|
603
|
-
<div class="scope-container">
|
|
604
|
-
<el-input
|
|
605
|
-
v-model="commitScope"
|
|
606
|
-
placeholder="作用域(可选)"
|
|
607
|
-
class="scope-input"
|
|
608
|
-
clearable
|
|
609
|
-
/>
|
|
610
|
-
<el-button
|
|
611
|
-
type="primary"
|
|
612
|
-
:icon="Setting"
|
|
613
|
-
circle
|
|
614
|
-
size="small"
|
|
615
|
-
class="settings-button"
|
|
616
|
-
@click="openScopeSettings"
|
|
617
|
-
>
|
|
618
|
-
</el-button>
|
|
619
|
-
</div>
|
|
741
|
+
<el-input v-model="commitBody" type="textarea" :rows="4" placeholder="正文(可选):详细描述本次提交的内容和原因" class="body-input"
|
|
742
|
+
clearable />
|
|
620
743
|
|
|
621
|
-
|
|
622
|
-
<el-input
|
|
623
|
-
v-model="commitDescription"
|
|
624
|
-
placeholder="简短描述(必填)"
|
|
625
|
-
class="description-input"
|
|
626
|
-
clearable
|
|
627
|
-
/>
|
|
628
|
-
<el-button
|
|
629
|
-
type="primary"
|
|
630
|
-
:icon="Setting"
|
|
631
|
-
circle
|
|
632
|
-
size="small"
|
|
633
|
-
class="settings-button"
|
|
634
|
-
@click="openDescriptionSettings"
|
|
635
|
-
>
|
|
636
|
-
</el-button>
|
|
637
|
-
</div>
|
|
638
|
-
</div>
|
|
744
|
+
<el-input v-model="commitFooter" placeholder="页脚(可选):如 Closes #123" class="footer-input" clearable />
|
|
639
745
|
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
:rows="4"
|
|
644
|
-
placeholder="正文(可选):详细描述本次提交的内容和原因"
|
|
645
|
-
class="body-input"
|
|
646
|
-
clearable
|
|
647
|
-
/>
|
|
648
|
-
|
|
649
|
-
<el-input
|
|
650
|
-
v-model="commitFooter"
|
|
651
|
-
placeholder="页脚(可选):如 Closes #123"
|
|
652
|
-
class="footer-input"
|
|
653
|
-
clearable
|
|
654
|
-
/>
|
|
655
|
-
|
|
656
|
-
<div class="preview-section">
|
|
657
|
-
<div class="preview-title">预览:</div>
|
|
658
|
-
<pre class="preview-content">{{ finalCommitMessage }}</pre>
|
|
659
|
-
</div>
|
|
746
|
+
<div class="preview-section">
|
|
747
|
+
<div class="preview-title">提交信息预览:</div>
|
|
748
|
+
<pre class="preview-content">{{ finalCommitMessage }}</pre>
|
|
660
749
|
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
>
|
|
666
|
-
>
|
|
667
|
-
</div>
|
|
750
|
+
<div class="preview-title" style="margin-top: 10px;">Git命令预览:</div>
|
|
751
|
+
<pre class="preview-content code-command">{{ gitCommandPreview }}</pre>
|
|
752
|
+
</div>
|
|
753
|
+
</div>
|
|
754
|
+
</div>
|
|
668
755
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
756
|
+
<!-- 右侧:操作区域 -->
|
|
757
|
+
<div class="actions-section">
|
|
758
|
+
<h3>Git 操作</h3>
|
|
759
|
+
<div class="action-groups">
|
|
760
|
+
<div class="action-group">
|
|
761
|
+
<div class="group-title">基础操作</div>
|
|
762
|
+
<div class="group-buttons">
|
|
763
|
+
<el-button
|
|
764
|
+
type="primary"
|
|
765
|
+
@click="addToStage"
|
|
766
|
+
:loading="gitLogStore.isAddingFiles"
|
|
767
|
+
class="action-button"
|
|
768
|
+
>
|
|
769
|
+
暂存更改
|
|
770
|
+
<span class="command-text">git add .</span>
|
|
771
|
+
</el-button>
|
|
772
|
+
|
|
773
|
+
<el-button
|
|
774
|
+
type="primary"
|
|
775
|
+
@click="commitChanges"
|
|
776
|
+
:loading="gitLogStore.isLoadingStatus"
|
|
777
|
+
class="action-button"
|
|
778
|
+
>
|
|
779
|
+
提交
|
|
780
|
+
<span class="command-text">git commit</span>
|
|
781
|
+
</el-button>
|
|
782
|
+
|
|
783
|
+
<el-button
|
|
784
|
+
type="success"
|
|
785
|
+
@click="pushToRemote"
|
|
786
|
+
:loading="gitLogStore.isPushing"
|
|
787
|
+
class="action-button push-button"
|
|
788
|
+
>
|
|
789
|
+
推送
|
|
790
|
+
<span class="command-text">git push</span>
|
|
791
|
+
</el-button>
|
|
792
|
+
</div>
|
|
793
|
+
</div>
|
|
794
|
+
|
|
795
|
+
<div class="action-group">
|
|
796
|
+
<div class="group-title">组合操作</div>
|
|
797
|
+
<div class="group-buttons">
|
|
798
|
+
<el-button
|
|
799
|
+
type="warning"
|
|
800
|
+
@click="addAndCommit"
|
|
801
|
+
:loading="gitLogStore.isAddingFiles || gitLogStore.isCommiting"
|
|
802
|
+
class="action-button"
|
|
803
|
+
>
|
|
804
|
+
暂存并提交
|
|
805
|
+
<span class="command-text">git add + commit</span>
|
|
806
|
+
</el-button>
|
|
807
|
+
|
|
808
|
+
<el-button
|
|
809
|
+
type="danger"
|
|
810
|
+
@click="addCommitAndPush"
|
|
811
|
+
:loading="gitLogStore.isAddingFiles || gitLogStore.isCommiting || gitLogStore.isPushing"
|
|
812
|
+
class="action-button"
|
|
813
|
+
>
|
|
814
|
+
一键推送
|
|
815
|
+
<span class="command-text command-text-long">git add + commit + push</span>
|
|
816
|
+
</el-button>
|
|
817
|
+
</div>
|
|
818
|
+
</div>
|
|
819
|
+
|
|
820
|
+
<div class="action-group">
|
|
821
|
+
<div class="group-title">重置操作</div>
|
|
822
|
+
<div class="group-buttons">
|
|
823
|
+
<!-- <el-button
|
|
824
|
+
type="info"
|
|
825
|
+
@click="resetHead"
|
|
826
|
+
:loading="gitLogStore.isResetting"
|
|
827
|
+
:icon="Refresh"
|
|
828
|
+
class="action-button reset-button"
|
|
829
|
+
>
|
|
830
|
+
重置暂存区
|
|
831
|
+
<span class="command-text">git reset HEAD</span>
|
|
832
|
+
</el-button> -->
|
|
833
|
+
|
|
834
|
+
<el-button
|
|
835
|
+
type="info"
|
|
836
|
+
@click="resetToRemote"
|
|
837
|
+
:loading="gitLogStore.isResetting"
|
|
838
|
+
class="action-button reset-button"
|
|
839
|
+
>
|
|
840
|
+
重置到远程
|
|
841
|
+
<span class="command-text command-text-long">git reset --hard origin/branch</span>
|
|
842
|
+
</el-button>
|
|
843
|
+
</div>
|
|
844
|
+
</div>
|
|
845
|
+
</div>
|
|
846
|
+
</div>
|
|
847
|
+
</template>
|
|
679
848
|
</div>
|
|
680
849
|
|
|
681
850
|
<!-- 简短描述设置弹窗 -->
|
|
682
|
-
<el-dialog
|
|
683
|
-
title="简短描述模板设置"
|
|
684
|
-
v-model="descriptionDialogVisible"
|
|
685
|
-
width="80vw"
|
|
686
|
-
style="height: 80vh"
|
|
687
|
-
>
|
|
851
|
+
<el-dialog title="简短描述模板设置" v-model="descriptionDialogVisible" width="80vw" style="height: 80vh">
|
|
688
852
|
<div class="template-container">
|
|
689
853
|
<div class="template-form">
|
|
690
|
-
<el-input
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
type="primary"
|
|
698
|
-
@click="saveDescriptionTemplate"
|
|
699
|
-
:disabled="!newTemplateName.trim()"
|
|
700
|
-
>添加模板</el-button
|
|
701
|
-
>
|
|
854
|
+
<el-input v-model="newTemplateName" :placeholder="isEditingDescription ? '编辑模板内容' : '输入新模板内容'"
|
|
855
|
+
class="template-input" clearable />
|
|
856
|
+
<div class="template-form-buttons">
|
|
857
|
+
<el-button v-if="isEditingDescription" @click="cancelEditDescriptionTemplate">取消</el-button>
|
|
858
|
+
<el-button type="primary" @click="saveDescriptionTemplate" :disabled="!newTemplateName.trim()">{{
|
|
859
|
+
isEditingDescription ? '更新模板' : '添加模板' }}</el-button>
|
|
860
|
+
</div>
|
|
702
861
|
</div>
|
|
703
862
|
|
|
704
863
|
<div class="template-list">
|
|
705
864
|
<h3>已保存模板</h3>
|
|
706
|
-
<el-empty
|
|
707
|
-
|
|
708
|
-
description="暂无保存的模板"
|
|
709
|
-
/>
|
|
710
|
-
<el-card
|
|
711
|
-
v-for="(template, index) in descriptionTemplates"
|
|
712
|
-
:key="index"
|
|
713
|
-
class="template-item"
|
|
714
|
-
>
|
|
865
|
+
<el-empty v-if="descriptionTemplates.length === 0" description="暂无保存的模板" />
|
|
866
|
+
<el-card v-for="(template, index) in descriptionTemplates" :key="index" class="template-item">
|
|
715
867
|
<!-- 两端对齐 -->
|
|
716
868
|
<el-row justify="space-between" align="middle" style="width: 100%">
|
|
717
869
|
<div class="template-content">{{ template }}</div>
|
|
718
870
|
<div class="template-actions">
|
|
719
|
-
<el-button
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
>使用</el-button
|
|
724
|
-
>
|
|
725
|
-
<el-button
|
|
726
|
-
type="danger"
|
|
727
|
-
size="small"
|
|
728
|
-
@click="deleteDescriptionTemplate(template)"
|
|
729
|
-
>删除</el-button
|
|
730
|
-
>
|
|
871
|
+
<el-button type="primary" size="small" @click="useTemplate(template)">使用</el-button>
|
|
872
|
+
<el-button type="warning" size="small" :icon="Edit"
|
|
873
|
+
@click="startEditDescriptionTemplate(template, index)">编辑</el-button>
|
|
874
|
+
<el-button type="danger" size="small" @click="deleteDescriptionTemplate(template)">删除</el-button>
|
|
731
875
|
</div>
|
|
732
876
|
</el-row>
|
|
733
877
|
</el-card>
|
|
@@ -736,54 +880,29 @@ onMounted(() => {
|
|
|
736
880
|
</el-dialog>
|
|
737
881
|
|
|
738
882
|
<!-- 作用域设置弹窗 -->
|
|
739
|
-
<el-dialog
|
|
740
|
-
title="作用域模板设置"
|
|
741
|
-
v-model="scopeDialogVisible"
|
|
742
|
-
width="80%"
|
|
743
|
-
style="height: 80vh"
|
|
744
|
-
>
|
|
883
|
+
<el-dialog title="作用域模板设置" v-model="scopeDialogVisible" width="80%" style="height: 80vh">
|
|
745
884
|
<div class="template-container">
|
|
746
885
|
<div class="template-form">
|
|
747
|
-
<el-input
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
type="primary"
|
|
755
|
-
@click="saveScopeTemplate"
|
|
756
|
-
:disabled="!newScopeTemplate.trim()"
|
|
757
|
-
>添加模板</el-button
|
|
758
|
-
>
|
|
886
|
+
<el-input v-model="newScopeTemplate" :placeholder="isEditingScope ? '编辑作用域模板内容' : '输入新作用域模板'"
|
|
887
|
+
class="template-input" clearable />
|
|
888
|
+
<div class="template-form-buttons">
|
|
889
|
+
<el-button v-if="isEditingScope" @click="cancelEditScopeTemplate">取消</el-button>
|
|
890
|
+
<el-button type="primary" @click="saveScopeTemplate" :disabled="!newScopeTemplate.trim()">{{ isEditingScope
|
|
891
|
+
? '更新模板' : '添加模板' }}</el-button>
|
|
892
|
+
</div>
|
|
759
893
|
</div>
|
|
760
894
|
|
|
761
895
|
<div class="template-list">
|
|
762
896
|
<h3>已保存作用域</h3>
|
|
763
|
-
<el-empty
|
|
764
|
-
|
|
765
|
-
description="暂无保存的作用域"
|
|
766
|
-
/>
|
|
767
|
-
<el-card
|
|
768
|
-
v-for="(template, index) in scopeTemplates"
|
|
769
|
-
:key="index"
|
|
770
|
-
class="template-item"
|
|
771
|
-
>
|
|
897
|
+
<el-empty v-if="scopeTemplates.length === 0" description="暂无保存的作用域" />
|
|
898
|
+
<el-card v-for="(template, index) in scopeTemplates" :key="index" class="template-item">
|
|
772
899
|
<el-row justify="space-between" align="middle" style="width: 100%">
|
|
773
900
|
<div class="template-content">{{ template }}</div>
|
|
774
901
|
<div class="template-actions">
|
|
775
|
-
<el-button
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
>使用</el-button
|
|
780
|
-
>
|
|
781
|
-
<el-button
|
|
782
|
-
type="danger"
|
|
783
|
-
size="small"
|
|
784
|
-
@click="deleteScopeTemplate(template)"
|
|
785
|
-
>删除</el-button
|
|
786
|
-
>
|
|
902
|
+
<el-button type="primary" size="small" @click="useScopeTemplate(template)">使用</el-button>
|
|
903
|
+
<el-button type="warning" size="small" :icon="Edit"
|
|
904
|
+
@click="startEditScopeTemplate(template, index)">编辑</el-button>
|
|
905
|
+
<el-button type="danger" size="small" @click="deleteScopeTemplate(template)">删除</el-button>
|
|
787
906
|
</div>
|
|
788
907
|
</el-row>
|
|
789
908
|
</el-card>
|
|
@@ -794,65 +913,197 @@ onMounted(() => {
|
|
|
794
913
|
</template>
|
|
795
914
|
|
|
796
915
|
<style scoped>
|
|
916
|
+
.card {
|
|
917
|
+
background-color: white;
|
|
918
|
+
border-radius: 5px;
|
|
919
|
+
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
|
920
|
+
margin-bottom: 20px;
|
|
921
|
+
padding: 20px;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
.layout-container {
|
|
925
|
+
display: flex;
|
|
926
|
+
gap: 20px;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
.commit-section {
|
|
930
|
+
flex: 1;
|
|
931
|
+
min-width: 0; /* 防止子元素撑开 */
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
.actions-section {
|
|
935
|
+
width: 300px;
|
|
936
|
+
flex-shrink: 0;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
.actions-section h3 {
|
|
940
|
+
margin-top: 0;
|
|
941
|
+
margin-bottom: 15px;
|
|
942
|
+
padding-bottom: 10px;
|
|
943
|
+
border-bottom: 1px solid #dcdfe6;
|
|
944
|
+
font-size: 18px;
|
|
945
|
+
color: #303133;
|
|
946
|
+
font-weight: 500;
|
|
947
|
+
}
|
|
948
|
+
|
|
797
949
|
.commit-form {
|
|
798
950
|
display: flex;
|
|
799
951
|
margin-bottom: 15px;
|
|
800
952
|
gap: 10px;
|
|
801
953
|
}
|
|
802
|
-
|
|
954
|
+
|
|
955
|
+
.git-actions {
|
|
956
|
+
margin-top: 20px;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
.action-groups {
|
|
803
960
|
display: flex;
|
|
804
|
-
|
|
961
|
+
flex-direction: column;
|
|
962
|
+
gap: 15px;
|
|
805
963
|
}
|
|
806
|
-
|
|
807
|
-
|
|
964
|
+
|
|
965
|
+
.action-group {
|
|
966
|
+
background-color: #f9f9f9;
|
|
967
|
+
border-radius: 8px;
|
|
968
|
+
padding: 12px 15px;
|
|
969
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
|
970
|
+
border-left: 4px solid #409EFF;
|
|
971
|
+
overflow: hidden; /* 确保子元素不会溢出 */
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
.action-group:nth-child(2) {
|
|
975
|
+
border-left-color: #E6A23C;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
.action-group:nth-child(3) {
|
|
979
|
+
border-left-color: #909399;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
.group-title {
|
|
983
|
+
font-size: 14px;
|
|
984
|
+
font-weight: bold;
|
|
985
|
+
margin-bottom: 10px;
|
|
986
|
+
color: #606266;
|
|
987
|
+
text-align: left;
|
|
988
|
+
display: block;
|
|
989
|
+
position: relative;
|
|
990
|
+
padding-left: 10px;
|
|
991
|
+
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
|
992
|
+
padding-bottom: 8px;
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
.group-buttons {
|
|
996
|
+
display: flex;
|
|
997
|
+
flex-direction: column;
|
|
998
|
+
gap: 8px;
|
|
999
|
+
padding: 0 2px;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
.action-button {
|
|
1003
|
+
position: relative;
|
|
1004
|
+
padding: 14px 0 24px 0;
|
|
1005
|
+
width: 100%;
|
|
1006
|
+
display: flex;
|
|
1007
|
+
flex-direction: column;
|
|
1008
|
+
align-items: center;
|
|
1009
|
+
justify-content: center;
|
|
1010
|
+
height: auto;
|
|
1011
|
+
text-align: center;
|
|
1012
|
+
font-size: 16px;
|
|
1013
|
+
border-radius: 6px;
|
|
1014
|
+
border: none;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
.action-button:hover {
|
|
1018
|
+
transform: translateY(-2px);
|
|
1019
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
.action-button:active {
|
|
1023
|
+
transform: translateY(0);
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
.action-button :deep(.el-button__content) {
|
|
1027
|
+
display: flex;
|
|
1028
|
+
flex-direction: column;
|
|
1029
|
+
align-items: center;
|
|
1030
|
+
justify-content: center;
|
|
1031
|
+
width: 100%;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
.action-button :deep(.el-icon) {
|
|
1035
|
+
margin-right: 0;
|
|
1036
|
+
margin-bottom: 4px;
|
|
1037
|
+
font-size: 18px;
|
|
808
1038
|
}
|
|
1039
|
+
|
|
1040
|
+
.command-text {
|
|
1041
|
+
position: absolute;
|
|
1042
|
+
bottom: 6px;
|
|
1043
|
+
font-size: 14px;
|
|
1044
|
+
font-family: monospace;
|
|
1045
|
+
width: 100%;
|
|
1046
|
+
text-align: center;
|
|
1047
|
+
left: 0;
|
|
1048
|
+
white-space: nowrap;
|
|
1049
|
+
|
|
1050
|
+
}
|
|
1051
|
+
|
|
809
1052
|
.standard-commit-form {
|
|
810
1053
|
display: flex;
|
|
811
1054
|
flex-direction: column;
|
|
812
1055
|
gap: 15px;
|
|
813
1056
|
margin-bottom: 15px;
|
|
814
1057
|
}
|
|
1058
|
+
|
|
815
1059
|
.standard-commit-header {
|
|
816
1060
|
display: flex;
|
|
1061
|
+
flex-direction: column;
|
|
817
1062
|
gap: 10px;
|
|
818
1063
|
width: 100%;
|
|
819
1064
|
}
|
|
1065
|
+
|
|
820
1066
|
.type-select {
|
|
821
|
-
width:
|
|
822
|
-
flex-shrink: 0;
|
|
1067
|
+
width: 100%;
|
|
823
1068
|
}
|
|
1069
|
+
|
|
824
1070
|
.scope-container {
|
|
825
1071
|
display: flex;
|
|
826
1072
|
align-items: center;
|
|
827
1073
|
gap: 5px;
|
|
828
|
-
|
|
829
|
-
width: 200px;
|
|
1074
|
+
width: 100%;
|
|
830
1075
|
}
|
|
1076
|
+
|
|
831
1077
|
.scope-input {
|
|
832
1078
|
flex-grow: 1;
|
|
833
1079
|
}
|
|
1080
|
+
|
|
834
1081
|
.description-container {
|
|
835
1082
|
display: flex;
|
|
836
1083
|
align-items: center;
|
|
837
1084
|
gap: 5px;
|
|
838
|
-
|
|
1085
|
+
width: 100%;
|
|
839
1086
|
}
|
|
1087
|
+
|
|
840
1088
|
.description-input {
|
|
841
1089
|
flex-grow: 1;
|
|
842
|
-
min-width: 200px;
|
|
843
1090
|
}
|
|
1091
|
+
|
|
844
1092
|
.settings-button {
|
|
845
1093
|
flex-shrink: 0;
|
|
846
1094
|
}
|
|
1095
|
+
|
|
847
1096
|
.preview-section {
|
|
848
1097
|
background-color: #f5f7fa;
|
|
849
1098
|
padding: 10px;
|
|
850
1099
|
border-radius: 4px;
|
|
851
1100
|
}
|
|
1101
|
+
|
|
852
1102
|
.preview-title {
|
|
853
1103
|
font-weight: bold;
|
|
854
1104
|
margin-bottom: 5px;
|
|
855
1105
|
}
|
|
1106
|
+
|
|
856
1107
|
.preview-content {
|
|
857
1108
|
white-space: pre-wrap;
|
|
858
1109
|
font-family: monospace;
|
|
@@ -861,6 +1112,7 @@ onMounted(() => {
|
|
|
861
1112
|
background-color: #ebeef5;
|
|
862
1113
|
border-radius: 4px;
|
|
863
1114
|
}
|
|
1115
|
+
|
|
864
1116
|
.template-container {
|
|
865
1117
|
display: flex;
|
|
866
1118
|
flex-direction: column;
|
|
@@ -876,24 +1128,30 @@ onMounted(() => {
|
|
|
876
1128
|
flex: 1;
|
|
877
1129
|
overflow-y: auto;
|
|
878
1130
|
}
|
|
1131
|
+
|
|
879
1132
|
.template-input {
|
|
880
1133
|
flex-grow: 1;
|
|
881
1134
|
}
|
|
1135
|
+
|
|
882
1136
|
.template-list {
|
|
883
1137
|
overflow-y: auto;
|
|
884
1138
|
height: 100%;
|
|
885
1139
|
}
|
|
1140
|
+
|
|
886
1141
|
.template-item {
|
|
887
1142
|
margin-bottom: 10px;
|
|
888
1143
|
}
|
|
1144
|
+
|
|
889
1145
|
.template-item:hover {
|
|
890
1146
|
background-color: #f5f7fa;
|
|
891
1147
|
}
|
|
1148
|
+
|
|
892
1149
|
.template-content {
|
|
893
1150
|
flex-grow: 1;
|
|
894
1151
|
margin-right: 10px;
|
|
895
1152
|
word-break: break-all;
|
|
896
1153
|
}
|
|
1154
|
+
|
|
897
1155
|
.template-actions {
|
|
898
1156
|
display: flex;
|
|
899
1157
|
gap: 5px;
|
|
@@ -901,4 +1159,81 @@ onMounted(() => {
|
|
|
901
1159
|
min-width: 120px;
|
|
902
1160
|
flex-shrink: 0;
|
|
903
1161
|
}
|
|
1162
|
+
|
|
1163
|
+
.options-row {
|
|
1164
|
+
display: flex;
|
|
1165
|
+
justify-content: space-between;
|
|
1166
|
+
align-items: center;
|
|
1167
|
+
margin-bottom: 15px;
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
.code-command {
|
|
1171
|
+
background-color: #2d2d2d;
|
|
1172
|
+
color: #f8f8f2;
|
|
1173
|
+
font-family: 'Courier New', Courier, monospace;
|
|
1174
|
+
padding: 10px;
|
|
1175
|
+
border-radius: 4px;
|
|
1176
|
+
overflow-x: auto;
|
|
1177
|
+
white-space: pre;
|
|
1178
|
+
font-size: 14px;
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
@media (max-width: 768px) {
|
|
1182
|
+
.layout-container {
|
|
1183
|
+
flex-direction: column;
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
.actions-section {
|
|
1187
|
+
width: 100%;
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
.group-buttons {
|
|
1191
|
+
flex-direction: row;
|
|
1192
|
+
flex-wrap: wrap;
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
.action-button {
|
|
1196
|
+
flex: 1;
|
|
1197
|
+
min-width: 120px;
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
.git-config-warning {
|
|
1202
|
+
width: 100%;
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
.config-command {
|
|
1206
|
+
background-color: #2d2d2d;
|
|
1207
|
+
color: #f8f8f2;
|
|
1208
|
+
font-family: 'Courier New', Courier, monospace;
|
|
1209
|
+
padding: 10px;
|
|
1210
|
+
border-radius:
|
|
1211
|
+
4px;
|
|
1212
|
+
margin-top: 10px;
|
|
1213
|
+
white-space: pre;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
/* 特定按钮样式 */
|
|
1217
|
+
.push-button {
|
|
1218
|
+
background-color: #67c23a;
|
|
1219
|
+
border-color: #67c23a;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
.push-button:hover {
|
|
1223
|
+
background-color: #85ce61;
|
|
1224
|
+
border-color: #85ce61;
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
.reset-button {
|
|
1228
|
+
background-color: #909399;
|
|
1229
|
+
border-color: #909399;
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
.reset-button:hover {
|
|
1233
|
+
background-color: #a6a9ad;
|
|
1234
|
+
border-color: #a6a9ad;
|
|
1235
|
+
}
|
|
1236
|
+
.el-button+.el-button {
|
|
1237
|
+
margin-left: 0;
|
|
1238
|
+
}
|
|
904
1239
|
</style>
|