Compare commits
2 Commits
add-rsab-a
...
1702191d18
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1702191d18 | ||
|
|
9ab6fb405d |
@@ -23,10 +23,9 @@ window.config = {
|
|||||||
// above, the number of requests can be go a lot higher.
|
// above, the number of requests can be go a lot higher.
|
||||||
prefetch: 25,
|
prefetch: 25,
|
||||||
},
|
},
|
||||||
expertise: false, //* Tambahan untuk enable expertise (CustomizableViewportOverlay)
|
expertise_host: `http://192.168.0.137:8080/api/v1/radiology/expertise/image-number`, // API his3 untuk expertise radiologi
|
||||||
expertise_host: `http://192.168.1.90`, // IP ke NV di PACS Server, untuk fetch expertise bawaan versi NV
|
pacs_document_host: `152.42.173.210`, // IP ke NV di PACS Server untuk ambil pdf
|
||||||
pacs_document_host: `192.168.1.90`, // IP ke NV di PACS Server untuk ambil pdf
|
pacs_document_port: 8585,
|
||||||
pacs_document_port: 8080,
|
|
||||||
defaultDataSourceName: 'local-proxy',
|
defaultDataSourceName: 'local-proxy',
|
||||||
dataSources: [
|
dataSources: [
|
||||||
{
|
{
|
||||||
@@ -35,8 +34,9 @@ window.config = {
|
|||||||
configuration: {
|
configuration: {
|
||||||
friendlyName: 'Static WADO Local Data',
|
friendlyName: 'Static WADO Local Data',
|
||||||
name: 'DCM4CHEE',
|
name: 'DCM4CHEE',
|
||||||
qidoRoot: `http://192.168.1.90:5000/rs`, // IP ke dicomweb-proxy PACS Server. URI selalu /rs
|
qidoRoot: `http://152.42.173.210:5000/rs`, // IP ke dicomweb-proxy PACS Server. URI selalu /rs
|
||||||
wadoRoot: `http://192.168.1.90:5000/rs`, // IP ke dicomweb-proxy PACS Server. URI selalu /rs qidoSupportsIncludeField: false,
|
wadoRoot: `http://152.42.173.210:5000/rs`, // IP ke dicomweb-proxy PACS Server. URI selalu /rs
|
||||||
|
qidoSupportsIncludeField: false,
|
||||||
supportsReject: true,
|
supportsReject: true,
|
||||||
supportsStow: true,
|
supportsStow: true,
|
||||||
imageRendering: 'wadors',
|
imageRendering: 'wadors',
|
||||||
@@ -341,7 +341,8 @@ const SidePanel = ({
|
|||||||
fetchAccessionNumber();
|
fetchAccessionNumber();
|
||||||
}, [studyInstanceUID]); // Run when studyInstanceUID changes
|
}, [studyInstanceUID]); // Run when studyInstanceUID changes
|
||||||
|
|
||||||
// Ubah fungsi fetchExpertiseData menjadi dengan parameter accessionNumber
|
const [expertiseError, setExpertiseError] = useState(null);
|
||||||
|
|
||||||
const fetchExpertiseData = async accessionNumber => {
|
const fetchExpertiseData = async accessionNumber => {
|
||||||
try {
|
try {
|
||||||
// Check if window.config.expertise_host exists
|
// Check if window.config.expertise_host exists
|
||||||
@@ -355,46 +356,45 @@ const SidePanel = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsExpertiseLoading(true);
|
accessionNumber = 'MR.251027.001';
|
||||||
const url = `${window.config.expertise_host}/nv/query.php?method=view&AccessionNumber=${encodeURIComponent(accessionNumber)}`;
|
|
||||||
|
|
||||||
// Debuggging
|
setIsExpertiseLoading(true);
|
||||||
// const url = 'http://152.42.173.210/nv/testQueryBase64.php';
|
const url = `${window.config.expertise_host}/${encodeURIComponent(accessionNumber)}`;
|
||||||
|
|
||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
const data = await response.json();
|
const resp = await response.json();
|
||||||
console.log('Study data:', data);
|
console.log('Expertise Resp:', resp);
|
||||||
|
|
||||||
if (data?.study?.expertise && data.study.expertise.length > 0) {
|
if (resp?.error) {
|
||||||
const expertiseItem = { ...data.study.expertise[0] };
|
setExpertiseError(resp.message || resp.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resp?.status_code === 200 && resp?.data) {
|
||||||
|
const expertiseItem = { ...resp.data };
|
||||||
|
|
||||||
// Decode base64 encoded fields
|
// Decode base64 encoded fields
|
||||||
// UTF-8 safe base64 decoding
|
|
||||||
const decodeBase64 = str => {
|
const decodeBase64 = str => {
|
||||||
try {
|
try {
|
||||||
// Step 1: decode base64 to binary
|
|
||||||
const binary = atob(str);
|
const binary = atob(str);
|
||||||
// Step 2: create a Uint8Array from the binary string
|
|
||||||
const bytes = new Uint8Array(binary.length);
|
const bytes = new Uint8Array(binary.length);
|
||||||
for (let i = 0; i < binary.length; i++) {
|
for (let i = 0; i < binary.length; i++) {
|
||||||
bytes[i] = binary.charCodeAt(i);
|
bytes[i] = binary.charCodeAt(i);
|
||||||
}
|
}
|
||||||
// Step 3: decode the Uint8Array as UTF-8
|
|
||||||
return new TextDecoder('utf-8').decode(bytes);
|
return new TextDecoder('utf-8').decode(bytes);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Error decoding base64 string:', e);
|
console.error('Error decoding base64 string:', e);
|
||||||
return str; // Return original if decoding fails
|
return str;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Decode known base64 fields
|
// Decode known base64 fields
|
||||||
if (expertiseItem.expertise) {
|
if (expertiseItem.ekspertiseResult) {
|
||||||
expertiseItem.expertise = decodeBase64(expertiseItem.expertise);
|
expertiseItem.ekspertiseResult = decodeBase64(expertiseItem.ekspertiseResult);
|
||||||
}
|
}
|
||||||
if (expertiseItem.radiologist) {
|
if (expertiseItem.radiologist) {
|
||||||
expertiseItem.radiologist = decodeBase64(expertiseItem.radiologist);
|
expertiseItem.radiologist = decodeBase64(expertiseItem.radiologist);
|
||||||
}
|
}
|
||||||
// Add any other fields that might be base64 encoded
|
|
||||||
|
|
||||||
setExpertiseData(expertiseItem);
|
setExpertiseData(expertiseItem);
|
||||||
}
|
}
|
||||||
@@ -416,83 +416,45 @@ const SidePanel = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (expertiseError) {
|
||||||
|
return (
|
||||||
|
<ScrollArea className="border-input bg-background h-[500px] w-full rounded-md border py-2 px-3 text-base text-white">
|
||||||
|
<h3 className="mb-4 text-lg font-bold">Expertise</h3>
|
||||||
|
<p className="text-red-500">{expertiseError}</p>
|
||||||
|
</ScrollArea>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (!expertiseData) {
|
if (!expertiseData) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const parseExpertise = text => {
|
|
||||||
if (!text) return {};
|
|
||||||
|
|
||||||
const result = {};
|
|
||||||
let currentSection = 'Keterangan';
|
|
||||||
|
|
||||||
// Split expertise text by lines and process each line
|
|
||||||
const lines = text.split('\r\n').filter(line => line.trim() !== '');
|
|
||||||
|
|
||||||
lines.forEach(line => {
|
|
||||||
// Check if this is a section header
|
|
||||||
if (line.includes(':') && !line.trim().startsWith('-')) {
|
|
||||||
const parts = line.split(':');
|
|
||||||
currentSection = parts[0].trim();
|
|
||||||
const value = parts[1]?.trim() || '';
|
|
||||||
|
|
||||||
if (value) {
|
|
||||||
if (!result[currentSection]) {
|
|
||||||
result[currentSection] = [];
|
|
||||||
}
|
|
||||||
result[currentSection].push(value);
|
|
||||||
}
|
|
||||||
} else if (line.toLowerCase().includes('kesan')) {
|
|
||||||
currentSection = 'Kesan';
|
|
||||||
} else {
|
|
||||||
// Add line to current section
|
|
||||||
if (!result[currentSection]) {
|
|
||||||
result[currentSection] = [];
|
|
||||||
}
|
|
||||||
result[currentSection].push(line.trim());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
const parsedSections = parseExpertise(expertiseData.expertise);
|
|
||||||
|
|
||||||
// Create formatted data structure
|
// Create formatted data structure
|
||||||
const formattedData = [
|
const formattedData = [
|
||||||
{ label: 'Dokter Pengirim', value: expertiseData.ordering_physician || '' },
|
{ label: 'Dokter Pengirim', value: expertiseData.orderingPhysician || '' },
|
||||||
{ label: 'Dokter Radiologis', value: expertiseData.radiologist || '' },
|
{ label: 'Dokter Radiologis', value: expertiseData.radiologist || '' },
|
||||||
{ label: 'Waktu Expertise', value: expertiseData.expertise_dttm || '' },
|
{ label: 'Waktu Expertise', value: expertiseData.expertiseDttm || '' },
|
||||||
];
|
];
|
||||||
|
|
||||||
// Add additional sections from parsed text
|
|
||||||
Object.entries(parsedSections).forEach(([key, value]) => {
|
|
||||||
formattedData.push({
|
|
||||||
label: key,
|
|
||||||
value: Array.isArray(value) ? value : [value],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollArea className="border-input bg-background h-[500px] w-full rounded-md border p-2 text-sm text-white">
|
<ScrollArea className="border-input bg-background h-[800px] w-full rounded-md border py-2 px-3 text-base text-white">
|
||||||
<h3 className="mb-4 text-lg font-bold">Expertise</h3>
|
<h3 className="mb-4 text-xl font-bold">Expertise</h3>
|
||||||
{formattedData.map((section, index) => (
|
{formattedData.map((section, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className="mb-4"
|
className="mb-4"
|
||||||
>
|
>
|
||||||
<h5 className="text-base font-bold">{section.label}:</h5>
|
<h5 className="text-lg font-bold">{section.label}:</h5>
|
||||||
{Array.isArray(section.value) ? (
|
<p className="break-words">{section.value}</p>
|
||||||
<ul className="list-disc pl-6">
|
|
||||||
{section.value.map((item, idx) => (
|
|
||||||
<li key={idx}>{item}</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
) : (
|
|
||||||
<p className="break-words">{section.value}</p>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
<div className="mb-4">
|
||||||
|
<h5 className="text-lg font-bold">Hasil Expertise:</h5>
|
||||||
|
<div
|
||||||
|
className="leading-6"
|
||||||
|
dangerouslySetInnerHTML={{ __html: expertiseData.ekspertiseResult || '' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user