From 9d211ed43cd1e4c20842e30dc1c85f1a4974350b Mon Sep 17 00:00:00 2001 From: MinhNN Date: Mon, 9 Feb 2026 21:55:56 +0700 Subject: [PATCH] feat: add camera configuration translations and enhance Camera components with internationalization support --- src/locales/en-US/master/master-thing-en.ts | 54 ++++++ src/locales/vi-VN/master/master-thing-vi.ts | 54 ++++++ .../Camera/components/CameraFormModal.tsx | 183 +++++++++++++++--- .../Device/Camera/components/CameraTable.tsx | 72 ++++++- .../Camera/components/ConfigCameraV5.tsx | 72 ++++--- .../Camera/components/ConfigCameraV6.tsx | 83 ++++++-- src/pages/Manager/Device/Camera/index.tsx | 51 ++++- 7 files changed, 489 insertions(+), 80 deletions(-) diff --git a/src/locales/en-US/master/master-thing-en.ts b/src/locales/en-US/master/master-thing-en.ts index 6d3fca8..3e1b13d 100644 --- a/src/locales/en-US/master/master-thing-en.ts +++ b/src/locales/en-US/master/master-thing-en.ts @@ -44,4 +44,58 @@ export default { 'master.devices.location.placeholder': 'Enter data', 'master.devices.location.update.success': 'Location updated successfully', 'master.devices.location.update.error': 'Location update failed', + + // Camera translations + 'master.camera.loading': 'Loading...', + 'master.camera.config.success': 'Configuration sent successfully', + 'master.camera.config.error.deviceOffline': + 'Device is offline, cannot send configuration', + 'master.camera.config.error.missingConfig': + 'Missing device configuration information', + 'master.camera.config.error.mqttNotConnected': 'MQTT not connected', + // Camera Form Modal + 'master.camera.form.title.add': 'Add New Camera', + 'master.camera.form.title.edit': 'Edit Camera', + 'master.camera.form.name': 'Name', + 'master.camera.form.name.placeholder': 'Enter name', + 'master.camera.form.name.required': 'Please enter name', + 'master.camera.form.type': 'Type', + 'master.camera.form.type.required': 'Please select type', + 'master.camera.form.username': 'Username', + 'master.camera.form.username.placeholder': 'Enter username', + 'master.camera.form.username.required': 'Please enter username', + 'master.camera.form.password': 'Password', + 'master.camera.form.password.placeholder': 'Enter password', + 'master.camera.form.password.required': 'Please enter password', + 'master.camera.form.ip': 'IP Address', + 'master.camera.form.ip.placeholder': '192.168.1.10', + 'master.camera.form.ip.required': 'Please enter IP address', + 'master.camera.form.rtspPort': 'RTSP Port', + 'master.camera.form.rtspPort.required': 'Please enter RTSP port', + 'master.camera.form.httpPort': 'HTTP Port', + 'master.camera.form.httpPort.required': 'Please enter HTTP port', + 'master.camera.form.stream': 'Stream', + 'master.camera.form.stream.required': 'Please enter stream', + 'master.camera.form.channel': 'Channel', + 'master.camera.form.channel.required': 'Please enter channel', + 'master.camera.form.cancel': 'Cancel', + 'master.camera.form.submit': 'OK', + 'master.camera.form.update': 'Update', + // Camera Table + 'master.camera.table.add': 'Add New Camera', + 'master.camera.table.column.name': 'Name', + 'master.camera.table.column.type': 'Type', + 'master.camera.table.column.ip': 'IP Address', + 'master.camera.table.column.action': 'Actions', + 'master.camera.table.offline.tooltip': 'Device is offline', + 'master.camera.table.pagination': 'Showing {0}-{1} of {2} cameras', + // Camera Config V6 + 'master.camera.config.recording': 'Camera Recording', + 'master.camera.config.send': 'Send', + 'master.camera.config.alarmList': 'Alarm List', + 'master.camera.config.selected': '{0} items selected', + 'master.camera.config.clear': 'Clear', + 'master.camera.config.recordingMode.none': 'No Recording', + 'master.camera.config.recordingMode.alarm': 'On Alarm', + 'master.camera.config.recordingMode.all': '24/7', }; diff --git a/src/locales/vi-VN/master/master-thing-vi.ts b/src/locales/vi-VN/master/master-thing-vi.ts index 61c7e53..5702103 100644 --- a/src/locales/vi-VN/master/master-thing-vi.ts +++ b/src/locales/vi-VN/master/master-thing-vi.ts @@ -44,4 +44,58 @@ export default { 'master.devices.location.placeholder': 'Nhập dữ liệu', 'master.devices.location.update.success': 'Cập nhật vị trí thành công', 'master.devices.location.update.error': 'Cập nhật vị trí thất bại', + + // Camera translations + 'master.camera.loading': 'Đang tải...', + 'master.camera.config.success': 'Đã gửi cấu hình thành công', + 'master.camera.config.error.deviceOffline': + 'Thiết bị đang ngoại tuyến, không thể gửi cấu hình', + 'master.camera.config.error.missingConfig': + 'Thiếu thông tin cấu hình thiết bị', + 'master.camera.config.error.mqttNotConnected': 'MQTT chưa kết nối', + // Camera Form Modal + 'master.camera.form.title.add': 'Tạo mới camera', + 'master.camera.form.title.edit': 'Chỉnh sửa camera', + 'master.camera.form.name': 'Tên', + 'master.camera.form.name.placeholder': 'Nhập tên', + 'master.camera.form.name.required': 'Vui lòng nhập tên', + 'master.camera.form.type': 'Loại', + 'master.camera.form.type.required': 'Vui lòng chọn loại', + 'master.camera.form.username': 'Tài khoản', + 'master.camera.form.username.placeholder': 'Nhập tài khoản', + 'master.camera.form.username.required': 'Vui lòng nhập tài khoản', + 'master.camera.form.password': 'Mật khẩu', + 'master.camera.form.password.placeholder': 'Nhập mật khẩu', + 'master.camera.form.password.required': 'Vui lòng nhập mật khẩu', + 'master.camera.form.ip': 'Địa chỉ IP', + 'master.camera.form.ip.placeholder': '192.168.1.10', + 'master.camera.form.ip.required': 'Vui lòng nhập địa chỉ IP', + 'master.camera.form.rtspPort': 'Cổng RTSP', + 'master.camera.form.rtspPort.required': 'Vui lòng nhập cổng RTSP', + 'master.camera.form.httpPort': 'Cổng HTTP', + 'master.camera.form.httpPort.required': 'Vui lòng nhập cổng HTTP', + 'master.camera.form.stream': 'Luồng', + 'master.camera.form.stream.required': 'Vui lòng nhập luồng', + 'master.camera.form.channel': 'Kênh', + 'master.camera.form.channel.required': 'Vui lòng nhập kênh', + 'master.camera.form.cancel': 'Hủy', + 'master.camera.form.submit': 'Đồng ý', + 'master.camera.form.update': 'Cập nhật', + // Camera Table + 'master.camera.table.add': 'Tạo mới camera', + 'master.camera.table.column.name': 'Tên', + 'master.camera.table.column.type': 'Loại', + 'master.camera.table.column.ip': 'Địa chỉ IP', + 'master.camera.table.column.action': 'Thao tác', + 'master.camera.table.offline.tooltip': 'Thiết bị đang ngoại tuyến', + 'master.camera.table.pagination': 'Hiển thị {0}-{1} của {2} camera', + // Camera Config V6 + 'master.camera.config.recording': 'Ghi dữ liệu camera', + 'master.camera.config.send': 'Gửi đi', + 'master.camera.config.alarmList': 'Danh sách cảnh báo', + 'master.camera.config.selected': 'đã chọn {0} mục', + 'master.camera.config.clear': 'Xóa', + 'master.camera.config.recordingMode.none': 'Không ghi', + 'master.camera.config.recordingMode.alarm': 'Theo cảnh báo', + 'master.camera.config.recordingMode.all': '24/24', }; diff --git a/src/pages/Manager/Device/Camera/components/CameraFormModal.tsx b/src/pages/Manager/Device/Camera/components/CameraFormModal.tsx index 6501a4e..274cc12 100644 --- a/src/pages/Manager/Device/Camera/components/CameraFormModal.tsx +++ b/src/pages/Manager/Device/Camera/components/CameraFormModal.tsx @@ -1,3 +1,4 @@ +import { useIntl } from '@umijs/max'; import { Button, Col, @@ -33,6 +34,7 @@ const CameraFormModal: React.FC = ({ editingCamera, }) => { const [form] = Form.useForm(); + const intl = useIntl(); const isEditMode = !!editingCamera; // Populate form when editing @@ -73,15 +75,28 @@ const CameraFormModal: React.FC = ({ return ( - Hủy + {intl.formatMessage({ + id: 'master.camera.form.cancel', + defaultMessage: 'Hủy', + })} , , ]} width={500} @@ -99,63 +114,159 @@ const CameraFormModal: React.FC = ({ }} > - + + - + @@ -165,18 +276,40 @@ const CameraFormModal: React.FC = ({ diff --git a/src/pages/Manager/Device/Camera/components/CameraTable.tsx b/src/pages/Manager/Device/Camera/components/CameraTable.tsx index 3771fb8..1daaaff 100644 --- a/src/pages/Manager/Device/Camera/components/CameraTable.tsx +++ b/src/pages/Manager/Device/Camera/components/CameraTable.tsx @@ -4,6 +4,7 @@ import { PlusOutlined, ReloadOutlined, } from '@ant-design/icons'; +import { useIntl } from '@umijs/max'; import { Button, Card, Space, Table, theme, Tooltip } from 'antd'; import { useState } from 'react'; @@ -27,6 +28,7 @@ const CameraTable: React.FC = ({ isOnline = false, }) => { const { token } = theme.useToken(); + const intl = useIntl(); const [selectedRowKeys, setSelectedRowKeys] = useState([]); const handleReload = () => { @@ -48,7 +50,10 @@ const CameraTable: React.FC = ({ const columns = [ { - title: 'Tên', + title: intl.formatMessage({ + id: 'master.camera.table.column.name', + defaultMessage: 'Tên', + }), dataIndex: 'name', key: 'name', render: (text: string) => ( @@ -56,22 +61,40 @@ const CameraTable: React.FC = ({ ), }, { - title: 'Loại', + title: intl.formatMessage({ + id: 'master.camera.table.column.type', + defaultMessage: 'Loại', + }), dataIndex: 'cate_id', key: 'cate_id', render: (text: string) => text || '-', }, { - title: 'Địa chỉ IP', + title: intl.formatMessage({ + id: 'master.camera.table.column.ip', + defaultMessage: 'Địa chỉ IP', + }), dataIndex: 'ip', key: 'ip', render: (text: string) => text || '-', }, { - title: 'Thao tác', + title: intl.formatMessage({ + id: 'master.camera.table.column.action', + defaultMessage: 'Thao tác', + }), key: 'action', render: (_: any, record: MasterModel.Camera) => ( - + + ); diff --git a/src/pages/Manager/Device/Camera/components/ConfigCameraV6.tsx b/src/pages/Manager/Device/Camera/components/ConfigCameraV6.tsx index 76c8d80..a5d2351 100644 --- a/src/pages/Manager/Device/Camera/components/ConfigCameraV6.tsx +++ b/src/pages/Manager/Device/Camera/components/ConfigCameraV6.tsx @@ -1,5 +1,5 @@ import { apiQueryConfigAlarm } from '@/services/master/MessageController'; -import { useModel } from '@umijs/max'; +import { useIntl, useModel } from '@umijs/max'; import { Button, Card, @@ -10,17 +10,10 @@ import { Tooltip, Typography, } from 'antd'; -import { useEffect, useState } from 'react'; +import { useEffect, useMemo, useState } from 'react'; const { Text } = Typography; -// Recording modes for V6 -const RECORDING_MODES = [ - { label: 'Không ghi', value: 'none' }, - { label: 'Theo cảnh báo', value: 'alarm' }, - { label: '24/24', value: 'all' }, -]; - interface CameraV6Props { thing: MasterModel.Thing | null; cameraConfig?: MasterModel.CameraV6 | null; @@ -35,6 +28,7 @@ const CameraV6: React.FC = ({ isOnline = false, }) => { const { token } = theme.useToken(); + const intl = useIntl(); const { initialState } = useModel('@@initialState'); const [selectedAlerts, setSelectedAlerts] = useState([]); const [recordingMode, setRecordingMode] = @@ -43,6 +37,34 @@ const CameraV6: React.FC = ({ null, ); + // Recording modes for V6 - using useMemo for i18n + const RECORDING_MODES = useMemo( + () => [ + { + label: intl.formatMessage({ + id: 'master.camera.config.recordingMode.none', + defaultMessage: 'Không ghi', + }), + value: 'none', + }, + { + label: intl.formatMessage({ + id: 'master.camera.config.recordingMode.alarm', + defaultMessage: 'Theo cảnh báo', + }), + value: 'alarm', + }, + { + label: intl.formatMessage({ + id: 'master.camera.config.recordingMode.all', + defaultMessage: '24/24', + }), + value: 'all', + }, + ], + [intl], + ); + // Initialize states from cameraConfig when it's available useEffect(() => { if (cameraConfig) { @@ -125,7 +147,10 @@ const CameraV6: React.FC = ({
- Ghi dữ liệu camera + {intl.formatMessage({ + id: 'master.camera.config.recording', + defaultMessage: 'Ghi dữ liệu camera', + })}