zen-gitsync 2.0.5 → 2.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -2
- package/package.json +3 -1
- package/src/ui/client/src/App.vue +417 -123
- package/src/ui/client/src/components/CommitForm.vue +284 -211
- package/src/ui/client/src/components/GitStatus.vue +556 -171
- package/src/ui/client/src/components/LogList.vue +778 -94
- package/src/ui/client/src/stores/gitLogStore.ts +328 -13
- package/src/ui/client/stats.html +1 -1
- package/src/ui/public/assets/index-DaPynzAr.js +10 -0
- package/src/ui/public/assets/index-qfIezZmd.css +1 -0
- package/src/ui/public/assets/vendor-BcSuWc8z.js +45 -0
- package/src/ui/public/index.html +3 -3
- package/src/ui/server/index.js +287 -40
- package/src/ui/public/assets/index-CALk9kKc.js +0 -9
- package/src/ui/public/assets/index-D3zIiSNw.css +0 -1
- package/src/ui/public/assets/vendor-BfXVsoKv.js +0 -45
package/src/ui/public/index.html
CHANGED
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>Zen-GitSync - Git同步工具</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
-
<link rel="modulepreload" crossorigin href="/assets/vendor-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-DaPynzAr.js"></script>
|
|
9
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-BcSuWc8z.js">
|
|
10
10
|
<link rel="stylesheet" crossorigin href="/assets/vendor-Dp0FkvMe.css">
|
|
11
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
11
|
+
<link rel="stylesheet" crossorigin href="/assets/index-qfIezZmd.css">
|
|
12
12
|
</head>
|
|
13
13
|
<body>
|
|
14
14
|
<div id="app"></div>
|
package/src/ui/server/index.js
CHANGED
|
@@ -8,17 +8,25 @@ import config from '../../config.js';
|
|
|
8
8
|
import chalk from 'chalk';
|
|
9
9
|
import fs from 'fs/promises';
|
|
10
10
|
import os from 'os';
|
|
11
|
-
|
|
11
|
+
import { Server } from 'socket.io';
|
|
12
|
+
import chokidar from 'chokidar';
|
|
12
13
|
// import { exec } from 'child_process';
|
|
13
14
|
|
|
14
15
|
const __filename = fileURLToPath(import.meta.url);
|
|
15
16
|
const __dirname = path.dirname(__filename);
|
|
16
17
|
const configManager = config; // 确保 configManager 可用
|
|
17
18
|
|
|
19
|
+
// 文件系统变动监控器
|
|
20
|
+
let watcher = null;
|
|
21
|
+
// 防抖计时器
|
|
22
|
+
let debounceTimer = null;
|
|
23
|
+
// 防抖延迟时间 (毫秒)
|
|
24
|
+
const DEBOUNCE_DELAY = 1000;
|
|
25
|
+
|
|
18
26
|
async function startUIServer() {
|
|
19
27
|
const app = express();
|
|
20
28
|
const httpServer = createServer(app);
|
|
21
|
-
|
|
29
|
+
const io = new Server(httpServer);
|
|
22
30
|
|
|
23
31
|
// 添加全局中间件来解析JSON请求体
|
|
24
32
|
app.use(express.json());
|
|
@@ -30,24 +38,6 @@ async function startUIServer() {
|
|
|
30
38
|
next();
|
|
31
39
|
});
|
|
32
40
|
|
|
33
|
-
// // 启动前端Vue应用
|
|
34
|
-
// const clientPath = path.join(__dirname, '../client');
|
|
35
|
-
// console.log(`正在启动前端应用,路径: ${clientPath}`);
|
|
36
|
-
|
|
37
|
-
// const vueProcess = exec('npm run dev', { cwd: clientPath }, (error) => {
|
|
38
|
-
// if (error) {
|
|
39
|
-
// console.error('启动前端应用失败:', error);
|
|
40
|
-
// }
|
|
41
|
-
// });
|
|
42
|
-
|
|
43
|
-
// vueProcess.stdout.on('data', (data) => {
|
|
44
|
-
// console.log(`前端输出: ${data}`);
|
|
45
|
-
// });
|
|
46
|
-
|
|
47
|
-
// vueProcess.stderr.on('data', (data) => {
|
|
48
|
-
// console.error(`前端错误: ${data}`);
|
|
49
|
-
// });
|
|
50
|
-
|
|
51
41
|
// 静态文件服务
|
|
52
42
|
app.use(express.static(path.join(__dirname, '../public')));
|
|
53
43
|
|
|
@@ -198,7 +188,6 @@ async function startUIServer() {
|
|
|
198
188
|
// 新增切换工作目录接口
|
|
199
189
|
app.post('/api/change_directory', async (req, res) => {
|
|
200
190
|
try {
|
|
201
|
-
|
|
202
191
|
const { path } = req.body;
|
|
203
192
|
|
|
204
193
|
if (!path) {
|
|
@@ -212,12 +201,22 @@ async function startUIServer() {
|
|
|
212
201
|
// 检查新目录是否是Git仓库
|
|
213
202
|
try {
|
|
214
203
|
await execGitCommand('git rev-parse --is-inside-work-tree');
|
|
204
|
+
|
|
205
|
+
// 初始化文件监控
|
|
206
|
+
initFileSystemWatcher();
|
|
207
|
+
|
|
215
208
|
res.json({
|
|
216
209
|
success: true,
|
|
217
210
|
directory: newDirectory,
|
|
218
211
|
isGitRepo: true
|
|
219
212
|
});
|
|
220
213
|
} catch (error) {
|
|
214
|
+
// 不是Git仓库,停止监控
|
|
215
|
+
if (watcher) {
|
|
216
|
+
watcher.close().catch(err => console.error('关闭监控器失败:', err));
|
|
217
|
+
watcher = null;
|
|
218
|
+
}
|
|
219
|
+
|
|
221
220
|
res.json({
|
|
222
221
|
success: true,
|
|
223
222
|
directory: newDirectory,
|
|
@@ -482,6 +481,46 @@ async function startUIServer() {
|
|
|
482
481
|
}
|
|
483
482
|
});
|
|
484
483
|
|
|
484
|
+
// 添加单个文件到暂存区
|
|
485
|
+
app.post('/api/add-file', async (req, res) => {
|
|
486
|
+
try {
|
|
487
|
+
const { filePath } = req.body;
|
|
488
|
+
|
|
489
|
+
if (!filePath) {
|
|
490
|
+
return res.status(400).json({
|
|
491
|
+
success: false,
|
|
492
|
+
error: '缺少文件路径参数'
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// 执行 git add 命令添加特定文件
|
|
497
|
+
await execGitCommand(`git add "${filePath}"`);
|
|
498
|
+
res.json({ success: true });
|
|
499
|
+
} catch (error) {
|
|
500
|
+
res.status(500).json({ success: false, error: error.message });
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
// 从暂存区移除单个文件
|
|
505
|
+
app.post('/api/unstage-file', async (req, res) => {
|
|
506
|
+
try {
|
|
507
|
+
const { filePath } = req.body;
|
|
508
|
+
|
|
509
|
+
if (!filePath) {
|
|
510
|
+
return res.status(400).json({
|
|
511
|
+
success: false,
|
|
512
|
+
error: '缺少文件路径参数'
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// 执行 git reset HEAD 命令移除特定文件的暂存
|
|
517
|
+
await execGitCommand(`git reset HEAD -- "${filePath}"`);
|
|
518
|
+
res.json({ success: true });
|
|
519
|
+
} catch (error) {
|
|
520
|
+
res.status(500).json({ success: false, error: error.message });
|
|
521
|
+
}
|
|
522
|
+
});
|
|
523
|
+
|
|
485
524
|
// 推送更改
|
|
486
525
|
app.post('/api/push', async (req, res) => {
|
|
487
526
|
try {
|
|
@@ -502,9 +541,40 @@ async function startUIServer() {
|
|
|
502
541
|
// 由前端统一使用该接口
|
|
503
542
|
|
|
504
543
|
// 修改 git log 命令,添加 %ae 参数来获取作者邮箱
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
544
|
+
// 使用 %H 获取完整哈希值(而不是短哈希 %h)
|
|
545
|
+
// 使用 %B 获取完整提交信息(包括正文)
|
|
546
|
+
const { stdout } = await execGitCommand(`git log --all --pretty=format:"%H|%an|%ae|%ad|%B|%D" --date=short ${limit}`);
|
|
547
|
+
|
|
548
|
+
// 分隔符改为使用特殊标记,因为提交信息中可能包含|字符
|
|
549
|
+
const recordSeparator = "\n<<<RECORD_SEPARATOR>>>\n";
|
|
550
|
+
const fieldSeparator = "<<<FIELD_SEPARATOR>>>";
|
|
551
|
+
|
|
552
|
+
// 预处理输出,替换提交记录之间的换行符
|
|
553
|
+
const processedOutput = stdout.replace(/\n(?=[a-f0-9]{40}\|)/g, recordSeparator);
|
|
554
|
+
|
|
555
|
+
// 按记录分隔符拆分日志条目
|
|
556
|
+
const logEntries = processedOutput.split(recordSeparator);
|
|
557
|
+
|
|
558
|
+
const logs = logEntries.map(entry => {
|
|
559
|
+
// 使用第一个|分隔哈希值,其余部分作为整体
|
|
560
|
+
const hashEndIndex = entry.indexOf('|');
|
|
561
|
+
const hash = entry.substring(0, hashEndIndex);
|
|
562
|
+
const restPart = entry.substring(hashEndIndex + 1);
|
|
563
|
+
|
|
564
|
+
// 使用最后一个|分隔引用信息,其余部分作为整体
|
|
565
|
+
const lastPipeIndex = restPart.lastIndexOf('|');
|
|
566
|
+
const refs = restPart.substring(lastPipeIndex + 1).trim();
|
|
567
|
+
const middlePart = restPart.substring(0, lastPipeIndex);
|
|
568
|
+
|
|
569
|
+
// 分隔作者、邮箱、日期和提交信息
|
|
570
|
+
const parts = middlePart.split('|');
|
|
571
|
+
|
|
572
|
+
// 确保即使分隔出的部分不足,也能提供默认值
|
|
573
|
+
const author = parts[0] || '';
|
|
574
|
+
const email = parts[1] || '';
|
|
575
|
+
const date = parts[2] || '';
|
|
576
|
+
// 提交信息可能包含多行
|
|
577
|
+
const message = parts.slice(3).join('|').trim();
|
|
508
578
|
|
|
509
579
|
// 从引用信息中提取分支名称
|
|
510
580
|
let branch = null;
|
|
@@ -515,6 +585,7 @@ async function startUIServer() {
|
|
|
515
585
|
|
|
516
586
|
return { hash, author, email, date, message, branch };
|
|
517
587
|
});
|
|
588
|
+
|
|
518
589
|
res.json(logs);
|
|
519
590
|
} catch (error) {
|
|
520
591
|
res.status(500).json({ error: error.message });
|
|
@@ -630,6 +701,77 @@ async function startUIServer() {
|
|
|
630
701
|
}
|
|
631
702
|
});
|
|
632
703
|
|
|
704
|
+
// 获取提交的文件列表
|
|
705
|
+
app.get('/api/commit-files', async (req, res) => {
|
|
706
|
+
try {
|
|
707
|
+
const hash = req.query.hash;
|
|
708
|
+
|
|
709
|
+
if (!hash) {
|
|
710
|
+
return res.status(400).json({
|
|
711
|
+
success: false,
|
|
712
|
+
error: '缺少提交哈希参数'
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
console.log(`获取提交文件列表: hash=${hash}`);
|
|
717
|
+
|
|
718
|
+
// 执行命令获取提交中修改的文件列表
|
|
719
|
+
const { stdout } = await execGitCommand(`git show --name-only --format="" ${hash}`);
|
|
720
|
+
|
|
721
|
+
// 将输出按行分割,并过滤掉空行
|
|
722
|
+
const files = stdout.split('\n').filter(line => line.trim());
|
|
723
|
+
console.log(`找到${files.length}个文件:`, files);
|
|
724
|
+
|
|
725
|
+
res.json({
|
|
726
|
+
success: true,
|
|
727
|
+
files
|
|
728
|
+
});
|
|
729
|
+
} catch (error) {
|
|
730
|
+
console.error('获取提交文件列表失败:', error);
|
|
731
|
+
res.status(500).json({
|
|
732
|
+
success: false,
|
|
733
|
+
error: `获取提交文件列表失败: ${error.message}`
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
});
|
|
737
|
+
|
|
738
|
+
// 获取提交中特定文件的差异
|
|
739
|
+
app.get('/api/commit-file-diff', async (req, res) => {
|
|
740
|
+
try {
|
|
741
|
+
const hash = req.query.hash;
|
|
742
|
+
const filePath = req.query.file;
|
|
743
|
+
|
|
744
|
+
if (!hash || !filePath) {
|
|
745
|
+
return res.status(400).json({
|
|
746
|
+
success: false,
|
|
747
|
+
error: '缺少必要参数'
|
|
748
|
+
});
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
console.log(`获取提交文件差异: hash=${hash}, file=${filePath}`);
|
|
752
|
+
|
|
753
|
+
// 执行命令获取文件差异,-p显示补丁,限定文件路径
|
|
754
|
+
const { stdout } = await execGitCommand(`git show ${hash} -- "${filePath}"`);
|
|
755
|
+
|
|
756
|
+
console.log(`获取到差异内容,长度: ${stdout.length}`);
|
|
757
|
+
// 如果差异内容太长,只打印前100个字符
|
|
758
|
+
if (stdout.length > 100) {
|
|
759
|
+
console.log(`差异内容预览: ${stdout.substring(0, 100)}...`);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
res.json({
|
|
763
|
+
success: true,
|
|
764
|
+
diff: stdout
|
|
765
|
+
});
|
|
766
|
+
} catch (error) {
|
|
767
|
+
console.error('获取提交文件差异失败:', error);
|
|
768
|
+
res.status(500).json({
|
|
769
|
+
success: false,
|
|
770
|
+
error: `获取提交文件差异失败: ${error.message}`
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
});
|
|
774
|
+
|
|
633
775
|
// 添加清理Git锁定文件的接口
|
|
634
776
|
app.post('/api/remove-lock', async (req, res) => {
|
|
635
777
|
try {
|
|
@@ -715,24 +857,121 @@ async function startUIServer() {
|
|
|
715
857
|
});
|
|
716
858
|
|
|
717
859
|
// Socket.io 实时更新
|
|
718
|
-
|
|
719
|
-
|
|
860
|
+
io.on('connection', (socket) => {
|
|
861
|
+
console.log('客户端已连接:', socket.id);
|
|
862
|
+
|
|
863
|
+
// 当客户端连接时,立即发送一次Git状态
|
|
864
|
+
getAndBroadcastStatus();
|
|
720
865
|
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
866
|
+
// 客户端可以请求开始/停止监控
|
|
867
|
+
socket.on('start_monitoring', () => {
|
|
868
|
+
if (!watcher) {
|
|
869
|
+
initFileSystemWatcher();
|
|
870
|
+
socket.emit('monitoring_status', { active: true });
|
|
871
|
+
}
|
|
872
|
+
});
|
|
873
|
+
|
|
874
|
+
socket.on('stop_monitoring', () => {
|
|
875
|
+
if (watcher) {
|
|
876
|
+
watcher.close().catch(err => console.error('关闭监控器失败:', err));
|
|
877
|
+
watcher = null;
|
|
878
|
+
socket.emit('monitoring_status', { active: false });
|
|
879
|
+
}
|
|
880
|
+
});
|
|
730
881
|
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
882
|
+
// 客户端断开连接
|
|
883
|
+
socket.on('disconnect', () => {
|
|
884
|
+
console.log('客户端已断开连接:', socket.id);
|
|
885
|
+
});
|
|
886
|
+
});
|
|
887
|
+
|
|
888
|
+
// 初始化文件系统监控
|
|
889
|
+
function initFileSystemWatcher() {
|
|
890
|
+
// 停止已有的监控器
|
|
891
|
+
if (watcher) {
|
|
892
|
+
watcher.close().catch(err => console.error('关闭旧监控器失败:', err));
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
try {
|
|
896
|
+
// 获取当前工作目录
|
|
897
|
+
const currentDir = process.cwd();
|
|
898
|
+
|
|
899
|
+
console.log(`初始化文件系统监控器,路径: ${currentDir}`);
|
|
900
|
+
|
|
901
|
+
// 检查是否是Git仓库
|
|
902
|
+
try {
|
|
903
|
+
execGitCommand('git rev-parse --is-inside-work-tree');
|
|
904
|
+
} catch (error) {
|
|
905
|
+
console.log('当前目录不是Git仓库,不启动监控');
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// 使用chokidar监控文件变动
|
|
910
|
+
watcher = chokidar.watch(currentDir, {
|
|
911
|
+
ignored: [
|
|
912
|
+
/(^|[\/\\])\../, // 忽略.开头的文件和目录
|
|
913
|
+
'**/node_modules/**', // 忽略node_modules
|
|
914
|
+
'**/.git/**', // 忽略.git目录
|
|
915
|
+
],
|
|
916
|
+
persistent: true,
|
|
917
|
+
ignoreInitial: true, // 忽略初始扫描时的文件
|
|
918
|
+
awaitWriteFinish: {
|
|
919
|
+
stabilityThreshold: 300, // 等待文件写入完成的时间
|
|
920
|
+
pollInterval: 100 // 轮询间隔
|
|
921
|
+
}
|
|
922
|
+
});
|
|
923
|
+
|
|
924
|
+
// 合并所有变动事件到一个处理程序
|
|
925
|
+
const events = ['add', 'change', 'unlink'];
|
|
926
|
+
events.forEach(event => {
|
|
927
|
+
watcher.on(event, path => {
|
|
928
|
+
console.log(`检测到文件变动 [${event}]: ${path}`);
|
|
929
|
+
debouncedNotifyChanges();
|
|
930
|
+
});
|
|
931
|
+
});
|
|
932
|
+
|
|
933
|
+
watcher.on('error', error => {
|
|
934
|
+
console.error('文件监控错误:', error);
|
|
935
|
+
});
|
|
936
|
+
|
|
937
|
+
console.log('文件系统监控器已启动');
|
|
938
|
+
} catch (error) {
|
|
939
|
+
console.error('启动文件监控失败:', error);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
// 获取并广播Git状态
|
|
944
|
+
async function getAndBroadcastStatus() {
|
|
945
|
+
try {
|
|
946
|
+
// 获取常规状态
|
|
947
|
+
const { stdout: statusOutput } = await execGitCommand('git status');
|
|
948
|
+
|
|
949
|
+
// 获取porcelain格式状态
|
|
950
|
+
const { stdout: porcelainOutput } = await execGitCommand('git status --porcelain');
|
|
951
|
+
|
|
952
|
+
// 广播到所有连接的客户端
|
|
953
|
+
io.emit('git_status_update', {
|
|
954
|
+
status: statusOutput,
|
|
955
|
+
porcelain: porcelainOutput,
|
|
956
|
+
timestamp: new Date().toISOString()
|
|
957
|
+
});
|
|
958
|
+
|
|
959
|
+
console.log('已广播Git状态更新');
|
|
960
|
+
} catch (error) {
|
|
961
|
+
console.error('获取或广播Git状态失败:', error);
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
// 防抖处理函数
|
|
966
|
+
function debouncedNotifyChanges() {
|
|
967
|
+
if (debounceTimer) {
|
|
968
|
+
clearTimeout(debounceTimer);
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
debounceTimer = setTimeout(() => {
|
|
972
|
+
getAndBroadcastStatus();
|
|
973
|
+
}, DEBOUNCE_DELAY);
|
|
974
|
+
}
|
|
736
975
|
|
|
737
976
|
// 启动服务器
|
|
738
977
|
const PORT = 3000;
|
|
@@ -742,6 +981,10 @@ async function startUIServer() {
|
|
|
742
981
|
console.log(chalk.green(` 访问地址: http://localhost:${PORT}`));
|
|
743
982
|
console.log(chalk.green(` 启动时间: ${new Date().toLocaleString()}`));
|
|
744
983
|
console.log(chalk.green('======================================'));
|
|
984
|
+
|
|
985
|
+
// 启动文件监控
|
|
986
|
+
initFileSystemWatcher();
|
|
987
|
+
|
|
745
988
|
open(`http://localhost:${PORT}`);
|
|
746
989
|
}).on('error', async (err) => {
|
|
747
990
|
if (err.code === 'EADDRINUSE') {
|
|
@@ -756,6 +999,10 @@ async function startUIServer() {
|
|
|
756
999
|
console.log(chalk.green(` 访问地址: http://localhost:${newPort}`));
|
|
757
1000
|
console.log(chalk.green(` 启动时间: ${new Date().toLocaleString()}`));
|
|
758
1001
|
console.log(chalk.green('======================================'));
|
|
1002
|
+
|
|
1003
|
+
// 启动文件监控
|
|
1004
|
+
initFileSystemWatcher();
|
|
1005
|
+
|
|
759
1006
|
open(`http://localhost:${newPort}`);
|
|
760
1007
|
resolve();
|
|
761
1008
|
}).on('error', (e) => {
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import{d as Me,r as i,E as o,a as we,c as he,o as be,b as w,e as p,f as e,g as te,h as s,i as Ie,w as n,u as r,j as Ge,t as P,k as le,l as V,m as nt,F as se,n as oe,p as Re,q as Fe,s as Je,v as ze,x as Be,y as it,z as De,A as ee,B as rt,C as He,D as ct,G as ut,H as dt,I as We,J as Ze,K as qe,L as je,M as Ye,N as pt,O as Ke,P as Qe,Q as _e,R as ft,S as Xe,T as mt,U as Ne,V as vt,W as gt,X as yt,Y as pe,Z as ht,_ as _t,$ as wt,a0 as bt,a1 as $t,a2 as Ct}from"./vendor-BfXVsoKv.js";(function(){const h=document.createElement("link").relList;if(h&&h.supports&&h.supports("modulepreload"))return;for(const a of document.querySelectorAll('link[rel="modulepreload"]'))y(a);new MutationObserver(a=>{for(const x of a)if(x.type==="childList")for(const L of x.addedNodes)L.tagName==="LINK"&&L.rel==="modulepreload"&&y(L)}).observe(document,{childList:!0,subtree:!0});function G(a){const x={};return a.integrity&&(x.integrity=a.integrity),a.referrerPolicy&&(x.referrerPolicy=a.referrerPolicy),a.crossOrigin==="use-credentials"?x.credentials="include":a.crossOrigin==="anonymous"?x.credentials="omit":x.credentials="same-origin",x}function y(a){if(a.ep)return;a.ep=!0;const x=G(a);fetch(a.href,x)}})();const ie=Me("git",()=>{const F=i(""),h=i([]),G=i(""),y=i(""),a=i(!1),x=i(!1),L=i(!1),U=i(0);function q(){F.value="",h.value=[],G.value="",y.value="",a.value=!1,x.value=!1,L.value=!1,U.value=0}async function R(){const f=Date.now();if(f-U.value<1e3)return console.log("使用缓存的Git仓库状态:",L.value?"是":"不是"),L.value;try{const M=await(await fetch("/api/current_directory")).json();return L.value=M.isGitRepo===!0,U.value=f,console.log(`当前目录${L.value?"是":"不是"}Git仓库`),L.value}catch(g){return console.error("检查Git仓库状态失败:",g),L.value=!1,U.value=f,!1}}async function T(){try{const g=await(await fetch("/api/branch")).json();g.branch&&(F.value=g.branch)}catch(f){console.error("获取分支信息失败:",f)}}async function D(){try{const g=await(await fetch("/api/branches")).json();g.branches&&Array.isArray(g.branches)&&(h.value=g.branches)}catch(f){console.error("获取所有分支信息失败:",f)}}async function j(f){console.log("切换到分支:",f);try{a.value=!0;const M=await(await fetch("/api/checkout",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({branch:f})})).json();return M.success?(o({message:`已切换到分支: ${f}`,type:"success"}),T(),!0):(o({message:`切换分支失败: ${M.error}`,type:"error"}),!1)}catch(g){return o({message:`切换分支失败: ${g.message}`,type:"error"}),!1}finally{a.value=!1}}async function b(){try{const g=await(await fetch("/api/user-info")).json();g.name&&g.email&&(G.value=g.name,y.value=g.email)}catch(f){console.error("获取用户信息失败:",f)}}async function W(f,g){if(!f.trim())return o({message:"分支名称不能为空",type:"warning"}),!1;try{x.value=!0;const $=await(await fetch("/api/create-branch",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({newBranchName:f,baseBranch:g||F.value})})).json();return $.success?(o({message:`已创建并切换到分支: ${f}`,type:"success"}),T(),D(),!0):(o({message:`创建分支失败: ${$.error}`,type:"error"}),!1)}catch(M){return o({message:`创建分支失败: ${M.message}`,type:"error"}),!1}finally{x.value=!1}}async function C(){await R()?(T(),D(),b()):(F.value="",h.value=[],G.value="",y.value="")}async function E(){try{const g=await(await fetch("/api/clear-user-config",{method:"POST"})).json();return g.success?(G.value="",y.value="",o({message:"已清除Git用户配置",type:"success"}),!0):(o({message:`清除配置失败: ${g.error}`,type:"error"}),!1)}catch(f){return o({message:`清除配置失败: ${f.message}`,type:"error"}),!1}}async function I(f,g){try{const $=await(await fetch("/api/restore-user-config",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:f,email:g})})).json();return $.success?(G.value=f,y.value=g,o({message:"已恢复Git用户配置",type:"success"}),!0):(o({message:`恢复配置失败: ${$.error}`,type:"error"}),!1)}catch(M){return o({message:`恢复配置失败: ${M.message}`,type:"error"}),!1}}return{currentBranch:F,allBranches:h,userName:G,userEmail:y,isChangingBranch:a,isCreatingBranch:x,isGitRepo:L,lastCheckedTime:U,$reset:q,checkGitRepo:R,getCurrentBranch:T,getAllBranches:D,changeBranch:j,getUserInfo:b,createBranch:W,loadInitialData:C,clearUserConfig:E,restoreUserConfig:I}}),Le=300,Ee=Me("gitLog",()=>{const F=ie(),h=i([]),G=i({staged:[],unstaged:[],untracked:[]}),y=i(""),a=i([]),x=i(!1),L=i(!1),U=i(!1),q=i(!1),R=i(!1),T=i(!1);function D(m){if(m===void 0||m===""){a.value=[];return}const u=m.split(`
|
|
2
|
-
`),A=[];for(const v of u){const _=v.match(/^([ MADRCU\?]{2})\s+(.+)$/);if(_){let z="";const B=_[1].trim();B==="M"||B==="MM"||B==="AM"||B==="RM"?z="modified":B==="A"||B==="AA"?z="added":B==="D"||B==="AD"||B==="DA"?z="deleted":B==="??"?z="untracked":z="other",A.push({path:_[2],type:z})}}a.value=A}async function j(){if(!F.isGitRepo){console.log("当前目录不是Git仓库,跳过加载提交历史");return}try{x.value=!0,console.log("开始加载提交历史...");const u=await(await fetch("/api/log")).json();u&&Array.isArray(u)&&(h.value=u),console.log(`提交历史加载完成,共 ${h.value.length} 条记录`)}catch(m){console.error("获取提交历史失败:",m),o({message:`获取提交历史失败: ${m.message}`,type:"error"})}finally{x.value=!1}}async function b(){if(!F.isGitRepo){console.log("当前目录不是Git仓库,跳过加载Git状态");return}try{L.value=!0;const u=await(await fetch("/api/status")).json();u.status&&(y.value=u.status,G.value={staged:u.status.staged||[],unstaged:u.status.unstaged||[],untracked:u.status.untracked||[]}),await W()}catch(m){console.error("获取Git状态失败:",m),o({message:`获取Git状态失败: ${m.message}`,type:"error"})}finally{L.value=!1}}async function W(){if(!F.isGitRepo){console.log("当前目录不是Git仓库,跳过加载Git状态");return}try{const u=await(await fetch("/api/status_porcelain")).json();u.status!==void 0?D(u.status):a.value=[]}catch(m){console.error("获取Git状态(porcelain)失败:",m),o({message:`获取Git状态(porcelain)失败: ${m.message}`,type:"error"}),a.value=[]}}async function C(){if(!F.isGitRepo)return o.warning("当前目录不是Git仓库"),!1;try{U.value=!0;const u=await(await fetch("/api/add",{method:"POST"})).json();return u.success?(o({message:"文件已添加到暂存区",type:"success"}),b(),!0):(o({message:`添加文件失败: ${u.error}`,type:"error"}),!1)}catch(m){return o({message:`添加文件失败: ${m.message}`,type:"error"}),!1}finally{U.value=!1}}function E(m){return new Promise(u=>setTimeout(u,m))}async function I(m,u=!1){if(!F.isGitRepo)return o.warning("当前目录不是Git仓库"),!1;try{q.value=!0;const v=await(await fetch("/api/commit",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({message:m,hasNewlines:m.includes(`
|
|
3
|
-
`),noVerify:u})})).json();return v.success?(o({message:"提交成功",type:"success"}),b(),j(),!0):(o({message:`提交失败: ${v.error}`,type:"error"}),!1)}catch(A){return o({message:`提交失败: ${A.message}`,type:"error"}),!1}finally{q.value=!1}}async function f(){if(!F.isGitRepo)return o.warning("当前目录不是Git仓库"),!1;try{R.value=!0;const u=await(await fetch("/api/push",{method:"POST"})).json();return u.success?(o({message:"推送成功",type:"success"}),b(),j(),!0):(o({message:`推送失败: ${u.error}`,type:"error"}),!1)}catch(m){return o({message:`推送失败: ${m.message}`,type:"error"}),!1}finally{R.value=!1}}async function g(m,u=!1){return await C()?(await E(Le),await I(m,u)):!1}async function M(m,u=!1){try{return!await C()||(await E(Le),!await I(m,u))?!1:(await E(Le),await f())}catch(A){try{(await(await fetch("/api/remove-lock",{method:"POST"})).json()).success&&o({message:"已清理锁定文件,请重试操作",type:"warning"})}catch(v){console.error("清理锁定文件失败:",v)}return o({message:`操作失败: ${A.message}`,type:"error"}),!1}}async function $(){if(!F.isGitRepo)return o.warning("当前目录不是Git仓库"),!1;try{T.value=!0;const u=await(await fetch("/api/reset-head",{method:"POST"})).json();return u.success?(o({message:"已重置暂存区",type:"success"}),b(),!0):(o({message:`重置暂存区失败: ${u.error}`,type:"error"}),!1)}catch(m){return o({message:`重置暂存区失败: ${m.message}`,type:"error"}),!1}finally{T.value=!1}}async function l(m){if(!F.isGitRepo)return o.warning("当前目录不是Git仓库"),!1;try{T.value=!0;const A=await(await fetch("/api/reset-to-remote",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({branch:m})})).json();return A.success?(o({message:`已重置分支 ${m} 到远程状态`,type:"success"}),b(),j(),!0):(o({message:`重置分支失败: ${A.error}`,type:"error"}),!1)}catch(u){return o({message:`重置分支失败: ${u.message}`,type:"error"}),!1}finally{T.value=!1}}return{log:h,status:G,statusText:y,fileList:a,isLoadingLog:x,isLoadingStatus:L,isAddingFiles:U,isResetting:T,isCommiting:q,isPushing:R,fetchLog:j,fetchStatus:b,fetchStatusPorcelain:W,parseStatusPorcelain:D,addToStage:C,commitChanges:I,pushToRemote:f,addAndCommit:g,addCommitAndPush:M,resetHead:$,resetToRemote:l}}),kt={class:"card"},St={class:"current-directory"},Tt={class:"status-header"},Vt={class:"status-box"},Gt={key:0,class:"file-list"},Lt=["onClick"],xt={class:"file-type"},Bt={class:"file-path"},Dt={class:"file-actions"},jt={class:"directory-buttons"},Rt={class:"browser-current-path"},zt={key:0,class:"browser-error"},Et={class:"directory-browser"},At={class:"browser-nav"},Ot={class:"directory-items-container"},Pt={class:"directory-items"},Ut=["onClick"],Nt={class:"diff-content"},Mt=["innerHTML"],It={key:1,class:"no-diff"},Ft={class:"file-navigation"},Jt={class:"file-counter"},Ht=we({__name:"GitStatus",props:{initialDirectory:{type:String,default:""}},setup(F,{expose:h}){const G=F,y=Ee(),a=ie(),x=he(()=>y.isLoadingStatus),L=i(""),U=i(""),q=i(!1),R=i(!1),T=i(-1),D=i(!1),j=i(""),b=i(!1),W=i(!1),C=i(""),E=i([]),I=i(!1),f=i(""),g=i(G.initialDirectory||"");async function M(){try{if(!g.value){const d=await(await fetch("/api/current_directory")).json();g.value=d.directory||"未知目录"}if(!a.isGitRepo)return;await y.fetchStatus(),o({message:"Git 状态已刷新",type:"success"})}catch(k){o({message:"刷新失败: "+k.message,type:"error"})}}function $(k){if(!k)return"";const d=k.split(`
|
|
4
|
-
`);function Z(O){return O.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}return d.map(O=>{const Q=Z(O);return O.startsWith("diff --git")?`<div class="diff-header">${Q}</div>`:O.startsWith("---")?`<div class="diff-old-file">${Q}</div>`:O.startsWith("+++")?`<div class="diff-new-file">${Q}</div>`:O.startsWith("@@")?`<div class="diff-hunk-header">${Q}</div>`:O.startsWith("+")?`<div class="diff-added">${Q}</div>`:O.startsWith("-")?`<div class="diff-removed">${Q}</div>`:`<div class="diff-context">${Q}</div>`}).join("")}async function l(k){try{R.value=!0,L.value=k,T.value=y.fileList.findIndex(O=>O.path===k);const Z=await(await fetch(`/api/diff?file=${encodeURIComponent(k)}`)).json();U.value=Z.diff||"没有变更",q.value=!0}catch(d){o({message:"获取文件差异失败: "+d.message,type:"error"}),U.value="获取差异失败: "+d.message}finally{R.value=!1}}async function m(){if(y.fileList.length===0||T.value<=0)return;const k=T.value-1,d=y.fileList[k];await l(d.path)}async function u(){if(y.fileList.length===0||T.value>=y.fileList.length-1)return;const k=T.value+1,d=y.fileList[k];await l(d.path)}function A(){j.value=g.value,D.value=!0}function v(){f.value="",C.value=j.value||g.value,W.value=!0,_(C.value)}async function _(k){try{I.value=!0,f.value="";let d=k;/^[A-Za-z]:$/.test(d)&&(d+="/");const Z=await fetch(`/api/browse_directory?path=${encodeURIComponent(d)}`);if(Z.status===403){const Q=await Z.json();f.value=Q.error||"目录浏览功能未启用";return}if(!Z.ok){const Q=await Z.json();f.value=Q.error||"获取目录内容失败";return}const O=await Z.json();O.success?(E.value=O.items,C.value=O.currentPath):f.value=O.error||"获取目录内容失败"}catch(d){f.value=`获取目录内容失败: ${d.message}`}finally{I.value=!1}}function z(){if(/^[A-Za-z]:$/.test(C.value)||/^[A-Za-z]:[\\/]$/.test(C.value)||C.value==="/")return;let k=C.value.split(/[/\\]/);k.pop();let d=k.join("/");k.length===1&&/^[A-Za-z]:$/.test(k[0])&&(d=k[0]+"/"),d&&_(d)}function B(k){k.type==="directory"&&_(k.path)}function J(){j.value=C.value,W.value=!1}async function K(){if(!j.value){o.warning("目录路径不能为空");return}try{b.value=!0;const d=await(await fetch("/api/change_directory",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:j.value})})).json();d.success?(o.success("已切换工作目录"),g.value=d.directory,D.value=!1,a.isGitRepo=d.isGitRepo,d.isGitRepo?(await Promise.all([a.getCurrentBranch(),a.getAllBranches(),a.getUserInfo()]),await M()):(o.warning("当前目录不是一个Git仓库"),a.$reset())):o.error(d.error||"切换目录失败")}catch(k){o.error(`切换目录失败: ${k.message}`)}finally{b.value=!1}}function ae(k){l(k.path)}function N(k){switch(k){case"added":return"新增";case"modified":return"修改";case"deleted":return"删除";case"untracked":return"未跟踪";default:return"其他"}}async function me(){await M()}async function Ce(k){try{await qe.confirm(`确定要撤回文件 "${k}" 的所有修改吗?此操作无法撤销。`,"撤回修改",{confirmButtonText:"确定",cancelButtonText:"取消",type:"warning"});const Z=await(await fetch("/api/revert_file",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({filePath:k})})).json();Z.success?(o.success("已撤回文件修改"),await M()):o.error(Z.error||"撤回文件修改失败")}catch(d){d.message!=="cancel"&&o.error(`撤回文件修改失败: ${d.message}`)}}return be(()=>{M()}),h({refreshStatus:me}),(k,d)=>{const Z=Ie,O=le,Q=Ze,ke=ze,Se=Je,Te=Fe,re=Re,ve=He;return p(),w("div",kt,[e("div",St,[s(Z,null,{default:n(()=>[s(r(Ge))]),_:1}),e("span",null,P(g.value),1),s(O,{type:"primary",size:"small",onClick:A,plain:""},{default:n(()=>d[4]||(d[4]=[V(" 切换目录 ")])),_:1})]),e("div",Tt,[d[5]||(d[5]=e("h2",null,"Git 状态(git status)",-1)),s(O,{type:"primary",icon:r(nt),circle:"",size:"small",onClick:me,loading:x.value},null,8,["icon","loading"])]),e("div",Vt,P(r(a).isGitRepo?r(y).statusText||"加载中...":"当前目录不是一个Git仓库"),1),r(y).fileList.length?(p(),w("div",Gt,[(p(!0),w(se,null,oe(r(y).fileList,H=>(p(),w("div",{key:H.path,class:De(["file-item",H.type])},[e("div",{class:"file-info",onClick:ge=>ae(H)},[e("span",xt,P(N(H.type)),1),e("span",Bt,P(H.path),1)],8,Lt),e("div",Dt,[s(Q,{content:"撤回修改",placement:"top","hide-after":1e3},{default:n(()=>[s(O,{type:"danger",size:"small",icon:r(We),circle:"",onClick:dt(ge=>Ce(H.path),["stop"])},null,8,["icon","onClick"])]),_:2},1024)])],2))),128))])):te("",!0),s(re,{modelValue:D.value,"onUpdate:modelValue":d[1]||(d[1]=H=>D.value=H),title:"切换工作目录",width:"500px"},{default:n(()=>[s(Te,null,{default:n(()=>[s(Se,{label:"目录路径"},{default:n(()=>[s(ke,{modelValue:j.value,"onUpdate:modelValue":d[0]||(d[0]=H=>j.value=H),placeholder:"请输入目录路径",clearable:""},null,8,["modelValue"]),e("div",jt,[s(O,{onClick:v,type:"primary",plain:"",class:"no-padding-left"},{default:n(()=>[s(Z,null,{default:n(()=>[s(r(Ge))]),_:1}),d[6]||(d[6]=V(" 浏览 "))]),_:1}),s(O,{onClick:K,loading:b.value,type:"primary"},{default:n(()=>d[7]||(d[7]=[V(" 切换 ")])),_:1},8,["loading"])])]),_:1})]),_:1})]),_:1},8,["modelValue"]),s(re,{modelValue:W.value,"onUpdate:modelValue":d[2]||(d[2]=H=>W.value=H),title:"浏览目录",width:"600px"},{default:n(()=>[e("div",Rt,[e("span",null,"当前路径: "+P(C.value),1)]),f.value?(p(),w("div",zt,P(f.value),1)):te("",!0),Be((p(),w("div",Et,[e("div",At,[s(O,{onClick:z,disabled:!C.value||I.value,size:"small",class:"no-padding-left"},{default:n(()=>[s(Z,null,{default:n(()=>[s(r(it))]),_:1}),d[8]||(d[8]=V(" 上级目录 "))]),_:1},8,["disabled"]),s(O,{onClick:J,type:"primary",size:"small",class:"no-padding-left"},{default:n(()=>d[9]||(d[9]=[V(" 选择当前目录 ")])),_:1})]),e("div",Ot,[e("ul",Pt,[(p(!0),w(se,null,oe(E.value,H=>(p(),w("li",{key:H.path,class:De(["directory-item",H.type]),onClick:ge=>B(H)},[H.type==="directory"?(p(),ee(Z,{key:0},{default:n(()=>[s(r(Ge))]),_:1})):(p(),ee(Z,{key:1},{default:n(()=>[s(r(rt))]),_:1})),e("span",null,P(H.name),1)],10,Ut))),128))])])])),[[ve,I.value]])]),_:1},8,["modelValue"]),s(re,{modelValue:q.value,"onUpdate:modelValue":d[3]||(d[3]=H=>q.value=H),title:`文件差异: ${L.value}`,width:"80%","destroy-on-close":""},{default:n(()=>[Be((p(),w("div",Nt,[U.value?(p(),w("div",{key:0,innerHTML:$(U.value),class:"diff-formatted"},null,8,Mt)):(p(),w("div",It,"该文件没有差异或是新文件"))])),[[ve,R.value]]),e("div",Ft,[s(O,{icon:r(ct),onClick:m,disabled:T.value<=0||r(y).fileList.length===0,circle:""},null,8,["icon","disabled"]),e("span",Jt,P(T.value+1)+" / "+P(r(y).fileList.length),1),s(O,{icon:r(ut),onClick:u,disabled:T.value>=r(y).fileList.length-1||r(y).fileList.length===0,circle:""},null,8,["icon","disabled"])])]),_:1},8,["modelValue","title"])])}}}),$e=(F,h)=>{const G=F.__vccOpts||F;for(const[y,a]of h)G[y]=a;return G},Wt=$e(Ht,[["__scopeId","data-v-bcbbf547"]]),Zt={class:"card"},qt={class:"layout-container"},Yt={key:0,class:"git-config-warning"},Kt={class:"commit-section"},Qt={class:"commit-options"},Xt={class:"options-row"},es={class:"commit-mode-toggle"},ts={class:"no-verify-toggle"},ss={key:0,class:"commit-form"},as={key:1,class:"standard-commit-form"},ls={class:"standard-commit-header"},os={class:"scope-container"},ns={class:"description-container"},is={class:"preview-section"},rs={class:"preview-content"},cs={class:"preview-content code-command"},us={class:"actions-section"},ds={class:"action-groups"},ps={class:"action-group"},fs={class:"group-buttons"},ms={class:"action-group"},vs={class:"group-buttons"},gs={class:"action-group"},ys={class:"group-buttons"},hs={class:"template-container"},_s={class:"template-form"},ws={class:"template-form-buttons"},bs={class:"template-list"},$s={class:"template-content"},Cs={class:"template-actions"},ks={class:"template-container"},Ss={class:"template-form"},Ts={class:"template-form-buttons"},Vs={class:"template-list"},Gs={class:"template-content"},Ls={class:"template-actions"},xs=we({__name:"CommitForm",setup(F){const h=Ee(),G=ie(),y=i(""),a=i(!1),x=i("输入提交信息..."),L=i(""),U=i(!1),q=i("feat"),R=i(""),T=i(""),D=i(""),j=i(""),b=i([]),W=i(!1),C=i(""),E=i(!1),I=i(""),f=i(-1),g=i([]),M=i(!1),$=i(""),l=i(!1),m=i(""),u=i(-1),A=i(!1),v=[{value:"feat",label:"feat: 新功能"},{value:"fix",label:"fix: 修复bug"},{value:"docs",label:"docs: 文档修改"},{value:"style",label:"style: 样式修改"},{value:"refactor",label:"refactor: 代码重构"},{value:"test",label:"test: 测试代码"},{value:"chore",label:"chore: 构建/工具修改"}];je(U,c=>{localStorage.setItem("zen-gitsync-standard-commit",c.toString())}),je(A,c=>{localStorage.setItem("zen-gitsync-skip-hooks",c.toString())});const _=he(()=>{if(!U.value)return y.value||L.value;let c=`${q.value||""}`;return R.value&&(c+=`(${R.value})`),c+=`: ${T.value}`,D.value&&(c+=`
|
|
5
|
-
|
|
6
|
-
${D.value}`),j.value&&(c+=`
|
|
7
|
-
|
|
8
|
-
${j.value}`),c}),z=he(()=>{let c=`git commit -m "${_.value}"`;return A.value&&(c+=" --no-verify"),c});async function B(){try{const t=await(await fetch("/api/config/getConfig")).json();x.value=`输入提交信息 (默认: ${t.defaultCommitMessage})`,L.value=t.defaultCommitMessage||"",t.descriptionTemplates&&Array.isArray(t.descriptionTemplates)&&(b.value=t.descriptionTemplates),t.scopeTemplates&&Array.isArray(t.scopeTemplates)&&(g.value=t.scopeTemplates)}catch(c){console.error("加载配置失败:",c)}}async function J(){if(!C.value.trim()){o({message:"请输入模板内容",type:"warning"});return}try{if(E.value)await K();else{if(b.value.includes(C.value)){o({message:"该模板已存在",type:"warning"});return}b.value.push(C.value);const t=await(await fetch("/api/config/save-template",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({template:C.value,type:"description"})})).json();t.success?(o({message:"模板保存成功!",type:"success"}),C.value=""):o({message:"模板保存失败: "+t.error,type:"error"})}}catch(c){o({message:"模板保存失败: "+c.message,type:"error"})}}async function K(){try{if(f.value>=0){const c=I.value,t=C.value;b.value[f.value]=t;const X=await(await fetch("/api/config/update-template",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({oldTemplate:c,newTemplate:t,type:"description"})})).json();X.success?(o({message:"模板更新成功!",type:"success"}),E.value=!1,I.value="",f.value=-1,C.value=""):o({message:"模板更新失败: "+X.error,type:"error"})}}catch(c){o({message:"模板更新失败: "+c.message,type:"error"})}}function ae(c,t){E.value=!0,I.value=c,f.value=t,C.value=c}function N(){E.value=!1,I.value="",f.value=-1,C.value=""}async function me(){if(!$.value.trim()){o({message:"请输入模板内容",type:"warning"});return}try{if(l.value)await Ce();else{if(g.value.includes($.value)){o({message:"该模板已存在",type:"warning"});return}g.value.push($.value);const t=await(await fetch("/api/config/save-template",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({template:$.value,type:"scope"})})).json();t.success?(o({message:"作用域模板保存成功!",type:"success"}),$.value=""):o({message:"作用域模板保存失败: "+t.error,type:"error"})}}catch(c){o({message:"作用域模板保存失败: "+c.message,type:"error"})}}async function Ce(){try{if(u.value>=0){const c=m.value,t=$.value;g.value[u.value]=t;const X=await(await fetch("/api/config/update-template",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({oldTemplate:c,newTemplate:t,type:"scope"})})).json();X.success?(o({message:"作用域模板更新成功!",type:"success"}),l.value=!1,m.value="",u.value=-1,$.value=""):o({message:"作用域模板更新失败: "+X.error,type:"error"})}}catch(c){o({message:"作用域模板更新失败: "+c.message,type:"error"})}}function k(c,t){l.value=!0,m.value=c,u.value=t,$.value=c}function d(){l.value=!1,m.value="",u.value=-1,$.value=""}async function Z(c){try{const t=b.value.indexOf(c);t!==-1&&b.value.splice(t,1);const X=await(await fetch("/api/config/delete-template",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({template:c,type:"description"})})).json();X.success?o({message:"模板删除成功!",type:"success"}):o({message:"模板删除失败: "+X.error,type:"error"})}catch(t){o({message:"模板删除失败: "+t.message,type:"error"})}}async function O(c){try{const t=g.value.indexOf(c);t!==-1&&g.value.splice(t,1);const X=await(await fetch("/api/config/delete-template",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({template:c,type:"scope"})})).json();X.success?o({message:"作用域模板删除成功!",type:"success"}):o({message:"作用域模板删除失败: "+X.error,type:"error"})}catch(t){o({message:"作用域模板删除失败: "+t.message,type:"error"})}}function Q(c){T.value=c,W.value=!1}function ke(c){R.value=c,M.value=!1}function Se(){W.value=!0}function Te(){M.value=!0}async function re(){try{await h.addToStage()&&h.fetchStatus()}catch(c){o({message:`添加文件失败: ${c.message}`,type:"error"})}}async function ve(){if(!_.value.trim()){o({message:"提交信息不能为空",type:"warning"});return}try{await h.commitChanges(_.value,A.value)&&(Ve(),h.fetchStatus(),h.fetchLog())}catch(c){o({message:`提交失败: ${c.message}`,type:"error"})}}async function H(){try{a.value=!0,await h.pushToRemote()&&(G.getCurrentBranch(),h.fetchLog())}catch(c){o({message:`推送失败: ${c.message}`,type:"error"})}finally{a.value=!1}}async function ge(){if(!_.value.trim()){o({message:"提交信息不能为空",type:"warning"});return}try{await h.addAndCommit(_.value,A.value),Ve(),h.fetchStatus(),h.fetchLog()}catch(c){o({message:`暂存并提交失败: ${c.message}`,type:"error"})}}async function tt(){if(!_.value.trim()){o({message:"提交信息不能为空",type:"warning"});return}try{await h.addCommitAndPush(_.value,A.value),Ve(),G.getCurrentBranch(),h.fetchLog()}catch(c){o({message:`暂存、提交并推送失败: ${c.message}`,type:"error"})}finally{}}async function st(){try{await qe.confirm(`确定要重置当前分支 "${G.currentBranch}" 到远程状态吗?这将丢失所有未推送的提交和本地更改。`,"重置到远程分支",{confirmButtonText:"确定",cancelButtonText:"取消",type:"warning"}),await h.resetToRemote(G.currentBranch)&&(h.fetchStatus(),h.fetchLog())}catch(c){c!=="cancel"&&o({message:`重置到远程分支失败: ${c.message}`,type:"error"})}}function Ve(){y.value="",T.value="",D.value="",j.value=""}return be(()=>{B();const c=localStorage.getItem("zen-gitsync-standard-commit");c!==null&&(U.value=c==="true");const t=localStorage.getItem("zen-gitsync-skip-hooks");t!==null&&(A.value=t==="true")}),(c,t)=>{const ce=Ye,X=pt,at=Ze,ne=ze,lt=Qe,ot=Ke,Y=le,Ae=ft,Oe=mt,Pe=Xe,Ue=Re;return p(),w("div",Zt,[t[35]||(t[35]=e("h2",null,"提交更改",-1)),e("div",qt,[r(G).userName===""||r(G).userEmail===""?(p(),w("div",Yt,[s(ce,{title:"Git用户信息未配置",type:"warning",closable:!1,"show-icon":""},{default:n(()=>t[12]||(t[12]=[e("p",null,"您需要配置Git用户名和邮箱才能提交代码。请使用以下命令配置:",-1),e("pre",{class:"config-command"},`git config --global user.name "Your Name"
|
|
9
|
-
git config --global user.email "your.email@example.com"`,-1)])),_:1})])):(p(),w(se,{key:1},[e("div",Kt,[e("div",Qt,[e("div",Xt,[e("div",es,[s(X,{modelValue:U.value,"onUpdate:modelValue":t[0]||(t[0]=S=>U.value=S),"active-text":"标准化提交","inactive-text":"普通提交"},null,8,["modelValue"])]),e("div",ts,[s(at,{content:"跳过 Git 钩子检查 (--no-verify)",placement:"top"},{default:n(()=>[s(X,{modelValue:A.value,"onUpdate:modelValue":t[1]||(t[1]=S=>A.value=S),"active-text":"跳过钩子 (--no-verify)"},null,8,["modelValue"])]),_:1})])])]),U.value?(p(),w("div",as,[e("div",ls,[s(ot,{modelValue:q.value,"onUpdate:modelValue":t[3]||(t[3]=S=>q.value=S),placeholder:"提交类型",class:"type-select",clearable:""},{default:n(()=>[(p(),w(se,null,oe(v,S=>s(lt,{key:S.value,label:S.label,value:S.value},null,8,["label","value"])),64))]),_:1},8,["modelValue"]),e("div",os,[s(ne,{modelValue:R.value,"onUpdate:modelValue":t[4]||(t[4]=S=>R.value=S),placeholder:"作用域(可选)",class:"scope-input",clearable:""},null,8,["modelValue"]),s(Y,{type:"primary",icon:r(_e),circle:"",size:"small",class:"settings-button",onClick:Te},null,8,["icon"])]),e("div",ns,[s(ne,{modelValue:T.value,"onUpdate:modelValue":t[5]||(t[5]=S=>T.value=S),placeholder:"简短描述(必填)",class:"description-input",clearable:""},null,8,["modelValue"]),s(Y,{type:"primary",icon:r(_e),circle:"",size:"small",class:"settings-button",onClick:Se},null,8,["icon"])])]),s(ne,{modelValue:D.value,"onUpdate:modelValue":t[6]||(t[6]=S=>D.value=S),type:"textarea",rows:4,placeholder:"正文(可选):详细描述本次提交的内容和原因",class:"body-input",clearable:""},null,8,["modelValue"]),s(ne,{modelValue:j.value,"onUpdate:modelValue":t[7]||(t[7]=S=>j.value=S),placeholder:"页脚(可选):如 Closes #123",class:"footer-input",clearable:""},null,8,["modelValue"]),e("div",is,[t[13]||(t[13]=e("div",{class:"preview-title"},"提交信息预览:",-1)),e("pre",rs,P(_.value),1),t[14]||(t[14]=e("div",{class:"preview-title",style:{"margin-top":"10px"}},"Git命令预览:",-1)),e("pre",cs,P(z.value),1)])])):(p(),w("div",ss,[s(ne,{modelValue:y.value,"onUpdate:modelValue":t[2]||(t[2]=S=>y.value=S),placeholder:x.value,clearable:""},null,8,["modelValue","placeholder"])]))]),e("div",us,[t[24]||(t[24]=e("h3",null,"Git 操作",-1)),e("div",ds,[e("div",ps,[t[18]||(t[18]=e("div",{class:"group-title"},"基础操作",-1)),e("div",fs,[s(Y,{type:"primary",onClick:re,loading:r(h).isAddingFiles,class:"action-button"},{default:n(()=>t[15]||(t[15]=[V(" 暂存更改 "),e("span",{class:"command-text"},"git add .",-1)])),_:1},8,["loading"]),s(Y,{type:"primary",onClick:ve,loading:r(h).isLoadingStatus,class:"action-button"},{default:n(()=>t[16]||(t[16]=[V(" 提交 "),e("span",{class:"command-text"},"git commit",-1)])),_:1},8,["loading"]),s(Y,{type:"success",onClick:H,loading:r(h).isPushing,class:"action-button push-button"},{default:n(()=>t[17]||(t[17]=[V(" 推送 "),e("span",{class:"command-text"},"git push",-1)])),_:1},8,["loading"])])]),e("div",ms,[t[21]||(t[21]=e("div",{class:"group-title"},"组合操作",-1)),e("div",vs,[s(Y,{type:"warning",onClick:ge,loading:r(h).isAddingFiles||r(h).isCommiting,class:"action-button"},{default:n(()=>t[19]||(t[19]=[V(" 暂存并提交 "),e("span",{class:"command-text"},"git add + commit",-1)])),_:1},8,["loading"]),s(Y,{type:"danger",onClick:tt,loading:r(h).isAddingFiles||r(h).isCommiting||r(h).isPushing,class:"action-button"},{default:n(()=>t[20]||(t[20]=[V(" 一键推送 "),e("span",{class:"command-text command-text-long"},"git add + commit + push",-1)])),_:1},8,["loading"])])]),e("div",gs,[t[23]||(t[23]=e("div",{class:"group-title"},"重置操作",-1)),e("div",ys,[s(Y,{type:"info",onClick:st,loading:r(h).isResetting,class:"action-button reset-button"},{default:n(()=>t[22]||(t[22]=[V(" 重置到远程 "),e("span",{class:"command-text command-text-long"},"git reset --hard origin/branch",-1)])),_:1},8,["loading"])])])])])],64))]),s(Ue,{title:"简短描述模板设置",modelValue:W.value,"onUpdate:modelValue":t[9]||(t[9]=S=>W.value=S),width:"80vw",style:{height:"80vh"}},{default:n(()=>[e("div",hs,[e("div",_s,[s(ne,{modelValue:C.value,"onUpdate:modelValue":t[8]||(t[8]=S=>C.value=S),placeholder:E.value?"编辑模板内容":"输入新模板内容",class:"template-input",clearable:""},null,8,["modelValue","placeholder"]),e("div",ws,[E.value?(p(),ee(Y,{key:0,onClick:N},{default:n(()=>t[25]||(t[25]=[V("取消")])),_:1})):te("",!0),s(Y,{type:"primary",onClick:J,disabled:!C.value.trim()},{default:n(()=>[V(P(E.value?"更新模板":"添加模板"),1)]),_:1},8,["disabled"])])]),e("div",bs,[t[29]||(t[29]=e("h3",null,"已保存模板",-1)),b.value.length===0?(p(),ee(Ae,{key:0,description:"暂无保存的模板"})):te("",!0),(p(!0),w(se,null,oe(b.value,(S,ue)=>(p(),ee(Pe,{key:ue,class:"template-item"},{default:n(()=>[s(Oe,{justify:"space-between",align:"middle",style:{width:"100%"}},{default:n(()=>[e("div",$s,P(S),1),e("div",Cs,[s(Y,{type:"primary",size:"small",onClick:de=>Q(S)},{default:n(()=>t[26]||(t[26]=[V("使用")])),_:2},1032,["onClick"]),s(Y,{type:"warning",size:"small",icon:r(Ne),onClick:de=>ae(S,ue)},{default:n(()=>t[27]||(t[27]=[V("编辑")])),_:2},1032,["icon","onClick"]),s(Y,{type:"danger",size:"small",onClick:de=>Z(S)},{default:n(()=>t[28]||(t[28]=[V("删除")])),_:2},1032,["onClick"])])]),_:2},1024)]),_:2},1024))),128))])])]),_:1},8,["modelValue"]),s(Ue,{title:"作用域模板设置",modelValue:M.value,"onUpdate:modelValue":t[11]||(t[11]=S=>M.value=S),width:"80%",style:{height:"80vh"}},{default:n(()=>[e("div",ks,[e("div",Ss,[s(ne,{modelValue:$.value,"onUpdate:modelValue":t[10]||(t[10]=S=>$.value=S),placeholder:l.value?"编辑作用域模板内容":"输入新作用域模板",class:"template-input",clearable:""},null,8,["modelValue","placeholder"]),e("div",Ts,[l.value?(p(),ee(Y,{key:0,onClick:d},{default:n(()=>t[30]||(t[30]=[V("取消")])),_:1})):te("",!0),s(Y,{type:"primary",onClick:me,disabled:!$.value.trim()},{default:n(()=>[V(P(l.value?"更新模板":"添加模板"),1)]),_:1},8,["disabled"])])]),e("div",Vs,[t[34]||(t[34]=e("h3",null,"已保存作用域",-1)),g.value.length===0?(p(),ee(Ae,{key:0,description:"暂无保存的作用域"})):te("",!0),(p(!0),w(se,null,oe(g.value,(S,ue)=>(p(),ee(Pe,{key:ue,class:"template-item"},{default:n(()=>[s(Oe,{justify:"space-between",align:"middle",style:{width:"100%"}},{default:n(()=>[e("div",Gs,P(S),1),e("div",Ls,[s(Y,{type:"primary",size:"small",onClick:de=>ke(S)},{default:n(()=>t[31]||(t[31]=[V("使用")])),_:2},1032,["onClick"]),s(Y,{type:"warning",size:"small",icon:r(Ne),onClick:de=>k(S,ue)},{default:n(()=>t[32]||(t[32]=[V("编辑")])),_:2},1032,["icon","onClick"]),s(Y,{type:"danger",size:"small",onClick:de=>O(S)},{default:n(()=>t[33]||(t[33]=[V("删除")])),_:2},1032,["onClick"])])]),_:2},1024)]),_:2},1024))),128))])])]),_:1},8,["modelValue"])])}}}),Bs=$e(xs,[["__scopeId","data-v-8d105fc1"]]),Ds={class:"card"},js={class:"log-header"},Rs={class:"log-actions"},zs={key:0},Es={key:1},As={key:0,class:"refresh-notification"},Os={key:1,class:"graph-view"},Ps={key:0,class:"commit-count"},Us={class:"graph-controls"},Ns={class:"zoom-controls"},Ms={class:"scale-info"},Is={key:2},Fs={key:0,class:"commit-count"},Js={key:0,class:"branch-container"},fe=.5,ye=1.5,xe=.1,Hs=we({__name:"LogList",setup(F,{expose:h}){const G=Ee(),y=ie();let a=[];const x=i(a),L=i(""),U=i(!1),q=he(()=>G.isLoadingLog||U.value),R=i(!1),T=i(0),D=i(!0),j=i(null),b=i(1),W=i(!1);async function C(v=!1){if(!ie().isGitRepo){L.value="当前目录不是Git仓库";return}try{R.value=v,U.value=!0;const z=v?"/api/log?all=true&graph=true":"/api/log?graph=true";console.log(`加载日志数据: ${z}`);const J=await(await fetch(z)).json();if(a.length=0,Array.isArray(J))console.log(`日志加载完成: 共${J.length}条记录`),J.forEach(K=>a.push(K)),T.value=J.length;else if(J.log&&Array.isArray(J.log))console.log(`日志加载完成: 共${J.log.length}条记录`),J.log.forEach(K=>a.push(K)),T.value=J.log.length;else{console.error("未知的日志数据格式:",J),L.value="日志数据格式错误";return}x.value=[...a],console.log(`logsData长度: ${a.length}`),W.value=!0,setTimeout(()=>{W.value=!1},2e3),D.value&&setTimeout(E,0),L.value=""}catch(z){L.value="加载提交历史失败: "+(z instanceof Error?z.message:String(z)),console.error("加载日志失败:",z)}finally{U.value=!1}}async function E(){if(console.log(`开始渲染图表...数据长度: ${a.length}`),!j.value){console.error("图表容器未找到");return}if(a.length===0){console.error("没有日志数据可渲染");return}try{j.value.innerHTML="",console.log(`创建gitgraph实例,分支: ${y.currentBranch||"main"}`);const v=wt(j.value,{orientation:"vertical-reverse",template:"metro",author:"提交者 <committer@example.com>"}),_={},z=v.branch(y.currentBranch||"main");_[y.currentBranch||"main"]=z,console.log(`开始创建提交图...共${a.length}条提交`),a.forEach((B,J)=>{let K=z;if(B.branch){const ae=g(B.branch.split(",")[0]);_[ae]||(_[ae]=v.branch(ae)),K=_[ae]}K.commit({hash:B.hash,subject:B.message,author:`${B.author} <${B.email}>`}),J%10===0&&console.log(`已渲染 ${J+1}/${a.length} 个提交`)}),console.log("图表渲染完成"),setTimeout(()=>{A()},100)}catch(v){console.error("渲染图表失败:",v),L.value="渲染图表失败: "+(v instanceof Error?v.message:String(v))}}function I(){D.value=!D.value,D.value&&a.length>0&&setTimeout(E,0)}function f(){C(!R.value)}function g(v){return v.includes("HEAD -> ")?v.replace("HEAD -> ",""):v.includes("origin/")?v:v.trim()}function M(v){return v.includes("HEAD")?"success":v.includes("origin/")?"warning":"info"}be(()=>{y.isGitRepo?G.log.length>0?(console.log("使用已加载的日志数据"),a.length=0,G.log.forEach(v=>a.push(v)),T.value=G.log.length,D.value&&setTimeout(()=>{console.log(`准备渲染图表,数据长度: ${a.length}`),E()},100)):(console.log("初始加载日志数据"),C()):L.value="当前目录不是Git仓库"});const $=()=>{if(!y.isGitRepo){L.value="当前目录不是Git仓库";return}C(R.value)};je(()=>G.log,v=>{console.log("监听到gitLogStore.log变化,更新图表数据"),a.length=0,v.forEach(_=>a.push(_)),T.value=v.length;try{x.value=[...a]}catch(_){console.warn("无法更新logs.value:",_)}console.log(`数据更新完成,准备渲染图表(${a.length}条记录)`),D.value&&a.length>0&&setTimeout(E,0)}),h({refreshLog:$});function l(){b.value<ye&&(b.value=Math.min(ye,b.value+xe),u())}function m(){b.value>fe&&(b.value=Math.max(fe,b.value-xe),u())}function u(){if(!j.value)return;const v=j.value.querySelector("svg");v&&(v.style.transform=`scale(${b.value})`,v.style.transformOrigin="top left")}function A(){if(!j.value)return;const v=j.value.querySelector("svg");if(!v)return;const _=v.getBoundingClientRect().width/b.value,z=j.value.clientWidth;_>z?b.value=Math.max(fe,z/_):b.value=1,u()}return(v,_)=>{const z=He;return p(),w("div",Ds,[e("div",js,[_[2]||(_[2]=e("h2",null,"提交历史",-1)),e("div",Rs,[s(r(le),{type:"primary",size:"small",onClick:I},{default:n(()=>[V(P(D.value?"表格视图":"图表视图"),1)]),_:1}),s(r(le),{type:"primary",size:"small",onClick:f,loading:q.value},{default:n(()=>[V(P(R.value?"显示最近30条":"显示所有提交"),1)]),_:1},8,["loading"]),s(r(le),{icon:r(We),circle:"",size:"small",onClick:_[0]||(_[0]=B=>$()),loading:q.value,class:De({"refresh-button-animated":W.value})},null,8,["icon","loading","class"])])]),L.value?(p(),w("div",zs,P(L.value),1)):(p(),w("div",Es,[W.value?(p(),w("div",As," 提交历史已刷新 ")):te("",!0),D.value?(p(),w("div",Os,[r(a).length>0?(p(),w("div",Ps," 显示 "+P(r(a).length)+" 条提交记录 "+P(R.value?"(全部)":"(最近30条)"),1)):te("",!0),e("div",Us,[e("div",Ns,[s(r(le),{type:"primary",icon:r(vt),circle:"",size:"small",onClick:m,disabled:b.value<=fe},null,8,["icon","disabled"]),s(r(gt),{modelValue:b.value,"onUpdate:modelValue":_[1]||(_[1]=B=>b.value=B),min:fe,max:ye,step:xe,onChange:u,class:"zoom-slider"},null,8,["modelValue"]),s(r(le),{type:"primary",icon:r(yt),circle:"",size:"small",onClick:l,disabled:b.value>=ye},null,8,["icon","disabled"]),s(r(le),{type:"primary",size:"small",onClick:A},{default:n(()=>_[3]||(_[3]=[V(" 自适应大小 ")])),_:1})]),e("div",Ms," 缩放: "+P(Math.round(b.value*100))+"% ",1)]),e("div",{ref_key:"graphContainer",ref:j,class:"graph-container"},null,512)])):(p(),w("div",Is,[x.value.length>0?(p(),w("div",Fs," 显示 "+P(x.value.length)+" 条提交记录 "+P(R.value?"(全部)":"(最近30条)"),1)):te("",!0),Be((p(),ee(r(_t),{data:x.value,style:{width:"100%"},stripe:"",border:""},{default:n(()=>[s(r(pe),{prop:"hash",label:"提交哈希",width:"100",resizable:""}),s(r(pe),{prop:"date",label:"日期",width:"180",resizable:""}),s(r(pe),{label:"作者",width:"200",resizable:""},{default:n(B=>[V(P(B.row.author)+" <"+P(B.row.email)+"> ",1)]),_:1}),s(r(pe),{label:"分支",width:"180",resizable:""},{default:n(B=>[B.row.branch?(p(),w("div",Js,[(p(!0),w(se,null,oe(B.row.branch.split(","),(J,K)=>(p(),ee(r(ht),{key:K,size:"small",type:M(J),class:"branch-tag"},{default:n(()=>[V(P(g(J)),1)]),_:2},1032,["type"]))),128))])):te("",!0)]),_:1}),s(r(pe),{prop:"message",label:"提交信息","min-width":"250"})]),_:1},8,["data"])),[[z,q.value]])]))]))])}}}),Ws=$e(Hs,[["__scopeId","data-v-bc81ef7e"]]),Zs="data:image/svg+xml,%3csvg%20width='200'%20height='200'%20viewBox='0%200%20200%20200'%20xmlns='http://www.w3.org/2000/svg'%3e%3c!--%20主分支%20--%3e%3cline%20x1='40'%20y1='40'%20x2='40'%20y2='160'%20stroke='%2334495e'%20stroke-width='8'%20stroke-linecap='round'%20/%3e%3c!--%20特性分支%20--%3e%3cpath%20d='M40,70%20C60,70%2080,90%2080,110%20L80,130'%20stroke='%233498db'%20stroke-width='8'%20stroke-linecap='round'%20stroke-linejoin='round'%20fill='none'%20/%3e%3c!--%20开发分支%20--%3e%3cpath%20d='M40,100%20C60,100%20100,110%20100,130%20L100,160'%20stroke='%232ecc71'%20stroke-width='8'%20stroke-linecap='round'%20stroke-linejoin='round'%20fill='none'%20/%3e%3c!--%20修复分支%20--%3e%3cpath%20d='M40,130%20C60,130%20120,140%20120,160'%20stroke='%23e74c3c'%20stroke-width='8'%20stroke-linecap='round'%20stroke-linejoin='round'%20fill='none'%20/%3e%3c!--%20合并点%20--%3e%3cpath%20d='M80,130%20C80,145%2060,145%2040,145'%20stroke='%233498db'%20stroke-width='8'%20stroke-linecap='round'%20stroke-linejoin='round'%20fill='none'%20/%3e%3c!--%20节点%20--%3e%3ccircle%20cx='40'%20cy='40'%20r='10'%20fill='%2334495e'%20/%3e%3ccircle%20cx='40'%20cy='70'%20r='10'%20fill='%2334495e'%20/%3e%3ccircle%20cx='40'%20cy='100'%20r='10'%20fill='%2334495e'%20/%3e%3ccircle%20cx='40'%20cy='130'%20r='10'%20fill='%2334495e'%20/%3e%3ccircle%20cx='40'%20cy='145'%20r='10'%20fill='%2334495e'%20/%3e%3ccircle%20cx='40'%20cy='160'%20r='10'%20fill='%2334495e'%20/%3e%3ccircle%20cx='80'%20cy='130'%20r='10'%20fill='%233498db'%20/%3e%3ccircle%20cx='100'%20cy='160'%20r='10'%20fill='%232ecc71'%20/%3e%3ccircle%20cx='120'%20cy='160'%20r='10'%20fill='%23e74c3c'%20/%3e%3c/svg%3e",qs={class:"main-header"},Ys={class:"header-left"},Ks=["src"],Qs={class:"header-info"},Xs={key:0,id:"user-info"},ea={class:"user-name"},ta={class:"user-email"},sa={key:1,id:"user-info"},aa={class:"container"},la={key:0,class:"loading-container"},oa={class:"loading-spinner"},na={key:1,class:"layout-container"},ia={class:"left-panel"},ra={key:0,class:"right-panel"},ca={key:0,class:"card"},ua={class:"tips"},da={key:1,class:"right-panel"},pa={class:"dialog-footer"},fa={class:"main-footer"},ma={key:0,class:"branch-info"},va={class:"branch-wrapper"},ga={class:"dialog-footer"},ya=we({__name:"App",setup(F){const h=i(""),G=i(null),y=i(null),a=ie(),x=i(!1),L=i("");async function U(){try{const l=await(await fetch("/api/config/getConfig")).json();h.value=`默认提交信息: ${l.defaultCommitMessage}`}catch($){console.error("加载配置失败:",$)}}async function q(){try{const l=await(await fetch("/api/current_directory")).json();return L.value=l.directory||"未知目录",l}catch($){return console.error("获取当前目录失败:",$),{directory:"未知目录",isGitRepo:!1}}}be(async()=>{console.log("---------- 页面初始化开始 ----------");try{const[$,l]=await Promise.all([U(),q()]);a.isGitRepo=l.isGitRepo===!0,a.lastCheckedTime=Date.now(),a.isGitRepo?await Promise.all([a.getCurrentBranch(),a.getAllBranches(),a.getUserInfo()]):o.warning("当前目录不是Git仓库,部分功能将不可用")}catch($){console.error("初始化失败:",$)}finally{x.value=!0,console.log("---------- 页面初始化完成 ----------")}});const R=i(!1),T=i(""),D=i("");async function j(){await a.createBranch(T.value,D.value)&&(R.value=!1,T.value="",y.value&&y.value.refreshStatus(),G.value&&G.value.refreshLog())}function b(){D.value=a.currentBranch,R.value=!0}async function W($){await a.changeBranch($)&&(y.value&&y.value.refreshStatus(),G.value&&G.value.refreshLog())}const C=i(!1),E=i(""),I=i("");function f(){E.value=a.userName,I.value=a.userEmail,C.value=!0}async function g(){if(!E.value||!I.value){o.warning("用户名和邮箱不能为空");return}await a.restoreUserConfig(E.value,I.value)&&(C.value=!1)}async function M(){await a.clearUserConfig()&&(E.value="",I.value="")}return($,l)=>{const m=Ie,u=le,A=Xe,v=ze,_=Je,z=Qe,B=Ke,J=Fe,K=Re,ae=Ye;return p(),w(se,null,[e("header",qs,[e("div",Ys,[e("img",{src:r(Zs),alt:"Zen GitSync Logo",class:"logo"},null,8,Ks),l[9]||(l[9]=e("h1",null,"Zen GitSync UI",-1))]),e("div",Qs,[r(a).userName&&r(a).userEmail?(p(),w("div",Xs,[l[10]||(l[10]=e("span",{class:"user-label"},"用户:",-1)),e("span",ea,P(r(a).userName),1),e("span",ta,"<"+P(r(a).userEmail)+">",1),s(u,{type:"primary",size:"small",onClick:f,class:"user-settings-btn",circle:""},{default:n(()=>[s(m,null,{default:n(()=>[s(r(_e))]),_:1})]),_:1})])):(p(),w("div",sa,[l[11]||(l[11]=e("span",{class:"user-label"},"用户: ",-1)),l[12]||(l[12]=e("span",{class:"user-warning"},"未配置",-1)),s(u,{type:"primary",size:"small",onClick:f,class:"user-settings-btn",circle:""},{default:n(()=>[s(m,null,{default:n(()=>[s(r(_e))]),_:1})]),_:1})]))])]),e("div",aa,[x.value?(p(),w("div",na,[e("div",ia,[s(Wt,{ref_key:"gitStatusRef",ref:y,"initial-directory":L.value},null,8,["initial-directory"])]),r(a).isGitRepo?(p(),w("div",ra,[!r(a).userName||!r(a).userEmail?(p(),w("div",ca,[l[18]||(l[18]=e("h2",null,"Git用户未配置",-1)),l[19]||(l[19]=e("p",null,"请先配置Git用户信息才能进行提交操作。",-1)),e("div",ua,[l[16]||(l[16]=e("h3",null,"您可以通过以下方式配置:",-1)),l[17]||(l[17]=e("ol",null,[e("li",null,"点击右上角的设置按钮,配置用户名和邮箱"),e("li",null,"或者使用命令行配置:"),e("div",{class:"code-block"},[V(' git config --global user.name "您的用户名"'),e("br"),V(' git config --global user.email "您的邮箱" ')])],-1)),s(u,{type:"primary",onClick:f},{default:n(()=>l[15]||(l[15]=[V(" 立即配置 ")])),_:1})])])):(p(),w(se,{key:1},[s(Bs),s(Ws,{ref_key:"logListRef",ref:G},null,512)],64))])):(p(),w("div",da,l[20]||(l[20]=[e("div",{class:"card"},[e("h2",null,"Git仓库初始化"),e("p",null,"当前目录不是Git仓库,请先初始化Git仓库或切换到Git仓库目录。"),e("div",{class:"tips"},[e("h3",null,"可以使用以下命令初始化仓库:"),e("div",{class:"code-block"},"git init")])],-1)]))),s(K,{modelValue:R.value,"onUpdate:modelValue":l[3]||(l[3]=N=>R.value=N),title:"创建新分支",width:"30%","destroy-on-close":""},{footer:n(()=>[e("span",pa,[s(u,{onClick:l[2]||(l[2]=N=>R.value=!1)},{default:n(()=>l[21]||(l[21]=[V("取消")])),_:1}),s(u,{type:"primary",onClick:j,loading:r(a).isCreatingBranch},{default:n(()=>l[22]||(l[22]=[V(" 创建 ")])),_:1},8,["loading"])])]),default:n(()=>[s(J,{model:{newBranchName:T.value,selectedBaseBranch:D.value}},{default:n(()=>[s(_,{label:"新分支名称"},{default:n(()=>[s(v,{modelValue:T.value,"onUpdate:modelValue":l[0]||(l[0]=N=>T.value=N),placeholder:"请输入新分支名称"},null,8,["modelValue"])]),_:1}),s(_,{label:"基于分支"},{default:n(()=>[s(B,{modelValue:D.value,"onUpdate:modelValue":l[1]||(l[1]=N=>D.value=N),placeholder:"选择基础分支",style:{width:"100%"}},{default:n(()=>[(p(!0),w(se,null,oe(r(a).allBranches,N=>(p(),ee(z,{key:N,label:N,value:N},null,8,["label","value"]))),128))]),_:1},8,["modelValue"])]),_:1})]),_:1},8,["model"])]),_:1},8,["modelValue"])])):(p(),w("div",la,[s(A,{class:"loading-card"},{default:n(()=>[e("div",oa,[s(m,{class:"is-loading"},{default:n(()=>l[13]||(l[13]=[e("svg",{viewBox:"0 0 1024 1024",xmlns:"http://www.w3.org/2000/svg"},[e("path",{fill:"currentColor",d:"M512 64a32 32 0 0 1 32 32v192a32 32 0 0 1-64 0V96a32 32 0 0 1 32-32zm0 640a32 32 0 0 1 32 32v192a32 32 0 1 1-64 0V736a32 32 0 0 1 32-32zm448-192a32 32 0 0 1-32 32H736a32 32 0 1 1 0-64h192a32 32 0 0 1 32 32zm-640 0a32 32 0 0 1-32 32H96a32 32 0 0 1 0-64h192a32 32 0 0 1 32 32zM195.2 195.2a32 32 0 0 1 45.248 0L376.32 331.008a32 32 0 0 1-45.248 45.248L195.2 240.448a32 32 0 0 1 0-45.248zm452.544 452.544a32 32 0 0 1 45.248 0L828.8 783.552a32 32 0 0 1-45.248 45.248L647.744 692.992a32 32 0 0 1 0-45.248zM828.8 195.264a32 32 0 0 1 0 45.184L692.992 376.32a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0zm-452.544 452.48a32 32 0 0 1 0 45.248L240.448 828.8a32 32 0 0 1-45.248-45.248l135.808-135.808a32 32 0 0 1 45.248 0z"})],-1)])),_:1})]),l[14]||(l[14]=e("div",{class:"loading-text"},"加载中...",-1))]),_:1})]))]),e("footer",fa,[r(a).currentBranch?(p(),w("div",ma,[e("div",va,[l[24]||(l[24]=e("span",{class:"branch-label"},"当前分支:",-1)),s(B,{modelValue:r(a).currentBranch,"onUpdate:modelValue":l[4]||(l[4]=N=>r(a).currentBranch=N),size:"small",onChange:W,loading:r(a).isChangingBranch,class:"branch-select"},{default:n(()=>[(p(!0),w(se,null,oe(r(a).allBranches,N=>(p(),ee(z,{key:N,label:N,value:N},null,8,["label","value"]))),128))]),_:1},8,["modelValue","loading"]),s(u,{type:"primary",size:"small",onClick:b,class:"create-branch-btn"},{default:n(()=>[s(m,null,{default:n(()=>[s(r(bt))]),_:1}),l[23]||(l[23]=V(" 新建分支 "))]),_:1})])])):te("",!0),l[25]||(l[25]=e("div",{class:"footer-right"},null,-1))]),s(K,{modelValue:C.value,"onUpdate:modelValue":l[8]||(l[8]=N=>C.value=N),title:"Git用户设置",width:"30%","destroy-on-close":""},{footer:n(()=>[e("span",ga,[s(u,{type:"danger",onClick:M},{default:n(()=>l[27]||(l[27]=[V(" 清除配置 ")])),_:1}),s(u,{onClick:l[7]||(l[7]=N=>C.value=!1)},{default:n(()=>l[28]||(l[28]=[V("取消")])),_:1}),s(u,{type:"primary",onClick:g},{default:n(()=>l[29]||(l[29]=[V(" 保存 ")])),_:1})])]),default:n(()=>[s(J,null,{default:n(()=>[s(_,{label:"用户名"},{default:n(()=>[s(v,{modelValue:E.value,"onUpdate:modelValue":l[5]||(l[5]=N=>E.value=N),placeholder:"请输入Git用户名"},null,8,["modelValue"])]),_:1}),s(_,{label:"邮箱"},{default:n(()=>[s(v,{modelValue:I.value,"onUpdate:modelValue":l[6]||(l[6]=N=>I.value=N),placeholder:"请输入Git邮箱"},null,8,["modelValue"])]),_:1}),s(_,null,{default:n(()=>[s(ae,{type:"info",closable:!1,"show-icon":""},{default:n(()=>l[26]||(l[26]=[V(" 这些设置将影响全局Git配置,对所有Git仓库生效。 ")])),_:1})]),_:1})]),_:1})]),_:1},8,["modelValue"])],64)}}}),ha=$e(ya,[["__scopeId","data-v-0bd851aa"]]),et=$t(ha);et.use(Ct());et.mount("#app");
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.card[data-v-bcbbf547]{background-color:#fff;border-radius:8px;box-shadow:0 2px 12px #0000001a;padding:20px;margin-bottom:20px}.status-header[data-v-bcbbf547]{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}.status-header h2[data-v-bcbbf547]{margin:0}.status-box[data-v-bcbbf547]{white-space:pre-wrap;font-family:monospace;background-color:#f5f7fa;padding:15px;border-radius:4px;margin-bottom:15px;max-height:300px;overflow-y:auto}.file-list[data-v-bcbbf547]{max-height:300px;overflow-y:auto}.file-item[data-v-bcbbf547]{padding:8px 12px;margin-bottom:5px;border-radius:4px;cursor:pointer;display:flex;align-items:center;justify-content:space-between}.file-item[data-v-bcbbf547]:hover{background-color:#f5f7fa}.file-info[data-v-bcbbf547]{display:flex;align-items:center;flex-grow:1}.file-actions[data-v-bcbbf547]{margin-left:10px;opacity:.5;transition:opacity .2s}.file-item:hover .file-actions[data-v-bcbbf547]{opacity:1}.file-type[data-v-bcbbf547]{font-size:12px;padding:2px 6px;border-radius:10px;margin-right:10px;flex-shrink:0}.added .file-type[data-v-bcbbf547]{background-color:#e1f3d8;color:#67c23a}.modified .file-type[data-v-bcbbf547]{background-color:#e6f1fc;color:#409eff}.deleted .file-type[data-v-bcbbf547]{background-color:#fef0f0;color:#f56c6c}.untracked .file-type[data-v-bcbbf547]{background-color:#fdf6ec;color:#e6a23c}.file-path[data-v-bcbbf547]{font-family:monospace;word-break:break-all}.diff-content[data-v-bcbbf547]{font-family:monospace;white-space:pre-wrap;max-height:60vh;overflow-y:auto;padding:10px;background-color:#f5f7fa;border-radius:4px}.diff-formatted[data-v-bcbbf547]{font-size:14px;line-height:1.5}.file-navigation[data-v-bcbbf547]{display:flex;justify-content:center;align-items:center;margin-top:15px}.file-counter[data-v-bcbbf547]{margin:0 15px;font-size:14px;color:#606266}.current-directory[data-v-bcbbf547]{display:flex;align-items:center;margin-bottom:15px;padding:8px 12px;background-color:#f5f7fa;border-radius:4px;font-family:monospace}.current-directory .el-icon[data-v-bcbbf547]{margin-right:8px;color:#409eff}.current-directory span[data-v-bcbbf547]{flex-grow:1;word-break:break-all;margin-right:10px}.browser-current-path[data-v-bcbbf547]{margin-bottom:10px;font-size:14px;color:#606266;background-color:#f5f7fa;padding:8px 12px;border-radius:4px;font-family:monospace;word-break:break-all}.browser-error[data-v-bcbbf547]{margin-bottom:10px;color:#f56c6c;padding:8px 12px;background-color:#fef0f0;border-radius:4px}.directory-browser[data-v-bcbbf547]{padding:10px;height:400px;display:flex;flex-direction:column}.browser-nav[data-v-bcbbf547]{margin-bottom:10px;display:flex;justify-content:space-between;position:sticky;top:0;background-color:#fff;z-index:1;padding:10px 0}.directory-items-container[data-v-bcbbf547]{flex:1;overflow-y:auto}.directory-items[data-v-bcbbf547]{list-style:none;padding:0;margin:0}.directory-item[data-v-bcbbf547]{padding:8px 12px;margin-bottom:5px;border-radius:4px;cursor:pointer;display:flex;align-items:center}.directory-item[data-v-bcbbf547]:hover{background-color:#f5f7fa}.directory-item.directory[data-v-bcbbf547]{color:#409eff}.directory-item.file[data-v-bcbbf547]{color:#606266}.directory-item .el-icon[data-v-bcbbf547]{margin-right:10px}.directory-item span[data-v-bcbbf547]{font-family:monospace;word-break:break-all}.directory-buttons[data-v-bcbbf547]{display:flex;gap:10px;margin-top:10px}.no-padding-left[data-v-bcbbf547]{padding-left:8px!important}.diff-header{font-weight:700;background-color:#e6f1fc;padding:3px;margin:5px 0}.diff-old-file,.diff-new-file{color:#888}.diff-hunk-header{color:#6f42c1}.diff-added{background-color:#e6ffed;color:#28a745}.diff-removed{background-color:#ffeef0;color:#d73a49}.diff-context{color:#444}.card[data-v-8d105fc1]{background-color:#fff;border-radius:5px;box-shadow:0 2px 5px #0000001a;margin-bottom:20px;padding:20px}.layout-container[data-v-8d105fc1]{display:flex;gap:20px}.commit-section[data-v-8d105fc1]{flex:1;min-width:0}.actions-section[data-v-8d105fc1]{width:300px;flex-shrink:0}.actions-section h3[data-v-8d105fc1]{margin-top:0;margin-bottom:15px;padding-bottom:10px;border-bottom:1px solid #dcdfe6;font-size:18px;color:#303133;font-weight:500}.commit-form[data-v-8d105fc1]{display:flex;margin-bottom:15px;gap:10px}.git-actions[data-v-8d105fc1]{margin-top:20px}.action-groups[data-v-8d105fc1]{display:flex;flex-direction:column;gap:15px}.action-group[data-v-8d105fc1]{background-color:#f9f9f9;border-radius:8px;padding:12px 15px;box-shadow:0 1px 3px #0000000d;border-left:4px solid #409EFF;overflow:hidden}.action-group[data-v-8d105fc1]:nth-child(2){border-left-color:#e6a23c}.action-group[data-v-8d105fc1]:nth-child(3){border-left-color:#909399}.group-title[data-v-8d105fc1]{font-size:14px;font-weight:700;margin-bottom:10px;color:#606266;text-align:left;display:block;position:relative;padding-left:10px;border-bottom:1px solid rgba(0,0,0,.06);padding-bottom:8px}.group-buttons[data-v-8d105fc1]{display:flex;flex-direction:column;gap:8px;padding:0 2px}.action-button[data-v-8d105fc1]{position:relative;padding:14px 0 24px;width:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;height:auto;text-align:center;font-size:16px;border-radius:6px;border:none}.action-button[data-v-8d105fc1]:hover{transform:translateY(-2px);box-shadow:0 2px 8px #00000026}.action-button[data-v-8d105fc1]:active{transform:translateY(0)}.action-button[data-v-8d105fc1] .el-button__content{display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%}.action-button[data-v-8d105fc1] .el-icon{margin-right:0;margin-bottom:4px;font-size:18px}.command-text[data-v-8d105fc1]{position:absolute;bottom:6px;font-size:14px;font-family:monospace;width:100%;text-align:center;left:0;white-space:nowrap}.standard-commit-form[data-v-8d105fc1]{display:flex;flex-direction:column;gap:15px;margin-bottom:15px}.standard-commit-header[data-v-8d105fc1]{display:flex;flex-direction:column;gap:10px;width:100%}.type-select[data-v-8d105fc1]{width:100%}.scope-container[data-v-8d105fc1]{display:flex;align-items:center;gap:5px;width:100%}.scope-input[data-v-8d105fc1]{flex-grow:1}.description-container[data-v-8d105fc1]{display:flex;align-items:center;gap:5px;width:100%}.description-input[data-v-8d105fc1]{flex-grow:1}.settings-button[data-v-8d105fc1]{flex-shrink:0}.preview-section[data-v-8d105fc1]{background-color:#f5f7fa;padding:10px;border-radius:4px}.preview-title[data-v-8d105fc1]{font-weight:700;margin-bottom:5px}.preview-content[data-v-8d105fc1]{white-space:pre-wrap;font-family:monospace;margin:0;padding:10px;background-color:#ebeef5;border-radius:4px}.template-container[data-v-8d105fc1]{display:flex;flex-direction:column;height:calc(85vh - 100px);overflow-y:auto}.template-form[data-v-8d105fc1]{margin-bottom:20px}.template-list[data-v-8d105fc1]{flex:1;overflow-y:auto}.template-input[data-v-8d105fc1]{flex-grow:1}.template-list[data-v-8d105fc1]{overflow-y:auto;height:100%}.template-item[data-v-8d105fc1]{margin-bottom:10px}.template-item[data-v-8d105fc1]:hover{background-color:#f5f7fa}.template-content[data-v-8d105fc1]{flex-grow:1;margin-right:10px;word-break:break-all}.template-actions[data-v-8d105fc1]{display:flex;gap:5px;justify-content:flex-end;min-width:120px;flex-shrink:0}.options-row[data-v-8d105fc1]{display:flex;justify-content:space-between;align-items:center;margin-bottom:15px}.code-command[data-v-8d105fc1]{background-color:#2d2d2d;color:#f8f8f2;font-family:Courier New,Courier,monospace;padding:10px;border-radius:4px;overflow-x:auto;white-space:pre;font-size:14px}@media (max-width: 768px){.layout-container[data-v-8d105fc1]{flex-direction:column}.actions-section[data-v-8d105fc1]{width:100%}.group-buttons[data-v-8d105fc1]{flex-direction:row;flex-wrap:wrap}.action-button[data-v-8d105fc1]{flex:1;min-width:120px}}.git-config-warning[data-v-8d105fc1]{width:100%}.config-command[data-v-8d105fc1]{background-color:#2d2d2d;color:#f8f8f2;font-family:Courier New,Courier,monospace;padding:10px;border-radius:4px;margin-top:10px;white-space:pre}.push-button[data-v-8d105fc1]{background-color:#67c23a;border-color:#67c23a}.push-button[data-v-8d105fc1]:hover{background-color:#85ce61;border-color:#85ce61}.reset-button[data-v-8d105fc1]{background-color:#909399;border-color:#909399}.reset-button[data-v-8d105fc1]:hover{background-color:#a6a9ad;border-color:#a6a9ad}.el-button+.el-button[data-v-8d105fc1]{margin-left:0}.log-header[data-v-bc81ef7e]{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}.log-actions[data-v-bc81ef7e]{display:flex;gap:8px}.branch-container[data-v-bc81ef7e]{display:flex;flex-wrap:wrap;gap:4px}.branch-tag[data-v-bc81ef7e]{margin-right:4px}.commit-count[data-v-bc81ef7e]{margin-bottom:10px;font-size:14px;color:#606266;text-align:right}.graph-container[data-v-bc81ef7e]{width:100%;height:600px;overflow:auto;border:1px solid #ebeef5;border-radius:4px;padding:10px;background-color:#fff;position:relative}.graph-container svg[data-v-bc81ef7e]{transform-origin:top left;transition:transform .2s ease}.graph-view[data-v-bc81ef7e]{width:100%}.graph-controls[data-v-bc81ef7e]{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}.zoom-controls[data-v-bc81ef7e]{display:flex;gap:8px}.zoom-slider[data-v-bc81ef7e]{width:200px}.scale-info[data-v-bc81ef7e]{font-size:14px;color:#606266}.refresh-button-animated[data-v-bc81ef7e]{animation:pulse-bc81ef7e 1s}.refresh-notification[data-v-bc81ef7e]{background-color:#f0f9eb;color:#67c23a;padding:8px;border-radius:4px;margin-bottom:10px;text-align:center;font-size:14px;border-left:4px solid #67c23a;animation:fadeOut-bc81ef7e 2s forwards}@keyframes pulse-bc81ef7e{0%{transform:scale(1)}50%{transform:scale(1.2)}to{transform:scale(1)}}@keyframes fadeOut-bc81ef7e{0%{opacity:1}70%{opacity:1}to{opacity:0}}body{font-family:Arial,sans-serif;margin:0;padding:0;background-color:#f5f5f5}.container{margin:0 auto;padding:20px 30px}.main-header{background-color:#24292e;color:#fff;padding:15px 20px;display:flex;justify-content:space-between;align-items:center}.header-left{display:flex;align-items:center;gap:10px}.logo{height:32px;width:auto}h1{margin:0;font-size:24px}.header-info{display:flex;flex-direction:column;align-items:flex-end;gap:5px}#branch-info,#user-info{background-color:#ffffff1a;padding:4px 8px;border-radius:4px;font-size:14px}.branch-label,.user-label,.user-name{font-weight:700;margin-right:5px}.user-email{color:#e0e0e0}.branch-name{font-family:monospace}.card{background-color:#fff;border-radius:5px;box-shadow:0 2px 5px #0000001a;margin-bottom:20px;padding:20px}.status-box{background-color:#f6f8fa;border:1px solid #e1e4e8;border-radius:3px;padding:15px;white-space:pre-wrap;font-family:monospace;max-height:300px;overflow-y:auto}.layout-container{display:flex;gap:20px}.left-panel{flex:0 0 30%;max-width:30%}.right-panel{flex:0 0 70%;max-width:70%}@media (max-width: 768px){.layout-container{flex-direction:column}.left-panel,.right-panel{flex:0 0 100%;max-width:100%}.header-left{gap:8px}.logo{height:24px}h1{font-size:20px}}.commit-form{display:flex;margin-bottom:15px}.log-item{padding:10px 0;border-bottom:1px solid #eee}.log-item:last-child{border-bottom:none}.log-hash{color:#6f42c1;font-family:monospace}.log-author,.log-date{color:#6a737d}.log-message{font-weight:700}.log-branch{display:inline-block;background-color:#0366d6;color:#fff;border-radius:3px;padding:2px 6px;margin-left:8px;font-size:12px}.branch-select :deep(.el-input__inner){background-color:#ffffff1a;color:#fff;border:none}.branch-select :deep(.el-input__suffix){color:#fff}.tips{margin-top:20px;padding:15px;background-color:#f5f7fa;border-radius:5px;border-left:4px solid #409eff}.tips h3{margin-top:0;font-size:16px;margin-bottom:10px}.code-block{background-color:#2d2d2d;color:#f8f8f2;font-family:monospace;padding:10px 15px;border-radius:4px;margin-bottom:10px}.loading-container{display:flex;justify-content:center;align-items:center;min-height:400px}.loading-card{width:300px;text-align:center;padding:30px}.loading-spinner{font-size:48px;margin-bottom:20px;color:#409eff}.loading-text{font-size:18px;color:#606266}.user-settings-btn{margin-left:10px}.user-warning{color:#e6a23c;font-weight:700}.logo[data-v-0bd851aa]{will-change:filter;transition:filter .3s}.logo[data-v-0bd851aa]:hover{filter:drop-shadow(0 0 2em #42b883aa)}.main-footer[data-v-0bd851aa]{background-color:#24292e;color:#fff;padding:10px 20px;display:flex;justify-content:space-between;align-items:center;position:fixed;bottom:0;left:0;right:0;z-index:100;box-shadow:0 -2px 10px #0000001a}.branch-info[data-v-0bd851aa]{display:flex;align-items:center;gap:10px}.branch-wrapper[data-v-0bd851aa]{display:flex;align-items:center;background-color:#ffffff26;border-radius:4px;padding:8px 12px;box-shadow:0 2px 4px #0003;transition:all .3s}.branch-wrapper[data-v-0bd851aa]:hover{background-color:#fff3}.branch-label[data-v-0bd851aa]{font-weight:700;margin-right:10px;color:#fff}.branch-select[data-v-0bd851aa]{width:200px;margin-right:10px}.create-branch-btn[data-v-0bd851aa]{background-color:#2ea44f;border-color:#2ea44f;transition:all .3s;box-shadow:0 2px 4px #0003}.create-branch-btn[data-v-0bd851aa]:hover{background-color:#3bbc63;border-color:#3bbc63;transform:translateY(-2px);box-shadow:0 4px 8px #0003}.footer-right[data-v-0bd851aa]{display:flex;align-items:center;gap:10px;color:#ffffffe6;font-size:13px;background-color:#ffffff1a;padding:8px 12px;border-radius:4px;box-shadow:0 2px 4px #0003}
|