Files
2026-07-23 16:15:57 +09:00

235 lines
9.8 KiB
PHP

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>배포 파일 관리 시스템</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
</head>
<body class="bg-gray-100 p-6">
<div class="max-w-screen-xl mx-auto">
<div class="flex items-center mb-4">
<svg class="w-7 h-7 text-blue-600 mr-2" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" d="M4 16v2a2 2 0 002 2h12a2 2 0 002-2v-2M7 10l5-5m0 0l5 5m-5-5v12" />
</svg>
<span class="text-xl font-bold mr-4">파일 업로드 관리자</span>
</div>
<!-- 헤드 구성 -->
<div class="bg-white p-4 rounded shadow mb-6 flex items-center justify-between">
<div class="flex items-center space-x-4">
<label for="product-select" class="font-bold">제품명(제품코드):</label>
<select id="product-select" class="p-2 border border-gray-300 rounded">
<option value="1">EG-BIM</option>
<option value="2">TOVA</option>
<option value="3">GAIA</option>
</select>
</div>
<div class="flex items-center space-x-4">
<div>
<span class="text-sm">내부 배포 버전(최신):</span>
<span class="text-blue-600 font-semibold">0.28.1</span>
</div>
<div class="flex items-center space-x-1">
<span class="text-sm">외부 배포 버전:</span>
<input type="number" id="ver1" class="w-14 p-1 border rounded" min="0" max="99">
<span class="text-sm">.</span>
<input type="number" id="ver2" class="w-14 p-1 border rounded" min="0" max="99">
<span class="text-sm">.</span>
<input type="number" id="ver3" class="w-14 p-1 border rounded" min="0" max="99">
</div>
<button id="save-version" class="bg-blue-500 text-white px-3 py-1 rounded hover:bg-blue-600">저장</button>
</div>
</div>
<!-- 버튼 영역 -->
<div class="flex justify-end space-x-2 mb-4">
<button id="btn-new" class="bg-green-500 text-white px-3 py-1 rounded hover:bg-green-600">+ 신규 버전</button>
<button class="bg-gray-500 text-white px-3 py-1 rounded hover:bg-gray-600">다운로드</button>
<button class="bg-red-500 text-white px-3 py-1 rounded hover:bg-red-600">파일삭제</button>
</div>
<!-- 테이블 -->
<div class="bg-white shadow rounded-lg overflow-x-auto">
<table class="min-w-full text-sm text-left">
<thead class="bg-gray-200">
<tr>
<th class="px-4 py-2"><input type="checkbox" id="select-all" /></th>
<th class="px-4 py-2">번호</th>
<th class="px-4 py-2">파일명</th>
<th class="px-4 py-2">파일타입</th>
<th class="px-4 py-2">버전</th>
<th class="px-4 py-2">크기</th>
<th class="px-4 py-2">업로드일</th>
<th class="px-4 py-2">업로드자</th>
<th class="px-4 py-2">테스트완료</th>
<th class="px-4 py-2">테스트자</th>
<th class="px-4 py-2">릴리즈일</th>
<th class="px-4 py-2">릴리즈자</th>
</tr>
</thead>
<tbody id="file-list">
<!-- JavaScript로 동적 삽입 예정 -->
</tbody>
</table>
</div>
</div>
<!-- 신규 버전 업로드 팝업(모달) -->
<div id="upload-modal" class="fixed inset-0 bg-black bg-opacity-40 flex items-center justify-center z-50 hidden">
<div class="bg-white p-8 rounded shadow-lg w-full max-w-lg relative">
<h2 class="text-xl font-bold mb-6 text-center">
신규 버전 업로드
<span class="text-base text-gray-500">(테스트 서버)</span>
</h2>
<div class="space-y-3">
<div class="flex items-center">
<label class="w-28">S/W 버전 :</label>
<input type="number" class="border w-14 p-1 mx-1 text-center" id="sw1" min="0">
<span>.</span>
<input type="number" class="border w-14 p-1 mx-1 text-center" id="sw2" min="0">
<span>.</span>
<input type="number" class="border w-14 p-1 mx-1 text-center" id="sw3" min="0">
<span class="ml-3 text-gray-500">MAJOR</span>
</div>
<!-- 설치파일 -->
<div class="flex items-center mb-2">
<label class="w-39 flex justify-between items-center">
<span>설치파일(EXE)</span>
<span>:</span>
</label>
<input type="file" class="hidden" id="setup-file" accept=".exe">
<input type="text" class="border flex-1 p-1 bg-gray-100 ml-2" id="setup-filename" readonly>
<button type="button" class="ml-2 px-3 py-1 bg-blue-500 text-white rounded" id="setup-add">추가</button>
</div>
<!-- 패치파일 -->
<div class="flex items-center mb-2">
<label class="w-39 flex justify-between items-center">
<span>패치파일(EXE)</span>
<span>:</span>
</label>
<input type="file" class="hidden" id="patch-file" accept=".exe">
<input type="text" class="border flex-1 p-1 bg-gray-100 ml-2" id="patch-filename" readonly>
<button type="button" class="ml-2 px-3 py-1 bg-blue-500 text-white rounded" id="patch-add">추가</button>
</div>
<!-- 정보파일 -->
<div class="flex items-center mb-2">
<label class="w-39 flex justify-between items-center">
<span class="flex items-center">
정보파일
<span class="relative group cursor-pointer ml-1">
<span class="w-5 h-5 flex items-center justify-center bg-blue-100 rounded-full text-blue-700 font-bold">i</span>
<span class="absolute left-1/2 -translate-x-1/2 top-7 z-50 hidden group-hover:block bg-gray-800 text-white text-xs rounded py-1 px-2 whitespace-nowrap shadow-lg">
2 이상의 파일을 업로드 압축파일 형태로 업로드해주세요
</span>
</span>
</span>
<span>:</span>
</label>
<input type="file" class="hidden" id="info-file" accept=".zip">
<input type="text" class="border flex-1 p-1 bg-gray-100 ml-2" id="info-filename" readonly>
<button type="button" class="ml-2 px-3 py-1 bg-blue-500 text-white rounded" id="info-add">추가</button>
</div>
</div>
</div>
</div>
<script>
$('#save-version').on('click', function() {
const product = $('#product-select').val().replace(/['"]/g, '');
const family = $('.text-blue-600').text().replace(/['"]/g, '');
const v1 = $('#ver1').val();
const v2 = $('#ver2').val();
const v3 = $('#ver3').val();
if(!v1 || !v2 || !v3) {
alert("외부 버전 모든 칸을 입력하세요");
return;
}
const external = [v1, v2, v3].join('.');
// 실제 전송 (주석처리 상태)
// $.post('/egbim1/save_version.php', {
// product_code: product,
// family_version: family,
// external_version: external
// }, function(res) {
// alert(res.message || '저장 완료');
// }, 'json');
});
// 전체 선택 체크박스 처리
$('#select-all').on('change', function() {
$('.file-checkbox').prop('checked', this.checked);
});
// 신규버전 버튼 → 팝업
$('#btn-new').on('click', function() {
$('#upload-modal').removeClass('hidden');
});
// 취소 버튼, 바깥 클릭 → 닫기
$('#upload-cancel').on('click', function() {
$('#upload-modal').addClass('hidden');
});
$('#upload-modal').on('click', function(e){
if (e.target === this) $(this).addClass('hidden');
});
// 파일 추가 버튼
$('#setup-add').on('click', function() { $('#setup-file').click(); });
$('#patch-add').on('click', function() { $('#patch-file').click(); });
$('#info-add').on('click', function() { $('#info-file').click(); });
// 파일명 표시
$('#setup-file').on('change', function(){ $('#setup-filename').val(this.files[0]?.name || ''); });
$('#patch-file').on('change', function(){ $('#patch-filename').val(this.files[0]?.name || ''); });
$('#info-file').on('change', function(){ $('#info-filename').val(this.files[0]?.name || ''); });
//cloudflare 업로드
async function uploadToR2(file) {
// 1) 서버에서 presigned URL 요청
let formData = new FormData();
formData.append("filename", file.name);
let res = await fetch("/egbim1/upload_presign.php", {
method: "POST",
body: formData
});
let data = await res.json();
console.log("Presigned URL:", data.url);
// 2) presigned URL로 직접 업로드
let putRes = await fetch(data.url, {
method: "PUT",
body: file
});
if (putRes.ok) {
alert(file.name + " 업로드 성공!");
// 👉 DB 저장 호출 (버전 + 파일 정보)
$.post('/egbim1/save_version.php', {
filename: file.name,
product_code: $('#product-select').val(),
version: [$('#sw1').val(), $('#sw2').val(), $('#sw3').val()].join('.')
}, function(res) {
console.log(res);
}, 'json');
} else {
alert(file.name + " 업로드 실패!");
}
}
</script>
</body>
</html>