373 lines
9.7 KiB
JavaScript
373 lines
9.7 KiB
JavaScript
import { ArrowLeftOutlined, ArrowRightOutlined } from "@ant-design/icons";
|
|
import {
|
|
Button,
|
|
Card,
|
|
Col,
|
|
ConfigProvider,
|
|
Divider,
|
|
Form,
|
|
Grid,
|
|
InputNumber,
|
|
Progress,
|
|
Row,
|
|
Select,
|
|
Slider,
|
|
Space,
|
|
} from "antd";
|
|
import { useForm } from "antd/es/form/Form";
|
|
import useMessage from "antd/es/message/useMessage";
|
|
import { useEffect, useRef, useState } from "react";
|
|
import { myFetch } from "./utils";
|
|
|
|
const { useBreakpoint } = Grid;
|
|
|
|
const Constants = {
|
|
DISTANCE: {
|
|
MIN: 0,
|
|
MAX: 100,
|
|
},
|
|
ACCELERATION: {
|
|
MIN: 0,
|
|
MAX: 100,
|
|
},
|
|
DURATION: {
|
|
MIN: 1,
|
|
MAX: 60,
|
|
},
|
|
};
|
|
|
|
function App() {
|
|
const screens = useBreakpoint();
|
|
const [form] = useForm();
|
|
const [messageApi, messageContextHolder] = useMessage();
|
|
|
|
const [distance, setDistance] = useState([20, 50]);
|
|
const [acceleration, setAcceleration] = useState(0);
|
|
const [direction, setDirection] = useState(0);
|
|
const [durationUnit, setDurationUnit] = useState("seconds");
|
|
|
|
const remainingTimeRef = useRef(0);
|
|
const [remainingTime, setRemainingTime] = useState(0);
|
|
const [procesStatus, setProcessStatus] = useState("");
|
|
|
|
const intervalRef = useRef(null);
|
|
|
|
const setRemainingTimeProgress = (time) => {
|
|
remainingTimeRef.current = time;
|
|
setRemainingTime(time);
|
|
};
|
|
|
|
const showErrorMessage = () => {
|
|
messageApi.error({
|
|
type: "error",
|
|
content: "Ein Fehler ist aufgetreten",
|
|
});
|
|
};
|
|
|
|
useEffect(() => {
|
|
myFetch({
|
|
url: "/status",
|
|
method: "GET",
|
|
showNotification: messageApi,
|
|
})
|
|
.then((response) => {
|
|
console.log(response);
|
|
|
|
setRemainingTimeProgress(response.runningUntil);
|
|
setProcessStatus(response.status);
|
|
})
|
|
.catch((error) => {
|
|
console.error(error);
|
|
showErrorMessage();
|
|
});
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
intervalRef.current = setInterval(() => {
|
|
if (remainingTimeRef.current <= 0) {
|
|
clearInterval(intervalRef.current);
|
|
return;
|
|
}
|
|
|
|
setRemainingTime((prev) => {
|
|
const newTime = prev - 1000;
|
|
|
|
if (newTime <= 0) {
|
|
remainingTimeRef.current = 0;
|
|
clearInterval(intervalRef.current);
|
|
}
|
|
|
|
return newTime;
|
|
});
|
|
}, 1000);
|
|
|
|
return () => {
|
|
clearInterval(intervalRef.current);
|
|
};
|
|
}, [remainingTimeRef.current]);
|
|
|
|
const sendControlRequest = (urlPath) => {
|
|
form
|
|
.validateFields()
|
|
.then((values) => {
|
|
myFetch({
|
|
url: urlPath,
|
|
method: "POST",
|
|
body: {
|
|
distance: distance,
|
|
acceleration: acceleration,
|
|
direction: direction,
|
|
duration: values.duration * (durationUnit === "seconds" ? 1 : 60),
|
|
},
|
|
showNotification: messageApi,
|
|
})
|
|
.then((response) => {
|
|
console.log(response);
|
|
|
|
setRemainingTimeProgress(response.runningUntil);
|
|
setProcessStatus(response.status);
|
|
})
|
|
.catch((error) => {
|
|
console.error(error);
|
|
showErrorMessage();
|
|
setProcessStatus("");
|
|
setRemainingTimeProgress(0);
|
|
});
|
|
})
|
|
.catch((err) => console.error(err));
|
|
};
|
|
|
|
return (
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
alignItems: "center",
|
|
overflow: "auto",
|
|
marginTop: 60,
|
|
marginBottom: 60,
|
|
}}
|
|
>
|
|
{messageContextHolder}
|
|
|
|
<Card
|
|
title="Kamera Slider"
|
|
style={{
|
|
width: "90%",
|
|
maxWidth: 800,
|
|
}}
|
|
>
|
|
<Form
|
|
form={form}
|
|
layout="vertical"
|
|
onFinish={() => sendControlRequest("/start")}
|
|
>
|
|
<Form.Item
|
|
label={`Status${procesStatus !== "" ? `: ${procesStatus}` : ""}`}
|
|
>
|
|
<Progress
|
|
percent={
|
|
100 -
|
|
Math.round((remainingTime / remainingTimeRef.current) * 100)
|
|
}
|
|
type="line"
|
|
status="active"
|
|
strokeColor={{
|
|
from: "#108ee9",
|
|
to: "#87d068",
|
|
}}
|
|
/>
|
|
</Form.Item>
|
|
|
|
<Divider />
|
|
|
|
<Form.Item label="Distanz">
|
|
<Row>
|
|
<Col xs={24} md={4}>
|
|
<InputNumber
|
|
min={Constants.DISTANCE.MIN}
|
|
max={Constants.DISTANCE.MAX}
|
|
value={distance[0]}
|
|
step={1}
|
|
onChange={(value) =>
|
|
setDistance((newDistance) => {
|
|
const newData = [...newDistance];
|
|
|
|
newData[0] = value;
|
|
|
|
return newData;
|
|
})
|
|
}
|
|
/>
|
|
</Col>
|
|
|
|
<Col xs={24} md={16}>
|
|
<Slider
|
|
range
|
|
defaultValue={[20, 50]}
|
|
marks={{ 0: "0", 100: "100" }}
|
|
min={Constants.DISTANCE.MIN}
|
|
max={Constants.DISTANCE.MAX}
|
|
value={distance}
|
|
onChange={(values) => setDistance(values)}
|
|
/>
|
|
</Col>
|
|
|
|
<Col xs={24} md={4}>
|
|
<InputNumber
|
|
min={Constants.DISTANCE.MIN}
|
|
max={Constants.DISTANCE.MAX}
|
|
style={{
|
|
margin: screens.md ? "0 26px" : "",
|
|
}}
|
|
value={distance[1]}
|
|
step={1}
|
|
onChange={(value) =>
|
|
setDistance((newDistance) => {
|
|
const newData = [...newDistance];
|
|
|
|
newData[1] = value;
|
|
|
|
return newData;
|
|
})
|
|
}
|
|
/>
|
|
</Col>
|
|
</Row>
|
|
</Form.Item>
|
|
|
|
<Form.Item name="duration" label="Dauer" initialValue={5}>
|
|
<InputNumber
|
|
step={1}
|
|
min={Constants.DURATION.MIN}
|
|
max={Constants.DURATION.MAX}
|
|
addonAfter={
|
|
<Select
|
|
style={{
|
|
width: 120,
|
|
}}
|
|
value={durationUnit}
|
|
onChange={(value) => setDurationUnit(value)}
|
|
>
|
|
<Select.Option value="seconds">Sekunden</Select.Option>
|
|
<Select.Option value="minutes">Minuten</Select.Option>
|
|
</Select>
|
|
}
|
|
/>
|
|
</Form.Item>
|
|
|
|
<Form.Item label="Beschleunigung">
|
|
<Row>
|
|
<Col xs={24} md={20}>
|
|
<Slider
|
|
defaultValue={20}
|
|
marks={{ 0: "0", 100: "100" }}
|
|
min={Constants.ACCELERATION.MIN}
|
|
max={Constants.ACCELERATION.MAX}
|
|
value={acceleration}
|
|
onChange={(value) => setAcceleration(value)}
|
|
/>
|
|
</Col>
|
|
|
|
<Col xs={24} md={4}>
|
|
<InputNumber
|
|
min={Constants.ACCELERATION.MIN}
|
|
max={Constants.ACCELERATION.MAX}
|
|
style={{
|
|
margin: screens.md ? "0 26px" : "",
|
|
}}
|
|
value={acceleration}
|
|
onChange={(value) => setAcceleration(value)}
|
|
/>
|
|
</Col>
|
|
</Row>
|
|
</Form.Item>
|
|
|
|
<Form.Item label="Richtung">
|
|
<Space>
|
|
<Button
|
|
type={direction === 0 ? "primary" : "default"}
|
|
shape="round"
|
|
icon={<ArrowLeftOutlined />}
|
|
onClick={() => setDirection(0)}
|
|
>
|
|
Links
|
|
</Button>
|
|
|
|
<Button
|
|
type={direction === 1 ? "primary" : "default"}
|
|
shape="round"
|
|
icon={<ArrowRightOutlined />}
|
|
iconPosition="end"
|
|
onClick={() => setDirection(1)}
|
|
>
|
|
Rechts
|
|
</Button>
|
|
</Space>
|
|
</Form.Item>
|
|
|
|
<Form.Item>
|
|
<Row gutter={[16, 16]}>
|
|
<Col span={12}>
|
|
<Button
|
|
type="primary"
|
|
block
|
|
danger
|
|
onClick={() => {
|
|
myFetch({
|
|
url: "/stop",
|
|
method: "POST",
|
|
showNotification: messageApi,
|
|
})
|
|
.then((response) => {
|
|
console.log(response);
|
|
|
|
setRemainingTimeProgress(0);
|
|
setProcessStatus("Angehalten");
|
|
})
|
|
.catch((error) => {
|
|
console.error(error);
|
|
showErrorMessage();
|
|
setProcessStatus("");
|
|
|
|
setRemainingTimeProgress(0);
|
|
});
|
|
}}
|
|
>
|
|
Stop
|
|
</Button>
|
|
</Col>
|
|
|
|
<Col span={12}>
|
|
<ConfigProvider
|
|
theme={{
|
|
token: {
|
|
colorPrimary: "#27ae60",
|
|
},
|
|
}}
|
|
>
|
|
<Button type="primary" htmlType="submit" block>
|
|
Start
|
|
</Button>
|
|
</ConfigProvider>
|
|
</Col>
|
|
</Row>
|
|
</Form.Item>
|
|
</Form>
|
|
|
|
<Divider />
|
|
|
|
<Button
|
|
type="primary"
|
|
block
|
|
onClick={() => sendControlRequest("/moveNextPoint")}
|
|
>
|
|
Fahre zum nächsten Punkt
|
|
</Button>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default App;
|