feat: add camera configuration translations and enhance Camera components with internationalization support
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { useIntl } from '@umijs/max';
|
||||
import {
|
||||
Button,
|
||||
Col,
|
||||
@@ -33,6 +34,7 @@ const CameraFormModal: React.FC<CameraFormModalProps> = ({
|
||||
editingCamera,
|
||||
}) => {
|
||||
const [form] = Form.useForm<MasterModel.Camera>();
|
||||
const intl = useIntl();
|
||||
const isEditMode = !!editingCamera;
|
||||
|
||||
// Populate form when editing
|
||||
@@ -73,15 +75,28 @@ const CameraFormModal: React.FC<CameraFormModalProps> = ({
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={isEditMode ? 'Chỉnh sửa camera' : 'Tạo mới camera'}
|
||||
title={intl.formatMessage({
|
||||
id: isEditMode
|
||||
? 'master.camera.form.title.edit'
|
||||
: 'master.camera.form.title.add',
|
||||
defaultMessage: isEditMode ? 'Chỉnh sửa camera' : 'Tạo mới camera',
|
||||
})}
|
||||
open={open}
|
||||
onCancel={handleCancel}
|
||||
footer={[
|
||||
<Button key="cancel" onClick={handleCancel}>
|
||||
Hủy
|
||||
{intl.formatMessage({
|
||||
id: 'master.camera.form.cancel',
|
||||
defaultMessage: 'Hủy',
|
||||
})}
|
||||
</Button>,
|
||||
<Button key="submit" type="primary" onClick={handleSubmit}>
|
||||
{isEditMode ? 'Cập nhật' : 'Đồng ý'}
|
||||
{intl.formatMessage({
|
||||
id: isEditMode
|
||||
? 'master.camera.form.update'
|
||||
: 'master.camera.form.submit',
|
||||
defaultMessage: isEditMode ? 'Cập nhật' : 'Đồng ý',
|
||||
})}
|
||||
</Button>,
|
||||
]}
|
||||
width={500}
|
||||
@@ -99,63 +114,159 @@ const CameraFormModal: React.FC<CameraFormModalProps> = ({
|
||||
}}
|
||||
>
|
||||
<Form.Item
|
||||
label="Tên"
|
||||
label={intl.formatMessage({
|
||||
id: 'master.camera.form.name',
|
||||
defaultMessage: 'Tên',
|
||||
})}
|
||||
name="name"
|
||||
rules={[{ required: true, message: 'Vui lòng nhập tên' }]}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: intl.formatMessage({
|
||||
id: 'master.camera.form.name.required',
|
||||
defaultMessage: 'Vui lòng nhập tên',
|
||||
}),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input placeholder="nhập dữ liệu" />
|
||||
<Input
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'master.camera.form.name.placeholder',
|
||||
defaultMessage: 'nhập dữ liệu',
|
||||
})}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="Loại"
|
||||
label={intl.formatMessage({
|
||||
id: 'master.camera.form.type',
|
||||
defaultMessage: 'Loại',
|
||||
})}
|
||||
name="cate_id"
|
||||
rules={[{ required: true, message: 'Vui lòng chọn loại' }]}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: intl.formatMessage({
|
||||
id: 'master.camera.form.type.required',
|
||||
defaultMessage: 'Vui lòng chọn loại',
|
||||
}),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Select options={CAMERA_TYPES} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="Tài khoản"
|
||||
label={intl.formatMessage({
|
||||
id: 'master.camera.form.username',
|
||||
defaultMessage: 'Tài khoản',
|
||||
})}
|
||||
name="username"
|
||||
rules={[{ required: true, message: 'Vui lòng nhập tài khoản' }]}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: intl.formatMessage({
|
||||
id: 'master.camera.form.username.required',
|
||||
defaultMessage: 'Vui lòng nhập tài khoản',
|
||||
}),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input placeholder="nhập tài khoản" autoComplete="off" />
|
||||
<Input
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'master.camera.form.username.placeholder',
|
||||
defaultMessage: 'nhập tài khoản',
|
||||
})}
|
||||
autoComplete="off"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="Mật khẩu"
|
||||
label={intl.formatMessage({
|
||||
id: 'master.camera.form.password',
|
||||
defaultMessage: 'Mật khẩu',
|
||||
})}
|
||||
name="password"
|
||||
rules={[{ required: true, message: 'Vui lòng nhập mật khẩu' }]}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: intl.formatMessage({
|
||||
id: 'master.camera.form.password.required',
|
||||
defaultMessage: 'Vui lòng nhập mật khẩu',
|
||||
}),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input.Password
|
||||
placeholder="nhập mật khẩu"
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'master.camera.form.password.placeholder',
|
||||
defaultMessage: 'nhập mật khẩu',
|
||||
})}
|
||||
autoComplete="new-password"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="Địa chỉ IP"
|
||||
label={intl.formatMessage({
|
||||
id: 'master.camera.form.ip',
|
||||
defaultMessage: 'Địa chỉ IP',
|
||||
})}
|
||||
name="ip"
|
||||
rules={[{ required: true, message: 'Vui lòng nhập địa chỉ IP' }]}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: intl.formatMessage({
|
||||
id: 'master.camera.form.ip.required',
|
||||
defaultMessage: 'Vui lòng nhập địa chỉ IP',
|
||||
}),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input placeholder="192.168.1.10" />
|
||||
<Input
|
||||
placeholder={intl.formatMessage({
|
||||
id: 'master.camera.form.ip.placeholder',
|
||||
defaultMessage: '192.168.1.10',
|
||||
})}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Row gutter={16}>
|
||||
<Col span={12}>
|
||||
<Form.Item
|
||||
label="Cổng RTSP"
|
||||
label={intl.formatMessage({
|
||||
id: 'master.camera.form.rtspPort',
|
||||
defaultMessage: 'Cổng RTSP',
|
||||
})}
|
||||
name="rtsp_port"
|
||||
rules={[{ required: true, message: 'Vui lòng nhập cổng RTSP' }]}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: intl.formatMessage({
|
||||
id: 'master.camera.form.rtspPort.required',
|
||||
defaultMessage: 'Vui lòng nhập cổng RTSP',
|
||||
}),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<InputNumber style={{ width: '100%' }} min={0} max={65535} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Form.Item
|
||||
label="Cổng HTTP"
|
||||
label={intl.formatMessage({
|
||||
id: 'master.camera.form.httpPort',
|
||||
defaultMessage: 'Cổng HTTP',
|
||||
})}
|
||||
name="http_port"
|
||||
rules={[{ required: true, message: 'Vui lòng nhập cổng HTTP' }]}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: intl.formatMessage({
|
||||
id: 'master.camera.form.httpPort.required',
|
||||
defaultMessage: 'Vui lòng nhập cổng HTTP',
|
||||
}),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<InputNumber style={{ width: '100%' }} min={0} max={65535} />
|
||||
</Form.Item>
|
||||
@@ -165,18 +276,40 @@ const CameraFormModal: React.FC<CameraFormModalProps> = ({
|
||||
<Row gutter={16}>
|
||||
<Col span={12}>
|
||||
<Form.Item
|
||||
label="Luồng"
|
||||
label={intl.formatMessage({
|
||||
id: 'master.camera.form.stream',
|
||||
defaultMessage: 'Luồng',
|
||||
})}
|
||||
name="stream"
|
||||
rules={[{ required: true, message: 'Vui lòng nhập luồng' }]}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: intl.formatMessage({
|
||||
id: 'master.camera.form.stream.required',
|
||||
defaultMessage: 'Vui lòng nhập luồng',
|
||||
}),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<InputNumber style={{ width: '100%' }} min={0} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Form.Item
|
||||
label="Kênh"
|
||||
label={intl.formatMessage({
|
||||
id: 'master.camera.form.channel',
|
||||
defaultMessage: 'Kênh',
|
||||
})}
|
||||
name="channel"
|
||||
rules={[{ required: true, message: 'Vui lòng nhập kênh' }]}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: intl.formatMessage({
|
||||
id: 'master.camera.form.channel.required',
|
||||
defaultMessage: 'Vui lòng nhập kênh',
|
||||
}),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<InputNumber style={{ width: '100%' }} min={0} />
|
||||
</Form.Item>
|
||||
|
||||
@@ -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<CameraTableProps> = ({
|
||||
isOnline = false,
|
||||
}) => {
|
||||
const { token } = theme.useToken();
|
||||
const intl = useIntl();
|
||||
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
||||
|
||||
const handleReload = () => {
|
||||
@@ -48,7 +50,10 @@ const CameraTable: React.FC<CameraTableProps> = ({
|
||||
|
||||
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<CameraTableProps> = ({
|
||||
),
|
||||
},
|
||||
{
|
||||
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) => (
|
||||
<Tooltip title={!isOnline ? 'Thiết bị đang ngoại tuyến' : ''}>
|
||||
<Tooltip
|
||||
title={
|
||||
!isOnline
|
||||
? intl.formatMessage({
|
||||
id: 'master.camera.table.offline.tooltip',
|
||||
defaultMessage: 'Thiết bị đang ngoại tuyến',
|
||||
})
|
||||
: ''
|
||||
}
|
||||
>
|
||||
<Button
|
||||
size="small"
|
||||
icon={<EditOutlined />}
|
||||
@@ -86,14 +109,26 @@ const CameraTable: React.FC<CameraTableProps> = ({
|
||||
return (
|
||||
<Card bodyStyle={{ padding: 16 }}>
|
||||
<Space style={{ marginBottom: 16 }}>
|
||||
<Tooltip title={!isOnline ? 'Thiết bị đang ngoại tuyến' : ''}>
|
||||
<Tooltip
|
||||
title={
|
||||
!isOnline
|
||||
? intl.formatMessage({
|
||||
id: 'master.camera.table.offline.tooltip',
|
||||
defaultMessage: 'Thiết bị đang ngoại tuyến',
|
||||
})
|
||||
: ''
|
||||
}
|
||||
>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
onClick={onCreateCamera}
|
||||
disabled={!isOnline}
|
||||
>
|
||||
Tạo mới camera
|
||||
{intl.formatMessage({
|
||||
id: 'master.camera.table.add',
|
||||
defaultMessage: 'Tạo mới camera',
|
||||
})}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Button
|
||||
@@ -101,7 +136,16 @@ const CameraTable: React.FC<CameraTableProps> = ({
|
||||
onClick={handleReload}
|
||||
loading={loading}
|
||||
/>
|
||||
<Tooltip title={!isOnline ? 'Thiết bị đang ngoại tuyến' : ''}>
|
||||
<Tooltip
|
||||
title={
|
||||
!isOnline
|
||||
? intl.formatMessage({
|
||||
id: 'master.camera.table.offline.tooltip',
|
||||
defaultMessage: 'Thiết bị đang ngoại tuyến',
|
||||
})
|
||||
: ''
|
||||
}
|
||||
>
|
||||
<Button
|
||||
icon={<DeleteOutlined />}
|
||||
onClick={handleDelete}
|
||||
@@ -126,7 +170,17 @@ const CameraTable: React.FC<CameraTableProps> = ({
|
||||
pagination={{
|
||||
size: 'small',
|
||||
showTotal: (total: number, range: [number, number]) =>
|
||||
`Hiển thị ${range[0]}-${range[1]} của ${total} camera`,
|
||||
intl.formatMessage(
|
||||
{
|
||||
id: 'master.camera.table.pagination',
|
||||
defaultMessage: 'Hiển thị {0}-{1} của {2} camera',
|
||||
},
|
||||
{
|
||||
0: range[0],
|
||||
1: range[1],
|
||||
2: total,
|
||||
},
|
||||
),
|
||||
pageSize: 10,
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
import { useIntl } from '@umijs/max';
|
||||
import { Button, Card, Select, Typography } from 'antd';
|
||||
import { useState } from 'react';
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
// Recording modes for V5 - chỉ có không ghi và ghi 24/24
|
||||
const RECORDING_MODES = [
|
||||
{ label: 'Không ghi', value: 'none' },
|
||||
{ label: 'Ghi 24/24', value: '24/7' },
|
||||
];
|
||||
|
||||
interface CameraV5Props {
|
||||
thing: MasterModel.Thing | null;
|
||||
@@ -18,9 +15,29 @@ const CameraV5: React.FC<CameraV5Props> = ({
|
||||
thing,
|
||||
initialRecordingMode = 'none',
|
||||
}) => {
|
||||
const [recordingMode, setRecordingMode] = useState(initialRecordingMode);
|
||||
const intl = useIntl();
|
||||
|
||||
console.log('ConfigCameraV5 - thing:', thing);
|
||||
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.all',
|
||||
defaultMessage: '24/24',
|
||||
}),
|
||||
value: 'all',
|
||||
},
|
||||
],
|
||||
[intl],
|
||||
);
|
||||
|
||||
const [recordingMode, setRecordingMode] = useState(initialRecordingMode);
|
||||
|
||||
const handleSubmit = () => {
|
||||
console.log('Submit recording mode:', recordingMode);
|
||||
@@ -30,23 +47,30 @@ const CameraV5: React.FC<CameraV5Props> = ({
|
||||
return (
|
||||
<Card bodyStyle={{ padding: 16 }}>
|
||||
{/* Recording Mode */}
|
||||
<div style={{ marginBottom: 24 }}>
|
||||
<Text strong style={{ display: 'block', marginBottom: 8 }}>
|
||||
Ghi dữ liệu camera
|
||||
</Text>
|
||||
<Select
|
||||
value={recordingMode}
|
||||
onChange={setRecordingMode}
|
||||
options={RECORDING_MODES}
|
||||
style={{ width: 200 }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Submit Button */}
|
||||
<div style={{ textAlign: 'center' }}>
|
||||
<Button type="primary" onClick={handleSubmit}>
|
||||
Gửi đi
|
||||
</Button>
|
||||
<div className="mb-6">
|
||||
<div className="flex flex-col sm:flex-row gap-2 sm:gap-4 items-start sm:items-end">
|
||||
<div className="w-full sm:w-1/3 lg:w-1/4">
|
||||
<Text strong className="block mb-2">
|
||||
{intl.formatMessage({
|
||||
id: 'master.camera.config.recording',
|
||||
defaultMessage: 'Ghi dữ liệu camera',
|
||||
})}
|
||||
</Text>
|
||||
<Select
|
||||
value={recordingMode}
|
||||
onChange={setRecordingMode}
|
||||
options={RECORDING_MODES}
|
||||
className="w-full"
|
||||
popupMatchSelectWidth={false}
|
||||
/>
|
||||
</div>
|
||||
<Button type="primary" onClick={handleSubmit}>
|
||||
{intl.formatMessage({
|
||||
id: 'master.camera.config.send',
|
||||
defaultMessage: 'Gửi đi',
|
||||
})}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
|
||||
@@ -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<CameraV6Props> = ({
|
||||
isOnline = false,
|
||||
}) => {
|
||||
const { token } = theme.useToken();
|
||||
const intl = useIntl();
|
||||
const { initialState } = useModel('@@initialState');
|
||||
const [selectedAlerts, setSelectedAlerts] = useState<string[]>([]);
|
||||
const [recordingMode, setRecordingMode] =
|
||||
@@ -43,6 +37,34 @@ const CameraV6: React.FC<CameraV6Props> = ({
|
||||
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<CameraV6Props> = ({
|
||||
<div className="flex flex-col sm:flex-row gap-2 sm:gap-4 items-start sm:items-end">
|
||||
<div className="w-full sm:w-1/3 lg:w-1/4">
|
||||
<Text strong className="block mb-2">
|
||||
Ghi dữ liệu camera
|
||||
{intl.formatMessage({
|
||||
id: 'master.camera.config.recording',
|
||||
defaultMessage: 'Ghi dữ liệu camera',
|
||||
})}
|
||||
</Text>
|
||||
<Select
|
||||
value={recordingMode}
|
||||
@@ -135,13 +160,25 @@ const CameraV6: React.FC<CameraV6Props> = ({
|
||||
popupMatchSelectWidth={false}
|
||||
/>
|
||||
</div>
|
||||
<Tooltip title={!isOnline ? 'Thiết bị đang ngoại tuyến' : ''}>
|
||||
<Tooltip
|
||||
title={
|
||||
!isOnline
|
||||
? intl.formatMessage({
|
||||
id: 'master.camera.table.offline.tooltip',
|
||||
defaultMessage: 'Thiết bị đang ngoại tuyến',
|
||||
})
|
||||
: ''
|
||||
}
|
||||
>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={handleSubmitConfig}
|
||||
disabled={!isOnline}
|
||||
>
|
||||
Gửi đi
|
||||
{intl.formatMessage({
|
||||
id: 'master.camera.config.send',
|
||||
defaultMessage: 'Gửi đi',
|
||||
})}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
@@ -151,7 +188,10 @@ const CameraV6: React.FC<CameraV6Props> = ({
|
||||
{recordingMode === 'alarm' && (
|
||||
<div>
|
||||
<Text strong className="block mb-2">
|
||||
Danh sách cảnh báo
|
||||
{intl.formatMessage({
|
||||
id: 'master.camera.config.alarmList',
|
||||
defaultMessage: 'Danh sách cảnh báo',
|
||||
})}
|
||||
</Text>
|
||||
|
||||
<div
|
||||
@@ -161,9 +201,22 @@ const CameraV6: React.FC<CameraV6Props> = ({
|
||||
borderColor: token.colorBorder,
|
||||
}}
|
||||
>
|
||||
<Text type="secondary">đã chọn {selectedAlerts.length} mục</Text>
|
||||
<Text type="secondary">
|
||||
{intl.formatMessage(
|
||||
{
|
||||
id: 'master.camera.config.selected',
|
||||
defaultMessage: 'đã chọn {0} mục',
|
||||
},
|
||||
{
|
||||
0: selectedAlerts.length,
|
||||
},
|
||||
)}
|
||||
</Text>
|
||||
<Button type="link" onClick={handleClearAlerts}>
|
||||
Xóa
|
||||
{intl.formatMessage({
|
||||
id: 'master.camera.config.clear',
|
||||
defaultMessage: 'Xóa',
|
||||
})}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user