240 lines
10 KiB
HTML
240 lines
10 KiB
HTML
<!DOCTYPE html>
|
|
<html xmlns:th="http://www.thymeleaf.org"
|
|
xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
|
|
xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
|
|
layout:decorate="~{layout/kjbank_title_layout}">
|
|
<head>
|
|
<title>API 키 신청 상세</title>
|
|
</head>
|
|
<body>
|
|
<section layout:fragment="title">
|
|
<div class="page-title-banner">
|
|
<img th:src="@{/img/img_title_bg.png}" class="title-image">
|
|
<h1>앱관리</h1>
|
|
</div>
|
|
</section>
|
|
<th:block layout:fragment="contentFragment">
|
|
<section class="apikey-detail-container">
|
|
|
|
<!-- Title Bar -->
|
|
<div class="register-title-bar">
|
|
<h2 class="register-title">API Key 신청 상세</h2>
|
|
<span class="register-subtitle">신청하신 API Key의 상세 정보를 확인할 수 있습니다.</span>
|
|
</div>
|
|
|
|
<!-- App Basic Info Card (Figma Design) -->
|
|
<div class="app-info-card">
|
|
<!-- App Icon -->
|
|
<div class="app-info-icon">
|
|
<img th:if="${appRequest.appIconFileId != null}"
|
|
th:src="@{/file/download(fileSn=1,fileId=${appRequest.appIconFileId})}"
|
|
alt="앱 아이콘"
|
|
class="app-icon-image">
|
|
<div th:unless="${appRequest.appIconFileId != null}" class="app-icon-placeholder">
|
|
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>
|
|
<circle cx="8.5" cy="8.5" r="1.5"></circle>
|
|
<polyline points="21 15 16 10 5 21"></polyline>
|
|
</svg>
|
|
</div>
|
|
</div>
|
|
<!-- App Info -->
|
|
<div class="app-info-content">
|
|
<!-- Status Badge -->
|
|
<span class="app-status-badge"
|
|
th:if="${appRequest.approval != null}"
|
|
th:classappend="${appRequest.approval.approvalStatus.toString() == 'APPROVED' ? 'status-approved' :
|
|
(appRequest.approval.approvalStatus.toString() == 'REJECTED' ? 'status-rejected' : 'status-pending')}"
|
|
th:text="${appRequest.approval.approvalStatus.description}">
|
|
대기중
|
|
</span>
|
|
<!-- App Name -->
|
|
<h3 class="app-info-name" th:text="${appRequest.clientName}">앱 이름</h3>
|
|
<!-- App Description -->
|
|
<p class="app-info-description"
|
|
th:text="${appRequest.appDescription != null ? appRequest.appDescription : '앱 설명이 없습니다.'}">
|
|
여기에 입력한 앱 설명이 표시됩니다.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Request Info Section (Figma Design: node 985-1365) -->
|
|
<div class="apikey-info-section">
|
|
|
|
<!-- Client ID (if exists) -->
|
|
<div class="info-row info-row-with-action" th:if="${appRequest.clientId != null}">
|
|
<label class="info-label">Client ID</label>
|
|
<div class="info-value">
|
|
<div class="info-value-box with-copy" th:text="${appRequest.clientId}">K00000001</div>
|
|
<button type="button" class="btn-copy-action" th:data-secret="${appRequest.clientId}" onclick="copyToClipboardFromButton(this)">
|
|
+ 복사
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Callback URL -->
|
|
<div class="info-row">
|
|
<label class="info-label">Callback URL</label>
|
|
<div class="info-value">
|
|
<div class="info-value-box" th:text="${appRequest.callbackUrl != null ? appRequest.callbackUrl : '설정되지 않음'}">
|
|
http://www.abcd.co.kr
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- IP Whitelist -->
|
|
<div class="info-row">
|
|
<label class="info-label">화이트리스트</label>
|
|
<div class="info-value">
|
|
<div class="info-value-box" th:text="${appRequest.ipWhitelist != null and !appRequest.ipWhitelist.isEmpty() ? appRequest.ipWhitelist : '설정되지 않음'}">
|
|
10.0.0.1, 10.0.0.2, 192.168.123.1
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Selected APIs -->
|
|
<div class="info-row info-row-vertical">
|
|
<label class="info-label">API 목록</label>
|
|
<div class="info-value">
|
|
<div class="api-list-box">
|
|
<div class="api-list-item-figma" th:each="api : ${appRequest.apiSpecList}">
|
|
<span class="api-item-name" th:text="${api.apiName}">추가된 API 1</span>
|
|
<span class="api-item-status">승인대기</span>
|
|
</div>
|
|
|
|
<!-- Empty State -->
|
|
<div class="empty-state" th:if="${appRequest.apiSpecList == null or appRequest.apiSpecList.isEmpty()}" style="padding: 24px;">
|
|
<p>선택된 API가 없습니다.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Created Date -->
|
|
<div class="info-row">
|
|
<label class="info-label">신청일시</label>
|
|
<div class="info-value">
|
|
<div class="info-value-box" th:text="${#temporals.format(appRequest.createdDate, 'yyyy.MM.dd HH:mm')}">
|
|
2025.11.22 12:00
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Approval Date (if approved) -->
|
|
<div class="info-row" th:if="${appRequest.approval != null and appRequest.approval.approvalDate != null}">
|
|
<label class="info-label">승인일시</label>
|
|
<div class="info-value">
|
|
<div class="info-value-box" th:text="${#temporals.format(appRequest.approval.approvalDate, 'yyyy.MM.dd HH:mm')}">
|
|
2025.11.22 12:00
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Reason (if exists) -->
|
|
<div class="info-row" th:if="${appRequest.approval != null and appRequest.reason != null and !appRequest.reason.isEmpty()}">
|
|
<label class="info-label">사유</label>
|
|
<div class="info-value">
|
|
<div class="info-value-box" th:text="${appRequest.reason}">
|
|
Approval reason
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- Action Buttons -->
|
|
<div class="form-actions-center">
|
|
<button type="button"
|
|
sec:authorize="hasRole('ROLE_API_KEY_REQUEST')"
|
|
class="btn btn-submit btn-danger"
|
|
th:if="${appRequest.approval != null and appRequest.approval.approvalStatus != null and
|
|
(appRequest.approval.approvalStatus.toString() == 'PENDING' or appRequest.approval.approvalStatus.toString() == 'REQUESTED')}"
|
|
th:data-request-id="${appRequest.id}"
|
|
onclick="cancelRequestById(this)">
|
|
신청 취소
|
|
</button>
|
|
<a th:href="@{/myapikey}" class="btn btn-submit btn-secondary">
|
|
목록
|
|
</a>
|
|
</div>
|
|
|
|
</section>
|
|
|
|
</th:block>
|
|
|
|
<th:block layout:fragment="contentScript">
|
|
<script th:inline="javascript">
|
|
/*<![CDATA[*/
|
|
|
|
// Copy to clipboard function
|
|
function copyToClipboardFromButton(button) {
|
|
var text = $(button).data('secret');
|
|
|
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
navigator.clipboard.writeText(text).then(function() {
|
|
alert('클립보드에 복사되었습니다.');
|
|
}).catch(function(err) {
|
|
console.error('Failed to copy:', err);
|
|
fallbackCopy(text);
|
|
});
|
|
} else {
|
|
fallbackCopy(text);
|
|
}
|
|
}
|
|
|
|
function fallbackCopy(text) {
|
|
const textArea = document.createElement('textarea');
|
|
textArea.value = text;
|
|
textArea.style.position = 'fixed';
|
|
textArea.style.left = '-999999px';
|
|
document.body.appendChild(textArea);
|
|
textArea.select();
|
|
try {
|
|
document.execCommand('copy');
|
|
alert('클립보드에 복사되었습니다.');
|
|
} catch (err) {
|
|
alert('복사에 실패했습니다.');
|
|
}
|
|
document.body.removeChild(textArea);
|
|
}
|
|
|
|
// Cancel request function - called from button with data-request-id attribute
|
|
function cancelRequestById(button) {
|
|
var requestId = $(button).data('request-id');
|
|
|
|
if (!confirm('정말로 이 신청을 취소하시겠습니까?')) {
|
|
return;
|
|
}
|
|
|
|
$('.loading-overlay').show();
|
|
|
|
$.ajax({
|
|
url: '/myapikey/api_key_request/cancel',
|
|
type: 'POST',
|
|
data: {id: requestId},
|
|
dataType: 'json',
|
|
headers: {
|
|
'X-XSRF-TOKEN': /*[[${_csrf.token}]]*/ 'token'
|
|
}
|
|
}).done(function(response) {
|
|
if (response.success) {
|
|
alert(response.message || '신청이 취소되었습니다.');
|
|
window.location.href = /*[[@{/myapikey}]]*/ '/myapikey';
|
|
} else {
|
|
alert(response.message || '신청 취소 중 오류가 발생했습니다.');
|
|
$('.loading-overlay').hide();
|
|
}
|
|
}).fail(function(xhr, status, error) {
|
|
alert('신청 취소 중 오류가 발생했습니다.');
|
|
console.error('Cancel error:', error);
|
|
$('.loading-overlay').hide();
|
|
});
|
|
}
|
|
|
|
/*]]>*/
|
|
</script>
|
|
</th:block>
|
|
|
|
</body>
|
|
</html>
|