forked from pu8crm6xf/analysiscode
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
203 lines
8.0 KiB
203 lines
8.0 KiB
const API_BASE_URL = window.location.origin + '/api';
|
|
|
|
function formatFileSize(bytes) {
|
|
if (bytes === 0) return '0 B';
|
|
const k = 1024;
|
|
const sizes = ['B', 'KB', 'MB', 'GB'];
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i];
|
|
}
|
|
|
|
function showSuccessMessage(message) {
|
|
const messageDiv = document.createElement('div');
|
|
messageDiv.style.cssText = `position: fixed; top: 20px; right: 20px; background: #d4edda; color: #155724; border: 1px solid #c3e6cb; border-radius: 6px; padding: 15px 20px; z-index: 3000; box-shadow: 0 4px 12px rgba(0,0,0,0.15); display: flex; align-items: center; gap: 10px;`;
|
|
messageDiv.innerHTML = `<i class="fas fa-check-circle"></i><span>${message}</span>`;
|
|
document.body.appendChild(messageDiv);
|
|
setTimeout(() => messageDiv.remove(), 3000);
|
|
}
|
|
|
|
function showErrorMessage(message) {
|
|
const messageDiv = document.createElement('div');
|
|
messageDiv.style.cssText = `position: fixed; top: 20px; right: 20px; background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; border-radius: 6px; padding: 15px 20px; z-index: 3000; box-shadow: 0 4px 12px rgba(0,0,0,0.15); display: flex; align-items: center; gap: 10px;`;
|
|
messageDiv.innerHTML = `<i class="fas fa-exclamation-circle"></i><span>${message}</span>`;
|
|
document.body.appendChild(messageDiv);
|
|
setTimeout(() => messageDiv.remove(), 5000);
|
|
}
|
|
|
|
async function loadRules() {
|
|
try {
|
|
const response = await fetch(`${API_BASE_URL}/rules`);
|
|
const data = await response.json();
|
|
if (!data.success) throw new Error(data.error || '加载失败');
|
|
renderRulesList(data.data || []);
|
|
} catch (e) {
|
|
console.error('加载规则失败:', e);
|
|
showErrorMessage('加载规则失败');
|
|
}
|
|
}
|
|
|
|
function renderRulesList(files) {
|
|
const container = document.getElementById('rulesList');
|
|
if (!container) return;
|
|
container.innerHTML = '';
|
|
if (!files.length) {
|
|
container.innerHTML = '<div style="text-align:center; padding: 20px; color:#666;">暂无规则文件</div>';
|
|
return;
|
|
}
|
|
files.forEach(f => {
|
|
const card = document.createElement('div');
|
|
card.className = 'project-card';
|
|
const size = formatFileSize(f.size || 0);
|
|
card.innerHTML = `
|
|
<div class="project-header">
|
|
<div>
|
|
<div class="project-title">${f.name}</div>
|
|
<div class="project-description">大小: ${size} | 更新: ${new Date(f.modified_at).toLocaleString()}</div>
|
|
</div>
|
|
</div>
|
|
<div class="project-actions">
|
|
<button class="btn btn-secondary">编辑</button>
|
|
<button class="btn btn-primary">下载</button>
|
|
<button class="btn btn-danger">删除</button>
|
|
</div>
|
|
`;
|
|
const [editBtn, downloadBtn, deleteBtn] = card.querySelectorAll('.project-actions .btn');
|
|
editBtn.addEventListener('click', (e) => { e.stopPropagation(); editRule(f.name); });
|
|
downloadBtn.addEventListener('click', (e) => { e.stopPropagation(); downloadRule(f.name); });
|
|
deleteBtn.addEventListener('click', (e) => { e.stopPropagation(); deleteRule(f.name); });
|
|
container.appendChild(card);
|
|
});
|
|
}
|
|
|
|
function showRuleUploadDialog() {
|
|
const input = document.createElement('input');
|
|
input.type = 'file';
|
|
input.multiple = true;
|
|
input.accept = '.cfg,.ini,.toml,.yaml,.yml,.json,.flake8,.pylintrc,setup.cfg,pyproject.toml,tox.ini';
|
|
input.onchange = async (e) => {
|
|
const files = Array.from(e.target.files || []);
|
|
if (!files.length) return;
|
|
const formData = new FormData();
|
|
files.forEach(f => formData.append('files', f));
|
|
try {
|
|
const resp = await fetch(`${API_BASE_URL}/rules/upload`, { method: 'POST', body: formData });
|
|
const data = await resp.json();
|
|
if (data.success) {
|
|
showSuccessMessage('规则上传成功');
|
|
loadRules();
|
|
} else {
|
|
showErrorMessage('规则上传失败:' + (data.error || ''));
|
|
}
|
|
} catch (e) {
|
|
console.error('上传规则失败:', e);
|
|
showErrorMessage('上传规则失败');
|
|
}
|
|
};
|
|
input.click();
|
|
}
|
|
|
|
let currentEditingRule = '';
|
|
|
|
async function editRule(name) {
|
|
try {
|
|
const resp = await fetch(`${API_BASE_URL}/rules/${encodeURIComponent(name)}`);
|
|
const data = await resp.json();
|
|
if (!data.success) throw new Error(data.error || '读取失败');
|
|
currentEditingRule = name;
|
|
document.getElementById('editRuleTitle').textContent = `编辑规则 - ${name}`;
|
|
document.getElementById('editRuleTextarea').value = data.data.content || '';
|
|
document.getElementById('editRuleModal').style.display = 'block';
|
|
} catch (e) {
|
|
console.error('读取规则失败:', e);
|
|
showErrorMessage('读取规则失败');
|
|
}
|
|
}
|
|
|
|
function hideEditRuleModal() {
|
|
const modal = document.getElementById('editRuleModal');
|
|
if (modal) modal.style.display = 'none';
|
|
currentEditingRule = '';
|
|
}
|
|
|
|
async function saveEditingRule() {
|
|
if (!currentEditingRule) return;
|
|
const content = document.getElementById('editRuleTextarea').value;
|
|
try {
|
|
const resp = await fetch(`${API_BASE_URL}/rules/${encodeURIComponent(currentEditingRule)}`, {
|
|
method: 'PUT',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ content })
|
|
});
|
|
const data = await resp.json();
|
|
if (data.success) {
|
|
showSuccessMessage('保存成功');
|
|
hideEditRuleModal();
|
|
loadRules();
|
|
} else {
|
|
showErrorMessage('保存失败:' + (data.error || ''));
|
|
}
|
|
} catch (e) {
|
|
console.error('保存规则失败:', e);
|
|
showErrorMessage('保存失败');
|
|
}
|
|
}
|
|
|
|
async function deleteRule(name) {
|
|
if (!confirm(`确定删除规则文件 "${name}" 吗?`)) return;
|
|
try {
|
|
const resp = await fetch(`${API_BASE_URL}/rules/${encodeURIComponent(name)}`, { method: 'DELETE' });
|
|
const data = await resp.json();
|
|
if (data.success) {
|
|
showSuccessMessage('删除成功');
|
|
loadRules();
|
|
} else {
|
|
showErrorMessage('删除失败:' + (data.error || ''));
|
|
}
|
|
} catch (e) {
|
|
console.error('删除规则失败:', e);
|
|
showErrorMessage('删除失败');
|
|
}
|
|
}
|
|
|
|
async function downloadRule(name) {
|
|
try {
|
|
const resp = await fetch(`${API_BASE_URL}/rules/${encodeURIComponent(name)}`);
|
|
const data = await resp.json();
|
|
if (!data.success) throw new Error(data.error || '下载失败');
|
|
const blob = new Blob([data.data.content || ''], { type: 'text/plain;charset=utf-8' });
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = name;
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
a.remove();
|
|
} catch (e) {
|
|
console.error('下载规则失败:', e);
|
|
showErrorMessage('下载失败');
|
|
}
|
|
}
|
|
|
|
function bindRulesEvents() {
|
|
const uploadRuleBtn = document.getElementById('uploadRuleBtn');
|
|
const refreshRuleBtn = document.getElementById('refreshRuleBtn');
|
|
const closeEditRule = document.getElementById('closeEditRule');
|
|
const cancelEditRule = document.getElementById('cancelEditRule');
|
|
const saveRuleBtn = document.getElementById('saveRuleBtn');
|
|
|
|
if (uploadRuleBtn) uploadRuleBtn.addEventListener('click', showRuleUploadDialog);
|
|
if (refreshRuleBtn) refreshRuleBtn.addEventListener('click', loadRules);
|
|
if (closeEditRule) closeEditRule.addEventListener('click', hideEditRuleModal);
|
|
if (cancelEditRule) cancelEditRule.addEventListener('click', hideEditRuleModal);
|
|
if (saveRuleBtn) saveRuleBtn.addEventListener('click', saveEditingRule);
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
bindRulesEvents();
|
|
});
|
|
|
|
export { loadRules };
|
|
|
|
|