초기 커밋: 5130 레거시 시스템

- URL 하드코딩 → .env APP_URL 기반 동적 URL로 변경
- DB 연결 하드코딩 → .env 기반으로 변경
- MySQL strict mode DATE 오류 수정
This commit is contained in:
2025-12-10 20:14:31 +09:00
commit aca1767eb9
6728 changed files with 1863265 additions and 0 deletions

20
shutterbox/_request.php Normal file
View File

@@ -0,0 +1,20 @@
<?php
$num = $_REQUEST['num'] ?? '';
$is_deleted = $_REQUEST['is_deleted'] ?? '';
$registration_date = $_REQUEST['registration_date'] ?? '';
$exit_direction = $_REQUEST['exit_direction'] ?? '';
$author = $_REQUEST['author'] ?? '';
$remark = $_REQUEST['remark'] ?? '';
$update_log = $_REQUEST['update_log'] ?? '';
$search_tag = $_REQUEST['search_tag'] ?? '';
// 추가된 컬럼
$front_bottom_width = $_REQUEST['front_bottom_width'] ?? '';
$rail_width = $_REQUEST['rail_width'] ?? '';
$box_width = $_REQUEST['box_width'] ?? '';
$box_height = $_REQUEST['box_height'] ?? '';
$bending_components = $_REQUEST['bending_components'] ?? '';
$search_keyword = $_REQUEST['search_keyword'] ?? '';
$material_summary = $_REQUEST['material_summary'] ?? '';
?>

19
shutterbox/_row.php Normal file
View File

@@ -0,0 +1,19 @@
<?php
$num = $row['num'] ?? '';
$is_deleted = $row['is_deleted'] ?? '';
$registration_date = $row['registration_date'] ?? '';
$exit_direction = $row['exit_direction'] ?? '';
$author = $row['author'] ?? '';
$remark = $row['remark'] ?? '';
$update_log = $row['update_log'] ?? '';
// 추가된 컬럼
$front_bottom_width = $row['front_bottom_width'] ?? '';
$rail_width = $row['rail_width'] ?? '';
$box_width = $row['box_width'] ?? '';
$box_height = $row['box_height'] ?? '';
$bending_components = $row['bending_components'] ?? '';
$search_keyword = $row['search_keyword'] ?? '';
$material_summary = $row['material_summary'] ?? '';
?>

45
shutterbox/_rowinput.php Normal file
View File

@@ -0,0 +1,45 @@
<?php
// /shutterbox/_rowinput.php
// insert.php 또는 process.php 에서 extract($row) 이후에 include하여
// 방금 작업한 한 행(<tr>…</tr>)을 렌더링합니다.
$upload_dir = '../shutterbox/images/';
?>
<tr
data-num="<?= htmlspecialchars($num, ENT_QUOTES, 'UTF-8') ?>"
onclick="redirectToView(
'<?= htmlspecialchars($num, ENT_QUOTES, 'UTF-8') ?>',
'<?= htmlspecialchars($tablename, ENT_QUOTES, 'UTF-8') ?>'
)"
>
<td class="text-center"><?= htmlspecialchars($num, ENT_QUOTES, 'UTF-8') ?></td>
<td class="text-center"><?= htmlspecialchars($registration_date, ENT_QUOTES, 'UTF-8') ?></td>
<td class="text-center"><?= htmlspecialchars($exit_direction, ENT_QUOTES, 'UTF-8') ?></td>
<td class="text-center"><?= htmlspecialchars($front_bottom_width, ENT_QUOTES, 'UTF-8') ?></td>
<td class="text-center"><?= htmlspecialchars($rail_width, ENT_QUOTES, 'UTF-8') ?></td>
<td class="text-center"><?= htmlspecialchars($box_width, ENT_QUOTES, 'UTF-8') ?></td>
<td class="text-center"><?= htmlspecialchars($box_height, ENT_QUOTES, 'UTF-8') ?></td>
<td class="text-center">
<?php if (!empty($imgdata)): ?>
<img
src="<?= htmlspecialchars($upload_dir . $imgdata, ENT_QUOTES, 'UTF-8') ?>"
alt="형상 이미지"
style="max-width:100px; max-height:50px;"
>
<?php else: ?>
<span class="text-secondary">이미지 없음</span>
<?php endif; ?>
</td>
<td class="text-center text-secondary"
title="<?= htmlspecialchars($search_keyword, ENT_QUOTES, 'UTF-8') ?>">
<?= htmlspecialchars($search_keyword, ENT_QUOTES, 'UTF-8') ?>
</td>
<td class="text-center text-secondary"
title="<?= htmlspecialchars($author, ENT_QUOTES, 'UTF-8') ?>">
<?= htmlspecialchars($author, ENT_QUOTES, 'UTF-8') ?>
</td>
<td class="text-center text-secondary"
title="<?= htmlspecialchars($remark, ENT_QUOTES, 'UTF-8') ?>">
<?= htmlspecialchars($remark, ENT_QUOTES, 'UTF-8') ?>
</td>
</tr>

View File

@@ -0,0 +1,3 @@

994
shutterbox/css/style.css Normal file
View File

@@ -0,0 +1,994 @@
#openModalBtn {
padding: 10px 20px;
font-size: 16px;
}
.modal {
display: none;
position: fixed;
z-index: 1;
left: 50%;
transform: translateX(-50%);
top: 0;
width: 85%;
max-width: 85%;
height: 100%;
overflow: hidden; /* Changed from 'auto' to 'hidden' to prevent closing on outside click */
padding-top: 60px;
}
.modal-content {
background-color: #fefefe;
margin: auto;
border-radius: 10px;
width: 100%;
max-width: 100%;
animation: fadeIn 0.5s;
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.modal-header {
background-color: #1f48d4;
color: white;
padding: 10px;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
display: flex;
justify-content: space-between;
align-items: center;
}
.modal-title {
font-size: 18px;
}
.close {
color: white;
font-size: 18px;
font-weight: bold;
cursor: pointer;
}
.close:hover,
.close:focus {
color: #bbb;
text-decoration: none;
}
.modal-body {
padding: 15px;
width: 100%;
max-width: 100%;
max-height: calc(100vh - 50px); /* 뷰포트 높이에서 여유 공간 확보 */
overflow-y: auto; /* 세로 스크롤 추가 */
}
.custom-card {
background-color: #f9f9f9;
padding: 20px;
border: 1px solid #ddd;
border-radius: 5px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.tooltip-inner {
background-color: black !important; /* 배경색 */
color: white !important; /* 글자색 */
}
.tooltip-arrow {
color: black !important; /* 화살표 색상 */
}
/* 입력창에 대한 설계 */
.ui-autocomplete {
max-height: 500px;
overflow-y: auto;
overflow-x: hidden;
}
.specialinputWrap {
position: relative;
display: inline-block;
width:100%;
}
.specialbtnClear {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
background: transparent;
border: none;
color: black;
cursor: pointer;
}
.specialbtnClear:before {
content: 'X';
font-size: 12px;
}
.specialbtnClear:hover {
color: black;
}
.btnClear_lot {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
background: transparent;
border: none;
color: black;
cursor: pointer;
}
.btnClear_lot:before {
content: 'X';
font-size: 12px;
}
.btnClear_lot:hover {
color: black;
}
/* 전체 테이블에 대한 설정 */
table {
border-collapse: collapse;
}
/* 모든 td 요소에 적용되는 기본 패딩 및 행간 조정 */
td {
padding: 5px !important; /* 셀의 내부 여백을 줄임 */
line-height: 1.3 !important; /* 행간을 줄여서 상하단 여백을 줄임 */
}
/* 테이블의 상단과 하단 마진을 제거하여 전체 공백 줄이기 */
table, .d-flex {
margin-top: 2 !important;
margin-bottom: 2 !important;
}
@media print {
body {
width: 210mm; /* A4 width */
height: 297mm; /* A4 height */
margin: 0; /* Remove default margin */
font-size: 8pt; /* Font size for printing */
}
.table {
width: 100%; /* Full width tables */
table-layout: fixed; /* Uniform column sizing */
border-collapse: collapse; /* Ensure borders collapse */
}
.table th, .table td {
padding: 1px; /* Reduce padding */
/* border: 1px solid black!important; Ensure borders are visible */
}
.text-center {
text-align: center; /* Maintain center alignment */
}
/* Prevent table row splitting */
.table tr {
page-break-inside: avoid; /* Prevent breaking inside rows */
page-break-after: avoid; /* Allow breaking after rows */
}
.table thead {
display: table-header-group; /* Ensure table headers are repeated */
}
.table tbody {
display: table-row-group; /* Ensure table rows are grouped */
}
.table tfoot {
display: table-footer-group; /* Ensure table footers are repeated */
}
/* Add top and bottom margins to each page */
.table tbody:before,
.table tbody:after {
content: "";
display: table-row;
height: 5mm; /* Adjust as needed for top and bottom margins */
}
/* Remove border from the before and after elements */
.table tbody:before td,
.table tbody:after td {
border: none; /* Remove borders */
}
/* Adjust the border of the last row on the page */
.table tbody tr:last-child td {
border-bottom: none; /* Remove the bottom border */
border-left: none; /* Remove the bottom border */
border-right: none; /* Remove the bottom border */
border-top: none; /* Remove the bottom border */
}
/* Prevent border at the connection of two pages */
.table tbody tr:last-child td:first-child {
border-bottom: none; /* Remove the bottom border */
border-left: none; /* Remove the bottom border */
border-right: none; /* Remove the bottom border */
border-top: none; /* Remove the bottom border */
}
.table tbody tr:last-child td:last-child {
border-bottom: none; /* Remove the bottom border */
border-left: none; /* Remove the bottom border */
border-right: none; /* Remove the bottom border */
border-top: none; /* Remove the bottom border */
}
}
#specailTable th, #specailTable td {
padding: 3px!important;
}
#specailTable2 th, #specailTable2 td {
padding: 3px!important;
border: 0.2px solid gray !important;
}
/* Assembly Table Styles */
.table-container {
width: 100%;
}
#assemblyTable {
table-layout: fixed;
width: 100%;
}
#assemblyTable th:first-child,
#assemblyTable td:first-child {
width: 100px;
min-width: 100px;
max-width: 100px;
}
#assemblyTable th:nth-child(2),
#assemblyTable td:nth-child(2) {
width: 1100px;
min-width: 1100px;
max-width: 1100px;
}
/* 테이블 셀의 padding 최소화 */
#assemblyTable td {
padding: 2px !important;
vertical-align: middle;
}
#assemblyTable th {
padding: 2px !important;
vertical-align: middle;
}
.input-container {
white-space: nowrap;
display: flex;
align-items: center;
justify-content: start;
padding: 0;
margin: 0;
}
.input-container input,
.input-container span {
display: inline-block;
margin-right: 5px; /* 간격 늘림 */
padding: 1px 2px; /* input 내부 padding 최소화 */
border: 0.2px solid #ccc;
font-size: 0.8rem; /* 폰트 크기 줄임 */
text-align: center; /* 모든 텍스트 가운데 정렬 */
vertical-align: middle;
}
.input-container input[type="text"] {
width: 40px;
height: 26px; /* 높이 줄임 */
}
/* 음영, A각 표시 행의 체크박스도 text-input 칸과 동일 폭/높이 */
.input-container input[type="checkbox"] {
width: 16px; /* 체크박스 크기 줄임 */
height: 16px; /* 체크박스 크기 줄임 */
margin: 0;
padding: 0;
vertical-align: middle;
}
/* form-control 클래스의 padding 최소화 */
.form-control {
padding: 1px 2px !important;
font-size: 0.8rem !important;
height: 24px !important;
}
.form-check-input {
padding: 0 !important;
margin: 0 12px 0 16px!important;
width: 17px !important;
height: 16px !important;
}
/* 테이블 전체 스타일 최적화 */
.table {
margin-bottom: 0;
}
.table-bordered td,
.table-bordered th {
border-width: 0.2px;
}
/* 체크박스가 포함된 셀도 동일한 너비 유지 */
.input-container:has(input[type="checkbox"]) {
justify-content: start; /* 왼쪽 정렬로 되돌림 */
}
/* 모든 input-container의 자식 요소들이 동일한 공간을 차지하도록 */
.input-container > * {
flex-shrink: 0; /* 요소가 축소되지 않도록 */
}
/* wrapper: 원래 폭과 높이를 그대로 쓰되 inline-block 으로 묶어줌 */
.input-container .col-cell {
display: inline-block;
vertical-align: middle;
position: relative;
/* wrapper 에는 너비나 높이를 지정하지 않습니다.
table-layout:fixed 와 input/span 의 width:40px;height:24px 가
각각 칸을 균등 분할하고, 내부 요소 크기를 결정합니다. */
}
/* 삭제 버튼 */
.col-cell .remove-col {
position: absolute;
top: 0;
right: 0;
width: 1em;
height: 1em;
line-height: 1em;
padding: 0;
font-size: 0.8rem;
border: none;
background: transparent;
color: #d33;
cursor: pointer;
}
/* 라벨 셀 스타일 */
.lightgray {
background-color: #f8f9fa;
font-weight: bold;
text-align: center;
}
/* 두 번째 모달(#bendingSearchModal)의 z-index를 높여서 항상 위에 표시되도록 함 */
#bendingSearchModal {
z-index: 1060; /* Bootstrap의 기본 모달 z-index(1050)보다 높은 값 */
}
/* 만약 두 번째 모달의 회색 배경(backdrop)도 뒤에 숨는다면 아래 코드도 추가 */
/* 참고: Bootstrap 버전에 따라 backdrop 클래스 명이 다를 수 있음 */
.modal-backdrop.fade.show:nth-of-type(2) {
z-index: 1055; /* 첫 번째 모달과 두 번째 모달 사이의 값 */
}
/* 선택된 행 스타일 */
#bendingSearchResults tr.table-active {
background-color: #e3f2fd !important;
border-left: 4px solid #2196F3;
}
#bendingSearchResults tr:hover {
background-color: #f8f9fa;
transition: background-color 0.2s ease;
}
#bendingSearchResults tr {
transition: all 0.2s ease;
}
/* 조립 부품 테이블 스타일 (bending/write_form.php와 동일) */
.table-container {
width: 100%;
}
#assemblyTable {
table-layout: fixed;
width: 100%;
}
#assemblyTable th:first-child,
#assemblyTable td:first-child {
width: 100px;
min-width: 100px;
max-width: 100px;
}
#assemblyTable th:nth-child(2),
#assemblyTable td:nth-child(2) {
width: auto;
min-width: 200px;
}
/* 테이블 셀의 padding 최소화 */
#assemblyTable td {
padding: 2px !important;
vertical-align: middle;
}
#assemblyTable th {
padding: 2px !important;
vertical-align: middle;
}
.input-container {
white-space: nowrap;
display: flex;
align-items: center;
justify-content: start;
padding: 0;
margin: 0;
}
.input-container input,
.input-container span {
display: inline-block;
margin-right: 5px;
padding: 1px 2px;
border: 1px solid #ccc;
font-size: 0.8rem;
text-align: center;
vertical-align: middle;
}
.input-container input[type="text"] {
width: 40px;
height: 24px;
}
.form-control {
padding: 1px 2px !important;
font-size: 0.8rem !important;
height: 24px !important;
}
.form-check-input {
padding: 0 !important;
margin: 0 12px 0 16px!important;
width: 17px !important;
height: 16px !important;
}
.table {
margin-bottom: 0;
}
.table-bordered td,
.table-bordered th {
border-width: 1px;
}
.input-container > * {
flex-shrink: 0;
}
.input-container .col-cell {
display: inline-block;
vertical-align: middle;
position: relative;
}
.col-cell .remove-col {
position: absolute;
top: 0;
right: 0;
width: 1em;
height: 1em;
line-height: 1em;
padding: 0;
font-size: 0.8rem;
border: none;
background: transparent;
color: #d33;
cursor: pointer;
}
.lightgray {
background-color: #f8f9fa;
font-weight: bold;
}
.yellowBold {
background-color: #fff3cd;
font-weight: bold;
}
.orangeBlackBold {
background-color: #fd7e14;
color: white;
font-weight: bold;
}
/* 기본 스타일 설정 */
input[type="checkbox"],
input[type="radio"] {
transform: scale(1.2); /* 크기 확대 */
margin: 3px; /* 여백 추가 */
}
/* "readonly" 상태일 때 스타일 설정 */
.readonly-checkbox,
.readonly-radio {
pointer-events: none; /* 사용자 상호작용 비활성화 */
opacity: 1; /* 불투명도 설정 */
color: red !important;
}
/* 순서 관련 스타일 */
.order-number {
font-weight: bold;
color: #007bff;
background-color: #f8f9fa;
border-radius: 4px;
padding: 2px 6px;
min-width: 30px;
text-align: center;
}
.draggable-row {
cursor: move;
}
.draggable-row:hover {
background-color: #f8f9fa;
}
.dragging {
opacity: 0.5;
background-color: #e9ecef !important;
}
.drag-over {
border-top: 2px solid #007bff;
}
/* 순서 배지 스타일 */
.order-badge {
font-size: 0.8rem;
padding: 2px 6px;
}
/* 선택된 부품 스타일 */
.component-block.selected {
background-color: #e3f2fd !important;
border: 2px solid #2196f3 !important;
}
.component-block.selected .card {
border-color: #2196f3 !important;
}
/* 드래그 가능한 부품 스타일 */
.component-block {
cursor: move;
transition: all 0.2s ease;
}
.component-block:hover {
background-color: #f8f9fa;
}
.component-block:not(.selected):hover {
border: 1px solid #dee2e6;
}
/* 라디오 버튼 스타일 */
.btn-check:checked + .btn-outline-primary {
background-color: #0d6efd;
border-color: #0d6efd;
color: white;
}
.btn-check:checked + .btn-outline-success {
background-color: #198754;
border-color: #198754;
color: white;
}
.btn-check:checked + .btn-outline-secondary {
background-color: #6c757d;
border-color: #6c757d;
color: white;
}
.btn-group .btn {
margin-right: 2px;
}
.btn-group .btn:last-child {
margin-right: 0;
}
/* search_guiderail.php 이미지 확대 기능 스타일 */
.search-zoomable-image {
transition: all 0.3s ease;
cursor: pointer;
position: relative;
}
.search-zoomable-image:hover {
opacity: 0.8;
}
/* 이미지 팝업 오버레이 - 마우스 위치에 표시 */
.image-popup-overlay {
display: none;
position: fixed;
background: white;
border: 2px solid #007bff;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
z-index: 10000;
padding: 5px;
text-align: center;
}
.image-popup-content {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.image-popup-content img {
max-width: 100%;
max-height: 100%;
border-radius: 4px;
object-fit: contain;
}
/* 이미지 모달 스타일 */
.image-modal {
display: none;
position: fixed;
z-index: 9999;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.8);
cursor: pointer;
}
.image-modal-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
max-width: 90%;
max-height: 90%;
border-radius: 8px;
box-shadow: 0 4px 20px rgba(0,0,0,0.5);
}
.image-modal-content img {
width: 100%;
height: auto;
border-radius: 8px;
}
/* 그리기 컨트롤 버튼 활성화 상태 */
#lineBtn.active, #textBtn.active, #eraserBtn.active {
background-color: #007bff !important;
color: white !important;
border-color: #007bff !important;
}
/* "아직 등록된 이미지가 없습니다" 메시지 스타일 */
.no-image-message {
color: #6c757d;
font-style: italic;
padding: 20px;
text-align: center;
background-color: #f8f9fa;
border: 1px dashed #dee2e6;
border-radius: 4px;
margin: 10px 0;
}
.no-image-message i {
margin-right: 8px;
font-size: 1.2em;
}
/* 이미지 에디터 스타일 정의 */
dialog {
width: 1300px; height: 800px;
border: none; border-radius: .5rem;
padding: 0; overflow: hidden;
}
dialog::backdrop { background: rgba(0,0,0,.5); }
#editorHeader {
background: #f8f9fa; padding: .5rem 1rem;
border-bottom: 1px solid #dee2e6;
display: flex; align-items: center;
}
#editorHeader h5 { margin: 0; flex-grow: 1; }
#editorHeader .btn-close { margin-left: .5rem; }
#editorToolbar, #editorToolbar2 {
background: #fff;
padding: .5rem; gap: .25rem;
}
#editorToolbar { display: flex; align-items: center; flex-wrap: wrap; }
#editorToolbar2 { display: flex; align-items: center; }
.toolbar-btn { width: 40px; height: 40px; padding: 0; }
.toolbar-btn i { font-size: 1.2rem; }
.toolbar-btn.active { background-color: #0d6efd; color: #fff; }
.color-btn { width: 24px; height: 24px; padding: 0; border: 2px solid #fff; cursor: pointer; }
.color-btn.active { border-color: #000; }
#editorBody { position: relative; width: 100%; height: calc(100% - 128px); }
#editorBody canvas { width: 100%; height: 100%; cursor: crosshair; }
.canvas-text-input {
position: absolute;
border: 1px dashed #666;
background: transparent;
resize: none;
outline: none;
padding: 2px;
font-family: sans-serif;
}
/* 이미지 컨테이너 스타일 */
.image-container {
position: relative;
display: inline-block;
}
.paste-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 123, 255, 0.8);
color: white;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: 0.375rem;
font-size: 0.875rem;
opacity: 0;
transition: opacity 0.2s;
}
.paste-overlay.show {
opacity: 1;
}
.paste-overlay i {
font-size: 2rem;
margin-bottom: 0.5rem;
}
canvas {
border: 1px solid black;
margin: 10;
}
/* 스타일 코드는 변경이 없으므로 여기에 그대로 유지합니다. */
.image-container { position: relative; display: inline-block; }
.image-container img { display: block; }
.input-overlay { position: absolute; background: rgba(255, 255, 255, 0.5); border: 1px solid blue; width: 40px; color: blue; }
.assembly-area { border: 1px solid #ddd; padding: 10px; margin-top: 10px; background-color: #f9f9f9; }
.assembly-area th { background-color: #f0f0f0; }
/* 정렬 헤더 스타일 */
.sortable-header {
position: relative;
user-select: none;
transition: background-color 0.2s;
}
.sortable-header:hover {
background-color: #e9ecef !important;
}
.sortable-header.active {
background-color: #007bff !important;
color: white !important;
}
.sort-icon {
margin-left: 5px;
font-size: 0.8em;
opacity: 0.6;
}
.sortable-header:hover .sort-icon {
opacity: 1;
}
.sortable-header.active .sort-icon {
opacity: 1;
color: white;
}
/* 정렬 방향 아이콘 */
.sort-asc .sort-icon::before {
content: "\F12C"; /* bi-arrow-up */
}
.sort-desc .sort-icon::before {
content: "\F12F"; /* bi-arrow-down */
}
.sort-default .sort-icon::before {
content: "\F12E"; /* bi-arrow-down-up */
}
/* modal-specialfull 클래스 - width 1800px로 확장 */
.modal-specialfull {
width: 1700px !important;
max-width: 1700px !important;
margin: 1.75rem auto;
}
.modal-specialfull .modal-content {
width: 100%;
height: auto;
min-height: 80vh;
border: 0;
border-radius: 0.5rem;
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
}
.modal-specialfull .modal-header {
border-bottom: 1px solid #dee2e6;
padding: 1rem 1.5rem;
}
.modal-specialfull .modal-body {
padding: 1.5rem;
overflow-y: auto;
}
.modal-specialfull .modal-footer {
border-top: 1px solid #dee2e6;
padding: 1rem 1.5rem;
}
/* 반응형 처리 */
@media (max-width: 1920px) {
.modal-specialfull {
width: 80% !important;
max-width: 80% !important;
}
}
@media (max-width: 1400px) {
.modal-specialfull {
width: 98% !important;
max-width: 98% !important;
}
}
/* modal-full 클래스 - 화면에 꽉 차게 */
.modal-full {
width: 100% !important;
max-width: 100% !important;
height: 100% !important;
margin: 0 !important;
padding: 0 !important;
}
.modal-full .modal-content {
width: 100% !important;
height: 100vh !important;
min-height: 100vh !important;
border: 0 !important;
border-radius: 0 !important;
box-shadow: none !important;
margin: 0 !important;
display: flex;
flex-direction: column;
}
.modal-full .modal-header {
border-bottom: 1px solid #dee2e6;
padding: 1rem 1.5rem;
background-color: #28a745; /* 녹색 배경 */
color: white; /* 텍스트 색상을 흰색으로 */
}
.modal-full .modal-body {
padding: 1.5rem;
overflow-y: auto;
flex: 1;
height: calc(100vh - 200px); /* 헤더와 푸터 높이를 더 정확하게 계산 */
max-height: calc(100vh - 200px); /* 최대 높이 제한 */
margin-bottom: 0; /* 하부 여백 제거 */
}
.modal-full .modal-footer {
border-top: 2px solid #dee2e6;
padding: 1.5rem 2rem;
background-color: #ffffff;
position: relative;
z-index: 1000;
min-height: 80px; /* 최소 높이 증가 */
display: flex;
align-items: center;
justify-content: flex-end;
gap: 15px;
box-shadow: 0 -2px 10px rgba(0,0,0,0.1); /* 상단 그림자 추가 */
flex-shrink: 0; /* 푸터가 축소되지 않도록 */
}
/* 모달 푸터 버튼 스타일 강화 */
.modal-full .modal-footer .btn {
font-size: 1rem;
font-weight: 600;
padding: 0.75rem 1.5rem;
border-radius: 6px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
transition: all 0.3s ease;
min-width: 120px;
}
.modal-full .modal-footer .btn:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.2);
}
.modal-full .modal-footer .btn-secondary {
background-color: #6c757d;
border-color: #6c757d;
color: white;
}
.modal-full .modal-footer .btn-success {
background-color: #28a745;
border-color: #28a745;
color: white;
}
/* 모달 푸터 전체를 더 눈에 띄게 만들기 */
.modal-full .modal-footer {
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
border-top: 3px solid #28a745;
}
/* 버튼에 더 강한 대비 추가 */
.modal-full .modal-footer .btn {
text-shadow: 0 1px 2px rgba(0,0,0,0.3);
letter-spacing: 0.5px;
}
/* 선택 적용 버튼 특별 스타일 */
.modal-full .modal-footer #applyBendingSelectionBtn {
background: linear-gradient(135deg, #28a745 0%, #20c997 100%);
border: none;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1px;
}
/* 모달 배경도 전체 화면으로 */
.modal-full {
position: fixed !important;
top: 0 !important;
left: 0 !important;
right: 0 !important;
bottom: 0 !important;
}
/* 반응형 처리 - 모든 화면에서 전체 화면 */
@media (max-width: 1920px) {
.modal-full {
width: 100% !important;
max-width: 100% !important;
height: 100% !important;
}
}
@media (max-width: 1400px) {
.modal-full {
width: 100% !important;
max-width: 100% !important;
height: 100% !important;
}
}

264
shutterbox/fetch_flat.php Normal file
View File

@@ -0,0 +1,264 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
$mode = isset($_POST['mode']) ? $_POST['mode'] : '';
$num = isset($_POST['num']) ? $_POST['num'] : '';
$tablename = isset($_POST['tablename']) ? $_POST['tablename'] : '';
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
try {
$sql = "SELECT * FROM {$DB}.$tablename WHERE num=? ";
$stmh = $pdo->prepare($sql);
$stmh->bindValue(1, $num, PDO::PARAM_INT);
$stmh->execute();
$row = $stmh->fetch(PDO::FETCH_ASSOC);
include '_row.php';
} catch (PDOException $Exception) {
echo "오류: ".$Exception->getMessage();
exit;
}
$title_message = '케이스 절곡 전개';
// echo '<pre>';
// print_r($row);
// echo '</pre>';
// 기존에 저장된 값이 있는 경우 해당 값을 설정
$selected_exit_directionFlat = isset($row['exit_direction']) ? $row['exit_direction'] : '양면 점검구';
?>
<style>
.image-container {
position: relative;
display: inline-block;
}
.image-container img {
display: block;
}
.input-overlay {
position: absolute;
background: rgba(255, 255, 255, 0.5);
border: 1px solid blue;
width: 50px;
color: blue;
/* font-weight: bold; */
}
.modal-body {
max-height: 750px; /* 원하는 높이 설정 */
max-width: 1200px; /* 원하는 너비 설정 */
overflow-x: auto; /* 가로 스크롤 가능 */
overflow-y: auto; /* 세로 스크롤 가능 */
}
.table-container {
width: 100%;
}
#dynamicTable {
table-layout: fixed;
width: 1000px;
}
#dynamicTable th:first-child,
#dynamicTable td:first-child {
width: 100px;
min-width: 100px;
max-width: 100px;
}
#dynamicTable th:nth-child(2),
#dynamicTable td:nth-child(2) {
width: 900px;
min-width: 900px;
max-width: 900px;
}
.input-container {
width: 100%;
white-space: nowrap;
display: flex;
align-items: center;
border : none;
}
.input-container input,
.input-container span {
display: inline-block;
margin-right: 5px;
}
.input-container input[type="text"] {
width: 30px;
height:30px;
}
</style>
<div class="container-fluid">
<div class="card justify-content-center">
<div class="card-header text-center">
<div class="row">
<div class="col-sm-2">
</div>
<div class="col-sm-8">
<div class="d-flex align-items-center justify-content-center">
<span class="text-center fs-5"><?=$title_message?></span>
<button class="btn btn-dark btn-sm ms-5 me-2" onclick="generatePDF()"> PDF 저장 </button>
<button class="btn btn-dark btn-sm " onclick="viewWork('<?=$num?>');return false"> 절곡 작업지시서 </button>
</div>
</div>
<div class="col-sm-2">
<div class="d-flex align-items-center justify-content-end">
<button type="button" class="btn btn-outline-dark btn-sm me-2 closeBtn"> <ion-icon name="close-circle-outline"></ion-icon> 닫기 </button>
</div>
</div>
</div>
</div>
<div class="card-body">
<div class="row mb-3">
<div class="col text-center">
<span class="badge fs-5
<?php
if($selected_exit_directionFlat === '양면 점검구') {
echo 'bg-primary';
} elseif($selected_exit_directionFlat === '밑면 점검구') {
echo 'bg-success';
} elseif($selected_exit_directionFlat === '후면 점검구') {
echo 'bg-danger';
}
?>">
<?php echo $selected_exit_directionFlat; ?>
</span>
</div>
</div>
<div class="d-flex align-items-center justify-content-center m-2">
<div class="image-container mb-5">
<img id="checkImageFlat" alt="Image">
<span id="display_front_bottom_width" class="input-overlay text-success fs-6" style="top: 350px; left: 110px;" > 전면밑 <?=$front_bottom_width?> </span>
<span id="display_rail_width" class="input-overlay text-danger fs-6" style="top: 410px; left: 180px;" > 레일폭 <?=$rail_width?> </span>
</div>
</div>
<div id="content-to-print">
<div class="row justify-content-center text-center">
<div class="d-flex align-items-center justify-content-center m-2">
<table class="table ">
<tbody>
<tr>
<td class="text-center fs-6 fw-bold" colspan="6" >
<div class="d-flex align-items-center justify-content-center">
<span class="text-center fs-6 ms-1 me-1"> (<?= $selected_exit_directionFlat?>) 케이스 &nbsp;&nbsp;
<span class="text-center fs-6 ms-1 me-1"> 전면 밑 : <?=$front_bottom_width?> &nbsp;&nbsp; 레일폭 : <?=$rail_width?> &nbsp;&nbsp;&nbsp;&nbsp; </span>
<span class="text-center fs-6 ms-1 me-1 text-primary"> 가로(폭): </span>
<span class="text-primary ms-1 me-1"><?=$box_width?></span>
<span class="text-center fs-6 ms-1 me-1"> x </span>
<span class="text-center fs-6 ms-1 me-1 text-danger"> 세로(높이): </span>
<span class="text-danger"><?=$box_height?></span>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="row justify-content-center text-center">
<?php
// 공통인 것
$box_height = isset($row['box_height']) ? $row['box_height'] : 0;
$front_bottom_width = isset($row['front_bottom_width']) ? $row['front_bottom_width'] : 0;
// 케이스 전개도 함수
require_once($_SERVER['DOCUMENT_ROOT'] . "/shutterbox/fun_case.php");
$productData = getCasePlate($selected_exit_directionFlat, $box_width, $box_height, $rail_width, $front_bottom_width);
?>
<div class="table-container">
<table class="table">
<thead>
<tr>
<th class="w100px">번호</th>
<th class="w80px">구분</th>
<th>상세내역</th>
</tr>
</thead>
<tbody id="tableBody">
<?php foreach ($productData as $productIndex => $product): ?>
<?php
// 첫 번째 행에 번호를 표시 (1, 2, 3... inputValues의 길이만큼)
echo '<tr>';
echo '<td rowspan="6" class="lightgray">' . $product['label'] . '</td>';
echo '<td class="lightgray">번호</td>';
echo '<td class="input-container" style="border:none!important; border-bottom: 1px solid black!important;">';
foreach ($product['inputValues'] as $index => $value) {
echo '<span class="form-control text-center" style="width: 30px;">' . ($index + 1) . '</span>';
}
echo '</td>';
echo '</tr>';
// 입력 값 행
echo '<tr>';
echo '<td class="lightgray">입력</td>';
echo '<td class="input-container" style="border:none!important; border-bottom: 1px solid black!important;">';
foreach ($product['inputValues'] as $value) {
echo '<span class="yellowBold text-center" style="width: 30px;">' . $value . '</span>';
}
echo '</td>';
echo '</tr>';
// 연신율 행
echo '<tr>';
echo '<td class="lightgray">연신율 (-)</td>';
echo '<td class="input-container" style="border:none!important; border-bottom: 1px solid black!important;">';
foreach ($product['bendingRates'] as $rate) {
echo '<span class="text-center" style="width: 30px;">' . $rate . '</span>';
}
echo '</td>';
echo '</tr>';
// 합계 행
echo '<tr>';
echo '<td class="lightgray">합계</td>';
echo '<td class="input-container" style="border:none!important; border-bottom: 1px solid black!important;">';
foreach ($product['sums'] as $sum) {
echo '<span class="orangeBlackBold text-center" style="width: 30px;">' . $sum . '</span>';
}
echo '</td>';
echo '</tr>';
// 음영 행
echo '<tr>';
echo '<td class="lightgray">음영</td>';
echo '<td class="input-container" style="border:none!important; border-bottom: 1px solid black!important;">';
foreach ($product['colors'] as $color) {
echo '<span style="width: 10px; margin-left:10px; margin-right:15px;">' . ($color ? 'O' : '&nbsp;') . '</span>';
}
echo '</td>';
echo '</tr>';
// A각 표시 행
echo '<tr>';
echo '<td class="lightgray">A각 표시</td>';
echo '<td class="input-container" style="border:none!important; border-bottom: 1px solid black!important;">';
foreach ($product['aAngles'] as $angle) {
echo '<span style="width: 10px; margin-left:10px; margin-right:15px;">' . ($angle ? 'O' : '&nbsp;') . '</span>';
}
echo '</td>';
echo '</tr>';
?>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>

542
shutterbox/fetch_modal.php Normal file
View File

@@ -0,0 +1,542 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
$mode = isset($_POST['mode']) ? $_POST['mode'] : '';
$num = isset($_POST['num']) ? $_POST['num'] : '';
$tablename = isset($_POST['tablename']) ? $_POST['tablename'] : '';
require_once($_SERVER['DOCUMENT_ROOT'] . "/common.php"); // 초기파일 로드
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
// --- 변수 초기화 ---
$bending_components = '';
$registration_date = date('Y-m-d');
$author = isset($user_name) ? $user_name : '';
$num_display = $num;
if ( ($mode === 'modify' or $mode === 'copy' or $mode === 'view' ) && $num) {
try {
$sql = "SELECT * FROM {$DB}.$tablename WHERE num=? ";
$stmh = $pdo->prepare($sql);
$stmh->bindValue(1, $num, PDO::PARAM_INT);
$stmh->execute();
$row = $stmh->fetch(PDO::FETCH_ASSOC);
if ($row) {
include '_row.php';
}
if ($mode === 'copy') {
$registration_date = date('Y-m-d');
$num_display = ''; // 복사 모드에서는 번호 비움
$author = isset($user_name) ? $user_name : '';
}
} catch (PDOException $Exception) {
echo "오류: ".$Exception->getMessage();
exit;
}
} else {
include '_request.php';
$mode = 'insert';
$registration_date = date('Y-m-d');
$author = isset($user_name) ? $user_name : '';
}
$title_message = ($mode === 'view') ? "셔터박스 조회 (#{$num_display})" : '셔터박스 등록';
$title_message = ($mode === 'modify') ? "셔터박스 수정 (#{$num_display})" : $title_message ;
$title_message = ($mode === 'copy') ? '셔터박스 (데이터 복사)' : $title_message ;
// 기존에 저장된 값이 있는 경우 해당 값을 설정
$selected_exit_direction = isset($row['exit_direction']) ? $row['exit_direction'] : '양면 점검구';
$is_assembly_model = true;
?>
<link href="../css/bending.css?v=<?php echo time(); ?>" rel="stylesheet"> <!-- 절곡관련 (가이드레일,케이스,하단마감재) -->
<input type="hidden" id="update_log" name="update_log" value="<?= isset($update_log) ? htmlspecialchars($update_log, ENT_QUOTES, 'UTF-8') : '' ?>">
<input type="hidden" id="selected_exit_direction" name="selected_exit_direction" value="<?=$selected_exit_direction?>">
<input type="hidden" id="bending_components_data" name="bending_components" value="<?= htmlspecialchars($bending_components, ENT_QUOTES, 'UTF-8') ?>">
<input type="hidden" id="material_summary" name="material_summary" value="<?= isset($material_summary) ? htmlspecialchars($material_summary, ENT_QUOTES, 'UTF-8') : '' ?>">
<div class="container-fluid">
<div class="card justify-content-center">
<div class="card-header text-center" style="height: 45px;">
<div class="row" style="height: 40px;">
<div class="col-sm-10">
<div class="d-flex align-items-center justify-content-center">
<span class="text-center mx-5"><?= $mode ?></span>
<span class="text-center fs-6 me-5"> <?=$title_message?> </span>
<?php if($mode == 'view' ) { ?>
<button type="button" id="modifyBtn" data-num="<?=$num?>" class="btn btn-dark btn-sm mx-1"> <i class="bi bi-pencil-square"></i> 수정 </button>
<button id="copyBtn" data-num="<?=$num?>" class="btn btn-primary btn-sm mx-1" type="button"><i class="bi bi-copy"></i> 복사 </button>
<?php } ?>
<?php if($mode == 'insert' || $mode == 'modify' || $mode == 'copy' ) { ?>
<button type="button" id="saveBtn" class="btn btn-dark btn-sm mx-1"> <i class="bi bi-save"></i> 저장 </button>
<button type="button" class="btn btn-dark btn-sm mx-1 registImageBtn"> <i class="bi bi-list"></i> 결합형태 이미지 등록 </button>
<?php } ?>
<?php if( $mode == 'view' ) { ?>
<button type="button" id="deleteBtn" class="btn btn-danger btn-sm mx-1"> <i class="bi bi-trash"></i> 삭제 </button>
<?php } ?>
</div>
</div>
<div class="col-sm-2">
<div class="d-flex align-items-center justify-content-end">
<button type="button" class="btn btn-outline-dark btn-sm me-2 closeBtn"> &times; 닫기 </button>
</div>
</div>
</div>
</div>
<div class="card-body">
<div class="row">
<div class="col-sm-8">
<div class="d-flex justify-content-center" style="padding : 2px;">
<table class="table table-bordered table-sm" id="mainTable">
<tbody>
<tr>
<td class="text-center fw-bold w80px" style="width:80px!important;"> 등록일</td>
<td class="text-center" >
<input type="date" class="form-control viewmode " id="registration_date" name="registration_date" value="<?=$registration_date?>">
</td>
<td class="text-center fw-bold">작성자</td>
<td class="text-center" style="width:100px;">
<input class="form-control viewmode " id="author" name="author" value="<?=$author?>" autocomplete="off">
</td>
<td class="text-center" >
<div class="d-flex align-items-center justify-content-center">
<span class="text-center ms-1 me-1 text-primary fw-bold"> 가로(폭) </span>
<input type="text" class="form-control w50px text-primary ms-1 me-1 viewmode" id="box_width" name="box_width" value="<?= isset($box_width) ? htmlspecialchars($box_width, ENT_QUOTES, 'UTF-8') : '' ?>">
<span class="text-center ms-1 me-1"> x </span>
<span class="text-center ms-1 me-1 text-danger fw-bold"> 세로(높이) </span>
<input type="text" class="form-control w50px text-danger viewmode" id="box_height" name="box_height" value="<?= isset($box_height) ? htmlspecialchars($box_height, ENT_QUOTES, 'UTF-8') : '' ?>">
<span class="text-center ms-3 me-1 text-success fw-bold"> 전면밑 </span>
<input type="text" class="form-control w50px text-success viewmode inputVal" id="front_bottom_width" name="front_bottom_width" value="<?= isset($front_bottom_width) ? htmlspecialchars($front_bottom_width, ENT_QUOTES, 'UTF-8') : '' ?>">
<span class="text-center ms-2 me-1 text-danger fw-bold"> 레일폭 </span>
<input type="text" class="form-control w50px text-danger viewmode inputVal" id="rail_width" name="rail_width" value="<?= isset($rail_width) ? htmlspecialchars($rail_width, ENT_QUOTES, 'UTF-8') : '' ?>">
</div>
</td>
</tr>
<tr>
<td class="text-center " colspan="4" >
<div class="col text-center">
<label class="me-3">
<input type="radio" name="exit_direction" value="양면 점검구" <?php if($selected_exit_direction === '양면 점검구') echo 'checked'; ?>> 양면 점검구
</label>
<label class="me-3">
<input type="radio" name="exit_direction" value="밑면 점검구" <?php if($selected_exit_direction === '밑면 점검구') echo 'checked'; ?>> 밑면 점검구
</label>
<label>
<input type="radio" name="exit_direction" value="후면 점검구" <?php if($selected_exit_direction === '후면 점검구') echo 'checked'; ?>> 후면 점검구
</label>
</div>
</td>
<td class="text-center" colspan="1" >
<div class="d-flex align-items-center justify-content-center">
<span class="mx-2 fw-bold">품목 검색어</span>
<input type="text" class="form-control text-start viewmode" id="search_keyword" name="search_keyword" value="<?= isset($search_keyword) ? htmlspecialchars($search_keyword, ENT_QUOTES, 'UTF-8') : '' ?>" style="height: 30px;">
<span class="mx-2 fw-bold">비고</span>
<input type="text" class="form-control text-start viewmode" id="remark" name="remark" value="<?= isset($remark) ? htmlspecialchars($remark, ENT_QUOTES, 'UTF-8') : '' ?>" autocomplete="off" style="height: 30px;">
</div>
</td>
</tr>
<tr>
<td class="text-end" colspan="5">
<!-- 재질별 폭합 테이블 -->
<div id="materialSummaryArea" class="assembly-area" style="<?= !$is_assembly_model ? 'display:none;' : '' ?>">
<div class="d-flex justify-content-between align-items-center">
<small class="text-muted mx-1">※ 각 부품의 합계 </small>
<div class="table-responsive">
<table class="table table-bordered table-sm w-auto" id="materialSummaryTable">
<thead class="table-secondary">
<tr>
<th class="text-center" style="width: 50%;">재질</th>
<th class="text-center" style="width: 50%;">폭합계</th>
</tr>
</thead>
<tbody>
<!-- JavaScript로 동적으로 생성됨 -->
</tbody>
</table>
</div>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-sm-4" style="padding : 4px;">
<!-- 그리기 컨트롤 -->
<div class="d-flex align-items-center mb-2" style="width:260px;">
<?php if($mode!=='view') : ?>
<button id="openEditorBtn" type="button" class="btn btn-outline-dark btn-sm me-2 viewNoBtn">그리기</button>
<?php else: ?>
<div class="text-muted">
<i class="bi bi-info-circle"></i> 조회 모드, 그리기 기능 불가
</div>
<?php endif; ?>
</div>
<!-- 셔터박스용 이미지 표시 영역 (수정) -->
<div class="card mb-3">
<div class="card-body">
<div class="image-container mb-3">
<?php
// PHP: 셔터박스 JSON 파일 경로
$jsonFile = $_SERVER['DOCUMENT_ROOT'].'/shutterbox/shutterbox.json';
$imgUrl = '';
// 이미지 찾기 함수: 조건에 맞는 이미지 URL 리턴
function findImageByConditions($items, $conditions) {
foreach ($items as $item) {
$matched = true;
foreach ($conditions as $key => $value) {
if (empty($item[$key]) || $item[$key] !== $value) {
$matched = false;
break;
}
}
if ($matched && !empty($item['image'])) {
return $item['image'];
}
}
return '';
}
if ($mode === 'insert') {
// insert 모드: 기본 셔터박스 그림
switch ($selected_exit_direction) {
case '양면 점검구': $default = '../img/box/box_both.png'; break;
case '밑면 점검구': $default = '../img/box/box_bottom.png';break;
case '후면 점검구': $default = '../img/box/box_back.png'; break;
default: $default = '../img/box/box_both.png';
}
$imgUrl = $default;
} else {
// update 모드: JSON에서 검색
if (file_exists($jsonFile)) {
$shutterboxImages = json_decode(file_get_contents($jsonFile), true);
if (is_array($shutterboxImages)) {
// 우선순위 조건 배열
$searchCases = [
// 1순위: 키워드
!empty($row['search_keyword'])
? ['search_keyword' => $row['search_keyword']]
: null,
// 2순위: 모든 속성 일치
[
'box_width' => $row['box_width'],
'box_height' => $row['box_height'],
'front_bottom_width' => $row['front_bottom_width'],
'rail_width' => $row['rail_width'],
'exit_direction' => $row['exit_direction'],
],
];
// null 제거
$searchCases = array_filter($searchCases);
// 순차 검색
foreach ($searchCases as $case) {
$found = findImageByConditions($shutterboxImages, $case);
if ($found) {
$imgUrl = $found;
break;
}
}
}
}
}
?>
<?php if (!empty($imgUrl)): ?>
<img
id="targetImage"
src="<?= htmlspecialchars($imgUrl) ?>"
class="img-thumbnail img-fluid "
alt="편집할 이미지"
style="max-width:350px; cursor:pointer;"
>
<?php else: ?>
<img
id="targetImage"
src="../img/empty.png"
class="img-thumbnail img-fluid "
alt="이미지가 없습니다."
style="max-width:350px; cursor:pointer;"
>
<?php endif; ?>
<div class="paste-overlay" style="display: none;">
<i class="bi bi-clipboard-plus"></i>
<span>Ctrl+V로 이미지 붙여넣기</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row mb-2">
<div id="assemblyModelArea" class="assembly-area" style="<?= !$is_assembly_model ? 'display:none;' : '' ?>">
<div class="d-flex justify-content-between align-items-center mb-2">
<h5 class="mb-0">절곡 부품 조립</h5>
<div class="d-flex gap-2">
<button type="button" id="addPartBtn" class="btn btn-sm btn-info viewmode"><i class="bi bi-plus-lg"></i> 부품 추가</button>
<button type="button" id="removeAllPartBtn" class="btn btn-sm btn-danger viewmode"><i class="bi bi-minus-lg"></i> 전체 삭제</button>
</div>
</div>
<div class="d-flex justify-content-between align-items-center mb-2">
<div class="d-flex gap-2">
<button type="button" id="resetOrderBtn" class="btn btn-sm btn-outline-secondary viewmode"><i class="bi bi-arrow-clockwise"></i> 순서 초기화</button>
<button type="button" id="moveUpBtn" class="btn btn-sm btn-outline-primary viewmode"><i class="bi bi-arrow-up"></i> 위로</button>
<button type="button" id="moveDownBtn" class="btn btn-sm btn-outline-primary viewmode"><i class="bi bi-arrow-down"></i> 아래로</button>
</div>
<small class="text-muted">※ 순서변경은 위/아래 버튼을 사용하세요</small>
</div>
<div class="table-container d-flex">
<table class="table table-bordered" id="assemblyTable">
<tbody>
<!-- JavaScript로 동적으로 생성됨 -->
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- 셔터박스 검색 Modal -->
<div id="shutterboxSearchModal" class="modal fade" tabindex="-1">
<div class="modal-dialog modal-fullscreen modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">셔터박스 조건 및 이미지 검색</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="row mb-3">
<div class="col-md-12">
<div class="d-flex flex-wrap gap-2 align-items-center mb-3" style="flex-wrap: wrap;">
<!-- 점검구 형태 라디오 버튼 -->
<div class="mx-2">
<div class="btn-group" role="group" aria-label="점검구 형태 선택">
<?php
$exit_direction_list = ['양면 점검구', '밑면 점검구', '후면 점검구'];
$selected_exit_direction = isset($_REQUEST['exit_direction_search']) ? $_REQUEST['exit_direction_search'] : '';
// 전체 옵션 추가
$all_checked = empty($selected_exit_direction) ? 'checked' : '';
echo '<input type="radio" class="btn-check" name="shutterbox_exit_direction_search" id="shutterbox_exit_direction_all" value="" ' . $all_checked . '>';
echo '<label class="btn btn-outline-secondary btn-sm" for="shutterbox_exit_direction_all">전체</label>';
foreach ($exit_direction_list as $item) {
$checked = ($selected_exit_direction === $item) ? 'checked' : '';
echo '<input type="radio" class="btn-check" name="shutterbox_exit_direction_search" id="shutterbox_exit_direction_' . htmlspecialchars($item, ENT_QUOTES, 'UTF-8') . '" value="' . htmlspecialchars($item, ENT_QUOTES, 'UTF-8') . '" ' . $checked . '>';
echo '<label class="btn btn-outline-primary btn-sm" for="shutterbox_exit_direction_' . htmlspecialchars($item, ENT_QUOTES, 'UTF-8') . '">' . htmlspecialchars($item, ENT_QUOTES, 'UTF-8') . '</label>';
}
?>
</div>
</div>
<!-- 검색어 입력 -->
<div class="input-group" style="width: auto; min-width: 200px;">
<input type="text" class="form-control text-start" id="shutterboxSearchInput" placeholder="품목검색어 입력" style="font-size: 0.9rem; height:35px!important;">
<button class="btn btn-primary" type="button" id="shutterboxSearchBtn" style="font-size: 0.9rem;"><i class="bi bi-search"></i> 검색</button>
</div>
<!-- 검색 조건 초기화 버튼 -->
<button class="btn btn-outline-secondary" type="button" id="resetShutterboxSearchBtn" style="font-size: 0.9rem;" ><i class="bi bi-arrow-clockwise"></i> 초기화</button>
</div>
</div>
</div>
<div class="table-responsive">
<table class="table table-hover table-bordered">
<thead class="table-secondary">
<tr>
<th style="width: 50px;" class="text-center">
<input class="form-check-input" type="checkbox" id="selectAllShutterboxItems">
</th>
<th style="width: 60px;" class="text-center">순서</th>
<th>점검구 형태</th>
<th>전면부 밑면치수</th>
<th>레일(폭)</th>
<th>품목검색어</th>
<th>이미지</th>
</tr>
</thead>
<tbody id="shutterboxSearchResults">
<!-- 검색 결과가 여기에 표시됩니다 -->
</tbody>
</table>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">취소</button>
<button type="button" class="btn btn-success" id="applyShutterboxSelectionBtn">선택 적용</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// 셔터박스 검색 관련 JavaScript
$(document).ready(function() {
// 셔터박스 검색 버튼
$("#shutterboxSearchBtn").on("click", function() {
performShutterboxSearch();
});
// 라디오 버튼 변경 시 검색
$(document).on('change', 'input[name="shutterbox_exit_direction_search"]', function() {
performShutterboxSearch();
});
// 검색 조건 초기화
$("#resetShutterboxSearchBtn").on("click", function() {
// 라디오 버튼 초기화
$('#shutterboxSearchModal input[name="shutterbox_exit_direction_search"]').prop('checked', false);
$('#shutterbox_exit_direction_all').prop('checked', true);
// 검색어 초기화
$("#shutterboxSearchInput").val('');
performShutterboxSearch();
});
// 전체 선택 체크박스
$("#selectAllShutterboxItems").on("change", function() {
var isChecked = $(this).is(":checked");
$("#shutterboxSearchResults input[type='checkbox']").prop("checked", isChecked);
});
// 선택 적용 버튼
$("#applyShutterboxSelectionBtn").on("click", function() {
var selectedItems = [];
$("#shutterboxSearchResults input[type='checkbox']:checked").each(function() {
var row = $(this).closest("tr");
var itemData = {
exit_direction: row.find("td:eq(2)").text().trim(),
front_bottom_width: row.find("td:eq(3)").text().trim(),
rail_width: row.find("td:eq(4)").text().trim(),
search_keyword: row.find("td:eq(5)").text().trim()
};
selectedItems.push(itemData);
});
if (selectedItems.length > 0) {
// 선택된 아이템들을 적용
applySelectedShutterboxItems(selectedItems);
$("#shutterboxSearchModal").modal('hide');
} else {
alert("선택된 아이템이 없습니다.");
}
});
});
// 셔터박스 검색 함수
function performShutterboxSearch() {
var searchData = {
exit_direction: $('input[name="shutterbox_exit_direction_search"]:checked').val(),
searchKeyword: $("#shutterboxSearchInput").val()
};
$.ajax({
url: "search_shutterbox_json.php",
type: "GET",
data: searchData,
success: function(response) {
var tbody = $("#shutterboxSearchResults");
tbody.empty();
if (response && response.length > 0) {
response.forEach(function(item, index) {
var row = `
<tr>
<td class="text-center">
<input type="checkbox" class="form-check-input" value="${index}">
</td>
<td class="text-center">${index + 1}</td>
<td>${item.exit_direction || ''}</td>
<td>${item.front_bottom_width || ''}</td>
<td>${item.rail_width || ''}</td>
<td>${item.search_keyword || ''}</td>
<td class="text-center">
${item.image ? `<div class="image-zoom-container"><img src="${item.image}" alt="이미지" class="image-zoom" style="width:50px;height:50px;" data-src="${item.image}"></div>` : ''}
</td>
</tr>
`;
tbody.append(row);
});
} else {
tbody.append('<tr><td colspan="7" class="text-center">검색 결과가 없습니다.</td></tr>');
}
},
error: function(xhr, status, error) {
console.error("검색 오류:", error);
$("#shutterboxSearchResults").html('<tr><td colspan="7" class="text-center">검색 중 오류가 발생했습니다.</td></tr>');
}
});
}
// 선택된 셔터박스 아이템 적용 함수
function applySelectedShutterboxItems(selectedItems) {
console.log("선택된 셔터박스 아이템들:", selectedItems);
// 첫 번째 선택된 아이템의 정보를 폼에 적용
if (selectedItems.length > 0) {
var firstItem = selectedItems[0];
// 폼 필드에 값 설정
if (firstItem.front_bottom_width) {
$('#front_bottom_width').val(firstItem.front_bottom_width);
}
if (firstItem.rail_width) {
$('#rail_width').val(firstItem.rail_width);
}
if (firstItem.search_keyword) {
$('#search_keyword').val(firstItem.search_keyword);
}
if (firstItem.exit_direction) {
$('input[name="exit_direction"][value="' + firstItem.exit_direction + '"]').prop('checked', true);
}
// 변경사항 알림
Toastify({
text: '셔터박스 정보가 적용되었습니다.',
duration: 1500,
close: true,
gravity: 'top',
position: 'center',
style: { background: '#4fbe87' }
}).showToast();
}
}
// 이미지 확대 기능
$(document).on('click', '.image-zoom', function(e) {
e.stopPropagation();
var imageSrc = $(this).data('src');
if (imageSrc) {
openImageZoom(imageSrc);
}
});
function openImageZoom(imageSrc) {
document.getElementById('zoomedImage').src = imageSrc;
document.getElementById('imageZoomOverlay').style.display = 'flex';
document.body.style.overflow = 'hidden';
}
function closeImageZoom() {
document.getElementById('imageZoomOverlay').style.display = 'none';
document.body.style.overflow = 'auto';
}
// 모달 외부 클릭으로 닫기
document.getElementById('imageZoomOverlay').addEventListener('click', function(event) {
if (event.target === this) {
closeImageZoom();
}
});
</script>

258
shutterbox/fun_case.php Normal file
View File

@@ -0,0 +1,258 @@
<?php
/**
* 셔터박스 케이스 플레이트 데이터 생성 함수
*
* @param string $selected_exit_directionFlat 선택된 체크 타입 ('양면 점검구', '후면 점검구', '밑면 점검구')
* @param float|int $box_width 박스 너비
* @param float|int $box_height 박스 높이
* @param float|int $rail_width 레일 폭
* @param float|int $front_bottom_width 전면 하단 너비
* @return array 케이스 플레이트 데이터 배열
*/
function getCasePlate($selected_exit_directionFlat, $box_width, $box_height, $rail_width, $front_bottom_width) {
$productData = [];
// 박스폭이 590 이상이면 철재형태인데, 전면부 절곡 첫 치수 변경 17 -> 47로 수정
if( $box_width > 590)
$frontFirstBending = 48;
else
$frontFirstBending = 17;
// 1번 전면부 데이터 생성
$frontSectionData = [
'label' => '1번 전면부',
'surang' => 1,
'inputValues' => [$frontFirstBending , 55, $front_bottom_width, $box_height, 55, 15, 20],
'bendingRates' => [0, 1, 1, 1, 1, 0, 0],
'sums' => [],
'colors' => [false, false, false, false, false, true, false],
'aAngles' => [false, true, false, false, false, false, false]
];
if ($selected_exit_directionFlat === '양면 점검구') {
$calWidth = $box_width - $rail_width - $front_bottom_width - 50 - 50 - 17*2 - 6;
$calHeight = $box_height - 50*2 - 17*2 - 6;
$productData = [
$frontSectionData,
[
'label' => '2번 린텔부',
'surang' => 1,
'inputValues' => [20, 15, 50, 55, 30],
'bendingRates' => [0, 0, 1, 1, 0],
'sums' => [],
'colors' => [true, false, false, false, false],
'aAngles' => [false, false, false, false, false]
],
[
'label' => '3번 하부 점검구',
'surang' => 1,
'inputValues' => [17, 13, $calWidth, 13, 17],
'bendingRates' => [0, 0, 1, 1, 0],
'sums' => [],
'colors' => [true, false, false, true, false],
'aAngles' => [false, false, false, false, false]
],
[
'label' => '4번 후면 코너부',
'surang' => 2,
'inputValues' => [20, 15, 50, 50, 15, 20],
'bendingRates' => [0, 0, 1, 1, 0, 0],
'sums' => [],
'colors' => [true, false, false, false, true, false],
'aAngles' => [false, false, false, false, false, false]
],
[
'label' => '5번 후면 점검구',
'surang' => 1,
'inputValues' => [17, 13, $calHeight, 13, 17],
'bendingRates' => [0, 0, 1, 1, 0],
'sums' => [],
'colors' => [true, false, false, true, false],
'aAngles' => [false, false, false, false, false]
],
[
'label' => '6번 상부덮개',
'surang' => 1,
'inputValues' => [$box_width - 111],
'bendingRates' => [0],
'sums' => [],
'colors' => [false],
'aAngles' => [false]
],
[
'label' => '7번 마구리(가로)',
'surang' => 1,
'inputValues' => [50, $box_width + 5, 50],
'bendingRates' => [0, 1, 0],
'sums' => [],
'colors' => [false, false, false],
'aAngles' => [false, false, false]
],
[
'label' => '7번 마구리(세로)',
'surang' => 1,
'inputValues' => [50, $box_height + 5, 50],
'bendingRates' => [0, 1, 0],
'sums' => [],
'colors' => [false, false, false],
'aAngles' => [false, false, false]
]
];
}
if ($selected_exit_directionFlat === '후면 점검구') {
$calWidth = $box_width - $front_bottom_width - $rail_width;
$calHeight = $box_height - 50*2 - 17*2 - 6;
$productData = [
$frontSectionData,
[
'label' => '2번 린텔부',
'surang' => 1,
'inputValues' => [25, 15, 50, $calWidth, 55, 30],
'bendingRates' => [0, 0, 1, 1, 1, 0],
'sums' => [],
'colors' => [true, false, false, false, false, false],
'aAngles' => [false, false, false, false, false, false]
],
[
'label' => '3번 후면 점검구',
'surang' => 1,
'inputValues' => [17, 13, $calHeight, 13, 17],
'bendingRates' => [0, 0, 1, 1, 0],
'sums' => [],
'colors' => [true, false, false, true, false],
'aAngles' => [false, false, false, false, false]
],
[
'label' => '4번 후면 코너부',
'surang' => 1,
'inputValues' => [20, 15, 50, 50, 15, 20],
'bendingRates' => [0, 0, 1, 1, 0, 0],
'sums' => [],
'colors' => [true, false, false, false, true, false],
'aAngles' => [false, false, false, false, false, false]
],
[
'label' => '5번 상부덮개',
'surang' => 1,
'inputValues' => [$box_width - 111],
'bendingRates' => [0],
'sums' => [],
'colors' => [false],
'aAngles' => [false]
],
[
'label' => '6번 마구리(가로)',
'surang' => 1,
'inputValues' => [50, $box_width + 5, 50],
'bendingRates' => [0, 1, 0],
'sums' => [],
'colors' => [false, false, false],
'aAngles' => [false, false, false]
],
[
'label' => '6번 마구리(세로)',
'surang' => 1,
'inputValues' => [50, $box_height + 5, 50],
'bendingRates' => [0, 1, 0],
'sums' => [],
'colors' => [false, false, false],
'aAngles' => [false, false, false]
]
];
}
if($selected_exit_directionFlat === '밑면 점검구')
{
// 2번 린텔부 데이터 생성 (고정치수)
$lintelSectionData = [
'label' => '2번 린텔부',
'surang' => 1,
'inputValues' => [20,15,50,55,30],
'bendingRates' => [0, 0, 1, 1, 0],
'sums' => [], // 나중에 계산됨
'colors' => [true, false, false, false, false],
'aAngles' => [false, false, false, false, false]
];
// 3번 하부 점검구
$calWidth = $box_width - $rail_width - $front_bottom_width - 50 - 50 - 17*2 -6 ;
$bottomExitSectionData = [
'label' => '3번 하부 점검구',
'surang' => 1,
'inputValues' => [17, 13, $calWidth , 13, 17],
'bendingRates' => [0, 0, 1, 1, 0],
'sums' => [], // 나중에 계산됨
'colors' => [true, false, false, true, false],
'aAngles' => [false, false, false, false, false]
];
// 4번 후면부
$cornerSectionData = [
'label' => '4번 후면부',
'surang' => 1,
'inputValues' => [20,15,50,$box_height,50,15,20],
'bendingRates' => [0, 0, 1, 1, 1, 0, 0],
'sums' => [], // 나중에 계산됨
'colors' => [true, false, false, false, false, true, false ],
'aAngles' => [false, false, false, false, false, false, false]
];
// 5번 상부덮개
$topCoverSectionData = [
'label' => '5번 상부덮개',
'surang' => 1,
'inputValues' => [$box_width - 111],
'bendingRates' => [0],
'sums' => [], // 나중에 계산됨
'colors' => [false],
'aAngles' => [false]
];
// 6번 마구리(가로)
$calWidth = $box_width+5;
$finishBox_width = [
'label' => '6번 마구리(가로)',
'surang' => 1,
'inputValues' => [50, $calWidth , 50],
'bendingRates' => [0, 1, 0],
'sums' => [], // 나중에 계산됨
'colors' => [false, false, false ],
'aAngles' => [false, false, false ]
];
// 6번 마구리(세로)
$calHeight = $box_height + 5;
$finishBox_height = [
'label' => '6번 마구리(세로)',
'surang' => 1,
'inputValues' => [50, $calHeight , 50],
'bendingRates' => [0, 1, 0],
'sums' => [], // 나중에 계산됨
'colors' => [false, false, false ],
'aAngles' => [false, false, false ]
];
// 테이블에 출력할 데이터를 배열로 정리
$productData = [$frontSectionData, $lintelSectionData,$bottomExitSectionData, $cornerSectionData, $topCoverSectionData, $finishBox_width, $finishBox_height ];
}
// sums 계산 함수
$calculateSums = function($product) {
$accumulatedSum = 0;
$sums = [];
foreach ($product['inputValues'] as $index => $inputVal) {
$bendingRateVal = $product['bendingRates'][$index];
$result = $inputVal - $bendingRateVal;
$accumulatedSum += $result;
$sums[] = $accumulatedSum;
}
return $sums;
};
// 각 제품의 sums 계산
foreach ($productData as &$product) {
$product['sums'] = $calculateSums($product);
}
unset($product);
return $productData;
}
?>

3054
shutterbox/list.php Normal file

File diff suppressed because it is too large Load Diff

119
shutterbox/model_flat.php Normal file
View File

@@ -0,0 +1,119 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
include $_SERVER['DOCUMENT_ROOT'] . '/load_header.php';
require_once $_SERVER['DOCUMENT_ROOT'] . '/shutterbox/fun_case.php';
// 기본값 세팅
$type = $_POST['exit_direction'] ?? '양면 점검구';
$box_width = isset($_POST['box_width']) ? floatval($_POST['box_width']) : 500;
$box_height = isset($_POST['box_height']) ? floatval($_POST['box_height']) : 380;
$rail_width = isset($_POST['rail_width']) ? floatval($_POST['rail_width']) : 70;
$front_bottom_width = isset($_POST['front_bottom_width']) ? floatval($_POST['front_bottom_width']) : 50;
$blocks = [];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$blocks = getCasePlate($type, $box_width, $box_height, $rail_width, $front_bottom_width);
}
?>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>점검구 형태별 기본 전개도</title>
</head>
<body>
<div class="container py-4">
<h3 class="mb-4">점검구 형태별 기본 전개도 자동 생성</h3>
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">조건 입력</h5>
</div>
<div class="card-body">
<form method="post" class="row g-3">
<div class="col-md-3">
<label class="form-label">점검구 형태</label>
<select name="exit_direction" class="form-select" style="height: calc(1.5em + 0.75rem + 2px);">
<option value="양면 점검구"<?= $type==='양면 점검구'?' selected':''?>>양면 점검구</option>
<option value="후면 점검구"<?= $type==='후면 점검구'?' selected':''?>>후면 점검구</option>
<option value="밑면 점검구"<?= $type==='밑면 점검구'?' selected':''?>>밑면 점검구</option>
</select>
</div>
<div class="col-md-2">
<label class="form-label">박스폭</label>
<input type="number" name="box_width" value="<?=htmlspecialchars($box_width)?>" class="form-control" style="height: calc(1.5em + 0.75rem + 2px);">
</div>
<div class="col-md-2">
<label class="form-label">박스높이</label>
<input type="number" name="box_height" value="<?=htmlspecialchars($box_height)?>" class="form-control" style="height: calc(1.5em + 0.75rem + 2px);">
</div>
<div class="col-md-2">
<label class="form-label">레일폭</label>
<input type="number" name="rail_width" value="<?=htmlspecialchars($rail_width)?>" class="form-control" style="height: calc(1.5em + 0.75rem + 2px);">
</div>
<div class="col-md-2">
<label class="form-label">전면하단폭</label>
<input type="number" name="front_bottom_width" value="<?=htmlspecialchars($front_bottom_width)?>" class="form-control" style="height: calc(1.5em + 0.75rem + 2px);">
</div>
<div class="col-md-1 d-flex align-items-end">
<button type="submit" class="btn btn-primary w-100">생성</button>
</div>
</form>
</div>
</div>
<?php if (!empty($blocks)): ?>
<div class="row">
<?php foreach ($blocks as $block): ?>
<div class="col-12 mb-3">
<div class="card">
<div class="card-header">
<strong><?=htmlspecialchars($block['label'])?></strong> (수량: <?=intval($block['surang'])?>)
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered table-sm mb-0">
<tr class="table-light">
<th class="text-center" style="width:100px;">입력값</th>
<?php foreach ($block['inputValues'] as $v) echo "<td class='text-center'>$v</td>"; ?>
</tr>
<tr>
<th class="text-center table-light">연신율</th>
<?php foreach ($block['bendingRates'] as $v) echo "<td class='text-center'>$v</td>"; ?>
</tr>
<tr class="table-warning">
<th class="text-center">합계</th>
<?php foreach ($block['sums'] as $v) echo "<td class='text-center fw-bold'>$v</td>"; ?>
</tr>
<tr>
<th class="text-center table-light">음영</th>
<?php foreach ($block['colors'] as $v) echo "<td class='text-center'>".($v?'<span class="badge bg-dark">O</span>':'')."</td>"; ?>
</tr>
<tr>
<th class="text-center table-light">A각</th>
<?php foreach ($block['aAngles'] as $v) echo "<td class='text-center'>".($v?'<span class="badge bg-primary">A</span>':'')."</td>"; ?>
</tr>
</table>
</div>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php elseif ($_SERVER['REQUEST_METHOD'] === 'POST'): ?>
<div class="alert alert-warning">
<i class="bi bi-exclamation-triangle"></i> 생성된 데이터가 없습니다.
</div>
<?php endif; ?>
</div>
<script>
$(document).ready(function(){
// 로더 숨기기
var loader = document.getElementById('loadingOverlay');
if(loader)
loader.style.display = 'none';
});
</script>
</body>
</html>

126
shutterbox/process.php Normal file
View File

@@ -0,0 +1,126 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
$tablename = isset($_REQUEST['tablename']) ? $_REQUEST['tablename'] : '';
$mode = isset($_REQUEST['mode']) ? $_REQUEST['mode'] : '';
header("Content-Type: application/json"); // JSON 콘텐츠 유형 설정
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
include "_request.php";
// search_tag에 추가된 컬럼들을 포함
$search_tag = $exit_direction . ' ' .
$registration_date . ' ' .
$author . ' ' .
$remark . ' ' .
$front_bottom_width . ' ' .
$rail_width . ' ' .
$box_width . ' ' .
$box_height . ' ' .
$bending_components . ' ' .
$search_keyword . ' ' .
$material_summary . ' ';
if ($mode == "modify") {
$update_log = date("Y-m-d H:i:s") . " - " . $_SESSION["name"] . " " . $update_log . "&#10";
try {
$pdo->beginTransaction();
// SQL 쿼리 생성 (업데이트)
$sql = "UPDATE " . $DB . "." . $tablename . " SET ";
$sql .= "registration_date = ?, exit_direction = ?, author = ?, remark = ?, update_log = ?, search_tag = ?, ";
$sql .= "front_bottom_width = ?, rail_width = ?, box_width = ?, box_height = ?, bending_components = ?, search_keyword = ?, material_summary = ? ";
$sql .= "WHERE num = ? LIMIT 1"; // num이 일치하는 하나의 레코드만 업데이트
$stmh = $pdo->prepare($sql);
// 변수 바인딩
$stmh->bindValue(1, $registration_date, PDO::PARAM_STR);
$stmh->bindValue(2, $exit_direction, PDO::PARAM_STR);
$stmh->bindValue(3, $author, PDO::PARAM_STR);
$stmh->bindValue(4, $remark, PDO::PARAM_STR);
$stmh->bindValue(5, $update_log, PDO::PARAM_STR);
$stmh->bindValue(6, $search_tag, PDO::PARAM_STR);
$stmh->bindValue(7, $front_bottom_width, PDO::PARAM_STR);
$stmh->bindValue(8, $rail_width, PDO::PARAM_STR);
$stmh->bindValue(9, $box_width, PDO::PARAM_STR);
$stmh->bindValue(10, $box_height, PDO::PARAM_STR);
$stmh->bindValue(11, $bending_components, PDO::PARAM_STR);
$stmh->bindValue(12, $search_keyword, PDO::PARAM_STR);
$stmh->bindValue(13, $material_summary, PDO::PARAM_STR);
$stmh->bindValue(14, $num, PDO::PARAM_INT);
// 실행
$stmh->execute();
$pdo->commit();
} catch (PDOException $Exception) {
$pdo->rollBack();
print "오류: " . $Exception->getMessage();
}
}
else if ($mode == "insert" || $mode == "copy" || $mode == '' || $mode == null) {
$update_log = date("Y-m-d H:i:s") . " - " . $_SESSION["name"] . " " . $update_log . "&#10";
// 데이터 삽입
try {
$pdo->beginTransaction();
// SQL 쿼리 생성 (삽입)
$sql = "INSERT INTO " . $DB . "." . $tablename . " (";
$sql .= "registration_date, exit_direction, author, remark, update_log, search_tag, ";
$sql .= "front_bottom_width, rail_width, box_width, box_height, bending_components, search_keyword, material_summary ";
$sql .= ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
$stmh = $pdo->prepare($sql);
// 변수 바인딩
$stmh->bindValue(1, $registration_date, PDO::PARAM_STR);
$stmh->bindValue(2, $exit_direction, PDO::PARAM_STR);
$stmh->bindValue(3, $author, PDO::PARAM_STR);
$stmh->bindValue(4, $remark, PDO::PARAM_STR);
$stmh->bindValue(5, $update_log, PDO::PARAM_STR);
$stmh->bindValue(6, $search_tag, PDO::PARAM_STR);
$stmh->bindValue(7, $front_bottom_width, PDO::PARAM_STR);
$stmh->bindValue(8, $rail_width, PDO::PARAM_STR);
$stmh->bindValue(9, $box_width, PDO::PARAM_STR);
$stmh->bindValue(10, $box_height, PDO::PARAM_STR);
$stmh->bindValue(11, $bending_components, PDO::PARAM_STR);
$stmh->bindValue(12, $search_keyword, PDO::PARAM_STR);
$stmh->bindValue(13, $material_summary, PDO::PARAM_STR);
// 실행
$stmh->execute();
// 삽입된 마지막 ID를 가져오기
$num = $pdo->lastInsertId();
$pdo->commit();
} catch (PDOException $Exception) {
$pdo->rollBack();
print "오류: " . $Exception->getMessage();
}
}
else if ($mode == "delete") { // 데이터 삭제
try {
$pdo->beginTransaction();
$sql = "UPDATE " . $DB . "." . $tablename . " SET is_deleted=1 WHERE num = ?";
$stmh = $pdo->prepare($sql);
$stmh->bindValue(1, $num, PDO::PARAM_INT);
$stmh->execute();
$pdo->commit();
} catch (PDOException $ex) {
$pdo->rollBack();
print "오류: ".$ex->getMessage();
}
}
$data = [
'num' => $num,
'mode' => $mode
];
echo json_encode($data, JSON_UNESCAPED_UNICODE);
?>

View File

@@ -0,0 +1,103 @@
<?php
// put_shutterbox_image.php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
if (!isset($_SESSION["level"]) || $_SESSION["level"] > 5) {
sleep(1);
header("HTTP/1.1 403 Forbidden");
exit;
}
$jsonFile = $_SERVER['DOCUMENT_ROOT'] . '/shutterbox/shutterbox.json';
// POST 필드
$box_width = trim($_POST['box_width'] ?? '');
$box_height = trim($_POST['box_height'] ?? '');
$exit_direction = trim($_POST['exit_direction'] ?? '');
$rail_width = trim($_POST['rail_width'] ?? '');
$front_bottom_width= trim($_POST['front_bottom_width']?? '');
$search_keyword = trim($_POST['search_keyword'] ?? '');
$index = isset($_POST['index']) ? intval($_POST['index']) : null;
// JSON 읽기
$shutterboxData = [];
if (file_exists($jsonFile)) {
$json = file_get_contents($jsonFile);
$shutterboxData = json_decode($json, true) ?: [];
}
// 이미지 업로드
$imagePath = '';
$uploadDir = $_SERVER['DOCUMENT_ROOT'] . '/shutterbox/images/';
if (!file_exists($uploadDir)) mkdir($uploadDir, 0777, true);
if (isset($_FILES['upfile']) && $_FILES['upfile']['error'] === UPLOAD_ERR_OK) {
$orig = $_FILES['upfile']['name'];
$tmp = $_FILES['upfile']['tmp_name'];
$info = pathinfo($orig);
$name = preg_replace('/[^A-Za-z0-9_\-]/', '_', $info['filename']);
$new = date("Y_m_d_H_i_s") . "_{$name}" . (!empty($info['extension']) ? ".{$info['extension']}" : '');
$dest = $uploadDir . $new;
if (!move_uploaded_file($tmp, $dest)) {
echo json_encode(['error' => '파일 업로드 실패']);
exit;
}
$imagePath = '/shutterbox/images/' . $new;
} else {
echo json_encode(['error' => '업로드된 이미지가 없습니다']);
exit;
}
// 새 항목 배열
$newItem = [
'box_width' => $box_width,
'box_height' => $box_height,
'exit_direction' => $exit_direction,
'rail_width' => $rail_width,
'front_bottom_width'=> $front_bottom_width,
'search_keyword' => $search_keyword,
'image' => $imagePath
];
// 같은 조건의 데이터가 있는지 확인하고 덮어쓰기 또는 신규 추가
$foundIndex = null;
// 기존 데이터에서 같은 조건의 항목 찾기
foreach ($shutterboxData as $idx => $item) {
if ($item['box_width'] === $box_width &&
$item['box_height'] === $box_height &&
$item['exit_direction'] === $exit_direction &&
$item['rail_width'] === $rail_width &&
$item['front_bottom_width'] === $front_bottom_width &&
$item['search_keyword'] === $search_keyword) {
$foundIndex = $idx;
break;
}
}
// 덮어쓰기 or 신규 추가
if ($foundIndex !== null) {
// 같은 조건의 데이터가 있으면 덮어쓰기
$shutterboxData[$foundIndex] = $newItem;
$action = 'updated';
} else {
// 같은 조건의 데이터가 없으면 새로 추가
$shutterboxData[] = $newItem;
$action = 'added';
}
// JSON 저장
if (false === file_put_contents(
$jsonFile,
json_encode($shutterboxData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
)) {
echo json_encode(['error' => 'JSON 저장 실패']);
exit;
}
// 성공 응답
echo json_encode([
'success' => true,
'imagePath' => $imagePath,
'action' => $action,
'message' => $action === 'updated' ? '기존 데이터가 업데이트되었습니다.' : '새 데이터가 추가되었습니다.'
]);

View File

@@ -0,0 +1,128 @@
<?php
// 기초절곡정보 검색
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
// POST 데이터 받기
$search_keyword = isset($_POST['search_keyword']) ? trim($_POST['search_keyword']) : '';
$itemName = isset($_POST['itemName']) ? trim($_POST['itemName']) : '';
$material = isset($_POST['material']) ? trim($_POST['material']) : '';
$item_bending = isset($_POST['item_bending']) ? trim($_POST['item_bending']) : '';
$exit_direction = isset($_POST['exit_direction']) ? trim($_POST['exit_direction']) : '';
$front_bottom_width = isset($_POST['front_bottom_width']) ? trim($_POST['front_bottom_width']) : '';
$rail_width = isset($_POST['rail_width']) ? trim($_POST['rail_width']) : '';
$box_width = isset($_POST['box_width']) ? trim($_POST['box_width']) : '';
$box_height = isset($_POST['box_height']) ? trim($_POST['box_height']) : '';
$response = array('success' => false, 'data' => null, 'message' => '');
try {
$pdo = db_connect();
// 품목 검색어가 있는 경우
if (!empty($search_keyword)) {
$sql = "SELECT num, itemName, item_spec, material, search_keyword, item_bending, exit_direction, front_bottom_width, rail_width, box_width, box_height FROM {$DB}.bending
WHERE search_keyword LIKE :search_keyword
ORDER BY num DESC
LIMIT 1";
$stmh = $pdo->prepare($sql);
$stmh->bindValue(':search_keyword', '%' . $search_keyword . '%');
$stmh->execute();
$row = $stmh->fetch(PDO::FETCH_ASSOC);
if ($row) {
$response['success'] = true;
$response['data'] = $row;
$response['message'] = '품목검색어로 검색된 결과입니다.';
} else {
$response['message'] = '품목검색어로 검색된 결과가 없습니다.';
}
}
// 품목 검색어가 없는 경우 - 조건별 검색 (품목명은 '셔터박스'로 고정)
else {
// 규격을 120*70 형태로 변환
$formatted_spec = '';
if (!empty($item_spec)) {
// 기존 규격에서 가로*세로 형태로 변환
// 예: 120*70 형태로 변환
$formatted_spec = $item_spec;
}
// 조건별 검색 쿼리 구성 (절곡그룹은 찾기)
$where_conditions = array("item_bending = :item_bending");
$params = array(':item_bending' => $item_bending);
if (!empty($exit_direction)) {
$where_conditions[] = "exit_direction = :exit_direction";
$params[':exit_direction'] = $exit_direction;
}
if (!empty($front_bottom_width)) {
$where_conditions[] = "front_bottom_width = :front_bottom_width";
$params[':front_bottom_width'] = $front_bottom_width;
}
if (!empty($rail_width)) {
$where_conditions[] = "rail_width = :rail_width";
$params[':rail_width'] = $rail_width;
}
if (!empty($box_width)) {
$where_conditions[] = "box_width = :box_width";
$params[':box_width'] = $box_width;
}
if (!empty($box_height)) {
$where_conditions[] = "box_height = :box_height";
$params[':box_height'] = $box_height;
}
// 추가 검색 조건들
if (!empty($material)) {
$where_conditions[] = "material = :material";
$params[':material'] = $material;
}
if (!empty($itemName)) {
$where_conditions[] = "itemName = :itemName";
$params[':itemName'] = $itemName;
}
$sql = "SELECT num, itemName, material, search_keyword, item_bending, exit_direction, front_bottom_width, rail_width, box_width, box_height FROM {$DB}.bending
WHERE " . implode(' AND ', $where_conditions) . "
ORDER BY num DESC
LIMIT 1";
$stmh = $pdo->prepare($sql);
// 파라미터 바인딩
foreach ($params as $key => $value) {
$stmh->bindValue($key, $value);
}
$stmh->execute();
$row = $stmh->fetch(PDO::FETCH_ASSOC);
if ($row) {
$response['success'] = true;
$response['data'] = $row;
$response['message'] = '조건별 검색으로 찾은 결과입니다.';
} else {
$row['num'] = '';
$response['data'] = $row;
$response['success'] = false;
$response['message'] = '조건에 맞는 결과가 없습니다.';
}
}
} catch (PDOException $e) {
$response['message'] = '검색 중 오류가 발생했습니다: ' . $e->getMessage();
}
// JSON 응답
header('Content-Type: application/json; charset=utf-8');
echo json_encode($response, JSON_UNESCAPED_UNICODE);
?>

View File

@@ -0,0 +1,150 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
// GET 파라미터 받기 - JavaScript에서 보내는 파라미터 이름과 일치
$selectedItem = $_GET['selectedItem'] ?? '';
$selectedUA = $_GET['selectedUA'] ?? '';
$selectedBendingCategory = $_GET['selectedBendingCategory'] ?? '';
$selectedName = $_GET['selectedName'] ?? '';
$selectedMaterial = $_GET['selectedMaterial'] ?? '';
$search = $_GET['search'] ?? '';
// SQL 쿼리 구성
$sql = "SELECT * FROM {$DB}.bending WHERE is_deleted IS NULL";
$params = [];
// 필터 (item_sep)
if (!empty($selectedItem)) {
$sql .= " AND item_sep = :selectedItem";
$params[':selectedItem'] = $selectedItem;
}
// 인정/비인정 필터 (model_UA)
if (!empty($selectedUA)) {
$sql .= " AND model_UA = :selectedUA";
$params[':selectedUA'] = $selectedUA;
}
// 중분류 필터 (item_bending)
if (!empty($selectedBendingCategory)) {
$sql .= " AND item_bending = :selectedBendingCategory";
$params[':selectedBendingCategory'] = $selectedBendingCategory;
}
// 품명 필터 (itemName)
if (!empty($selectedName)) {
$sql .= " AND itemName = :selectedName";
$params[':selectedName'] = $selectedName;
}
// 재질 필터 (material)
if (!empty($selectedMaterial)) {
$sql .= " AND material = :selectedMaterial";
$params[':selectedMaterial'] = $selectedMaterial;
}
// 검색어 필터 (모든 텍스트 필드에서 검색)
if (!empty($search)) {
$searchTerm = '%' . $search . '%';
$sql .= " AND (itemName LIKE :search_name OR material LIKE :search_material OR item_sep LIKE :search_sep OR item_bending LIKE :search_bending OR model_UA LIKE :selectedUA)";
$params[':search_name'] = $searchTerm;
$params[':search_material'] = $searchTerm;
$params[':search_sep'] = $searchTerm;
$params[':search_bending'] = $searchTerm;
$params[':selectedUA'] = $searchTerm;
}
$sql .= " ORDER BY num DESC";
// 디버깅용 로그
error_log("Search SQL: " . $sql);
error_log("Search Params: " . print_r($params, true));
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
// shutterbox.json 읽기
$jsonFile = $_SERVER['DOCUMENT_ROOT'].'/shutterbox/shutterbox.json';
$shutterboxData = [];
if (file_exists($jsonFile)) {
$jsonContent = file_get_contents($jsonFile);
$shutterboxData = json_decode($jsonContent, true);
if (!is_array($shutterboxData)) $shutterboxData = [];
}
// 결과 출력
if (empty($results)) {
echo '<tr><td colspan="9" class="text-center">검색 결과가 없습니다.</td></tr>';
} else {
foreach ($results as $row) {
$num = $row['num'];
$itemName = $row['itemName'] ?? '';
$material = $row['material'] ?? '';
$item_sep = $row['item_sep'] ?? '';
$item_bending = $row['item_bending'] ?? '';
$model_UA = $row['model_UA'] ?? '';
$imgdata = $row['imgdata'] ?? '';
$widthsum = $row['widthsum'] ?? '';
$exit_direction = $row['exit_direction'] ?? '';
$front_bottom_width = $row['front_bottom_width'] ?? '';
$rail_width = $row['rail_width'] ?? '';
$box_width = $row['box_width'] ?? '';
$box_height = $row['box_height'] ?? '';
$search_keyword = $row['search_keyword'] ?? '';
// guiderail.json에서 상세 데이터 찾기 (모델명+형태+마감+대분류+UA)
$summary = '';
// bending/write_form.php와 동일한 구조로 데이터 구성
$inputList = $row['inputList'] ?? [];
$bendingrateList = $row['bendingrateList'] ?? [];
$sumList = $row['sumList'] ?? [];
$colorList = $row['colorList'] ?? [];
$AList = $row['AList'] ?? [];
// 등록일 추가
$registration_date = $row['registration_date'] ?? '';
$summary = htmlspecialchars(json_encode([
'inputList' => $inputList,
'bendingrateList' => $bendingrateList,
'calcAfterList' => $calcAfterList,
'sumList' => $sumList,
'colorList' => $colorList,
'AList' => $AList
], JSON_UNESCAPED_UNICODE), ENT_QUOTES, 'UTF-8');
$box_size = htmlspecialchars($box_width . 'x' . $box_height, ENT_QUOTES, 'UTF-8');
echo '<tr data-num="' . $num . '" class="search-result-row">';
echo '<td class="text-center">';
echo '<input class="form-check-input bending-item-checkbox" type="checkbox" data-num="' . $num . '">';
echo '</td>';
echo '<td class="text-center order-number" style="width: 60px; font-weight: bold; color: #007bff;">-</td>';
echo '<td class="text-center">' . htmlspecialchars($registration_date, ENT_QUOTES, 'UTF-8') . '</td>';
echo '<td class="text-center">' . htmlspecialchars($item_sep, ENT_QUOTES, 'UTF-8') . '</td>';
echo '<td class="text-center">' . htmlspecialchars($model_UA, ENT_QUOTES, 'UTF-8') . '</td>';
echo '<td class="text-center">' . htmlspecialchars($item_bending, ENT_QUOTES, 'UTF-8') . '</td>';
echo '<td class="text-center">' . htmlspecialchars($exit_direction, ENT_QUOTES, 'UTF-8') . '</td>';
echo '<td class="text-center">' . htmlspecialchars($box_size, ENT_QUOTES, 'UTF-8') . '</td>';
echo '<td class="text-center">' . htmlspecialchars($front_bottom_width, ENT_QUOTES, 'UTF-8') . '</td>';
echo '<td class="text-center">' . htmlspecialchars($rail_width, ENT_QUOTES, 'UTF-8') . '</td>';
echo '<td class="text-center">' . htmlspecialchars($itemName, ENT_QUOTES, 'UTF-8') . '</td>';
echo '<td class="text-center">' . htmlspecialchars($search_keyword, ENT_QUOTES, 'UTF-8') . '</td>';
echo '<td class="text-center">' . htmlspecialchars($material, ENT_QUOTES, 'UTF-8') . '</td>';
echo '<td class="text-center">';
if ($imgdata) {
echo '<img src="/bending/img/' . htmlspecialchars($imgdata, ENT_QUOTES, 'UTF-8') . '"
class="search-zoomable-image"
style="width: 40px; height: 24px; object-fit: cover; cursor: pointer;"
data-src="/bending/img/' . htmlspecialchars($imgdata, ENT_QUOTES, 'UTF-8') . '">';
}
echo '</td>';
// 합계 셀: data-summary 속성 추가
echo '<td class="text-center mini-summary-trigger" ' . ($summary ? 'data-summary=\'' . $summary . '\'' : '') . '>' . htmlspecialchars($widthsum, ENT_QUOTES, 'UTF-8') . '</td>';
echo '</tr>';
}
}
?>

View File

@@ -0,0 +1,61 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
// 검색 조건 받기
$exit_direction = $_GET['exit_direction'] ?? '';
$searchKeyword = $_GET['searchKeyword'] ?? '';
// shutterbox.json 파일 읽기
$jsonFile = $_SERVER['DOCUMENT_ROOT'].'/shutterbox/shutterbox.json';
$shutterboxData = [];
if (file_exists($jsonFile)) {
$jsonContent = file_get_contents($jsonFile);
$shutterboxData = json_decode($jsonContent, true);
if (!is_array($shutterboxData)) {
$shutterboxData = [];
}
}
// 검색 조건에 따라 필터링
$filteredData = [];
foreach ($shutterboxData as $item) {
// 점검구 형태 필터
if (!empty($exit_direction) && $item['exit_direction'] !== $exit_direction) {
continue;
}
// 검색어 필터
if (!empty($searchKeyword)) {
$searchTrimmed = str_replace(' ', '', $searchKeyword);
$searchFields = [
$item['search_keyword'] ?? '',
$item['exit_direction'] ?? '',
$item['front_bottom_width'] ?? '',
$item['rail_width'] ?? '',
$item['box_width'] ?? '',
$item['box_height'] ?? ''
];
$found = false;
foreach ($searchFields as $field) {
if (stripos($field, $searchTrimmed) !== false) {
$found = true;
break;
}
}
if (!$found) {
continue;
}
}
// 필터링을 통과한 항목 저장
$filteredData[] = $item;
}
// JSON 형태로 결과 출력
header('Content-Type: application/json');
echo json_encode($filteredData);
?>

299
shutterbox/shutterbox.json Normal file
View File

@@ -0,0 +1,299 @@
[
{
"box_width": "500",
"box_height": "380",
"exit_direction": "후면 점검구",
"rail_width": "70",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_21_00_59_52_drawing.png"
},
{
"box_width": "500",
"box_height": "350",
"exit_direction": "양면 점검구",
"rail_width": "70",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_20_23_03_26_drawing.png"
},
{
"box_width": "500",
"box_height": "350",
"exit_direction": "밑면 점검구",
"rail_width": "70",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_20_23_17_27_drawing.png"
},
{
"box_width": "500",
"box_height": "350",
"exit_direction": "후면 점검구",
"rail_width": "70",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_21_01_00_06_drawing.png"
},
{
"box_width": "700",
"box_height": "600",
"exit_direction": "양면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_21_00_49_30_drawing.png"
},
{
"box_width": "700",
"box_height": "600",
"exit_direction": "밑면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_21_00_53_54_drawing.png"
},
{
"box_width": "700",
"box_height": "600",
"exit_direction": "후면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_21_00_58_21_drawing.png"
},
{
"box_width": "780",
"box_height": "650",
"exit_direction": "양면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_21_01_28_19_drawing.png"
},
{
"box_width": "780",
"box_height": "650",
"exit_direction": "밑면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_21_01_31_10_drawing.png"
},
{
"box_width": "780",
"box_height": "650",
"exit_direction": "후면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_21_01_33_18_drawing.png"
},
{
"box_width": "650",
"box_height": "550",
"exit_direction": "양면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_22_15_52_18_drawing.png"
},
{
"box_width": "650",
"box_height": "550",
"exit_direction": "밑면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_22_16_00_22_drawing.png"
},
{
"box_width": "650",
"box_height": "550",
"exit_direction": "후면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_22_16_10_26_drawing.png"
},
{
"box_width": "750",
"box_height": "500",
"search_keyword": "",
"exit_direction": "양면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"image": "\/shutterbox\/images\/2025_07_11_16_18_26_image_copy.png"
},
{
"box_width": "750",
"box_height": "500",
"search_keyword": "",
"exit_direction": "밑면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"image": "\/shutterbox\/images\/2025_07_11_16_19_08_image_copy.png"
},
{
"box_width": "750",
"box_height": "500",
"search_keyword": "",
"exit_direction": "후면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"image": "\/shutterbox\/images\/2025_07_11_16_19_30_image_copy.png"
},
{
"box_width": "780",
"box_height": "600",
"exit_direction": "양면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_21_01_13_57_drawing.png"
},
{
"box_width": "780",
"box_height": "600",
"exit_direction": "밑면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_21_01_16_59_drawing.png"
},
{
"box_width": "780",
"box_height": "600",
"exit_direction": "후면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_21_01_19_21_drawing.png"
},
{
"box_width": "700",
"box_height": "550",
"exit_direction": "양면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_21_00_33_58_drawing.png"
},
{
"box_width": "700",
"box_height": "550",
"exit_direction": "밑면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_21_00_36_50_drawing.png"
},
{
"box_width": "700",
"box_height": "550",
"exit_direction": "후면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_21_00_59_07_drawing.png"
},
{
"box_width": "650",
"box_height": "500",
"exit_direction": "양면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_22_15_35_40_drawing.png"
},
{
"box_width": "650",
"box_height": "500",
"exit_direction": "밑면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_22_15_39_03_drawing.png"
},
{
"box_width": "650",
"box_height": "500",
"exit_direction": "후면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_22_15_42_39_drawing.png"
},
{
"box_width": "500",
"box_height": "380",
"exit_direction": "밑면 점검구",
"rail_width": "70",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_20_22_36_19_drawing.png"
},
{
"box_width": "500",
"box_height": "380",
"exit_direction": "양면 점검구",
"rail_width": "70",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_20_21_55_42_drawing.png"
},
{
"box_width": "600",
"box_height": "500",
"exit_direction": "양면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_20_23_37_57_drawing.png"
},
{
"box_width": "600",
"box_height": "500",
"exit_direction": "밑면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_20_23_52_15_drawing.png"
},
{
"box_width": "600",
"box_height": "500",
"exit_direction": "후면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_20_23_55_24_drawing.png"
},
{
"box_width": "600",
"box_height": "550",
"exit_direction": "양면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_20_23_58_41_drawing.png"
},
{
"box_width": "600",
"box_height": "550",
"exit_direction": "밑면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_21_00_10_47_drawing.png"
},
{
"box_width": "600",
"box_height": "550",
"exit_direction": "후면 점검구",
"rail_width": "75",
"front_bottom_width": "50",
"search_keyword": "",
"image": "\/shutterbox\/images\/2025_07_21_00_59_27_drawing.png"
}
]

View File

@@ -0,0 +1,620 @@
<?php
// shutterboxlist.php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
if (!isset($_SESSION["level"]) || $_SESSION["level"] > 5) {
sleep(1);
header("Location: /login/login_form.php");
exit;
}
$title_message = '케이스 결합형태 이미지 관리';
include $_SERVER['DOCUMENT_ROOT'] . '/load_header.php';
$jsonFile = $_SERVER['DOCUMENT_ROOT'] . '/shutterbox/shutterbox.json';
$search_keyword = $_REQUEST['search_keyword'] ?? '';
// JSON 파일이 존재하면 읽어오고, 없으면 빈 배열 생성
$shutterboxData = [];
if (file_exists($jsonFile)) {
$jsonContent = file_get_contents($jsonFile);
$shutterboxData = json_decode($jsonContent, true);
if (!is_array($shutterboxData)) {
$shutterboxData = [];
}
}
// POST 요청 처리: 추가, 수정, 삭제
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = isset($_POST['action']) ? $_POST['action'] : '';
$index = isset($_POST['index']) ? intval($_POST['index']) : -1;
$box_width = isset($_POST['box_width']) ? trim($_POST['box_width']) : '';
$box_height = isset($_POST['box_height']) ? trim($_POST['box_height']) : '';
$exit_direction = isset($_POST['exit_direction']) ? trim($_POST['exit_direction']) : '';
$rail_width = isset($_POST['rail_width']) ? trim($_POST['rail_width']) : '';
$front_bottom_width = isset($_POST['front_bottom_width']) ? trim($_POST['front_bottom_width']) : '';
$search_keyword = isset($_POST['search_keyword']) ? trim($_POST['search_keyword']) : '';
// 이미지 파일 업로드 처리 (drop 영역 및 일반 파일 input 모두 지원)
$imagePath = '';
// 1. drop 영역 처리
if (isset($_FILES['upfile']) && isset($_FILES['upfile']['size'][0]) && $_FILES['upfile']['size'][0] > 0) {
$uploadDir = $_SERVER['DOCUMENT_ROOT'] . '/shutterbox/images/';
if (!file_exists($uploadDir)) {
mkdir($uploadDir, 0777, true);
}
$originalName = $_FILES['upfile']['name'][0];
$tmpName = $_FILES['upfile']['tmp_name'][0];
$pathInfo = pathinfo($originalName);
$fileName = $pathInfo['filename'];
$fileExt = isset($pathInfo['extension']) ? $pathInfo['extension'] : '';
$fileNameSanitized = preg_replace('/[^A-Za-z0-9_\-]/', '_', $fileName);
$newFileName = date("Y_m_d_H_i_s") . "_" . $fileNameSanitized;
if (!empty($fileExt)) {
$newFileName .= "." . $fileExt;
}
$targetFile = $uploadDir . $newFileName;
if (!move_uploaded_file($tmpName, $targetFile)) {
echo json_encode(['error' => '파일 업로드 실패']);
exit;
}
$imagePath = '/shutterbox/images/' . $newFileName;
// 2. 일반 파일 input 처리
} elseif (isset($_FILES['image']) && $_FILES['image']['error'] === UPLOAD_ERR_OK) {
$uploadDir = $_SERVER['DOCUMENT_ROOT'] . '/shutterbox/images/';
if (!file_exists($uploadDir)) {
mkdir($uploadDir, 0777, true);
}
$originalName = $_FILES['image']['name'];
$tmpName = $_FILES['image']['tmp_name'];
$pathInfo = pathinfo($originalName);
$fileName = $pathInfo['filename'];
$fileExt = isset($pathInfo['extension']) ? $pathInfo['extension'] : '';
$fileNameSanitized = preg_replace('/[^A-Za-z0-9_\-]/', '_', $fileName);
$newFileName = date("Y_m_d_H_i_s") . "_" . $fileNameSanitized;
if (!empty($fileExt)) {
$newFileName .= "." . $fileExt;
}
$targetFile = $uploadDir . $newFileName;
if (!move_uploaded_file($tmpName, $targetFile)) {
echo json_encode(['error' => '파일 업로드 실패']);
exit;
}
$imagePath = '/shutterbox/images/' . $newFileName;
}
// 3. 기존 이미지 사용
if (empty($imagePath) && isset($_POST['existing_image'])) {
$imagePath = trim($_POST['existing_image']);
}
if ($action === 'insert' && !empty($exit_direction)) {
// 신규 추가
$shutterboxData[] = array(
"box_width" => $box_width ?? '',
"box_height" => $box_height ?? '',
"search_keyword" => $search_keyword ?? '',
"exit_direction" => $exit_direction ?? '',
"rail_width" => $rail_width ?? '',
"front_bottom_width" => $front_bottom_width ?? '',
"image" => $imagePath ?? ''
);
} elseif ($action === 'update' && !empty($exit_direction) && $index >= 0 && $index < count($shutterboxData)) {
// 수정
$shutterboxData[$index]["box_width"] = $box_width ?? '';
$shutterboxData[$index]["box_height"] = $box_height ?? '';
$shutterboxData[$index]["search_keyword"] = $search_keyword ?? '';
$shutterboxData[$index]["exit_direction"] = $exit_direction ?? '';
$shutterboxData[$index]["rail_width"] = $rail_width ?? '';
$shutterboxData[$index]["front_bottom_width"] = $front_bottom_width ?? '';
if (!empty($imagePath)) {
$shutterboxData[$index]["image"] = $imagePath;
}
} elseif ($action === 'copy' && $index >= 0 && $index < count($shutterboxData)) {
// 복사
$originalItem = $shutterboxData[$index];
$newImagePath = '';
// 이미지가 있는 경우 복사
if (!empty($originalItem['image'])) {
$originalImagePath = $_SERVER['DOCUMENT_ROOT'] . $originalItem['image'];
if (file_exists($originalImagePath)) {
$pathInfo = pathinfo($originalImagePath);
$fileName = $pathInfo['filename'];
$fileExt = isset($pathInfo['extension']) ? $pathInfo['extension'] : '';
$newFileName = $fileName . '_copy';
if (!empty($fileExt)) {
$newFileName .= "." . $fileExt;
}
$newImagePath = $pathInfo['dirname'] . '/' . $newFileName;
// 파일 복사
if (copy($originalImagePath, $newImagePath)) {
$newImagePath = str_replace($_SERVER['DOCUMENT_ROOT'], '', $newImagePath);
} else {
$newImagePath = $originalItem['image']; // 복사 실패 시 원본 경로 사용
}
} else {
$newImagePath = $originalItem['image']; // 원본 파일이 없으면 원본 경로 사용
}
}
// 새로운 항목 추가
$shutterboxData[] = array(
"box_width" => $originalItem['box_width'] ?? '',
"box_height" => $originalItem['box_height'] ?? '',
"search_keyword" => $originalItem['search_keyword'] ?? '',
"exit_direction" => $originalItem['exit_direction'] ?? '',
"rail_width" => $originalItem['rail_width'] ?? '',
"front_bottom_width" => $originalItem['front_bottom_width'] ?? '',
"image" => $newImagePath
);
// 복사된 데이터를 폼에 설정하기 위한 변수들
$box_width = $originalItem['box_width'] ?? '';
$box_height = $originalItem['box_height'] ?? '';
$exit_direction = $originalItem['exit_direction'] ?? '';
$rail_width = $originalItem['rail_width'] ?? '';
$front_bottom_width = $originalItem['front_bottom_width'] ?? '';
$search_keyword = $originalItem['search_keyword'] ?? '';
} elseif ($action === 'delete' && $index >= 0 && $index < count($shutterboxData)) {
// 삭제
array_splice($shutterboxData, $index, 1);
}
// JSON 파일에 저장
file_put_contents($jsonFile, json_encode($shutterboxData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
}
?>
<style>
/* 편집할때 보여지는 이미지 크기 */
#previewContainer {
width: 700px !important;
height: auto !important;
}
</style>
</head>
<body>
<div class="container-fluid mt-3">
<div class="card">
<div class="card-header d-flex justify-content-center align-items-center text-center">
<h3><?= $title_message ?></h3>
<button type="button" class="btn btn-dark btn-sm mx-5" onclick="window.close();">
<i class="bi bi-x-square"></i> 닫기
</button>
</div>
<div class="card-body">
<!-- 신규/수정 폼 -->
<form id="shutterboxForm" method="post" action="shutterboxlist.php" enctype="multipart/form-data" class="row g-1">
<input type="hidden" name="action" id="action" value="insert">
<input type="hidden" name="index" id="index" value="-1">
<input type="hidden" name="existing_image" id="existing_image" value="">
<div class="d-flex justify-content-center">
<div class="col-sm-5">
<table class="table table-bordered table-sm ">
<thead class="table-secondary">
<tr>
<th class="text-center">크기(가로)</th>
<th class="text-center">크기(세로)</th>
<th class="text-center">점검구형태</th>
<th class="text-center">전면부 밑</th>
<th class="text-center">레일폭</th>
<th class="text-center">품목검색어 등록</th>
</tr>
</thead>
<tbody></tbody>
<tr>
<td>
<input type="text" name="box_width" id="box_width" value="<?= isset($box_width) ? htmlspecialchars($box_width, ENT_QUOTES, 'UTF-8') : '' ?>" class="form-control text-center " style="font-size: 0.7rem; height: 28px;" placeholder="크기(가로)" autocomplete="off">
</td>
<td>
<input type="text" name="box_height" id="box_height" value="<?= isset($box_height) ? htmlspecialchars($box_height, ENT_QUOTES, 'UTF-8') : '' ?>" class="form-control text-center " style="font-size: 0.7rem; height: 28px;" placeholder="크기(세로)" autocomplete="off">
</td>
<td>
<select name="exit_direction" id="exit_direction" class="form-select text-start" style="font-size: 0.7rem; height: 28px; width: 120px;">
<option value="">점검구형태</option>
<option value="양면 점검구">양면 점검구</option>
<option value="밑면 점검구">밑면 점검구</option>
<option value="후면 점검구">후면 점검구</option>
</select>
</td>
<td>
<input type="text" name="front_bottom_width" id="front_bottom_width" value="<?= isset($front_bottom_width) ? htmlspecialchars($front_bottom_width, ENT_QUOTES, 'UTF-8') : '' ?>" class="form-control text-center " style="font-size: 0.7rem; height: 28px;" placeholder="전면부 밑" autocomplete="off">
</td>
<td>
<input type="text" name="rail_width" id="rail_width" value="<?= isset($rail_width) ? htmlspecialchars($rail_width, ENT_QUOTES, 'UTF-8') : '' ?>" class="form-control text-center " style="font-size: 0.7rem; height: 28px;" placeholder="레일폭" autocomplete="off">
</td>
<td>
<input type="text" name="search_keyword" id="search_keyword" value="<?= isset($search_keyword) ? htmlspecialchars($search_keyword, ENT_QUOTES, 'UTF-8') : '' ?>" class="form-control text-start " style="font-size: 0.7rem; width: 200px; height: 28px;" placeholder="품목검색어 등록" autocomplete="off">
</td>
</tr>
</tbody>
</table>
</div>
<!-- 이미지 파일 선택 및 드롭 영역 -->
<div class="col-auto">
<!-- 이미지 파일 선택 (숨김 처리, drop 영역에서 사용) -->
<input type="file" id="upfile" name="upfile[]" multiple style="display:none;">
<button class="btn btn-dark btn-sm ms-1 me-4" type="button" onclick="document.getElementById('upfile').click();">
<i class="bi bi-image"></i>
</button>
<div class="d-flex justify-content-center">
<!-- 드롭 영역 -->
<div id="dropArea" style="border: 1px dashed #ccc; padding: 5px; width:95%; height:100px; text-align: center;">
여기로 사진을 drop or 캡쳐 붙여넣기(ctrl+v)
</div>
</div>
<!-- 파일 목록 및 미리보기 영역 -->
<div class="d-flex mt-2 justify-content-center">
<div id="previewContainer">
<?php if (!empty($imgdata)): ?>
<img src="<?= htmlspecialchars($upload_dir . $imgdata, ENT_QUOTES, 'UTF-8') ?>" alt="Image" id="currentImage" class="img-fluid">
<?php else: ?>
<span class="text-danger mx-5">No image!</span>
<?php endif; ?>
</div>
</div>
</div>
<!-- JavaScript for Drag & Drop, 파일 선택, 그리고 클립보드 붙여넣기 -->
<script>
document.getElementById('dropArea').addEventListener('dragover', function(event) {
event.preventDefault();
event.stopPropagation();
this.style.borderColor = '#000';
});
document.getElementById('dropArea').addEventListener('dragleave', function(event) {
event.preventDefault();
event.stopPropagation();
this.style.borderColor = '#ccc';
});
document.getElementById('dropArea').addEventListener('drop', function(event) {
event.preventDefault();
event.stopPropagation();
const files = event.dataTransfer.files;
if (files.length > 0) {
handleFiles(files);
}
});
document.getElementById('upfile').addEventListener('change', function(event) {
const files = event.target.files;
if (files.length > 0) {
handleFiles(files);
}
});
// 클립보드 붙여넣기 (윈도우키+Shift+S 등)
document.addEventListener('paste', function(event) {
let items = (event.clipboardData || event.originalEvent.clipboardData).items;
for (let index in items) {
let item = items[index];
if (item.kind === 'file' && item.type.startsWith('image/')) {
let blob = item.getAsFile();
let reader = new FileReader();
reader.onload = function(event) {
const previewContainer = document.getElementById('previewContainer');
previewContainer.innerHTML = '';
let img = document.createElement('img');
img.src = event.target.result;
img.className = 'img-fluid';
previewContainer.appendChild(img);
// 파일을 upfile input에 추가
const fileInput = document.getElementById('upfile');
const dataTransfer = new DataTransfer();
dataTransfer.items.add(blob);
fileInput.files = dataTransfer.files;
};
reader.readAsDataURL(blob);
}
}
});
function handleFiles(files) {
const file = files[0]; // 첫 번째 파일만 처리 (필요에 따라 확장 가능)
const reader = new FileReader();
reader.onload = function(event) {
const previewContainer = document.getElementById('previewContainer');
previewContainer.innerHTML = '';
let img = document.createElement('img');
img.src = event.target.result;
img.className = 'img-fluid';
previewContainer.appendChild(img);
// 파일을 upfile input에 설정
const fileInput = document.getElementById('upfile');
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
fileInput.files = dataTransfer.files;
};
reader.readAsDataURL(file);
}
</script>
<div class="col-auto">
<button type="submit" class="btn btn-primary btn-sm" id="submitBtn">등록</button>
</div>
</div>
</form>
<hr>
<!-- 저장된 케이스 이미지 목록 테이블 -->
<div class="table-responsive">
<table class="table table-bordered" id="mainTable">
<style>
.hover-image-modal {
display: none;
position: fixed;
z-index: 1000;
pointer-events: none;
}
.hover-image-modal img {
max-width: none;
max-height: none;
}
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {
// 모달 div 생성
const modal = document.createElement('div');
modal.className = 'hover-image-modal';
document.body.appendChild(modal);
// 테이블의 이미지에 호버 이벤트 추가
document.querySelectorAll('#mainTable td img').forEach(img => {
img.addEventListener('mouseenter', function(e) {
const fullImg = new Image();
fullImg.src = this.src;
modal.innerHTML = '';
modal.appendChild(fullImg);
modal.style.display = 'block';
});
img.addEventListener('mousemove', function(e) {
modal.style.left = (e.pageX - modal.offsetWidth - 10) + 'px';
modal.style.top = e.clientY + 10 + 'px';
});
img.addEventListener('mouseleave', function() {
modal.style.display = 'none';
});
});
});
</script>
<thead class="table-secondary">
<tr>
<th class="sortable" data-sort="index">순번 <i class="bi bi-arrow-down-up"></i></th>
<th class="sortable" data-sort="box_width">크기(가로) <i class="bi bi-arrow-down-up"></i></th>
<th class="sortable" data-sort="box_height">크기(세로) <i class="bi bi-arrow-down-up"></i></th>
<th class="sortable text-center" data-sort="exit_direction">점검구형태 <i class="bi bi-arrow-down-up"></i></th>
<th class="sortable text-center" data-sort="front_bottom_width">전면부 밑치수 <i class="bi bi-arrow-down-up"></i></th>
<th class="sortable text-center" data-sort="rail_width">레일폭 <i class="bi bi-arrow-down-up"></i></th>
<th class="sortable text-center" data-sort="search_keyword">품목검색어 <i class="bi bi-arrow-down-up"></i></th>
<th>이미지</th>
<th>수정/삭제</th>
</tr>
</thead>
<tbody>
<?php if (!empty($shutterboxData)): ?>
<?php // foreach ($shutterboxData as $i => $item): // 역순으로 돌리는 코드는 아래와 같다. ?>
<?php foreach (array_reverse($shutterboxData, true) as $i => $item): ?>
<tr>
<td><?= $i + 1 ?></td>
<td><?= isset($item["box_width"]) ? htmlspecialchars($item["box_width"], ENT_QUOTES, 'UTF-8') : '' ?></td>
<td><?= isset($item["box_height"]) ? htmlspecialchars($item["box_height"], ENT_QUOTES, 'UTF-8') : '' ?></td>
<td><?= isset($item["exit_direction"]) ? htmlspecialchars($item["exit_direction"], ENT_QUOTES, 'UTF-8') : '' ?></td>
<td><?= isset($item["front_bottom_width"]) ? htmlspecialchars($item["front_bottom_width"], ENT_QUOTES, 'UTF-8') : '' ?></td>
<td><?= isset($item["rail_width"]) ? htmlspecialchars($item["rail_width"], ENT_QUOTES, 'UTF-8') : '' ?></td>
<td><?= isset($item["search_keyword"]) ? htmlspecialchars($item["search_keyword"], ENT_QUOTES, 'UTF-8') : '' ?></td>
<td>
<?php if (!empty($item["image"])): ?>
<img src="<?= htmlspecialchars($item["image"], ENT_QUOTES, 'UTF-8') ?>" alt="이미지" style="max-width:100px;">
<?php else: ?>
없음
<?php endif; ?>
</td>
<td>
<button type="button" class="btn btn-sm btn-outline-primary editBtn" data-index="<?= $i ?>">수정</button>
<button type="button" class="btn btn-sm btn-outline-success copyBtn" data-index="<?= $i ?>">복사</button>
<button type="button" class="btn btn-sm btn-outline-danger deleteBtn" data-index="<?= $i ?>">삭제</button>
</td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr><td colspan="6">등록된 케이스 이미지 정보가 없습니다.</td></tr>
<?php endif; ?>
</tbody>
</table>
</div><!-- table-responsive -->
<div style="height: 400px;"></div>
</div><!-- card-body -->
</div><!-- card -->
</div><!-- container -->
<script>
$(document).ready(function(){
var loader = document.getElementById('loadingOverlay');
if(loader)
loader.style.display = 'none';
});
$(document).ready(function(){
// 테이블 정렬 기능
let currentSort = { column: null, direction: 'asc' };
// 정렬 가능한 헤더 클릭 이벤트
$('.sortable').on('click', function() {
const column = $(this).data('sort');
const tbody = $('#mainTable tbody');
const rows = tbody.find('tr').toArray();
// 정렬 방향 결정
if (currentSort.column === column) {
currentSort.direction = currentSort.direction === 'asc' ? 'desc' : 'asc';
} else {
currentSort.column = column;
currentSort.direction = 'asc';
}
// 정렬 실행
rows.sort(function(a, b) {
let aValue, bValue;
// 컬럼 인덱스 결정
let columnIndex;
switch(column) {
case 'index': columnIndex = 0; break;
case 'box_width': columnIndex = 1; break;
case 'box_height': columnIndex = 2; break;
case 'exit_direction': columnIndex = 3; break;
case 'front_bottom_width': columnIndex = 4; break;
case 'rail_width': columnIndex = 5; break;
case 'search_keyword': columnIndex = 6; break;
default: columnIndex = 0;
}
aValue = $(a).find('td').eq(columnIndex).text().trim();
bValue = $(b).find('td').eq(columnIndex).text().trim();
// 숫자 정렬 (순번, 크기, 레일폭, 전면부 밑치수)
if (['index', 'box_width', 'box_height', 'rail_width', 'front_bottom_width'].includes(column)) {
aValue = parseFloat(aValue) || 0;
bValue = parseFloat(bValue) || 0;
}
// 정렬 방향에 따른 비교
if (currentSort.direction === 'asc') {
return aValue > bValue ? 1 : -1;
} else {
return aValue < bValue ? 1 : -1;
}
});
// 정렬된 행을 테이블에 다시 추가
tbody.empty();
rows.forEach(function(row) {
tbody.append(row);
});
// 정렬 아이콘 업데이트
$('.sortable i').removeClass('bi-arrow-up bi-arrow-down').addClass('bi-arrow-down-up');
const currentHeader = $(`.sortable[data-sort="${column}"]`);
const icon = currentHeader.find('i');
icon.removeClass('bi-arrow-down-up');
icon.addClass(currentSort.direction === 'asc' ? 'bi-arrow-up' : 'bi-arrow-down');
// 순번 재정렬 (정렬 후 순번을 1부터 다시 매김)
tbody.find('tr').each(function(index) {
$(this).find('td').eq(0).text(index + 1);
});
});
// 정렬 가능한 헤더에 커서 스타일 적용
$('.sortable').css('cursor', 'pointer');
// 수정 버튼 클릭 시: 해당 행의 데이터를 폼에 채워 수정 모드로 전환
$('.editBtn').on('click', function(){
var index = $(this).data('index');
var row = $(this).closest('tr');
var box_width = row.find('td:eq(1)').text().trim();
var box_height = row.find('td:eq(2)').text().trim();
var exit_direction = row.find('td:eq(3)').text().trim();
var front_bottom_width = row.find('td:eq(4)').text().trim();
var rail_width = row.find('td:eq(5)').text().trim();
var search_keyword = row.find('td:eq(6)').text().trim();
var imageSrc = row.find('td:eq(7) img').attr('src') || ''; // 7번째 이미지
$('#box_width').val(box_width);
$('#box_height').val(box_height);
$('#exit_direction').val(exit_direction);
$('#front_bottom_width').val(front_bottom_width);
$('#rail_width').val(rail_width);
$('#search_keyword').val(search_keyword);
$('#existing_image').val(imageSrc);
$('#index').val(index);
$('#action').val('update');
$('#submitBtn').text('수정');
// 기존 이미지 미리보기 업데이트
if(imageSrc) {
$('#previewContainer').html('<img src="' + imageSrc + '" alt="이미지" class="img-fluid">');
} else {
$('#previewContainer').html('아직 등록된 이미지가 없습니다.');
}
});
// 복사 버튼 클릭 시: 확인 후 폼 제출하여 복사 처리
$('.copyBtn').on('click', function(){
var index = $(this).data('index');
Swal.fire({
title: '복사 확인',
text: "이 항목을 복사하시겠습니까?",
icon: 'question',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: '확인',
cancelButtonText: '취소'
}).then((result) => {
if (result.isConfirmed) {
// 복사할 데이터 가져오기
var row = $(this).closest('tr');
var box_width = row.find('td:eq(1)').text().trim();
var box_height = row.find('td:eq(2)').text().trim();
var exit_direction = row.find('td:eq(3)').text().trim();
var front_bottom_width = row.find('td:eq(4)').text().trim();
var rail_width = row.find('td:eq(5)').text().trim();
var search_keyword = row.find('td:eq(6)').text().trim();
var imageSrc = row.find('td:eq(7) img').attr('src') || '';
// 폼에 데이터 설정
$('#box_width').val(box_width);
$('#box_height').val(box_height);
$('#exit_direction').val(exit_direction);
$('#front_bottom_width').val(front_bottom_width);
$('#rail_width').val(rail_width);
$('#search_keyword').val(search_keyword);
$('#existing_image').val(imageSrc);
// 수정 모드로 설정 (새로운 항목이므로 index는 -1)
$('#index').val(-1);
$('#action').val('insert');
$('#submitBtn').text('등록');
// 이미지 미리보기 업데이트
if(imageSrc) {
$('#previewContainer').html('<img src="' + imageSrc + '" alt="이미지" class="img-fluid">');
} else {
$('#previewContainer').html('아직 등록된 이미지가 없습니다.');
}
// // 페이지 상단으로 스크롤하여 폼이 보이도록 함
// $('html, body').animate({
// scrollTop: $('#shutterboxForm').offset().top - 20
// }, 500);
// 성공 메시지 표시
setTimeout(function() {
Swal.fire({
text: '복사된 데이터가 폼에 로드되었습니다. 필요에 따라 수정 후 등록하세요.',
timer: 1500,
showConfirmButton: false,
icon: 'success'
});
}, 100);
}
});
});
// 삭제 버튼 클릭 시: 확인 후 폼 제출하여 삭제 처리
$('.deleteBtn').on('click', function(){
var index = $(this).data('index');
if(confirm("정말 삭제하시겠습니까?")){
$('#index').val(index);
$('#action').val('delete');
$('#shutterboxForm').submit();
}
});
});
</script>
</body>
</html>

281
shutterbox/view.php Normal file
View File

@@ -0,0 +1,281 @@
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . "/session.php");
if (!isset($_SESSION["level"]) || $_SESSION["level"] > 5) {
sleep(1);
header("Location:" . $WebSite . "login/login_form.php");
exit;
}
include $_SERVER['DOCUMENT_ROOT'] . '/load_header.php';
$title_message = '절곡 작업지시서';
$mode = isset($_['mode']) ? $_REQUEST['mode'] : '';
$num = isset($_REQUEST['num']) ? $_REQUEST['num'] : '';
$tablename = isset($_REQUEST['tablename']) ? $_REQUEST['tablename'] : '';
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
$today = date("Y-m-d");
if(!isset($DB))
$DB = 'chandj';
try {
$sql = "SELECT * FROM {$DB}.$tablename WHERE num=? ";
$stmh = $pdo->prepare($sql);
$stmh->bindValue(1, $num, PDO::PARAM_INT);
$stmh->execute();
$row = $stmh->fetch(PDO::FETCH_ASSOC);
include '_row.php';
} catch (PDOException $Exception) {
echo "오류: ".$Exception->getMessage();
exit;
}
// echo '<pre>';
// print_r($row);
// echo '</pre>';
// 기존에 저장된 값이 있는 경우 해당 값을 설정
$selected_exit_directionFlat = isset($row['exit_direction']) ? $row['exit_direction'] : '양면 점검구';
?>
<style>
.table-container {
width: 100%;
}
#dynamicTable {
table-layout: fixed;
width: 1000px;
}
#dynamicTable th:first-child,
#dynamicTable td:first-child {
width: 100px;
min-width: 100px;
max-width: 100px;
}
#dynamicTable th:nth-child(2),
#dynamicTable td:nth-child(2) {
width: 900px;
min-width: 900px;
max-width: 900px;
}
.input-container {
width: 100%;
white-space: nowrap;
display: flex;
align-items: center;
}
.input-container input,
.input-container span {
display: inline-block;
margin-right: 5px;
}
.input-container input[type="text"] {
width: 30px;
height:30px;
}
</style>
<div class="container-fluid">
<div class="card justify-content-center">
<div class="card-header text-center">
<div class="row">
<div class="col-sm-2">
</div>
<div class="col-sm-8">
<div class="d-flex align-items-center justify-content-center">
<span class="text-center fs-5"><?=$title_message?></span>
<button class="btn btn-dark btn-sm ms-5 me-2" onclick="generatePDF()"> PDF 저장 </button>
</div>
</div>
<div class="col-sm-2">
<div class="d-flex align-items-center justify-content-end">
<button type="button" class="btn btn-outline-dark btn-sm me-2" onclick="self.close();" > <ion-icon name="close-circle-outline"></ion-icon> 닫기 </button>
</div>
</div>
</div>
</div>
<div class="card-body">
<div class="row mb-3">
<div class="col text-center">
<span class="badge fs-5
<?php
if($selected_exit_directionFlat === '양면 점검구') {
echo 'bg-primary';
} elseif($selected_exit_directionFlat === '밑면 점검구') {
echo 'bg-success';
} elseif($selected_exit_directionFlat === '후면 점검구') {
echo 'bg-danger';
}
?>">
<?php echo $selected_exit_directionFlat; ?>
</span>
</div>
</div>
<div id="content-to-print">
<div class="row justify-content-center text-center">
<div class="d-flex align-items-center justify-content-center m-2">
<table class="table ">
<tbody>
<tr>
<td class="text-center fs-6 fw-bold" colspan="6" >
<div class="d-flex align-items-center justify-content-center">
<span class="text-center fs-6 ms-1 me-1"> (<?= $selected_exit_directionFlat?>) 셔터박스 &nbsp;&nbsp;
<span class="text-center fs-6 ms-1 me-1"> 전면 밑 : <?=$front_bottom_width?> &nbsp;&nbsp; 레일폭 : <?=$rail_width?> &nbsp;&nbsp;&nbsp;&nbsp; </span>
<span class="text-center fs-6 ms-1 me-1 text-primary"> 가로(폭): </span>
<span class="text-primary ms-1 me-1"><?=$box_width?></span>
<span class="text-center fs-6 ms-1 me-1"> x </span>
<span class="text-center fs-6 ms-1 me-1 text-danger"> 세로(높이): </span>
<span class="text-danger"><?=$box_height?></span>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="row justify-content-center text-center">
<?php
// 공통인 것
$box_height = isset($row['box_height']) ? $row['box_height'] : 0;
$front_bottom_width = isset($row['front_bottom_width']) ? $row['front_bottom_width'] : 0;
// 케이스 전개도 함수
require_once($_SERVER['DOCUMENT_ROOT'] . "/shutterbox/fun_case.php");
$productData = getCasePlate($selected_exit_directionFlat, $box_width, $box_height, $rail_width, $front_bottom_width);
?>
<div class="table-container">
<table class="table">
<thead class="table-secondary">
<tr>
<th class="w170px">번호</th>
<th class="w100px">재질</th>
<th>절곡치수</th>
<th>길이</th>
<th>수량</th>
<th>면적</th>
</tr>
</thead>
<tbody id="tableBody">
<?php foreach ($productData as $productIndex => $product): ?>
<?php
// 합계 행
echo '<tr>';
echo '<td rowspan="2" >' . $product['label'] . '</td>';
echo '<td rowspan="2" > EGI 1.55T</td>';
echo '<td class="input-container" >';
// sums와 colors를 함께 사용하여 배경색을 설정
foreach ($product['sums'] as $index => $sum) {
$backgroundColor = $product['colors'][$index] ? 'background-color: gray;' : '';
$foreColor = $product['colors'][$index] ? 'text-white ' : '';
echo '<span class="text-center ' . $foreColor . '" style="width: 30px; ' . $backgroundColor . '">' . $sum . '</span>';
}
echo '</td>';
echo '<td></td>';
echo '<td></td>';
echo '<td></td>';
echo '</tr>';
// A각 표시 행
echo '<tr>';
echo '<td class="input-container" >';
foreach ($product['aAngles'] as $angle) {
echo '<span style="width: 10px; margin-left:10px; margin-right:15px;">' . ($angle ? 'A"' : '&nbsp;') . '</span>';
}
echo '</td>';
echo '<td></td>';
echo '<td></td>';
echo '<td></td>';
echo '</tr>';
?>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function(){
var loader = document.getElementById('loadingOverlay');
if(loader)
loader.style.display = 'none';
$("#newBtn").on("click", function() {
loadForm('insert');
});
$("#searchBtn").on("click", function() {
$("#board_form").submit();
});
});
function enter() {
$("#board_form").submit();
}
function inputNumberFormat(obj) {
obj.value = obj.value.replace(/[^0-9]/g, '');
let value = obj.value.replace(/,/g, '');
obj.value = value.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
$(document).on("keypress", "input", function(event) {
return event.keyCode != 13;
});
function generatePDF() {
// 이벤트의 기본 동작을 방지 (모달창 닫힘 방지)
event.preventDefault();
var deadline = '<?php echo $today; ?>';
var deadlineDate = new Date(deadline);
var formattedDate = "(" + String(deadlineDate.getFullYear()).slice(-2) + "." + ("0" + (deadlineDate.getMonth() + 1)).slice(-2) + "." + ("0" + deadlineDate.getDate()).slice(-2) + ")";
var result = 'KD_셔터박스_' + formattedDate + '.pdf';
var element = document.getElementById('content-to-print');
var opt = {
margin: [10, 3, 12, 3], // Top, right, bottom, left margins
filename: result,
image: { type: 'jpeg', quality: 0.98 },
html2canvas: { scale: 1 },
jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' },
pagebreak: { mode: [''] }
};
html2pdf().from(element).set(opt).save();
}
</script>