lavoce #2
@@ -8,54 +8,33 @@ import dayjs from 'dayjs';
|
|||||||
|
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
// Line Chart Data (same as IndexTrending) converted to table format
|
// New data structure for tag history
|
||||||
const lineChartData = [
|
const tagHistoryData = [
|
||||||
{
|
{
|
||||||
id: 'Compressor Section 1',
|
tag: 'TEMP_SENSOR_1',
|
||||||
color: '#FF6B4A',
|
color: '#FF6B4A',
|
||||||
data: [
|
history: [
|
||||||
{ x: 'Jan', y: 15 },
|
{ timestamp: '2025-10-09 08:00', value: 75 },
|
||||||
{ x: 'Feb', y: 18 },
|
{ timestamp: '2025-10-09 08:05', value: 76 },
|
||||||
{ x: 'Mar', y: 17 },
|
{ timestamp: '2025-10-09 08:10', value: 75 },
|
||||||
{ x: 'Apr', y: 24 },
|
|
||||||
{ x: 'Mei', y: 21 },
|
|
||||||
{ x: 'Jun', y: 19 },
|
|
||||||
{ x: 'Jul', y: 28 },
|
|
||||||
{ x: 'Agu', y: 26 },
|
|
||||||
{ x: 'Sep', y: 22 },
|
|
||||||
{ x: 'Okt', y: 25 },
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'Compressor Section 2',
|
tag: 'GAS_LEAK_SENSOR_1',
|
||||||
color: '#4ECDC4',
|
color: '#4ECDC4',
|
||||||
data: [
|
history: [
|
||||||
{ x: 'Jan', y: 12 },
|
{ timestamp: '2025-10-09 08:00', value: 10 },
|
||||||
{ x: 'Feb', y: 14 },
|
{ timestamp: '2025-10-09 08:05', value: 150 },
|
||||||
{ x: 'Mar', y: 19 },
|
{ timestamp: '2025-10-09 08:10', value: 12 },
|
||||||
{ x: 'Apr', y: 21 },
|
|
||||||
{ x: 'Mei', y: 22 },
|
|
||||||
{ x: 'Jun', y: 20 },
|
|
||||||
{ x: 'Jul', y: 19 },
|
|
||||||
{ x: 'Agu', y: 21 },
|
|
||||||
{ x: 'Sep', y: 18 },
|
|
||||||
{ x: 'Okt', y: 20 },
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'Compressor Section 3',
|
tag: 'PRESSURE_SENSOR_1',
|
||||||
color: '#FFE66D',
|
color: '#FFE66D',
|
||||||
data: [
|
history: [
|
||||||
{ x: 'Jan', y: 8 },
|
{ timestamp: '2025-10-09 08:00', value: 1.2 },
|
||||||
{ x: 'Feb', y: 10 },
|
{ timestamp: '2025-10-09 08:05', value: 1.3 },
|
||||||
{ x: 'Mar', y: 12 },
|
{ timestamp: '2025-10-09 08:10', value: 1.2 },
|
||||||
{ x: 'Apr', y: 15 },
|
|
||||||
{ x: 'Mei', y: 18 },
|
|
||||||
{ x: 'Jun', y: 20 },
|
|
||||||
{ x: 'Jul', y: 22 },
|
|
||||||
{ x: 'Agu', y: 21 },
|
|
||||||
{ x: 'Sep', y: 19 },
|
|
||||||
{ x: 'Okt', y: 26 },
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@@ -67,7 +46,7 @@ const IndexReport = memo(function IndexReport() {
|
|||||||
const [plantSubSection, setPlantSubSection] = useState('Semua Plant');
|
const [plantSubSection, setPlantSubSection] = useState('Semua Plant');
|
||||||
const [startDate, setStartDate] = useState(dayjs('2025-09-30'));
|
const [startDate, setStartDate] = useState(dayjs('2025-09-30'));
|
||||||
const [endDate, setEndDate] = useState(dayjs('2025-10-09'));
|
const [endDate, setEndDate] = useState(dayjs('2025-10-09'));
|
||||||
const [periode, setPeriode] = useState('Bulanan');
|
const [periode, setPeriode] = useState('30 Menit');
|
||||||
const [userRole, setUserRole] = useState(null);
|
const [userRole, setUserRole] = useState(null);
|
||||||
const [roleLevel, setRoleLevel] = useState(null);
|
const [roleLevel, setRoleLevel] = useState(null);
|
||||||
|
|
||||||
@@ -120,63 +99,53 @@ const IndexReport = memo(function IndexReport() {
|
|||||||
setPlantSubSection('Semua Plant');
|
setPlantSubSection('Semua Plant');
|
||||||
setStartDate(dayjs('2025-09-30'));
|
setStartDate(dayjs('2025-09-30'));
|
||||||
setEndDate(dayjs('2025-10-09'));
|
setEndDate(dayjs('2025-10-09'));
|
||||||
setPeriode('Bulanan');
|
setPeriode('30 Menit');
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if user has permission to view data (all except guest)
|
// Check if user has permission to view data (all except guest)
|
||||||
const canViewData = userRole && userRole !== 'guest';
|
const canViewData = userRole && userRole !== 'guest';
|
||||||
|
|
||||||
// Convert chart data to table format
|
// Convert tag history data to table format
|
||||||
const convertToTableData = () => {
|
const convertToTableData = () => {
|
||||||
return lineChartData.map((section, index) => {
|
const timestamps = {}; // Use an object to collect data per timestamp
|
||||||
const rowData = {
|
|
||||||
key: index,
|
tagHistoryData.forEach((tagData) => {
|
||||||
section: section.id,
|
tagData.history.forEach((point) => {
|
||||||
color: section.color,
|
if (!timestamps[point.timestamp]) {
|
||||||
|
timestamps[point.timestamp] = {
|
||||||
|
key: point.timestamp,
|
||||||
|
'Date and Time': point.timestamp,
|
||||||
};
|
};
|
||||||
|
}
|
||||||
// Add each month's data as a column
|
timestamps[point.timestamp][tagData.tag] = point.value;
|
||||||
section.data.forEach((point) => {
|
});
|
||||||
rowData[point.x] = point.y;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return rowData;
|
// Convert the object to an array
|
||||||
});
|
return Object.values(timestamps);
|
||||||
};
|
};
|
||||||
|
|
||||||
const tableData = convertToTableData();
|
const tableData = convertToTableData();
|
||||||
|
|
||||||
// Create dynamic columns based on months
|
// Create dynamic columns based on tags
|
||||||
const months = lineChartData[0]?.data.map((point) => point.x) || [];
|
const tags = tagHistoryData.map((tagData) => tagData.tag);
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: 'Plant Sub Section',
|
title: 'Date and Time',
|
||||||
dataIndex: 'section',
|
dataIndex: 'Date and Time',
|
||||||
key: 'section',
|
key: 'Date and Time',
|
||||||
fixed: 'left',
|
fixed: 'left',
|
||||||
width: 200,
|
width: 180,
|
||||||
render: (text, record) => (
|
render: (text) => <Text strong>{text}</Text>,
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
width: '12px',
|
|
||||||
height: '12px',
|
|
||||||
borderRadius: '50%',
|
|
||||||
backgroundColor: record.color,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Text strong>{text}</Text>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
...months.map((month) => ({
|
...tags.map((tag) => ({
|
||||||
title: month,
|
title: tag,
|
||||||
dataIndex: month,
|
dataIndex: tag,
|
||||||
key: month,
|
key: tag,
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: 80,
|
width: 150,
|
||||||
render: (value) => <Text>{value}</Text>,
|
render: (value) => <Text>{value !== undefined ? value : '-'}</Text>,
|
||||||
})),
|
})),
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -242,9 +211,10 @@ const IndexReport = memo(function IndexReport() {
|
|||||||
onChange={setPeriode}
|
onChange={setPeriode}
|
||||||
style={{ width: '100%', marginTop: '4px' }}
|
style={{ width: '100%', marginTop: '4px' }}
|
||||||
options={[
|
options={[
|
||||||
{ value: 'Harian', label: 'Harian' },
|
{ value: '5 Menit', label: '5 Menit' },
|
||||||
{ value: 'Mingguan', label: 'Mingguan' },
|
{ value: '10 Menit', label: '10 Menit' },
|
||||||
{ value: 'Bulanan', label: 'Bulanan' },
|
{ value: '30 Menit', label: '30 Menit' },
|
||||||
|
{ value: '1 Jam', label: '1 Jam' },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -272,9 +242,8 @@ const IndexReport = memo(function IndexReport() {
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Table Section */}
|
{/* Table Section */}
|
||||||
{!canViewData ? (
|
{/* {!canViewData ? (
|
||||||
<Card style={{ marginTop: '24px', textAlign: 'center', padding: '40px' }}>
|
<Card style={{ marginTop: '24px', textAlign: 'center', padding: '40px' }}>
|
||||||
<Text style={{ fontSize: '16px', color: '#999' }}>
|
<Text style={{ fontSize: '16px', color: '#999' }}>
|
||||||
Anda tidak memiliki akses untuk melihat data report.
|
Anda tidak memiliki akses untuk melihat data report.
|
||||||
@@ -282,11 +251,11 @@ const IndexReport = memo(function IndexReport() {
|
|||||||
Silakan hubungi administrator untuk mendapatkan akses.
|
Silakan hubungi administrator untuk mendapatkan akses.
|
||||||
</Text>
|
</Text>
|
||||||
</Card>
|
</Card>
|
||||||
) : (
|
) : ( */}
|
||||||
<Card style={{ marginTop: '24px' }}>
|
<Card style={{ marginTop: '24px' }}>
|
||||||
<div style={{ marginBottom: '16px' }}>
|
<div style={{ marginBottom: '16px' }}>
|
||||||
<Text strong style={{ fontSize: '16px' }}>
|
<Text strong style={{ fontSize: '16px' }}>
|
||||||
☰ Trending Error per Plant Sub Section
|
☰ History Report
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
<Table
|
<Table
|
||||||
@@ -297,7 +266,7 @@ const IndexReport = memo(function IndexReport() {
|
|||||||
size="middle"
|
size="middle"
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
{/* )} */}
|
||||||
</div>
|
</div>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const IndexTrending = memo(function IndexTrending() {
|
|||||||
const [plantSubSection, setPlantSubSection] = useState('Semua Plant');
|
const [plantSubSection, setPlantSubSection] = useState('Semua Plant');
|
||||||
const [startDate, setStartDate] = useState(dayjs('2025-09-30'));
|
const [startDate, setStartDate] = useState(dayjs('2025-09-30'));
|
||||||
const [endDate, setEndDate] = useState(dayjs('2025-10-09'));
|
const [endDate, setEndDate] = useState(dayjs('2025-10-09'));
|
||||||
const [periode, setPeriode] = useState('Bulanan');
|
const [periode, setPeriode] = useState('10 Menit');
|
||||||
const [userRole, setUserRole] = useState(null);
|
const [userRole, setUserRole] = useState(null);
|
||||||
const [roleLevel, setRoleLevel] = useState(null);
|
const [roleLevel, setRoleLevel] = useState(null);
|
||||||
|
|
||||||
@@ -66,79 +66,53 @@ const IndexTrending = memo(function IndexTrending() {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const lineChartData = [
|
const tagTrendingData = [
|
||||||
{
|
{
|
||||||
id: 'Compressor Section 1',
|
id: 'TEMP_SENSOR_1',
|
||||||
color: '#FF6B4A',
|
color: '#FF6B4A',
|
||||||
data: [
|
data: [
|
||||||
{ x: 'Jan', y: 15 },
|
{ y: '08:00', x: 75 },
|
||||||
{ x: 'Feb', y: 18 },
|
{ y: '08:05', x: 76 },
|
||||||
{ x: 'Mar', y: 17 },
|
{ y: '08:10', x: 75 },
|
||||||
{ x: 'Apr', y: 24 },
|
{ y: '08:15', x: 77 },
|
||||||
{ x: 'Mei', y: 21 },
|
{ y: '08:20', x: 76 },
|
||||||
{ x: 'Jun', y: 19 },
|
{ y: '08:25', x: 78 },
|
||||||
{ x: 'Jul', y: 28 },
|
{ y: '08:30', x: 79 },
|
||||||
{ x: 'Agu', y: 26 },
|
|
||||||
{ x: 'Sep', y: 22 },
|
|
||||||
{ x: 'Okt', y: 25 },
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'Compressor Section 2',
|
id: 'GAS_LEAK_SENSOR_1',
|
||||||
color: '#4ECDC4',
|
color: '#4ECDC4',
|
||||||
data: [
|
data: [
|
||||||
{ x: 'Jan', y: 12 },
|
{ y: '08:00', x: 10 },
|
||||||
{ x: 'Feb', y: 14 },
|
{ y: '08:05', x: 150 },
|
||||||
{ x: 'Mar', y: 19 },
|
{ y: '08:10', x: 40 },
|
||||||
{ x: 'Apr', y: 21 },
|
{ y: '08:15', x: 20 },
|
||||||
{ x: 'Mei', y: 22 },
|
{ y: '08:20', x: 15 },
|
||||||
{ x: 'Jun', y: 20 },
|
{ y: '08:25', x: 18 },
|
||||||
{ x: 'Jul', y: 19 },
|
{ y: '08:30', x: 25 },
|
||||||
{ x: 'Agu', y: 21 },
|
|
||||||
{ x: 'Sep', y: 18 },
|
|
||||||
{ x: 'Okt', y: 20 },
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'Compressor Section 3',
|
id: 'PRESSURE_SENSOR_1',
|
||||||
color: '#FFE66D',
|
color: '#FFE66D',
|
||||||
data: [
|
data: [
|
||||||
{ x: 'Jan', y: 8 },
|
{ y: '08:00', x: 1.2 },
|
||||||
{ x: 'Feb', y: 10 },
|
{ y: '08:05', x: 1.3 },
|
||||||
{ x: 'Mar', y: 12 },
|
{ y: '08:10', x: 1.2 },
|
||||||
{ x: 'Apr', y: 15 },
|
{ y: '08:15', x: 1.4 },
|
||||||
{ x: 'Mei', y: 18 },
|
{ y: '08:20', x: 1.5 },
|
||||||
{ x: 'Jun', y: 20 },
|
{ y: '08:25', x: 1.3 },
|
||||||
{ x: 'Jul', y: 22 },
|
{ y: '08:30', x: 1.2 },
|
||||||
{ x: 'Agu', y: 21 },
|
|
||||||
{ x: 'Sep', y: 19 },
|
|
||||||
{ x: 'Okt', y: 26 },
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const donutChartData = [
|
|
||||||
{ id: 'Section 1', label: 'Section 1', value: 35, color: '#FF6B4A' },
|
|
||||||
{ id: 'Section 2', label: 'Section 2', value: 25, color: '#4ECDC4' },
|
|
||||||
{ id: 'Section 3', label: 'Section 3', value: 15, color: '#FFE66D' },
|
|
||||||
{ id: 'Section 4', label: 'Section 4', value: 12, color: '#95E1D3' },
|
|
||||||
{ id: 'Section 5', label: 'Section 5', value: 8, color: '#F38BA0' },
|
|
||||||
{ id: 'Section 6', label: 'Section 6', value: 5, color: '#A78BFA' },
|
|
||||||
];
|
|
||||||
|
|
||||||
const barChartData = [
|
|
||||||
{ label: 'Overheat', value: 65 },
|
|
||||||
{ label: 'Low Pressure', value: 48 },
|
|
||||||
{ label: 'High Vibration', value: 42 },
|
|
||||||
{ label: 'Oil Leak', value: 35 },
|
|
||||||
{ label: 'Sensor Error', value: 28 },
|
|
||||||
];
|
|
||||||
|
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
setPlantSubSection('Semua Plant');
|
setPlantSubSection('Semua Plant');
|
||||||
setStartDate(dayjs('2025-09-30'));
|
setStartDate(dayjs('2025-09-30'));
|
||||||
setEndDate(dayjs('2025-10-09'));
|
setEndDate(dayjs('2025-10-09'));
|
||||||
setPeriode('Bulanan');
|
setPeriode('10 Menit');
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if user has permission to view data (all except guest)
|
// Check if user has permission to view data (all except guest)
|
||||||
@@ -204,9 +178,10 @@ const IndexTrending = memo(function IndexTrending() {
|
|||||||
onChange={setPeriode}
|
onChange={setPeriode}
|
||||||
style={{ width: '100%', marginTop: '4px' }}
|
style={{ width: '100%', marginTop: '4px' }}
|
||||||
options={[
|
options={[
|
||||||
{ value: 'Harian', label: 'Harian' },
|
{ value: '5 Menit', label: '5 Menit' },
|
||||||
{ value: 'Mingguan', label: 'Mingguan' },
|
{ value: '10 Menit', label: '10 Menit' },
|
||||||
{ value: 'Bulanan', label: 'Bulanan' },
|
{ value: '30 Menit', label: '30 Menit' },
|
||||||
|
{ value: '1 Jam', label: '1 Jam' },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -234,9 +209,8 @@ const IndexTrending = memo(function IndexTrending() {
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
{/* Charts Section */}
|
{/* Charts Section */}
|
||||||
{!canViewData ? (
|
{/* {!canViewData ? (
|
||||||
<Card style={{ marginTop: '24px', textAlign: 'center', padding: '40px' }}>
|
<Card style={{ marginTop: '24px', textAlign: 'center', padding: '40px' }}>
|
||||||
<Text style={{ fontSize: '16px', color: '#999' }}>
|
<Text style={{ fontSize: '16px', color: '#999' }}>
|
||||||
Anda tidak memiliki akses untuk melihat data trending.
|
Anda tidak memiliki akses untuk melihat data trending.
|
||||||
@@ -244,7 +218,7 @@ const IndexTrending = memo(function IndexTrending() {
|
|||||||
Silakan hubungi administrator untuk mendapatkan akses.
|
Silakan hubungi administrator untuk mendapatkan akses.
|
||||||
</Text>
|
</Text>
|
||||||
</Card>
|
</Card>
|
||||||
) : (
|
) : ( */}
|
||||||
<>
|
<>
|
||||||
<Row gutter={16} style={{ marginTop: '24px' }}>
|
<Row gutter={16} style={{ marginTop: '24px' }}>
|
||||||
{/* Line Chart */}
|
{/* Line Chart */}
|
||||||
@@ -252,25 +226,39 @@ const IndexTrending = memo(function IndexTrending() {
|
|||||||
<Card className="chart-card">
|
<Card className="chart-card">
|
||||||
<div className="chart-header">
|
<div className="chart-header">
|
||||||
<Text strong style={{ fontSize: '14px' }}>
|
<Text strong style={{ fontSize: '14px' }}>
|
||||||
☰ Trending Error per Plant Sub Section
|
☰ Tag Value Trending
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ height: '500px', marginTop: '16px' }}>
|
<div style={{ height: '500px', marginTop: '16px' }}>
|
||||||
<ResponsiveLine
|
<ResponsiveLine
|
||||||
data={lineChartData}
|
data={tagTrendingData}
|
||||||
margin={{ top: 20, right: 20, bottom: 50, left: 50 }}
|
margin={{ top: 20, right: 20, bottom: 50, left: 60 }}
|
||||||
xScale={{ type: 'point' }}
|
xScale={{
|
||||||
yScale={{ type: 'linear', min: 0, max: 35 }}
|
type: 'linear',
|
||||||
|
min: 'auto',
|
||||||
|
max: 'auto',
|
||||||
|
stacked: false,
|
||||||
|
reverse: false,
|
||||||
|
}}
|
||||||
|
yScale={{
|
||||||
|
type: 'point',
|
||||||
|
}}
|
||||||
curve="natural"
|
curve="natural"
|
||||||
axisBottom={{
|
axisBottom={{
|
||||||
tickSize: 5,
|
tickSize: 5,
|
||||||
tickPadding: 5,
|
tickPadding: 5,
|
||||||
tickRotation: 0,
|
tickRotation: 0,
|
||||||
|
legend: 'Value',
|
||||||
|
legendOffset: 40,
|
||||||
|
legendPosition: 'middle',
|
||||||
}}
|
}}
|
||||||
axisLeft={{
|
axisLeft={{
|
||||||
tickSize: 5,
|
tickSize: 5,
|
||||||
tickPadding: 5,
|
tickPadding: 5,
|
||||||
tickRotation: 0,
|
tickRotation: 0,
|
||||||
|
legend: 'Time',
|
||||||
|
legendOffset: -45,
|
||||||
|
legendPosition: 'middle',
|
||||||
}}
|
}}
|
||||||
colors={{ datum: 'color' }}
|
colors={{ datum: 'color' }}
|
||||||
pointSize={6}
|
pointSize={6}
|
||||||
@@ -281,14 +269,14 @@ const IndexTrending = memo(function IndexTrending() {
|
|||||||
useMesh={true}
|
useMesh={true}
|
||||||
legends={[
|
legends={[
|
||||||
{
|
{
|
||||||
anchor: 'bottom',
|
anchor: 'bottom-right',
|
||||||
direction: 'row',
|
direction: 'column',
|
||||||
justify: false,
|
justify: false,
|
||||||
translateX: 0,
|
translateX: 100,
|
||||||
translateY: 50,
|
translateY: 0,
|
||||||
itemsSpacing: 10,
|
itemsSpacing: 2,
|
||||||
itemDirection: 'left-to-right',
|
itemDirection: 'left-to-right',
|
||||||
itemWidth: 140,
|
itemWidth: 80,
|
||||||
itemHeight: 20,
|
itemHeight: 20,
|
||||||
itemOpacity: 0.75,
|
itemOpacity: 0.75,
|
||||||
symbolSize: 12,
|
symbolSize: 12,
|
||||||
@@ -301,7 +289,7 @@ const IndexTrending = memo(function IndexTrending() {
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</>
|
</>
|
||||||
)}
|
{/* )} */}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const DetailDevice = (props) => {
|
|||||||
device_id: '',
|
device_id: '',
|
||||||
device_code: '',
|
device_code: '',
|
||||||
device_name: '',
|
device_name: '',
|
||||||
device_status: true,
|
is_active: true,
|
||||||
device_location: 'Building A',
|
device_location: 'Building A',
|
||||||
device_description: '',
|
device_description: '',
|
||||||
ip_address: '',
|
ip_address: '',
|
||||||
@@ -139,7 +139,7 @@ const DetailDevice = (props) => {
|
|||||||
// Backend validation schema doesn't include device_code
|
// Backend validation schema doesn't include device_code
|
||||||
const payload = {
|
const payload = {
|
||||||
device_name: FormData.device_name,
|
device_name: FormData.device_name,
|
||||||
device_status: FormData.device_status,
|
is_active: FormData.is_active,
|
||||||
device_location: FormData.device_location,
|
device_location: FormData.device_location,
|
||||||
ip_address: FormData.ip_address,
|
ip_address: FormData.ip_address,
|
||||||
};
|
};
|
||||||
@@ -211,11 +211,10 @@ const DetailDevice = (props) => {
|
|||||||
const isChecked = event;
|
const isChecked = event;
|
||||||
setFormData({
|
setFormData({
|
||||||
...FormData,
|
...FormData,
|
||||||
device_status: isChecked ? true : false,
|
is_active: isChecked ? true : false,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const token = localStorage.getItem('token');
|
const token = localStorage.getItem('token');
|
||||||
if (token) {
|
if (token) {
|
||||||
@@ -312,16 +311,14 @@ const DetailDevice = (props) => {
|
|||||||
disabled={props.readOnly}
|
disabled={props.readOnly}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
FormData.device_status === true ? '#23A55A' : '#bfbfbf',
|
FormData.is_active === true ? '#23A55A' : '#bfbfbf',
|
||||||
}}
|
}}
|
||||||
checked={FormData.device_status === true}
|
checked={FormData.is_active === true}
|
||||||
onChange={handleStatusToggle}
|
onChange={handleStatusToggle}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Text>
|
<Text>{FormData.is_active === true ? 'Running' : 'Offline'}</Text>
|
||||||
{FormData.device_status === true ? 'Running' : 'Offline'}
|
|
||||||
</Text>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const DetailTag = (props) => {
|
|||||||
|
|
||||||
const defaultData = {
|
const defaultData = {
|
||||||
tag_id: '',
|
tag_id: '',
|
||||||
tag_code: '',
|
|
||||||
tag_name: '',
|
tag_name: '',
|
||||||
tag_number: '',
|
tag_number: '',
|
||||||
data_type: '',
|
data_type: '',
|
||||||
@@ -24,8 +24,7 @@ const DetailTag = (props) => {
|
|||||||
is_active: true,
|
is_active: true,
|
||||||
is_alarm: false,
|
is_alarm: false,
|
||||||
device_id: null,
|
device_id: null,
|
||||||
device_code: '',
|
|
||||||
device_name: '',
|
|
||||||
sub_section_id: null,
|
sub_section_id: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -118,6 +117,18 @@ const DetailTag = (props) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validasi data type harus Diskrit atau Analog
|
||||||
|
const validDataTypes = ['Diskrit', 'Analog'];
|
||||||
|
if (!validDataTypes.includes(FormData.data_type)) {
|
||||||
|
NotifOk({
|
||||||
|
icon: 'warning',
|
||||||
|
title: 'Peringatan',
|
||||||
|
message: `Data Type harus "Diskrit" atau "Analog". Nilai "${FormData.data_type}" tidak valid. Silakan pilih dari dropdown.`,
|
||||||
|
});
|
||||||
|
setConfirmLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!FormData.unit || FormData.unit.trim() === '') {
|
if (!FormData.unit || FormData.unit.trim() === '') {
|
||||||
NotifOk({
|
NotifOk({
|
||||||
icon: 'warning',
|
icon: 'warning',
|
||||||
@@ -141,17 +152,22 @@ const DetailTag = (props) => {
|
|||||||
|
|
||||||
// Prepare payload berdasarkan backend validation schema
|
// Prepare payload berdasarkan backend validation schema
|
||||||
const payload = {
|
const payload = {
|
||||||
tag_name: FormData.tag_name,
|
tag_name: FormData.tag_name.trim(),
|
||||||
tag_number: parseInt(FormData.tag_number),
|
tag_number: parseInt(FormData.tag_number),
|
||||||
data_type: FormData.data_type,
|
data_type: FormData.data_type,
|
||||||
unit: FormData.unit,
|
unit: FormData.unit.trim(),
|
||||||
is_active: FormData.is_active,
|
is_active: FormData.is_active,
|
||||||
is_alarm: FormData.is_alarm,
|
is_alarm: FormData.is_alarm,
|
||||||
device_id: parseInt(FormData.device_id),
|
device_id: parseInt(FormData.device_id),
|
||||||
device_code: FormData.device_code,
|
|
||||||
device_name: FormData.device_name,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Add sub_section_id only if it's selected
|
||||||
|
if (FormData.sub_section_id) {
|
||||||
|
payload.sub_section_id = parseInt(FormData.sub_section_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug logging
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let response;
|
let response;
|
||||||
|
|
||||||
@@ -185,6 +201,7 @@ const DetailTag = (props) => {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Save Tag Error:', error);
|
console.error('Save Tag Error:', error);
|
||||||
|
console.error('Error details:', error);
|
||||||
NotifAlert({
|
NotifAlert({
|
||||||
icon: 'error',
|
icon: 'error',
|
||||||
title: 'Error',
|
title: 'Error',
|
||||||
@@ -215,8 +232,6 @@ const DetailTag = (props) => {
|
|||||||
setFormData({
|
setFormData({
|
||||||
...FormData,
|
...FormData,
|
||||||
device_id: deviceId,
|
device_id: deviceId,
|
||||||
device_code: selectedDevice?.device_code || '',
|
|
||||||
device_name: selectedDevice?.device_name || '',
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,13 @@ const columns = (showPreviewModal, showEditModal, showDeleteDialog) => [
|
|||||||
key: 'unit',
|
key: 'unit',
|
||||||
width: '8%',
|
width: '8%',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: 'Sub Section',
|
||||||
|
dataIndex: 'sub_section_name',
|
||||||
|
key: 'sub_section_name',
|
||||||
|
width: '12%',
|
||||||
|
render: (text) => text || '-',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: 'Device',
|
title: 'Device',
|
||||||
dataIndex: 'device_name',
|
dataIndex: 'device_name',
|
||||||
|
|||||||
Reference in New Issue
Block a user