i18n(feeder): replace all English UI text with Chinese

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
caoqianming 2026-04-20 09:12:15 +08:00
parent 268c5f76af
commit f8757a757e
10 changed files with 63 additions and 63 deletions

View File

@ -38,7 +38,7 @@
</div> </div>
<div class="toolbar"> <div class="toolbar">
<select id="pointSourceSelect"></select> <select id="pointSourceSelect"></select>
<div class="muted" id="pointSourceNodeCount">Nodes: 0</div> <div class="muted" id="pointSourceNodeCount">节点: 0</div>
<button id="browseNodes">加载节点</button> <button id="browseNodes">加载节点</button>
<button class="secondary" id="refreshTree">刷新树</button> <button class="secondary" id="refreshTree">刷新树</button>
</div> </div>

View File

@ -42,7 +42,7 @@
</div> </div>
<div class="toolbar"> <div class="toolbar">
<select id="pointSourceSelect"></select> <select id="pointSourceSelect"></select>
<div class="muted" id="pointSourceNodeCount">Nodes: 0</div> <div class="muted" id="pointSourceNodeCount">节点: 0</div>
<button id="browseNodes">加载节点</button> <button id="browseNodes">加载节点</button>
<button class="secondary" id="refreshTree">刷新树</button> <button class="secondary" id="refreshTree">刷新树</button>
</div> </div>

View File

@ -105,8 +105,8 @@ function bindEvents() {
dom.closeEquipmentModalBtn.addEventListener("click", closeEquipmentModal); dom.closeEquipmentModalBtn.addEventListener("click", closeEquipmentModal);
dom.openPointModalBtn.addEventListener("click", openPointCreateModal); dom.openPointModalBtn.addEventListener("click", openPointCreateModal);
dom.pointSourceSelect.addEventListener("change", () => { dom.pointSourceSelect.addEventListener("change", () => {
dom.nodeTree.innerHTML = '<div class="muted">Click "Load Nodes" to fetch node tree</div>'; dom.nodeTree.innerHTML = '<div class="muted">点击"加载节点"获取节点树</div>';
dom.pointSourceNodeCount.textContent = "Nodes: 0"; dom.pointSourceNodeCount.textContent = "节点: 0";
}); });
dom.browseNodesBtn.addEventListener("click", () => withStatus(browseAndLoadTree())); dom.browseNodesBtn.addEventListener("click", () => withStatus(browseAndLoadTree()));
dom.refreshTreeBtn.addEventListener("click", () => withStatus(loadTree())); dom.refreshTreeBtn.addEventListener("click", () => withStatus(loadTree()));

View File

@ -52,8 +52,8 @@ function formatTimeLabel(timestamp) {
export async function openChart(pointId, pointName) { export async function openChart(pointId, pointName) {
state.chartPointId = pointId; state.chartPointId = pointId;
state.chartPointName = pointName || "Point"; state.chartPointName = pointName || "点位";
dom.chartTitle.textContent = `${state.chartPointName} Chart`; dom.chartTitle.textContent = `${state.chartPointName} 趋势图`;
const items = await apiFetch(`/api/point/${pointId}/history?limit=120`); const items = await apiFetch(`/api/point/${pointId}/history?limit=120`);
state.chartData = (items || []) state.chartData = (items || [])
@ -99,8 +99,8 @@ export function renderChart() {
if (!state.chartData.length) { if (!state.chartData.length) {
ctx.fillStyle = "#94a3b8"; ctx.fillStyle = "#94a3b8";
ctx.font = "14px Segoe UI"; ctx.font = "14px Segoe UI";
ctx.fillText("Click a point row to view its chart", 24, 40); ctx.fillText("点击点位行查看图表", 24, 40);
dom.chartSummary.textContent = "Click a point row to view its chart"; dom.chartSummary.textContent = "点击点位行查看图表";
return; return;
} }
@ -158,9 +158,9 @@ export function renderChart() {
ctx.translate(16, padding.top + plotHeight / 2); ctx.translate(16, padding.top + plotHeight / 2);
ctx.rotate(-Math.PI / 2); ctx.rotate(-Math.PI / 2);
ctx.fillStyle = "#64748b"; ctx.fillStyle = "#64748b";
ctx.fillText("Value", 0, 0); ctx.fillText("数值", 0, 0);
ctx.restore(); ctx.restore();
ctx.fillText("Time", width / 2 - 12, height - 28); ctx.fillText("时间", width / 2 - 12, height - 28);
ctx.strokeStyle = "#2563eb"; ctx.strokeStyle = "#2563eb";
ctx.lineWidth = 2; ctx.lineWidth = 2;

View File

@ -41,7 +41,7 @@ function renderEquipmentUnitOptions(selected = "", target = dom.equipmentUnitId)
} }
export function renderBindingEquipmentOptions(selected = "", target = dom.bindingEquipmentId) { export function renderBindingEquipmentOptions(selected = "", target = dom.bindingEquipmentId) {
const options = ['<option value="">Unbound</option>']; const options = ['<option value="">未绑定</option>'];
filteredEquipments().forEach((item) => { filteredEquipments().forEach((item) => {
const equipment = equipmentOf(item); const equipment = equipmentOf(item);
const isSelected = equipment.id === selected ? "selected" : ""; const isSelected = equipment.id === selected ? "selected" : "";
@ -112,7 +112,7 @@ export function renderEquipments() {
const items = filteredEquipments(); const items = filteredEquipments();
if (!items.length) { if (!items.length) {
dom.equipmentList.innerHTML = '<div class="list-item"><div class="muted">No equipment</div></div>'; dom.equipmentList.innerHTML = '<div class="list-item"><div class="muted">暂无设备</div></div>';
return; return;
} }
@ -126,7 +126,7 @@ export function renderEquipments() {
<span class="badge">${item.point_count ?? 0} pts</span> <span class="badge">${item.point_count ?? 0} pts</span>
</div> </div>
<div>${equipment.name}</div> <div>${equipment.name}</div>
<div class="muted">${equipment.kind || "No type"}</div> <div class="muted">${equipment.kind || "未分类"}</div>
<div class="muted">单元: ${currentUnitLabel(equipment.unit_id)}</div> <div class="muted">单元: ${currentUnitLabel(equipment.unit_id)}</div>
<div class="row equipment-card-actions"></div> <div class="row equipment-card-actions"></div>
`; `;
@ -141,7 +141,7 @@ export function renderEquipments() {
const editBtn = document.createElement("button"); const editBtn = document.createElement("button");
editBtn.className = "secondary"; editBtn.className = "secondary";
editBtn.textContent = "Edit"; editBtn.textContent = "编辑";
editBtn.addEventListener("click", (event) => { editBtn.addEventListener("click", (event) => {
event.stopPropagation(); event.stopPropagation();
openEditEquipmentModal(equipment); openEditEquipmentModal(equipment);
@ -149,7 +149,7 @@ export function renderEquipments() {
const deleteBtn = document.createElement("button"); const deleteBtn = document.createElement("button");
deleteBtn.className = "danger"; deleteBtn.className = "danger";
deleteBtn.textContent = "Delete"; deleteBtn.textContent = "删除";
deleteBtn.addEventListener("click", (event) => { deleteBtn.addEventListener("click", (event) => {
event.stopPropagation(); event.stopPropagation();
deleteEquipment(equipment.id).catch((error) => { deleteEquipment(equipment.id).catch((error) => {
@ -218,7 +218,7 @@ export async function saveEquipment(event) {
} }
export async function deleteEquipment(equipmentId) { export async function deleteEquipment(equipmentId) {
if (!window.confirm("Delete this equipment?")) { if (!window.confirm("确认删除该设备?")) {
return; return;
} }

View File

@ -58,7 +58,7 @@ export function renderOpsUnits() {
const startBlocked = !isAutoOn && (runtime?.fault_locked || runtime?.manual_ack_required || runtime?.rem_local); const startBlocked = !isAutoOn && (runtime?.fault_locked || runtime?.manual_ack_required || runtime?.rem_local);
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 ? "停止自动" : "启动自动";
autoBtn.disabled = startBlocked; autoBtn.disabled = startBlocked;
autoBtn.title = startBlocked autoBtn.title = startBlocked
? (runtime?.fault_locked ? "设备故障中,无法启动自动控制" ? (runtime?.fault_locked ? "设备故障中,无法启动自动控制"
@ -75,7 +75,7 @@ export function renderOpsUnits() {
if (runtime?.manual_ack_required) { if (runtime?.manual_ack_required) {
const ackBtn = document.createElement("button"); const ackBtn = document.createElement("button");
ackBtn.className = "danger"; ackBtn.className = "danger";
ackBtn.textContent = "Ack Fault"; ackBtn.textContent = "故障确认";
ackBtn.title = "人工确认解除故障锁定"; ackBtn.title = "人工确认解除故障锁定";
ackBtn.addEventListener("click", (e) => { ackBtn.addEventListener("click", (e) => {
e.stopPropagation(); e.stopPropagation();
@ -153,13 +153,13 @@ function renderOpsEquipments(equipments) {
const startBtn = document.createElement("button"); const startBtn = document.createElement("button");
startBtn.className = "secondary"; startBtn.className = "secondary";
startBtn.textContent = "Start"; startBtn.textContent = "启动";
startBtn.addEventListener("click", () => startBtn.addEventListener("click", () =>
apiFetch(`/api/control/equipment/${eq.id}/start`, { method: "POST" }).catch(() => {}) apiFetch(`/api/control/equipment/${eq.id}/start`, { method: "POST" }).catch(() => {})
); );
const stopBtn = document.createElement("button"); const stopBtn = document.createElement("button");
stopBtn.className = "danger"; stopBtn.className = "danger";
stopBtn.textContent = "Stop"; stopBtn.textContent = "停止";
stopBtn.addEventListener("click", () => stopBtn.addEventListener("click", () =>
apiFetch(`/api/control/equipment/${eq.id}/stop`, { method: "POST" }).catch(() => {}) apiFetch(`/api/control/equipment/${eq.id}/stop`, { method: "POST" }).catch(() => {})
); );

View File

@ -11,7 +11,7 @@ import { state } from "./state.js";
function updatePointSourceNodeCount() { function updatePointSourceNodeCount() {
const count = dom.nodeTree.querySelectorAll("details").length; const count = dom.nodeTree.querySelectorAll("details").length;
dom.pointSourceNodeCount.textContent = `Nodes: ${count}`; dom.pointSourceNodeCount.textContent = `节点: ${count}`;
} }
export function formatValue(monitor) { export function formatValue(monitor) {
@ -28,13 +28,13 @@ export function formatValue(monitor) {
} }
export function renderSelectedNodes() { export function renderSelectedNodes() {
dom.selectedCount.textContent = `Selected ${state.selectedNodeIds.size} nodes`; dom.selectedCount.textContent = `已选中 ${state.selectedNodeIds.size} 个节点`;
} }
export function updateSelectedPointSummary() { export function updateSelectedPointSummary() {
const count = state.selectedPointIds.size; const count = state.selectedPointIds.size;
dom.selectedPointCount.textContent = `Selected ${count} points`; dom.selectedPointCount.textContent = `已选中 ${count} 个点位`;
dom.batchBindingSummary.textContent = `Selected ${count} points`; dom.batchBindingSummary.textContent = `已选中 ${count} 个点位`;
dom.openBatchBindingBtn.disabled = count === 0; dom.openBatchBindingBtn.disabled = count === 0;
} }
@ -42,16 +42,16 @@ export function updatePointFilterSummary() {
const filters = []; const filters = [];
if (state.selectedEquipmentId) { if (state.selectedEquipmentId) {
const equipment = state.equipmentMap.get(state.selectedEquipmentId); const equipment = state.equipmentMap.get(state.selectedEquipmentId);
filters.push(`Equipment:${equipment?.name || equipment?.code || "Unknown"}`); filters.push(`设备:${equipment?.name || equipment?.code || "未知"}`);
} }
if (state.selectedSourceId) { if (state.selectedSourceId) {
const source = state.sources.find((item) => item.id === state.selectedSourceId); const source = state.sources.find((item) => item.id === state.selectedSourceId);
filters.push(`Source:${source?.name || "Unknown"}`); filters.push(`数据源:${source?.name || "未知"}`);
} }
dom.pointFilterSummary.textContent = filters.length dom.pointFilterSummary.textContent = filters.length
? `Current filter: ${filters.join(" / ")}` ? `当前筛选: ${filters.join(" / ")}`
: "Current filter: All points"; : "当前筛选: 全部点位";
} }
export function clearSelectedPoints() { export function clearSelectedPoints() {
@ -102,8 +102,8 @@ export function openPointCreateModal() {
if (dom.pointSourceSelect) { if (dom.pointSourceSelect) {
dom.pointSourceSelect.value = state.selectedSourceId || ""; dom.pointSourceSelect.value = state.selectedSourceId || "";
} }
dom.nodeTree.innerHTML = '<div class="muted">Select a source and load nodes</div>'; dom.nodeTree.innerHTML = '<div class="muted">选择数据源并加载节点</div>';
dom.pointSourceNodeCount.textContent = "Nodes: 0"; dom.pointSourceNodeCount.textContent = "节点: 0";
state.selectedNodeIds.clear(); state.selectedNodeIds.clear();
renderSelectedNodes(); renderSelectedNodes();
} }
@ -111,8 +111,8 @@ export function openPointCreateModal() {
export async function loadTree() { export async function loadTree() {
const sourceId = dom.pointSourceSelect.value || state.selectedSourceId; const sourceId = dom.pointSourceSelect.value || state.selectedSourceId;
if (!sourceId) { if (!sourceId) {
dom.nodeTree.innerHTML = '<div class="muted">Select a source</div>'; dom.nodeTree.innerHTML = '<div class="muted">请选择数据源</div>';
dom.pointSourceNodeCount.textContent = "Nodes: 0"; dom.pointSourceNodeCount.textContent = "节点: 0";
return; return;
} }
@ -126,7 +126,7 @@ export async function loadTree() {
export async function browseAndLoadTree() { export async function browseAndLoadTree() {
const sourceId = dom.pointSourceSelect.value || state.selectedSourceId; const sourceId = dom.pointSourceSelect.value || state.selectedSourceId;
if (!sourceId) { if (!sourceId) {
throw new Error("Select a source first"); throw new Error("请先选择数据源");
} }
state.selectedSourceId = sourceId; state.selectedSourceId = sourceId;
@ -178,7 +178,7 @@ export async function loadPoints() {
dom.pointList.innerHTML = ""; dom.pointList.innerHTML = "";
if (!items.length) { if (!items.length) {
dom.pointList.innerHTML = '<tr><td colspan="7" class="empty-state">No points</td></tr>'; dom.pointList.innerHTML = '<tr><td colspan="7" class="empty-state">暂无点位</td></tr>';
dom.pointsPageInfo.textContent = `${state.pointsPage} / 1`; dom.pointsPageInfo.textContent = `${state.pointsPage} / 1`;
clearSelectedPoints(); clearSelectedPoints();
updatePointFilterSummary(); updatePointFilterSummary();
@ -207,7 +207,7 @@ export async function loadPoints() {
<td><span class="badge quality-${(monitor?.quality || "unknown").toLowerCase()}">${(monitor?.quality || "unknown").toUpperCase()}</span></td> <td><span class="badge quality-${(monitor?.quality || "unknown").toLowerCase()}">${(monitor?.quality || "unknown").toUpperCase()}</span></td>
<td> <td>
<div class="point-meta"> <div class="point-meta">
<div>${equipment ? equipment.name : '<span class="muted">Unbound</span>'}</div> <div>${equipment ? equipment.name : '<span class="muted">未绑定</span>'}</div>
<div class="point-role">${point.signal_role || "--"}</div> <div class="point-role">${point.signal_role || "--"}</div>
</div> </div>
</td> </td>
@ -228,7 +228,7 @@ export async function loadPoints() {
actionCell.className = "point-actions"; actionCell.className = "point-actions";
const editBtn = document.createElement("button"); const editBtn = document.createElement("button");
editBtn.className = "secondary"; editBtn.className = "secondary";
editBtn.textContent = "Edit"; editBtn.textContent = "编辑";
editBtn.addEventListener("click", (event) => { editBtn.addEventListener("click", (event) => {
event.stopPropagation(); event.stopPropagation();
openPointBinding(point); openPointBinding(point);
@ -236,7 +236,7 @@ export async function loadPoints() {
const deleteBtn = document.createElement("button"); const deleteBtn = document.createElement("button");
deleteBtn.className = "danger"; deleteBtn.className = "danger";
deleteBtn.textContent = "Delete"; deleteBtn.textContent = "删除";
deleteBtn.addEventListener("click", (event) => { deleteBtn.addEventListener("click", (event) => {
event.stopPropagation(); event.stopPropagation();
deletePoint(point.id).catch((error) => { deletePoint(point.id).catch((error) => {
@ -270,14 +270,14 @@ export function openPointBinding(point) {
dom.bindingPointName.disabled = false; dom.bindingPointName.disabled = false;
const modalTitle = dom.pointBindingModal.querySelector("h3"); const modalTitle = dom.pointBindingModal.querySelector("h3");
if (modalTitle) { if (modalTitle) {
modalTitle.textContent = "Edit Point"; modalTitle.textContent = "编辑点位";
} }
if (dom.clearPointBindingBtn) { if (dom.clearPointBindingBtn) {
dom.clearPointBindingBtn.textContent = "Clear Equipment"; dom.clearPointBindingBtn.textContent = "清除设备";
} }
const saveButton = dom.pointBindingForm?.querySelector('button[type="submit"]'); const saveButton = dom.pointBindingForm?.querySelector('button[type="submit"]');
if (saveButton) { if (saveButton) {
saveButton.textContent = "Save"; saveButton.textContent = "保存";
} }
renderBindingEquipmentOptions(point.equipment_id || ""); renderBindingEquipmentOptions(point.equipment_id || "");
dom.bindingSignalRole.innerHTML = renderRoleOptions(point.signal_role || ""); dom.bindingSignalRole.innerHTML = renderRoleOptions(point.signal_role || "");
@ -353,7 +353,7 @@ export async function clearBatchBinding() {
} }
export async function deletePoint(pointId) { export async function deletePoint(pointId) {
if (!window.confirm("Delete this point?")) { if (!window.confirm("确认删除该点位?")) {
return; return;
} }

View File

@ -1,17 +1,17 @@
export const SIGNAL_ROLE_OPTIONS = [ export const SIGNAL_ROLE_OPTIONS = [
{ value: "", label: "Unset" }, { value: "", label: "未设置" },
{ value: "rem", label: "REM Remote Enable" }, { value: "rem", label: "REM 远程使能" },
{ value: "run", label: "RUN Running" }, { value: "run", label: "RUN 运行" },
{ value: "flt", label: "FLT Fault" }, { value: "flt", label: "FLT 故障" },
{ value: "ii", label: "II Current" }, { value: "ii", label: "II 电流" },
{ value: "start_cmd", label: "Start Command" }, { value: "start_cmd", label: "启动命令" },
{ value: "stop_cmd", label: "Stop Command" }, { value: "stop_cmd", label: "停止命令" },
]; ];
export const EQUIPMENT_KIND_OPTIONS = [ export const EQUIPMENT_KIND_OPTIONS = [
{ value: "", label: "Unset" }, { value: "", label: "未设置" },
{ value: "coal_feeder", label: "Coal Feeder" }, { value: "coal_feeder", label: "投煤器" },
{ value: "distributor", label: "Distributor" }, { value: "distributor", label: "布料机" },
]; ];
export function renderRoleOptions(selected = "") { export function renderRoleOptions(selected = "") {

View File

@ -8,7 +8,7 @@ function renderPointSourceOptions() {
return; return;
} }
const options = ['<option value="">Select source</option>']; const options = ['<option value="">选择数据源</option>'];
state.sources.forEach((source) => { state.sources.forEach((source) => {
const selected = source.id === state.selectedSourceId ? "selected" : ""; const selected = source.id === state.selectedSourceId ? "selected" : "";
options.push(`<option value="${source.id}" ${selected}>${source.name}</option>`); options.push(`<option value="${source.id}" ${selected}>${source.name}</option>`);
@ -41,7 +41,7 @@ export function renderSources() {
const editBtn = document.createElement("button"); const editBtn = document.createElement("button");
editBtn.className = "secondary"; editBtn.className = "secondary";
editBtn.textContent = "Edit"; editBtn.textContent = "编辑";
editBtn.addEventListener("click", (event) => { editBtn.addEventListener("click", (event) => {
event.stopPropagation(); event.stopPropagation();
dom.sourceId.value = source.id; dom.sourceId.value = source.id;
@ -53,7 +53,7 @@ export function renderSources() {
const reconnectBtn = document.createElement("button"); const reconnectBtn = document.createElement("button");
reconnectBtn.className = "secondary"; reconnectBtn.className = "secondary";
reconnectBtn.textContent = "Reconnect"; reconnectBtn.textContent = "重连";
reconnectBtn.addEventListener("click", (event) => { reconnectBtn.addEventListener("click", (event) => {
event.stopPropagation(); event.stopPropagation();
reconnectSource(source.id, source.name).catch((error) => { reconnectSource(source.id, source.name).catch((error) => {
@ -63,7 +63,7 @@ export function renderSources() {
const deleteBtn = document.createElement("button"); const deleteBtn = document.createElement("button");
deleteBtn.className = "danger"; deleteBtn.className = "danger";
deleteBtn.textContent = "Delete"; deleteBtn.textContent = "删除";
deleteBtn.addEventListener("click", (event) => { deleteBtn.addEventListener("click", (event) => {
event.stopPropagation(); event.stopPropagation();
deleteSource(source.id).catch((error) => { deleteSource(source.id).catch((error) => {
@ -118,14 +118,14 @@ export async function saveSource(event) {
} }
export async function reconnectSource(sourceId, name) { export async function reconnectSource(sourceId, name) {
dom.statusText.textContent = `Reconnecting ${name || "Source"}...`; dom.statusText.textContent = `正在重连 ${name || "数据源"}...`;
await apiFetch(`/api/source/${sourceId}/reconnect`, { method: "POST" }); await apiFetch(`/api/source/${sourceId}/reconnect`, { method: "POST" });
await loadSources(); await loadSources();
dom.statusText.textContent = "Ready"; dom.statusText.textContent = "就绪";
} }
export async function deleteSource(sourceId) { export async function deleteSource(sourceId) {
if (!window.confirm("Delete this source?")) { if (!window.confirm("确认删除该数据源?")) {
return; return;
} }

View File

@ -125,8 +125,8 @@ function buildUnitCard(unit, mode) {
<span class="badge ${unit.enabled ? "" : "offline"}">${unit.enabled ? "EN" : "DIS"}</span> <span class="badge ${unit.enabled ? "" : "offline"}">${unit.enabled ? "EN" : "DIS"}</span>
</div> </div>
<div>${unit.name}</div> <div>${unit.name}</div>
<div class="muted">设备 ${bound.length} | Acc ${runtime ? Math.floor(runtime.display_acc_sec / 1000) : 0}s</div> <div class="muted">设备 ${bound.length} | 累计 ${runtime ? Math.floor(runtime.display_acc_sec / 1000) : 0}s</div>
<div class="muted">Run ${unit.run_time_sec}s / Stop ${unit.stop_time_sec}s / Acc ${unit.acc_time_sec}s / BL ${unit.bl_time_sec}s</div> <div class="muted">运行 ${unit.run_time_sec}s / 停止 ${unit.stop_time_sec}s / 累计 ${unit.acc_time_sec}s / 间隔 ${unit.bl_time_sec}s</div>
${mode === "config" ? `<div class="unit-equipment-tags">${equipTags}</div>` : ""} ${mode === "config" ? `<div class="unit-equipment-tags">${equipTags}</div>` : ""}
<div class="row unit-card-actions"></div> <div class="row unit-card-actions"></div>
`; `;
@ -143,7 +143,7 @@ function buildUnitCard(unit, mode) {
const editBtn = document.createElement("button"); const editBtn = document.createElement("button");
editBtn.className = "secondary"; editBtn.className = "secondary";
editBtn.textContent = "Edit"; editBtn.textContent = "编辑";
editBtn.addEventListener("click", (event) => { editBtn.addEventListener("click", (event) => {
event.stopPropagation(); event.stopPropagation();
openEditUnitModal(unit); openEditUnitModal(unit);
@ -151,7 +151,7 @@ function buildUnitCard(unit, mode) {
const deleteBtn = document.createElement("button"); const deleteBtn = document.createElement("button");
deleteBtn.className = "danger"; deleteBtn.className = "danger";
deleteBtn.textContent = "Delete"; deleteBtn.textContent = "删除";
deleteBtn.addEventListener("click", (event) => { deleteBtn.addEventListener("click", (event) => {
event.stopPropagation(); event.stopPropagation();
deleteUnit(unit.id).catch((error) => { deleteUnit(unit.id).catch((error) => {
@ -240,7 +240,7 @@ export async function saveUnit(event) {
} }
export async function deleteUnit(unitId) { export async function deleteUnit(unitId) {
if (!window.confirm("Delete this unit?")) { if (!window.confirm("确认删除该单元?")) {
return; return;
} }