refactor: streamline camera form handling and update types for better consistency

This commit is contained in:
2026-02-08 14:58:33 +07:00
parent d619534a73
commit 4af34eab3e
4 changed files with 38 additions and 84 deletions

View File

@@ -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} />

View File

@@ -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 : [],
}); });
}; };

View File

@@ -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}

View File

@@ -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[];
} }