feat(core): sgw-device-ui

This commit is contained in:
Tran Anh Tuan
2025-09-26 18:22:04 +07:00
parent 466e931537
commit 2707b92f7e
88 changed files with 19104 additions and 0 deletions

View File

@@ -0,0 +1,160 @@
import {
deleteSos,
getSos,
sendSosMessage,
} from '@/services/controller/DeviceController';
import { sosMessage } from '@/utils/sosUtil';
import { InfoCircleOutlined, WarningOutlined } from '@ant-design/icons';
import {
ModalForm,
ProFormDependency,
ProFormSelect,
ProFormText,
} from '@ant-design/pro-components';
import { Button, Form, Grid, message, Typography } from 'antd';
import { useEffect, useState } from 'react';
import './index.less';
interface SosButtonProps {
onRefresh?: (isTrue: boolean) => void;
}
const SosButton: React.FC<SosButtonProps> = ({ onRefresh }) => {
const [form] = Form.useForm<{ message: string; messageOther?: string }>();
const [sosData, setSosData] = useState<API.SosResponse>();
const screens = Grid.useBreakpoint();
useEffect(() => {
getSosData();
}, []);
const getSosData = async () => {
try {
const sosData = await getSos();
console.log('SOS Data: ', sosData);
setSosData(sosData);
} catch (error) {
console.error('Failed to fetch SOS data:', error);
}
};
// map width cho từng breakpoint
const getWidth = () => {
if (screens.xs) return '95%'; // mobile
if (screens.sm) return '30%';
if (screens.md) return '30%';
if (screens.lg) return '30%';
return '40%'; // xl, xxl
};
const handleSos = async (messageData?: string) => {
if (messageData) {
try {
await sendSosMessage(messageData);
message.success('Gửi tín hiệu SOS thành công!');
getSosData(); // Cập nhật lại trạng thái SOS
onRefresh?.(true);
} catch (error) {
console.error('Failed to send SOS:', error);
message.error('Gửi tín hiệu SOS thất bại!');
}
} else {
try {
await deleteSos();
message.success('Huỷ tín hiệu SOS thành công!');
getSosData(); // Cập nhật lại trạng thái SOS
onRefresh?.(true);
} catch (error) {
console.error('Failed to delete SOS:', error);
message.error('Huỷ tín hiệu SOS thất bại!');
}
console.log('Sending SOS without message');
}
};
return sosData && sosData.active == true ? (
<div className=" flex flex-col sm:flex-row sm:justify-between sm:items-center bg-red-500 px-4 py-3 gap-3 rounded-xl animate-pulse">
<div className="flex items-center gap-2">
<WarningOutlined style={{ color: 'white', fontSize: '20px' }} />
<Typography.Text className="text-white text-sm sm:text-base">
Đang trong trạng thái khẩn cấp
</Typography.Text>
</div>
<Button
color="danger"
variant="outlined"
className="self-end sm:self-auto"
onClick={async () => await handleSos()}
>
Kết thúc
</Button>
</div>
) : (
<ModalForm
title="Thông báo khẩn cấp"
initialValues={{ message: 'Tình huống khẩn cấp, không kịp chọn !!!' }}
form={form}
width={getWidth()}
modalProps={{
destroyOnHidden: true,
onCancel: () => console.log('run'),
}}
onOpenChange={(open) => {
if (open) {
form.resetFields();
}
}}
trigger={
<Button
icon={<InfoCircleOutlined />}
size="large"
type="primary"
danger
shape="round"
>
Khẩn cấp
</Button>
}
onFinish={async (values) => {
console.log('Form Values: ', values);
// Nếu chọn "Khác" thì lấy messageOther, ngược lại lấy message
const finalMessage =
values.message === 'other' ? values.messageOther : values.message;
await handleSos(finalMessage);
return true;
}}
>
<ProFormSelect
options={[
{ value: 'other', label: 'Khác' },
...sosMessage.map((item) => ({
value: item.moTa,
label: item.moTa,
})),
]}
name="message"
rules={[{ required: true, message: 'Vui lòng chọn hoặc nhập lý do!' }]}
placeholder="Chọn hoặc nhập lý do..."
label="Nội dung:"
/>
<ProFormDependency name={['message']}>
{({ message }) =>
message === 'other' ? (
<ProFormText
name="messageOther"
placeholder="Nhập lý do khác..."
rules={[{ required: true, message: 'Vui lòng nhập lý do khác!' }]}
label="Lý do khác"
/>
) : null
}
</ProFormDependency>
</ModalForm>
);
};
export default SosButton;