Files
MBN_STOCK_WEBVIEW/Web/index.html

584 lines
37 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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">
<link rel="stylesheet" href="manual-lists-ui.css">
<link rel="stylesheet" href="manual-financial-ui.css">
<link rel="stylesheet" href="operator-catalog-ui.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" data-market="dashboard"><span></span>대시보드</button>
<button class="nav-item active" 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="foreign-stock"><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 stock-panel">
<div class="panel-header">
<div><p class="panel-kicker">LEGACY STOCK INPUT</p><h2>종목 검색 · 31개 컷</h2></div>
<span class="badge">항상 표시</span>
</div>
<section id="stockWorkflow" class="stock-workflow" aria-labelledby="stockWorkflowTitle">
<div class="stock-workflow-header">
<div>
<p class="panel-kicker">LEGACY STOCK WORKFLOW</p>
<h3 id="stockWorkflowTitle">종목 검색</h3>
</div>
<div class="stock-workflow-tools">
<span id="stockSearchBadge" class="badge neutral">DB SEARCH</span>
<button id="stockWorkflowToggle" type="button" aria-expanded="true">접기</button>
</div>
</div>
<form id="stockSearchForm" class="stock-search-form" autocomplete="off">
<label for="stockSearchInput" class="visually-hidden">종목명</label>
<input id="stockSearchInput" type="search" maxlength="64" placeholder="예: 삼성" spellcheck="false">
<button id="stockSearchButton" type="submit">검색</button>
</form>
<div id="stockSearchState" class="stock-search-state" role="status" aria-live="polite">종목명을 입력하고 Enter를 누르세요.</div>
<div id="stockSearchResults" class="stock-search-results" role="listbox" aria-label="종목 검색 결과"></div>
<div id="selectedStock" class="selected-stock" hidden>
<span>선택 종목</span>
<strong id="selectedStockName"></strong>
<small id="selectedStockMeta"></small>
</div>
<div class="stock-cut-header">
<div><strong>종목용 컷</strong><small>더블클릭 또는 + 버튼으로 추가</small></div>
<label><input id="stockMa5" type="checkbox" checked>5일선</label>
<label><input id="stockMa20" type="checkbox" checked>20일선</label>
</div>
<div class="stock-cut-selection-tools">
<span id="stockCutSelectionCount" role="status" aria-live="polite">0개 선택</span>
<button id="stockCutBatchAdd" type="button">선택 컷 추가</button>
<button id="stockCutSelectionClear" type="button">선택 해제</button>
</div>
<div id="stockCutList" class="stock-cut-list" role="listbox"
aria-label="종목용 컷 목록" aria-multiselectable="true"></div>
<div id="manualStockActions" class="manual-stock-actions" aria-label="수동 재무 데이터"></div>
</section>
</section>
<section class="panel catalog-panel">
<div class="panel-header">
<div><p class="panel-kicker">OPERATOR INPUT</p><h2>업무별 그래픽 선택</h2></div>
<span id="catalogModeBadge" class="badge">Web UI</span>
</div>
<section id="legacyFixedWorkflow" class="legacy-fixed-workflow" aria-labelledby="legacyFixedWorkflowTitle" hidden>
<div class="legacy-fixed-header">
<div>
<p class="panel-kicker">LEGACY RUNTIME CATALOG</p>
<h3 id="legacyFixedWorkflowTitle">원본 운영 항목</h3>
</div>
<div class="legacy-fixed-tools">
<span id="legacyFixedCount" class="badge neutral">0 ACTIONS</span>
<button id="legacyFixedToggle" type="button" aria-expanded="true">접기</button>
</div>
</div>
<label class="legacy-fixed-search">
<span></span>
<input id="legacyFixedSearch" type="search" maxlength="64" autocomplete="off" placeholder="원본 항목 검색">
</label>
<div id="legacyFixedState" class="legacy-fixed-state" role="status" aria-live="polite"></div>
<div id="legacyFixedSections" class="legacy-fixed-sections" aria-label="원본 운영 항목"></div>
</section>
<section id="industryWorkflow" class="industry-workflow" aria-labelledby="industryWorkflowTitle" hidden>
<div class="industry-workflow-header">
<div>
<p class="panel-kicker">LEGACY INDUSTRY WORKFLOW</p>
<h3 id="industryWorkflowTitle">업종 선택</h3>
</div>
<div class="industry-workflow-tools">
<span id="industryCount" class="badge neutral">DB</span>
<button id="industryRetry" type="button">다시 조회</button>
<button id="industryWorkflowToggle" type="button" aria-expanded="true">접기</button>
</div>
</div>
<label class="industry-search">
<span></span>
<input id="industrySearch" type="search" maxlength="64" autocomplete="off" placeholder="업종명 검색">
</label>
<div id="industryState" class="industry-state" role="status" aria-live="polite"></div>
<div id="industryResults" class="industry-results" role="listbox" aria-label="업종 목록"></div>
<div class="industry-pair" aria-label="업종 비교 선택">
<div><span>첫 번째</span><strong id="industryPrimary">선택 없음</strong></div>
<button id="industrySwap" type="button" title="두 업종 순서 교환"></button>
<div><span>두 번째</span><strong id="industrySecondary">선택 없음</strong></div>
<button id="industryClear" type="button">초기화</button>
</div>
<div id="industryCutList" class="industry-cut-list" aria-label="업종용 컷 목록"></div>
</section>
<section id="comparisonWorkflow" class="comparison-workflow" aria-labelledby="comparisonWorkflowTitle" hidden>
<div class="comparison-workflow-header">
<div>
<p class="panel-kicker">LEGACY COMPARISON WORKFLOW</p>
<h3 id="comparisonWorkflowTitle">종목 비교</h3>
</div>
<div class="comparison-import-actions">
<button id="comparisonImportLegacy" type="button">원본 비교쌍 가져오기</button>
<span id="comparisonPairCount" class="badge neutral">0 PAIRS</span>
</div>
</div>
<div id="comparisonSourceTabs" class="comparison-source-tabs" role="tablist" aria-label="비교 대상 종류">
<button type="button" class="active" data-comparison-source="domestic">국내·NXT</button>
<button type="button" data-comparison-source="fixed">지수·환율</button>
<button type="button" data-comparison-source="world">해외 종목</button>
</div>
<section id="comparisonDomesticPanel" class="comparison-source-panel">
<form id="comparisonDomesticSearchForm" class="comparison-search-form" autocomplete="off">
<input id="comparisonDomesticSearch" type="search" maxlength="64" placeholder="국내·NXT 종목명" aria-label="국내·NXT 종목명">
<button id="comparisonDomesticSearchButton" type="submit">검색</button>
</form>
<div id="comparisonDomesticState" class="comparison-search-state" role="status" aria-live="polite"></div>
<div id="comparisonDomesticResults" class="comparison-target-results" role="listbox" aria-label="국내·NXT 종목 검색 결과"></div>
</section>
<section id="comparisonFixedPanel" class="comparison-source-panel" hidden>
<div id="comparisonFixedTargets" class="comparison-target-results fixed" role="listbox" aria-label="고정 비교 대상"></div>
</section>
<section id="comparisonWorldPanel" class="comparison-source-panel" hidden>
<form id="comparisonWorldSearchForm" class="comparison-search-form" autocomplete="off">
<input id="comparisonWorldSearch" type="search" maxlength="64" placeholder="미국·대만 종목명" aria-label="해외 종목명">
<button id="comparisonWorldSearchButton" type="submit">검색</button>
</form>
<div id="comparisonWorldState" class="comparison-search-state" role="status" aria-live="polite"></div>
<div id="comparisonWorldResults" class="comparison-target-results" role="listbox" aria-label="해외 종목 검색 결과"></div>
</section>
<div class="comparison-draft" aria-label="비교쌍 편집">
<div><span>첫 번째</span><strong id="comparisonFirst">선택 없음</strong></div>
<button id="comparisonSwap" type="button" title="비교 대상 순서 교환"></button>
<div><span>두 번째</span><strong id="comparisonSecond">선택 없음</strong></div>
<button id="comparisonClear" type="button">초기화</button>
<button id="comparisonSavePair" class="primary" type="button">비교쌍 추가</button>
</div>
<div class="comparison-pair-header">
<div><strong>저장 비교쌍</strong><small>행을 선택한 뒤 컷을 추가합니다.</small></div>
<div>
<button id="comparisonMoveUp" type="button" title="위로"></button>
<button id="comparisonMoveDown" type="button" title="아래로"></button>
<button id="comparisonDeletePair" type="button">삭제</button>
<button id="comparisonDeleteAll" type="button">전체삭제</button>
</div>
</div>
<div id="comparisonPairList" class="comparison-pair-list" role="listbox" aria-label="저장 비교쌍"></div>
<div class="comparison-action-header">
<div><strong>비교용 컷</strong><small>원본 종목비교.ini 9개 액션</small></div>
<button id="comparisonYieldBatch" type="button">수익률 5종 일괄 추가</button>
</div>
<div id="comparisonActionList" class="comparison-action-list" aria-label="비교용 컷 목록"></div>
</section>
<section id="themeWorkflow" class="theme-workflow" aria-labelledby="themeWorkflowTitle" hidden>
<div class="theme-workflow-header">
<div>
<p class="panel-kicker">LEGACY THEME WORKFLOW</p>
<h3 id="themeWorkflowTitle">테마 선택</h3>
</div>
<span id="themeCount" class="badge neutral">READ ONLY</span>
</div>
<form id="themeSearchForm" class="theme-search-form" autocomplete="off">
<input id="themeSearch" type="search" maxlength="64" placeholder="테마명 · 빈 값은 전체" aria-label="테마명">
<select id="themeNxtSession" aria-label="NXT 세션">
<option value="preMarket">NXT 장전</option>
<option value="afterMarket">NXT 시간외</option>
</select>
<button id="themeSearchButton" type="submit">조회</button>
</form>
<div id="themeSearchState" class="theme-search-state" role="status" aria-live="polite"></div>
<div id="themeResults" class="theme-results" role="listbox" aria-label="테마 검색 결과"></div>
<div id="selectedTheme" class="selected-theme" hidden>
<div><span>선택 테마</span><strong id="selectedThemeTitle"></strong><small id="selectedThemeMeta"></small></div>
<label>정렬
<select id="themeSort">
<option value="INPUT_ORDER">입력순</option>
<option value="GAIN_DESC">상승률순</option>
<option value="GAIN_ASC">하락률순</option>
</select>
</label>
</div>
<div class="theme-preview-header">
<div><strong>테마 종목</strong><small>송출 전 read-only 미리보기</small></div>
<span id="themePreviewCount">0 ITEMS</span>
</div>
<div id="themePreviewState" class="theme-preview-state" role="status" aria-live="polite"></div>
<div id="themePreviewItems" class="theme-preview-items" aria-label="테마 종목 미리보기"></div>
<div class="theme-action-header"><strong>테마용 컷</strong><small>5·6·12개 단위 · 최대 20페이지</small></div>
<div id="themeActionList" class="theme-action-list" aria-label="테마용 컷 목록"></div>
<div class="theme-crud-notice">
<span>ThemeA · 트랜잭션 기반 추가·편집·삭제</span>
<button id="themeCatalogManageButton" type="button">테마 관리</button>
</div>
</section>
<section id="overseasWorkflow" class="overseas-workflow" aria-labelledby="overseasWorkflowTitle" hidden>
<div class="overseas-workflow-header">
<div>
<p class="panel-kicker">LEGACY FOREIGN INSTRUMENT WORKFLOW</p>
<h3 id="overseasWorkflowTitle">해외업종·해외종목</h3>
</div>
<span id="overseasCount" class="badge neutral">ORACLE</span>
</div>
<div id="overseasSourceTabs" class="overseas-source-tabs" role="tablist" aria-label="해외 검색 종류">
<button type="button" class="active" data-overseas-source="industry">미국 해외업종</button>
<button type="button" data-overseas-source="stock">US·TW 해외종목</button>
</div>
<form id="overseasSearchForm" class="overseas-search-form" autocomplete="off">
<input id="overseasSearch" type="search" maxlength="64" placeholder="빈 값은 전체 목록" aria-label="해외업종 또는 해외종목 검색어">
<button id="overseasSearchButton" type="submit">조회</button>
</form>
<div id="overseasSearchState" class="overseas-search-state" role="status" aria-live="polite"></div>
<div id="overseasResults" class="overseas-results" role="listbox" aria-label="해외업종·해외종목 검색 결과"></div>
<div id="selectedOverseas" class="selected-overseas" hidden>
<div>
<span>선택 대상</span>
<strong id="selectedOverseasName">-</strong>
<small id="selectedOverseasMeta">-</small>
</div>
<div class="overseas-ma-options" aria-label="해외종목 캔들 이동평균선">
<label><input id="overseasMa5" type="checkbox" checked>5일선</label>
<label><input id="overseasMa20" type="checkbox" checked>20일선</label>
</div>
</div>
<div class="overseas-action-header"><strong>해외 대상 컷</strong><small>업종 1개 · 종목 6개 닫힌 동작</small></div>
<div id="overseasActionList" class="overseas-action-list" aria-label="해외 대상 컷 목록"></div>
</section>
<section id="expertWorkflow" class="expert-workflow" aria-labelledby="expertWorkflowTitle" hidden>
<div class="expert-workflow-header">
<div>
<p class="panel-kicker">LEGACY EXPERT WORKFLOW</p>
<h3 id="expertWorkflowTitle">전문가 추천</h3>
</div>
<span id="expertCount" class="badge neutral">READ ONLY</span>
</div>
<form id="expertSearchForm" class="expert-search-form" autocomplete="off">
<input id="expertSearch" type="search" maxlength="64" placeholder="전문가명 · 빈 값은 전체" aria-label="전문가명">
<button id="expertSearchButton" type="submit">조회</button>
</form>
<div id="expertSearchState" class="expert-search-state" role="status" aria-live="polite"></div>
<div id="expertResults" class="expert-results" role="listbox" aria-label="전문가 검색 결과"></div>
<div id="selectedExpert" class="selected-expert" hidden>
<span>선택 전문가</span>
<strong id="selectedExpertName">-</strong>
<small id="selectedExpertMeta">-</small>
</div>
<div class="expert-preview-header">
<div><strong>추천 종목</strong><small>PLAYINDEX 순서 · read-only 미리보기</small></div>
<span id="expertPreviewCount">0 ITEMS</span>
</div>
<div id="expertPreviewState" class="expert-preview-state" role="status" aria-live="polite"></div>
<div id="expertPreviewItems" class="expert-preview-items" aria-label="전문가 추천 종목 미리보기"></div>
<div class="expert-action-header"><strong>전문가 추천 컷</strong><small>5개 단위 · 최대 20페이지</small></div>
<div id="expertActionList" class="expert-action-list" aria-label="전문가 추천 컷 목록"></div>
<div class="expert-crud-notice">
<span>EList · 전문가·추천종목 추가·편집·삭제</span>
<button id="expertCatalogManageButton" type="button">전문가 관리</button>
</div>
</section>
<section id="tradingHaltWorkflow" class="trading-halt-workflow" aria-labelledby="tradingHaltWorkflowTitle" hidden>
<div class="trading-halt-workflow-header">
<div>
<p class="panel-kicker">LEGACY TRADING HALT WORKFLOW</p>
<h3 id="tradingHaltWorkflowTitle">거래 정지 종목</h3>
</div>
<span id="tradingHaltCount" class="badge neutral">DB</span>
</div>
<form id="tradingHaltSearchForm" class="trading-halt-search-form" autocomplete="off">
<input id="tradingHaltSearch" type="search" maxlength="64" placeholder="종목명 · 빈 값은 전체" aria-label="거래 정지 종목명">
<button id="tradingHaltSearchButton" type="submit">조회</button>
</form>
<div id="tradingHaltSearchState" class="trading-halt-search-state" role="status" aria-live="polite"></div>
<div class="trading-halt-results-header" role="group" aria-label="거래 정지 검색 결과 정렬">
<button id="tradingHaltNameSort" type="button" aria-controls="tradingHaltResults"
aria-label="종목명 정렬: 서버 기본 순서" data-sort-direction="none">종목명 ↕</button>
<span aria-hidden="true">시장</span>
</div>
<div id="tradingHaltResults" class="trading-halt-results" role="listbox" aria-label="거래 정지 종목 검색 결과"></div>
<div id="selectedTradingHalt" class="selected-trading-halt" hidden>
<div>
<span>선택 종목</span>
<strong id="selectedTradingHaltName">-</strong>
<small id="selectedTradingHaltMeta">-</small>
</div>
<div class="trading-halt-ma-options" aria-label="캔들 이동평균선">
<label><input id="tradingHaltMa5" type="checkbox" checked>5일선</label>
<label><input id="tradingHaltMa20" type="checkbox" checked>20일선</label>
</div>
</div>
<div class="trading-halt-action-header">
<strong>거래 정지 컷</strong>
<small>원본 UC7 · 현재가와 120일 캔들</small>
</div>
<div id="tradingHaltActionList" class="trading-halt-action-list" aria-label="거래 정지 컷 목록"></div>
</section>
<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="toggleAllEnabledButton" type="button">전체 송출</button>
<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>
<button id="deleteAllButton" class="danger" type="button">전체삭제</button>
<div class="global-candle-options" aria-label="전체 캔들 이동평균선">
<span>캔들</span>
<label><input id="globalMa5" type="checkbox" checked>5일선</label>
<label><input id="globalMa20" type="checkbox" checked>20일선</label>
</div>
<button id="namedPlaylistOpenButton" class="database-soft" type="button" aria-expanded="false" aria-controls="namedPlaylistPanel">DB 저장·불러오기</button>
<button id="loadButton" type="button">로컬 불러오기</button>
<button id="saveButton" class="primary-soft" type="button">로컬 임시저장</button>
</div>
<section id="namedPlaylistPanel" class="named-playlist-panel" aria-labelledby="namedPlaylistTitle" hidden>
<header class="named-playlist-header">
<div>
<p class="panel-kicker">ORACLE · DC_LIST / PLAY_LIST</p>
<h3 id="namedPlaylistTitle">DB 플레이리스트</h3>
</div>
<div class="named-playlist-header-actions">
<span id="namedPlaylistStateBadge" class="badge neutral">대기</span>
<button id="namedPlaylistRefreshButton" type="button">목록 새로고침</button>
<button id="namedPlaylistCloseButton" type="button" aria-label="DB 플레이리스트 닫기">닫기</button>
</div>
</header>
<div id="namedPlaylistStatus" class="named-playlist-status" role="status" aria-live="polite">
Oracle에 저장된 이름 목록을 조회하세요. 로컬 임시저장과는 별도입니다.
</div>
<div class="named-playlist-layout">
<label class="named-playlist-definitions-label" for="namedPlaylistDefinitions">저장된 이름</label>
<select id="namedPlaylistDefinitions" class="named-playlist-definitions" size="6" aria-describedby="namedPlaylistSelectionSummary"></select>
<div id="namedPlaylistSelectionSummary" class="named-playlist-selection-summary">선택된 DB 정의 없음</div>
<div class="named-playlist-load-actions">
<button id="namedPlaylistLoadButton" class="primary-soft" type="button">선택 DB 불러오기</button>
<button id="namedPlaylistPageRetryButton" type="button" hidden>페이지 다시 조회</button>
<button id="namedPlaylistRestoreBackupButton" type="button">불러오기 전 상태 복원</button>
</div>
<div class="named-playlist-create">
<label for="namedPlaylistProgramCode">새 코드</label>
<input id="namedPlaylistProgramCode" type="text" inputmode="numeric" maxlength="8" autocomplete="off" placeholder="00000001">
<label for="namedPlaylistProgramTitle">새 이름</label>
<input id="namedPlaylistProgramTitle" type="text" maxlength="128" autocomplete="off" placeholder="예: 오전 방송">
<button id="namedPlaylistCreateButton" type="button">새 이름 만들기</button>
</div>
<div class="named-playlist-mutation-actions">
<button id="namedPlaylistReplaceButton" class="primary-soft" type="button">선택 정의에 현재 순서 저장</button>
<button id="namedPlaylistDeleteButton" class="danger" type="button">선택 정의 삭제</button>
</div>
</div>
<p id="namedPlaylistGuardSummary" class="named-playlist-guard-summary">
DB에서 읽은 각 행은 신뢰 복원과 현재 페이지 재계산을 통과해야 PREPARE할 수 있습니다.
</p>
</section>
<div class="table-wrap">
<table>
<thead><tr><th class="check-cell">송출</th><th class="number-cell">#</th><th>종목·대상</th><th></th><th>세부사항</th><th class="page-cell">Page</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 class="background-control-bar" aria-label="장면 배경 설정">
<div>
<small>BACKGROUND</small>
<strong id="backgroundFileName">배경 없음</strong>
<span id="backgroundStateText">원본 F2/F3 배경 상태 확인 중</span>
</div>
<button id="chooseBackgroundButton" type="button">배경 파일 (F2)</button>
<button id="toggleBackgroundButton" type="button">배경 켜기/끄기 (F3)</button>
</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>PREP</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="market-nav-reorder.js"></script>
<script src="operator-workflow.js"></script>
<script src="legacy-batch-selection-workflow.js"></script>
<script src="legacy-fixed-workflow.js"></script>
<script src="industry-workflow.js"></script>
<script src="comparison-workflow.js"></script>
<script src="comparison-import-workflow.js"></script>
<script src="theme-workflow.js"></script>
<script src="overseas-workflow.js"></script>
<script src="expert-workflow.js"></script>
<script src="trading-halt-workflow.js"></script>
<script src="candle-options-workflow.js"></script>
<script src="manual-lists-workflow.js"></script>
<script src="manual-financial-workflow.js"></script>
<script src="named-manual-restore-workflow.js"></script>
<script src="named-comparison-restore-workflow.js"></script>
<script src="legacy-foreign-index-candle-workflow.js"></script>
<script src="named-nxt-theme-restore-workflow.js"></script>
<script src="legacy-named-row-workflow.js"></script>
<script src="operator-catalog-workflow.js"></script>
<script src="manual-lists-ui.js"></script>
<script src="manual-financial-ui.js"></script>
<script src="operator-catalog-ui.js"></script>
<script src="named-playlist-workflow.js"></script>
<script src="app.js"></script>
</body>
</html>