refactor: streamline camera form handling and update types for better consistency
This commit is contained in:
@@ -17,18 +17,6 @@ const CAMERA_TYPES = [
|
|||||||
{ label: 'GENERIC', value: 'GENERIC' },
|
{ label: 'GENERIC', value: 'GENERIC' },
|
||||||
];
|
];
|
||||||
|
|
||||||
interface CameraFormValues {
|
|
||||||
name: string;
|
|
||||||
type: string;
|
|
||||||
account: string;
|
|
||||||
password: string;
|
|
||||||
ipAddress: string;
|
|
||||||
rtspPort: number;
|
|
||||||
httpPort: number;
|
|
||||||
stream: number;
|
|
||||||
channel: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface CameraFormModalProps {
|
interface CameraFormModalProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
@@ -44,22 +32,17 @@ const CameraFormModal: React.FC<CameraFormModalProps> = ({
|
|||||||
isOnline = true,
|
isOnline = true,
|
||||||
editingCamera,
|
editingCamera,
|
||||||
}) => {
|
}) => {
|
||||||
const [form] = Form.useForm<CameraFormValues>();
|
const [form] = Form.useForm<MasterModel.Camera>();
|
||||||
const isEditMode = !!editingCamera;
|
const isEditMode = !!editingCamera;
|
||||||
|
|
||||||
// Populate form when editing
|
// Populate form when editing
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open && editingCamera) {
|
if (open && editingCamera) {
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
name: editingCamera.name || '',
|
...editingCamera,
|
||||||
type: editingCamera.cate_id || 'HIKVISION',
|
cate_id: editingCamera.cate_id || 'HIKVISION',
|
||||||
account: editingCamera.username || '',
|
rtsp_port: editingCamera.rtsp_port || 554,
|
||||||
password: editingCamera.password || '',
|
http_port: editingCamera.http_port || 80,
|
||||||
ipAddress: editingCamera.ip || '',
|
|
||||||
rtspPort: editingCamera.rtsp_port || 554,
|
|
||||||
httpPort: editingCamera.http_port || 80,
|
|
||||||
stream: editingCamera.stream || 0,
|
|
||||||
channel: editingCamera.channel || 0,
|
|
||||||
});
|
});
|
||||||
} else if (open) {
|
} else if (open) {
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
@@ -69,19 +52,12 @@ const CameraFormModal: React.FC<CameraFormModalProps> = ({
|
|||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
try {
|
try {
|
||||||
const values = await form.validateFields();
|
const values = await form.validateFields();
|
||||||
// Convert form values to MasterModel.Camera format
|
// Values already in MasterModel.Camera format
|
||||||
const camera: MasterModel.Camera = {
|
const camera: MasterModel.Camera = {
|
||||||
// Keep existing ID when editing, generate new ID when creating
|
...editingCamera,
|
||||||
|
...values,
|
||||||
|
// Ensure ID is set for new cameras
|
||||||
id: editingCamera?.id || `cam_${Date.now()}`,
|
id: editingCamera?.id || `cam_${Date.now()}`,
|
||||||
name: values.name,
|
|
||||||
cate_id: values.type,
|
|
||||||
ip: values.ipAddress,
|
|
||||||
rtsp_port: values.rtspPort,
|
|
||||||
http_port: values.httpPort,
|
|
||||||
stream: values.stream,
|
|
||||||
channel: values.channel,
|
|
||||||
username: values.account,
|
|
||||||
password: values.password,
|
|
||||||
};
|
};
|
||||||
onSubmit(camera);
|
onSubmit(camera);
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
@@ -114,9 +90,10 @@ const CameraFormModal: React.FC<CameraFormModalProps> = ({
|
|||||||
form={form}
|
form={form}
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
initialValues={{
|
initialValues={{
|
||||||
type: 'HIKVISION',
|
cate_id: 'HIKVISION',
|
||||||
rtspPort: 554,
|
ip: '192.168.1.10',
|
||||||
httpPort: 80,
|
rtsp_port: 554,
|
||||||
|
http_port: 80,
|
||||||
stream: 0,
|
stream: 0,
|
||||||
channel: 0,
|
channel: 0,
|
||||||
}}
|
}}
|
||||||
@@ -131,7 +108,7 @@ const CameraFormModal: React.FC<CameraFormModalProps> = ({
|
|||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="Loại"
|
label="Loại"
|
||||||
name="type"
|
name="cate_id"
|
||||||
rules={[{ required: true, message: 'Vui lòng chọn loại' }]}
|
rules={[{ required: true, message: 'Vui lòng chọn loại' }]}
|
||||||
>
|
>
|
||||||
<Select options={CAMERA_TYPES} />
|
<Select options={CAMERA_TYPES} />
|
||||||
@@ -139,7 +116,7 @@ const CameraFormModal: React.FC<CameraFormModalProps> = ({
|
|||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="Tài khoản"
|
label="Tài khoản"
|
||||||
name="account"
|
name="username"
|
||||||
rules={[{ required: true, message: 'Vui lòng nhập tài khoản' }]}
|
rules={[{ required: true, message: 'Vui lòng nhập tài khoản' }]}
|
||||||
>
|
>
|
||||||
<Input placeholder="nhập tài khoản" autoComplete="off" />
|
<Input placeholder="nhập tài khoản" autoComplete="off" />
|
||||||
@@ -158,7 +135,7 @@ const CameraFormModal: React.FC<CameraFormModalProps> = ({
|
|||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="Địa chỉ IP"
|
label="Địa chỉ IP"
|
||||||
name="ipAddress"
|
name="ip"
|
||||||
rules={[{ required: true, message: 'Vui lòng nhập địa chỉ IP' }]}
|
rules={[{ required: true, message: 'Vui lòng nhập địa chỉ IP' }]}
|
||||||
>
|
>
|
||||||
<Input placeholder="192.168.1.10" />
|
<Input placeholder="192.168.1.10" />
|
||||||
@@ -168,7 +145,7 @@ const CameraFormModal: React.FC<CameraFormModalProps> = ({
|
|||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="Cổng RTSP"
|
label="Cổng RTSP"
|
||||||
name="rtspPort"
|
name="rtsp_port"
|
||||||
rules={[{ required: true, message: 'Vui lòng nhập cổng RTSP' }]}
|
rules={[{ required: true, message: 'Vui lòng nhập cổng RTSP' }]}
|
||||||
>
|
>
|
||||||
<InputNumber style={{ width: '100%' }} min={0} max={65535} />
|
<InputNumber style={{ width: '100%' }} min={0} max={65535} />
|
||||||
@@ -177,7 +154,7 @@ const CameraFormModal: React.FC<CameraFormModalProps> = ({
|
|||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="Cổng HTTP"
|
label="Cổng HTTP"
|
||||||
name="httpPort"
|
name="http_port"
|
||||||
rules={[{ required: true, message: 'Vui lòng nhập cổng HTTP' }]}
|
rules={[{ required: true, message: 'Vui lòng nhập cổng HTTP' }]}
|
||||||
>
|
>
|
||||||
<InputNumber style={{ width: '100%' }} min={0} max={65535} />
|
<InputNumber style={{ width: '100%' }} min={0} max={65535} />
|
||||||
|
|||||||
@@ -24,10 +24,7 @@ const RECORDING_MODES = [
|
|||||||
interface CameraV6Props {
|
interface CameraV6Props {
|
||||||
thing: MasterModel.Thing | null;
|
thing: MasterModel.Thing | null;
|
||||||
cameraConfig?: MasterModel.CameraV6 | null;
|
cameraConfig?: MasterModel.CameraV6 | null;
|
||||||
onSubmit?: (config: {
|
onSubmit?: (config: MasterModel.CameraV6) => void;
|
||||||
recordingMode: MasterModel.CameraV6['record_type'];
|
|
||||||
selectedAlerts: string[];
|
|
||||||
}) => void;
|
|
||||||
isOnline?: boolean;
|
isOnline?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +38,7 @@ const CameraV6: React.FC<CameraV6Props> = ({
|
|||||||
const { initialState } = useModel('@@initialState');
|
const { initialState } = useModel('@@initialState');
|
||||||
const [selectedAlerts, setSelectedAlerts] = useState<string[]>([]);
|
const [selectedAlerts, setSelectedAlerts] = useState<string[]>([]);
|
||||||
const [recordingMode, setRecordingMode] =
|
const [recordingMode, setRecordingMode] =
|
||||||
useState<MasterModel.CameraV6['record_type']>('none');
|
useState<MasterModel.CameraRecordType>('none');
|
||||||
const [alarmConfig, setAlarmConfig] = useState<MasterModel.Alarm[] | null>(
|
const [alarmConfig, setAlarmConfig] = useState<MasterModel.Alarm[] | null>(
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
@@ -115,8 +112,9 @@ const CameraV6: React.FC<CameraV6Props> = ({
|
|||||||
|
|
||||||
const handleSubmitConfig = () => {
|
const handleSubmitConfig = () => {
|
||||||
onSubmit?.({
|
onSubmit?.({
|
||||||
recordingMode,
|
...cameraConfig,
|
||||||
selectedAlerts,
|
record_type: recordingMode,
|
||||||
|
record_alarm_list: recordingMode === 'alarm' ? selectedAlerts : [],
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ const CameraConfigPage = () => {
|
|||||||
const [cameraConfig, setCameraConfig] = useState<MasterModel.CameraV6 | null>(
|
const [cameraConfig, setCameraConfig] = useState<MasterModel.CameraV6 | null>(
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
const [mqttConnected, setMqttConnected] = useState(false);
|
|
||||||
const [isOnline, setIsOnline] = useState(false);
|
const [isOnline, setIsOnline] = useState(false);
|
||||||
const [editingCamera, setEditingCamera] = useState<MasterModel.Camera | null>(
|
const [editingCamera, setEditingCamera] = useState<MasterModel.Camera | null>(
|
||||||
null,
|
null,
|
||||||
@@ -43,18 +42,15 @@ const CameraConfigPage = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const unConnect = mqttClient.onConnect(() => {
|
const unConnect = mqttClient.onConnect(() => {
|
||||||
console.log('MQTT Connected successfully!');
|
// MQTT connected
|
||||||
setMqttConnected(true);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const unError = mqttClient.onError((error) => {
|
const unError = mqttClient.onError((error) => {
|
||||||
console.error('MQTT Error:', error);
|
console.error('MQTT Error:', error);
|
||||||
setMqttConnected(false);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const unClose = mqttClient.onClose(() => {
|
const unClose = mqttClient.onClose(() => {
|
||||||
console.log('MQTT Connection closed');
|
// MQTT connection closed
|
||||||
setMqttConnected(false);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
@@ -140,6 +136,11 @@ const CameraConfigPage = () => {
|
|||||||
|
|
||||||
// Core function to send camera config via MQTT
|
// Core function to send camera config via MQTT
|
||||||
const sendCameraConfig = (configPayload: MasterModel.CameraV6) => {
|
const sendCameraConfig = (configPayload: MasterModel.CameraV6) => {
|
||||||
|
// Skip sending for gmsv5
|
||||||
|
if (thing?.metadata?.type === 'gmsv5') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if device is online
|
// Check if device is online
|
||||||
if (!isOnline) {
|
if (!isOnline) {
|
||||||
message.error('Thiết bị đang ngoại tuyến, không thể gửi cấu hình');
|
message.error('Thiết bị đang ngoại tuyến, không thể gửi cấu hình');
|
||||||
@@ -230,44 +231,20 @@ const CameraConfigPage = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Handle recording config submission from ConfigCameraV6
|
// Handle recording config submission from ConfigCameraV6
|
||||||
const handleSubmitConfig = (configPayload: {
|
const handleSubmitConfig = (configPayload: MasterModel.CameraV6) => {
|
||||||
recordingMode: MasterModel.CameraV6['record_type'];
|
if (sendCameraConfig(configPayload)) {
|
||||||
selectedAlerts: string[];
|
|
||||||
}) => {
|
|
||||||
// Chỉ gửi record_alarm_list khi record_type = alarm
|
|
||||||
const fullConfig: MasterModel.CameraV6 = {
|
|
||||||
cams: cameraConfig?.cams || [],
|
|
||||||
record_type: configPayload.recordingMode,
|
|
||||||
...(configPayload.recordingMode === 'alarm' && {
|
|
||||||
record_alarm_list: configPayload.selectedAlerts,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (sendCameraConfig(fullConfig)) {
|
|
||||||
// Update local state
|
// Update local state
|
||||||
setCameraConfig(fullConfig);
|
setCameraConfig(configPayload);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper function to determine which camera component to render
|
// Helper function to determine which camera component to render
|
||||||
const renderCameraRecordingComponent = () => {
|
const renderCameraRecordingComponent = () => {
|
||||||
const thingType = thing?.metadata?.type;
|
if (thing?.metadata?.type === 'gmsv5') {
|
||||||
|
|
||||||
if (thingType === 'gmsv5') {
|
|
||||||
return <ConfigCameraV5 thing={thing} />;
|
return <ConfigCameraV5 thing={thing} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (thingType === 'spole' || thingType === 'gmsv6') {
|
// Default: gmsv6, spole, and other types
|
||||||
return (
|
|
||||||
<ConfigCameraV6
|
|
||||||
thing={thing}
|
|
||||||
cameraConfig={cameraConfig}
|
|
||||||
onSubmit={handleSubmitConfig}
|
|
||||||
isOnline={isOnline}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ConfigCameraV6
|
<ConfigCameraV6
|
||||||
thing={thing}
|
thing={thing}
|
||||||
|
|||||||
4
src/services/master/typings/camera.d.ts
vendored
4
src/services/master/typings/camera.d.ts
vendored
@@ -16,8 +16,10 @@ declare namespace MasterModel {
|
|||||||
cams?: Camera[];
|
cams?: Camera[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CameraRecordType = 'none' | 'alarm' | 'all';
|
||||||
|
|
||||||
interface CameraV6 extends CameraV5 {
|
interface CameraV6 extends CameraV5 {
|
||||||
record_type?: 'none' | 'alarm' | 'all';
|
record_type?: CameraRecordType;
|
||||||
record_alarm_list?: string[];
|
record_alarm_list?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user