diff --git a/src/pages/history/report/IndexReport.jsx b/src/pages/history/report/IndexReport.jsx
index 4a26478..00a4149 100644
--- a/src/pages/history/report/IndexReport.jsx
+++ b/src/pages/history/report/IndexReport.jsx
@@ -8,54 +8,33 @@ import dayjs from 'dayjs';
const { Text } = Typography;
-// Line Chart Data (same as IndexTrending) converted to table format
-const lineChartData = [
+// New data structure for tag history
+const tagHistoryData = [
{
- id: 'Compressor Section 1',
+ tag: 'TEMP_SENSOR_1',
color: '#FF6B4A',
- data: [
- { x: 'Jan', y: 15 },
- { x: 'Feb', y: 18 },
- { x: 'Mar', y: 17 },
- { 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 },
+ history: [
+ { timestamp: '2025-10-09 08:00', value: 75 },
+ { timestamp: '2025-10-09 08:05', value: 76 },
+ { timestamp: '2025-10-09 08:10', value: 75 },
],
},
{
- id: 'Compressor Section 2',
+ tag: 'GAS_LEAK_SENSOR_1',
color: '#4ECDC4',
- data: [
- { x: 'Jan', y: 12 },
- { x: 'Feb', y: 14 },
- { x: 'Mar', y: 19 },
- { 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 },
+ history: [
+ { timestamp: '2025-10-09 08:00', value: 10 },
+ { timestamp: '2025-10-09 08:05', value: 150 },
+ { timestamp: '2025-10-09 08:10', value: 12 },
],
},
{
- id: 'Compressor Section 3',
+ tag: 'PRESSURE_SENSOR_1',
color: '#FFE66D',
- data: [
- { x: 'Jan', y: 8 },
- { x: 'Feb', y: 10 },
- { x: 'Mar', y: 12 },
- { 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 },
+ history: [
+ { timestamp: '2025-10-09 08:00', value: 1.2 },
+ { timestamp: '2025-10-09 08:05', value: 1.3 },
+ { timestamp: '2025-10-09 08:10', value: 1.2 },
],
},
];
@@ -67,7 +46,7 @@ const IndexReport = memo(function IndexReport() {
const [plantSubSection, setPlantSubSection] = useState('Semua Plant');
const [startDate, setStartDate] = useState(dayjs('2025-09-30'));
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 [roleLevel, setRoleLevel] = useState(null);
@@ -120,63 +99,53 @@ const IndexReport = memo(function IndexReport() {
setPlantSubSection('Semua Plant');
setStartDate(dayjs('2025-09-30'));
setEndDate(dayjs('2025-10-09'));
- setPeriode('Bulanan');
+ setPeriode('30 Menit');
};
// Check if user has permission to view data (all except guest)
const canViewData = userRole && userRole !== 'guest';
- // Convert chart data to table format
+ // Convert tag history data to table format
const convertToTableData = () => {
- return lineChartData.map((section, index) => {
- const rowData = {
- key: index,
- section: section.id,
- color: section.color,
- };
+ const timestamps = {}; // Use an object to collect data per timestamp
- // Add each month's data as a column
- section.data.forEach((point) => {
- rowData[point.x] = point.y;
+ tagHistoryData.forEach((tagData) => {
+ tagData.history.forEach((point) => {
+ if (!timestamps[point.timestamp]) {
+ timestamps[point.timestamp] = {
+ key: point.timestamp,
+ 'Date and Time': point.timestamp,
+ };
+ }
+ timestamps[point.timestamp][tagData.tag] = point.value;
});
-
- return rowData;
});
+
+ // Convert the object to an array
+ return Object.values(timestamps);
};
const tableData = convertToTableData();
- // Create dynamic columns based on months
- const months = lineChartData[0]?.data.map((point) => point.x) || [];
+ // Create dynamic columns based on tags
+ const tags = tagHistoryData.map((tagData) => tagData.tag);
const columns = [
{
- title: 'Plant Sub Section',
- dataIndex: 'section',
- key: 'section',
+ title: 'Date and Time',
+ dataIndex: 'Date and Time',
+ key: 'Date and Time',
fixed: 'left',
- width: 200,
- render: (text, record) => (
-
- ),
+ width: 180,
+ render: (text) => {text},
},
- ...months.map((month) => ({
- title: month,
- dataIndex: month,
- key: month,
+ ...tags.map((tag) => ({
+ title: tag,
+ dataIndex: tag,
+ key: tag,
align: 'center',
- width: 80,
- render: (value) => {value},
+ width: 150,
+ render: (value) => {value !== undefined ? value : '-'},
})),
];
@@ -242,9 +211,10 @@ const IndexReport = memo(function IndexReport() {
onChange={setPeriode}
style={{ width: '100%', marginTop: '4px' }}
options={[
- { value: 'Harian', label: 'Harian' },
- { value: 'Mingguan', label: 'Mingguan' },
- { value: 'Bulanan', label: 'Bulanan' },
+ { value: '5 Menit', label: '5 Menit' },
+ { value: '10 Menit', label: '10 Menit' },
+ { value: '30 Menit', label: '30 Menit' },
+ { value: '1 Jam', label: '1 Jam' },
]}
/>
@@ -272,9 +242,8 @@ const IndexReport = memo(function IndexReport() {
-
{/* Table Section */}
- {!canViewData ? (
+ {/* {!canViewData ? (
Anda tidak memiliki akses untuk melihat data report.
@@ -282,22 +251,22 @@ const IndexReport = memo(function IndexReport() {
Silakan hubungi administrator untuk mendapatkan akses.
- ) : (
-
-
-
- ☰ Trending Error per Plant Sub Section
-
-
-
-
- )}
+ ) : ( */}
+
+
+
+ ☰ History Report
+
+
+
+
+ {/* )} */}
);
diff --git a/src/pages/history/trending/IndexTrending.jsx b/src/pages/history/trending/IndexTrending.jsx
index f61edd7..83e1cb0 100644
--- a/src/pages/history/trending/IndexTrending.jsx
+++ b/src/pages/history/trending/IndexTrending.jsx
@@ -17,7 +17,7 @@ const IndexTrending = memo(function IndexTrending() {
const [plantSubSection, setPlantSubSection] = useState('Semua Plant');
const [startDate, setStartDate] = useState(dayjs('2025-09-30'));
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 [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',
data: [
- { x: 'Jan', y: 15 },
- { x: 'Feb', y: 18 },
- { x: 'Mar', y: 17 },
- { 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 },
+ { y: '08:00', x: 75 },
+ { y: '08:05', x: 76 },
+ { y: '08:10', x: 75 },
+ { y: '08:15', x: 77 },
+ { y: '08:20', x: 76 },
+ { y: '08:25', x: 78 },
+ { y: '08:30', x: 79 },
],
},
{
- id: 'Compressor Section 2',
+ id: 'GAS_LEAK_SENSOR_1',
color: '#4ECDC4',
data: [
- { x: 'Jan', y: 12 },
- { x: 'Feb', y: 14 },
- { x: 'Mar', y: 19 },
- { 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 },
+ { y: '08:00', x: 10 },
+ { y: '08:05', x: 150 },
+ { y: '08:10', x: 40 },
+ { y: '08:15', x: 20 },
+ { y: '08:20', x: 15 },
+ { y: '08:25', x: 18 },
+ { y: '08:30', x: 25 },
],
},
{
- id: 'Compressor Section 3',
+ id: 'PRESSURE_SENSOR_1',
color: '#FFE66D',
data: [
- { x: 'Jan', y: 8 },
- { x: 'Feb', y: 10 },
- { x: 'Mar', y: 12 },
- { 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 },
+ { y: '08:00', x: 1.2 },
+ { y: '08:05', x: 1.3 },
+ { y: '08:10', x: 1.2 },
+ { y: '08:15', x: 1.4 },
+ { y: '08:20', x: 1.5 },
+ { y: '08:25', x: 1.3 },
+ { y: '08:30', x: 1.2 },
],
},
];
- 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 = () => {
setPlantSubSection('Semua Plant');
setStartDate(dayjs('2025-09-30'));
setEndDate(dayjs('2025-10-09'));
- setPeriode('Bulanan');
+ setPeriode('10 Menit');
};
// Check if user has permission to view data (all except guest)
@@ -204,9 +178,10 @@ const IndexTrending = memo(function IndexTrending() {
onChange={setPeriode}
style={{ width: '100%', marginTop: '4px' }}
options={[
- { value: 'Harian', label: 'Harian' },
- { value: 'Mingguan', label: 'Mingguan' },
- { value: 'Bulanan', label: 'Bulanan' },
+ { value: '5 Menit', label: '5 Menit' },
+ { value: '10 Menit', label: '10 Menit' },
+ { value: '30 Menit', label: '30 Menit' },
+ { value: '1 Jam', label: '1 Jam' },
]}
/>
@@ -234,9 +209,8 @@ const IndexTrending = memo(function IndexTrending() {
-
{/* Charts Section */}
- {!canViewData ? (
+ {/* {!canViewData ? (
Anda tidak memiliki akses untuk melihat data trending.
@@ -244,64 +218,78 @@ const IndexTrending = memo(function IndexTrending() {
Silakan hubungi administrator untuk mendapatkan akses.
- ) : (
- <>
-
- {/* Line Chart */}
-
-
-
-
- ☰ Trending Error per Plant Sub Section
-
-
-
-
-
-
-
-
- >
- )}
+ ) : ( */}
+ <>
+
+ {/* Line Chart */}
+
+
+
+
+ ☰ Tag Value Trending
+
+
+
+
+
+
+
+
+ >
+ {/* )} */}
);
});
diff --git a/src/pages/master/device/component/DetailDevice.jsx b/src/pages/master/device/component/DetailDevice.jsx
index ba9e858..b8fb6d3 100644
--- a/src/pages/master/device/component/DetailDevice.jsx
+++ b/src/pages/master/device/component/DetailDevice.jsx
@@ -26,7 +26,7 @@ const DetailDevice = (props) => {
device_id: '',
device_code: '',
device_name: '',
- device_status: true,
+ is_active: true,
device_location: 'Building A',
device_description: '',
ip_address: '',
@@ -139,7 +139,7 @@ const DetailDevice = (props) => {
// Backend validation schema doesn't include device_code
const payload = {
device_name: FormData.device_name,
- device_status: FormData.device_status,
+ is_active: FormData.is_active,
device_location: FormData.device_location,
ip_address: FormData.ip_address,
};
@@ -211,11 +211,10 @@ const DetailDevice = (props) => {
const isChecked = event;
setFormData({
...FormData,
- device_status: isChecked ? true : false,
+ is_active: isChecked ? true : false,
});
};
-
useEffect(() => {
const token = localStorage.getItem('token');
if (token) {
@@ -312,16 +311,14 @@ const DetailDevice = (props) => {
disabled={props.readOnly}
style={{
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}
/>
-
- {FormData.device_status === true ? 'Running' : 'Offline'}
-
+ {FormData.is_active === true ? 'Running' : 'Offline'}
diff --git a/src/pages/master/tag/component/DetailTag.jsx b/src/pages/master/tag/component/DetailTag.jsx
index 3863ae6..1e4154c 100644
--- a/src/pages/master/tag/component/DetailTag.jsx
+++ b/src/pages/master/tag/component/DetailTag.jsx
@@ -16,7 +16,7 @@ const DetailTag = (props) => {
const defaultData = {
tag_id: '',
- tag_code: '',
+
tag_name: '',
tag_number: '',
data_type: '',
@@ -24,8 +24,7 @@ const DetailTag = (props) => {
is_active: true,
is_alarm: false,
device_id: null,
- device_code: '',
- device_name: '',
+
sub_section_id: null,
};
@@ -118,6 +117,18 @@ const DetailTag = (props) => {
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() === '') {
NotifOk({
icon: 'warning',
@@ -141,17 +152,22 @@ const DetailTag = (props) => {
// Prepare payload berdasarkan backend validation schema
const payload = {
- tag_name: FormData.tag_name,
+ tag_name: FormData.tag_name.trim(),
tag_number: parseInt(FormData.tag_number),
data_type: FormData.data_type,
- unit: FormData.unit,
+ unit: FormData.unit.trim(),
is_active: FormData.is_active,
is_alarm: FormData.is_alarm,
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 {
let response;
@@ -185,6 +201,7 @@ const DetailTag = (props) => {
}
} catch (error) {
console.error('Save Tag Error:', error);
+ console.error('Error details:', error);
NotifAlert({
icon: 'error',
title: 'Error',
@@ -215,8 +232,6 @@ const DetailTag = (props) => {
setFormData({
...FormData,
device_id: deviceId,
- device_code: selectedDevice?.device_code || '',
- device_name: selectedDevice?.device_name || '',
});
};
diff --git a/src/pages/master/tag/component/ListTag.jsx b/src/pages/master/tag/component/ListTag.jsx
index 270561e..2451e71 100644
--- a/src/pages/master/tag/component/ListTag.jsx
+++ b/src/pages/master/tag/component/ListTag.jsx
@@ -51,6 +51,13 @@ const columns = (showPreviewModal, showEditModal, showDeleteDialog) => [
key: 'unit',
width: '8%',
},
+ {
+ title: 'Sub Section',
+ dataIndex: 'sub_section_name',
+ key: 'sub_section_name',
+ width: '12%',
+ render: (text) => text || '-',
+ },
{
title: 'Device',
dataIndex: 'device_name',