Files
MBN_STOCK_WEBVIEW/Web/index.html

213 lines
13 KiB
HTML

<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; connect-src 'none'; object-src 'none'; base-uri 'none'; form-action 'none'">
<title>MBN Stock WebView</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="app-shell">
<aside class="sidebar" aria-label="주요 메뉴">
<div class="brand-block">
<div class="brand-mark">M</div>
<div>
<strong>MBN STOCK</strong>
<span>방송 그래픽 콘솔</span>
</div>
</div>
<nav id="marketNav" class="market-nav">
<button class="nav-item active" data-market="dashboard"><span></span>대시보드</button>
<button class="nav-item" data-market="overseas"><span></span>해외</button>
<button class="nav-item" data-market="exchange"><span></span>환율</button>
<button class="nav-item" data-market="index"><span></span>지수</button>
<button class="nav-item" data-market="kospi"><span>K</span>코스피</button>
<button class="nav-item" data-market="kosdaq"><span>Q</span>코스닥</button>
<button class="nav-item" data-market="compare"><span></span>비교</button>
<button class="nav-item" data-market="theme"><span></span>테마</button>
<button class="nav-item" data-market="expert"><span></span>전문가</button>
<button class="nav-item" data-market="halted"><span></span>정지</button>
</nav>
<div class="sidebar-status">
<div class="status-row"><span class="status-dot ok"></span><span>Native Bridge</span><strong id="bridgeState">연결 중</strong></div>
<div class="status-row"><span id="databaseStateDot" class="status-dot pending"></span><span>Database</span><strong id="databaseState">확인 중</strong></div>
<div class="runtime" id="runtimeLabel">.NET 8 · WinUI 3 · x64</div>
</div>
</aside>
<main class="workspace">
<header class="workspace-header">
<div>
<p class="eyebrow">OPERATOR WORKSPACE</p>
<h1 id="workspaceTitle">마이그레이션 대시보드</h1>
</div>
<div class="header-meta">
<div><span>현재 시각</span><strong id="clock">--:--:--</strong></div>
<div><span>패키지</span><strong id="packageLabel">MSIX</strong></div>
<button id="requestInfoButton" class="ghost-button" type="button">상태 새로고침</button>
</div>
</header>
<section class="summary-strip" aria-label="마이그레이션 상태">
<article><span class="metric-icon mint"></span><div><strong>WebView UI</strong><small>FarPoint 대체 기반</small></div><b>READY</b></article>
<article><span class="metric-icon blue">71</span><div><strong>데이터 요청</strong><small>기존 SQL 계층 이관</small></div><b>MIGRATED</b></article>
<article id="databaseSummary"><span id="databaseSummaryIcon" class="metric-icon amber">DB</span><div><strong>Oracle · MariaDB</strong><small id="databaseSummaryDetail">연결 상태 확인 중</small></div><b id="databaseSummaryBadge">CHECKING</b></article>
<article id="playoutSummary" class="playout-summary"><span id="playoutSummaryIcon" class="metric-icon violet">T2</span><div><strong>Tornado Engine</strong><small id="playoutSummaryDetail">상태 확인 중</small></div><b id="playoutSummaryBadge">CHECKING</b></article>
</section>
<div class="console-grid">
<section class="panel catalog-panel">
<div class="panel-header">
<div><p class="panel-kicker">CUT CATALOG</p><h2>그래픽 항목</h2></div>
<span id="catalogModeBadge" class="badge">Web UI</span>
</div>
<label class="search-box">
<span></span>
<input id="catalogSearch" type="search" autocomplete="off" placeholder="종목·지수·그래픽 검색">
<kbd>Ctrl K</kbd>
</label>
<div id="catalogTabs" class="catalog-tabs" role="tablist">
<button class="active" type="button" data-category="all">전체</button>
<button type="button" data-category="plate"></button>
<button type="button" data-category="chart">차트</button>
<button type="button" data-category="market">시장</button>
</div>
<section id="liveDataPanel" class="live-data-panel" aria-labelledby="liveDataTitle" hidden>
<div class="live-data-header">
<div>
<p class="panel-kicker">LIVE DATABASE</p>
<h3 id="liveDataTitle">실시간 시장 데이터</h3>
</div>
<button id="retryLiveDataButton" class="live-retry" type="button">다시 조회</button>
</div>
<div id="databaseSources" class="database-sources" aria-label="데이터베이스 연결 상태"></div>
<div id="liveDataState" class="live-data-state" role="status" aria-live="polite"></div>
<div id="liveDataTables" class="live-data-tables"></div>
</section>
<div id="catalogList" class="catalog-list" aria-live="polite"></div>
</section>
<section class="panel playlist-panel">
<div class="panel-header">
<div><p class="panel-kicker">PLAYLIST</p><h2>송출 순서</h2></div>
<span id="playlistCount" class="badge neutral">0 CUTS</span>
</div>
<div class="playlist-actions">
<button id="selectAllButton" type="button">전체 선택</button>
<button id="moveUpButton" type="button" title="선택 항목 위로"></button>
<button id="moveDownButton" type="button" title="선택 항목 아래로"></button>
<button id="deleteButton" class="danger" type="button">삭제</button>
<span></span>
<button id="loadButton" type="button">불러오기</button>
<button id="saveButton" class="primary-soft" type="button">저장</button>
</div>
<div class="table-wrap">
<table>
<thead><tr><th class="check-cell"></th><th class="number-cell">#</th><th>그래픽 컷</th><th>구분</th><th class="drag-cell">정렬</th></tr></thead>
<tbody id="playlistBody"></tbody>
</table>
<div id="playlistEmpty" class="empty-state">
<strong>플레이리스트가 비어 있습니다.</strong>
<span>왼쪽 항목의 + 버튼으로 송출 순서를 구성하세요.</span>
</div>
</div>
</section>
<section class="panel playout-panel">
<div class="panel-header">
<div><p class="panel-kicker">PROGRAM / PREVIEW</p><h2>송출 제어</h2></div>
<span id="playoutState" class="badge neutral">IDLE</span>
</div>
<div class="playout-health" aria-label="Tornado 송출 연결 상태">
<div class="playout-health-item">
<span id="tornadoProcessDot" class="status-dot pending"></span>
<small>Tornado2 Process</small>
<strong id="tornadoProcessState">확인 중</strong>
</div>
<div class="playout-health-item">
<span id="playoutConnectionDot" class="status-dot pending"></span>
<small>Engine</small>
<strong id="playoutConnectionState">확인 중</strong>
</div>
<div class="playout-health-item safety">
<small>Safety Mode</small>
<strong id="playoutSafetyMode">확인 중</strong>
</div>
</div>
<div id="playoutStatusMessage" class="playout-status-message" role="status" aria-live="polite">송출 어댑터 상태를 확인하고 있습니다.</div>
<div class="playout-page-state" aria-label="장면 및 페이지 상태">
<span>SCENE <strong id="playoutSceneCode"></strong></span>
<span>ENTRY <strong id="playoutEntryId"></strong></span>
<span>BUILDER <strong id="playoutBuilderKey"></strong></span>
<span>PAGE <strong id="playoutPageNumber"></strong></span>
<span>PAGE SIZE <strong id="playoutPageSize"></strong></span>
<span>TOTAL ROWS <strong id="playoutItemCount">0</strong></span>
<span>PAGE ROWS <strong id="playoutCurrentRows">0</strong></span>
<span>LAST PAGE <strong id="playoutLastPage">YES</strong></span>
<span>NEXT <strong id="playoutNextKind">NONE</strong></span>
<span>REFRESH <strong id="playoutRefreshState">STOPPED</strong></span>
</div>
<div id="playoutError" class="playout-error" role="alert" hidden>
<div><strong>송출 명령 오류</strong><span id="playoutErrorMessage"></span></div>
<button id="clearPlayoutErrorButton" type="button" aria-label="송출 오류 닫기">닫기</button>
</div>
<div class="preview-stage" id="previewStage">
<div class="safe-area">
<span>PREVIEW</span>
<strong id="previewTitle">선택된 그래픽 없음</strong>
<small id="previewSubtitle">플레이리스트 항목을 선택하세요.</small>
</div>
<div class="stage-corner top-left"></div><div class="stage-corner top-right"></div>
<div class="stage-corner bottom-left"></div><div class="stage-corner bottom-right"></div>
</div>
<section class="scene-data-preview" aria-label="실제 장면 DTO mutation 미리보기">
<div class="scene-data-preview-header"><strong>SCENE DATA</strong><span>asset 경로는 숨김 처리</span></div>
<div id="sceneDataPreview" class="scene-data-preview-body"></div>
</section>
<form id="sceneSelectionForm" class="scene-selection-form" autocomplete="off">
<label>CUT ALIAS<select id="sceneCutAlias" aria-label="CUT alias"></select></label>
<label>GROUP<input id="sceneGroupCode" maxlength="256" list="sceneGroupOptions" placeholder="KOSPI_STOCK"></label>
<label>SUBJECT<input id="sceneSubject" maxlength="256" placeholder="종목명 또는 지수명"></label>
<label>GRAPHIC<input id="sceneGraphicType" maxlength="256" placeholder="MA5,MA20 등 닫힌 옵션"></label>
<label>SUBTYPE<input id="sceneSubtype" maxlength="256" list="sceneSubtypeOptions" placeholder="PRICE"></label>
<label>DATA CODE<input id="sceneDataCode" maxlength="256" placeholder="종목·업종 코드"></label>
<label>FADE<input id="sceneFadeDuration" type="number" min="0" max="60" step="1" value="6"></label>
<button id="applySceneSelectionButton" type="submit">조회값 적용</button>
<datalist id="sceneGroupOptions">
<option value="KOSPI_INDEX"></option><option value="KOSDAQ_INDEX"></option>
<option value="KOSPI200_INDEX"></option><option value="KRX100_INDEX"></option>
<option value="FUTURES_INDEX"></option><option value="KOSPI_INDUSTRY"></option>
<option value="KOSDAQ_INDUSTRY"></option><option value="FOREIGN_INDEX"></option>
<option value="FOREIGN_STOCK"></option><option value="KOSPI_STOCK"></option>
<option value="KOSDAQ_STOCK"></option><option value="NXT_KOSPI"></option>
<option value="NXT_KOSDAQ"></option>
</datalist>
<datalist id="sceneSubtypeOptions">
<option value="PRICE"></option><option value="EXPECTED"></option>
<option value="VOLUME"></option><option value="TRADING_HALT"></option>
</datalist>
</form>
<div class="playout-controls">
<button id="prepareButton" class="prepare" type="button"><span>F2</span>PREPARE</button>
<button id="takeInButton" class="take-in" type="button"><span>F8</span>TAKE IN</button>
<button id="nextButton" type="button"><span></span>NEXT</button>
<button id="takeOutButton" class="take-out" type="button"><span>ESC</span>TAKE OUT</button>
</div>
<div class="event-log">
<div class="event-log-header"><strong>운영 로그</strong><button id="clearLogButton" type="button">지우기</button></div>
<ol id="eventLog"></ol>
</div>
</section>
</div>
</main>
</div>
<div id="toast" class="toast" role="status" aria-live="polite"></div>
<script src="playout-safety.js"></script>
<script src="app.js"></script>
</body>
</html>