import { useEffect, useRef } from 'react'
import './layout.css'
// IIT_DATA 추출
const audServerUrl = window.IIT_DATA.audServerUrl
// 보고서 목록 (데모용 — 실제 보고서 코드로 교체)
const reportList = [
{ name: {좌측에 표시할 보고서 명}, code: {AUD7에 등록된 보고서 코드}, module: {보고서 모듈 코드}, isShow: {타이틀바 표시 여부} },
{ name: 'i-AUD 보고서 호출2', code: 'REP236AB97070714FA3AC22F9DFD00AFFF3', module: 'SD', isShow: false },
]
// 컴포넌트 외부 모듈 스코프에 두는 가변 상태
// (외부 AUD JS 가 직접 DOM 을 조작하므로 React 리렌더링이 필요 없어 useState 대신 plain object 사용)
const state = {
reportInfo: null,
rName: '',
folderCode: '',
description: '',
moduleCode: '',
TemplateCode: '',
reportId: '',
}
// React 18 StrictMode 미사용이지만, 혹시 모를 중복 마운트에 대비한 가드
let initialized = false
function DivViewer() {
const errorRef = useRef({ show: false, message: '' })
useEffect(() => {
if (initialized) return
initialized = true
try {
loadExternalResources(audServerUrl)
winResizer()
if (window.GFN_AUTHORITY && window.GFN_AUTHORITY.UpdateSession) {
window.GFN_AUTHORITY.UpdateSession()
}
const handleResize = () => {
winResizer()
if (window.AUD && window.AUD.GetMainViewer) {
const mainViewer = window.AUD.GetMainViewer()
if (mainViewer && mainViewer.ViewerSizeChanged) mainViewer.ViewerSizeChanged()
}
}
window.addEventListener('resize', handleResize)
return () => window.removeEventListener('resize', handleResize)
} catch (e) {
handleError('초기화 중 오류가 발생했습니다.', e)
}
}, [])
function handleError(message, error) {
errorRef.current = { show: true, message: `${message} (${error.message || error})` }
console.error(message, error)
}
return (
<>
<div className="top_panel"></div>
<div className="left_panel">
<ul>
{reportList.map(report => (
<li key={report.code}>
<div
className="rep_div"
onClick={() => openReport(report.code, report.isShow, report.module)}
>
{report.name}
</div>
</li>
))}
</ul>
</div>
<div className="main_group VisibleFrame">
<div className="titlebg" id="titlebg_main" style={{ display: 'none' }}>
<div className="title_area">
<ul>
<li><span id="dvReportName"></span></li>
</ul>
</div>
<div className="bookmark" id="bookmarkIcon" style={{ display: 'none' }}></div>
<div className="location" style={{ display: 'none' }}></div>
<div className="topbtn_group"></div>
</div>
<div id="AUDview" className="istudio-common-viewer"></div>
</div>
<div className="foot_panel"></div>
</>
)
}
// ─────────────────────────────────────────────────────────────────
// 외부 리소스 로드 (AUD 프레임워크 JS/CSS)
// ─────────────────────────────────────────────────────────────────
function loadExternalResources(serverUrl) {
const head = document.head
const scripts = [
'/AUD/500/js/lib/audframework/debug/bimatrix.lib.audframework.js',
'/AUD/500/js/lib/audframework/debug/bimatrix.module.audframework.js',
'/AUD/500/js/lib/rsa/jsbn.js',
'/AUD/500/js/lib/rsa/prng4.js',
'/AUD/500/js/lib/rsa/rng.js',
'/AUD/500/js/lib/rsa/rsa.js',
'/portal/js/jquery-3.6.0.min.js',
'/portal/js/Base64.js',
'/portal/js/jquery.portal.common.js',
'/portal/js/jquery.cookie.js',
'/portal/js/authorityCheck_em.jsp',
'/portal/js/portal.message.jsp',
'/portal/js/portal.option.data.jsp',
'/portal/js/portal.content.top.js',
'/portal/js/matrix.script.comm.js',
'/portal/js/matrix.script.content.em.js',
'/portal/js/portal.content.bookmark.js',
'/portal/js/portal.content.condition.js',
'/extention/AUD/customscript.jsp',
'/extention/portal/customscript.jsp',
]
const styles = [
'/AUD/500/theme/skin-default/ko/css/bimatrix.module.audframework.css',
'/AUD/500/theme/skin-default/ko/css/ion.rangeSlider.css',
'/extention/AUD/bimatrix.custom.audframework.css',
]
styles.forEach(path => {
const link = document.createElement('link')
link.rel = 'stylesheet'
link.href = serverUrl + path
head.appendChild(link)
})
scripts.forEach(path => {
const script = document.createElement('script')
script.src = serverUrl + path
script.async = false
// GFN_OPTION을 정의하는 스크립트가 로드된 직후 portal 테마 CSS를 동적으로 추가
if (path.endsWith('portal.option.data.jsp')) {
script.onload = () => loadPortalThemeCss(serverUrl)
}
head.appendChild(script)
})
}
function loadPortalThemeCss(serverUrl) {
const opt = window.GFN_OPTION
if (!opt || !opt.PORTAL_THEME_CSS_PATH) return
const root = opt.WEB_ROOTNAME || ''
const baseUrl = (root && serverUrl.endsWith(root))
? serverUrl.slice(0, -root.length)
: serverUrl
const link = document.createElement('link')
link.rel = 'stylesheet'
link.href = `${baseUrl}${opt.PORTAL_THEME_CSS_PATH}/theme.css`
document.head.appendChild(link)
}
// ─────────────────────────────────────────────────────────────────
// 보고서 호출
// ─────────────────────────────────────────────────────────────────
function openReport(code, isTitle, module) {
state.reportId = code
state.moduleCode = module
const PARAM_ARR = [{ KEY: 'VS_TEST', VALUE: 'VS_TEST1_VAL' }]
if (window.AUD) window.AUD.SetCustomParams(PARAM_ARR)
if (window.GFN_AUTHORITY && window.GFN_AUTHORITY.searchReportInfo) {
state.reportInfo = window.GFN_AUTHORITY.searchReportInfo(code)
state.rName = state.reportInfo.name
state.folderCode = state.reportInfo.option.FolderCode
state.description = state.reportInfo.desc
}
if (window.GFN_AUTHORITY && window.GFN_AUTHORITY.USER_AUTH_INFO) window.GFN_AUTHORITY.USER_AUTH_INFO()
if (isTitle) {
const btnType = (window.GFN_OPTION && window.GFN_OPTION.OP04_VIEW_BTN === 'TEXT') ? 'text_type' : 'img_type'
if (window.$ && typeof window.$('.topbtn_group').option_top === 'function') {
window.$('.topbtn_group').option_top('view_btn', {
btn_type: btnType,
callbackFn: settingTitle,
embedded: true,
})
}
} else {
document.querySelector('.titlebg').style.display = 'none'
winResizer()
}
if (module === 'SD') {
if (window.AUD && window.AUD.Init) window.AUD.Init(AudOpenReport)
} else if (module === 'SX') {
window.AUD.ShellModuleCode = 'SX'
if (window.AUD && window.AUD.Init) window.AUD.Init(MetaOpenReport)
}
}
function AudOpenReport() {
if (window.AUD && window.AUD.SetFileDialogCallback) window.AUD.SetFileDialogCallback()
if (window.AUD) window.AUD.LoadDocument('AUDview', state.reportId, 2)
}
function MetaOpenReport() {
const metaInfo = {
META_CODE: state.reportId,
NAME: state.rName,
DESC: state.description,
PARENT: state.folderCode,
TYPE: state.moduleCode,
}
window.AUD.MetaViewManager.IsMetaFileView = true
window.AUD.mViewerId = 'AUDview'
window.AUD.LoadMetaDocument('AUDview', state.reportId, metaInfo)
}
// ─────────────────────────────────────────────────────────────────
// 타이틀 / 메뉴 버튼 셋업 (option_top 콜백)
// ─────────────────────────────────────────────────────────────────
function settingTitle() {
document.querySelector('.titlebg').style.display = ''
const info = state.reportInfo
if (!info) return
if (window.setReportInfo) window.setReportInfo(
info.code,
info.name,
info.desc,
info.module,
info.path,
'',
{ FolderCode: info.option.FolderCode }
)
if (window.menuVisible) window.menuVisible(
info.code,
info.module,
{ AuthNo: info.option.AuthNo },
false
)
const buttons = ['btnEdit', 'btnSaveAs', 'btnExport']
buttons.forEach(id => {
const el = document.getElementById(id)
if (el) el.style.display = 'none'
})
settingReportInfo(info.name)
winResizer()
}
function settingReportInfo(name) {
const el = document.querySelector('.titlebg #dvReportName')
if (!el) return
el.innerText = name
el.classList.add('title_bullet')
const opt = window.GFN_OPTION || {}
const root = opt.WEB_ROOTNAME || ''
const baseUrl = (root && audServerUrl.endsWith(root))
? audServerUrl.slice(0, -root.length)
: audServerUrl
const imgUrl = `${baseUrl}${opt.PORTAL_THEME_IMG_PATH}/tree/tree_iaud.png`
el.style.background = `url('${imgUrl}') 0px 0px no-repeat`
}
// ─────────────────────────────────────────────────────────────────
// 리사이즈 처리
// ─────────────────────────────────────────────────────────────────
function winResizer() {
const win_w = window.innerWidth
const win_h = window.innerHeight
const topPanel = document.querySelector('.top_panel')
const leftPanel = document.querySelector('.left_panel')
const footPanel = document.querySelector('.foot_panel')
const titleBg = document.querySelector('.titlebg')
const viewPanel = document.querySelector('.view_panel')
const audView = document.getElementById('AUDview')
const top_panel_height = (topPanel && topPanel.offsetHeight) || 0
const left_panel_width = (leftPanel && leftPanel.offsetWidth) || 0
const foot_panel_height = (footPanel && footPanel.offsetHeight) || 0
if (leftPanel) {
leftPanel.style.height = `${win_h - top_panel_height}px`
leftPanel.style.top = `${top_panel_height}px`
}
const mainGroup = document.querySelector('.main_group')
if (mainGroup) {
mainGroup.style.height = `${win_h - top_panel_height - foot_panel_height}px`
mainGroup.style.top = `${top_panel_height}px`
mainGroup.style.left = `${left_panel_width}px`
mainGroup.style.width = `${win_w - left_panel_width}px`
}
let title_panel_height = (titleBg && titleBg.offsetHeight) || 0
const isHidden = titleBg && getComputedStyle(titleBg).display === 'none'
if (isHidden) {
title_panel_height = 0
} else {
settingReportTitleWidth()
}
if (viewPanel) {
viewPanel.style.height = `${win_h}px`
viewPanel.style.width = `${win_w}px`
}
if (audView) {
audView.style.top = `${title_panel_height}px`
audView.style.height = `${win_h - top_panel_height - foot_panel_height - title_panel_height}px`
}
}
function settingReportTitleWidth() {
const titleEl = document.querySelector('#titlebg_main')
const topArea = titleEl ? titleEl.querySelector('.topbtn_area') : null
const bullet = titleEl ? titleEl.querySelector('.title_bullet') : null
if (!titleEl || !topArea || !bullet) return
const titlebg_w = titleEl.offsetWidth
const title_topbtn_w = topArea.offsetWidth
const title_reportName_w = titlebg_w - title_topbtn_w
bullet.style.width = `${title_reportName_w}px`
}
export default DivViewer