= {
@@ -494,7 +494,7 @@ export default function CabinetDetail() {
📶 RSSI: {detail.rssi != null ? detail.rssi : '-'}
- 🌡 柜温: --°C
+ 🌡 柜温: {formatTempK100(detail.temp, '--°C')}
{/* 停电状态(协议 §5.4):直流 / 交流两个独立事件,可同时出现 */}
@@ -565,7 +565,6 @@ export default function CabinetDetail() {
{board.compartments.map((comp) => {
const st = STATUS_MAP[comp.status] || { label: '未知', color: 'gray' };
- const c = comp as any;
// 协议 §3.8:电池状态与电源状态是两个相互独立维度,分别解析、分别展示
const batt = parseBattStatus(comp.batt_status);
const pow = parsePowStatus(comp.pow_status);
@@ -590,11 +589,12 @@ export default function CabinetDetail() {
-
{c.voltage ?? '-'}mV
-
{c.current ?? '-'}mA
- {c.temp != null &&
{((c.temp / 100) - 273.15).toFixed(1)}°C}
- {c.soc != null &&
{c.soc}%}
- {c.battery_id &&
{c.battery_id}}
+
{comp.voltage ?? '-'}mV
+
{comp.current ?? '-'}mA
+ {comp.temp != null &&
{formatTempK100(comp.temp)}}
+ {/* 电量单位是 ‰(协议附 A:4500 = 45.0%),需 /10 换算,否则会大 10 倍 */}
+ {comp.soc != null &&
{(comp.soc / 10).toFixed(1)}%}
+ {comp.battery_id &&
{comp.battery_id}}
@@ -587,20 +625,15 @@ export default function Devices() {
-
-
- {total > pageSize && (
-
-
setPage(p)}
- size="small"
- hideOnSinglePage
- />
-
- )}
+
+ {/* 上分页 */}
+ {renderPagination()}
+ {/* 卡片网格(独立滚动区域,避免分页器被内容顶走) */}
+
+
+
+ {/* 下分页 */}
+ {renderPagination()}
@@ -672,7 +705,7 @@ export default function Devices() {
visible={cabinetModalVisible}
orgList={orgList}
onCancel={() => setCabinetModalVisible(false)}
- onSuccess={async () => { setCabinetModalVisible(false); await loadTree(); }}
+ onSuccess={async () => { setCabinetModalVisible(false); await handleRefresh(); }}
/>
{/* 项目管理弹窗 */}
diff --git a/software/web/src/pages/energy/index.tsx b/software/web/src/pages/energy/index.tsx
index 838a1e8..b3c7176 100644
--- a/software/web/src/pages/energy/index.tsx
+++ b/software/web/src/pages/energy/index.tsx
@@ -31,6 +31,7 @@ import {
ResponsiveContainer,
} from 'recharts';
import { api } from '@/api/request';
+import { Permission } from '@/components/Permission';
import DownloadCenter from '../charge-records/DownloadCenter';
const Row = Grid.Row;
@@ -145,14 +146,15 @@ export default function Energy() {
fetchTrend();
}, [fetchTrend]);
- /** 导出 */
+ /** 导出(后端要求 energy:export) */
const handleExport = async () => {
try {
await api.get('/energy-stats/export');
Message.success('导出任务已创建,请到下载中心查看');
setDownloadVisible(true);
- } catch {
- Message.error('创建导出任务失败');
+ } catch (e) {
+ // 优先展示后端返回的 message(如「缺少权限: energy:export」)
+ Message.error(e instanceof Error && e.message ? e.message : '创建导出任务失败');
}
};
@@ -317,9 +319,12 @@ export default function Energy() {
} onClick={handleExport}>
- 导出报表
-
+ /* 导出报表需 energy:export(后端 /energy-stats/export 校验) */
+
+ } onClick={handleExport}>
+ 导出报表
+
+
}>
{
fetchData();
}, [fetchData]);
+ /**
+ * 查询按钮
+ * 过滤条件变化后需回到第 1 页;`page` 已变更时交给 `useEffect` 统一发请求,
+ * 否则直接重查 —— 避免「先 setPage(1) 又用旧 page 发请求」
+ */
const handleSearch = () => {
- setPage(1);
- fetchData();
+ if (page === 1) {
+ fetchData();
+ } else {
+ setPage(1);
+ }
};
const updateStatus = async (id: number, nextStatus: number) => {
diff --git a/software/web/src/pages/settings/operation-logs.tsx b/software/web/src/pages/settings/operation-logs.tsx
index ed48966..a57b798 100644
--- a/software/web/src/pages/settings/operation-logs.tsx
+++ b/software/web/src/pages/settings/operation-logs.tsx
@@ -91,10 +91,17 @@ export default function OperationLogsPage() {
fetchData();
}, [fetchData]);
- /** 查询 */
+ /**
+ * 查询
+ * 过滤条件变化后需回到第 1 页;`page` 已变更时交给 `useEffect` 统一发请求,
+ * 否则直接重查 —— 避免「先 setPage(1) 又用旧 page 发请求」
+ */
const handleSearch = () => {
- setPage(1);
- fetchData();
+ if (page === 1) {
+ fetchData();
+ } else {
+ setPage(1);
+ }
};
/** 重置 */
@@ -102,7 +109,9 @@ export default function OperationLogsPage() {
setUserId(undefined);
setAction('');
setTimeRange([]);
- setPage(1);
+ if (page !== 1) {
+ setPage(1);
+ }
};
/** 操作类型显示映射 */
diff --git a/software/web/src/utils/deviceStatus.ts b/software/web/src/utils/deviceStatus.ts
index 7755cff..845786a 100644
--- a/software/web/src/utils/deviceStatus.ts
+++ b/software/web/src/utils/deviceStatus.ts
@@ -98,3 +98,18 @@ export function normalizeFlag(value?: boolean | null): boolean | null {
export function isPowerFail(value?: boolean | null): boolean {
return normalizeFlag(value) === true;
}
+
+/**
+ * 温度格式化:协议统一按 **K×100** 存储(附 A:`29865` = 298.65K = 25.5°C)
+ *
+ * 用于柜温 / 仓温等实时温度字段;`null` / `undefined`(字段缺失或设备未上报)
+ * 返回占位符(默认 `-`),由调用方决定占位文案(如柜温用 `--°C`)。
+ *
+ * @param value 温度原始值(K×100)
+ * @param placeholder 无数据时的占位文案
+ */
+export function formatTempK100(value?: number | null, placeholder = '-'): string {
+ if (value === null || value === undefined) return placeholder;
+ const celsius = value / 100 - 273.15;
+ return `${celsius.toFixed(1)}°C`;
+}