撤回 布局修改 任务点击的接口格式修改
This commit is contained in:
@@ -40,6 +40,9 @@ const CesiumMap = React.forwardRef(({ ifClear, ifClearPlanLine, ifClearNavLine,
|
||||
const polygonRef = useRef(null); // coverage 区域多边形
|
||||
const navLineRef = useRef(null); // 完成点实时轨迹
|
||||
const markedPointsRef = useRef([]); // 标记点实体
|
||||
const markedLineRef = useRef(null); // 标记点连线实体
|
||||
const onMarkPointRef = useRef(onMarkPoint); // 总是指向最新的 onMarkPoint,避免闭包滞后
|
||||
const onCameraClickRef = useRef(onCameraClick); // 同样处理,避免闭包滞后
|
||||
const { t } = useTranslation();
|
||||
|
||||
|
||||
@@ -474,19 +477,41 @@ const CesiumMap = React.forwardRef(({ ifClear, ifClearPlanLine, ifClearNavLine,
|
||||
}
|
||||
}, [points]);
|
||||
|
||||
// 渲染绿色标记点
|
||||
// 渲染标记点 + 连线(唯一系统,避免重复标记)
|
||||
const drawMarkedPoints = (points) => {
|
||||
const viewer = viewerRef.current;
|
||||
if (!viewer) return;
|
||||
|
||||
// 先清空之前的标记点
|
||||
// 先清空之前的标记点与连线
|
||||
markedPointsRef.current.forEach(id => {
|
||||
viewer.entities.removeById(id);
|
||||
});
|
||||
markedPointsRef.current = [];
|
||||
|
||||
if (markedLineRef.current) {
|
||||
try {
|
||||
viewer.entities.remove(markedLineRef.current);
|
||||
} catch (e) { }
|
||||
markedLineRef.current = null;
|
||||
}
|
||||
|
||||
if (!points || points.length === 0) return;
|
||||
|
||||
// 先绘制连线:有 2 个及以上打点才连线
|
||||
if (points.length >= 2) {
|
||||
const linePositions = points.map(p =>
|
||||
window.Cesium.Cartesian3.fromDegrees(Number(p.lon), Number(p.lat))
|
||||
);
|
||||
markedLineRef.current = viewer.entities.add({
|
||||
polyline: {
|
||||
positions: linePositions,
|
||||
width: 4,
|
||||
material: window.Cesium.Color.SKYBLUE,
|
||||
clampToGround: true,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
points.forEach((p, i) => {
|
||||
const id = `marked-point-${i}`;
|
||||
viewer.entities.add({
|
||||
@@ -1627,6 +1652,10 @@ const CesiumMap = React.forwardRef(({ ifClear, ifClearPlanLine, ifClearNavLine,
|
||||
};
|
||||
}, [points]);
|
||||
|
||||
// 每次渲染都更新回调引用,确保单击处理器用最新版本(避免闭包滞后)
|
||||
onMarkPointRef.current = onMarkPoint;
|
||||
onCameraClickRef.current = onCameraClick;
|
||||
|
||||
useEffect(() => {
|
||||
const viewer = viewerRef.current;
|
||||
if (!viewer) return;
|
||||
@@ -1650,7 +1679,7 @@ const CesiumMap = React.forwardRef(({ ifClear, ifClearPlanLine, ifClearNavLine,
|
||||
const picked = viewer.scene.pick(movement.position);
|
||||
if (window.Cesium.defined(picked) && picked.id?.properties?.robot) {
|
||||
const robot = picked.id.properties.robot.getValue();
|
||||
robot.feStatus == 1 && onCameraClick?.(robot);
|
||||
robot.feStatus == 1 && onCameraClickRef.current?.(robot);
|
||||
}
|
||||
}, window.Cesium.ScreenSpaceEventType.LEFT_CLICK);
|
||||
|
||||
@@ -1663,10 +1692,7 @@ const CesiumMap = React.forwardRef(({ ifClear, ifClearPlanLine, ifClearNavLine,
|
||||
const lon = window.Cesium.Math.toDegrees(cartographic.longitude);
|
||||
const lat = window.Cesium.Math.toDegrees(cartographic.latitude);
|
||||
const newPoint = { lon, lat };
|
||||
const newPoints = [...drawPoints, newPoint];
|
||||
setDrawPoints(newPoints);
|
||||
updateDrawPath(newPoints);
|
||||
onMarkPoint?.({ lon, lat });
|
||||
onMarkPointRef.current?.({ lon, lat });
|
||||
}, window.Cesium.ScreenSpaceEventType.LEFT_CLICK);
|
||||
|
||||
if (onClearDraw) {
|
||||
|
||||
@@ -680,6 +680,17 @@ export default function DeviceStatusPage() {
|
||||
messageApi.success(t('devices.pointMarked', { count: markedPoints.length + 1 }));
|
||||
};
|
||||
|
||||
// 撤回上一个打点
|
||||
const handleUndoMark = () => {
|
||||
if (markedPoints.length === 0) {
|
||||
message.info(t('devices.noPointsToUndo'));
|
||||
return;
|
||||
}
|
||||
const newPoints = markedPoints.slice(0, -1);
|
||||
setMarkedPoints(newPoints);
|
||||
messageApi.success(t('devices.pointUndone', { count: newPoints.length }));
|
||||
};
|
||||
|
||||
// 清空标记点
|
||||
const handleClearPoints = () => {
|
||||
setMarkedPoints([]);
|
||||
@@ -924,6 +935,13 @@ export default function DeviceStatusPage() {
|
||||
>
|
||||
{t('devices.markPoint')}
|
||||
</Button>
|
||||
<Button
|
||||
type="default"
|
||||
onClick={handleUndoMark}
|
||||
disabled={markedPoints?.length === 0}
|
||||
>
|
||||
{t('devices.undoMark')}
|
||||
</Button>
|
||||
<Button
|
||||
type="default"
|
||||
onClick={handleClearPoints}
|
||||
|
||||
@@ -25,7 +25,7 @@ import {
|
||||
import {
|
||||
getRobotRouteList,
|
||||
getSingleRouteList,
|
||||
getPlaneDeviceListAll, saveDeviceTask, getRobotTaskList,
|
||||
saveDeviceTask, getRobotTaskList,
|
||||
deleteDeviceTask,
|
||||
getSiteDevice,
|
||||
excuetRoute,
|
||||
@@ -184,15 +184,17 @@ export default function RobotTaskPage() {
|
||||
if (!taskId) return;
|
||||
try {
|
||||
const res = await getRouteByTask({ taskId });
|
||||
if (res?.code === 200 && res?.data) {
|
||||
if (res?.code === 200 && res?.data?.jsonData?.path) {
|
||||
let pathPoints = [];
|
||||
try {
|
||||
const data = res.data;
|
||||
pathPoints = data || [];
|
||||
pathPoints = data.jsonData.path || [];
|
||||
setRouteMode(data?.mode || 'coverage'); // 设置路线模式
|
||||
|
||||
|
||||
} catch (err) {
|
||||
console.error('解析任务路径数据失败:', err);
|
||||
}
|
||||
setRouteMode('coverage')
|
||||
setPolyPoints(pathPoints);
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -567,30 +569,6 @@ export default function RobotTaskPage() {
|
||||
|
||||
setExecuteModalVisible(true);
|
||||
setSelectedRobotForExecute(null);
|
||||
|
||||
// 调用接口检查是否有路径点
|
||||
const res = await getSingleRouteList({ id: route?.id });
|
||||
let hasPathPoints = false;
|
||||
|
||||
if (res?.code === 200 && res?.data) {
|
||||
try {
|
||||
if (res.data.jsonData) {
|
||||
const data = typeof res.data.jsonData === 'string'
|
||||
? JSON.parse(res.data.jsonData)
|
||||
: res.data.jsonData;
|
||||
hasPathPoints = data?.path && data.path.length > 0;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('解析路线数据失败:', err);
|
||||
}
|
||||
}
|
||||
|
||||
//if (!hasPathPoints) {
|
||||
// utils.message.warning(t('devices.routeExecuteFixed2'));
|
||||
// return;
|
||||
//}
|
||||
|
||||
|
||||
} catch (err) {
|
||||
console.error('检查路线失败:', err);
|
||||
utils.message.error(t('devices.checkRouteFail'));
|
||||
@@ -1219,7 +1197,7 @@ export default function RobotTaskPage() {
|
||||
extra={
|
||||
<Space size={4} wrap> {/* Space开启自动换行,小屏按钮自动折行 */}
|
||||
<Button size="small" icon={<DeleteOutlined />} type="primary" style={{ borderRadius: 4 }} onClick={() => setClearNavLine(v => v + 1)}>{t('devices.clearRealtimeTrack')}</Button>
|
||||
<Button size="small" icon={<DeleteOutlined />} danger style={{ borderRadius: 4 }} onClick={() => { setPoints([]); setRouteMode(""); setClearPlanLine(v => v + 1); }}>{t('devices.clearPlanRoute')}</Button>
|
||||
<Button size="small" icon={<DeleteOutlined />} danger style={{ borderRadius: 4 }} onClick={() => { setPoints([]); setPolyPoints([]); setRouteMode(""); setClearPlanLine(v => v + 1); }}>{t('devices.clearPlanRoute')}</Button>
|
||||
{/*<Button size="small" icon={<PlusOutlined />} style={{ borderRadius: 4 }}>{t('common.addNew')}</Button>
|
||||
<Button size="small" icon={<ImportOutlined />} style={{ borderRadius: 4 }}>{t('common.import')}</Button>
|
||||
<Button size="small" icon={<NodeIndexOutlined />} style={{ borderRadius: 4 }}>{t('devices.optimize')}</Button>
|
||||
@@ -1283,28 +1261,9 @@ export default function RobotTaskPage() {
|
||||
<span style={{ color: '#9eff9e' }}>{t('devices.remoteMode')}</span>
|
||||
)}
|
||||
</span>
|
||||
{/* const fixStatusMap: Record<string, string> = {
|
||||
'no_fix': t('devices.noFix'),
|
||||
'single': t('devices.single'),
|
||||
'dgnss': t('devices.dgnss'),
|
||||
'ins': t('devices.ins'),
|
||||
'rtk_fixed': t('devices.rtkFixed'),
|
||||
'rtk_float': t('devices.rtkFloat'),
|
||||
'single_no_heading': t('devices.singleNoHeading'),
|
||||
'dgnss_no_heading': t('devices.dgnssNoHeading'),
|
||||
'rtk_fixed_no_heading': t('devices.rtkFixedNoHeading'),
|
||||
'rtk_float_no_heading': t('devices.rtkFloatNoHeading'),
|
||||
}
|
||||
*/}
|
||||
|
||||
<span>
|
||||
{t('devices.heading')}
|
||||
{robotRealtimePosition?.headingStatus == '1' ? (
|
||||
<span style={{ color: '#9eff9e' }}>{t('devices.initialized')}</span>
|
||||
) : (
|
||||
<span style={{ color: '#ff6f6f' }}>{t('devices.uninitialized')}</span>
|
||||
)}
|
||||
</span>
|
||||
|
||||
|
||||
|
||||
<span>
|
||||
{t('devices.location')}
|
||||
@@ -1559,94 +1518,7 @@ export default function RobotTaskPage() {
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
<Col xs={24} xl={10} style={{ display: "flex", flexDirection: "column" }} >
|
||||
<Card
|
||||
title={<span style={{ fontSize: fontTitle, fontWeight: 700 }}>{t('devices.operationSuggestion')}</span>}
|
||||
variant="borderless"
|
||||
styles={{ body: { padding: '12px 16px' } }}
|
||||
style={{ ...cardStyle, marginBottom: 8 }}
|
||||
>
|
||||
<Timeline
|
||||
mode="left"
|
||||
items={[
|
||||
{
|
||||
color: 'green',
|
||||
label: '09:30',
|
||||
children: (
|
||||
<>
|
||||
<Text strong>{t('devices.timelineMow', { robot: 'RBT-01' })}</Text>
|
||||
<div style={{ fontSize: 12, color: '#86909C' }}>{t('devices.timelineMowDetail')}</div>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
color: 'blue',
|
||||
label: '11:00',
|
||||
children: (
|
||||
<>
|
||||
<Text strong>{t('devices.timelineInspect', { robot: 'RBT-02' })}</Text>
|
||||
<div style={{ fontSize: 12, color: '#86909C' }}>{t('devices.timelineInspectDetail')}</div>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
color: 'gray',
|
||||
label: '14:00',
|
||||
children: (
|
||||
<>
|
||||
<Text strong>{t('devices.timelineMaintenance')}</Text>
|
||||
<div style={{ fontSize: 12, color: '#86909C' }}>{t('devices.timelineMaintenanceDetail')}</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
]}
|
||||
/>
|
||||
<Button type="primary" block style={{ marginTop: 16, borderRadius: 18 }}>{t('devices.autoGenerateTodayPlan')}</Button>
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title={<span style={{ fontSize: fontTitle, fontWeight: 700 }}>{t('devices.deviceEnvironment')}</span>}
|
||||
variant="borderless"
|
||||
styles={{ body: { padding: '16px' } }}
|
||||
style={{ ...cardStyle, flex: 1 }}
|
||||
>
|
||||
<Row gutter={[8, 8]}>
|
||||
<Col span={12}>
|
||||
<div style={{ background: '#F7F8FA', padding: 12, borderRadius: 10 }}>
|
||||
<div style={{ fontSize: 12, color: '#86909C' }}>{t('devices.currentTemp')}</div>
|
||||
<div style={{ fontSize: 18, fontWeight: 700 }}>24.5 ℃</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<div style={{ background: '#F7F8FA', padding: 12, borderRadius: 10 }}>
|
||||
<div style={{ fontSize: 12, color: '#86909C' }}>{t('devices.humidity')}</div>
|
||||
<div style={{ fontSize: 18, fontWeight: 700 }}>65 %</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<div style={{ background: '#F7F8FA', padding: 12, borderRadius: 10 }}>
|
||||
<div style={{ fontSize: 12, color: '#86909C' }}>{t('devices.positionAccuracy')}</div>
|
||||
<div style={{ fontSize: 18, fontWeight: 700, color: '#00B42A' }}>{t('devices.rtkFixed')}</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<div style={{ background: '#F7F8FA', padding: 12, borderRadius: 10 }}>
|
||||
<div style={{ fontSize: 12, color: '#86909C' }}>{t('devices.networkLatency')}</div>
|
||||
<div style={{ fontSize: 18, fontWeight: 700 }}>45 ms</div>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<div style={{ marginTop: 8, padding: 12, background: 'rgba(255, 125, 0, 0.1)', borderRadius: 8, display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<AlertCircle size={16} style={{ color: '#FF7D00' }} />
|
||||
<span style={{ fontSize: 13, color: '#FF7D00' }}>{t('devices.waterRiskWarning')}</span>
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row gutter={16}>
|
||||
<Col xs={24} xl={6}>
|
||||
<Col xs={24} xl={10}>
|
||||
<Card
|
||||
title={
|
||||
<div className="flex justify-between items-center w-full">
|
||||
@@ -1661,7 +1533,7 @@ export default function RobotTaskPage() {
|
||||
</div>
|
||||
}
|
||||
variant="borderless"
|
||||
styles={{ body: { padding: '12px', height: 400, overflow: 'auto' } }}
|
||||
styles={{ body: { padding: '12px', height: 732, overflow: 'auto' } }}
|
||||
style={cardStyle}
|
||||
>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
|
||||
@@ -1789,16 +1661,105 @@ export default function RobotTaskPage() {
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={24} xl={18}>
|
||||
|
||||
|
||||
</Row>
|
||||
|
||||
<Row gutter={16} >
|
||||
<Col xs={24} xl={6} style={{ display: "flex", flexDirection: "column" }} >
|
||||
<Card
|
||||
title={<span style={{ fontSize: fontTitle, fontWeight: 700 }}>{t('devices.operationSuggestion')}</span>}
|
||||
variant="borderless"
|
||||
styles={{ body: { padding: '12px 16px' } }}
|
||||
style={{ ...cardStyle, marginBottom: 8 }}
|
||||
>
|
||||
<Timeline
|
||||
mode="left"
|
||||
items={[
|
||||
{
|
||||
color: 'green',
|
||||
label: '09:30',
|
||||
children: (
|
||||
<>
|
||||
<Text strong>{t('devices.timelineMow', { robot: 'RBT-01' })}</Text>
|
||||
<div style={{ fontSize: 12, color: '#86909C' }}>{t('devices.timelineMowDetail')}</div>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
color: 'blue',
|
||||
label: '11:00',
|
||||
children: (
|
||||
<>
|
||||
<Text strong>{t('devices.timelineInspect', { robot: 'RBT-02' })}</Text>
|
||||
<div style={{ fontSize: 12, color: '#86909C' }}>{t('devices.timelineInspectDetail')}</div>
|
||||
</>
|
||||
)
|
||||
},
|
||||
{
|
||||
color: 'gray',
|
||||
label: '14:00',
|
||||
children: (
|
||||
<>
|
||||
<Text strong>{t('devices.timelineMaintenance')}</Text>
|
||||
<div style={{ fontSize: 12, color: '#86909C' }}>{t('devices.timelineMaintenanceDetail')}</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
]}
|
||||
/>
|
||||
<Button type="primary" block style={{ marginTop: 16, borderRadius: 18 }}>{t('devices.autoGenerateTodayPlan')}</Button>
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
title={<span style={{ fontSize: fontTitle, fontWeight: 700 }}>{t('devices.deviceEnvironment')}</span>}
|
||||
variant="borderless"
|
||||
styles={{ body: { padding: '16px' } }}
|
||||
style={{ ...cardStyle, flex: 1 }}
|
||||
>
|
||||
<Row gutter={[8, 8]}>
|
||||
<Col span={12}>
|
||||
<div style={{ background: '#F7F8FA', padding: 12, borderRadius: 10 }}>
|
||||
<div style={{ fontSize: 12, color: '#86909C' }}>{t('devices.currentTemp')}</div>
|
||||
<div style={{ fontSize: 18, fontWeight: 700 }}>24.5 ℃</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<div style={{ background: '#F7F8FA', padding: 12, borderRadius: 10 }}>
|
||||
<div style={{ fontSize: 12, color: '#86909C' }}>{t('devices.humidity')}</div>
|
||||
<div style={{ fontSize: 18, fontWeight: 700 }}>65 %</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<div style={{ background: '#F7F8FA', padding: 12, borderRadius: 10 }}>
|
||||
<div style={{ fontSize: 12, color: '#86909C' }}>{t('devices.positionAccuracy')}</div>
|
||||
<div style={{ fontSize: 18, fontWeight: 700, color: '#00B42A' }}>{t('devices.rtkFixed')}</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<div style={{ background: '#F7F8FA', padding: 12, borderRadius: 10 }}>
|
||||
<div style={{ fontSize: 12, color: '#86909C' }}>{t('devices.networkLatency')}</div>
|
||||
<div style={{ fontSize: 18, fontWeight: 700 }}>45 ms</div>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<div style={{ marginTop: 8, padding: 12, background: 'rgba(255, 125, 0, 0.1)', borderRadius: 8, display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<AlertCircle size={16} style={{ color: '#FF7D00' }} />
|
||||
<span style={{ fontSize: 13, color: '#FF7D00' }}>{t('devices.waterRiskWarning')}</span>
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
<Col xs={24} xl={18} style={{ display: 'flex', flexDirection: 'column', }}>
|
||||
<Card
|
||||
title={<span style={{ fontSize: fontTitle, fontWeight: 700 }}>{t('devices.taskBoard')}</span>}
|
||||
variant="borderless"
|
||||
styles={{ body: { padding: '12px' } }}
|
||||
style={{ ...cardStyle, height: '100%' }}
|
||||
styles={{ body: { padding: '12px', flex: 1 } }}
|
||||
style={{ ...cardStyle, height: '100%', display: "flex", flexDirection: "column" }}
|
||||
>
|
||||
<Row gutter={16}>
|
||||
<Row gutter={16} style={{ height: "100%" }} >
|
||||
<Col span={8}>
|
||||
<div style={{ background: '#F7F8FA', padding: 12, borderRadius: 8, height: 400 }}>
|
||||
<div style={{ background: '#F7F8FA', padding: 12, borderRadius: 8, height: "100%" }}>
|
||||
<Title level={5} style={{ fontSize: 14, marginBottom: 12 }}><Badge color="#86909C" text={t('devices.pending')} /></Title>
|
||||
{waitList.map((item, idx) => (
|
||||
<Card key={idx} size="small" style={{ marginBottom: 8, borderRadius: 6 }}>
|
||||
@@ -1809,7 +1770,7 @@ export default function RobotTaskPage() {
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<div style={{ background: '#E8F3FF', padding: 12, borderRadius: 8, height: 400 }}>
|
||||
<div style={{ background: '#E8F3FF', padding: 12, borderRadius: 8, height: "100%" }}>
|
||||
<Title level={5} style={{ fontSize: 14, marginBottom: 12 }}><Badge color="#165DFF" text={t('devices.statInProgress')} /></Title>
|
||||
{runList.map((item, idx) => (
|
||||
<Card key={idx} size="small" style={{ marginBottom: 8, borderRadius: 6 }}>
|
||||
@@ -1822,7 +1783,7 @@ export default function RobotTaskPage() {
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<div style={{ background: '#F6FFED', padding: 12, borderRadius: 8, height: 400 }}>
|
||||
<div style={{ background: '#F6FFED', padding: 12, borderRadius: 8, height: "100%" }}>
|
||||
<Title level={5} style={{ fontSize: 14, marginBottom: 12 }}><Badge color="#52C41A" text={t('workOrder.completed')} /></Title>
|
||||
{finishList.slice(0, 3).map((item, idx) => (
|
||||
<Card key={idx} size="small" style={{ marginBottom: 8, borderRadius: 6 }}>
|
||||
|
||||
@@ -609,6 +609,9 @@ const en = {
|
||||
lostControlAction: 'Lost Control Action',
|
||||
lostControlActionLabel: 'Lost Control Action Label',
|
||||
markPoint: 'Mark Point',
|
||||
undoMark: 'Undo Mark',
|
||||
noPointsToUndo: 'No points to undo',
|
||||
pointUndone: 'Undone, {{count}} points left',
|
||||
markedPointsCount: 'Marked Points Count',
|
||||
minBattery: 'Min Battery',
|
||||
minBatteryLabel: 'Min Battery Label',
|
||||
|
||||
@@ -631,6 +631,9 @@ const zh = {
|
||||
lostControlAction: '丢失控制操作',
|
||||
lostControlActionLabel: '丢失控制操作标签',
|
||||
markPoint: '打点',
|
||||
undoMark: '撤回打点',
|
||||
noPointsToUndo: '暂无打点可撤回',
|
||||
pointUndone: '已撤回,剩余 {{count}} 个打点',
|
||||
markedPointsCount: '已标记点数量',
|
||||
minBattery: '最小电量',
|
||||
minBatteryLabel: '最小电量标签',
|
||||
|
||||
Reference in New Issue
Block a user