0
0
Files
vs-p/out/panels/views/ConfigView.js

958 lines
36 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConfigView = void 0;
const BaseView_1 = require("./BaseView");
class ConfigView extends BaseView_1.BaseView {
render(data) {
const container = data?.container;
const configs = data?.configs || [];
const gitRepos = data?.gitRepos || [];
const currentGitRepo = data?.currentGitRepo;
const gitFileTree = data?.gitFileTree || [];
const gitLoading = data?.gitLoading || false;
const gitBranches = data?.gitBranches || [];
const gitRepoUrl = data?.gitRepoUrl || '';
const mergedFolders = data?.mergedFolders || [];
// 生成配置列表的 HTML - 包含配置文件和 Git 仓库
const configsHtml = configs.map((config) => `
<tr>
<td>
<input type="checkbox" class="config-checkbox" data-id="${config.id}" data-type="config">
<span class="editable" onclick="editConfigName('${config.id}', '${config.name}')">🔧 ${config.name}</span>
</td>
<td>
<span class="clickable" onclick="openConfigFileInVSCode('${config.id}')">📄 ${config.fileName}</span>
</td>
<td>
<button class="btn-delete" onclick="deleteConfig('${config.id}')">删除</button>
</td>
</tr>
`).join('');
// 生成合并文件夹的 HTML - 显示在配置列表中
const mergedFoldersHtml = mergedFolders.map((folder) => `
<tr>
<td>
<span class="editable">📁 ${folder.displayName}</span>
<div style="font-size: 12px; color: var(--vscode-descriptionForeground); margin-top: 4px;">
包含 ${folder.fileCount} 个文件
</div>
</td>
<td>
<span class="clickable" onclick="loadMergedFolder('${folder.id}')">${folder.folderName}</span>
</td>
<td>
<button class="btn-delete" onclick="deleteMergedFolder('${folder.id}')">删除</button>
</td>
</tr>
`).join('');
// 生成 Git 仓库列表的 HTML - 修改显示方式Git 仓库不可勾选
const gitReposHtml = gitRepos.map(repo => {
// 提取仓库名称从URL中获取或使用name
const repoName = repo.name.split(' (')[0]; // 移除分支名部分
// 提取分支名
const branchMatch = repo.name.match(/\(([^)]+)\)/);
const branchName = branchMatch ? branchMatch[1] : repo.branch;
return `
<tr>
<td>
<span class="editable">📁 ${repoName}</span>
<div style="font-size: 12px; color: var(--vscode-descriptionForeground); margin-top: 4px;">
</div>
</td>
<td>
<span class="clickable" onclick="openGitRepoInVSCode('${repo.id}')">${branchName}</span>
</td>
<td>
<button class="btn-delete" onclick="deleteGitRepo('${repo.id}')">删除</button>
</td>
</tr>
`;
}).join('');
// 生成分支选择的 HTML - 使用树状结构
const branchesHtml = gitBranches.length > 0 ? this.generateBranchesTreeHtml(gitBranches) : '';
return `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>配置管理</title>
${this.getStyles()}
<style>
.url-input-section {
background: var(--vscode-panel-background);
padding: 15px;
border-radius: 4px;
margin-bottom: 15px;
border: 1px solid var(--vscode-input-border);
}
.section-title {
margin: 30px 0 15px 0;
padding-bottom: 10px;
border-bottom: 2px solid var(--vscode-panel-border);
color: var(--vscode-titleBar-activeForeground);
}
.config-section {
margin-bottom: 30px;
}
.branch-selection {
border: 1px solid var(--vscode-input-border);
}
.branch-item:hover {
background: var(--vscode-list-hoverBackground);
}
.btn-delete {
background: var(--vscode-inputValidation-errorBackground);
color: white;
padding: 4px 8px;
border: none;
border-radius: 2px;
cursor: pointer;
}
.btn-delete:hover {
background: var(--vscode-inputValidation-errorBackground);
opacity: 0.8;
}
/* 树状分支样式 */
.branch-tree {
font-family: 'Courier New', monospace;
user-select: none;
margin: 0;
padding: 0;
}
.branch-node {
padding: 2px 0;
display: flex;
align-items: center;
cursor: pointer;
line-height: 1.2;
}
.branch-node:hover {
background: var(--vscode-list-hoverBackground);
}
.branch-icon {
margin-right: 4px;
font-size: 16px;
width: 16px;
text-align: center;
}
.branch-expand {
margin-right: 2px;
cursor: pointer;
width: 14px;
text-align: center;
}
.branch-checkbox {
margin-right: 6px;
}
.branch-name {
flex: 1;
font-size: 13px;
}
.branch-children {
margin-left: 16px;
border-left: 1px solid var(--vscode-panel-border);
padding-left: 8px;
}
.branch-leaf {
margin-left: 16px;
}
.current-branch {
color: var(--vscode-gitDecoration-untrackedResourceForeground);
font-weight: bold;
}
/* 树图标样式 */
.tree-icon {
font-size: 2em;
}
/* 分支树标题样式 */
.branch-tree-title {
font-size: 1.2em;
}
/* 复选框样式 */
.config-checkbox {
margin-right: 8px;
}
/* 操作按钮样式 */
.action-buttons {
display: flex;
gap: 10px;
margin-bottom: 15px;
}
.btn-merge {
background: var(--vscode-button-background);
color: var(--vscode-button-foreground);
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
}
.btn-merge:hover {
background: var(--vscode-button-hoverBackground);
}
.btn-merge:disabled {
background: var(--vscode-button-secondaryBackground);
color: var(--vscode-button-secondaryForeground);
cursor: not-allowed;
}
/* 合并弹窗样式 */
.merge-dialog-content {
display: flex;
gap: 15px;
margin: 15px 0;
}
.merge-input-section {
flex: 1;
}
.merge-input-label {
font-weight: bold;
margin-bottom: 8px;
display: block;
}
.merge-input-field {
width: 100%;
padding: 8px;
background: var(--vscode-input-background);
color: var(--vscode-input-foreground);
border: 1px solid var(--vscode-input-border);
border-radius: 4px;
margin-bottom: 5px;
}
.merge-input-help {
font-size: 12px;
color: var(--vscode-descriptionForeground);
}
</style>
</head>
<body>
<div class="header">
<h2>⚙️ 配置管理 - <span style="color: var(--vscode-textLink-foreground);">${container?.name || '未知容器'}</span></h2>
<button class="back-btn" onclick="goBackToContainers()">← 返回容器管理</button>
</div>
<!-- 配置文件管理部分 -->
<div class="config-section">
<h3 class="section-title">📋 配置文件管理</h3>
<!-- 操作按钮区域 -->
<div class="action-buttons">
<button class="btn-new" onclick="createNewConfig()">+ 新建配置</button>
<button class="btn-merge" id="mergeButton" onclick="mergeSelectedConfigs()" disabled>合并选中配置</button>
</div>
<table class="table">
<thead>
<tr>
<th width="30%">配置</th>
<th width="40%">文件</th>
<th width="30%">操作</th>
</tr>
</thead>
<tbody>
${configsHtml}
${mergedFoldersHtml}
${gitReposHtml}
</tbody>
</table>
</div>
<!-- Git 仓库管理部分 -->
<div class="config-section">
<h3 class="section-title">📚 Git 仓库管理</h3>
<!-- URL 输入区域 -->
<div class="url-input-section">
<h4>🔗 添加 Git 仓库</h4>
<div style="display: flex; gap: 10px; margin-top: 10px;">
<input type="text" id="repoUrlInput"
placeholder="请输入 Git 仓库 URL例如: https://github.com/username/repo.git"
value="${gitRepoUrl}"
style="flex: 1; padding: 8px; background: var(--vscode-input-background); color: var(--vscode-input-foreground); border: 1px solid var(--vscode-input-border); border-radius: 4px;">
<button class="btn-new" onclick="fetchBranches()">获取分支</button>
</div>
<div id="branchSelectionContainer">
${branchesHtml}
</div>
</div>
</div>
<script>
const vscode = acquireVsCodeApi();
let currentConfigId = null;
let selectedBranches = new Set();
let currentRepoUrl = '';
let branchTreeData = [];
let selectedConfigs = new Set();
// 配置管理功能
function editConfigName(configId, currentName) {
showPromptDialog(
'修改配置名称',
'请输入新的配置名称:',
currentName,
function(newName) {
if (newName && newName !== currentName) {
vscode.postMessage({
type: 'updateConfigName',
configId: configId,
name: newName
});
}
}
);
}
// 新功能:在 VSCode 中打开配置文件
function openConfigFileInVSCode(configId) {
console.log('📄 在 VSCode 中打开配置文件:', configId);
vscode.postMessage({
type: 'openConfigFileInVSCode',
configId: configId
});
}
// 新功能:加载合并文件夹(与 Git 仓库行为一致)
function loadMergedFolder(folderId) {
console.log('📂 加载合并文件夹:', folderId);
vscode.postMessage({
type: 'loadMergedFolder',
folderId: folderId
});
}
function openGitRepoInVSCode(repoId) {
console.log('📂 在 VSCode 中打开 Git 仓库文件选择器:', repoId);
vscode.postMessage({
type: 'openGitRepoInVSCode',
repoId: repoId
});
}
function createNewConfig() {
showPromptDialog(
'新建配置',
'请输入配置名称:',
'',
function(name) {
if (name) {
vscode.postMessage({
type: 'createConfig',
name: name
});
}
}
);
}
function deleteConfig(configId) {
showConfirmDialog(
'确认删除',
'确定删除这个配置文件吗?',
function() {
console.log('🗑️ 删除配置文件:', configId);
vscode.postMessage({
type: 'deleteConfig',
configId: configId
});
},
function() {
// 用户取消删除
console.log('❌ 用户取消删除配置文件');
}
);
}
// 删除合并文件夹功能
function deleteMergedFolder(folderId) {
console.log('🗑️ 尝试删除合并文件夹:', folderId);
showConfirmDialog(
'确认删除合并文件夹',
'确定删除这个合并文件夹吗?这将删除文件夹及其所有内容。',
function() {
console.log('✅ 用户确认删除合并文件夹:', folderId);
vscode.postMessage({
type: 'deleteMergedFolder',
folderId: folderId
});
},
function() {
// 用户取消删除
console.log('❌ 用户取消删除合并文件夹');
}
);
}
// Git 仓库删除功能
function deleteGitRepo(repoId) {
console.log('🗑️ 尝试删除 Git 仓库:', repoId);
showConfirmDialog(
'确认删除 Git 仓库',
'确定删除这个 Git 仓库吗?这将删除本地克隆的代码文件夹。',
function() {
console.log('✅ 用户确认删除 Git 仓库:', repoId);
vscode.postMessage({
type: 'deleteGitRepo',
repoId: repoId
});
},
function() {
// 用户取消删除
console.log('❌ 用户取消删除 Git 仓库');
}
);
}
function goBackToContainers() {
vscode.postMessage({ type: 'goBackToContainers' });
}
// Git 仓库管理功能
function fetchBranches() {
const urlInput = document.getElementById('repoUrlInput');
const repoUrl = urlInput.value.trim();
if (!repoUrl) {
alert('请输入 Git 仓库 URL');
return;
}
if (!repoUrl.startsWith('http')) {
alert('请输入有效的 Git 仓库 URL');
return;
}
currentRepoUrl = repoUrl;
console.log('🌿 获取分支列表:', repoUrl);
vscode.postMessage({
type: 'fetchBranches',
url: repoUrl
});
}
function toggleBranch(branchName) {
const checkbox = document.getElementById('branch-' + branchName.replace(/[^a-zA-Z0-9-]/g, '-'));
if (checkbox.checked) {
selectedBranches.add(branchName);
} else {
selectedBranches.delete(branchName);
}
console.log('选中的分支:', Array.from(selectedBranches));
}
function cloneSelectedBranches() {
if (selectedBranches.size === 0) {
alert('请至少选择一个分支');
return;
}
console.log('🚀 开始克隆选中的分支:', Array.from(selectedBranches));
vscode.postMessage({
type: 'cloneBranches',
url: currentRepoUrl,
branches: Array.from(selectedBranches)
});
// 重置选择
selectedBranches.clear();
const checkboxes = document.querySelectorAll('input[type="checkbox"]');
checkboxes.forEach(checkbox => checkbox.checked = false);
// 隐藏分支选择区域
document.getElementById('branchSelectionContainer').innerHTML = '';
}
function cancelBranchSelection() {
selectedBranches.clear();
const checkboxes = document.querySelectorAll('input[type="checkbox"]');
checkboxes.forEach(checkbox => checkbox.checked = false);
// 隐藏分支选择区域
document.getElementById('branchSelectionContainer').innerHTML = '';
vscode.postMessage({
type: 'cancelBranchSelection'
});
}
function syncGitRepo(repoId) {
console.log('🔄 同步仓库:', repoId);
vscode.postMessage({
type: 'syncGitRepo',
repoId: repoId
});
}
// 配置文件合并功能
function toggleConfigSelection(configId) {
const checkbox = document.querySelector('.config-checkbox[data-id="' + configId + '"]');
if (checkbox.checked) {
selectedConfigs.add(configId);
} else {
selectedConfigs.delete(configId);
}
// 更新合并按钮状态
updateMergeButtonState();
console.log('选中的配置文件:', Array.from(selectedConfigs));
}
function updateMergeButtonState() {
const mergeButton = document.getElementById('mergeButton');
if (mergeButton) {
mergeButton.disabled = selectedConfigs.size < 2;
}
}
function mergeSelectedConfigs() {
if (selectedConfigs.size < 2) {
alert('请至少选择两个配置文件进行合并');
return;
}
console.log('🔄 开始合并选中的配置文件:', Array.from(selectedConfigs));
// 弹出新的合并对话框
showMergeDialog();
}
// 新的合并对话框函数
function showMergeDialog() {
const overlay = document.createElement('div');
overlay.className = 'modal-overlay';
overlay.id = 'mergeModal';
overlay.innerHTML = \`
<div class="modal-dialog" style="width: 500px;">
<div class="modal-title">合并配置文件</div>
<div class="merge-dialog-content">
<div class="merge-input-section">
<label class="merge-input-label">配置显示名称</label>
<input type="text" id="displayNameInput" class="merge-input-field"
placeholder="在配置栏显示的名称" value="合并配置">
<div class="merge-input-help">在左侧配置栏显示的名称</div>
</div>
<div class="merge-input-section">
<label class="merge-input-label">文件夹名称</label>
<input type="text" id="folderNameInput" class="merge-input-field"
placeholder="文件夹的实际名称" value="merged-config">
<div class="merge-input-help">磁盘上的实际文件夹名称</div>
</div>
</div>
<div class="modal-buttons">
<button class="modal-btn modal-btn-secondary" onclick="closeMergeDialog()">取消</button>
<button class="modal-btn modal-btn-primary" onclick="confirmMerge()">确定合并</button>
</div>
</div>
\`;
document.body.appendChild(overlay);
// 自动聚焦到第一个输入框
setTimeout(() => {
const displayNameInput = document.getElementById('displayNameInput');
if (displayNameInput) {
displayNameInput.focus();
displayNameInput.select();
}
}, 100);
}
function confirmMerge() {
const displayNameInput = document.getElementById('displayNameInput');
const folderNameInput = document.getElementById('folderNameInput');
const displayName = displayNameInput.value.trim();
const folderName = folderNameInput.value.trim();
if (!displayName) {
alert('请输入配置显示名称');
return;
}
if (!folderName) {
alert('请输入文件夹名称');
return;
}
if (displayName && folderName) {
vscode.postMessage({
type: 'mergeConfigs',
configIds: Array.from(selectedConfigs),
displayName: displayName,
folderName: folderName
});
// 重置选择
selectedConfigs.clear();
const checkboxes = document.querySelectorAll('.config-checkbox');
checkboxes.forEach(checkbox => checkbox.checked = false);
updateMergeButtonState();
closeMergeDialog();
}
}
function closeMergeDialog() {
const modal = document.getElementById('mergeModal');
if (modal) {
modal.remove();
}
}
// 树状分支功能
function toggleBranchNode(nodeId) {
const node = findNodeById(branchTreeData, nodeId);
if (node && !node.isLeaf) {
node.expanded = !node.expanded;
renderBranchTree(branchTreeData);
}
}
function expandAllBranches() {
setAllExpanded(branchTreeData, true);
renderBranchTree(branchTreeData);
}
function collapseAllBranches() {
setAllExpanded(branchTreeData, false);
renderBranchTree(branchTreeData);
}
function setAllExpanded(nodes, expanded) {
nodes.forEach(node => {
if (!node.isLeaf) {
node.expanded = expanded;
if (node.children) {
setAllExpanded(node.children, expanded);
}
}
});
}
function findNodeById(nodes, nodeId) {
for (const node of nodes) {
if (node.fullName === nodeId) return node;
if (node.children) {
const found = findNodeById(node.children, nodeId);
if (found) return found;
}
}
return null;
}
// 动态渲染树状分支
function renderBranchTree(treeData) {
const container = document.getElementById('branchSelectionContainer');
if (!treeData || treeData.length === 0) {
container.innerHTML = '<div style="text-align: center; padding: 10px; color: var(--vscode-descriptionForeground);">未找到分支</div>';
return;
}
let html = '<div class="branch-selection" style="margin: 10px 0; padding: 10px; background: var(--vscode-panel-background); border-radius: 4px;">';
html += '<h4 class="branch-tree-title" style="margin: 0 0 8px 0;"><span class="tree-icon">🌳</span> 分支树</h4>';
// 展开/收起按钮
html += '<div style="margin-bottom: 8px;">';
html += '<button class="back-btn" onclick="expandAllBranches()" style="margin-right: 8px; padding: 2px 6px; font-size: 11px;">展开全部</button>';
html += '<button class="back-btn" onclick="collapseAllBranches()" style="padding: 2px 6px; font-size: 11px;">收起全部</button>';
html += '</div>';
html += '<div class="branch-tree">';
html += renderBranchNodes(treeData, 0);
html += '</div>';
html += '<div style="margin-top: 12px;">';
html += '<button class="btn-new" onclick="cloneSelectedBranches()" style="margin-right: 8px; padding: 4px 8px; font-size: 12px;">✅ 克隆选中分支</button>';
html += '<button class="back-btn" onclick="cancelBranchSelection()" style="padding: 4px 8px; font-size: 12px;">取消</button>';
html += '</div></div>';
container.innerHTML = html;
}
function renderBranchNodes(nodes, level) {
let html = '';
nodes.forEach(node => {
const indent = level * 20;
const nodeId = node.fullName.replace(/[^a-zA-Z0-9-]/g, '-');
if (node.isLeaf) {
// 叶子节点(实际分支)
html += '<div class="branch-node branch-leaf" style="margin-left: ' + indent + 'px;">';
html += '<input type="checkbox" id="branch-' + nodeId + '" class="branch-checkbox" ';
html += (node.branch && node.branch.selected ? 'checked' : '') + ' onchange="toggleBranch(\\'' + node.fullName + '\\')">';
html += '<span class="branch-icon">🌿</span>';
html += '<span class="branch-name ' + (node.branch && node.branch.isCurrent ? 'current-branch' : '') + '">';
html += node.name;
html += (node.branch && node.branch.isCurrent ? ' ⭐' : '');
html += '</span>';
html += '</div>';
} else {
// 文件夹节点
html += '<div class="branch-node" style="margin-left: ' + indent + 'px;">';
html += '<span class="branch-expand" onclick="toggleBranchNode(\\'' + node.fullName + '\\')">';
html += (node.expanded ? '🪵' : '🪵');
html += '</span>';
html += '<span class="branch-icon">🪵</span>';
html += '<span class="branch-name">' + node.name + '</span>';
html += '</div>';
if (node.expanded && node.children) {
html += '<div class="branch-children">';
html += renderBranchNodes(node.children, level + 1);
html += '</div>';
}
}
});
return html;
}
function countLeafNodes(nodes) {
let count = 0;
nodes.forEach(node => {
if (node.isLeaf) {
count++;
} else if (node.children) {
count += countLeafNodes(node.children);
}
});
return count;
}
// 对话框函数
function showConfirmDialog(title, message, onConfirm, onCancel) {
const overlay = document.createElement('div');
overlay.className = 'modal-overlay';
overlay.id = 'confirmModal';
overlay.innerHTML = \`
<div class="modal-dialog">
<div class="modal-title">\${title}</div>
<div>\${message}</div>
<div class="modal-buttons">
<button class="modal-btn modal-btn-secondary" onclick="closeConfirmDialog(false)">取消</button>
<button class="modal-btn modal-btn-primary" onclick="closeConfirmDialog(true)">确定</button>
</div>
</div>
\`;
document.body.appendChild(overlay);
window.confirmCallback = function(result) {
if (result && onConfirm) {
onConfirm();
} else if (!result && onCancel) {
onCancel();
}
delete window.confirmCallback;
};
}
function closeConfirmDialog(result) {
const modal = document.getElementById('confirmModal');
if (modal) {
modal.remove();
}
if (window.confirmCallback) {
window.confirmCallback(result);
}
}
function showPromptDialog(title, message, defaultValue, onConfirm) {
const overlay = document.createElement('div');
overlay.className = 'modal-overlay';
overlay.id = 'promptModal';
overlay.innerHTML = \`
<div class="modal-dialog">
<div class="modal-title">\${title}</div>
<div>\${message}</div>
<input type="text" id="promptInput" value="\${defaultValue}" style="width: 100%; margin: 10px 0; padding: 6px; background: var(--vscode-input-background); color: var(--vscode-input-foreground); border: 1px solid var(--vscode-input-border);">
<div class="modal-buttons">
<button class="modal-btn modal-btn-secondary" onclick="closePromptDialog(null)">取消</button>
<button class="modal-btn modal-btn-primary" onclick="closePromptDialog(document.getElementById('promptInput').value)">确定</button>
</div>
</div>
\`;
document.body.appendChild(overlay);
setTimeout(() => {
const input = document.getElementById('promptInput');
if (input) {
input.focus();
input.select();
}
}, 100);
window.promptCallback = onConfirm;
}
function closePromptDialog(result) {
const modal = document.getElementById('promptModal');
if (modal) {
modal.remove();
}
if (window.promptCallback) {
window.promptCallback(result);
}
delete window.promptCallback;
}
// 消息监听
window.addEventListener('message', event => {
const message = event.data;
console.log('📨 前端收到后端消息:', message);
if (message.type === 'branchesFetched') {
console.log('🌿 收到分支数据:', message.branches);
console.log('🌳 收到分支树数据:', message.branchTree);
branchTreeData = message.branchTree || [];
renderBranchTree(branchTreeData);
}
});
// 初始化
document.addEventListener('DOMContentLoaded', function() {
console.log('📄 ConfigView 页面加载完成');
// 为所有配置复选框添加事件监听
document.addEventListener('change', function(event) {
if (event.target.classList.contains('config-checkbox')) {
const configId = event.target.getAttribute('data-id');
toggleConfigSelection(configId);
}
});
});
</script>
</body>
</html>`;
}
generateBranchesTreeHtml(branches) {
if (branches.length === 0)
return '';
// 构建分支树
const branchTree = this.buildBranchTree(branches);
let html = '<div class="branch-selection" style="margin: 10px 0; padding: 10px; background: var(--vscode-panel-background); border-radius: 4px;">';
html += '<h4 class="branch-tree-title" style="margin: 0 0 8px 0;"><span class="tree-icon">🌳</span> 分支树</h4>';
html += '<div style="margin-bottom: 8px;">';
html += '<button class="back-btn" onclick="expandAllBranches()" style="margin-right: 8px; padding: 2px 6px; font-size: 11px;">展开全部</button>';
html += '<button class="back-btn" onclick="collapseAllBranches()" style="padding: 2px 6px; font-size: 11px;">收起全部</button>';
html += '</div>';
html += '<div class="branch-tree">';
html += this.renderBranchTreeNodes(branchTree, 0);
html += '</div>';
html += '<div style="margin-top: 12px;">';
html += '<button class="btn-new" onclick="cloneSelectedBranches()" style="margin-right: 8px; padding: 4px 8px; font-size: 12px;">✅ 克隆选中分支</button>';
html += '<button class="back-btn" onclick="cancelBranchSelection()" style="padding: 4px 8px; font-size: 12px;">取消</button>';
html += '</div></div>';
return html;
}
/**
* 构建分支树状结构
*/
buildBranchTree(branches) {
const root = [];
branches.forEach(branch => {
const parts = branch.name.split('/');
let currentLevel = root;
for (let i = 0; i < parts.length; i++) {
const part = parts[i];
const isLeaf = i === parts.length - 1;
const fullName = parts.slice(0, i + 1).join('/');
let node = currentLevel.find(n => n.name === part);
if (!node) {
node = {
name: part,
fullName: fullName,
isLeaf: isLeaf,
children: [],
level: i
};
currentLevel.push(node);
}
if (isLeaf) {
node.branch = branch;
}
else {
node.expanded = node.expanded || true; // 默认展开
}
currentLevel = node.children;
}
});
return root;
}
/**
* 渲染分支树节点
*/
renderBranchTreeNodes(nodes, level) {
let html = '';
nodes.forEach(node => {
const indent = level * 20;
const nodeId = node.fullName.replace(/[^a-zA-Z0-9-]/g, '-');
if (node.isLeaf) {
// 叶子节点(实际分支)
html += '<div class="branch-node branch-leaf" style="margin-left: ' + indent + 'px;">';
html += '<input type="checkbox" id="branch-' + nodeId + '" class="branch-checkbox" ';
html += (node.branch && node.branch.selected ? 'checked' : '') + ' onchange="toggleBranch(\'' + node.fullName + '\')">';
html += '<span class="branch-icon">🌿</span>';
html += '<span class="branch-name ' + (node.branch && node.branch.isCurrent ? 'current-branch' : '') + '">';
html += node.name;
html += (node.branch && node.branch.isCurrent ? ' ⭐' : '');
html += '</span>';
html += '</div>';
}
else {
// 文件夹节点
html += '<div class="branch-node" style="margin-left: ' + indent + 'px;">';
html += '<span class="branch-expand" onclick="toggleBranchNode(\'' + node.fullName + '\')">';
html += (node.expanded ? '🪵' : '🪵');
html += '</span>';
html += '<span class="branch-icon">🪵</span>';
html += '<span class="branch-name">' + node.name + '</span>';
html += '</div>';
if (node.expanded && node.children && node.children.length > 0) {
html += '<div class="branch-children">';
html += this.renderBranchTreeNodes(node.children, level + 1);
html += '</div>';
}
}
});
return html;
}
/**
* 计算叶子节点数量
*/
countLeafNodes(nodes) {
let count = 0;
nodes.forEach(node => {
if (node.isLeaf) {
count++;
}
else {
count += this.countLeafNodes(node.children);
}
});
return count;
}
}
exports.ConfigView = ConfigView;
//# sourceMappingURL=ConfigView.js.map