fix: 监控页任务概况去掉「编辑/删除」,只留执行/停用 + 显示覆盖设备
监控页的任务卡片原来带「编辑」,但 openTaskModal 依赖 _taskTypes/_groupsList/
_devicesList,这三个列表只在任务 Tab 的 loadTasks() 里加载——从监控页直接点编辑,
下拉框是空的(这就是"编辑有问题")。按需求把编辑/删除从监控页移除(编辑统一去任务 Tab),
每张卡片只留:执行任务 + 停用任务/启用任务。
并给卡片加「覆盖设备」一行:
- 后端 /api/jobs(含 POST/PUT 返回的 job)新增 coverage = {mode, serials, total}:
按 target 定义解析(all=设备池全量 / group=分组∩设备池 / serial=该设备),
不做离线过滤、不写调度日志(该接口每 5s 轮询),与调度用的 resolve_serials 口径差异已写入文档
- 前端用已在手的 /api/status 标注在线状态,渲染成彩色 chip:
在线=蓝、运行中=黄+⏳、离线或不在池=灰划线+✕,完整 serial/型号放 tooltip
- 文档:API.md §5 补 coverage 字段与三种模式口径、ARCHITECTURE §5.1 补卡片说明
自测:coverage 三种模式端到端(含分组过滤池外 serial)全通过;Edge headless 验卡片
(2 个按钮、无编辑/删除、chip 文案/样式/tooltip)全通过;离线分支与任务 Tab 编辑器回归通过
This commit is contained in:
@@ -54,13 +54,47 @@ def _job_next_run(job):
|
||||
nr = context.mgr.next_run_of(job)
|
||||
return nr.strftime("%Y-%m-%d %H:%M") if nr else None
|
||||
|
||||
def _job_coverage(job, configured):
|
||||
"""任务覆盖的设备(监控页「任务运行概况」展示用)。
|
||||
|
||||
与 TaskJob.resolve_serials 的差别:这里按 **target 定义**给出「这台任务会覆盖
|
||||
哪些设备」,不因设备当前是否空闲而变(在线/运行中由前端拿实时状态标注),
|
||||
也不做离线过滤、不写调度日志——它是每 5s 轮询的展示接口。
|
||||
"""
|
||||
tgt = job.target or {}
|
||||
mode = tgt.get("mode", "all")
|
||||
try:
|
||||
if mode == "serial":
|
||||
serials = [tgt.get("serial") or ""]
|
||||
elif mode == "group":
|
||||
g = context.mgr.groups.get(tgt.get("group_name"))
|
||||
serials = [s for s in (list(g.serials) if g else []) if s in configured]
|
||||
else:
|
||||
serials = sorted(configured)
|
||||
serials = [s for s in serials if s]
|
||||
return {"mode": mode, "serials": serials, "total": len(serials)}
|
||||
except Exception as e:
|
||||
_log.warning(f"任务「{job.name}」覆盖设备解析失败: {e}")
|
||||
return {"mode": mode, "serials": [], "total": 0, "error": str(e)[:80]}
|
||||
|
||||
|
||||
def _configured_set():
|
||||
"""设备池清单(coverage 计算用,取一次给所有任务复用)。"""
|
||||
try:
|
||||
return set(device_pool.list_configured())
|
||||
except Exception:
|
||||
return set()
|
||||
|
||||
|
||||
@bp.route("/api/jobs")
|
||||
@login_required
|
||||
def api_jobs_list():
|
||||
configured = _configured_set()
|
||||
jobs = []
|
||||
for j in context.mgr.jobs.values():
|
||||
d = j.to_dict()
|
||||
d["next_run"] = _job_next_run(j)
|
||||
d["coverage"] = _job_coverage(j, configured)
|
||||
jobs.append(d)
|
||||
return jsonify({"ok": True, "jobs": jobs,
|
||||
"task_types": list_task_types()})
|
||||
@@ -84,6 +118,7 @@ def api_jobs_create():
|
||||
enabled=data.get("enabled", True))
|
||||
d = job.to_dict()
|
||||
d["next_run"] = _job_next_run(job)
|
||||
d["coverage"] = _job_coverage(job, _configured_set())
|
||||
return jsonify({"ok": True, "msg": "任务已创建", "job": d})
|
||||
|
||||
@bp.route("/api/jobs/<job_id>", methods=["PUT"])
|
||||
@@ -102,6 +137,7 @@ def api_jobs_update(job_id):
|
||||
context.mgr.update_job(job_id, **fields)
|
||||
d = job.to_dict()
|
||||
d["next_run"] = _job_next_run(job)
|
||||
d["coverage"] = _job_coverage(job, _configured_set())
|
||||
return jsonify({"ok": True, "msg": "任务已更新", "job": d})
|
||||
|
||||
@bp.route("/api/jobs/<job_id>", methods=["DELETE"])
|
||||
|
||||
Reference in New Issue
Block a user