zen-gitsync 2.1.3 → 2.1.8
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/LICENSE +21 -21
- package/README.md +96 -96
- package/index.js +2 -2
- package/package.json +69 -66
- package/src/config.js +51 -51
- package/src/gitCommit.js +261 -261
- package/src/ui/public/assets/index-B7Bmz9T9.js +22 -0
- package/src/ui/public/assets/index-DNVXEFTm.css +1 -0
- package/src/ui/public/assets/{vendor-Dy1zosHw.js → vendor-Bm8yNvvz.js} +1 -1
- package/src/ui/public/favicon.svg +26 -26
- package/src/ui/public/index.html +3 -3
- package/src/ui/public/logo.svg +26 -26
- package/src/ui/server/index.js +231 -60
- package/src/ui/client/README.md +0 -5
- package/src/ui/client/auto-imports.d.ts +0 -10
- package/src/ui/client/components.d.ts +0 -33
- package/src/ui/client/index.html +0 -13
- package/src/ui/client/package.json +0 -28
- package/src/ui/client/public/favicon.svg +0 -27
- package/src/ui/client/public/logo.svg +0 -27
- package/src/ui/client/public/vite.svg +0 -1
- package/src/ui/client/src/App.vue +0 -984
- package/src/ui/client/src/assets/logo.svg +0 -27
- package/src/ui/client/src/components/CommitForm.vue +0 -2158
- package/src/ui/client/src/components/GitStatus.vue +0 -1621
- package/src/ui/client/src/components/LogList.vue +0 -1937
- package/src/ui/client/src/main.ts +0 -7
- package/src/ui/client/src/stores/configStore.ts +0 -212
- package/src/ui/client/src/stores/gitLogStore.ts +0 -790
- package/src/ui/client/src/stores/gitStore.ts +0 -443
- package/src/ui/client/src/vite-env.d.ts +0 -1
- package/src/ui/client/stats.html +0 -4949
- package/src/ui/client/tsconfig.app.json +0 -14
- package/src/ui/client/tsconfig.json +0 -7
- package/src/ui/client/tsconfig.node.json +0 -24
- package/src/ui/client/vite.config.ts +0 -50
- package/src/ui/public/assets/index-CekdGwXY.js +0 -20
- package/src/ui/public/assets/index-SwSkrgGk.css +0 -1
|
@@ -1,2158 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
import { ref, onMounted, computed, watch } from "vue";
|
|
3
|
-
import { ElMessage, ElMessageBox } from "element-plus";
|
|
4
|
-
import { Setting, Edit, Check, Upload, RefreshRight, Delete, Position, Download, Connection, ArrowDown } from "@element-plus/icons-vue";
|
|
5
|
-
import { useGitLogStore } from "../stores/gitLogStore";
|
|
6
|
-
import { useGitStore } from "../stores/gitStore";
|
|
7
|
-
import { useConfigStore } from "../stores/configStore";
|
|
8
|
-
|
|
9
|
-
const gitLogStore = useGitLogStore();
|
|
10
|
-
const gitStore = useGitStore();
|
|
11
|
-
const configStore = useConfigStore();
|
|
12
|
-
const commitMessage = ref("");
|
|
13
|
-
const isPushing = ref(false);
|
|
14
|
-
// 添加提交并推送的状态变量
|
|
15
|
-
const showPushSuccess = ref(false);
|
|
16
|
-
// 添加git pull和fetch操作相关状态变量
|
|
17
|
-
const isGitPulling = ref(false);
|
|
18
|
-
const isGitFetching = ref(false);
|
|
19
|
-
// 添加placeholder变量
|
|
20
|
-
const placeholder = ref("输入提交信息...");
|
|
21
|
-
// 添加默认提交信息变量
|
|
22
|
-
const defaultCommitMessage = ref("");
|
|
23
|
-
const isStandardCommit = ref(false);
|
|
24
|
-
const commitType = ref("feat");
|
|
25
|
-
const commitScope = ref("");
|
|
26
|
-
const commitDescription = ref("");
|
|
27
|
-
const commitBody = ref("");
|
|
28
|
-
const commitFooter = ref("");
|
|
29
|
-
|
|
30
|
-
// 提交模板相关变量
|
|
31
|
-
const descriptionTemplates = ref<string[]>([]);
|
|
32
|
-
// 添加对话框可见性变量
|
|
33
|
-
const descriptionDialogVisible = ref(false);
|
|
34
|
-
const newTemplateName = ref("");
|
|
35
|
-
// 添加模板编辑相关变量
|
|
36
|
-
const isEditingDescription = ref(false);
|
|
37
|
-
const originalDescriptionTemplate = ref("");
|
|
38
|
-
const editingDescriptionIndex = ref(-1);
|
|
39
|
-
|
|
40
|
-
// 作用域模板相关变量
|
|
41
|
-
const scopeTemplates = ref<string[]>([]);
|
|
42
|
-
const scopeDialogVisible = ref(false);
|
|
43
|
-
const newScopeTemplate = ref("");
|
|
44
|
-
// 添加作用域模板编辑相关变量
|
|
45
|
-
const isEditingScope = ref(false);
|
|
46
|
-
const originalScopeTemplate = ref("");
|
|
47
|
-
const editingScopeIndex = ref(-1);
|
|
48
|
-
|
|
49
|
-
// 默认提交信息设置相关变量
|
|
50
|
-
const defaultMessageDialogVisible = ref(false);
|
|
51
|
-
const newDefaultMessage = ref("");
|
|
52
|
-
|
|
53
|
-
// 跳过钩子
|
|
54
|
-
const skipHooks = ref(false);
|
|
55
|
-
|
|
56
|
-
// 添加控制正文和页脚显示的状态变量
|
|
57
|
-
const showAdvancedFields = ref(false);
|
|
58
|
-
|
|
59
|
-
// 提交类型选项
|
|
60
|
-
const commitTypeOptions = [
|
|
61
|
-
{ value: "feat", label: "feat: 新功能" },
|
|
62
|
-
{ value: "fix", label: "fix: 修复bug" },
|
|
63
|
-
{ value: "docs", label: "docs: 文档修改" },
|
|
64
|
-
{ value: "style", label: "style: 样式修改" },
|
|
65
|
-
{ value: "refactor", label: "refactor: 代码重构" },
|
|
66
|
-
{ value: "test", label: "test: 测试代码" },
|
|
67
|
-
{ value: "chore", label: "chore: 构建/工具修改" },
|
|
68
|
-
];
|
|
69
|
-
|
|
70
|
-
// 添加默认提交信息模板相关变量
|
|
71
|
-
const messageTemplates = ref<string[]>([]);
|
|
72
|
-
const isEditingMessage = ref(false);
|
|
73
|
-
const originalMessageTemplate = ref("");
|
|
74
|
-
const editingMessageIndex = ref(-1);
|
|
75
|
-
|
|
76
|
-
// 监听标准化提交状态变化,保存到localStorage
|
|
77
|
-
watch(isStandardCommit, (newValue) => {
|
|
78
|
-
localStorage.setItem("zen-gitsync-standard-commit", newValue.toString());
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
// 监听跳过钩子状态变化,保存到localStorage
|
|
82
|
-
watch(skipHooks, (newValue) => {
|
|
83
|
-
localStorage.setItem("zen-gitsync-skip-hooks", newValue.toString());
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
// 计算最终的提交信息
|
|
87
|
-
const finalCommitMessage = computed(() => {
|
|
88
|
-
if (!isStandardCommit.value) {
|
|
89
|
-
// 如果用户没有输入提交信息,则使用默认提交信息
|
|
90
|
-
return commitMessage.value || defaultCommitMessage.value;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// 构建标准化提交信息
|
|
94
|
-
let message = `${commitType.value || ""}`;
|
|
95
|
-
if (commitScope.value) {
|
|
96
|
-
message += `(${commitScope.value})`;
|
|
97
|
-
}
|
|
98
|
-
message += `: ${commitDescription.value}`;
|
|
99
|
-
|
|
100
|
-
if (commitBody.value) {
|
|
101
|
-
message += `\n\n${commitBody.value}`;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (commitFooter.value) {
|
|
105
|
-
message += `\n\n${commitFooter.value}`;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return message;
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
// 计算Git命令预览
|
|
112
|
-
const gitCommandPreview = computed(() => {
|
|
113
|
-
// 基本命令
|
|
114
|
-
let command = `git commit -m "${finalCommitMessage.value}"`
|
|
115
|
-
|
|
116
|
-
// 如果跳过钩子开关打开,添加 --no-verify 参数
|
|
117
|
-
if (skipHooks.value) {
|
|
118
|
-
command += ' --no-verify'
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return command
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
// 加载配置
|
|
125
|
-
async function loadConfig() {
|
|
126
|
-
try {
|
|
127
|
-
const config = await configStore.loadConfig();
|
|
128
|
-
if (config) {
|
|
129
|
-
placeholder.value = `输入提交信息 (默认: ${config.defaultCommitMessage})`;
|
|
130
|
-
// 保存默认提交信息到变量中,以便后续使用
|
|
131
|
-
defaultCommitMessage.value = config.defaultCommitMessage || "";
|
|
132
|
-
|
|
133
|
-
// 加载描述模板
|
|
134
|
-
if (
|
|
135
|
-
config.descriptionTemplates &&
|
|
136
|
-
Array.isArray(config.descriptionTemplates)
|
|
137
|
-
) {
|
|
138
|
-
descriptionTemplates.value = config.descriptionTemplates;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// 加载作用域模板
|
|
142
|
-
if (config.scopeTemplates && Array.isArray(config.scopeTemplates)) {
|
|
143
|
-
scopeTemplates.value = config.scopeTemplates;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// 加载提交信息模板
|
|
147
|
-
if (config.messageTemplates && Array.isArray(config.messageTemplates)) {
|
|
148
|
-
messageTemplates.value = config.messageTemplates;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
} catch (error) {
|
|
152
|
-
console.error("加载配置失败:", error);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// 保存描述模板
|
|
157
|
-
async function saveDescriptionTemplate() {
|
|
158
|
-
if (!newTemplateName.value.trim()) {
|
|
159
|
-
ElMessage({
|
|
160
|
-
message: "请输入模板内容",
|
|
161
|
-
type: "warning",
|
|
162
|
-
});
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
try {
|
|
167
|
-
// 判断是编辑还是新建
|
|
168
|
-
if (isEditingDescription.value) {
|
|
169
|
-
// 编辑现有模板
|
|
170
|
-
await updateDescriptionTemplate();
|
|
171
|
-
} else {
|
|
172
|
-
// 新建模板
|
|
173
|
-
// 检查是否已存在相同模板
|
|
174
|
-
if (descriptionTemplates.value.includes(newTemplateName.value)) {
|
|
175
|
-
ElMessage({
|
|
176
|
-
message: "该模板已存在",
|
|
177
|
-
type: "warning",
|
|
178
|
-
});
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// 使用 configStore 保存模板
|
|
183
|
-
const success = await configStore.saveTemplate(newTemplateName.value, 'description');
|
|
184
|
-
|
|
185
|
-
if (success) {
|
|
186
|
-
// 确保本地数组同步更新
|
|
187
|
-
if (!descriptionTemplates.value.includes(newTemplateName.value)) {
|
|
188
|
-
descriptionTemplates.value.push(newTemplateName.value);
|
|
189
|
-
}
|
|
190
|
-
// 强制更新视图
|
|
191
|
-
descriptionTemplates.value = [...descriptionTemplates.value];
|
|
192
|
-
|
|
193
|
-
// configStore已经显示了成功消息,这里不需要重复操作
|
|
194
|
-
newTemplateName.value = ""; // 清空输入框,但不关闭弹窗
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
} catch (error) {
|
|
198
|
-
ElMessage({
|
|
199
|
-
message: `保存模板失败: ${(error as Error).message}`,
|
|
200
|
-
type: "error",
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// 更新描述模板
|
|
206
|
-
async function updateDescriptionTemplate() {
|
|
207
|
-
if (!newTemplateName.value.trim()) {
|
|
208
|
-
ElMessage({
|
|
209
|
-
message: "请输入模板内容",
|
|
210
|
-
type: "warning",
|
|
211
|
-
});
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
try {
|
|
216
|
-
// 使用 configStore 更新模板
|
|
217
|
-
const success = await configStore.updateTemplate(
|
|
218
|
-
originalDescriptionTemplate.value,
|
|
219
|
-
newTemplateName.value,
|
|
220
|
-
'description'
|
|
221
|
-
);
|
|
222
|
-
|
|
223
|
-
if (success) {
|
|
224
|
-
// 确保本地数组同步更新
|
|
225
|
-
const index = descriptionTemplates.value.indexOf(originalDescriptionTemplate.value);
|
|
226
|
-
if (index !== -1) {
|
|
227
|
-
descriptionTemplates.value[index] = newTemplateName.value;
|
|
228
|
-
}
|
|
229
|
-
// 强制更新视图
|
|
230
|
-
descriptionTemplates.value = [...descriptionTemplates.value];
|
|
231
|
-
|
|
232
|
-
// configStore已经更新了本地数组并显示了成功消息,这里不需要重复操作
|
|
233
|
-
|
|
234
|
-
// 重置编辑状态
|
|
235
|
-
isEditingDescription.value = false;
|
|
236
|
-
originalDescriptionTemplate.value = "";
|
|
237
|
-
editingDescriptionIndex.value = -1;
|
|
238
|
-
newTemplateName.value = "";
|
|
239
|
-
}
|
|
240
|
-
} catch (error) {
|
|
241
|
-
ElMessage({
|
|
242
|
-
message: `更新模板失败: ${(error as Error).message}`,
|
|
243
|
-
type: "error",
|
|
244
|
-
});
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// 开始编辑描述模板
|
|
249
|
-
function startEditDescriptionTemplate(template: string, index: number) {
|
|
250
|
-
isEditingDescription.value = true;
|
|
251
|
-
originalDescriptionTemplate.value = template;
|
|
252
|
-
editingDescriptionIndex.value = index;
|
|
253
|
-
newTemplateName.value = template;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// 取消编辑描述模板
|
|
257
|
-
function cancelEditDescriptionTemplate() {
|
|
258
|
-
isEditingDescription.value = false;
|
|
259
|
-
originalDescriptionTemplate.value = "";
|
|
260
|
-
editingDescriptionIndex.value = -1;
|
|
261
|
-
newTemplateName.value = "";
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// 保存作用域模板
|
|
265
|
-
async function saveScopeTemplate() {
|
|
266
|
-
if (!newScopeTemplate.value.trim()) {
|
|
267
|
-
ElMessage({
|
|
268
|
-
message: "请输入模板内容",
|
|
269
|
-
type: "warning",
|
|
270
|
-
});
|
|
271
|
-
return;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
try {
|
|
275
|
-
// 判断是编辑还是新建
|
|
276
|
-
if (isEditingScope.value) {
|
|
277
|
-
// 编辑现有模板
|
|
278
|
-
await updateScopeTemplate();
|
|
279
|
-
} else {
|
|
280
|
-
// 新建模板
|
|
281
|
-
// 检查是否已存在相同模板
|
|
282
|
-
if (scopeTemplates.value.includes(newScopeTemplate.value)) {
|
|
283
|
-
ElMessage({
|
|
284
|
-
message: "该模板已存在",
|
|
285
|
-
type: "warning",
|
|
286
|
-
});
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
// 使用 configStore 保存模板
|
|
291
|
-
const success = await configStore.saveTemplate(newScopeTemplate.value, 'scope');
|
|
292
|
-
|
|
293
|
-
if (success) {
|
|
294
|
-
// 确保本地数组同步更新
|
|
295
|
-
if (!scopeTemplates.value.includes(newScopeTemplate.value)) {
|
|
296
|
-
scopeTemplates.value.push(newScopeTemplate.value);
|
|
297
|
-
}
|
|
298
|
-
// 强制更新视图
|
|
299
|
-
scopeTemplates.value = [...scopeTemplates.value];
|
|
300
|
-
|
|
301
|
-
// configStore已经显示了成功消息,这里不需要重复操作
|
|
302
|
-
newScopeTemplate.value = ""; // 清空输入框,但不关闭弹窗
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
} catch (error) {
|
|
306
|
-
ElMessage({
|
|
307
|
-
message: `保存模板失败: ${(error as Error).message}`,
|
|
308
|
-
type: "error",
|
|
309
|
-
});
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// 更新作用域模板
|
|
314
|
-
async function updateScopeTemplate() {
|
|
315
|
-
if (!newScopeTemplate.value.trim()) {
|
|
316
|
-
ElMessage({
|
|
317
|
-
message: "请输入模板内容",
|
|
318
|
-
type: "warning",
|
|
319
|
-
});
|
|
320
|
-
return;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
try {
|
|
324
|
-
// 使用 configStore 更新模板
|
|
325
|
-
const success = await configStore.updateTemplate(
|
|
326
|
-
originalScopeTemplate.value,
|
|
327
|
-
newScopeTemplate.value,
|
|
328
|
-
'scope'
|
|
329
|
-
);
|
|
330
|
-
|
|
331
|
-
if (success) {
|
|
332
|
-
// 确保本地数组同步更新
|
|
333
|
-
const index = scopeTemplates.value.indexOf(originalScopeTemplate.value);
|
|
334
|
-
if (index !== -1) {
|
|
335
|
-
scopeTemplates.value[index] = newScopeTemplate.value;
|
|
336
|
-
}
|
|
337
|
-
// 强制更新视图
|
|
338
|
-
scopeTemplates.value = [...scopeTemplates.value];
|
|
339
|
-
|
|
340
|
-
// configStore已经更新了本地数组并显示了成功消息,这里不需要重复操作
|
|
341
|
-
|
|
342
|
-
// 重置编辑状态
|
|
343
|
-
isEditingScope.value = false;
|
|
344
|
-
originalScopeTemplate.value = "";
|
|
345
|
-
editingScopeIndex.value = -1;
|
|
346
|
-
newScopeTemplate.value = "";
|
|
347
|
-
}
|
|
348
|
-
} catch (error) {
|
|
349
|
-
ElMessage({
|
|
350
|
-
message: `更新模板失败: ${(error as Error).message}`,
|
|
351
|
-
type: "error",
|
|
352
|
-
});
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
// 开始编辑作用域模板
|
|
357
|
-
function startEditScopeTemplate(template: string, index: number) {
|
|
358
|
-
isEditingScope.value = true;
|
|
359
|
-
originalScopeTemplate.value = template;
|
|
360
|
-
editingScopeIndex.value = index;
|
|
361
|
-
newScopeTemplate.value = template;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
// 取消编辑作用域模板
|
|
365
|
-
function cancelEditScopeTemplate() {
|
|
366
|
-
isEditingScope.value = false;
|
|
367
|
-
originalScopeTemplate.value = "";
|
|
368
|
-
editingScopeIndex.value = -1;
|
|
369
|
-
newScopeTemplate.value = "";
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// 删除描述模板
|
|
373
|
-
async function deleteDescriptionTemplate(template: string) {
|
|
374
|
-
try {
|
|
375
|
-
// 确认删除
|
|
376
|
-
await ElMessageBox.confirm(
|
|
377
|
-
`确定要删除描述模板 "${template}" 吗?`,
|
|
378
|
-
"删除确认",
|
|
379
|
-
{
|
|
380
|
-
confirmButtonText: "确定",
|
|
381
|
-
cancelButtonText: "取消",
|
|
382
|
-
type: "warning",
|
|
383
|
-
}
|
|
384
|
-
);
|
|
385
|
-
|
|
386
|
-
// 使用 configStore 删除模板
|
|
387
|
-
const success = await configStore.deleteTemplate(template, 'description');
|
|
388
|
-
|
|
389
|
-
if (success) {
|
|
390
|
-
// 确保本地数组同步更新
|
|
391
|
-
const index = descriptionTemplates.value.indexOf(template);
|
|
392
|
-
if (index !== -1) {
|
|
393
|
-
descriptionTemplates.value.splice(index, 1);
|
|
394
|
-
}
|
|
395
|
-
// 强制更新视图
|
|
396
|
-
descriptionTemplates.value = [...descriptionTemplates.value];
|
|
397
|
-
}
|
|
398
|
-
} catch (error) {
|
|
399
|
-
if (error === "cancel") {
|
|
400
|
-
// 用户取消删除,不做任何操作
|
|
401
|
-
return;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
ElMessage({
|
|
405
|
-
message: `删除模板失败: ${(error as Error).message}`,
|
|
406
|
-
type: "error",
|
|
407
|
-
});
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
// 删除作用域模板
|
|
412
|
-
async function deleteScopeTemplate(template: string) {
|
|
413
|
-
try {
|
|
414
|
-
// 确认删除
|
|
415
|
-
await ElMessageBox.confirm(
|
|
416
|
-
`确定要删除作用域模板 "${template}" 吗?`,
|
|
417
|
-
"删除确认",
|
|
418
|
-
{
|
|
419
|
-
confirmButtonText: "确定",
|
|
420
|
-
cancelButtonText: "取消",
|
|
421
|
-
type: "warning",
|
|
422
|
-
}
|
|
423
|
-
);
|
|
424
|
-
|
|
425
|
-
// 使用 configStore 删除模板
|
|
426
|
-
const success = await configStore.deleteTemplate(template, 'scope');
|
|
427
|
-
|
|
428
|
-
if (success) {
|
|
429
|
-
// 确保本地数组同步更新
|
|
430
|
-
const index = scopeTemplates.value.indexOf(template);
|
|
431
|
-
if (index !== -1) {
|
|
432
|
-
scopeTemplates.value.splice(index, 1);
|
|
433
|
-
}
|
|
434
|
-
// 强制更新视图
|
|
435
|
-
scopeTemplates.value = [...scopeTemplates.value];
|
|
436
|
-
}
|
|
437
|
-
} catch (error) {
|
|
438
|
-
if (error === "cancel") {
|
|
439
|
-
// 用户取消删除,不做任何操作
|
|
440
|
-
return;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
ElMessage({
|
|
444
|
-
message: `删除模板失败: ${(error as Error).message}`,
|
|
445
|
-
type: "error",
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
// 使用模板
|
|
451
|
-
function useTemplate(template: string) {
|
|
452
|
-
commitDescription.value = template;
|
|
453
|
-
descriptionDialogVisible.value = false;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
// 使用作用域模板
|
|
457
|
-
function useScopeTemplate(template: string) {
|
|
458
|
-
commitScope.value = template;
|
|
459
|
-
scopeDialogVisible.value = false;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
// 打开设置弹窗
|
|
463
|
-
function openDescriptionSettings() {
|
|
464
|
-
descriptionDialogVisible.value = true;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
// 打开作用域设置弹窗
|
|
468
|
-
function openScopeSettings() {
|
|
469
|
-
scopeDialogVisible.value = true;
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
// 添加文件到暂存区 (git add)
|
|
473
|
-
async function addToStage() {
|
|
474
|
-
try {
|
|
475
|
-
const result = await gitLogStore.addToStage();
|
|
476
|
-
if (result) {
|
|
477
|
-
// 触发状态更新事件
|
|
478
|
-
gitLogStore.fetchStatus();
|
|
479
|
-
}
|
|
480
|
-
} catch (error) {
|
|
481
|
-
ElMessage({
|
|
482
|
-
message: `添加文件失败: ${(error as Error).message}`,
|
|
483
|
-
type: "error",
|
|
484
|
-
});
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
// 提交更改 (git commit)
|
|
489
|
-
async function commitChanges() {
|
|
490
|
-
if (!finalCommitMessage.value.trim()) {
|
|
491
|
-
ElMessage({
|
|
492
|
-
message: "提交信息不能为空",
|
|
493
|
-
type: "warning",
|
|
494
|
-
});
|
|
495
|
-
return;
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
try {
|
|
499
|
-
// 使用Store提交更改
|
|
500
|
-
const result = await gitLogStore.commitChanges(finalCommitMessage.value, skipHooks.value);
|
|
501
|
-
|
|
502
|
-
if (result) {
|
|
503
|
-
// 清空提交信息
|
|
504
|
-
clearCommitFields();
|
|
505
|
-
|
|
506
|
-
// 触发成功事件
|
|
507
|
-
gitLogStore.fetchStatus();
|
|
508
|
-
gitLogStore.fetchLog();
|
|
509
|
-
|
|
510
|
-
// 手动更新分支状态
|
|
511
|
-
gitStore.getBranchStatus();
|
|
512
|
-
}
|
|
513
|
-
} catch (error) {
|
|
514
|
-
ElMessage({
|
|
515
|
-
message: `提交失败: ${(error as Error).message}`,
|
|
516
|
-
type: "error",
|
|
517
|
-
});
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
// 显示推送成功提示
|
|
522
|
-
function showPushSuccessIndicator() {
|
|
523
|
-
showPushSuccess.value = true;
|
|
524
|
-
setTimeout(() => {
|
|
525
|
-
showPushSuccess.value = false;
|
|
526
|
-
}, 2000);
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
// 推送到远程 (git push)
|
|
530
|
-
async function pushToRemote() {
|
|
531
|
-
isPushing.value = true;
|
|
532
|
-
try {
|
|
533
|
-
await gitLogStore.pushToRemote();
|
|
534
|
-
// 显示推送成功提示
|
|
535
|
-
showPushSuccessIndicator();
|
|
536
|
-
|
|
537
|
-
// 手动更新分支状态
|
|
538
|
-
gitStore.getBranchStatus();
|
|
539
|
-
} catch (error) {
|
|
540
|
-
ElMessage({
|
|
541
|
-
message: `推送失败: ${(error as Error).message}`,
|
|
542
|
-
type: 'error',
|
|
543
|
-
});
|
|
544
|
-
} finally {
|
|
545
|
-
isPushing.value = false;
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
// 处理git pull操作
|
|
550
|
-
async function handleGitPull() {
|
|
551
|
-
isGitPulling.value = true;
|
|
552
|
-
try {
|
|
553
|
-
await gitStore.gitPull();
|
|
554
|
-
// 刷新状态
|
|
555
|
-
await gitLogStore.fetchStatus();
|
|
556
|
-
} catch (error) {
|
|
557
|
-
ElMessage({
|
|
558
|
-
message: `拉取失败: ${(error as Error).message}`,
|
|
559
|
-
type: 'error',
|
|
560
|
-
});
|
|
561
|
-
} finally {
|
|
562
|
-
isGitPulling.value = false;
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
// 处理git fetch --all操作
|
|
567
|
-
async function handleGitFetchAll() {
|
|
568
|
-
isGitFetching.value = true;
|
|
569
|
-
try {
|
|
570
|
-
await gitStore.gitFetchAll();
|
|
571
|
-
// 刷新状态
|
|
572
|
-
await gitLogStore.fetchStatus();
|
|
573
|
-
} catch (error) {
|
|
574
|
-
ElMessage({
|
|
575
|
-
message: `获取远程分支信息失败: ${(error as Error).message}`,
|
|
576
|
-
type: 'error',
|
|
577
|
-
});
|
|
578
|
-
} finally {
|
|
579
|
-
isGitFetching.value = false;
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
// 添加并提交 (git add + git commit)
|
|
584
|
-
async function addAndCommit() {
|
|
585
|
-
if (!finalCommitMessage.value.trim()) {
|
|
586
|
-
ElMessage({
|
|
587
|
-
message: "提交信息不能为空",
|
|
588
|
-
type: "warning",
|
|
589
|
-
});
|
|
590
|
-
return;
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
try {
|
|
594
|
-
await gitLogStore.addAndCommit(finalCommitMessage.value, skipHooks.value);
|
|
595
|
-
|
|
596
|
-
// 清空提交信息
|
|
597
|
-
clearCommitFields();
|
|
598
|
-
|
|
599
|
-
// 触发成功事件
|
|
600
|
-
gitLogStore.fetchStatus();
|
|
601
|
-
gitLogStore.fetchLog();
|
|
602
|
-
} catch (error) {
|
|
603
|
-
ElMessage({
|
|
604
|
-
message: `暂存并提交失败: ${(error as Error).message}`,
|
|
605
|
-
type: "error",
|
|
606
|
-
});
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
// 添加、提交并推送 (git add + git commit + git push)
|
|
611
|
-
async function addCommitAndPush() {
|
|
612
|
-
if (!finalCommitMessage.value.trim()) {
|
|
613
|
-
ElMessage({
|
|
614
|
-
message: "提交信息不能为空",
|
|
615
|
-
type: "warning",
|
|
616
|
-
});
|
|
617
|
-
return;
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
try {
|
|
621
|
-
isPushing.value = true
|
|
622
|
-
await gitLogStore.addCommitAndPush(finalCommitMessage.value, skipHooks.value);
|
|
623
|
-
|
|
624
|
-
// 清空提交信息
|
|
625
|
-
clearCommitFields();
|
|
626
|
-
|
|
627
|
-
// 显示成功动画
|
|
628
|
-
isPushing.value = false
|
|
629
|
-
showPushSuccessIndicator();
|
|
630
|
-
|
|
631
|
-
} catch (error) {
|
|
632
|
-
ElMessage({
|
|
633
|
-
message: `暂存、提交并推送失败: ${(error as Error).message}`,
|
|
634
|
-
type: "error",
|
|
635
|
-
});
|
|
636
|
-
isPushing.value = false
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
// 重置到远程分支 (git reset --hard origin/branch)
|
|
641
|
-
async function resetToRemote() {
|
|
642
|
-
try {
|
|
643
|
-
await ElMessageBox.confirm(
|
|
644
|
-
`确定要重置当前分支 "${gitStore.currentBranch}" 到远程状态吗?这将丢失所有未推送的提交和本地更改。`,
|
|
645
|
-
'重置到远程分支',
|
|
646
|
-
{
|
|
647
|
-
confirmButtonText: '确定',
|
|
648
|
-
cancelButtonText: '取消',
|
|
649
|
-
type: 'warning'
|
|
650
|
-
}
|
|
651
|
-
);
|
|
652
|
-
|
|
653
|
-
const result = await gitLogStore.resetToRemote(gitStore.currentBranch);
|
|
654
|
-
if (result) {
|
|
655
|
-
// 触发状态更新事件
|
|
656
|
-
gitLogStore.fetchStatus();
|
|
657
|
-
// 更新提交历史
|
|
658
|
-
gitLogStore.fetchLog();
|
|
659
|
-
}
|
|
660
|
-
} catch (error) {
|
|
661
|
-
// 用户取消操作,不显示错误
|
|
662
|
-
if ((error as any) !== 'cancel') {
|
|
663
|
-
ElMessage({
|
|
664
|
-
message: `重置到远程分支失败: ${(error as Error).message}`,
|
|
665
|
-
type: 'error'
|
|
666
|
-
});
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
// 清空提交字段
|
|
672
|
-
function clearCommitFields() {
|
|
673
|
-
commitMessage.value = "";
|
|
674
|
-
commitDescription.value = "";
|
|
675
|
-
commitBody.value = "";
|
|
676
|
-
commitFooter.value = "";
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
// 打开默认提交信息设置弹窗
|
|
680
|
-
function openDefaultMessageSettings() {
|
|
681
|
-
newDefaultMessage.value = defaultCommitMessage.value;
|
|
682
|
-
defaultMessageDialogVisible.value = true;
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
// 保存默认提交信息
|
|
686
|
-
async function saveDefaultMessage() {
|
|
687
|
-
if (!newDefaultMessage.value.trim()) {
|
|
688
|
-
ElMessage({
|
|
689
|
-
message: "请输入默认提交信息",
|
|
690
|
-
type: "warning",
|
|
691
|
-
});
|
|
692
|
-
return;
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
try {
|
|
696
|
-
// 使用 configStore 保存默认提交信息
|
|
697
|
-
const success = await configStore.saveDefaultMessage(newDefaultMessage.value);
|
|
698
|
-
|
|
699
|
-
if (success) {
|
|
700
|
-
// 更新本地默认提交信息
|
|
701
|
-
defaultCommitMessage.value = newDefaultMessage.value;
|
|
702
|
-
placeholder.value = `输入提交信息 (默认: ${newDefaultMessage.value})`;
|
|
703
|
-
|
|
704
|
-
// configStore 已经显示了成功消息,这里不需要重复显示
|
|
705
|
-
// ElMessage({
|
|
706
|
-
// message: "默认提交信息已保存",
|
|
707
|
-
// type: "success",
|
|
708
|
-
// });
|
|
709
|
-
|
|
710
|
-
// 关闭对话框
|
|
711
|
-
defaultMessageDialogVisible.value = false;
|
|
712
|
-
}
|
|
713
|
-
} catch (error) {
|
|
714
|
-
ElMessage({
|
|
715
|
-
message: `保存默认提交信息失败: ${(error as Error).message}`,
|
|
716
|
-
type: "error",
|
|
717
|
-
});
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
// 根据Git状态计算按钮禁用状态
|
|
722
|
-
const hasUnstagedChanges = computed(() => {
|
|
723
|
-
return gitLogStore.fileList.some(file => ['modified', 'deleted', 'untracked'].includes(file.type));
|
|
724
|
-
});
|
|
725
|
-
|
|
726
|
-
// 计算未暂存文件数量
|
|
727
|
-
const unstagedFilesCount = computed(() => {
|
|
728
|
-
return gitLogStore.fileList.filter(file => ['modified', 'deleted', 'untracked'].includes(file.type)).length;
|
|
729
|
-
});
|
|
730
|
-
|
|
731
|
-
// 计算已暂存文件数量
|
|
732
|
-
const stagedFilesCount = computed(() => {
|
|
733
|
-
return gitLogStore.fileList.filter(file => file.type === 'added').length;
|
|
734
|
-
});
|
|
735
|
-
|
|
736
|
-
const hasStagedChanges = computed(() => {
|
|
737
|
-
return stagedFilesCount.value > 0;
|
|
738
|
-
});
|
|
739
|
-
|
|
740
|
-
const hasAnyChanges = computed(() => {
|
|
741
|
-
return gitLogStore.fileList.length > 0;
|
|
742
|
-
});
|
|
743
|
-
|
|
744
|
-
const needsPush = computed(() => {
|
|
745
|
-
return gitStore.branchAhead > 0;
|
|
746
|
-
});
|
|
747
|
-
|
|
748
|
-
const needsPull = computed(() => {
|
|
749
|
-
return gitStore.branchBehind > 0;
|
|
750
|
-
});
|
|
751
|
-
|
|
752
|
-
const canPush = computed(() => {
|
|
753
|
-
// 修改条件判断:
|
|
754
|
-
// 1. 如果分支有上游并且领先提交,可以推送
|
|
755
|
-
// 2. 如果有已暂存的更改但未提交,不能推送
|
|
756
|
-
// 3. 如果有已提交未推送的更改,可以推送
|
|
757
|
-
return gitStore.hasUpstream && (needsPush.value || (hasStagedChanges.value && finalCommitMessage.value.trim()));
|
|
758
|
-
});
|
|
759
|
-
|
|
760
|
-
const canReset = computed(() => {
|
|
761
|
-
return hasStagedChanges.value;
|
|
762
|
-
});
|
|
763
|
-
|
|
764
|
-
const canResetToRemote = computed(() => {
|
|
765
|
-
return gitStore.hasUpstream && (needsPush.value || needsPull.value || hasAnyChanges.value);
|
|
766
|
-
});
|
|
767
|
-
|
|
768
|
-
// 保存默认提交信息模板
|
|
769
|
-
async function saveMessageTemplate() {
|
|
770
|
-
if (!newDefaultMessage.value.trim()) {
|
|
771
|
-
ElMessage({
|
|
772
|
-
message: "请输入模板内容",
|
|
773
|
-
type: "warning",
|
|
774
|
-
});
|
|
775
|
-
return;
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
try {
|
|
779
|
-
// 判断是编辑还是新建
|
|
780
|
-
if (isEditingMessage.value) {
|
|
781
|
-
// 编辑现有模板
|
|
782
|
-
await updateMessageTemplate();
|
|
783
|
-
} else {
|
|
784
|
-
// 新建模板
|
|
785
|
-
// 检查是否已存在相同模板
|
|
786
|
-
if (messageTemplates.value.includes(newDefaultMessage.value)) {
|
|
787
|
-
ElMessage({
|
|
788
|
-
message: "该模板已存在",
|
|
789
|
-
type: "warning",
|
|
790
|
-
});
|
|
791
|
-
return;
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
// 添加到本地数组
|
|
795
|
-
messageTemplates.value.push(newDefaultMessage.value);
|
|
796
|
-
|
|
797
|
-
// 保存到服务器
|
|
798
|
-
const response = await fetch("/api/config/save-template", {
|
|
799
|
-
method: "POST",
|
|
800
|
-
headers: {
|
|
801
|
-
"Content-Type": "application/json",
|
|
802
|
-
},
|
|
803
|
-
body: JSON.stringify({
|
|
804
|
-
template: newDefaultMessage.value,
|
|
805
|
-
type: "message",
|
|
806
|
-
}),
|
|
807
|
-
});
|
|
808
|
-
|
|
809
|
-
const result = await response.json();
|
|
810
|
-
if (result.success) {
|
|
811
|
-
ElMessage({
|
|
812
|
-
message: "提交信息模板保存成功!",
|
|
813
|
-
type: "success",
|
|
814
|
-
});
|
|
815
|
-
newDefaultMessage.value = "";
|
|
816
|
-
} else {
|
|
817
|
-
ElMessage({
|
|
818
|
-
message: "模板保存失败: " + result.error,
|
|
819
|
-
type: "error",
|
|
820
|
-
});
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
} catch (error) {
|
|
824
|
-
ElMessage({
|
|
825
|
-
message: "模板保存失败: " + (error as Error).message,
|
|
826
|
-
type: "error",
|
|
827
|
-
});
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
|
|
831
|
-
// 更新提交信息模板
|
|
832
|
-
async function updateMessageTemplate() {
|
|
833
|
-
try {
|
|
834
|
-
// 先从本地数组中更新
|
|
835
|
-
if (editingMessageIndex.value >= 0) {
|
|
836
|
-
// 保存原模板和新模板
|
|
837
|
-
const oldTemplate = originalMessageTemplate.value;
|
|
838
|
-
const newTemplate = newDefaultMessage.value;
|
|
839
|
-
|
|
840
|
-
// 更新本地数组
|
|
841
|
-
messageTemplates.value[editingMessageIndex.value] = newTemplate;
|
|
842
|
-
|
|
843
|
-
// 调用API更新服务器
|
|
844
|
-
const response = await fetch("/api/config/update-template", {
|
|
845
|
-
method: "POST",
|
|
846
|
-
headers: {
|
|
847
|
-
"Content-Type": "application/json",
|
|
848
|
-
},
|
|
849
|
-
body: JSON.stringify({
|
|
850
|
-
oldTemplate,
|
|
851
|
-
newTemplate,
|
|
852
|
-
type: "message",
|
|
853
|
-
}),
|
|
854
|
-
});
|
|
855
|
-
|
|
856
|
-
const result = await response.json();
|
|
857
|
-
if (result.success) {
|
|
858
|
-
ElMessage({
|
|
859
|
-
message: "提交信息模板更新成功!",
|
|
860
|
-
type: "success",
|
|
861
|
-
});
|
|
862
|
-
|
|
863
|
-
// 重置编辑状态
|
|
864
|
-
isEditingMessage.value = false;
|
|
865
|
-
originalMessageTemplate.value = "";
|
|
866
|
-
editingMessageIndex.value = -1;
|
|
867
|
-
newDefaultMessage.value = "";
|
|
868
|
-
} else {
|
|
869
|
-
ElMessage({
|
|
870
|
-
message: "模板更新失败: " + result.error,
|
|
871
|
-
type: "error",
|
|
872
|
-
});
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
} catch (error) {
|
|
876
|
-
ElMessage({
|
|
877
|
-
message: "模板更新失败: " + (error as Error).message,
|
|
878
|
-
type: "error",
|
|
879
|
-
});
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
// 开始编辑提交信息模板
|
|
884
|
-
function startEditMessageTemplate(template: string, index: number) {
|
|
885
|
-
isEditingMessage.value = true;
|
|
886
|
-
originalMessageTemplate.value = template;
|
|
887
|
-
editingMessageIndex.value = index;
|
|
888
|
-
newDefaultMessage.value = template;
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
// 取消编辑提交信息模板
|
|
892
|
-
function cancelEditMessageTemplate() {
|
|
893
|
-
isEditingMessage.value = false;
|
|
894
|
-
originalMessageTemplate.value = "";
|
|
895
|
-
editingMessageIndex.value = -1;
|
|
896
|
-
newDefaultMessage.value = "";
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
// 删除提交信息模板
|
|
900
|
-
async function deleteMessageTemplate(template: string) {
|
|
901
|
-
try {
|
|
902
|
-
// 从本地数组中删除
|
|
903
|
-
const index = messageTemplates.value.indexOf(template);
|
|
904
|
-
if (index !== -1) {
|
|
905
|
-
messageTemplates.value.splice(index, 1);
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
// 从服务器删除
|
|
909
|
-
const response = await fetch("/api/config/delete-template", {
|
|
910
|
-
method: "POST",
|
|
911
|
-
headers: {
|
|
912
|
-
"Content-Type": "application/json",
|
|
913
|
-
},
|
|
914
|
-
body: JSON.stringify({
|
|
915
|
-
template,
|
|
916
|
-
type: "message",
|
|
917
|
-
}),
|
|
918
|
-
});
|
|
919
|
-
|
|
920
|
-
const result = await response.json();
|
|
921
|
-
if (result.success) {
|
|
922
|
-
ElMessage({
|
|
923
|
-
message: "提交信息模板删除成功!",
|
|
924
|
-
type: "success",
|
|
925
|
-
});
|
|
926
|
-
} else {
|
|
927
|
-
ElMessage({
|
|
928
|
-
message: "模板删除失败: " + result.error,
|
|
929
|
-
type: "error",
|
|
930
|
-
});
|
|
931
|
-
}
|
|
932
|
-
} catch (error) {
|
|
933
|
-
ElMessage({
|
|
934
|
-
message: "模板删除失败: " + (error as Error).message,
|
|
935
|
-
type: "error",
|
|
936
|
-
});
|
|
937
|
-
}
|
|
938
|
-
}
|
|
939
|
-
|
|
940
|
-
// 使用默认提交信息模板
|
|
941
|
-
function useMessageTemplate(template: string) {
|
|
942
|
-
// 设置为当前提交信息
|
|
943
|
-
commitMessage.value = template;
|
|
944
|
-
// 设置为默认提交信息编辑框的内容
|
|
945
|
-
newDefaultMessage.value = template;
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
onMounted(() => {
|
|
949
|
-
loadConfig();
|
|
950
|
-
|
|
951
|
-
// 从 localStorage 中获取标准化提交设置
|
|
952
|
-
const savedStandardCommit = localStorage.getItem("zen-gitsync-standard-commit");
|
|
953
|
-
if (savedStandardCommit !== null) {
|
|
954
|
-
isStandardCommit.value = savedStandardCommit === "true";
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
// 从 localStorage 中获取跳过钩子设置
|
|
958
|
-
const savedSkipHooks = localStorage.getItem("zen-gitsync-skip-hooks");
|
|
959
|
-
if (savedSkipHooks !== null) {
|
|
960
|
-
skipHooks.value = savedSkipHooks === "true";
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
});
|
|
964
|
-
</script>
|
|
965
|
-
|
|
966
|
-
<template>
|
|
967
|
-
<div class="card" :class="{ 'is-pushing': gitLogStore.isPushing || isPushing }">
|
|
968
|
-
<div class="card-header">
|
|
969
|
-
<h2>提交更改</h2>
|
|
970
|
-
</div>
|
|
971
|
-
|
|
972
|
-
<!-- 添加推送中指示器 -->
|
|
973
|
-
<transition name="el-fade-in-linear">
|
|
974
|
-
<div v-if="isPushing" class="pushing-indicator">
|
|
975
|
-
<div class="pushing-spinner">
|
|
976
|
-
<svg viewBox="0 0 50 50" class="circular">
|
|
977
|
-
<circle class="path" cx="25" cy="25" r="20" fill="none" />
|
|
978
|
-
</svg>
|
|
979
|
-
</div>
|
|
980
|
-
<div class="pushing-text">正在推送...</div>
|
|
981
|
-
</div>
|
|
982
|
-
</transition>
|
|
983
|
-
|
|
984
|
-
<!-- 添加推送成功指示器 -->
|
|
985
|
-
<transition name="el-fade-in-linear">
|
|
986
|
-
<div v-if="showPushSuccess" class="push-success-indicator">
|
|
987
|
-
<el-icon class="push-success-icon"><Check /></el-icon>
|
|
988
|
-
<div class="push-success-text">推送成功!</div>
|
|
989
|
-
</div>
|
|
990
|
-
</transition>
|
|
991
|
-
|
|
992
|
-
<div class="card-content">
|
|
993
|
-
<div class="layout-container">
|
|
994
|
-
<!-- 如果没有配置Git用户信息,显示提示 -->
|
|
995
|
-
<div v-if="gitStore.userName === '' || gitStore.userEmail === ''" class="git-config-warning">
|
|
996
|
-
<el-alert
|
|
997
|
-
title="Git用户信息未配置"
|
|
998
|
-
type="warning"
|
|
999
|
-
:closable="false"
|
|
1000
|
-
show-icon
|
|
1001
|
-
>
|
|
1002
|
-
<p>您需要配置Git用户名和邮箱才能提交代码。请使用以下命令配置:</p>
|
|
1003
|
-
<pre class="config-command">git config --global user.name "Your Name"
|
|
1004
|
-
git config --global user.email "your.email@example.com"</pre>
|
|
1005
|
-
</el-alert>
|
|
1006
|
-
</div>
|
|
1007
|
-
|
|
1008
|
-
<!-- 正常的提交区域,仅在Git用户信息已配置时显示 -->
|
|
1009
|
-
<template v-else>
|
|
1010
|
-
<!-- 左侧:提交表单 -->
|
|
1011
|
-
<div class="commit-section">
|
|
1012
|
-
<div class="commit-options">
|
|
1013
|
-
<div class="options-row">
|
|
1014
|
-
<div class="commit-mode-toggle">
|
|
1015
|
-
<el-switch v-model="isStandardCommit" active-text="标准化提交" inactive-text="普通提交" />
|
|
1016
|
-
</div>
|
|
1017
|
-
|
|
1018
|
-
<div class="no-verify-toggle">
|
|
1019
|
-
<el-tooltip content="跳过 Git 钩子检查 (--no-verify)" placement="top">
|
|
1020
|
-
<el-switch v-model="skipHooks" active-text="跳过钩子 (--no-verify)" />
|
|
1021
|
-
</el-tooltip>
|
|
1022
|
-
</div>
|
|
1023
|
-
</div>
|
|
1024
|
-
</div>
|
|
1025
|
-
|
|
1026
|
-
<!-- 普通提交表单 -->
|
|
1027
|
-
<div v-if="!isStandardCommit" class="commit-form">
|
|
1028
|
-
<div class="description-container">
|
|
1029
|
-
<el-input
|
|
1030
|
-
v-model="commitMessage"
|
|
1031
|
-
:placeholder="placeholder"
|
|
1032
|
-
type="textarea"
|
|
1033
|
-
:rows="6"
|
|
1034
|
-
resize="none"
|
|
1035
|
-
class="commit-message-input"
|
|
1036
|
-
/>
|
|
1037
|
-
<div class="input-actions">
|
|
1038
|
-
<el-button type="primary" :icon="Setting" circle size="small" class="settings-button"
|
|
1039
|
-
@click="openDefaultMessageSettings">
|
|
1040
|
-
</el-button>
|
|
1041
|
-
</div>
|
|
1042
|
-
</div>
|
|
1043
|
-
|
|
1044
|
-
<!-- 添加Git命令预览区域 -->
|
|
1045
|
-
<div class="preview-section">
|
|
1046
|
-
<div class="preview-title">Git提交命令预览:</div>
|
|
1047
|
-
<pre class="preview-content code-command">git commit -m "{{ finalCommitMessage || '<提交信息>' }}"{{ skipHooks ? ' --no-verify' : '' }}</pre>
|
|
1048
|
-
</div>
|
|
1049
|
-
</div>
|
|
1050
|
-
|
|
1051
|
-
<!-- 标准化提交表单 -->
|
|
1052
|
-
<div v-else class="standard-commit-form">
|
|
1053
|
-
<div class="standard-commit-header">
|
|
1054
|
-
<div class="type-scope-container">
|
|
1055
|
-
<el-select v-model="commitType" placeholder="提交类型" class="type-select" clearable>
|
|
1056
|
-
<el-option v-for="item in commitTypeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
|
1057
|
-
</el-select>
|
|
1058
|
-
|
|
1059
|
-
<div class="scope-wrapper">
|
|
1060
|
-
<el-input v-model="commitScope" placeholder="作用域(可选)" class="scope-input" clearable />
|
|
1061
|
-
<el-button type="primary" :icon="Setting" circle size="small" class="settings-button"
|
|
1062
|
-
@click="openScopeSettings">
|
|
1063
|
-
</el-button>
|
|
1064
|
-
</div>
|
|
1065
|
-
</div>
|
|
1066
|
-
|
|
1067
|
-
<div class="description-container">
|
|
1068
|
-
<el-input v-model="commitDescription" placeholder="简短描述(必填)" class="description-input" clearable />
|
|
1069
|
-
<el-button type="primary" :icon="Setting" circle size="small" class="settings-button"
|
|
1070
|
-
@click="openDescriptionSettings">
|
|
1071
|
-
</el-button>
|
|
1072
|
-
</div>
|
|
1073
|
-
</div>
|
|
1074
|
-
|
|
1075
|
-
<!-- 添加展开/收起高级选项的控制按钮 -->
|
|
1076
|
-
<div class="advanced-options-toggle" @click="showAdvancedFields = !showAdvancedFields">
|
|
1077
|
-
<span>{{ showAdvancedFields ? '收起' : '正文及页脚' }}</span>
|
|
1078
|
-
<el-icon class="toggle-icon" :class="{ 'is-active': showAdvancedFields }">
|
|
1079
|
-
<arrow-down />
|
|
1080
|
-
</el-icon>
|
|
1081
|
-
</div>
|
|
1082
|
-
|
|
1083
|
-
<!-- 使用过渡效果包装高级字段 -->
|
|
1084
|
-
<div v-show="showAdvancedFields" class="advanced-fields">
|
|
1085
|
-
<el-input v-model="commitBody" type="textarea" :rows="4" placeholder="正文(可选):详细描述本次提交的内容和原因" class="body-input"
|
|
1086
|
-
clearable />
|
|
1087
|
-
|
|
1088
|
-
<el-input v-model="commitFooter" placeholder="页脚(可选):如 Closes #123" class="footer-input" clearable />
|
|
1089
|
-
</div>
|
|
1090
|
-
|
|
1091
|
-
<div class="preview-section">
|
|
1092
|
-
<div class="preview-title">提交信息预览:</div>
|
|
1093
|
-
<pre class="preview-content">{{ finalCommitMessage }}</pre>
|
|
1094
|
-
|
|
1095
|
-
<div class="preview-title" style="margin-top: 10px;">Git提交命令预览:</div>
|
|
1096
|
-
<pre class="preview-content code-command">{{ gitCommandPreview }}</pre>
|
|
1097
|
-
</div>
|
|
1098
|
-
</div>
|
|
1099
|
-
</div>
|
|
1100
|
-
|
|
1101
|
-
<!-- 右侧:操作区域 -->
|
|
1102
|
-
<div class="actions-section">
|
|
1103
|
-
<h3>Git 操作</h3>
|
|
1104
|
-
<div class="action-groups">
|
|
1105
|
-
<div class="operations-wrapper">
|
|
1106
|
-
<!-- 基础操作 -->
|
|
1107
|
-
<div class="action-group">
|
|
1108
|
-
<div class="group-title">基础操作</div>
|
|
1109
|
-
<div class="group-buttons">
|
|
1110
|
-
<el-tooltip :content="hasUnstagedChanges ? `暂存${unstagedFilesCount}个待更改文件` : 'git add .'" placement="top" effect="light" popper-class="git-cmd-tooltip">
|
|
1111
|
-
<el-button
|
|
1112
|
-
type="primary"
|
|
1113
|
-
@click="addToStage"
|
|
1114
|
-
:loading="gitLogStore.isAddingFiles"
|
|
1115
|
-
:disabled="!hasUnstagedChanges"
|
|
1116
|
-
class="action-button"
|
|
1117
|
-
>
|
|
1118
|
-
暂存更改
|
|
1119
|
-
<span v-if="unstagedFilesCount > 0">({{unstagedFilesCount}})</span>
|
|
1120
|
-
</el-button>
|
|
1121
|
-
</el-tooltip>
|
|
1122
|
-
|
|
1123
|
-
<el-tooltip :content="hasStagedChanges ? `提交${stagedFilesCount}个已暂存文件` : 'git commit'" placement="top" effect="light" popper-class="git-cmd-tooltip">
|
|
1124
|
-
<el-button
|
|
1125
|
-
type="primary"
|
|
1126
|
-
@click="commitChanges"
|
|
1127
|
-
:loading="gitLogStore.isLoadingStatus"
|
|
1128
|
-
:disabled="!hasStagedChanges || !finalCommitMessage.trim()"
|
|
1129
|
-
class="action-button"
|
|
1130
|
-
>
|
|
1131
|
-
提交
|
|
1132
|
-
<span v-if="stagedFilesCount > 0">({{stagedFilesCount}})</span>
|
|
1133
|
-
</el-button>
|
|
1134
|
-
</el-tooltip>
|
|
1135
|
-
|
|
1136
|
-
<el-tooltip :content="needsPush ? `推送${gitStore.branchAhead}个本地提交` : 'git push'" placement="top" effect="light" popper-class="git-cmd-tooltip">
|
|
1137
|
-
<el-button
|
|
1138
|
-
type="primary"
|
|
1139
|
-
:icon="Upload"
|
|
1140
|
-
@click="pushToRemote"
|
|
1141
|
-
:loading="gitLogStore.isPushing"
|
|
1142
|
-
:disabled="!canPush"
|
|
1143
|
-
:class="['action-button', 'push-button', { 'is-loading': gitLogStore.isPushing || isPushing }]"
|
|
1144
|
-
:style="needsPush ? {backgroundColor: '#67c23a !important', borderColor: '#67c23a !important'} : {}"
|
|
1145
|
-
>
|
|
1146
|
-
推送
|
|
1147
|
-
<span v-if="needsPush">({{gitStore.branchAhead}})</span>
|
|
1148
|
-
</el-button>
|
|
1149
|
-
</el-tooltip>
|
|
1150
|
-
|
|
1151
|
-
<el-tooltip :content="needsPull ? `拉取${gitStore.branchBehind}个远程提交` : 'git pull'" placement="top" effect="light" popper-class="git-cmd-tooltip">
|
|
1152
|
-
<el-button
|
|
1153
|
-
type="primary"
|
|
1154
|
-
:icon="Download"
|
|
1155
|
-
@click="handleGitPull"
|
|
1156
|
-
:loading="isGitPulling"
|
|
1157
|
-
:disabled="!gitStore.hasUpstream"
|
|
1158
|
-
class="action-button"
|
|
1159
|
-
:style="needsPull ? {color: 'white', backgroundColor: '#E6A23C', borderColor: '#E6A23C'} : {}"
|
|
1160
|
-
>
|
|
1161
|
-
拉取
|
|
1162
|
-
<span v-if="needsPull">({{gitStore.branchBehind}})</span>
|
|
1163
|
-
</el-button>
|
|
1164
|
-
</el-tooltip>
|
|
1165
|
-
|
|
1166
|
-
<el-tooltip content="git fetch --all" placement="top" effect="light" popper-class="git-cmd-tooltip">
|
|
1167
|
-
<el-button
|
|
1168
|
-
type="info"
|
|
1169
|
-
:icon="Connection"
|
|
1170
|
-
@click="handleGitFetchAll"
|
|
1171
|
-
:loading="isGitFetching"
|
|
1172
|
-
class="action-button"
|
|
1173
|
-
>
|
|
1174
|
-
获取所有远程分支
|
|
1175
|
-
</el-button>
|
|
1176
|
-
</el-tooltip>
|
|
1177
|
-
</div>
|
|
1178
|
-
</div>
|
|
1179
|
-
|
|
1180
|
-
<!-- 组合操作 -->
|
|
1181
|
-
<div class="action-group">
|
|
1182
|
-
<div class="group-title">组合操作</div>
|
|
1183
|
-
<div class="group-buttons">
|
|
1184
|
-
<el-tooltip content="git add + git commit" placement="top" effect="light" popper-class="git-cmd-tooltip">
|
|
1185
|
-
<el-button
|
|
1186
|
-
type="primary"
|
|
1187
|
-
:icon="Edit"
|
|
1188
|
-
@click="addAndCommit"
|
|
1189
|
-
:loading="gitLogStore.isAddingFiles || gitLogStore.isCommiting"
|
|
1190
|
-
:disabled="!hasUnstagedChanges || !finalCommitMessage.trim()"
|
|
1191
|
-
class="action-button"
|
|
1192
|
-
>
|
|
1193
|
-
暂存并提交
|
|
1194
|
-
</el-button>
|
|
1195
|
-
</el-tooltip>
|
|
1196
|
-
|
|
1197
|
-
<el-tooltip content="git add + git commit + git push" placement="top" effect="light" popper-class="git-cmd-tooltip">
|
|
1198
|
-
<el-button
|
|
1199
|
-
type="success"
|
|
1200
|
-
:icon="Position"
|
|
1201
|
-
@click="addCommitAndPush"
|
|
1202
|
-
:loading="gitLogStore.isAddingFiles || gitLogStore.isCommiting || gitLogStore.isPushing"
|
|
1203
|
-
:disabled="!hasAnyChanges || !finalCommitMessage.trim() || !gitStore.hasUpstream"
|
|
1204
|
-
:class="['action-button', 'one-click-push', { 'is-loading': gitLogStore.isAddingFiles || gitLogStore.isCommiting || gitLogStore.isPushing }]"
|
|
1205
|
-
>
|
|
1206
|
-
一键推送
|
|
1207
|
-
</el-button>
|
|
1208
|
-
</el-tooltip>
|
|
1209
|
-
</div>
|
|
1210
|
-
</div>
|
|
1211
|
-
</div>
|
|
1212
|
-
|
|
1213
|
-
<!-- 重置操作 -->
|
|
1214
|
-
<div class="action-group reset-group">
|
|
1215
|
-
<div class="group-title">重置操作</div>
|
|
1216
|
-
<div class="group-buttons">
|
|
1217
|
-
<el-tooltip :content="canReset ? `撤销${stagedFilesCount}个已暂存文件` : 'git reset HEAD'" placement="top" effect="light" popper-class="git-cmd-tooltip">
|
|
1218
|
-
<el-button
|
|
1219
|
-
type="warning"
|
|
1220
|
-
:icon="RefreshRight"
|
|
1221
|
-
@click="gitLogStore.resetHead"
|
|
1222
|
-
:loading="gitLogStore.isResetting"
|
|
1223
|
-
:disabled="!canReset"
|
|
1224
|
-
class="action-button reset-button"
|
|
1225
|
-
>
|
|
1226
|
-
重置暂存区
|
|
1227
|
-
<span v-if="stagedFilesCount > 0">({{stagedFilesCount}})</span>
|
|
1228
|
-
</el-button>
|
|
1229
|
-
</el-tooltip>
|
|
1230
|
-
|
|
1231
|
-
<el-tooltip content="git reset --hard origin/branch" placement="top" effect="light" popper-class="git-cmd-tooltip">
|
|
1232
|
-
<el-button
|
|
1233
|
-
type="danger"
|
|
1234
|
-
:icon="Delete"
|
|
1235
|
-
@click="resetToRemote"
|
|
1236
|
-
:loading="gitLogStore.isResetting"
|
|
1237
|
-
:disabled="!canResetToRemote"
|
|
1238
|
-
class="action-button danger-button"
|
|
1239
|
-
>
|
|
1240
|
-
重置到远程
|
|
1241
|
-
</el-button>
|
|
1242
|
-
</el-tooltip>
|
|
1243
|
-
</div>
|
|
1244
|
-
</div>
|
|
1245
|
-
</div>
|
|
1246
|
-
</div>
|
|
1247
|
-
</template>
|
|
1248
|
-
</div>
|
|
1249
|
-
|
|
1250
|
-
<!-- 简短描述设置弹窗 -->
|
|
1251
|
-
<el-dialog
|
|
1252
|
-
title="简短描述模板设置"
|
|
1253
|
-
v-model="descriptionDialogVisible"
|
|
1254
|
-
width="80vw"
|
|
1255
|
-
top="70px"
|
|
1256
|
-
style="height: calc(100vh - 140px);"
|
|
1257
|
-
:close-on-click-modal="false"
|
|
1258
|
-
class="template-dialog"
|
|
1259
|
-
>
|
|
1260
|
-
<div class="template-container">
|
|
1261
|
-
<div class="template-form">
|
|
1262
|
-
<el-input v-model="newTemplateName" :placeholder="isEditingDescription ? '编辑模板内容' : '输入新模板内容'"
|
|
1263
|
-
class="template-input" clearable />
|
|
1264
|
-
<div class="template-form-buttons">
|
|
1265
|
-
<el-button v-if="isEditingDescription" @click="cancelEditDescriptionTemplate">取消</el-button>
|
|
1266
|
-
<el-button type="primary" @click="saveDescriptionTemplate" :disabled="!newTemplateName.trim()">{{
|
|
1267
|
-
isEditingDescription ? '更新模板' : '添加模板' }}</el-button>
|
|
1268
|
-
</div>
|
|
1269
|
-
</div>
|
|
1270
|
-
|
|
1271
|
-
<div class="template-list">
|
|
1272
|
-
<h3>已保存模板</h3>
|
|
1273
|
-
<el-empty v-if="descriptionTemplates.length === 0" description="暂无保存的模板" />
|
|
1274
|
-
<el-card v-for="(template, index) in descriptionTemplates" :key="index" class="template-item">
|
|
1275
|
-
<!-- 两端对齐 -->
|
|
1276
|
-
<el-row justify="space-between" align="middle" style="width: 100%">
|
|
1277
|
-
<div class="template-content">{{ template }}</div>
|
|
1278
|
-
<div class="template-actions">
|
|
1279
|
-
<el-button type="primary" size="small" @click="useTemplate(template)">使用</el-button>
|
|
1280
|
-
<el-button type="warning" size="small" :icon="Edit"
|
|
1281
|
-
@click="startEditDescriptionTemplate(template, index)">编辑</el-button>
|
|
1282
|
-
<el-button type="danger" size="small" @click="deleteDescriptionTemplate(template)">删除</el-button>
|
|
1283
|
-
</div>
|
|
1284
|
-
</el-row>
|
|
1285
|
-
</el-card>
|
|
1286
|
-
</div>
|
|
1287
|
-
</div>
|
|
1288
|
-
</el-dialog>
|
|
1289
|
-
|
|
1290
|
-
<!-- 作用域设置弹窗 -->
|
|
1291
|
-
<el-dialog
|
|
1292
|
-
title="作用域模板设置"
|
|
1293
|
-
v-model="scopeDialogVisible"
|
|
1294
|
-
width="80vw"
|
|
1295
|
-
top="70px"
|
|
1296
|
-
style="height: calc(100vh - 140px);"
|
|
1297
|
-
:close-on-click-modal="false"
|
|
1298
|
-
class="template-dialog"
|
|
1299
|
-
>
|
|
1300
|
-
<div class="template-container">
|
|
1301
|
-
<div class="template-form">
|
|
1302
|
-
<el-input v-model="newScopeTemplate" :placeholder="isEditingScope ? '编辑作用域模板内容' : '输入新作用域模板'"
|
|
1303
|
-
class="template-input" clearable />
|
|
1304
|
-
<div class="template-form-buttons">
|
|
1305
|
-
<el-button v-if="isEditingScope" @click="cancelEditScopeTemplate">取消</el-button>
|
|
1306
|
-
<el-button type="primary" @click="saveScopeTemplate" :disabled="!newScopeTemplate.trim()">{{ isEditingScope
|
|
1307
|
-
? '更新模板' : '添加模板' }}</el-button>
|
|
1308
|
-
</div>
|
|
1309
|
-
</div>
|
|
1310
|
-
|
|
1311
|
-
<div class="template-list">
|
|
1312
|
-
<h3>已保存作用域</h3>
|
|
1313
|
-
<el-empty v-if="scopeTemplates.length === 0" description="暂无保存的作用域" />
|
|
1314
|
-
<el-card v-for="(template, index) in scopeTemplates" :key="index" class="template-item">
|
|
1315
|
-
<el-row justify="space-between" align="middle" style="width: 100%">
|
|
1316
|
-
<div class="template-content">{{ template }}</div>
|
|
1317
|
-
<div class="template-actions">
|
|
1318
|
-
<el-button type="primary" size="small" @click="useScopeTemplate(template)">使用</el-button>
|
|
1319
|
-
<el-button type="warning" size="small" :icon="Edit"
|
|
1320
|
-
@click="startEditScopeTemplate(template, index)">编辑</el-button>
|
|
1321
|
-
<el-button type="danger" size="small" @click="deleteScopeTemplate(template)">删除</el-button>
|
|
1322
|
-
</div>
|
|
1323
|
-
</el-row>
|
|
1324
|
-
</el-card>
|
|
1325
|
-
</div>
|
|
1326
|
-
</div>
|
|
1327
|
-
</el-dialog>
|
|
1328
|
-
|
|
1329
|
-
<!-- 默认提交信息设置弹窗 -->
|
|
1330
|
-
<el-dialog
|
|
1331
|
-
title="默认提交信息设置"
|
|
1332
|
-
v-model="defaultMessageDialogVisible"
|
|
1333
|
-
width="80vw"
|
|
1334
|
-
top="70px"
|
|
1335
|
-
style="height: calc(100vh - 140px);"
|
|
1336
|
-
:close-on-click-modal="false"
|
|
1337
|
-
class="message-template-dialog"
|
|
1338
|
-
>
|
|
1339
|
-
<div class="template-container message-template-container">
|
|
1340
|
-
<div class="template-form">
|
|
1341
|
-
<el-input v-model="newDefaultMessage" :placeholder="isEditingMessage ? '编辑模板内容' : '输入新模板内容'" class="template-input" clearable />
|
|
1342
|
-
<div class="template-form-buttons">
|
|
1343
|
-
<el-button v-if="isEditingMessage" @click="cancelEditMessageTemplate">取消</el-button>
|
|
1344
|
-
<el-button type="primary" @click="saveMessageTemplate" :disabled="!newDefaultMessage.trim()">
|
|
1345
|
-
{{ isEditingMessage ? '更新模板' : '添加模板' }}
|
|
1346
|
-
</el-button>
|
|
1347
|
-
<el-button type="success" @click="saveDefaultMessage" :disabled="!newDefaultMessage.trim()">
|
|
1348
|
-
设为默认提交信息
|
|
1349
|
-
</el-button>
|
|
1350
|
-
</div>
|
|
1351
|
-
</div>
|
|
1352
|
-
|
|
1353
|
-
<div class="templates-container">
|
|
1354
|
-
<div class="message-templates-list">
|
|
1355
|
-
<h3>已保存模板</h3>
|
|
1356
|
-
<div class="templates-scroll-area">
|
|
1357
|
-
<el-empty v-if="messageTemplates.length === 0" description="暂无保存的模板" />
|
|
1358
|
-
<el-card v-for="(template, index) in messageTemplates" :key="index" class="template-item">
|
|
1359
|
-
<el-row justify="space-between" align="middle" style="width: 100%">
|
|
1360
|
-
<div class="template-content">{{ template }}</div>
|
|
1361
|
-
<div class="template-actions">
|
|
1362
|
-
<el-button type="primary" size="small" @click="useMessageTemplate(template)">使用</el-button>
|
|
1363
|
-
<el-button type="warning" size="small" :icon="Edit"
|
|
1364
|
-
@click="startEditMessageTemplate(template, index)">编辑</el-button>
|
|
1365
|
-
<el-button type="danger" size="small" @click="deleteMessageTemplate(template)">删除</el-button>
|
|
1366
|
-
</div>
|
|
1367
|
-
</el-row>
|
|
1368
|
-
</el-card>
|
|
1369
|
-
</div>
|
|
1370
|
-
</div>
|
|
1371
|
-
|
|
1372
|
-
<div class="current-default-message">
|
|
1373
|
-
<h3>当前默认提交信息</h3>
|
|
1374
|
-
<el-card class="default-message-card" v-if="defaultCommitMessage">
|
|
1375
|
-
<div class="default-message-content">{{ defaultCommitMessage }}</div>
|
|
1376
|
-
</el-card>
|
|
1377
|
-
<el-empty v-else description="尚未设置默认提交信息" :image-size="100" />
|
|
1378
|
-
|
|
1379
|
-
<div class="message-help-text">
|
|
1380
|
-
<h4>关于默认提交信息</h4>
|
|
1381
|
-
<p>默认提交信息将在未输入提交信息时自动使用。</p>
|
|
1382
|
-
<p>你可以通过点击左侧模板的<el-tag size="small" type="primary">使用</el-tag>按钮先选择喜欢的模板,然后点击上方<el-tag size="small" type="success">设为默认提交信息</el-tag>按钮保存。</p>
|
|
1383
|
-
</div>
|
|
1384
|
-
</div>
|
|
1385
|
-
</div>
|
|
1386
|
-
</div>
|
|
1387
|
-
</el-dialog>
|
|
1388
|
-
</div>
|
|
1389
|
-
</div>
|
|
1390
|
-
</template>
|
|
1391
|
-
|
|
1392
|
-
<style scoped>
|
|
1393
|
-
/* 添加动画相关的CSS */
|
|
1394
|
-
@keyframes snakeBorder {
|
|
1395
|
-
0%, 100% {
|
|
1396
|
-
border-top: 2px solid #409EFF;
|
|
1397
|
-
border-right: 2px solid transparent;
|
|
1398
|
-
border-bottom: 2px solid transparent;
|
|
1399
|
-
border-left: 2px solid transparent;
|
|
1400
|
-
}
|
|
1401
|
-
25% {
|
|
1402
|
-
border-top: 2px solid #409EFF;
|
|
1403
|
-
border-right: 2px solid #67C23A;
|
|
1404
|
-
border-bottom: 2px solid transparent;
|
|
1405
|
-
border-left: 2px solid transparent;
|
|
1406
|
-
}
|
|
1407
|
-
50% {
|
|
1408
|
-
border-top: 2px solid transparent;
|
|
1409
|
-
border-right: 2px solid #67C23A;
|
|
1410
|
-
border-bottom: 2px solid #409EFF;
|
|
1411
|
-
border-left: 2px solid transparent;
|
|
1412
|
-
}
|
|
1413
|
-
75% {
|
|
1414
|
-
border-top: 2px solid transparent;
|
|
1415
|
-
border-right: 2px solid transparent;
|
|
1416
|
-
border-bottom: 2px solid #409EFF;
|
|
1417
|
-
border-left: 2px solid #67C23A;
|
|
1418
|
-
}
|
|
1419
|
-
}
|
|
1420
|
-
|
|
1421
|
-
@keyframes glowPulse {
|
|
1422
|
-
0%, 100% { box-shadow: 0 0 8px rgba(64, 158, 255, 0.4); }
|
|
1423
|
-
50% { box-shadow: 0 0 12px rgba(103, 194, 58, 0.5); }
|
|
1424
|
-
}
|
|
1425
|
-
|
|
1426
|
-
.card {
|
|
1427
|
-
background-color: white;
|
|
1428
|
-
border-radius: 8px;
|
|
1429
|
-
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.03);
|
|
1430
|
-
border: 1px solid rgba(0, 0, 0, 0.03);
|
|
1431
|
-
height: 100%;
|
|
1432
|
-
width: 100%;
|
|
1433
|
-
display: flex;
|
|
1434
|
-
flex-direction: column;
|
|
1435
|
-
overflow: hidden;
|
|
1436
|
-
position: relative;
|
|
1437
|
-
}
|
|
1438
|
-
|
|
1439
|
-
.card-header {
|
|
1440
|
-
padding: 8px 16px;
|
|
1441
|
-
border-bottom: 1px solid #f0f0f0;
|
|
1442
|
-
display: flex;
|
|
1443
|
-
justify-content: space-between;
|
|
1444
|
-
align-items: center;
|
|
1445
|
-
height: 36px;
|
|
1446
|
-
}
|
|
1447
|
-
|
|
1448
|
-
.card-header h2 {
|
|
1449
|
-
margin: 0;
|
|
1450
|
-
font-size: 16px;
|
|
1451
|
-
font-weight: 500;
|
|
1452
|
-
color: #303133;
|
|
1453
|
-
}
|
|
1454
|
-
|
|
1455
|
-
.card-content {
|
|
1456
|
-
padding: 15px;
|
|
1457
|
-
overflow-y: auto;
|
|
1458
|
-
flex: 1;
|
|
1459
|
-
}
|
|
1460
|
-
|
|
1461
|
-
.layout-container {
|
|
1462
|
-
display: flex;
|
|
1463
|
-
flex-direction: column;
|
|
1464
|
-
gap: 15px;
|
|
1465
|
-
height: 100%;
|
|
1466
|
-
}
|
|
1467
|
-
|
|
1468
|
-
.commit-section {
|
|
1469
|
-
flex: 1;
|
|
1470
|
-
min-width: 0; /* 防止子元素撑开 */
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
|
-
.actions-section {
|
|
1474
|
-
width: 100%;
|
|
1475
|
-
flex-shrink: 0;
|
|
1476
|
-
}
|
|
1477
|
-
|
|
1478
|
-
.actions-section h3 {
|
|
1479
|
-
margin-top: 0;
|
|
1480
|
-
margin-bottom: 10px;
|
|
1481
|
-
padding-bottom: 8px;
|
|
1482
|
-
border-bottom: 1px solid #dcdfe6;
|
|
1483
|
-
font-size: 16px;
|
|
1484
|
-
color: #303133;
|
|
1485
|
-
font-weight: 500;
|
|
1486
|
-
}
|
|
1487
|
-
|
|
1488
|
-
.operations-wrapper {
|
|
1489
|
-
display: flex;
|
|
1490
|
-
gap: 10px;
|
|
1491
|
-
}
|
|
1492
|
-
|
|
1493
|
-
.action-groups {
|
|
1494
|
-
display: flex;
|
|
1495
|
-
flex-direction: column;
|
|
1496
|
-
gap: 12px;
|
|
1497
|
-
}
|
|
1498
|
-
|
|
1499
|
-
.action-group {
|
|
1500
|
-
background-color: #f9f9f9;
|
|
1501
|
-
border-radius: 6px;
|
|
1502
|
-
padding: 8px 10px;
|
|
1503
|
-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
|
1504
|
-
border-left: 3px solid #409EFF;
|
|
1505
|
-
flex: 1;
|
|
1506
|
-
}
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
.action-group:nth-child(2) {
|
|
1510
|
-
border-left-color: #E6A23C;
|
|
1511
|
-
}
|
|
1512
|
-
|
|
1513
|
-
.action-group:nth-child(3) {
|
|
1514
|
-
border-left-color: #909399;
|
|
1515
|
-
}
|
|
1516
|
-
|
|
1517
|
-
.group-title {
|
|
1518
|
-
font-size: 13px;
|
|
1519
|
-
font-weight: bold;
|
|
1520
|
-
margin-bottom: 8px;
|
|
1521
|
-
color: #606266;
|
|
1522
|
-
text-align: left;
|
|
1523
|
-
display: block;
|
|
1524
|
-
position: relative;
|
|
1525
|
-
padding-left: 6px;
|
|
1526
|
-
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
|
1527
|
-
padding-bottom: 6px;
|
|
1528
|
-
}
|
|
1529
|
-
|
|
1530
|
-
.group-buttons {
|
|
1531
|
-
display: flex;
|
|
1532
|
-
flex-direction: row;
|
|
1533
|
-
flex-wrap: wrap;
|
|
1534
|
-
gap: 8px;
|
|
1535
|
-
padding: 0;
|
|
1536
|
-
}
|
|
1537
|
-
|
|
1538
|
-
.action-button {
|
|
1539
|
-
font-size: 14px;
|
|
1540
|
-
font-weight: 500;
|
|
1541
|
-
flex: 1;
|
|
1542
|
-
min-width: 100px;
|
|
1543
|
-
border-radius: 4px;
|
|
1544
|
-
height: 36px;
|
|
1545
|
-
padding: 0 10px;
|
|
1546
|
-
}
|
|
1547
|
-
|
|
1548
|
-
.action-button:hover {
|
|
1549
|
-
transform: translateY(-1px);
|
|
1550
|
-
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);
|
|
1551
|
-
}
|
|
1552
|
-
|
|
1553
|
-
.action-button:active {
|
|
1554
|
-
transform: translateY(0);
|
|
1555
|
-
}
|
|
1556
|
-
|
|
1557
|
-
.command-text {
|
|
1558
|
-
display: none;
|
|
1559
|
-
}
|
|
1560
|
-
|
|
1561
|
-
.command-text-long {
|
|
1562
|
-
display: none;
|
|
1563
|
-
}
|
|
1564
|
-
|
|
1565
|
-
.standard-commit-form {
|
|
1566
|
-
display: flex;
|
|
1567
|
-
flex-direction: column;
|
|
1568
|
-
gap: 15px;
|
|
1569
|
-
margin-bottom: 15px;
|
|
1570
|
-
}
|
|
1571
|
-
|
|
1572
|
-
.standard-commit-header {
|
|
1573
|
-
display: flex;
|
|
1574
|
-
flex-direction: column;
|
|
1575
|
-
gap: 10px;
|
|
1576
|
-
width: 100%;
|
|
1577
|
-
}
|
|
1578
|
-
|
|
1579
|
-
.type-scope-container {
|
|
1580
|
-
display: flex;
|
|
1581
|
-
gap: 10px;
|
|
1582
|
-
width: 100%;
|
|
1583
|
-
margin-bottom: 10px;
|
|
1584
|
-
}
|
|
1585
|
-
|
|
1586
|
-
.type-select {
|
|
1587
|
-
width: 35%; /* 提交类型占35%宽度 */
|
|
1588
|
-
}
|
|
1589
|
-
|
|
1590
|
-
.scope-wrapper {
|
|
1591
|
-
display: flex;
|
|
1592
|
-
align-items: center;
|
|
1593
|
-
gap: 5px;
|
|
1594
|
-
width: 65%; /* 作用域占65%宽度 */
|
|
1595
|
-
}
|
|
1596
|
-
|
|
1597
|
-
.description-container {
|
|
1598
|
-
display: flex;
|
|
1599
|
-
align-items: center;
|
|
1600
|
-
gap: 5px;
|
|
1601
|
-
width: 100%;
|
|
1602
|
-
}
|
|
1603
|
-
|
|
1604
|
-
.scope-input, .description-input {
|
|
1605
|
-
flex-grow: 1;
|
|
1606
|
-
}
|
|
1607
|
-
|
|
1608
|
-
.settings-button {
|
|
1609
|
-
flex-shrink: 0;
|
|
1610
|
-
}
|
|
1611
|
-
|
|
1612
|
-
.preview-section {
|
|
1613
|
-
background-color: #f5f7fa;
|
|
1614
|
-
padding: 10px;
|
|
1615
|
-
border-radius: 4px;
|
|
1616
|
-
}
|
|
1617
|
-
|
|
1618
|
-
.preview-title {
|
|
1619
|
-
font-weight: bold;
|
|
1620
|
-
margin-bottom: 5px;
|
|
1621
|
-
}
|
|
1622
|
-
|
|
1623
|
-
.preview-content {
|
|
1624
|
-
white-space: pre-wrap;
|
|
1625
|
-
font-family: monospace;
|
|
1626
|
-
margin: 0;
|
|
1627
|
-
padding: 10px;
|
|
1628
|
-
background-color: #ebeef5;
|
|
1629
|
-
border-radius: 4px;
|
|
1630
|
-
}
|
|
1631
|
-
|
|
1632
|
-
.template-container {
|
|
1633
|
-
display: flex;
|
|
1634
|
-
flex-direction: column;
|
|
1635
|
-
height: calc(85vh - 100px);
|
|
1636
|
-
overflow-y: auto;
|
|
1637
|
-
padding: 5px;
|
|
1638
|
-
}
|
|
1639
|
-
|
|
1640
|
-
.template-form {
|
|
1641
|
-
margin-bottom: 20px;
|
|
1642
|
-
background-color: #f8f9fa;
|
|
1643
|
-
padding: 15px;
|
|
1644
|
-
border-radius: 6px;
|
|
1645
|
-
border: 1px solid #ebeef5;
|
|
1646
|
-
}
|
|
1647
|
-
|
|
1648
|
-
.template-form-buttons {
|
|
1649
|
-
display: flex;
|
|
1650
|
-
gap: 10px;
|
|
1651
|
-
margin-top: 12px;
|
|
1652
|
-
justify-content: flex-end;
|
|
1653
|
-
}
|
|
1654
|
-
|
|
1655
|
-
.template-input {
|
|
1656
|
-
flex-grow: 1;
|
|
1657
|
-
}
|
|
1658
|
-
|
|
1659
|
-
.template-list {
|
|
1660
|
-
overflow-y: auto;
|
|
1661
|
-
height: 100%;
|
|
1662
|
-
}
|
|
1663
|
-
|
|
1664
|
-
.template-list h3 {
|
|
1665
|
-
margin-top: 0;
|
|
1666
|
-
margin-bottom: 15px;
|
|
1667
|
-
font-size: 16px;
|
|
1668
|
-
font-weight: 500;
|
|
1669
|
-
color: #303133;
|
|
1670
|
-
padding-bottom: 8px;
|
|
1671
|
-
border-bottom: 1px solid #ebeef5;
|
|
1672
|
-
}
|
|
1673
|
-
|
|
1674
|
-
.template-item {
|
|
1675
|
-
margin-bottom: 10px;
|
|
1676
|
-
transition: all 0.2s ease;
|
|
1677
|
-
border: 1px solid #ebeef5;
|
|
1678
|
-
}
|
|
1679
|
-
|
|
1680
|
-
.template-item:hover {
|
|
1681
|
-
background-color: #f5f7fa;
|
|
1682
|
-
transform: translateY(-2px);
|
|
1683
|
-
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
1684
|
-
}
|
|
1685
|
-
|
|
1686
|
-
.template-content {
|
|
1687
|
-
flex-grow: 1;
|
|
1688
|
-
margin-right: 10px;
|
|
1689
|
-
word-break: break-all;
|
|
1690
|
-
padding: 5px 0;
|
|
1691
|
-
color: #303133;
|
|
1692
|
-
font-weight: 500;
|
|
1693
|
-
}
|
|
1694
|
-
|
|
1695
|
-
.template-actions {
|
|
1696
|
-
display: flex;
|
|
1697
|
-
gap: 8px;
|
|
1698
|
-
justify-content: flex-end;
|
|
1699
|
-
min-width: 180px;
|
|
1700
|
-
flex-shrink: 0;
|
|
1701
|
-
}
|
|
1702
|
-
|
|
1703
|
-
.options-row {
|
|
1704
|
-
display: flex;
|
|
1705
|
-
justify-content: space-between;
|
|
1706
|
-
align-items: center;
|
|
1707
|
-
margin-bottom: 15px;
|
|
1708
|
-
}
|
|
1709
|
-
|
|
1710
|
-
.code-command {
|
|
1711
|
-
background-color: #2d2d2d;
|
|
1712
|
-
color: #f8f8f2;
|
|
1713
|
-
font-family: 'Courier New', Courier, monospace;
|
|
1714
|
-
padding: 10px;
|
|
1715
|
-
border-radius: 4px;
|
|
1716
|
-
overflow-x: auto;
|
|
1717
|
-
white-space: pre;
|
|
1718
|
-
font-size: 14px;
|
|
1719
|
-
}
|
|
1720
|
-
|
|
1721
|
-
@media (min-width: 768px) {
|
|
1722
|
-
.layout-container {
|
|
1723
|
-
flex-direction: row;
|
|
1724
|
-
}
|
|
1725
|
-
|
|
1726
|
-
.commit-section {
|
|
1727
|
-
flex: 3;
|
|
1728
|
-
}
|
|
1729
|
-
|
|
1730
|
-
.actions-section {
|
|
1731
|
-
width: 320px;
|
|
1732
|
-
}
|
|
1733
|
-
|
|
1734
|
-
.operations-wrapper {
|
|
1735
|
-
flex-direction: column;
|
|
1736
|
-
}
|
|
1737
|
-
}
|
|
1738
|
-
|
|
1739
|
-
.git-config-warning {
|
|
1740
|
-
width: 100%;
|
|
1741
|
-
}
|
|
1742
|
-
|
|
1743
|
-
.config-command {
|
|
1744
|
-
background-color: #2d2d2d;
|
|
1745
|
-
color: #f8f8f2;
|
|
1746
|
-
font-family: 'Courier New', Courier, monospace;
|
|
1747
|
-
padding: 10px;
|
|
1748
|
-
border-radius:
|
|
1749
|
-
4px;
|
|
1750
|
-
margin-top: 10px;
|
|
1751
|
-
white-space: pre;
|
|
1752
|
-
}
|
|
1753
|
-
|
|
1754
|
-
/* 推送时的动画效果 */
|
|
1755
|
-
@keyframes pushing-pulse {
|
|
1756
|
-
0% { box-shadow: 0 0 0 0 rgba(103, 194, 58, 0.4); }
|
|
1757
|
-
70% { box-shadow: 0 0 0 15px rgba(103, 194, 58, 0); }
|
|
1758
|
-
100% { box-shadow: 0 0 0 0 rgba(103, 194, 58, 0); }
|
|
1759
|
-
}
|
|
1760
|
-
|
|
1761
|
-
@keyframes pushing-border {
|
|
1762
|
-
0% { border-color: #67c23a; }
|
|
1763
|
-
50% { border-color: #85ce61; }
|
|
1764
|
-
100% { border-color: #67c23a; }
|
|
1765
|
-
}
|
|
1766
|
-
|
|
1767
|
-
.card.is-pushing {
|
|
1768
|
-
animation: pushing-border 1.5s infinite ease-in-out;
|
|
1769
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
1770
|
-
transition: all 0.3s ease;
|
|
1771
|
-
}
|
|
1772
|
-
|
|
1773
|
-
.push-button {
|
|
1774
|
-
background-color: #67c23a;
|
|
1775
|
-
border-color: #67c23a;
|
|
1776
|
-
}
|
|
1777
|
-
|
|
1778
|
-
.push-button:hover {
|
|
1779
|
-
background-color: #85ce61;
|
|
1780
|
-
border-color: #85ce61;
|
|
1781
|
-
}
|
|
1782
|
-
|
|
1783
|
-
.push-button.is-loading,
|
|
1784
|
-
.push-button.is-loading:hover,
|
|
1785
|
-
.push-button.is-loading:focus {
|
|
1786
|
-
animation: pushing-pulse 1.5s infinite;
|
|
1787
|
-
background-color: #67c23a !important;
|
|
1788
|
-
border-color: #67c23a !important;
|
|
1789
|
-
}
|
|
1790
|
-
|
|
1791
|
-
.el-button.push-button.is-loading .el-loading-spinner {
|
|
1792
|
-
color: #fff !important;
|
|
1793
|
-
}
|
|
1794
|
-
|
|
1795
|
-
/* 一键推送按钮动画 */
|
|
1796
|
-
@keyframes one-click-push-glow {
|
|
1797
|
-
0% { box-shadow: 0 0 5px rgba(103, 194, 58, 0.5); }
|
|
1798
|
-
50% { box-shadow: 0 0 20px rgba(103, 194, 58, 0.8); }
|
|
1799
|
-
100% { box-shadow: 0 0 5px rgba(103, 194, 58, 0.5); }
|
|
1800
|
-
}
|
|
1801
|
-
|
|
1802
|
-
.action-button.one-click-push {
|
|
1803
|
-
position: relative;
|
|
1804
|
-
overflow: hidden;
|
|
1805
|
-
}
|
|
1806
|
-
|
|
1807
|
-
.action-button.one-click-push.is-loading,
|
|
1808
|
-
.action-button.one-click-push.is-loading:hover {
|
|
1809
|
-
animation: one-click-push-glow 1.5s infinite;
|
|
1810
|
-
background-color: #67c23a !important;
|
|
1811
|
-
border-color: #67c23a !important;
|
|
1812
|
-
}
|
|
1813
|
-
|
|
1814
|
-
/* 推送成功动画 */
|
|
1815
|
-
@keyframes push-success {
|
|
1816
|
-
0% { transform: scale(1); }
|
|
1817
|
-
50% { transform: scale(1.1); }
|
|
1818
|
-
100% { transform: scale(1); }
|
|
1819
|
-
}
|
|
1820
|
-
|
|
1821
|
-
.push-success-indicator {
|
|
1822
|
-
position: absolute;
|
|
1823
|
-
inset: 0; /* 同时设置top, right, bottom, left为0 */
|
|
1824
|
-
margin: auto;
|
|
1825
|
-
background-color: rgba(255, 255, 255, 1);
|
|
1826
|
-
border-radius: 12px;
|
|
1827
|
-
padding: 20px 30px;
|
|
1828
|
-
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
|
|
1829
|
-
display: flex;
|
|
1830
|
-
flex-direction: column;
|
|
1831
|
-
align-items: center;
|
|
1832
|
-
justify-content: center;
|
|
1833
|
-
animation: push-success 0.5s ease-out;
|
|
1834
|
-
z-index: 9999;
|
|
1835
|
-
width: 200px;
|
|
1836
|
-
height: 200px;
|
|
1837
|
-
}
|
|
1838
|
-
|
|
1839
|
-
.push-success-icon {
|
|
1840
|
-
font-size: 64px;
|
|
1841
|
-
color: #67c23a;
|
|
1842
|
-
margin-bottom: 16px;
|
|
1843
|
-
animation: bounce 0.8s ease-in-out;
|
|
1844
|
-
}
|
|
1845
|
-
|
|
1846
|
-
@keyframes bounce {
|
|
1847
|
-
0%, 20%, 50%, 80%, 100% {transform: translateY(0);}
|
|
1848
|
-
40% {transform: translateY(-20px);}
|
|
1849
|
-
60% {transform: translateY(-10px);}
|
|
1850
|
-
}
|
|
1851
|
-
|
|
1852
|
-
.push-success-text {
|
|
1853
|
-
font-size: 20px;
|
|
1854
|
-
font-weight: bold;
|
|
1855
|
-
color: #303133;
|
|
1856
|
-
text-align: center;
|
|
1857
|
-
}
|
|
1858
|
-
|
|
1859
|
-
.reset-button {
|
|
1860
|
-
background-color: #909399;
|
|
1861
|
-
border-color: #909399;
|
|
1862
|
-
}
|
|
1863
|
-
|
|
1864
|
-
.reset-button:hover {
|
|
1865
|
-
background-color: #a6a9ad;
|
|
1866
|
-
border-color: #a6a9ad;
|
|
1867
|
-
}
|
|
1868
|
-
.el-button+.el-button {
|
|
1869
|
-
margin-left: 0;
|
|
1870
|
-
}
|
|
1871
|
-
|
|
1872
|
-
/* 推送中动画样式 */
|
|
1873
|
-
.pushing-indicator {
|
|
1874
|
-
position: absolute;
|
|
1875
|
-
inset: 0;
|
|
1876
|
-
margin: auto;
|
|
1877
|
-
background-color: rgba(64, 158, 255, 1);
|
|
1878
|
-
border-radius: 12px;
|
|
1879
|
-
padding: 20px 30px;
|
|
1880
|
-
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
|
|
1881
|
-
display: flex;
|
|
1882
|
-
flex-direction: column;
|
|
1883
|
-
align-items: center;
|
|
1884
|
-
justify-content: center;
|
|
1885
|
-
z-index: 9999;
|
|
1886
|
-
width: 200px;
|
|
1887
|
-
height: 200px;
|
|
1888
|
-
color: white;
|
|
1889
|
-
}
|
|
1890
|
-
|
|
1891
|
-
.pushing-spinner {
|
|
1892
|
-
margin-bottom: 16px;
|
|
1893
|
-
}
|
|
1894
|
-
|
|
1895
|
-
.pushing-text {
|
|
1896
|
-
font-size: 20px;
|
|
1897
|
-
font-weight: bold;
|
|
1898
|
-
text-align: center;
|
|
1899
|
-
}
|
|
1900
|
-
|
|
1901
|
-
.circular {
|
|
1902
|
-
height: 64px;
|
|
1903
|
-
width: 64px;
|
|
1904
|
-
animation: pushing-rotate 2s linear infinite;
|
|
1905
|
-
}
|
|
1906
|
-
|
|
1907
|
-
.path {
|
|
1908
|
-
stroke: white;
|
|
1909
|
-
stroke-width: 4;
|
|
1910
|
-
stroke-linecap: round;
|
|
1911
|
-
stroke-dasharray: 90, 150;
|
|
1912
|
-
stroke-dashoffset: 0;
|
|
1913
|
-
animation: pushing-dash 1.5s ease-in-out infinite;
|
|
1914
|
-
}
|
|
1915
|
-
|
|
1916
|
-
@keyframes pushing-rotate {
|
|
1917
|
-
100% {
|
|
1918
|
-
transform: rotate(360deg);
|
|
1919
|
-
}
|
|
1920
|
-
}
|
|
1921
|
-
|
|
1922
|
-
@keyframes pushing-dash {
|
|
1923
|
-
0% {
|
|
1924
|
-
stroke-dasharray: 1, 150;
|
|
1925
|
-
stroke-dashoffset: 0;
|
|
1926
|
-
}
|
|
1927
|
-
50% {
|
|
1928
|
-
stroke-dasharray: 90, 150;
|
|
1929
|
-
stroke-dashoffset: -35;
|
|
1930
|
-
}
|
|
1931
|
-
100% {
|
|
1932
|
-
stroke-dasharray: 90, 150;
|
|
1933
|
-
stroke-dashoffset: -124;
|
|
1934
|
-
}
|
|
1935
|
-
}
|
|
1936
|
-
|
|
1937
|
-
.message-template-container {
|
|
1938
|
-
display: flex;
|
|
1939
|
-
flex-direction: column;
|
|
1940
|
-
height: calc(100vh - 278px);
|
|
1941
|
-
overflow: hidden;
|
|
1942
|
-
}
|
|
1943
|
-
|
|
1944
|
-
.templates-container {
|
|
1945
|
-
display: flex;
|
|
1946
|
-
gap: 20px;
|
|
1947
|
-
margin-top: 15px;
|
|
1948
|
-
flex: 1;
|
|
1949
|
-
overflow: hidden;
|
|
1950
|
-
}
|
|
1951
|
-
|
|
1952
|
-
.message-templates-list {
|
|
1953
|
-
flex: 3;
|
|
1954
|
-
display: flex;
|
|
1955
|
-
flex-direction: column;
|
|
1956
|
-
border-right: 1px solid #ebeef5;
|
|
1957
|
-
padding-right: 15px;
|
|
1958
|
-
height: calc(100vh - 432px);
|
|
1959
|
-
}
|
|
1960
|
-
|
|
1961
|
-
.message-templates-list h3 {
|
|
1962
|
-
margin-top: 0;
|
|
1963
|
-
margin-bottom: 15px;
|
|
1964
|
-
font-size: 16px;
|
|
1965
|
-
font-weight: 500;
|
|
1966
|
-
color: #303133;
|
|
1967
|
-
padding-bottom: 8px;
|
|
1968
|
-
border-bottom: 1px solid #ebeef5;
|
|
1969
|
-
}
|
|
1970
|
-
|
|
1971
|
-
.current-default-message {
|
|
1972
|
-
flex: 2;
|
|
1973
|
-
display: flex;
|
|
1974
|
-
flex-direction: column;
|
|
1975
|
-
gap: 15px;
|
|
1976
|
-
padding-left: 15px;
|
|
1977
|
-
}
|
|
1978
|
-
|
|
1979
|
-
.current-default-message h3 {
|
|
1980
|
-
margin-top: 0;
|
|
1981
|
-
margin-bottom: 15px;
|
|
1982
|
-
font-size: 16px;
|
|
1983
|
-
font-weight: 500;
|
|
1984
|
-
color: #303133;
|
|
1985
|
-
padding-bottom: 8px;
|
|
1986
|
-
border-bottom: 1px solid #ebeef5;
|
|
1987
|
-
}
|
|
1988
|
-
|
|
1989
|
-
.templates-scroll-area {
|
|
1990
|
-
overflow-y: auto;
|
|
1991
|
-
padding-right: 5px;
|
|
1992
|
-
flex: 1;
|
|
1993
|
-
}
|
|
1994
|
-
|
|
1995
|
-
.default-message-card {
|
|
1996
|
-
margin-bottom: 15px;
|
|
1997
|
-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
1998
|
-
border-radius: 4px;
|
|
1999
|
-
transition: all 0.3s ease;
|
|
2000
|
-
}
|
|
2001
|
-
|
|
2002
|
-
.default-message-card:hover {
|
|
2003
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
|
|
2004
|
-
}
|
|
2005
|
-
|
|
2006
|
-
.default-message-content {
|
|
2007
|
-
padding: 12px 15px;
|
|
2008
|
-
background-color: #f0f9eb;
|
|
2009
|
-
border-left: 3px solid #67c23a;
|
|
2010
|
-
font-weight: 500;
|
|
2011
|
-
word-break: break-all;
|
|
2012
|
-
min-height: 60px;
|
|
2013
|
-
display: flex;
|
|
2014
|
-
align-items: center;
|
|
2015
|
-
border-radius: 0 4px 4px 0;
|
|
2016
|
-
color: #303133;
|
|
2017
|
-
}
|
|
2018
|
-
|
|
2019
|
-
.message-help-text {
|
|
2020
|
-
background-color: #f8f9fa;
|
|
2021
|
-
border-radius: 4px;
|
|
2022
|
-
padding: 15px;
|
|
2023
|
-
font-size: 14px;
|
|
2024
|
-
color: #606266;
|
|
2025
|
-
border-left: 3px solid #909399;
|
|
2026
|
-
margin-top: auto;
|
|
2027
|
-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
2028
|
-
}
|
|
2029
|
-
|
|
2030
|
-
.message-help-text h4 {
|
|
2031
|
-
margin-top: 0;
|
|
2032
|
-
margin-bottom: 10px;
|
|
2033
|
-
color: #303133;
|
|
2034
|
-
font-size: 15px;
|
|
2035
|
-
}
|
|
2036
|
-
|
|
2037
|
-
.message-help-text p {
|
|
2038
|
-
margin: 8px 0;
|
|
2039
|
-
line-height: 1.5;
|
|
2040
|
-
}
|
|
2041
|
-
|
|
2042
|
-
.advanced-options-toggle {
|
|
2043
|
-
display: flex;
|
|
2044
|
-
align-items: center;
|
|
2045
|
-
justify-content: center;
|
|
2046
|
-
padding: 8px 0;
|
|
2047
|
-
background-color: #f5f7fa;
|
|
2048
|
-
border-radius: 4px;
|
|
2049
|
-
cursor: pointer;
|
|
2050
|
-
transition: all 0.3s ease;
|
|
2051
|
-
user-select: none;
|
|
2052
|
-
}
|
|
2053
|
-
|
|
2054
|
-
.advanced-options-toggle:hover {
|
|
2055
|
-
background-color: #ebeef5;
|
|
2056
|
-
color: #409EFF;
|
|
2057
|
-
}
|
|
2058
|
-
|
|
2059
|
-
.toggle-icon {
|
|
2060
|
-
margin-left: 8px;
|
|
2061
|
-
transition: transform 0.3s ease;
|
|
2062
|
-
}
|
|
2063
|
-
|
|
2064
|
-
.toggle-icon.is-active {
|
|
2065
|
-
transform: rotate(180deg);
|
|
2066
|
-
}
|
|
2067
|
-
|
|
2068
|
-
.advanced-fields {
|
|
2069
|
-
margin-top: 10px;
|
|
2070
|
-
display: flex;
|
|
2071
|
-
flex-direction: column;
|
|
2072
|
-
gap: 15px;
|
|
2073
|
-
animation: fade-in 0.3s ease-in-out;
|
|
2074
|
-
}
|
|
2075
|
-
|
|
2076
|
-
@keyframes fade-in {
|
|
2077
|
-
from {
|
|
2078
|
-
opacity: 0;
|
|
2079
|
-
transform: translateY(-10px);
|
|
2080
|
-
}
|
|
2081
|
-
to {
|
|
2082
|
-
opacity: 1;
|
|
2083
|
-
transform: translateY(0);
|
|
2084
|
-
}
|
|
2085
|
-
}
|
|
2086
|
-
</style>
|
|
2087
|
-
|
|
2088
|
-
<!-- 添加全局样式 -->
|
|
2089
|
-
<style>
|
|
2090
|
-
/* Git命令tooltip样式 */
|
|
2091
|
-
.git-cmd-tooltip {
|
|
2092
|
-
font-family: 'Consolas', 'Courier New', monospace !important;
|
|
2093
|
-
font-size: 13px !important;
|
|
2094
|
-
font-weight: 500 !important;
|
|
2095
|
-
color: #303133 !important;
|
|
2096
|
-
background-color: #f5f7fa !important;
|
|
2097
|
-
border: 1px solid #dcdfe6 !important;
|
|
2098
|
-
border-radius: 4px !important;
|
|
2099
|
-
padding: 8px 12px !important;
|
|
2100
|
-
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1) !important;
|
|
2101
|
-
}
|
|
2102
|
-
|
|
2103
|
-
/* 弹窗样式优化 */
|
|
2104
|
-
.template-dialog .el-dialog__header,
|
|
2105
|
-
.message-template-dialog .el-dialog__header {
|
|
2106
|
-
padding: 15px 20px;
|
|
2107
|
-
margin-right: 0;
|
|
2108
|
-
border-bottom: 1px solid #ebeef5;
|
|
2109
|
-
background-color: #f8f9fa;
|
|
2110
|
-
}
|
|
2111
|
-
|
|
2112
|
-
.template-dialog .el-dialog__title,
|
|
2113
|
-
.message-template-dialog .el-dialog__title {
|
|
2114
|
-
font-size: 16px;
|
|
2115
|
-
font-weight: 600;
|
|
2116
|
-
color: #303133;
|
|
2117
|
-
}
|
|
2118
|
-
|
|
2119
|
-
.template-dialog .el-dialog__body,
|
|
2120
|
-
.message-template-dialog .el-dialog__body {
|
|
2121
|
-
padding: 20px;
|
|
2122
|
-
}
|
|
2123
|
-
|
|
2124
|
-
.template-dialog .el-dialog__headerbtn,
|
|
2125
|
-
.message-template-dialog .el-dialog__headerbtn {
|
|
2126
|
-
top: 15px;
|
|
2127
|
-
right: 20px;
|
|
2128
|
-
}
|
|
2129
|
-
|
|
2130
|
-
.template-dialog .el-input__inner,
|
|
2131
|
-
.message-template-dialog .el-input__inner {
|
|
2132
|
-
height: 40px;
|
|
2133
|
-
line-height: 40px;
|
|
2134
|
-
}
|
|
2135
|
-
|
|
2136
|
-
.template-dialog .el-button,
|
|
2137
|
-
.message-template-dialog .el-button {
|
|
2138
|
-
border-radius: 4px;
|
|
2139
|
-
font-weight: 500;
|
|
2140
|
-
}
|
|
2141
|
-
|
|
2142
|
-
.template-dialog .el-card,
|
|
2143
|
-
.message-template-dialog .el-card {
|
|
2144
|
-
border-radius: 4px;
|
|
2145
|
-
overflow: hidden;
|
|
2146
|
-
}
|
|
2147
|
-
|
|
2148
|
-
.template-dialog .el-card__body,
|
|
2149
|
-
.message-template-dialog .el-card__body {
|
|
2150
|
-
padding: 12px 15px;
|
|
2151
|
-
}
|
|
2152
|
-
|
|
2153
|
-
.template-dialog .el-empty__image,
|
|
2154
|
-
.message-template-dialog .el-empty__image {
|
|
2155
|
-
width: 80px;
|
|
2156
|
-
height: 80px;
|
|
2157
|
-
}
|
|
2158
|
-
</style>
|