Files
eacp_webapp/src/Data_Feed/Data_Feed.tsx
T
2026-06-16 11:24:50 +08:00

305 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import enhance from "../core/enhance.tsx";
import {Button, Checkbox, CheckboxChangeEvent, message, Select, Space, Switch, Tag, Typography} from "antd";
import {SettingOutlined} from "@ant-design/icons";
import axios from "axios";
import {baseURL, Prefix} from "../Global.tsx";
import React from "react";
import {Input_Port_Number, Input_String, Switch_Bool} from "../A_Global.tsx";
import { State_Shower } from "../State_Shower.tsx";
const {Option} = Select;
const { Text } = Typography;
class Output_Format {
type: string = "";
use_status: boolean = false;
mode_s_output_type: string = "";
use_mode_ac: boolean = false;
sbs_only_pos: boolean = false;
output(flush) {
return (<>
<Select
prefix={<Prefix label="包格式"/>}
defaultValue=""
value={this.type}
onChange={(value: string) => {
this.type = value;
flush();
}}
options={[
{value: 'BIN', label: 'BIN'},
{value: 'BIN_ID', label: 'BIN_ID'},
{value: 'AVR', label: 'AVR'},
{value: 'AVR_MLAT', label: 'AVR_MLAT'},
{value: 'SBS', label: 'SBS'},
]}
/>
{
(this.type == "BIN" || this.type == "BIN_ID") &&
<Checkbox checked={this.use_status} onChange={(e: CheckboxChangeEvent) => {
this.use_status = e.target.checked;
flush();
}}></Checkbox>
}
{
(this.type == "SBS") &&
<Checkbox checked={this.sbs_only_pos} onChange={(e: CheckboxChangeEvent) => {
this.sbs_only_pos = e.target.checked;
flush();
}}>SBS只输出带位置的飞机</Checkbox>
}
{
(this.type != "SBS") &&
<>
<Select
prefix={<Prefix label="Mode-S类型"/>}
defaultValue=""
style={{
width: '100%'
}}
value={this.mode_s_output_type}
onChange={(value: string) => {
this.mode_s_output_type = value;
flush();
}}
options={[
{value: 'ALL_Mode_S', label: '全部的mode_s'},
{value: 'DF_11_17_18', label: 'DF_11_17_18'},
{value: 'NO_POS_Mode_S', label: '无位置的mode_s'},
]}
/>
<Checkbox checked={this.use_mode_ac} onChange={(e: CheckboxChangeEvent) => {
this.use_mode_ac = e.target.checked;
flush();
}}>Mode_AC</Checkbox>
</>
}
</>);
}
}
export class Data_Feed extends enhance.Base {
key: string = "未命名";
enable: boolean = false;
type: string = "";
output_format: Output_Format = new Output_Format();
state: State_Shower = new State_Shower(`${baseURL}/get_data_feed_state`, () => this.key);
onClick(that) {
}
center_with_add(): React.JSX.Element {
return <></>
}
center(): React.JSX.Element {
return <></>
}
render(props: any) {
return (
<div style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between", // 将子元素水平分散
alignItems: "center", // 子元素垂直居中
gap: "8px", // 设置元素之间的间距
width: "100%" // 确保容器宽度占满父容器
}}>
<Button type="dashed">
<Space size={6}>
<Tag color="blue" style={{ marginInlineEnd: 0 }}>{this.type}</Tag>
<Text type="secondary"></Text>
<Text>{this.key}</Text>
</Space>
</Button>
<Button
icon={<SettingOutlined/>}
onClick={() => {
this.onClick(this);
}}>
{"格式: " + this.output_format.type}
</Button>
{
this.center_with_add()
}
{
this.center()
}
<div style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
gap: "8px",
}}>
<this.state.x/>
<Switch_Bool that={this} field={"enable"}></Switch_Bool>
<Button type="primary" autoInsertSpace onClick={() => {
axios.post(`${baseURL}/update_data_feed`, this).then((res) => {
Object.assign(this, res.data);
});
message.success(`${this.type}类型,数据馈送源${this.key}设置成功!` );
}}>
</Button>
</div>
</div>
);
}
}
class Data_Feed_Server extends Data_Feed {
port: number = 0;
dataSource: any[] = [];
// 新增:轮询定时器
private pollTimer: number | null = null;
private pollIntervalMs = 1000;
private fetchConnections = async () => {
try {
// 你原来这里用 post 并把 this 作为 body,我保留这个行为
const res = await axios.post(`${baseURL}/get_data_feed_server_connect`, this);
this.dataSource = (res.data ?? []).map((item: any, index: number) => ({
...item,
key: String(index),
}));
this.flush();
} catch (e) {
// 可选:失败不打断轮询
// console.error(e);
}
};
private startPolling = () => {
if (this.pollTimer !== null) return; // 已经在轮询
void this.fetchConnections(); // 先立刻拉一次
this.pollTimer = window.setInterval(() => {
void this.fetchConnections();
}, this.pollIntervalMs);
};
private stopPolling = () => {
if (this.pollTimer === null) return;
window.clearInterval(this.pollTimer);
this.pollTimer = null;
};
refresh() {
// refresh 保持可用:手动刷新一次
void this.fetchConnections();
}
center(): React.JSX.Element {
return (
<>
<Select
prefix={<Prefix label="已连接客户端" />}
popupMatchSelectWidth={false}
placeholder="展示所有连接"
onChange={(value) => {
console.log("你选择了:", value);
}}
value={""}
onOpenChange={(open) => {
if (open) {
this.startPolling(); // 展开:1 秒刷新
} else {
this.stopPolling(); // 收起:停止刷新
}
}}
>
{this.dataSource.map((item: any) => (
<Option key={item.key} value={item.key}>
<div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
{Object.entries(item)
.filter(([k]) => k !== "key")
.map(([k, v]) => (
<div
key={k}
style={{
display: "flex",
alignItems: "flex-start",
gap: 8,
lineHeight: 1.4,
}}
>
<strong style={{ whiteSpace: "nowrap" }}>{k}</strong>
<span style={{ wordBreak: "break-all" }}>
{typeof v === "object" ? JSON.stringify(v) : String(v)}
</span>
</div>
))}
</div>
</Option>
))}
</Select>
</>
);
}
center_with_add(): React.JSX.Element {
return (
<>
<Input_Port_Number that={this} field={"port"} />
</>
);
}
// 可选:如果这个对象有生命周期/销毁点,记得调用,避免内存泄漏
destroy() {
this.stopPolling();
}
}
class Data_Feed_Client extends Data_Feed {
url: string = "";
port: number = 0;
center_with_add() {
return <>
<Input_String that={this} field={"url"} name="IP地址"/>
<Input_Port_Number that={this} field={"port"}/>
</>
}
}
export class Data_Feed_TCP_Server extends Data_Feed_Server {
}
export class Data_Feed_UDP_Server extends Data_Feed_Server {
}
export class Data_Feed_TCP_Client extends Data_Feed_Client {
}
export class Data_Feed_UDP_Client extends Data_Feed_Client {
}
export function create_data_feed_from_type(type: string) {
let ret: Data_Feed
if (type === "Data_Feed_TCP_Server") {
ret = new Data_Feed_TCP_Server();
}
if (type === "Data_Feed_TCP_Client") {
ret = new Data_Feed_TCP_Client();
}
if (type === "Data_Feed_UDP_Server") {
ret = new Data_Feed_UDP_Server();
}
if (type === "Data_Feed_UDP_Client") {
ret = new Data_Feed_UDP_Client();
}
return ret;
}