修改运行时显示
This commit is contained in:
Binary file not shown.
+29
-1
@@ -1376,6 +1376,23 @@ def api_mission_state():
|
||||
if r < len(grid) and c < len(grid[r]) and grid[r][c]:
|
||||
path.append((r, c))
|
||||
|
||||
# 网格级别任务数据
|
||||
result["rows"] = rows
|
||||
result["cols"] = cols
|
||||
result["grid"] = grid
|
||||
result["point_status"] = {f"{pr}_{c}": "pending" for pr in range(rows+1) for c in range(cols)}
|
||||
result["machine_status"] = {}
|
||||
for r in range(rows):
|
||||
for c in range(cols):
|
||||
if r < len(grid) and c < len(grid[r]) and grid[r][c]:
|
||||
result["machine_status"][f"{r}_{c}"] = {
|
||||
"has_machine": True,
|
||||
"qr": "pending", "qr_val": None,
|
||||
"front": "pending", "front_cnt": 0,
|
||||
"back": "pending", "back_cnt": 0,
|
||||
"status": "pending", "step": "等待",
|
||||
}
|
||||
# 保留旧的 tasks 列表(兼容)
|
||||
tlist = []
|
||||
for (r, c) in path:
|
||||
tlist.append({
|
||||
@@ -1390,15 +1407,26 @@ def api_mission_state():
|
||||
})
|
||||
result["tasks"] = tlist
|
||||
except Exception:
|
||||
result["rows"] = 1
|
||||
result["cols"] = 1
|
||||
result["grid"] = []
|
||||
result["point_status"] = {}
|
||||
result["machine_status"] = {}
|
||||
result["tasks"] = []
|
||||
|
||||
# 错误弹窗状态
|
||||
# 错误弹窗状态和实时网格状态
|
||||
if hasattr(MissionExecutorV3, "_instance") and MissionExecutorV3._instance:
|
||||
ex = MissionExecutorV3._instance
|
||||
st = ex.get_status()
|
||||
result["error_msg"] = st.get("error", "")
|
||||
result["waiting_step"] = (st.get("status") == "waiting_step")
|
||||
result["waiting_error"] = (st.get("status") == "waiting_error")
|
||||
# 从 executor.report 读取实时点/机器状态
|
||||
rpt = ex.report
|
||||
if rpt.get("point_status"):
|
||||
result["point_status"] = rpt["point_status"]
|
||||
if rpt.get("machine_status"):
|
||||
result["machine_status"] = rpt["machine_status"]
|
||||
else:
|
||||
result["error_msg"] = ""
|
||||
result["waiting_step"] = False
|
||||
|
||||
@@ -1043,3 +1043,36 @@ a:hover { text-decoration: underline; }
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* ===== 运行页网格任务状态 ===== */
|
||||
/* 点位单元格 - 导航状态 */
|
||||
.point-cell { min-height: 52px; }
|
||||
.cell-nav-icon { font-size: 18px; text-align: center; }
|
||||
.cell-nav-label { font-size: 11px; color: #8899aa; text-align: center; margin-top: 2px; }
|
||||
.point-cell.nav-pending { background: #141e28; border-color: #2a3a4a; }
|
||||
.point-cell.nav-active { background: #1a3020; border-color: #4caf50; animation: navPulse 1.5s infinite; }
|
||||
.point-cell.nav-done { background: #152522; border-color: #2e7d32; }
|
||||
.point-cell.nav-done .cell-nav-icon { color: #4caf50; }
|
||||
.point-cell.nav-skipped { background: #141e28; border-color: #2a3a4a; opacity: 0.5; }
|
||||
@keyframes navPulse { 0%,100% { border-color: #4caf50; } 50% { border-color: #1b5e20; } }
|
||||
|
||||
/* 机器单元格状态 */
|
||||
.machine-cell { min-height: 62px; padding: 6px 8px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; }
|
||||
.machine-label { font-size: 12px; font-weight: 600; color: #ccc; }
|
||||
.machine-steps-mini { display: flex; gap: 8px; font-size: 13px; }
|
||||
.machine-qr-mini { font-size: 10px; color: #4fc3f7; max-width: 80px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
||||
.empty-cell { color: #445566; font-size: 12px; }
|
||||
|
||||
/* 步骤圆点 */
|
||||
.step-dot { opacity: 0.4; transition: opacity 0.3s; }
|
||||
.step-dot.dot-done { opacity: 1; }
|
||||
.step-dot.dot-scanning,
|
||||
.step-dot.dot-shooting { opacity: 0.8; animation: dotPulse 0.8s infinite; }
|
||||
@keyframes dotPulse { 0%,100% { opacity: 0.4; } 50% { opacity: 1; } }
|
||||
.step-dot.dot-manual { opacity: 0.7; }
|
||||
.step-dot.dot-skipped { opacity: 0.3; }
|
||||
|
||||
/* 机器状态背景 */
|
||||
.machine-cell.mstatus-pending { background: #141e28; border-color: #2a3a4a; }
|
||||
.machine-cell.mstatus-active { background: #1a2535; border-color: #4fc3f7; }
|
||||
.machine-cell.mstatus-completed { background: #152522; border-color: #2e7d32; }
|
||||
|
||||
@@ -2,8 +2,6 @@ const { createApp } = Vue
|
||||
const API = ''
|
||||
|
||||
createApp({
|
||||
delimiters: ['[[', ']]'],
|
||||
|
||||
data() {
|
||||
return {
|
||||
missionState: 'idle',
|
||||
@@ -15,7 +13,14 @@ createApp({
|
||||
polling: null,
|
||||
logs: [],
|
||||
showQrModal: false,
|
||||
qrSubmitting: false,
|
||||
qrValue: '',
|
||||
// 网格任务显示
|
||||
missionRows: 0,
|
||||
missionCols: 0,
|
||||
missionGrid: [],
|
||||
pointStatus: {},
|
||||
machineStatus: {},
|
||||
// 错误弹窗 / 单步执行
|
||||
waitingError: false,
|
||||
errorMsg: '',
|
||||
@@ -68,6 +73,13 @@ createApp({
|
||||
this.progress = data.progress || 0
|
||||
if (data.tasks) this.tasks = data.tasks
|
||||
|
||||
// 网格数据
|
||||
if (data.rows) this.missionRows = data.rows
|
||||
if (data.cols) this.missionCols = data.cols
|
||||
if (data.grid) this.missionGrid = data.grid
|
||||
if (data.point_status) this.pointStatus = data.point_status
|
||||
if (data.machine_status) this.machineStatus = data.machine_status
|
||||
|
||||
// 错误弹窗
|
||||
if (data.waiting_error) {
|
||||
this.waitingError = true
|
||||
@@ -84,8 +96,11 @@ createApp({
|
||||
this.waitingStep = false
|
||||
}
|
||||
|
||||
// QR 弹窗
|
||||
if (this.missionState === 'waiting_qr' && !this.showQrModal) {
|
||||
// QR 弹窗(防止提交后重复弹出)
|
||||
if (this.missionState !== 'waiting_qr') {
|
||||
this.qrSubmitting = false
|
||||
}
|
||||
if (this.missionState === 'waiting_qr' && !this.showQrModal && !this.qrSubmitting) {
|
||||
this.showQrModal = true
|
||||
this.qrValue = ''
|
||||
}
|
||||
@@ -190,10 +205,12 @@ createApp({
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ qr: val || ' ' })
|
||||
})
|
||||
this.qrSubmitting = true
|
||||
this.showQrModal = false
|
||||
this.qrValue = ''
|
||||
},
|
||||
cancelQr() {
|
||||
this.qrSubmitting = true
|
||||
this.showQrModal = false
|
||||
this.qrValue = ''
|
||||
fetch(API + '/api/mission/manual-qr', {
|
||||
@@ -207,6 +224,36 @@ createApp({
|
||||
},
|
||||
onArmPreviewError(e) {
|
||||
e.target.style.display = 'none'
|
||||
},
|
||||
// ===== 网格任务显示方法 =====
|
||||
getPointStatus(pr, c) {
|
||||
return (this.pointStatus && this.pointStatus[pr + '_' + c]) || 'pending'
|
||||
},
|
||||
navIcon(s) {
|
||||
const m = { pending: '⏳', active: '🔄', done: '✅', skipped: '⏭️' }
|
||||
return m[s] || '⏳'
|
||||
},
|
||||
navLabel(s) {
|
||||
const m = { pending: '等待', active: '导航中', done: '到达', skipped: '空位' }
|
||||
return m[s] || '等待'
|
||||
},
|
||||
hasMachine(r, c) {
|
||||
const key = r + '_' + c
|
||||
const ms = this.machineStatus && this.machineStatus[key]
|
||||
return ms && ms.has_machine
|
||||
},
|
||||
getMachineClass(r, c) {
|
||||
const key = r + '_' + c
|
||||
const ms = this.machineStatus && this.machineStatus[key]
|
||||
if (!ms) return ''
|
||||
const s = ms.status || 'pending'
|
||||
return 'mstatus-' + s
|
||||
},
|
||||
getMachineField(r, c, field) {
|
||||
const key = r + '_' + c
|
||||
const ms = this.machineStatus && this.machineStatus[key]
|
||||
if (!ms) return ''
|
||||
return ms[field] || ''
|
||||
}
|
||||
}
|
||||
}).mount('#app')
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>运行监控 - AGV 拍摄系统</title>
|
||||
<link rel="stylesheet" href="/static/css/style.css?v=20260527b">
|
||||
<link rel="stylesheet" href="/static/css/style.css?v=20260529a">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
@@ -23,10 +23,10 @@
|
||||
<div class="running-header">
|
||||
<div class="running-status" :class="missionState">
|
||||
<span class="pulse"></span>
|
||||
[[ missionStateText ]]
|
||||
{% raw %}{{ missionStateText }}{% endraw %}
|
||||
</div>
|
||||
<div class="running-progress" v-if="missionState === 'running' || missionState === 'waiting_qr'">
|
||||
<span>进度 [[ Math.round(progress) ]]%</span>
|
||||
<span>进度 {% raw %}{{ Math.round(progress) }}{% endraw %}%</span>
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill" :style="{width: progress + '%'}"></div>
|
||||
</div>
|
||||
@@ -96,50 +96,74 @@
|
||||
<div class="speed-row">
|
||||
<label class="speed-label">
|
||||
<span>🚗 AGV 移动速度</span>
|
||||
<span class="speed-val">[[ agvSpeed.toFixed(1) ]] m/s</span>
|
||||
<span class="speed-val">{% raw %}{{ agvSpeed.toFixed(1) }}{% endraw %} m/s</span>
|
||||
</label>
|
||||
<input type="range" class="speed-slider" min="0.1" max="1.0" step="0.1" v-model.number="agvSpeed">
|
||||
</div>
|
||||
<div class="speed-row">
|
||||
<label class="speed-label">
|
||||
<span>🦾 机械臂速度</span>
|
||||
<span class="speed-val">[[ armSpeed ]]</span>
|
||||
<span class="speed-val">{% raw %}{{ armSpeed }}{% endraw %}</span>
|
||||
</label>
|
||||
<input type="range" class="speed-slider" min="100" max="1000" step="50" v-model.number="armSpeed">
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 任务清单 -->
|
||||
<section class="card" v-if="tasks.length > 0">
|
||||
<h2>📋 任务清单 ([[ tasks.length ]] 台机器)</h2>
|
||||
<div class="task-grid">
|
||||
<div v-for="task in tasks" :key="task.machine_id"
|
||||
class="task-cell" :class="'task-' + task.status"
|
||||
:title="task.step">
|
||||
<div class="task-pos">[[ task.label ]]</div>
|
||||
<div class="task-status-icon">
|
||||
<span v-if="task.status === 'pending'">⏳</span>
|
||||
<span v-else-if="task.status === 'active'" class="pulse-icon">🔄</span>
|
||||
<span v-else-if="task.status === 'completed'">✅</span>
|
||||
<span v-else>❓</span>
|
||||
<!-- 任务清单 — 网格视图 -->
|
||||
<section class="card" v-if="missionRows > 0">
|
||||
<h2>📋 任务清单 ({% raw %}{{ missionRows }}{% endraw %}行×{% raw %}{{ missionCols }}{% endraw %}列,点位+机器网格)</h2>
|
||||
<div class="mission-grid-wrap" style="margin-top:12px">
|
||||
<div class="mission-grid" :style="{ gridTemplateColumns: '90px repeat(' + missionCols + ', 105px)' }">
|
||||
<!-- 表头 -->
|
||||
<div class="grid-cell grid-header"></div>
|
||||
<div v-for="c in missionCols" :key="'h'+c" class="grid-cell grid-header">第{% raw %}{{ c }}{% endraw %}列</div>
|
||||
|
||||
<!-- 第一个点位行 (pointRow=0): 所有机器正面拍摄点 -->
|
||||
<div class="grid-cell grid-header">点位行 1</div>
|
||||
<div v-for="c in missionCols" :key="'p0_'+c" class="grid-cell point-cell" :class="'nav-'+getPointStatus(0, c-1)">
|
||||
<div class="cell-nav-icon">{% raw %}{{ navIcon(getPointStatus(0, c-1)) }}{% endraw %}</div>
|
||||
<div class="cell-nav-label">{% raw %}{{ navLabel(getPointStatus(0, c-1)) }}{% endraw %}</div>
|
||||
</div>
|
||||
<div class="task-step-text">[[ task.step ]]</div>
|
||||
<div class="task-info">
|
||||
<div v-if="task.qr_value" class="task-qr">🏷 [[ task.qr_value.substring(0,8) ]]</div>
|
||||
<div class="task-photos" v-if="task.photos_front || task.photos_back">
|
||||
📷 [[ task.photos_front ]]正 [[ task.photos_back ]]背
|
||||
|
||||
<!-- 中间: 机器行 + 点位行 交替 -->
|
||||
<template v-for="ri in missionRows" :key="'block'+ri">
|
||||
<!-- 机器行 ri -->
|
||||
<div class="grid-cell grid-header">机器行 {% raw %}{{ ri }}{% endraw %}</div>
|
||||
<div v-for="c in missionCols" :key="'mr'+ri+'_'+c"
|
||||
class="grid-cell machine-cell"
|
||||
:class="getMachineClass(ri-1, c-1)">
|
||||
<template v-if="hasMachine(ri-1, c-1)">
|
||||
<div class="machine-label">机器{% raw %}{{ ri }}-{{ c }}{% endraw %}</div>
|
||||
<div class="machine-steps-mini">
|
||||
<span class="step-dot" :class="'dot-'+getMachineField(ri-1,c-1,'qr')" title="二维码">🔍</span>
|
||||
<span class="step-dot" :class="'dot-'+getMachineField(ri-1,c-1,'front')" title="正面照">📸正</span>
|
||||
<span class="step-dot" :class="'dot-'+getMachineField(ri-1,c-1,'back')" title="背面照">📸背</span>
|
||||
</div>
|
||||
<div v-if="getMachineField(ri-1,c-1,'qr_val')" class="machine-qr-mini">🏷 {% raw %}{{ getMachineField(ri-1,c-1,'qr_val').substring(0,6) }}{% endraw %}</div>
|
||||
</template>
|
||||
<div v-else class="empty-cell">空</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 点位行 ri (pointRow=ri): 上一个机器的背面 / 下一个机器的正面 -->
|
||||
<div class="grid-cell grid-header">点位行 {% raw %}{{ ri+1 }}{% endraw %}</div>
|
||||
<div v-for="c in missionCols" :key="'p'+ri+'_'+c" class="grid-cell point-cell" :class="'nav-'+getPointStatus(ri, c-1)">
|
||||
<div class="cell-nav-icon">{% raw %}{{ navIcon(getPointStatus(ri, c-1)) }}{% endraw %}</div>
|
||||
<div class="cell-nav-label">{% raw %}{{ navLabel(getPointStatus(ri, c-1)) }}{% endraw %}</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid-legend" style="margin-top:10px;font-size:12px;color:#8899aa">
|
||||
⏳等待 🔄执行中 ✅完成 ⏭️跳过 ⚠️手动 🔍扫码 📸拍摄
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- 实时日志 -->
|
||||
<section class="card">
|
||||
<h2>📜 任务日志</h2>
|
||||
<div class="log-box" ref="logBox">
|
||||
<div v-for="(log, i) in logs" :key="i" class="log-line">[[ log ]]</div>
|
||||
<div v-for="(log, i) in logs" :key="i" class="log-line">{% raw %}{{ log }}{% endraw %}</div>
|
||||
<div v-if="logs.length === 0" class="log-empty">等待任务开始...</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -163,9 +187,9 @@
|
||||
<section class="card" v-if="report">
|
||||
<h2>📊 任务报告</h2>
|
||||
<div class="report-summary">
|
||||
<div class="stat ok">✅ 完成: [[ report.completed ]]</div>
|
||||
<div class="stat error">❌ 失败: [[ report.failed ]]</div>
|
||||
<div class="stat">总计: [[ report.total_points ]]</div>
|
||||
<div class="stat ok">✅ 完成: {% raw %}{{ report.completed }}{% endraw %}</div>
|
||||
<div class="stat error">❌ 失败: {% raw %}{{ report.failed }}{% endraw %}</div>
|
||||
<div class="stat">总计: {% raw %}{{ report.total_points }}{% endraw %}</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -186,7 +210,7 @@
|
||||
<div class="modal-overlay" v-if="waitingError">
|
||||
<div class="modal">
|
||||
<h3>⚠️ 执行错误</h3>
|
||||
<p>[[ errorMsg ]]</p>
|
||||
<p>{% raw %}{{ errorMsg }}{% endraw %}</p>
|
||||
<div class="modal-actions">
|
||||
<button class="btn btn-warning" @click="skipError">跳过</button>
|
||||
<button class="btn btn-error" @click="abortError">中断</button>
|
||||
@@ -198,7 +222,7 @@
|
||||
<div class="modal-overlay" v-if="waitingStep">
|
||||
<div class="modal">
|
||||
<h3>🦶 单步执行确认</h3>
|
||||
<p>机器 [[ stepLabel ]] 执行完成,请确认结果是否正确:</p>
|
||||
<p>机器 {% raw %}{{ stepLabel }}{% endraw %} 执行完成,请确认结果是否正确:</p>
|
||||
<div class="modal-actions">
|
||||
<button class="btn btn-success" @click="confirmStep">✅ 正确,继续</button>
|
||||
<button class="btn btn-warning" @click="retryStep">🔄 不正确,重试</button>
|
||||
@@ -211,6 +235,6 @@
|
||||
</div>
|
||||
|
||||
<script src="/static/js/vue3.global.prod.js"></script>
|
||||
<script src="/static/js/running.js?v=20260527b"></script>
|
||||
<script src="/static/js/running.js?v=20260529a"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -219,6 +219,27 @@ class MissionExecutorV3:
|
||||
"photos_back": 0,
|
||||
})
|
||||
|
||||
# 初始化点位状态和机器状态(实时推送给前端)
|
||||
self.report["point_status"] = {}
|
||||
for _pr in range(rows + 1):
|
||||
for _c in range(cols):
|
||||
pk = f"{_pr}_{_c}"
|
||||
has_f = _pr < rows and MissionExecutorV3._has_machine(grid, _pr, _c)
|
||||
has_b = _pr > 0 and MissionExecutorV3._has_machine(grid, _pr - 1, _c)
|
||||
self.report["point_status"][pk] = "pending" if (has_f or has_b) else "skipped"
|
||||
|
||||
self.report["machine_status"] = {}
|
||||
for _r in range(rows):
|
||||
for _c in range(cols):
|
||||
if MissionExecutorV3._has_machine(grid, _r, _c):
|
||||
self.report["machine_status"][f"{_r}_{_c}"] = {
|
||||
"has_machine": True,
|
||||
"qr": "pending", "qr_val": None,
|
||||
"front": "pending", "front_cnt": 0,
|
||||
"back": "pending", "back_cnt": 0,
|
||||
"status": "pending", "step": "等待",
|
||||
}
|
||||
|
||||
self._log(f"📍 点位蛇形路径: {len(path)} 个点位, {total_machines} 台机器")
|
||||
|
||||
# 任务步骤控制开关
|
||||
@@ -300,12 +321,19 @@ class MissionExecutorV3:
|
||||
except Exception as e:
|
||||
self._log(f" ⚠️ 机械臂初始化失败: {e}")
|
||||
|
||||
# 更新点位状态:开始导航
|
||||
pk = f"{pr}_{c}"
|
||||
if pk in self.report.get("point_status", {}):
|
||||
self.report["point_status"][pk] = "active"
|
||||
|
||||
# 导航到该点位的坐标
|
||||
nav_ok = False
|
||||
if opt_agv_move:
|
||||
# 找该点位的任意有效坐标(正面/背面坐标相同)
|
||||
pos = MissionExecutorV3._find_any_position(positions, pr, c)
|
||||
if pos and MissionExecutorV3._has_coords(pos):
|
||||
if not self._navigate(pos, f"点位({pr},{c})"):
|
||||
nav_ok = self._navigate(pos, f"点位({pr},{c})")
|
||||
if not nav_ok:
|
||||
self._log(f"⚠️ 导航失败,尝试继续")
|
||||
choice = self._wait_error(f"点位({pr},{c})导航失败")
|
||||
if choice == "abort":
|
||||
@@ -314,11 +342,21 @@ class MissionExecutorV3:
|
||||
self._log(f"⚠️ 点位({pr},{c})无有效坐标")
|
||||
else:
|
||||
self._log(" ⏭️ 跳过AGV移动")
|
||||
nav_ok = True # 无移动视为到达
|
||||
|
||||
# 更新点位状态:到达
|
||||
if pk in self.report.get("point_status", {}):
|
||||
self.report["point_status"][pk] = "done"
|
||||
|
||||
# --- 正面操作(机器 pr,c 的正面) ---
|
||||
qr_value = None
|
||||
if has_front and not self._stop.is_set():
|
||||
self._wait_pause()
|
||||
# 更新机器状态:正面开始
|
||||
mk = f"{pr}_{c}"
|
||||
if mk in self.report.get("machine_status", {}):
|
||||
self.report["machine_status"][mk]["status"] = "active"
|
||||
self.report["machine_status"][mk]["step"] = "正面扫码"
|
||||
if opt_qr_scan:
|
||||
qr_value = self._scan_qr_with_poses(qr_configs)
|
||||
if self._stop.is_set():
|
||||
@@ -326,6 +364,12 @@ class MissionExecutorV3:
|
||||
else:
|
||||
self._log(" ⏭️ 跳过二维码识别(正面)")
|
||||
qr_cache[(pr, c)] = qr_value
|
||||
# 更新机器状态:扫码完成
|
||||
mk2 = f"{pr}_{c}"
|
||||
if mk2 in self.report.get("machine_status", {}):
|
||||
self.report["machine_status"][mk2]["qr"] = "done" if qr_value else "skipped"
|
||||
self.report["machine_status"][mk2]["qr_val"] = qr_value
|
||||
self.report["machine_status"][mk2]["step"] = "正面拍照"
|
||||
|
||||
task = self._get_task(pr, c)
|
||||
if task and qr_value:
|
||||
@@ -345,11 +389,20 @@ class MissionExecutorV3:
|
||||
else:
|
||||
self._log(" ⏭️ 跳过正面拍照")
|
||||
completed_actions += 1
|
||||
# 更新机器状态:正面拍照完成
|
||||
mk3 = f"{pr}_{c}"
|
||||
if mk3 in self.report.get("machine_status", {}):
|
||||
self.report["machine_status"][mk3]["front"] = "done" if opt_front_photo else "skipped"
|
||||
self.report["machine_status"][mk3]["front_cnt"] = self.report["machine_status"][mk3].get("front_cnt", 0) + 1
|
||||
|
||||
# --- 背面操作(机器 pr-1,c 的背面) ---
|
||||
if has_back and not self._stop.is_set():
|
||||
self._wait_pause()
|
||||
back_qr = qr_cache.get((pr - 1, c), "unknown")
|
||||
# 更新机器状态:背面开始
|
||||
mk_b = f"{pr-1}_{c}"
|
||||
if mk_b in self.report.get("machine_status", {}):
|
||||
self.report["machine_status"][mk_b]["step"] = "背面拍照"
|
||||
|
||||
task = self._get_task(pr - 1, c)
|
||||
if task:
|
||||
@@ -367,6 +420,13 @@ class MissionExecutorV3:
|
||||
else:
|
||||
self._log(" ⏭️ 跳过背面拍照")
|
||||
completed_actions += 1
|
||||
# 更新机器状态:背面完成
|
||||
mk_b2 = f"{pr-1}_{c}"
|
||||
if mk_b2 in self.report.get("machine_status", {}):
|
||||
self.report["machine_status"][mk_b2]["back"] = "done" if opt_back_photo else "skipped"
|
||||
self.report["machine_status"][mk_b2]["back_cnt"] = self.report["machine_status"][mk_b2].get("back_cnt", 0) + 1
|
||||
self.report["machine_status"][mk_b2]["status"] = "completed"
|
||||
self.report["machine_status"][mk_b2]["step"] = "完成"
|
||||
if task:
|
||||
task["status"] = "completed"
|
||||
task["step"] = "完成"
|
||||
|
||||
Reference in New Issue
Block a user