zen-gitsync 2.0.3 → 2.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/ui/client/components.d.ts +1 -0
- package/src/ui/client/package.json +1 -0
- package/src/ui/client/src/App.vue +368 -219
- package/src/ui/client/src/components/CommitForm.vue +777 -442
- package/src/ui/client/src/components/GitStatus.vue +89 -86
- package/src/ui/client/src/components/LogList.vue +393 -85
- package/src/ui/client/src/main.ts +3 -0
- package/src/ui/client/src/stores/gitLogStore.ts +464 -0
- package/src/ui/client/src/stores/gitStore.ts +301 -0
- package/src/ui/client/stats.html +1 -1
- package/src/ui/public/assets/index-CALk9kKc.js +9 -0
- package/src/ui/public/assets/index-D3zIiSNw.css +1 -0
- package/src/ui/public/assets/vendor-BfXVsoKv.js +45 -0
- package/src/ui/public/index.html +3 -3
- package/src/ui/server/index.js +197 -8
- package/src/ui/public/assets/index-BHmYZROy.css +0 -1
- package/src/ui/public/assets/index-kfMX1bxz.js +0 -9
- package/src/ui/public/assets/vendor-DxvF30ca.js +0 -41
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-CALk9kKc.js"></script>
|
|
9
|
+
<link rel="modulepreload" crossorigin href="/assets/vendor-BfXVsoKv.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-D3zIiSNw.css">
|
|
12
12
|
</head>
|
|
13
13
|
<body>
|
|
14
14
|
<div id="app"></div>
|
package/src/ui/server/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import open from 'open';
|
|
|
7
7
|
import config from '../../config.js';
|
|
8
8
|
import chalk from 'chalk';
|
|
9
9
|
import fs from 'fs/promises';
|
|
10
|
+
import os from 'os';
|
|
10
11
|
// import { Server } from 'socket.io';
|
|
11
12
|
// import { exec } from 'child_process';
|
|
12
13
|
|
|
@@ -22,6 +23,13 @@ async function startUIServer() {
|
|
|
22
23
|
// 添加全局中间件来解析JSON请求体
|
|
23
24
|
app.use(express.json());
|
|
24
25
|
|
|
26
|
+
// 添加请求日志中间件
|
|
27
|
+
app.use((req, res, next) => {
|
|
28
|
+
const now = new Date().toLocaleString();
|
|
29
|
+
console.log(`[${now}] ${req.method} ${req.url}`);
|
|
30
|
+
next();
|
|
31
|
+
});
|
|
32
|
+
|
|
25
33
|
// // 启动前端Vue应用
|
|
26
34
|
// const clientPath = path.join(__dirname, '../client');
|
|
27
35
|
// console.log(`正在启动前端应用,路径: ${clientPath}`);
|
|
@@ -148,10 +156,10 @@ async function startUIServer() {
|
|
|
148
156
|
// 获取Git用户配置信息
|
|
149
157
|
app.get('/api/user-info', async (req, res) => {
|
|
150
158
|
try {
|
|
151
|
-
//
|
|
152
|
-
const { stdout: userName } = await execGitCommand('git config user.name');
|
|
153
|
-
//
|
|
154
|
-
const { stdout: userEmail } = await execGitCommand('git config user.email');
|
|
159
|
+
// 获取全局用户名
|
|
160
|
+
const { stdout: userName } = await execGitCommand('git config --global user.name');
|
|
161
|
+
// 获取全局用户邮箱
|
|
162
|
+
const { stdout: userEmail } = await execGitCommand('git config --global user.email');
|
|
155
163
|
|
|
156
164
|
res.json({
|
|
157
165
|
name: userName.trim(),
|
|
@@ -376,6 +384,53 @@ async function startUIServer() {
|
|
|
376
384
|
}
|
|
377
385
|
})
|
|
378
386
|
|
|
387
|
+
// 更新模板
|
|
388
|
+
app.post('/api/config/update-template', express.json(), async (req, res) => {
|
|
389
|
+
try {
|
|
390
|
+
const { oldTemplate, newTemplate, type } = req.body
|
|
391
|
+
|
|
392
|
+
if (!oldTemplate || !newTemplate || !type) {
|
|
393
|
+
return res.status(400).json({ success: false, error: '缺少必要参数' })
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const config = await configManager.loadConfig()
|
|
397
|
+
|
|
398
|
+
if (type === 'description') {
|
|
399
|
+
// 确保描述模板数组存在
|
|
400
|
+
if (config.descriptionTemplates) {
|
|
401
|
+
const index = config.descriptionTemplates.indexOf(oldTemplate)
|
|
402
|
+
if (index !== -1) {
|
|
403
|
+
config.descriptionTemplates[index] = newTemplate
|
|
404
|
+
await configManager.saveConfig(config)
|
|
405
|
+
} else {
|
|
406
|
+
return res.status(404).json({ success: false, error: '未找到原模板' })
|
|
407
|
+
}
|
|
408
|
+
} else {
|
|
409
|
+
return res.status(404).json({ success: false, error: '模板列表不存在' })
|
|
410
|
+
}
|
|
411
|
+
} else if (type === 'scope') {
|
|
412
|
+
// 确保作用域模板数组存在
|
|
413
|
+
if (config.scopeTemplates) {
|
|
414
|
+
const index = config.scopeTemplates.indexOf(oldTemplate)
|
|
415
|
+
if (index !== -1) {
|
|
416
|
+
config.scopeTemplates[index] = newTemplate
|
|
417
|
+
await configManager.saveConfig(config)
|
|
418
|
+
} else {
|
|
419
|
+
return res.status(404).json({ success: false, error: '未找到原模板' })
|
|
420
|
+
}
|
|
421
|
+
} else {
|
|
422
|
+
return res.status(404).json({ success: false, error: '模板列表不存在' })
|
|
423
|
+
}
|
|
424
|
+
} else {
|
|
425
|
+
return res.status(400).json({ success: false, error: '不支持的模板类型' })
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
res.json({ success: true })
|
|
429
|
+
} catch (error) {
|
|
430
|
+
res.status(500).json({ success: false, error: error.message })
|
|
431
|
+
}
|
|
432
|
+
})
|
|
433
|
+
|
|
379
434
|
// 提交更改
|
|
380
435
|
app.post('/api/commit', express.json(), async (req, res) => {
|
|
381
436
|
try {
|
|
@@ -440,8 +495,11 @@ async function startUIServer() {
|
|
|
440
495
|
// 获取日志
|
|
441
496
|
app.get('/api/log', async (req, res) => {
|
|
442
497
|
try {
|
|
443
|
-
// 获取请求参数中的数量限制,默认为
|
|
444
|
-
const limit = req.query.all === 'true' ? '' : '-n
|
|
498
|
+
// 获取请求参数中的数量限制,默认为30
|
|
499
|
+
const limit = req.query.all === 'true' ? '' : '-n 30';
|
|
500
|
+
|
|
501
|
+
// graph参数保留但不做特殊处理,避免前端代码重复调用API
|
|
502
|
+
// 由前端统一使用该接口
|
|
445
503
|
|
|
446
504
|
// 修改 git log 命令,添加 %ae 参数来获取作者邮箱
|
|
447
505
|
const { stdout } = await execGitCommand(`git log --all --pretty=format:"%h|%an|%ae|%ad|%s|%D" --date=short ${limit}`);
|
|
@@ -533,6 +591,129 @@ async function startUIServer() {
|
|
|
533
591
|
}
|
|
534
592
|
});
|
|
535
593
|
|
|
594
|
+
// 重置暂存区 (git reset HEAD)
|
|
595
|
+
app.post('/api/reset-head', async (req, res) => {
|
|
596
|
+
try {
|
|
597
|
+
// 执行 git reset HEAD 命令
|
|
598
|
+
await execGitCommand('git reset HEAD');
|
|
599
|
+
res.json({ success: true });
|
|
600
|
+
} catch (error) {
|
|
601
|
+
console.error('重置暂存区失败:', error);
|
|
602
|
+
res.status(500).json({
|
|
603
|
+
success: false,
|
|
604
|
+
error: `重置暂存区失败: ${error.message}`
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
// 重置到远程分支 (git reset --hard origin/branch)
|
|
610
|
+
app.post('/api/reset-to-remote', async (req, res) => {
|
|
611
|
+
try {
|
|
612
|
+
const { branch } = req.body;
|
|
613
|
+
|
|
614
|
+
if (!branch) {
|
|
615
|
+
return res.status(400).json({
|
|
616
|
+
success: false,
|
|
617
|
+
error: '缺少分支名称参数'
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// 执行 git reset --hard origin/branch 命令
|
|
622
|
+
await execGitCommand(`git reset --hard origin/${branch}`);
|
|
623
|
+
res.json({ success: true });
|
|
624
|
+
} catch (error) {
|
|
625
|
+
console.error('重置到远程分支失败:', error);
|
|
626
|
+
res.status(500).json({
|
|
627
|
+
success: false,
|
|
628
|
+
error: `重置到远程分支失败: ${error.message}`
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
// 添加清理Git锁定文件的接口
|
|
634
|
+
app.post('/api/remove-lock', async (req, res) => {
|
|
635
|
+
try {
|
|
636
|
+
const gitDir = path.join(process.cwd(), '.git')
|
|
637
|
+
const indexLockFile = path.join(gitDir, 'index.lock')
|
|
638
|
+
|
|
639
|
+
// 检查文件是否存在
|
|
640
|
+
try {
|
|
641
|
+
await fs.access(indexLockFile)
|
|
642
|
+
// 如果文件存在,尝试删除它
|
|
643
|
+
await fs.unlink(indexLockFile)
|
|
644
|
+
res.json({ success: true, message: '已清理锁定文件' })
|
|
645
|
+
} catch (error) {
|
|
646
|
+
// 如果文件不存在,也返回成功
|
|
647
|
+
if (error.code === 'ENOENT') {
|
|
648
|
+
res.json({ success: true, message: '没有发现锁定文件' })
|
|
649
|
+
} else {
|
|
650
|
+
throw error
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
} catch (error) {
|
|
654
|
+
console.error('清理锁定文件失败:', error)
|
|
655
|
+
res.status(500).json({
|
|
656
|
+
success: false,
|
|
657
|
+
error: `清理锁定文件失败: ${error.message}`
|
|
658
|
+
})
|
|
659
|
+
}
|
|
660
|
+
})
|
|
661
|
+
|
|
662
|
+
// 清除Git用户配置
|
|
663
|
+
app.post('/api/clear-user-config', async (req, res) => {
|
|
664
|
+
try {
|
|
665
|
+
// 检查全局配置是否存在,如果存在才删除
|
|
666
|
+
try {
|
|
667
|
+
const { stdout: userName } = await execGitCommand('git config --global user.name');
|
|
668
|
+
if (userName.trim()) {
|
|
669
|
+
await execGitCommand('git config --global --unset user.name');
|
|
670
|
+
}
|
|
671
|
+
} catch (error) {
|
|
672
|
+
console.log('全局用户名配置检查失败,可能不存在:', error.message);
|
|
673
|
+
// 忽略错误继续执行
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
try {
|
|
677
|
+
const { stdout: userEmail } = await execGitCommand('git config --global user.email');
|
|
678
|
+
if (userEmail.trim()) {
|
|
679
|
+
await execGitCommand('git config --global --unset user.email');
|
|
680
|
+
}
|
|
681
|
+
} catch (error) {
|
|
682
|
+
console.log('全局邮箱配置检查失败,可能不存在:', error.message);
|
|
683
|
+
// 忽略错误继续执行
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
res.json({ success: true, message: '已清除全局Git用户配置' });
|
|
687
|
+
} catch (error) {
|
|
688
|
+
res.status(500).json({
|
|
689
|
+
success: false,
|
|
690
|
+
error: `清除全局Git用户配置失败: ${error.message}`
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
// 恢复Git用户配置
|
|
696
|
+
app.post('/api/restore-user-config', async (req, res) => {
|
|
697
|
+
try {
|
|
698
|
+
const { name, email } = req.body;
|
|
699
|
+
if (!name || !email) {
|
|
700
|
+
return res.status(400).json({
|
|
701
|
+
success: false,
|
|
702
|
+
error: '需要提供用户名和邮箱'
|
|
703
|
+
});
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
await execGitCommand(`git config --global user.name "${name}"`);
|
|
707
|
+
await execGitCommand(`git config --global user.email "${email}"`);
|
|
708
|
+
res.json({ success: true, message: '已更新全局Git用户配置' });
|
|
709
|
+
} catch (error) {
|
|
710
|
+
res.status(500).json({
|
|
711
|
+
success: false,
|
|
712
|
+
error: `更新全局Git用户配置失败: ${error.message}`
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
});
|
|
716
|
+
|
|
536
717
|
// Socket.io 实时更新
|
|
537
718
|
// io.on('connection', (socket) => {
|
|
538
719
|
// console.log('客户端已连接');
|
|
@@ -556,7 +737,11 @@ async function startUIServer() {
|
|
|
556
737
|
// 启动服务器
|
|
557
738
|
const PORT = 3000;
|
|
558
739
|
httpServer.listen(PORT, () => {
|
|
559
|
-
console.log(
|
|
740
|
+
console.log(chalk.green('======================================'));
|
|
741
|
+
console.log(chalk.green(` Zen GitSync 服务器已启动`));
|
|
742
|
+
console.log(chalk.green(` 访问地址: http://localhost:${PORT}`));
|
|
743
|
+
console.log(chalk.green(` 启动时间: ${new Date().toLocaleString()}`));
|
|
744
|
+
console.log(chalk.green('======================================'));
|
|
560
745
|
open(`http://localhost:${PORT}`);
|
|
561
746
|
}).on('error', async (err) => {
|
|
562
747
|
if (err.code === 'EADDRINUSE') {
|
|
@@ -566,7 +751,11 @@ async function startUIServer() {
|
|
|
566
751
|
try {
|
|
567
752
|
await new Promise((resolve, reject) => {
|
|
568
753
|
httpServer.listen(newPort, () => {
|
|
569
|
-
console.log(
|
|
754
|
+
console.log(chalk.green('======================================'));
|
|
755
|
+
console.log(chalk.green(` Zen GitSync 服务器已启动`));
|
|
756
|
+
console.log(chalk.green(` 访问地址: http://localhost:${newPort}`));
|
|
757
|
+
console.log(chalk.green(` 启动时间: ${new Date().toLocaleString()}`));
|
|
758
|
+
console.log(chalk.green('======================================'));
|
|
570
759
|
open(`http://localhost:${newPort}`);
|
|
571
760
|
resolve();
|
|
572
761
|
}).on('error', (e) => {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.card[data-v-61ea34c7]{background-color:#fff;border-radius:8px;box-shadow:0 2px 12px #0000001a;padding:20px;margin-bottom:20px}.status-header[data-v-61ea34c7]{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}.status-header h2[data-v-61ea34c7]{margin:0}.status-box[data-v-61ea34c7]{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-61ea34c7]{max-height:300px;overflow-y:auto}.file-item[data-v-61ea34c7]{padding:8px 12px;margin-bottom:5px;border-radius:4px;cursor:pointer;display:flex;align-items:center;justify-content:space-between}.file-item[data-v-61ea34c7]:hover{background-color:#f5f7fa}.file-info[data-v-61ea34c7]{display:flex;align-items:center;flex-grow:1}.file-actions[data-v-61ea34c7]{margin-left:10px;opacity:.5;transition:opacity .2s}.file-item:hover .file-actions[data-v-61ea34c7]{opacity:1}.file-type[data-v-61ea34c7]{font-size:12px;padding:2px 6px;border-radius:10px;margin-right:10px;flex-shrink:0}.added .file-type[data-v-61ea34c7]{background-color:#e1f3d8;color:#67c23a}.modified .file-type[data-v-61ea34c7]{background-color:#e6f1fc;color:#409eff}.deleted .file-type[data-v-61ea34c7]{background-color:#fef0f0;color:#f56c6c}.untracked .file-type[data-v-61ea34c7]{background-color:#fdf6ec;color:#e6a23c}.file-path[data-v-61ea34c7]{font-family:monospace;word-break:break-all}.diff-content[data-v-61ea34c7]{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-61ea34c7]{font-size:14px;line-height:1.5}.file-navigation[data-v-61ea34c7]{display:flex;justify-content:center;align-items:center;margin-top:15px}.file-counter[data-v-61ea34c7]{margin:0 15px;font-size:14px;color:#606266}.current-directory[data-v-61ea34c7]{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-61ea34c7]{margin-right:8px;color:#409eff}.current-directory span[data-v-61ea34c7]{flex-grow:1;word-break:break-all;margin-right:10px}.browser-current-path[data-v-61ea34c7]{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-61ea34c7]{margin-bottom:10px;color:#f56c6c;padding:8px 12px;background-color:#fef0f0;border-radius:4px}.directory-browser[data-v-61ea34c7]{padding:10px;max-height:400px;overflow-y:auto}.browser-nav[data-v-61ea34c7]{margin-bottom:10px;display:flex;justify-content:space-between}.directory-items[data-v-61ea34c7]{list-style:none;padding:0;margin:0}.directory-item[data-v-61ea34c7]{padding:8px 12px;margin-bottom:5px;border-radius:4px;cursor:pointer;display:flex;align-items:center}.directory-item[data-v-61ea34c7]:hover{background-color:#f5f7fa}.directory-item.directory[data-v-61ea34c7]{color:#409eff}.directory-item.file[data-v-61ea34c7]{color:#606266}.directory-item .el-icon[data-v-61ea34c7]{margin-right:10px}.directory-item span[data-v-61ea34c7]{font-family:monospace;word-break:break-all}.directory-buttons[data-v-61ea34c7]{display:flex;gap:10px;margin-top:10px}.no-padding-left[data-v-61ea34c7]{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}.commit-form[data-v-00e49634]{display:flex;margin-bottom:15px;gap:10px}.button-group[data-v-00e49634]{display:flex;gap:10px}.commit-mode-toggle[data-v-00e49634]{margin-bottom:15px}.standard-commit-form[data-v-00e49634]{display:flex;flex-direction:column;gap:15px;margin-bottom:15px}.standard-commit-header[data-v-00e49634]{display:flex;gap:10px;width:100%}.type-select[data-v-00e49634]{width:120px;flex-shrink:0}.scope-container[data-v-00e49634]{display:flex;align-items:center;gap:5px;flex-grow:0;width:200px}.scope-input[data-v-00e49634]{flex-grow:1}.description-container[data-v-00e49634]{display:flex;align-items:center;gap:5px;flex-grow:1}.description-input[data-v-00e49634]{flex-grow:1;min-width:200px}.settings-button[data-v-00e49634]{flex-shrink:0}.preview-section[data-v-00e49634]{background-color:#f5f7fa;padding:10px;border-radius:4px}.preview-title[data-v-00e49634]{font-weight:700;margin-bottom:5px}.preview-content[data-v-00e49634]{white-space:pre-wrap;font-family:monospace;margin:0;padding:10px;background-color:#ebeef5;border-radius:4px}.template-container[data-v-00e49634]{display:flex;flex-direction:column;height:calc(85vh - 100px);overflow-y:auto}.template-form[data-v-00e49634]{margin-bottom:20px}.template-list[data-v-00e49634]{flex:1;overflow-y:auto}.template-input[data-v-00e49634]{flex-grow:1}.template-list[data-v-00e49634]{overflow-y:auto;height:100%}.template-item[data-v-00e49634]{margin-bottom:10px}.template-item[data-v-00e49634]:hover{background-color:#f5f7fa}.template-content[data-v-00e49634]{flex-grow:1;margin-right:10px;word-break:break-all}.template-actions[data-v-00e49634]{display:flex;gap:5px;justify-content:flex-end;min-width:120px;flex-shrink:0}.log-header[data-v-c6b721c7]{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}.log-actions[data-v-c6b721c7]{display:flex;gap:8px}.branch-container[data-v-c6b721c7]{display:flex;flex-wrap:wrap;gap:4px}.branch-tag[data-v-c6b721c7]{margin-right:4px}.commit-count[data-v-c6b721c7]{margin-bottom:10px;font-size:14px;color:#606266;text-align:right}.graph-container[data-v-c6b721c7]{width:100%;height:600px;overflow:auto;border:1px solid #ebeef5;border-radius:4px;padding:10px;background-color:#fff}.graph-view[data-v-c6b721c7]{width:100%}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{width:150px;margin-left:5px}.branch-select :deep(.el-input__inner){background-color:#ffffff1a;color:#fff;border:none}.branch-select :deep(.el-input__suffix){color:#fff}.logo[data-v-93cc73d5]{will-change:filter;transition:filter .3s}.logo[data-v-93cc73d5]:hover{filter:drop-shadow(0 0 2em #42b883aa)}.main-footer[data-v-93cc73d5]{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}.branch-info[data-v-93cc73d5]{display:flex;align-items:center}.footer-right[data-v-93cc73d5]{color:#ffffffb3;font-size:12px}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import{d as ce,r as l,o as ue,c as g,a as d,b as a,e as q,f as t,E as xe,w as r,u as S,g as ge,t as w,h as se,i as B,j as Ae,F as K,k as Y,l as he,m as je,n as Be,p as _e,q as ye,s as Ne,v as $e,x as Z,y as Me,z as De,A as Ee,B as Re,C as c,D as Ue,G as Oe,H as ze,I as Ie,J as Ve,K as Fe,L as Ge,M as Pe,N as Le,O as Se,P as Je,Q as He,R as We,S as ne,T as Ze,U as qe,V as Ke,W as Qe,X as Xe}from"./vendor-DxvF30ca.js";(function(){const G=document.createElement("link").relList;if(G&&G.supports&&G.supports("modulepreload"))return;for(const n of document.querySelectorAll('link[rel="modulepreload"]'))y(n);new MutationObserver(n=>{for(const h of n)if(h.type==="childList")for(const z of h.addedNodes)z.tagName==="LINK"&&z.rel==="modulepreload"&&y(z)}).observe(document,{childList:!0,subtree:!0});function p(n){const h={};return n.integrity&&(h.integrity=n.integrity),n.referrerPolicy&&(h.referrerPolicy=n.referrerPolicy),n.crossOrigin==="use-credentials"?h.credentials="include":n.crossOrigin==="anonymous"?h.credentials="omit":h.credentials="same-origin",h}function y(n){if(n.ep)return;n.ep=!0;const h=p(n);fetch(n.href,h)}})();const Ye={class:"card"},et={class:"current-directory"},tt={class:"status-header"},st={class:"status-box"},at={key:0,class:"file-list"},lt=["onClick"],ot={class:"file-type"},nt={class:"file-path"},it={class:"file-actions"},rt={class:"directory-buttons"},ct={class:"browser-current-path"},ut={key:0,class:"browser-error"},dt={class:"directory-browser"},pt={class:"browser-nav"},ft={class:"directory-items"},vt=["onClick"],mt={class:"diff-content"},gt=["innerHTML"],yt={key:1,class:"no-diff"},ht={class:"file-navigation"},_t={class:"file-counter"},wt=ce({__name:"GitStatus",setup(O,{expose:G}){const p=l("加载中..."),y=l(!1),n=l([]),h=l(""),z=l(""),P=l(!1),E=l(!1),L=l(-1),I=l(!1),F=l(""),A=l(!1),J=l(!1),k=l(""),C=l([]),$=l(!1),f=l("");function j(u){if(u===void 0)return;const o=u.split(`
|
|
2
|
-
`),V=[];for(const m of o){const s=m.match(/^([ MADRCU\?]{2})\s+(.+)$/);if(s){let e="";const x=s[1].trim();x==="M"||x==="MM"||x==="AM"||x==="RM"?e="modified":x==="A"||x==="AA"?e="added":x==="D"||x==="AD"||x==="DA"?e="deleted":x==="??"?e="untracked":e="other",V.push({path:s[2],type:e})}}n.value=V}const T=l("");async function N(){try{y.value=!0;const o=await(await fetch("/api/current_directory")).json();if(T.value=o.directory||"未知目录",o.isGitRepo===!1){p.value="当前目录不是一个Git仓库",n.value=[],c.warning("当前目录不是一个Git仓库");return}const m=await(await fetch("/api/status")).json();p.value=m.status;const e=await(await fetch("/api/status_porcelain")).json();j(e.status),c({message:"Git 状态已刷新",type:"success"})}catch(u){p.value="加载状态失败: "+u.message,n.value=[],c({message:"刷新失败: "+u.message,type:"error"})}finally{y.value=!1}}function R(u){if(!u)return"";const o=u.split(`
|
|
3
|
-
`);function V(m){return m.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}return o.map(m=>{const s=V(m);return m.startsWith("diff --git")?`<div class="diff-header">${s}</div>`:m.startsWith("---")?`<div class="diff-old-file">${s}</div>`:m.startsWith("+++")?`<div class="diff-new-file">${s}</div>`:m.startsWith("@@")?`<div class="diff-hunk-header">${s}</div>`:m.startsWith("+")?`<div class="diff-added">${s}</div>`:m.startsWith("-")?`<div class="diff-removed">${s}</div>`:`<div class="diff-context">${s}</div>`}).join("")}async function _(u){try{E.value=!0,h.value=u,L.value=n.value.findIndex(m=>m.path===u);const V=await(await fetch(`/api/diff?file=${encodeURIComponent(u)}`)).json();z.value=V.diff||"没有变更",P.value=!0}catch(o){c({message:"获取文件差异失败: "+o.message,type:"error"}),z.value="获取差异失败: "+o.message}finally{E.value=!1}}async function i(){if(n.value.length===0||L.value<=0)return;const u=L.value-1,o=n.value[u];await _(o.path)}async function H(){if(n.value.length===0||L.value>=n.value.length-1)return;const u=L.value+1,o=n.value[u];await _(o.path)}function te(){F.value=T.value,I.value=!0}function Q(){f.value="",k.value=F.value||T.value,J.value=!0,X(k.value)}async function X(u){try{$.value=!0,f.value="";let o=u;/^[A-Za-z]:$/.test(o)&&(o+="/");const V=await fetch(`/api/browse_directory?path=${encodeURIComponent(o)}`);if(V.status===403){const s=await V.json();f.value=s.error||"目录浏览功能未启用";return}if(!V.ok){const s=await V.json();f.value=s.error||"获取目录内容失败";return}const m=await V.json();m.success?(C.value=m.items,k.value=m.currentPath):f.value=m.error||"获取目录内容失败"}catch(o){f.value=`获取目录内容失败: ${o.message}`}finally{$.value=!1}}function ae(){if(/^[A-Za-z]:$/.test(k.value)||/^[A-Za-z]:[\\/]$/.test(k.value)||k.value==="/")return;let u=k.value.split(/[/\\]/);u.pop();let o=u.join("/");u.length===1&&/^[A-Za-z]:$/.test(u[0])&&(o=u[0]+"/"),o&&X(o)}function ee(u){u.type==="directory"&&X(u.path)}function le(){F.value=k.value,J.value=!1}async function oe(){if(!F.value){c.warning("目录路径不能为空");return}try{A.value=!0;const o=await(await fetch("/api/change_directory",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:F.value})})).json();o.success?(c.success("已切换工作目录"),T.value=o.directory,I.value=!1,o.isGitRepo||c.warning("当前目录不是一个Git仓库"),N()):c.error(o.error||"切换目录失败")}catch(u){c.error(`切换目录失败: ${u.message}`)}finally{A.value=!1}}function D(u){_(u.path)}function pe(u){switch(u){case"added":return"新增";case"modified":return"修改";case"deleted":return"删除";case"untracked":return"未跟踪";default:return"其他"}}async function ie(){await N()}async function fe(u){try{await Ie.confirm(`确定要撤回文件 "${u}" 的所有修改吗?此操作无法撤销。`,"撤回修改",{confirmButtonText:"确定",cancelButtonText:"取消",type:"warning"});const V=await(await fetch("/api/revert_file",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({filePath:u})})).json();V.success?(c.success("已撤回文件修改"),await N()):c.error(V.error||"撤回文件修改失败")}catch(o){o.message!=="cancel"&&c.error(`撤回文件修改失败: ${o.message}`)}}return ue(()=>{N()}),G({refreshStatus:ie}),(u,o)=>{const V=xe,m=se,s=ze,e=_e,x=Be,W=je,M=he,U=De;return d(),g("div",Ye,[a("div",et,[t(V,null,{default:r(()=>[t(S(ge))]),_:1}),a("span",null,w(T.value),1),t(m,{type:"primary",size:"small",onClick:te,plain:""},{default:r(()=>o[4]||(o[4]=[B(" 切换目录 ")])),_:1})]),a("div",tt,[o[5]||(o[5]=a("h2",null,"Git 状态",-1)),t(m,{type:"primary",icon:S(Ae),circle:"",size:"small",onClick:ie,loading:y.value},null,8,["icon","loading"])]),a("div",st,w(p.value),1),n.value.length?(d(),g("div",at,[(d(!0),g(K,null,Y(n.value,b=>(d(),g("div",{key:b.path,class:$e(["file-item",b.type])},[a("div",{class:"file-info",onClick:re=>D(b)},[a("span",ot,w(pe(b.type)),1),a("span",nt,w(b.path),1)],8,lt),a("div",it,[t(s,{content:"撤回修改",placement:"top","hide-after":1e3},{default:r(()=>[t(m,{type:"danger",size:"small",icon:S(Oe),circle:"",onClick:Ue(re=>fe(b.path),["stop"])},null,8,["icon","onClick"])]),_:2},1024)])],2))),128))])):q("",!0),t(M,{modelValue:I.value,"onUpdate:modelValue":o[1]||(o[1]=b=>I.value=b),title:"切换工作目录",width:"500px"},{default:r(()=>[t(W,null,{default:r(()=>[t(x,{label:"目录路径"},{default:r(()=>[t(e,{modelValue:F.value,"onUpdate:modelValue":o[0]||(o[0]=b=>F.value=b),placeholder:"请输入目录路径",clearable:""},null,8,["modelValue"]),a("div",rt,[t(m,{onClick:Q,type:"primary",plain:"",class:"no-padding-left"},{default:r(()=>[t(V,null,{default:r(()=>[t(S(ge))]),_:1}),o[6]||(o[6]=B(" 浏览 "))]),_:1}),t(m,{onClick:oe,loading:A.value,type:"primary"},{default:r(()=>o[7]||(o[7]=[B(" 切换 ")])),_:1},8,["loading"])])]),_:1})]),_:1})]),_:1},8,["modelValue"]),t(M,{modelValue:J.value,"onUpdate:modelValue":o[2]||(o[2]=b=>J.value=b),title:"浏览目录",width:"600px"},{default:r(()=>[a("div",ct,[a("span",null,"当前路径: "+w(k.value),1)]),f.value?(d(),g("div",ut,w(f.value),1)):q("",!0),ye((d(),g("div",dt,[a("div",pt,[t(m,{onClick:ae,disabled:!k.value||$.value,size:"small",class:"no-padding-left"},{default:r(()=>[t(V,null,{default:r(()=>[t(S(Ne))]),_:1}),o[8]||(o[8]=B(" 上级目录 "))]),_:1},8,["disabled"]),t(m,{onClick:le,type:"primary",size:"small",class:"no-padding-left"},{default:r(()=>o[9]||(o[9]=[B(" 选择当前目录 ")])),_:1})]),a("ul",ft,[(d(!0),g(K,null,Y(C.value,b=>(d(),g("li",{key:b.path,class:$e(["directory-item",b.type]),onClick:re=>ee(b)},[b.type==="directory"?(d(),Z(V,{key:0},{default:r(()=>[t(S(ge))]),_:1})):(d(),Z(V,{key:1},{default:r(()=>[t(S(Me))]),_:1})),a("span",null,w(b.name),1)],10,vt))),128))])])),[[U,$.value]])]),_:1},8,["modelValue"]),t(M,{modelValue:P.value,"onUpdate:modelValue":o[3]||(o[3]=b=>P.value=b),title:`文件差异: ${h.value}`,width:"80%","destroy-on-close":""},{default:r(()=>[ye((d(),g("div",mt,[z.value?(d(),g("div",{key:0,innerHTML:R(z.value),class:"diff-formatted"},null,8,gt)):(d(),g("div",yt,"该文件没有差异或是新文件"))])),[[U,E.value]]),a("div",ht,[t(m,{icon:S(Ee),onClick:i,disabled:L.value<=0||n.value.length===0,circle:""},null,8,["icon","disabled"]),a("span",_t,w(L.value+1)+" / "+w(n.value.length),1),t(m,{icon:S(Re),onClick:H,disabled:L.value>=n.value.length-1||n.value.length===0,circle:""},null,8,["icon","disabled"])])]),_:1},8,["modelValue","title"])])}}}),de=(O,G)=>{const p=O.__vccOpts||O;for(const[y,n]of G)p[y]=n;return p},bt=de(wt,[["__scopeId","data-v-61ea34c7"]]),kt={class:"card"},Ct={class:"commit-options"},$t={class:"commit-mode-toggle"},Vt={class:"no-verify-toggle"},St={key:0,class:"commit-form"},Tt={key:1,class:"standard-commit-form"},xt={class:"standard-commit-header"},jt={class:"scope-container"},Bt={class:"description-container"},Dt={class:"preview-section"},Ot={class:"preview-content"},zt={class:"button-group"},Pt={class:"template-container"},Lt={class:"template-form"},At={class:"template-list"},Nt={class:"template-content"},Mt={class:"template-actions"},Et={class:"template-container"},Rt={class:"template-form"},Ut={class:"template-list"},It={class:"template-content"},Ft={class:"template-actions"},Gt=ce({__name:"CommitForm",emits:["commit-success","push-success"],setup(O,{emit:G}){const p=G,y=l(""),n=l("提交"),h=l("推送到远程"),z=l(!1),P=l(!1),E=l(!1),L=l("提交并推送"),I=l("输入提交信息..."),F=l(""),A=l(!1),J=l("feat"),k=l(""),C=l(""),$=l(""),f=l(""),j=l([]),T=l(!1),N=l(""),R=l([]),_=l(!1),i=l(""),H=l(!1),te=[{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: 构建/工具修改"}];Ve(A,s=>{localStorage.setItem("zen-gitsync-standard-commit",s.toString())}),Ve(H,s=>{localStorage.setItem("zen-gitsync-skip-hooks",s.toString())});const Q=Fe(()=>{if(!A.value)return y.value||F.value;let s=`${J.value||""}`;return k.value&&(s+=`(${k.value})`),s+=`: ${C.value}`,$.value&&(s+=`
|
|
4
|
-
|
|
5
|
-
${$.value}`),f.value&&(s+=`
|
|
6
|
-
|
|
7
|
-
${f.value}`),s});async function X(){try{const e=await(await fetch("/api/config/getConfig")).json();I.value=`输入提交信息 (默认: ${e.defaultCommitMessage})`,F.value=e.defaultCommitMessage||"",e.descriptionTemplates&&Array.isArray(e.descriptionTemplates)&&(j.value=e.descriptionTemplates),e.scopeTemplates&&Array.isArray(e.scopeTemplates)&&(R.value=e.scopeTemplates)}catch(s){console.error("加载配置失败:",s)}}async function ae(){if(!N.value.trim()){c({message:"请输入模板内容",type:"warning"});return}try{if(j.value.includes(N.value)){c({message:"该模板已存在",type:"warning"});return}j.value.push(N.value);const e=await(await fetch("/api/config/save-template",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({template:N.value,type:"description"})})).json();e.success?(c({message:"模板保存成功!",type:"success"}),N.value=""):c({message:"模板保存失败: "+e.error,type:"error"})}catch(s){c({message:"模板保存失败: "+s.message,type:"error"})}}async function ee(){if(!i.value.trim()){c({message:"请输入模板内容",type:"warning"});return}try{if(R.value.includes(i.value)){c({message:"该模板已存在",type:"warning"});return}R.value.push(i.value);const e=await(await fetch("/api/config/save-template",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({template:i.value,type:"scope"})})).json();e.success?(c({message:"作用域模板保存成功!",type:"success"}),i.value=""):c({message:"作用域模板保存失败: "+e.error,type:"error"})}catch(s){c({message:"作用域模板保存失败: "+s.message,type:"error"})}}async function le(s){try{const e=j.value.indexOf(s);e!==-1&&j.value.splice(e,1);const W=await(await fetch("/api/config/delete-template",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({template:s,type:"description"})})).json();W.success?c({message:"模板删除成功!",type:"success"}):c({message:"模板删除失败: "+W.error,type:"error"})}catch(e){c({message:"模板删除失败: "+e.message,type:"error"})}}async function oe(s){try{const e=R.value.indexOf(s);e!==-1&&R.value.splice(e,1);const W=await(await fetch("/api/config/delete-template",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({template:s,type:"scope"})})).json();W.success?c({message:"作用域模板删除成功!",type:"success"}):c({message:"作用域模板删除失败: "+W.error,type:"error"})}catch(e){c({message:"作用域模板删除失败: "+e.message,type:"error"})}}function D(s){C.value=s,T.value=!1}function pe(s){k.value=s,_.value=!1}function ie(){T.value=!0}function fe(){_.value=!0}function u(){const s=localStorage.getItem("zen-gitsync-standard-commit");s!==null&&(A.value=s==="true");const e=localStorage.getItem("zen-gitsync-skip-hooks");e!==null&&(H.value=e==="true")}async function o(){const s=Q.value;if(!s&&A.value&&!C.value){c({message:"请输入提交描述",type:"warning"});return}try{z.value=!0,n.value="提交中...";const x=await(await fetch("/api/add",{method:"POST"})).json();if(!x.success){c({message:"添加文件失败: "+x.error,type:"error"});return}const M=await(await fetch("/api/commit",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({message:s,hasNewlines:s.includes(`
|
|
8
|
-
`),noVerify:H.value})})).json();M.success?(A.value?(C.value="",$.value="",f.value=""):y.value="",c({message:"提交成功!",type:"success"}),p("commit-success")):c({message:"提交失败: "+M.error,type:"error"})}catch(e){c({message:"提交失败: "+e.message,type:"error"})}finally{z.value=!1,n.value="提交"}}async function V(){try{P.value=!0,h.value="推送中...";const e=await(await fetch("/api/push",{method:"POST"})).json();e.success?(c({message:"推送成功!",type:"success"}),p("push-success")):c({message:"推送失败: "+e.error,type:"error"})}catch(s){c({message:"推送失败: "+s.message,type:"error"})}finally{P.value=!1,h.value="推送到远程"}}async function m(){const s=Q.value;if(!s&&A.value&&!C.value){c({message:"请输入提交描述",type:"warning"});return}try{E.value=!0,L.value="处理中...";const x=await(await fetch("/api/add",{method:"POST"})).json();if(!x.success){c({message:"添加文件失败: "+x.error,type:"error"});return}const M=await(await fetch("/api/commit",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({message:s,hasNewlines:s.includes(`
|
|
9
|
-
`),noVerify:H.value})})).json();if(!M.success){c({message:"提交失败: "+M.error,type:"error"});return}A.value?(C.value="",$.value="",f.value=""):y.value="";const b=await(await fetch("/api/push",{method:"POST"})).json();b.success?(y.value="",c({message:"提交并推送成功!",type:"success"}),p("commit-success"),p("push-success")):c({message:"推送失败: "+b.error,type:"error"})}catch(e){c({message:"操作失败: "+e.message,type:"error"})}finally{E.value=!1,L.value="提交并推送"}}return ue(()=>{X(),u()}),(s,e)=>{const x=Ge,W=ze,M=_e,U=se,b=Le,re=Pe,we=Je,be=We,ke=He,Ce=he;return d(),g("div",kt,[e[21]||(e[21]=a("h2",null,"提交更改",-1)),a("div",Ct,[a("div",$t,[t(x,{modelValue:A.value,"onUpdate:modelValue":e[0]||(e[0]=v=>A.value=v),"active-text":"标准化提交","inactive-text":"普通提交"},null,8,["modelValue"])]),a("div",Vt,[t(W,{content:"跳过 Git 钩子检查 (--no-verify)",placement:"top"},{default:r(()=>[t(x,{modelValue:H.value,"onUpdate:modelValue":e[1]||(e[1]=v=>H.value=v),"active-text":"跳过钩子 (--no-verify)"},null,8,["modelValue"])]),_:1})])]),A.value?(d(),g("div",Tt,[a("div",xt,[t(re,{modelValue:J.value,"onUpdate:modelValue":e[3]||(e[3]=v=>J.value=v),placeholder:"提交类型",class:"type-select",clearable:""},{default:r(()=>[(d(),g(K,null,Y(te,v=>t(b,{key:v.value,label:v.label,value:v.value},null,8,["label","value"])),64))]),_:1},8,["modelValue"]),a("div",jt,[t(M,{modelValue:k.value,"onUpdate:modelValue":e[4]||(e[4]=v=>k.value=v),placeholder:"作用域(可选)",class:"scope-input",clearable:""},null,8,["modelValue"]),t(U,{type:"primary",icon:S(Se),circle:"",size:"small",class:"settings-button",onClick:fe},null,8,["icon"])]),a("div",Bt,[t(M,{modelValue:C.value,"onUpdate:modelValue":e[5]||(e[5]=v=>C.value=v),placeholder:"简短描述(必填)",class:"description-input",clearable:""},null,8,["modelValue"]),t(U,{type:"primary",icon:S(Se),circle:"",size:"small",class:"settings-button",onClick:ie},null,8,["icon"])])]),t(M,{modelValue:$.value,"onUpdate:modelValue":e[6]||(e[6]=v=>$.value=v),type:"textarea",rows:4,placeholder:"正文(可选):详细描述本次提交的内容和原因",class:"body-input",clearable:""},null,8,["modelValue"]),t(M,{modelValue:f.value,"onUpdate:modelValue":e[7]||(e[7]=v=>f.value=v),placeholder:"页脚(可选):如 Closes #123",class:"footer-input",clearable:""},null,8,["modelValue"]),a("div",Dt,[e[12]||(e[12]=a("div",{class:"preview-title"},"预览:",-1)),a("pre",Ot,w(Q.value),1)]),t(U,{type:"primary",onClick:o,loading:z.value},{default:r(()=>[B(w(n.value),1)]),_:1},8,["loading"])])):(d(),g("div",St,[t(M,{modelValue:y.value,"onUpdate:modelValue":e[2]||(e[2]=v=>y.value=v),placeholder:I.value,clearable:""},null,8,["modelValue","placeholder"]),t(U,{type:"primary",onClick:o,loading:z.value},{default:r(()=>[B(w(n.value),1)]),_:1},8,["loading"])])),a("div",zt,[t(U,{type:"success",onClick:V,loading:P.value},{default:r(()=>[B(w(h.value),1)]),_:1},8,["loading"]),t(U,{type:"warning",onClick:m,loading:E.value},{default:r(()=>[B(w(L.value),1)]),_:1},8,["loading"])]),t(Ce,{title:"简短描述模板设置",modelValue:T.value,"onUpdate:modelValue":e[9]||(e[9]=v=>T.value=v),width:"80vw",style:{height:"80vh"}},{default:r(()=>[a("div",Pt,[a("div",Lt,[t(M,{modelValue:N.value,"onUpdate:modelValue":e[8]||(e[8]=v=>N.value=v),placeholder:"输入新模板内容",class:"template-input",clearable:""},null,8,["modelValue"]),t(U,{type:"primary",onClick:ae,disabled:!N.value.trim()},{default:r(()=>e[13]||(e[13]=[B("添加模板")])),_:1},8,["disabled"])]),a("div",At,[e[16]||(e[16]=a("h3",null,"已保存模板",-1)),j.value.length===0?(d(),Z(we,{key:0,description:"暂无保存的模板"})):q("",!0),(d(!0),g(K,null,Y(j.value,(v,ve)=>(d(),Z(ke,{key:ve,class:"template-item"},{default:r(()=>[t(be,{justify:"space-between",align:"middle",style:{width:"100%"}},{default:r(()=>[a("div",Nt,w(v),1),a("div",Mt,[t(U,{type:"primary",size:"small",onClick:me=>D(v)},{default:r(()=>e[14]||(e[14]=[B("使用")])),_:2},1032,["onClick"]),t(U,{type:"danger",size:"small",onClick:me=>le(v)},{default:r(()=>e[15]||(e[15]=[B("删除")])),_:2},1032,["onClick"])])]),_:2},1024)]),_:2},1024))),128))])])]),_:1},8,["modelValue"]),t(Ce,{title:"作用域模板设置",modelValue:_.value,"onUpdate:modelValue":e[11]||(e[11]=v=>_.value=v),width:"80%",style:{height:"80vh"}},{default:r(()=>[a("div",Et,[a("div",Rt,[t(M,{modelValue:i.value,"onUpdate:modelValue":e[10]||(e[10]=v=>i.value=v),placeholder:"输入新作用域模板",class:"template-input",clearable:""},null,8,["modelValue"]),t(U,{type:"primary",onClick:ee,disabled:!i.value.trim()},{default:r(()=>e[17]||(e[17]=[B("添加模板")])),_:1},8,["disabled"])]),a("div",Ut,[e[20]||(e[20]=a("h3",null,"已保存作用域",-1)),R.value.length===0?(d(),Z(we,{key:0,description:"暂无保存的作用域"})):q("",!0),(d(!0),g(K,null,Y(R.value,(v,ve)=>(d(),Z(ke,{key:ve,class:"template-item"},{default:r(()=>[t(be,{justify:"space-between",align:"middle",style:{width:"100%"}},{default:r(()=>[a("div",It,w(v),1),a("div",Ft,[t(U,{type:"primary",size:"small",onClick:me=>pe(v)},{default:r(()=>e[18]||(e[18]=[B("使用")])),_:2},1032,["onClick"]),t(U,{type:"danger",size:"small",onClick:me=>oe(v)},{default:r(()=>e[19]||(e[19]=[B("删除")])),_:2},1032,["onClick"])])]),_:2},1024)]),_:2},1024))),128))])])]),_:1},8,["modelValue"])])}}}),Jt=de(Gt,[["__scopeId","data-v-00e49634"]]),Ht={class:"card"},Wt={class:"log-header"},Zt={class:"log-actions"},qt={key:0},Kt={key:1},Qt={key:0,class:"graph-view"},Xt={key:0,class:"commit-count"},Yt={key:1},es={key:0,class:"commit-count"},ts={key:0,class:"branch-container"};function Te(O){return O=O.trim().replace(/^HEAD\s*->\s*/,""),O=O.replace(/^origin\//,""),O=O.replace(/^tag:\s*/,""),O.trim()}function ss(O){return O.includes("HEAD")?"success":O.includes("tag:")?"warning":O.includes("origin/")?"info":"primary"}const as=ce({__name:"LogList",setup(O,{expose:G}){const p=l([]),y=l(""),n=l(!1),h=l(!1),z=l(0),P=l(!0),E=l(null);async function L(k=!1){try{n.value=!0,h.value=k;const $=await fetch(k?"/api/log?all=true&graph=true":"/api/log?graph=true");p.value=await $.json(),z.value=p.value.length,y.value="",P.value&&setTimeout(I,0)}catch(C){y.value="加载提交历史失败: "+C.message}finally{n.value=!1}}async function I(){if(!E.value||p.value.length===0)return;E.value.innerHTML="";const k=await fetch("/api/branch"),{branch:C}=await k.json(),$=Ke(E.value,{orientation:"vertical-reverse",template:"metro",author:"提交者 <committer@example.com>"}),f={},j=$.branch(C||"main");f[C||"main"]=j,p.value.forEach(T=>{let N=j;if(T.branch){const R=Te(T.branch.split(",")[0]);f[R]||(f[R]=$.branch(R)),N=f[R]}N.commit({hash:T.hash,subject:T.message,author:`${T.author} <${T.email}>`})})}function F(){P.value=!P.value,P.value&&p.value.length>0&&setTimeout(I,0)}function A(){L(!h.value)}ue(()=>{L()});const J=()=>L(h.value);return G({refreshLog:J}),(k,C)=>{const $=De;return d(),g("div",Ht,[a("div",Wt,[C[1]||(C[1]=a("h2",null,"提交历史",-1)),a("div",Zt,[t(S(se),{type:"primary",size:"small",onClick:F},{default:r(()=>[B(w(P.value?"表格视图":"图表视图"),1)]),_:1}),t(S(se),{type:"primary",size:"small",onClick:A,loading:n.value},{default:r(()=>[B(w(h.value?"显示最近100条":"显示所有提交"),1)]),_:1},8,["loading"]),t(S(se),{icon:S(Oe),circle:"",size:"small",onClick:C[0]||(C[0]=f=>J()),loading:n.value},null,8,["icon","loading"])])]),y.value?(d(),g("div",qt,w(y.value),1)):(d(),g("div",Kt,[P.value?(d(),g("div",Qt,[p.value.length>0?(d(),g("div",Xt," 显示 "+w(p.value.length)+" 条提交记录 "+w(h.value?"(全部)":"(最近100条)"),1)):q("",!0),a("div",{ref_key:"graphContainer",ref:E,class:"graph-container"},null,512)])):(d(),g("div",Yt,[p.value.length>0?(d(),g("div",es," 显示 "+w(p.value.length)+" 条提交记录 "+w(h.value?"(全部)":"(最近100条)"),1)):q("",!0),ye((d(),Z(S(qe),{data:p.value,style:{width:"100%"},stripe:"",border:""},{default:r(()=>[t(S(ne),{prop:"hash",label:"提交哈希",width:"100",resizable:""}),t(S(ne),{prop:"date",label:"日期",width:"180",resizable:""}),t(S(ne),{label:"作者",width:"200",resizable:""},{default:r(f=>[B(w(f.row.author)+" <"+w(f.row.email)+"> ",1)]),_:1}),t(S(ne),{label:"分支",width:"180",resizable:""},{default:r(f=>[f.row.branch?(d(),g("div",ts,[(d(!0),g(K,null,Y(f.row.branch.split(","),(j,T)=>(d(),Z(S(Ze),{key:T,size:"small",type:ss(j),class:"branch-tag"},{default:r(()=>[B(w(Te(j)),1)]),_:2},1032,["type"]))),128))])):q("",!0)]),_:1}),t(S(ne),{prop:"message",label:"提交信息","min-width":"250"})]),_:1},8,["data"])),[[$,n.value]])]))]))])}}}),ls=de(as,[["__scopeId","data-v-c6b721c7"]]),os="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",ns={class:"main-header"},is={class:"header-left"},rs=["src"],cs={class:"header-info"},us={key:0,id:"user-info"},ds={class:"user-name"},ps={class:"user-email"},fs={class:"container"},vs={class:"layout-container"},ms={class:"left-panel"},gs={class:"right-panel"},ys={class:"dialog-footer"},hs={class:"main-footer"},_s={key:0,class:"branch-info"},ws=ce({__name:"App",setup(O){const G=l(""),p=l(null),y=l(null),n=l(""),h=l(""),z=l(""),P=l([]),E=l(!1);async function L(){try{const i=await(await fetch("/api/config/getConfig")).json();G.value=`默认提交信息: ${i.defaultCommitMessage}`}catch(_){console.error("加载配置失败:",_)}}async function I(){try{const i=await(await fetch("/api/branch")).json();i.branch&&(n.value=i.branch)}catch(_){console.error("获取分支信息失败:",_)}}async function F(){try{const i=await(await fetch("/api/branches")).json();i.branches&&Array.isArray(i.branches)&&(P.value=i.branches)}catch(_){console.error("获取所有分支信息失败:",_)}}async function A(_){console.log("切换到分支:",_);try{E.value=!0;const H=await(await fetch("/api/checkout",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({branch:_})})).json();H.success?(c({message:`已切换到分支: ${_}`,type:"success"}),I(),y.value&&y.value.refreshStatus(),p.value&&p.value.refreshLog()):(c({message:`切换分支失败: ${H.error}`,type:"error"}),n.value=n.value)}catch(i){c({message:`切换分支失败: ${i.message}`,type:"error"}),n.value=n.value}finally{E.value=!1}}async function J(){try{const i=await(await fetch("/api/user-info")).json();i.name&&i.email&&(h.value=i.name,z.value=i.email)}catch(_){console.error("获取用户信息失败:",_)}}ue(()=>{L(),I(),F(),J()});function k(){p.value&&p.value.refreshLog(),y.value&&y.value.refreshStatus()}function C(){p.value&&p.value.refreshLog(),y.value&&y.value.refreshStatus(),I()}const $=l(!1),f=l(""),j=l(""),T=l(!1);async function N(){if(!f.value.trim()){c({message:"分支名称不能为空",type:"warning"});return}try{T.value=!0;const i=await(await fetch("/api/create-branch",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({newBranchName:f.value,baseBranch:j.value||n.value})})).json();i.success?(c({message:`已创建并切换到分支: ${f.value}`,type:"success"}),$.value=!1,f.value="",I(),F(),y.value&&y.value.refreshStatus(),p.value&&p.value.refreshLog()):c({message:`创建分支失败: ${i.error}`,type:"error"})}catch(_){c({message:`创建分支失败: ${_.message}`,type:"error"})}finally{T.value=!1}}function R(){j.value=n.value,$.value=!0}return(_,i)=>{const H=_e,te=Be,Q=Le,X=Pe,ae=je,ee=se,le=he,oe=xe;return d(),g(K,null,[a("header",ns,[a("div",is,[a("img",{src:S(os),alt:"Zen GitSync Logo",class:"logo"},null,8,rs),i[5]||(i[5]=a("h1",null,"Zen GitSync UI",-1))]),a("div",cs,[h.value&&z.value?(d(),g("div",us,[i[6]||(i[6]=a("span",{class:"user-label"},"用户:",-1)),a("span",ds,w(h.value),1),a("span",ps,"<"+w(z.value)+">",1)])):q("",!0)])]),a("div",fs,[a("div",vs,[a("div",ms,[t(bt,{ref_key:"gitStatusRef",ref:y},null,512)]),a("div",gs,[t(Jt,{onCommitSuccess:k,onPushSuccess:C}),t(ls,{ref_key:"logListRef",ref:p},null,512)]),t(le,{modelValue:$.value,"onUpdate:modelValue":i[3]||(i[3]=D=>$.value=D),title:"创建新分支",width:"30%","destroy-on-close":""},{footer:r(()=>[a("span",ys,[t(ee,{onClick:i[2]||(i[2]=D=>$.value=!1)},{default:r(()=>i[7]||(i[7]=[B("取消")])),_:1}),t(ee,{type:"primary",onClick:N,loading:T.value},{default:r(()=>i[8]||(i[8]=[B(" 创建 ")])),_:1},8,["loading"])])]),default:r(()=>[t(ae,{model:{newBranchName:f.value,selectedBaseBranch:j.value}},{default:r(()=>[t(te,{label:"新分支名称"},{default:r(()=>[t(H,{modelValue:f.value,"onUpdate:modelValue":i[0]||(i[0]=D=>f.value=D),placeholder:"请输入新分支名称"},null,8,["modelValue"])]),_:1}),t(te,{label:"基于分支"},{default:r(()=>[t(X,{modelValue:j.value,"onUpdate:modelValue":i[1]||(i[1]=D=>j.value=D),placeholder:"选择基础分支",style:{width:"100%"}},{default:r(()=>[(d(!0),g(K,null,Y(P.value,D=>(d(),Z(Q,{key:D,label:D,value:D},null,8,["label","value"]))),128))]),_:1},8,["modelValue"])]),_:1})]),_:1},8,["model"])]),_:1},8,["modelValue"])])]),a("footer",hs,[n.value?(d(),g("div",_s,[i[9]||(i[9]=a("span",{class:"branch-label"},"当前分支:",-1)),t(X,{modelValue:n.value,"onUpdate:modelValue":i[4]||(i[4]=D=>n.value=D),size:"small",onChange:A,loading:E.value,class:"branch-select"},{default:r(()=>[(d(!0),g(K,null,Y(P.value,D=>(d(),Z(Q,{key:D,label:D,value:D},null,8,["label","value"]))),128))]),_:1},8,["modelValue","loading"]),t(ee,{type:"primary",size:"small",onClick:R,style:{"margin-left":"5px"}},{default:r(()=>[t(oe,null,{default:r(()=>[t(S(Qe))]),_:1})]),_:1})])):q("",!0),i[10]||(i[10]=a("div",{class:"footer-right"},null,-1))])],64)}}}),bs=de(ws,[["__scopeId","data-v-93cc73d5"]]),ks=Xe(bs);ks.mount("#app");
|