0
0
Files
vs-p/out/panels/views/ConfigView.js
2025-12-02 14:48:30 +08:00

977 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 moduleFolders = data?.moduleFolders || [];
const currentModuleFolder = data?.currentModuleFolder;
const moduleFolderFileTree = data?.moduleFolderFileTree || [];
const moduleFolderLoading = data?.moduleFolderLoading || false;
const gitBranches = data?.gitBranches || [];
// 生成配置列表的 HTML - 包含配置文件和模块文件夹
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>local</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 moduleFoldersHtml = moduleFolders.map((folder) => {
const icon = folder.type === 'git' ? '📁' : '📁';
// 根据类型和上传状态确定类别显示
let category = folder.type === 'git' ? 'git' : 'local';
if (folder.uploaded) {
category += '(已上传)';
}
return `
<tr>
<td>
<span class="editable clickable" onclick="renameModuleFolder('${folder.id}')">
${icon} ${folder.name}
</span>
</td>
<td class="category-${folder.type}">${category}</td>
<td>
<span class="clickable"
onclick="renameModuleFolder('${folder.id}', '${folder.localPath.split('/').pop()}')">
📄 ${folder.localPath.split('/').pop()}
</span>
</td>
<td>
<button class="btn-upload" onclick="uploadModuleFolder('${folder.id}', '${folder.type}')" style="margin-right: 5px;">上传</button>
<button class="btn-delete" onclick="deleteModuleFolder('${folder.id}')">删除</button>
</td>
</tr>
`;
}).join('');
// 生成分支选择的 HTML - 使用树状结构(首次渲染可以为空,后续通过 message 更新)
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;
}
.btn-upload {
background: var(--vscode-button-background);
color: var(--vscode-button-foreground);
padding: 4px 8px;
border: none;
border-radius: 2px;
cursor: pointer;
}
.btn-upload:hover {
background: var(--vscode-button-hoverBackground);
}
.btn-upload:disabled {
background: var(--vscode-button-secondaryBackground);
color: var(--vscode-button-secondaryForeground);
cursor: not-allowed;
}
/* 树状分支样式 */
.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 {
margin: 15px 0;
}
.merge-input-section {
margin-bottom: 15px;
}
.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);
}
/* 类别标签样式 */
.category-git {
color: var(--vscode-gitDecoration-untrackedResourceForeground);
font-weight: bold;
}
.category-local {
color: var(--vscode-charts-orange);
font-weight: bold;
}
.category-git已上传 {
color: var(--vscode-gitDecoration-addedResourceForeground);
font-weight: bold;
}
.category-local已上传 {
color: var(--vscode-gitDecoration-addedResourceForeground);
font-weight: bold;
}
</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="25%">配置</th>
<th width="15%">类别</th>
<th width="35%">文件/文件夹</th>
<th width="25%">操作</th>
</tr>
</thead>
<tbody>
${configsHtml}
${moduleFoldersHtml}
</tbody>
</table>
</div>
<!-- 模块文件夹管理部分 -->
<div class="config-section">
<h3 class="section-title">📚 模块云仓库</h3>
<!-- 仓库选择区域 -->
<div class="url-input-section">
<h4>🔗 获取仓库</h4>
<div style="display: flex; gap: 10px; margin-top: 10px; align-items: center;">
<button class="btn-new" onclick="openRepoSelect()">获取仓库</button>
<span style="font-size: 12px; color: var(--vscode-descriptionForeground);">
从仓库配置中选择 Git 仓库,随后可以选择分支并克隆到本地
</span>
</div>
<div id="branchSelectionContainer">
${branchesHtml}
</div>
</div>
</div>
<script>
const vscode = acquireVsCodeApi();
let currentConfigId = null;
let selectedBranches = new Set();
let branchTreeData = [];
let selectedConfigs = new Set();
function renameModuleFolder(folderId, oldName) {
showPromptDialog(
'重命名模块文件夹',
'请输入新的名称:',
oldName,
function(newName) {
if (newName && newName.trim() && newName !== oldName) {
vscode.postMessage({
type: 'renameModuleFolder',
folderId: folderId,
newName: newName.trim()
});
}
}
);
}
// 配置管理功能
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
});
}
// 统一功能:打开模块文件夹
function openTheModuleFolder(id, type) {
console.log('📂 打开模块文件夹:', { id, type });
vscode.postMessage({
type: 'openTheModuleFolder',
id: id,
moduleType: type
});
}
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 deleteModuleFolder(folderId) {
console.log('🗑️ 尝试删除模块文件夹:', folderId);
showConfirmDialog(
'确认删除模块文件夹',
'确定删除这个模块文件夹吗?这将删除文件夹及其所有内容。',
function() {
console.log('✅ 用户确认删除模块文件夹:', folderId);
vscode.postMessage({
type: 'deleteModuleFolder',
folderId: folderId
});
},
function() {
// 用户取消删除
console.log('❌ 用户取消删除模块文件夹');
}
);
}
// 上传模块文件夹功能
function uploadModuleFolder(folderId, folderType) {
console.log('📤 上传模块文件夹:', { folderId, folderType });
if (folderType === 'git') {
// Git 类型:直接上传(相当于 push
showConfirmDialog(
'确认上传',
'确定要将 Git 文件夹的内容上传到远程仓库吗?这将执行 git push 操作。',
function() {
vscode.postMessage({
type: 'uploadGitModuleFolder',
folderId: folderId
});
},
function() {
console.log('❌ 用户取消上传 Git 文件夹');
}
);
} else if (folderType === 'local') {
// Local 类型:不再手动输入 URL改为复用“获取仓库”弹窗
// 后端将根据选择的仓库 + 本地文件夹名 自动确定 repoUrl 和 分支名
vscode.postMessage({
type: 'openRepoSelectForUpload',
folderId: folderId
});
}
}
function goBackToContainers() {
vscode.postMessage({ type: 'goBackToContainers' });
}
// 🔁 通过弹窗获取仓库(用于克隆)
function openRepoSelect() {
console.log('📦 请求仓库列表以选择 Git 仓库(用于克隆分支)');
vscode.postMessage({
type: 'openRepoSelect'
});
}
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',
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 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: 450px;">
<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