添加后台进程修复等功能

This commit is contained in:
z66
2025-08-26 18:01:12 +08:00
parent 37c42e17da
commit f0039bcbd4
+73 -53
View File
@@ -347,7 +347,6 @@
let currentSearchKeyword = "";
let currentServerDirectory = "";
let selectedScriptPath = null;
let scriptStatusMap = {}; // 缓存脚本状态映射
$(function () {
loadScripts();
@@ -370,15 +369,12 @@
alert('加载脚本失败:后端返回非数组格式');
return;
}
// 只保留有配置的脚本(后端已过滤,前端二次确认)
// 直接保存原始名称,不做额外处理
allScripts = scripts.filter(item =>
typeof item === 'object' && item !== null &&
'name' in item && typeof item.name === 'string' && item.name.trim() !== ''
);
// 批量获取所有脚本的状态和模式
$.get('/api/scripts/status', function(statusMap) {
scriptStatusMap = statusMap;
currentSearchKeyword = "";
$('#script-search').val("");
sortScripts();
@@ -395,10 +391,6 @@
$('#output-area').empty();
}
}
}).fail(function(xhr) {
alert('加载脚本状态失败:' + (xhr.responseJSON?.error || xhr.statusText));
});
}).fail(function (xhr) {
alert('加载脚本列表失败:' + (xhr.responseJSON?.error || xhr.statusText));
allScripts = [];
@@ -452,7 +444,7 @@
if (filteredScripts.length === 0) {
const tip = currentSearchKeyword ?
`<i class="bi bi-search"></i> 未找到包含"${currentSearchKeyword}"的脚本` :
`<i class="bi bi-folder-open"></i> 暂无配置的脚本`;
`<i class="bi bi-folder-open"></i> tasks目录下无脚本文件(支持.bat/.py)`;
container.append(`
<div class="text-center text-muted py-3">
${tip}
@@ -461,33 +453,20 @@
return;
}
// 使用文档片段减少DOM重绘
const fragment = document.createDocumentFragment();
filteredScripts.forEach(scriptObj => {
const scriptName = scriptObj.name.trim();
if (!scriptName) return;
const modifyTimeStr = scriptObj.modify_time_str || '未知时间';
// 从缓存的状态映射表中获取状态和模式
const statusInfo = scriptStatusMap[scriptName] || {
status: 'stopped',
running: false,
scheduled: false,
mode: 'single-run',
schedule_info: ''
};
getScriptStatus(scriptName, function (status) {
const statusClass = status.status === 'running' ? 'status-running' :
status.status === 'scheduled' ? 'status-scheduled' : 'status-stopped';
const statusText = status.status === 'running' ? '运行中' :
status.status === 'scheduled' ? '已调度' : '停止';
const statusTextClass = `status-text ${status.status}`;
// 状态样式处理
const statusClass = statusInfo.status === 'running' ? 'status-running' :
statusInfo.status === 'scheduled' ? 'status-scheduled' : 'status-stopped';
const statusText = statusInfo.status === 'running' ? '运行中' :
statusInfo.status === 'scheduled' ? '已调度' : '停止';
const statusTextClass = `status-text ${statusInfo.status}`;
// 按钮样式处理
let btnClass, btnIcon, btnText, btnClick;
if (statusInfo.running || statusInfo.scheduled) {
if (status.running || status.scheduled) {
btnClass = 'btn-danger';
btnIcon = 'bi-stop-fill';
btnText = '停止';
@@ -499,15 +478,9 @@
btnClick = `startScript('${escapeHtml(scriptName)}')`;
}
// 模式文本处理
const modeText = statusInfo.mode === 'long-running' ? '长期运行' :
statusInfo.mode === 'interval' ? '定时执行' : '单次运行';
const scheduleInfo = statusInfo.schedule_info ? ` | ${statusInfo.schedule_info}` : '';
// 创建DOM元素并添加到文档片段
const scriptItem = $(`
const scriptItemHtml = `
<div class="script-item ${currentScript === scriptName ? 'active' : ''}"
onclick="selectScript(&quot;${escapeHtml(scriptName)}&quot;)">
onclick="selectScript(&quot;${escapeHtml(scriptName)}&quot;)"> <!-- 使用&quot;转义双引号 -->
<div class="d-flex justify-content-between align-items-center">
<div>
<div class="d-flex align-items-center">
@@ -516,10 +489,7 @@
<span class="${statusTextClass}">${statusText}</span>
</div>
<div class="mode-info text-xs mt-1">
<div class="d-flex justify-content-between">
<span class="text-muted">模式:${modeText}${scheduleInfo}</span>
<span class="text-muted">最近修改:${modifyTimeStr}</span>
</div>
<span class="text-muted">加载模式信息中...</span>
</div>
</div>
<button class="btn btn-sm ${btnClass}"
@@ -528,12 +498,22 @@
</button>
</div>
</div>
`)[0];
fragment.appendChild(scriptItem);
});
`;
container.append(scriptItemHtml);
// 一次性将所有元素添加到容器
container.append(fragment);
getScriptMode(scriptName, function (mode) {
const modeText = mode === 'long-running' ? '长期运行' :
mode === 'interval' ? '定时执行' : '单次运行';
const scheduleInfo = status.schedule_info ? ` | ${status.schedule_info}` : '';
$(`.script-item:has(.script-name:contains('${escapeHtml(scriptName)}')) .mode-info`).html(`
<div class="d-flex justify-content-between">
<span class="text-muted">模式:${modeText}${scheduleInfo}</span>
<span class="text-muted">最近修改:${modifyTimeStr}</span>
</div>
`);
});
});
});
}
function updateConfigScriptSelect() {
@@ -545,15 +525,19 @@
typeof scriptObj.name === 'string' && scriptObj.name.trim()) {
const scriptName = scriptObj.name.trim();
const escapedName = escapeHtml(scriptName);
const escapedName = escapeHtml(scriptName); // 转义仅用于显示
// value使用原始名称,显示文本用转义后的值
select.append(`<option value="${scriptName}">${escapedName}</option>`);
}
});
if (currentScript && select.find(`option[value="${currentScript}"]`).length) {
// 恢复当前选中状态(使用原始名称匹配)
if (currentScript) {
if (select.find(`option[value="${currentScript}"]`).length) {
select.val(currentScript);
}
}
}
function selectScript(scriptName) {
currentScript = scriptName;
@@ -567,7 +551,8 @@
$.get(`/api/start/${encodeURIComponent(scriptName)}`)
.done(function (data) {
alert(data.msg);
loadScripts(); // 重新加载列表和状态
updateOutput();
renderScriptList();
})
.fail(function (xhr) {
alert('启动失败:' + (xhr.responseJSON?.error || xhr.statusText));
@@ -578,13 +563,35 @@
$.get(`/api/stop/${encodeURIComponent(scriptName)}`)
.done(function (data) {
alert(data.msg);
loadScripts(); // 重新加载列表和状态
updateOutput();
renderScriptList();
})
.fail(function (xhr) {
alert('停止失败:' + (xhr.responseJSON?.error || xhr.statusText));
});
}
function getScriptStatus(scriptName, callback) {
$.get(`/api/status/${encodeURIComponent(scriptName)}`)
.done(function (data) {
callback(data);
})
.fail(function () {
callback({status: 'stopped', running: false, scheduled: false});
});
}
function getScriptMode(scriptName, callback) {
$.get('/api/config')
.done(function (configs) {
const mode = configs[scriptName]?.mode || 'single-run';
callback(mode);
})
.fail(function () {
callback('single-run');
});
}
function loadConfig(scriptName) {
$.get('/api/config')
.done(function (configs) {
@@ -644,7 +651,7 @@
data: JSON.stringify({[scriptName]: config}),
success: function (data) {
alert(data.msg);
loadScripts(); // 保存后刷新列表
renderScriptList();
},
error: function (xhr) {
alert('保存失败:' + (xhr.responseJSON?.error || xhr.statusText));
@@ -801,13 +808,26 @@
document.getElementById('selectScriptBtn').addEventListener('click', function () {
if (selectedScriptPath) {
const scriptName = selectedScriptPath;
$('#config-script').val(scriptName);
const $select = $('#config-script');
// 检查下拉框中是否已有该脚本选项,若没有则手动添加
if ($select.find(`option[value="${escapeHtml(scriptName)}"]`).length === 0) {
$select.append(`<option value="${escapeHtml(scriptName)}">${escapeHtml(scriptName)}</option>`);
}
// 设置选中值并同步相关状态
$select.val(scriptName);
loadConfig(scriptName);
selectScript(scriptName);
// 刷新脚本列表,确保所有组件同步
loadScripts();
const modal = bootstrap.Modal.getInstance(document.getElementById('directoryBrowserModal'));
modal.hide();
}
});
</script>
</body>
</html>