diff --git a/platform/frontend/admin.html b/platform/frontend/admin.html
index 1937f6e..f5f2357 100644
--- a/platform/frontend/admin.html
+++ b/platform/frontend/admin.html
@@ -35,6 +35,7 @@
搜索排名
GEO 就绪度
配置管理
+ 任务管理
@@ -816,6 +817,122 @@
+
+
+
+ 定时任务配置与运行记录 — 共 {{ taskConfigs.length }} 个模块
+
+
加载中...
+
+
+
+
+
+
+
+
+
+ toggleModule(row, val)" @click.stop
+ style="--el-switch-on-color:#67c23a;">
+
+
+
+
+ {{ row.schedule || '-' }}
+
+
+
+
+
+ {{ row.params ? JSON.stringify(row.params).slice(0, 60) + (JSON.stringify(row.params).length > 60 ? '...' : '') : '-' }}
+
+
+
+
+
+
+
+ {{ row.last_log.status || '?' }}
+
+ {{ formatDate(row.last_log.started_at) }}
+
+ -
+
+
+
+
+ 编辑
+ 历史
+
+
+
+
+
+
+
+
+
+
+
+ 格式: 分 时 日 月 周 (5段cron)
+
+
+
+
+
+
+ 取消
+ 保存
+
+
+
+
+
+
+ 运行记录:{{ selectedModule.module_id }}
+ 最近 {{ taskLogs.length }} 条
+ 收起
+ 刷新
+
+
加载中...
+
+
+
+
+
+
+
+ {{ log.status }}
+
+ {{ log.task_name }}
+ 耗时 {{ log.duration }}s
+ 触发: {{ log.triggered_by }}
+
+ {{ log.message }}
+ {{ log.error_trace }}
+
+ 查看结果数据
+
+
+
+
+
+
+
+ {{ resultDialogContent }}
+ 关闭
+
+
@@ -1465,6 +1582,85 @@ const llmConfigs = ref([]);
const formatDate = (dateStr) => { if (!dateStr) return '-'; return new Date(dateStr.replace(' ', 'T')).toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' }); };
const logout = () => { localStorage.removeItem('authToken'); localStorage.removeItem('userRole'); localStorage.removeItem('currentUser'); window.location.href = '/login.html'; };
+ const taskConfigs = ref([]);
+ const tcLoading = ref(false);
+ const selectedModule = ref(null);
+ const showHistory = ref(false);
+ const taskLogs = ref([]);
+ const tlLoading = ref(false);
+
+ const loadTaskConfigs = async () => {
+ tcLoading.value = true;
+ try {
+ const data = await api.get('/api/admin/task-configs');
+ taskConfigs.value = Array.isArray(data) ? data : (data.data || []);
+ } catch (e) { ElMessage.error('加载任务配置失败: ' + e.message); }
+ finally { tcLoading.value = false; }
+ };
+
+ const toggleModule = async (row, val) => {
+ try {
+ await api.put(`/api/admin/task-configs/${row.module_id}`, { enabled: val });
+ row.enabled = val;
+ ElMessage.success(val ? '已启用' : '已停用');
+ } catch (e) { ElMessage.error('操作失败: ' + e.message); }
+ };
+
+ const tcEditDialogVisible = ref(false);
+ const tcEditSaving = ref(false);
+ const tcEditForm = reactive({ module_id: '', enabled: true, schedule: '', paramsStr: '{}' });
+
+ const showEditConfig = (row) => {
+ tcEditForm.module_id = row.module_id;
+ tcEditForm.enabled = row.enabled;
+ tcEditForm.schedule = row.schedule || '';
+ tcEditForm.paramsStr = row.params ? JSON.stringify(row.params, null, 2) : '{}';
+ tcEditDialogVisible.value = true;
+ };
+
+ const saveTaskConfig = async () => {
+ tcEditSaving.value = true;
+ try {
+ let params;
+ try { params = JSON.parse(tcEditForm.paramsStr); }
+ catch (e) { ElMessage.warning('参数格式不是有效的 JSON'); tcEditSaving.value = false; return; }
+ await api.put(`/api/admin/task-configs/${tcEditForm.module_id}`, {
+ enabled: tcEditForm.enabled,
+ schedule: tcEditForm.schedule,
+ params: params,
+ });
+ ElMessage.success('保存成功');
+ tcEditDialogVisible.value = false;
+ await loadTaskConfigs();
+ } catch (e) { ElMessage.error('保存失败: ' + e.message); }
+ finally { tcEditSaving.value = false; }
+ };
+
+ const selectModule = (row) => {
+ selectedModule.value = row;
+ showHistory.value = true;
+ loadTaskLogs(row);
+ };
+
+ const loadTaskLogs = async (row) => {
+ tlLoading.value = true;
+ try {
+ const data = await api.get(`/api/admin/task-configs/history/${row.module_id}?limit=30`);
+ taskLogs.value = Array.isArray(data) ? data : (data.data || []);
+ } catch (e) { ElMessage.error('加载运行记录失败: ' + e.message); taskLogs.value = []; }
+ finally { tlLoading.value = false; }
+ };
+
+ const resultDialogVisible = ref(false);
+ const resultDialogContent = ref('');
+ const showResultData = (log) => {
+ try {
+ const d = typeof log.result_data === 'string' ? log.result_data : JSON.stringify(log.result_data, null, 2);
+ resultDialogContent.value = d;
+ } catch (e) { resultDialogContent.value = String(log.result_data || ''); }
+ resultDialogVisible.value = true;
+ };
+
const tabLoaders = {
llmconfigs: loadLLMConfigs, platformconfigs: loadPlatformConfigs, systemconfigs: loadSystemConfigs,
users: fetchUsers,
@@ -1473,6 +1669,7 @@ const llmConfigs = ref([]);
searchrankings: loadRankings,
geo: loadGeoData,
configitems: () => { loadSensitiveWords(); loadContentCleanRules(); },
+ taskmanagement: loadTaskConfigs,
};
const loadedTabs = new Set([]);
@@ -1533,6 +1730,10 @@ const llmConfigs = ref([]);
loadContentCleanRules, showAddCleanRule, editCleanRule, saveCleanRule, deleteCleanRule,
rankings, rankingStats, rankingsLoading, loadRankings,
geoOverview, geoReadinessScores, geoLoading, geoTracking, loadGeoData, triggerGeoTrack,
+ taskConfigs, tcLoading, selectedModule, showHistory, taskLogs, tlLoading,
+ loadTaskConfigs, selectModule, toggleModule, loadTaskLogs,
+ tcEditDialogVisible, tcEditSaving, tcEditForm, showEditConfig, saveTaskConfig,
+ resultDialogVisible, resultDialogContent, showResultData,
};
}
});