Compare commits
No commits in common. "422774785210e30d637953c0f3ee1d27ce8fc621" and "45b2317ee8694af06bacaa9376eb75db1f6aec64" have entirely different histories.
4227747852
...
45b2317ee8
|
|
@ -1,2 +0,0 @@
|
||||||
ALTER TABLE point
|
|
||||||
ADD CONSTRAINT uq_equipment_signal_role UNIQUE (equipment_id, signal_role);
|
|
||||||
|
|
@ -317,15 +317,6 @@ async fn check_fault_comm(
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
// REM local: any equipment with a rem point that is explicitly false (local mode) with good quality.
|
|
||||||
let any_rem_local = all_roles.iter().any(|(_, roles)| {
|
|
||||||
roles
|
|
||||||
.get("rem")
|
|
||||||
.and_then(|rp| monitor.get(&rp.point_id))
|
|
||||||
.map(|m| !super::monitor_value_as_bool(m) && m.quality == PointQuality::Good)
|
|
||||||
.unwrap_or(false)
|
|
||||||
});
|
|
||||||
|
|
||||||
drop(monitor);
|
drop(monitor);
|
||||||
|
|
||||||
let prev_comm = runtime.comm_locked;
|
let prev_comm = runtime.comm_locked;
|
||||||
|
|
@ -333,11 +324,9 @@ async fn check_fault_comm(
|
||||||
let prev_fault_locked = runtime.fault_locked;
|
let prev_fault_locked = runtime.fault_locked;
|
||||||
let prev_auto = runtime.auto_enabled;
|
let prev_auto = runtime.auto_enabled;
|
||||||
let prev_ack = runtime.manual_ack_required;
|
let prev_ack = runtime.manual_ack_required;
|
||||||
let prev_rem_local = runtime.rem_local;
|
|
||||||
|
|
||||||
runtime.comm_locked = any_bad;
|
runtime.comm_locked = any_bad;
|
||||||
runtime.flt_active = any_flt;
|
runtime.flt_active = any_flt;
|
||||||
runtime.rem_local = any_rem_local;
|
|
||||||
|
|
||||||
if !prev_comm && runtime.comm_locked {
|
if !prev_comm && runtime.comm_locked {
|
||||||
let _ = state.event_manager.send(AppEvent::CommLocked { unit_id: unit.id });
|
let _ = state.event_manager.send(AppEvent::CommLocked { unit_id: unit.id });
|
||||||
|
|
@ -362,18 +351,11 @@ async fn check_fault_comm(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop auto-control when any equipment switches to local mode.
|
|
||||||
if any_rem_local && runtime.auto_enabled {
|
|
||||||
runtime.auto_enabled = false;
|
|
||||||
let _ = state.event_manager.send(AppEvent::AutoControlStopped { unit_id: unit.id });
|
|
||||||
}
|
|
||||||
|
|
||||||
runtime.comm_locked != prev_comm
|
runtime.comm_locked != prev_comm
|
||||||
|| runtime.flt_active != prev_flt
|
|| runtime.flt_active != prev_flt
|
||||||
|| runtime.fault_locked != prev_fault_locked
|
|| runtime.fault_locked != prev_fault_locked
|
||||||
|| runtime.auto_enabled != prev_auto
|
|| runtime.auto_enabled != prev_auto
|
||||||
|| runtime.manual_ack_required != prev_ack
|
|| runtime.manual_ack_required != prev_ack
|
||||||
|| runtime.rem_local != prev_rem_local
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type EquipMaps = (
|
type EquipMaps = (
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,6 @@ pub struct UnitRuntime {
|
||||||
pub flt_active: bool,
|
pub flt_active: bool,
|
||||||
pub comm_locked: bool,
|
pub comm_locked: bool,
|
||||||
pub manual_ack_required: bool,
|
pub manual_ack_required: bool,
|
||||||
/// True when any equipment in the unit has REM=false (local mode) with good signal quality.
|
|
||||||
pub rem_local: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UnitRuntime {
|
impl UnitRuntime {
|
||||||
|
|
@ -41,7 +39,6 @@ impl UnitRuntime {
|
||||||
flt_active: false,
|
flt_active: false,
|
||||||
comm_locked: false,
|
comm_locked: false,
|
||||||
manual_ack_required: false,
|
manual_ack_required: false,
|
||||||
rem_local: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ fn validate_unit_timing_order(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn auto_control_start_blocked(runtime: &crate::control::runtime::UnitRuntime) -> bool {
|
fn auto_control_start_blocked(runtime: &crate::control::runtime::UnitRuntime) -> bool {
|
||||||
runtime.fault_locked || runtime.comm_locked || runtime.manual_ack_required || runtime.rem_local
|
runtime.fault_locked || runtime.comm_locked || runtime.manual_ack_required
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Validate)]
|
#[derive(Debug, Deserialize, Validate)]
|
||||||
|
|
@ -543,8 +543,6 @@ pub async fn start_auto_unit(
|
||||||
"Unit is fault locked, cannot start auto control"
|
"Unit is fault locked, cannot start auto control"
|
||||||
} else if runtime.comm_locked {
|
} else if runtime.comm_locked {
|
||||||
"Unit communication is locked, cannot start auto control"
|
"Unit communication is locked, cannot start auto control"
|
||||||
} else if runtime.rem_local {
|
|
||||||
"Equipment is in local mode (REM off), cannot start auto control"
|
|
||||||
} else {
|
} else {
|
||||||
"Fault acknowledgement required before starting auto control"
|
"Fault acknowledgement required before starting auto control"
|
||||||
};
|
};
|
||||||
|
|
@ -742,7 +740,6 @@ mod tests {
|
||||||
flt_active: false,
|
flt_active: false,
|
||||||
comm_locked: true,
|
comm_locked: true,
|
||||||
manual_ack_required: false,
|
manual_ack_required: false,
|
||||||
rem_local: false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
assert!(auto_control_start_blocked(&runtime));
|
assert!(auto_control_start_blocked(&runtime));
|
||||||
|
|
|
||||||
|
|
@ -208,14 +208,9 @@ export function renderEquipments() {
|
||||||
actionRow.append(editBtn, deleteBtn);
|
actionRow.append(editBtn, deleteBtn);
|
||||||
|
|
||||||
if (equipment.kind === "coal_feeder" || equipment.kind === "distributor") {
|
if (equipment.kind === "coal_feeder" || equipment.kind === "distributor") {
|
||||||
const unitRuntime = equipment.unit_id ? state.runtimes.get(equipment.unit_id) : null;
|
|
||||||
const remLocal = unitRuntime?.rem_local ?? false;
|
|
||||||
|
|
||||||
const startBtn = document.createElement("button");
|
const startBtn = document.createElement("button");
|
||||||
startBtn.className = "secondary";
|
startBtn.className = "secondary";
|
||||||
startBtn.textContent = "Start";
|
startBtn.textContent = "Start";
|
||||||
startBtn.disabled = remLocal;
|
|
||||||
startBtn.title = remLocal ? "设备处于本地模式(REM关)" : "";
|
|
||||||
startBtn.addEventListener("click", (e) => {
|
startBtn.addEventListener("click", (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
apiFetch(`/api/control/equipment/${equipment.id}/start`, { method: "POST" })
|
apiFetch(`/api/control/equipment/${equipment.id}/start`, { method: "POST" })
|
||||||
|
|
@ -225,8 +220,6 @@ export function renderEquipments() {
|
||||||
const stopBtn = document.createElement("button");
|
const stopBtn = document.createElement("button");
|
||||||
stopBtn.className = "danger";
|
stopBtn.className = "danger";
|
||||||
stopBtn.textContent = "Stop";
|
stopBtn.textContent = "Stop";
|
||||||
stopBtn.disabled = remLocal;
|
|
||||||
stopBtn.title = remLocal ? "设备处于本地模式(REM关)" : "";
|
|
||||||
stopBtn.addEventListener("click", (e) => {
|
stopBtn.addEventListener("click", (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
apiFetch(`/api/control/equipment/${equipment.id}/stop`, { method: "POST" })
|
apiFetch(`/api/control/equipment/${equipment.id}/stop`, { method: "POST" })
|
||||||
|
|
|
||||||
|
|
@ -55,15 +55,13 @@ export function renderOpsUnits() {
|
||||||
const actions = item.querySelector(".ops-unit-item-actions");
|
const actions = item.querySelector(".ops-unit-item-actions");
|
||||||
|
|
||||||
const isAutoOn = runtime?.auto_enabled;
|
const isAutoOn = runtime?.auto_enabled;
|
||||||
const startBlocked = !isAutoOn && (runtime?.fault_locked || runtime?.manual_ack_required || runtime?.rem_local);
|
const startBlocked = !isAutoOn && (runtime?.fault_locked || runtime?.manual_ack_required);
|
||||||
const autoBtn = document.createElement("button");
|
const autoBtn = document.createElement("button");
|
||||||
autoBtn.className = isAutoOn ? "danger" : "secondary";
|
autoBtn.className = isAutoOn ? "danger" : "secondary";
|
||||||
autoBtn.textContent = isAutoOn ? "Stop Auto" : "Start Auto";
|
autoBtn.textContent = isAutoOn ? "Stop Auto" : "Start Auto";
|
||||||
autoBtn.disabled = startBlocked;
|
autoBtn.disabled = startBlocked;
|
||||||
autoBtn.title = startBlocked
|
autoBtn.title = startBlocked
|
||||||
? (runtime?.fault_locked ? "设备故障中,无法启动自动控制"
|
? (runtime?.fault_locked ? "设备故障中,无法启动自动控制" : "需人工确认故障后才可启动自动控制")
|
||||||
: runtime?.rem_local ? "设备处于本地模式(REM关),无法启动自动控制"
|
|
||||||
: "需人工确认故障后才可启动自动控制")
|
|
||||||
: (isAutoOn ? "停止自动控制" : "启动自动控制");
|
: (isAutoOn ? "停止自动控制" : "启动自动控制");
|
||||||
autoBtn.addEventListener("click", (e) => {
|
autoBtn.addEventListener("click", (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
|
||||||
|
|
@ -151,15 +151,13 @@ export function renderUnits() {
|
||||||
actions.append(editBtn, deleteBtn);
|
actions.append(editBtn, deleteBtn);
|
||||||
|
|
||||||
const isAutoOn = runtime?.auto_enabled;
|
const isAutoOn = runtime?.auto_enabled;
|
||||||
const startBlocked = !isAutoOn && (runtime?.fault_locked || runtime?.manual_ack_required || runtime?.rem_local);
|
const startBlocked = !isAutoOn && (runtime?.fault_locked || runtime?.manual_ack_required);
|
||||||
const autoBtn = document.createElement("button");
|
const autoBtn = document.createElement("button");
|
||||||
autoBtn.className = isAutoOn ? "danger" : "secondary";
|
autoBtn.className = isAutoOn ? "danger" : "secondary";
|
||||||
autoBtn.textContent = isAutoOn ? "Stop Auto" : "Start Auto";
|
autoBtn.textContent = isAutoOn ? "Stop Auto" : "Start Auto";
|
||||||
autoBtn.disabled = startBlocked;
|
autoBtn.disabled = startBlocked;
|
||||||
autoBtn.title = startBlocked
|
autoBtn.title = startBlocked
|
||||||
? (runtime?.fault_locked ? "设备故障中,无法启动自动控制"
|
? (runtime?.fault_locked ? "设备故障中,无法启动自动控制" : "需人工确认故障后才可启动自动控制")
|
||||||
: runtime?.rem_local ? "设备处于本地模式(REM关),无法启动自动控制"
|
|
||||||
: "需人工确认故障后才可启动自动控制")
|
|
||||||
: (isAutoOn ? "停止自动控制" : "启动自动控制");
|
: (isAutoOn ? "停止自动控制" : "启动自动控制");
|
||||||
autoBtn.addEventListener("click", (e) => {
|
autoBtn.addEventListener("click", (e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue