Files
sam-kd/account/list.php
hskwon aca1767eb9 초기 커밋: 5130 레거시 시스템
- URL 하드코딩 → .env APP_URL 기반 동적 URL로 변경
- DB 연결 하드코딩 → .env 기반으로 변경
- MySQL strict mode DATE 오류 수정
2025-12-10 20:14:31 +09:00

2340 lines
90 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
require_once $_SERVER['DOCUMENT_ROOT'] . '/load_GoogleDrive.php'; // 세션 등 여러가지 포함됨 파일 포함
if (!isset($_SESSION["level"]) || $_SESSION["level"] > 5) {
sleep(1);
header("Location:" . $WebSite . "login/login_form.php");
exit;
}
// 에러 표시 설정
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
// **대량 등록용 임시 key 발급**
$bulkTimeKey = bin2hex(random_bytes(16));
include $_SERVER['DOCUMENT_ROOT'] . '/load_header.php';
$title_message = '금전 출납부';
$tablename = 'account';
require_once $_SERVER['DOCUMENT_ROOT'] . '/load_GoogleDriveSecond.php'; // attached, image에 대한 정보 불러오기
?>
<link href="css/style.css" rel="stylesheet">
<title> <?=$title_message?> </title>
<style>
/* 테이블에 테두리 추가 */
#myTable, #myTable th, #myTable td {
border: 1px solid black;
border-collapse: collapse;
}
/* 테이블 셀 패딩 조정 */
#myTable th, #myTable td {
padding: 8px;
text-align: center;
}
/* 전체 모달 폰트 기본값 12px 유지 */
#bulkEntryModal * {
font-size: 12px;
box-sizing: border-box;
}
/* 모달 배경 오버레이 */
#bulkEntryModal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.6);
z-index: 1050;
}
/* 모달 내용 영역 (가운데 정렬) */
#bulkEntryModal > div {
background: white;
width: 1920px;
height: 950px;
margin: 40px auto;
padding: 20px;
border-radius: 8px;
position: relative;
display: flex;
flex-direction: column;
}
/* 버튼 스타일 */
#bulkEntryModal .btn {
padding: 2px 8px;
font-size: 12px;
cursor: pointer;
}
/* 테이블 관련 */
#bulkEntryModal table {
width: 100%;
border-collapse: collapse;
}
#bulkEntryModal table th,
#bulkEntryModal table td {
padding: 4px;
vertical-align: middle;
font-size: 12px;
border: 1px solid #dee2e6;
}
#bulkEntryModal table thead {
background-color: #f8f9fa;
}
/* 모달 바디 스크롤 설정 */
#bulkEntryModal .custom-modal-body {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
margin: 10px 0;
}
/* 테이블 헤더 고정 */
#bulkEntryModal .table-responsive {
position: relative;
}
#bulkEntryModal table thead {
position: sticky;
top: 0;
z-index: 10;
background-color: #f8f9fa;
}
/* 모달 열릴 때 바디 스크롤 방지 */
body.modal-open {
overflow: hidden;
}
</style>
</head>
<body>
<!-- 로딩 오버레이 -->
<div id="loadingOverlay" style="
display: none;
position: fixed;
top: 0; left: 0;
width: 100%; height: 100%;
background: rgba(0,0,0,0.6);
z-index: 2000;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
font-size: 1.5em;
display: none;
">
<div>
<i class="bi bi-arrow-clockwise rotate" style="font-size:2em; animation: spin 1s linear infinite;"></i>
<div>잠시만 기다려주세요…</div>
</div>
</div>
<style>
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
</style>
<?php
// 세무사아이디면 다른 메뉴 연결
if($_SESSION["userid"] == '0266771300') {
include $_SERVER['DOCUMENT_ROOT'] . '/myheader_accountant.php';
}
else {
include $_SERVER['DOCUMENT_ROOT'] . '/myheader.php';
}
$search = isset($_REQUEST['search']) ? $_REQUEST['search'] : '';
$fromdate = isset($_REQUEST['fromdate']) ? $_REQUEST['fromdate'] : '';
$todate = isset($_REQUEST['todate']) ? $_REQUEST['todate'] : '';
$mode = isset($_REQUEST['mode']) ? $_REQUEST['mode'] : '';
// 현재 날짜
$currentDate = date("Y-m-d");
// fromdate 또는 todate가 빈 문자열이거나 null인 경우
if ($fromdate === "" || $fromdate === null || $todate === "" || $todate === null) {
// 현재 월의 1일을 fromdate로 설정
// $fromdate = date("Y-m-01");
// 전달(이전 달)의 1일을 fromdate로 설정
$fromdate = date("Y-m-01", strtotime("-1 month"));
$todate = $currentDate;
$Transtodate = $todate;
} else {
$Transtodate = $todate;
}
function checkNull($strtmp) {
return $strtmp !== null && trim($strtmp) !== '';
}
require_once($_SERVER['DOCUMENT_ROOT'] . "/lib/mydb.php");
$pdo = db_connect();
$inoutsep_select = isset($_REQUEST['inoutsep_select']) ? $_REQUEST['inoutsep_select'] : '';
$content_select = isset($_REQUEST['content_select']) ? $_REQUEST['content_select'] : '';
$order = " ORDER BY registDate ASC, num ASC ";
$sql_conditions = [];
$sql_params = [];
if (checkNull($search)) {
$sql_conditions[] = "searchtag LIKE :search";
$sql_params[':search'] = "%$search%";
}
$sql_conditions[] = "registDate BETWEEN :fromdate AND :todate";
$sql_params[':fromdate'] = $fromdate;
$sql_params[':todate'] = $todate;
$sql_conditions[] = "is_deleted = 0";
if (checkNull($inoutsep_select)) {
$sql_conditions[] = "inoutsep = :inoutsep";
$sql_params[':inoutsep'] = $inoutsep_select;
}
if (checkNull($content_select)) {
$sql_conditions[] = "content = :content";
$sql_params[':content'] = $content_select;
}
$sql = "SELECT * FROM " . $tablename . " WHERE " . implode(' AND ', $sql_conditions) . $order;
try {
$stmh = $pdo->prepare($sql);
foreach ($sql_params as $param => $value) {
$stmh->bindValue($param, $value);
}
$stmh->execute();
$total_row = $stmh->rowCount();
// 수입, 지출을 기반으로 초기 잔액 계산
$initialBalanceSql = "SELECT
SUM(CASE WHEN inoutsep = '수입' THEN REPLACE(amount, ',', '') ELSE 0 END) +
SUM(CASE WHEN inoutsep = '최초전월이월' THEN REPLACE(amount, ',', '') ELSE 0 END) -
SUM(CASE WHEN inoutsep = '지출' THEN REPLACE(amount, ',', '') ELSE 0 END) AS balance
FROM $tablename
WHERE is_deleted = '0' AND registDate < :fromdate
AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')";
$initialBalanceStmh = $pdo->prepare($initialBalanceSql);
$initialBalanceStmh->bindParam(':fromdate', $fromdate);
$initialBalanceStmh->execute();
$initialBalance = $initialBalanceStmh->fetch(PDO::FETCH_ASSOC)['balance'];
$totalIncomeSql = "SELECT SUM(REPLACE(amount, ',', '')) AS totalIncome
FROM $tablename
WHERE is_deleted = '0' AND (inoutsep = '수입' OR inoutsep = '최초전월이월')
AND registDate BETWEEN :fromdate AND :todate
AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')";
$totalIncomeStmh = $pdo->prepare($totalIncomeSql);
$totalIncomeStmh->bindParam(':fromdate', $fromdate);
$totalIncomeStmh->bindParam(':todate', $todate);
$totalIncomeStmh->execute();
$totalIncome = $totalIncomeStmh->fetch(PDO::FETCH_ASSOC)['totalIncome'];
$totalExpenseSql = "SELECT SUM(REPLACE(amount, ',', '')) AS totalExpense
FROM $tablename
WHERE is_deleted = '0' AND inoutsep = '지출'
AND registDate BETWEEN :fromdate AND :todate
AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')";
$totalExpenseStmh = $pdo->prepare($totalExpenseSql);
$totalExpenseStmh->bindParam(':fromdate', $fromdate);
$totalExpenseStmh->bindParam(':todate', $todate);
$totalExpenseStmh->execute();
$totalExpense = $totalExpenseStmh->fetch(PDO::FETCH_ASSOC)['totalExpense'];
$finalBalance = $initialBalance + $totalIncome - $totalExpense;
// Bankbook options
$bankbookOptions = [];
$jsonFile = $_SERVER['DOCUMENT_ROOT'] . "/account/accoutlist.json";
$accounts = [];
$selectedAccount = null;
$accountBalances = [];
if (file_exists($jsonFile)) {
$jsonContent = file_get_contents($jsonFile);
$accounts = json_decode($jsonContent, true);
if (is_array($accounts) && !empty($accounts)) {
// 선택된 계좌 또는 기본 계좌(첫 번째) 설정
$selectedAccountIndex = isset($_REQUEST['selected_account']) ? intval($_REQUEST['selected_account']) : 0;
$selectedAccount = $accounts[$selectedAccountIndex] ?? $accounts[0];
// 각 계좌별 잔액 계산
foreach ($accounts as $index => $account) {
$accountDisplay = $account['company'] . ' ' . $account['number'];
if (!empty($account['memo'])) {
$accountDisplay .= ' (' . $account['memo'] . ')';
}
// 해당 계좌의 잔액 계산
$accountBalanceSql = "SELECT
SUM(CASE WHEN inoutsep = '수입' AND bankbook = ? THEN REPLACE(amount, ',', '') ELSE 0 END) +
SUM(CASE WHEN inoutsep = '최초전월이월' AND bankbook = ? THEN REPLACE(amount, ',', '') ELSE 0 END) -
SUM(CASE WHEN inoutsep = '지출' AND bankbook = ? THEN REPLACE(amount, ',', '') ELSE 0 END) AS balance
FROM $tablename
WHERE is_deleted = '0'
AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')";
$accountBalanceStmh = $pdo->prepare($accountBalanceSql);
$accountBalanceStmh->bindValue(1, $accountDisplay, PDO::PARAM_STR);
$accountBalanceStmh->bindValue(2, $accountDisplay, PDO::PARAM_STR);
$accountBalanceStmh->bindValue(3, $accountDisplay, PDO::PARAM_STR);
$accountBalanceStmh->execute();
$accountBalances[$index] = $accountBalanceStmh->fetch(PDO::FETCH_ASSOC)['balance'] ?? 0;
}
}
}
// 각 계좌별 요약 정보를 담을 배열 초기화
$accountSummaries = [];
if (is_array($accounts)) {
foreach ($accounts as $index => $account) {
$accountDisplay = $account['company'] . ' ' . $account['number'];
if (!empty($account['memo'])) {
$accountDisplay .= ' (' . $account['memo'] . ')';
}
// 1. 계좌별 기초 잔액 (기간 이전)
$initialSql = "SELECT
(SUM(CASE WHEN inoutsep = '수입' OR inoutsep = '최초전월이월' THEN REPLACE(amount, ',', '') ELSE 0 END) -
SUM(CASE WHEN inoutsep = '지출' THEN REPLACE(amount, ',', '') ELSE 0 END)) AS balance
FROM $tablename
WHERE is_deleted = '0' AND registDate < :fromdate AND bankbook = :bankbook
AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')";
$initialStmh = $pdo->prepare($initialSql);
$initialStmh->bindParam(':fromdate', $fromdate);
$initialStmh->bindParam(':bankbook', $accountDisplay);
$initialStmh->execute();
$initialBalanceAccount = $initialStmh->fetch(PDO::FETCH_ASSOC)['balance'] ?? 0;
// 2. 기간 내 수입
$incomeSql = "SELECT SUM(REPLACE(amount, ',', '')) AS totalIncome
FROM $tablename
WHERE is_deleted = '0' AND (inoutsep = '수입' OR inoutsep = '최초전월이월')
AND registDate BETWEEN :fromdate AND :todate AND bankbook = :bankbook
AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')";
$incomeStmh = $pdo->prepare($incomeSql);
$incomeStmh->bindParam(':fromdate', $fromdate);
$incomeStmh->bindParam(':todate', $todate);
$incomeStmh->bindParam(':bankbook', $accountDisplay);
$incomeStmh->execute();
$totalIncomeAccount = $incomeStmh->fetch(PDO::FETCH_ASSOC)['totalIncome'] ?? 0;
// 3. 기간 내 지출
$expenseSql = "SELECT SUM(REPLACE(amount, ',', '')) AS totalExpense
FROM $tablename
WHERE is_deleted = '0' AND inoutsep = '지출'
AND registDate BETWEEN :fromdate AND :todate AND bankbook = :bankbook
AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')";
$expenseStmh = $pdo->prepare($expenseSql);
$expenseStmh->bindParam(':fromdate', $fromdate);
$expenseStmh->bindParam(':todate', $todate);
$expenseStmh->bindParam(':bankbook', $accountDisplay);
$expenseStmh->execute();
$totalExpenseAccount = $expenseStmh->fetch(PDO::FETCH_ASSOC)['totalExpense'] ?? 0;
// 4. 최종 잔액
$finalBalanceAccount = $initialBalanceAccount + $totalIncomeAccount - $totalExpenseAccount;
// 계산된 정보를 배열에 저장
$accountSummaries[$index] = [
'name' => $accountDisplay,
'income' => $totalIncomeAccount,
'expense' => $totalExpenseAccount,
'balance' => $finalBalanceAccount
];
}
}
// 각 계좌별 최종 잔액 정보를 담을 배열 초기화
$accountFinalBalances = [];
if (is_array($accounts)) {
foreach ($accounts as $index => $account) {
$accountDisplay = $account['company'] . ' ' . $account['number'];
if (!empty($account['memo'])) {
$accountDisplay .= ' (' . $account['memo'] . ')';
}
// 계좌별 전체 기간의 최종 잔액 계산
$balanceSql = "SELECT
(SUM(CASE WHEN inoutsep = '수입' OR inoutsep = '최초전월이월' THEN REPLACE(amount, ',', '') ELSE 0 END) -
SUM(CASE WHEN inoutsep = '지출' THEN REPLACE(amount, ',', '') ELSE 0 END)) AS balance
FROM $tablename
WHERE is_deleted = '0' AND bankbook = :bankbook
AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')";
$balanceStmh = $pdo->prepare($balanceSql);
$balanceStmh->bindParam(':bankbook', $accountDisplay);
$balanceStmh->execute();
$balanceResult = $balanceStmh->fetch(PDO::FETCH_ASSOC);
// 계산된 정보를 배열에 저장
$accountFinalBalances[$index] = [
'name' => $accountDisplay,
'balance' => $balanceResult['balance'] ?? 0
];
}
}
// print $sql;
?>
<form id="board_form" name="board_form" method="post" enctype="multipart/form-data">
<input type="hidden" id="mode" name="mode" value="<?= isset($mode) ? $mode : '' ?>">
<input type="hidden" id="num" name="num" value="<?= isset($num) ? $num : '' ?>">
<input type="hidden" id="tablename" name="tablename" value="<?= isset($tablename) ? $tablename : '' ?>">
<input type="hidden" id="savetitle" name="savetitle" value="<?=isset($savetitle) ? $savetitle : '' ?>" >
<input type="hidden" id="pInput" name="pInput" value="<?=isset($pInput) ? $pInput : '' ?>" >
<div id="bulkEntryModal" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.6); z-index:1050;">
<div style="background:white; width:1880px; height:950px; margin:40px auto; padding:20px; border-radius:8px; position:relative;">
<div class="d-flex justify-content-between bg-dark text-white" >
<h3 class="p-2">금전출납부 대량 등록</h3>
<button type="button" id="closeAccountModal" style="background:none; border:none; color:white; font-size:24px;">&times;</button>
</div>
<div class="custom-modal-body">
<div class="table-responsive">
<table class="table table-bordered" id="bulkEntryTable">
<thead>
<tr>
<th style="width:6%;">+/-/Copy</th>
<th style="width:6%;">등록일자</th>
<th style="width:7%;">구분</th>
<th style="width:15%;">계좌</th>
<th style="width:8%;">항목</th>
<th style="width:8%;">세부항목</th>
<th style="width:5%;">거래처 <i class="bi bi-search"></i></th>
<th style="width:5%;">거래처코드</th>
<th style="width:6%;">만기일자</th>
<th style="width:6%;">배서일자</th>
<th style="width:14%;">상세내용</th>
<th style="width:6%;">금액</th>
<th style="width:8%;">이미지첨부</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
<div class="d-flex justify-content-end">
<button type="button" id="saveBulkBtn" class="btn btn-dark btn-sm me-2">
<i class="bi bi-floppy-fill"></i> 전체 저장
</button>
<button type="button" class="btn btn-dark btn-sm me-2" id="closeAccountModal2">
&times; 닫기
</button>
</div>
</div>
</div>
</div>
<!-- 전자어음 검색 모달 -->
<div class="modal fade" id="electronicBillModal" tabindex="-1" aria-labelledby="electronicBillModalLabel" aria-hidden="true" style="z-index:1060;">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="electronicBillModalLabel">전자어음 검색</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="table-responsive">
<table class="table table-hover">
<thead class="table-secondary">
<tr>
<th>번호</th>
<th>등록일자</th>
<th>항목</th>
<th>세부항목</th>
<th>상세내용</th>
<th>금액</th>
<th>만기일자</th>
<th>선택</th>
</tr>
</thead>
<tbody id="electronicBillTableBody">
<!-- 전자어음 데이터가 여기에 동적으로 추가됩니다 -->
</tbody>
</table>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">닫기</button>
</div>
</div>
</div>
</div>
<div class="container-fluid">
<!-- Modal -->
<div id="myModal" class="modal">
<div class="modal-content" style="width:1000px;">
<div class="modal-header">
<span class="modal-title"> <?=$title_message?> </span>
<span class="close">&times;</span>
</div>
<div class="modal-body">
<div class="custom-card"></div>
</div>
</div>
</div>
</div>
<div class="container-fluid">
<div class="card justify-content-center text-center mt-5">
<div class="card-header">
<span class="text-center fs-5"> <?=$title_message?>
<button type="button" class="btn btn-dark btn-sm me-1" onclick='location.reload()'>
<i class="bi bi-arrow-clockwise" ></i> </button>
</span>
</div>
<div class="card-body">
<div class="d-flex justify-content-center align-items-center mt-2">
<span>
▷ <?= $total_row ?> &nbsp;
</span>
<!-- 기간부터 검색까지 연결 묶음 start -->
<span id="showdate" class="btn btn-dark btn-sm">기간</span> &nbsp;
<div id="showframe" class="card" style="width:500px;">
<div class="card-header" style="padding:2px;">
<div class="d-flex justify-content-center align-items-center">
기간 설정
</div>
</div>
<div class="card-body">
<div class="d-flex justify-content-center align-items-center">
<button type="button" class="btn btn-outline-success btn-sm me-1 change_dateRange" onclick='alldatesearch()'>전체</button>
<button type="button" class="btn btn-outline-primary btn-sm me-1 change_dateRange" onclick='pre_year()'>전년도</button>
<button type="button" class="btn btn-dark btn-sm me-1 change_dateRange" onclick='pre_month()'>전월</button>
<button type="button" class="btn btn-dark btn-sm me-1 change_dateRange" onclick='dayBeforeYesterday()'>전전일</button>
<button type="button" class="btn btn-dark btn-sm me-1 change_dateRange" onclick='yesterday()'>전일</button>
<button type="button" class="btn btn-outline-danger btn-sm me-1 change_dateRange" onclick='this_today()'>오늘</button>
<button type="button" class="btn btn-dark btn-sm me-1 change_dateRange" onclick='this_month()'>당월</button>
<button type="button" class="btn btn-dark btn-sm me-1 change_dateRange" onclick='this_year()'>당해년도</button>
</div>
</div>
</div>
<input type="date" id="fromdate" name="fromdate" class="form-control" style="width:110px;" value="<?=$fromdate?>"> &nbsp; ~ &nbsp;
<input type="date" id="todate" name="todate" class="form-control me-1" style="width:110px;" value="<?=$todate?>"> &nbsp;
<!-- 첫 번째 select 문: 수입/지출 구분 -->
<select id="inoutsep_select" name="inoutsep_select" class="form-select form-select-sm mx-1 d-block w-auto mx-1" >
<option value="">구분</option>
<option value="수입" <?= $inoutsep_select === '수입' ? 'selected' : '' ?>>수입</option>
<option value="지출" <?= $inoutsep_select === '지출' ? 'selected' : '' ?>>지출</option>
<option value="최초전월이월" <?= $inoutsep_select === '최초전월이월' ? 'selected' : '' ?>>최초전월이월</option>
</select>
<!-- 두 번째 select 문: 항목 선택 -->
<select id="content_select" name="content_select" class="form-select form-select-sm mx-1 d-block w-auto mx-1" >
<option value="">전체항목</option>
<?php
include 'fetch_options.php';
$options = array_merge(array_keys($incomeOptions), array_keys($expenseOptions));
foreach ($options as $option) {
$selected = ($content_select === $option) ? 'selected' : '';
echo "<option value=\"$option\" $selected>$option</option>";
}
?>
</select>
<div class="inputWrap30">
<input type="text" id="search" class="form-control" style="width:150px;" name="search" value="<?=$search?>" onKeyPress="if (event.keyCode==13){ enter(); }">
<button class="btnClear"></button>
</div>
&nbsp;&nbsp;
<button class="btn btn-outline-dark btn-sm" type="button" id="searchBtn"> <i class="bi bi-search"></i> </button> &nbsp;&nbsp;&nbsp;&nbsp;
<button type="button" class="btn btn-secondary btn-sm ms-2 me-2" onclick="settings();" data-bs-toggle="tooltip" data-bs-placement="bottom" title="계정 관리(추가/수정/삭제)" > <i class="bi bi-gear-fill"></i> </button>
<button id="newBtn" type="button" class="btn btn-dark btn-sm me-2"> <i class="bi bi-pencil-square"></i> 신규 </button>
<button id="bulkNewBtn" type="button" class="btn btn-info btn-sm me-2"> <i class="bi bi-plus-square"></i> 대량등록 </button>
<button type="button" class="btn btn-dark btn-sm me-2" onclick="generateExcel();" > <i class="bi bi-file-earmark-spreadsheet"></i> 엑셀다운로드 </button>
<button type="button" class="btn btn-primary btn-sm me-2" onclick="detail();" > <i class="bi bi-ticket-detailed"></i> 상세내역 </button>
</div>
</div>
<div class="d-flex flex-wrap justify-content-start align-items-center mt-2 p-2 border rounded" style="gap: 10px;">
<strong class="me-2">계좌 잔액:</strong>
<?php foreach ($accountFinalBalances as $summary): ?>
<?php if ($summary['balance'] > 0): ?>
<?php
// USD가 포함된 경우 금액 앞에 $ 추가
$isUSD = stripos($summary['name'], 'USD') !== false;
$formattedBalance = $isUSD ? '$' . number_format($summary['balance']) : number_format($summary['balance']);
?>
<div class="border rounded p-1" style="font-size: 0.8em;">
<span class="text-secondary"><?= htmlspecialchars($summary['name']) ?>:</span>
<span class="fw-bold ms-1"><?= $formattedBalance ?></span>
</div>
<?php endif; ?>
<?php endforeach; ?>
</div>
<div class="table-responsive">
<table class="table table-hover" id="myTable">
<thead class="table-secondary">
<tr>
<th class="text-center" style="width:40px;">번호</th>
<th class="text-center" style="width:70px;">등록일자</th>
<th class="text-center" style="width:50px;">구분</th>
<th class="text-center" style="width:80px;">항목</th>
<th class="text-center" style="width:80px;">세부항목</th>
<th class="text-center" style="width:250px;">상세내용</th>
<th class="text-center" style="width:90px;">수입</th>
<th class="text-center" style="width:90px;">지출</th>
<th class="text-center" style="width:90px;">잔액</th>
<th class="text-center" style="width:230px;">계좌</th>
<th class="text-center" style="width:70px;">만기일자</th>
<th class="text-center" style="width:70px;">배서일자</th>
<th class="text-center" style="width:60px;">✅ 첨부서류</th>
</tr>
<tr style="background-color: #808080!important;">
<th class="text-end" colspan="6"> 합계 &nbsp; </th>
<th class="text-end" id="totalIncomeAmount"></th>
<th class="text-end" id="totalExpenseAmount"></th>
<th class="text-end" id="totalBalanceAmount"></th>
<th class="text-end" colspan="4"></th>
</tr>
</thead>
<?php
// 1. 계좌별 기초 잔액을 계산하여 배열로 관리 (기간 시작일 이전)
$runningBalances = [];
if (is_array($accounts)) {
foreach ($accounts as $account) {
$accountDisplay = $account['company'] . ' ' . $account['number'];
if (!empty($account['memo'])) {
$accountDisplay .= ' (' . $account['memo'] . ')';
}
$initialBalanceSql = "SELECT
(SUM(CASE WHEN inoutsep = '수입' OR inoutsep = '최초전월이월' THEN REPLACE(amount, ',', '') ELSE 0 END) -
SUM(CASE WHEN inoutsep = '지출' THEN REPLACE(amount, ',', '') ELSE 0 END)) AS balance
FROM $tablename
WHERE is_deleted = '0' AND registDate < :fromdate AND bankbook = :bankbook
AND (dueDate = '0000-00-00' OR dueDate IS NULL OR dueDate = '')";
$initialBalanceStmh = $pdo->prepare($initialBalanceSql);
$initialBalanceStmh->bindParam(':fromdate', $fromdate);
$initialBalanceStmh->bindParam(':bankbook', $accountDisplay);
$initialBalanceStmh->execute();
$result = $initialBalanceStmh->fetch(PDO::FETCH_ASSOC);
$runningBalances[$accountDisplay] = $result['balance'] ?? 0;
}
}
$start_num = $total_row;
$counter = 1;
// 2. 루프를 돌며 각 거래에 대한 계좌별 잔액을 계산하고 출력
// 이 while 루프는 페이지 상단에서 시작된 try 블록 안에서 실행됩니다.
while($row = $stmh->fetch(PDO::FETCH_ASSOC)) {
include '_row.php'; // $num, $registDate, $bankbook 등의 변수 할당
$amount = floatval(str_replace(',', '', $row['amount']));
// json에 없는 계좌의 거래가 있을 경우를 대비해 초기화
if (!isset($runningBalances[$bankbook])) {
$runningBalances[$bankbook] = 0;
}
// 해당 계좌의 잔액을 업데이트 (어음이 아닌 경우만)
if ($dueDate === '0000-00-00' || !$dueDate || $dueDate === '' || $bankbook === '전자어음') {
if ($row['inoutsep'] === '수입' || $row['inoutsep'] === '최초전월이월') {
$runningBalances[$bankbook] += $amount;
} else { // 지출
$runningBalances[$bankbook] -= $amount;
}
}
?>
<tr>
<td class="text-center" onclick="loadForm('update', '<?=$num?>');"><?= $counter ?></td>
<td class="text-center" onclick="loadForm('update', '<?=$num?>');"><?= $registDate ?></td>
<td class="text-center <?= ($inoutsep === '수입' || $inoutsep === '최초전월이월') ? 'text-primary' : 'text-danger' ?>" onclick="loadForm('update', '<?=$num?>');"><?= $inoutsep ?></td>
<td class="text-center fw-bold <?= ($inoutsep === '수입' || $inoutsep === '최초전월이월') ? 'text-primary' : 'text-danger' ?>" onclick="loadForm('update', '<?=$num?>');"> <?= $content ?> </td>
<td class="text-center fw-bold <?= ($inoutsep === '수입' || $inoutsep === '최초전월이월') ? 'text-primary' : 'text-danger' ?>" onclick="loadForm('update', '<?=$num?>');"> <?= $contentSub ?> </td>
<td class="text-start <?= ($inoutsep === '수입' || $inoutsep === '최초전월이월') ? 'text-primary' : 'text-danger' ?>" onclick="loadForm('update', '<?=$num?>');"><?= $content_detail ?></td>
<?php if ($inoutsep === '수입' || $inoutsep === '최초전월이월') : ?>
<td class="text-end fw-bold text-primary" onclick="loadForm('update', '<?=$num?>');">
<?= is_numeric($amount) ? number_format($amount) : htmlspecialchars($amount) ?>
</td>
<td class="text-end"></td>
<?php else : ?>
<td class="text-end"></td>
<td class="text-end fw-bold text-danger" onclick="loadForm('update', '<?=$num?>');">
<?= is_numeric($amount) ? number_format($amount) : htmlspecialchars($amount) ?>
</td>
<?php endif; ?>
<td class="text-end fw-bold" onclick="loadForm('update', '<?=$num?>');"><?= number_format($runningBalances[$bankbook]) ?></td>
<td class="text-start" onclick="loadForm('update', '<?=$num?>');"><?= $bankbook ?></td>
<td class="text-start" onclick="loadForm('update', '<?=$num?>');">
<?= ($dueDate === '0000-00-00' || !$dueDate) ? '' : '(어음)'. $dueDate ?>
</td>
<td class="text-start" onclick="loadForm('update', '<?=$num?>');">
<?= ($bankbook === '전자어음' && $endorsementDate && $endorsementDate !== '0000-00-00') ? $endorsementDate : '' ?>
</td>
<td class="text-center">
<?php
// picuploads 테이블에서 이미지 검색
$imageSql = "SELECT picname FROM {$DB}.picuploads WHERE tablename = 'account' AND parentnum = :num AND item = 'image' ";
$imageStmh = $pdo->prepare($imageSql);
$imageStmh->bindParam(':num', $num);
$imageStmh->execute();
$images = $imageStmh->fetchAll(PDO::FETCH_COLUMN); // 모든 결과를 배열로 가져옴
if (!empty($images)) {
foreach ($images as $fileId) {
if ($fileId) {
$imageId = 'account_image_' . $num . '_' . array_search($fileId, $images); // 고유 ID 생성
$link = "https://drive.google.com/file/d/{$fileId}/view?usp=drivesdk";
?>
<i class="bi bi-check2-square text-success" style="cursor: pointer;"
onclick="openTmpImagePopup('<?= $link ?>', '<?= $imageId ?>');"></i>
<?php
}
}
} else {
echo ' ';
}
?>
</td>
</tr>
<?php
$start_num--;
$counter++;
} // while 루프의 닫는 괄호
// ▼▼▼ 페이지 상단의 try 구문을 닫는 필수 catch 구문 ▼▼▼
} catch (PDOException $Exception) {
print "오류: ".$Exception->getMessage();
}
?>
</table>
</div>
</div>
</div>
</div>
</form>
<!-- 이미지 로딩 모달 -->
<div class="modal fade" id="loadingImageModal" tabindex="-1" aria-labelledby="loadingImageModalLabel" aria-hidden="true" data-bs-backdrop="static" data-bs-keyboard="false">
<div class="modal-dialog modal-dialog-centered modal-sm">
<div class="modal-content">
<div class="modal-body text-center">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-2 mb-0">이미지를 불러오는 중...</p>
</div>
</div>
</div>
</div>
<script>
// 페이지 로딩
$(document).ready(function(){
var loader = document.getElementById('loadingOverlay');
if (loader) {
loader.style.display = 'none';
}
$("#loadingOverlay").hide();
});
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
$(document).ready(function() {
const initialBalance = <?= json_encode($initialBalance) ?>;
const finalBalance = <?= json_encode($finalBalance) ?>;
dataTable = $('#myTable').DataTable({
"paging": true,
"ordering": true,
"searching": true,
"pageLength": 1000,
"lengthMenu": [1000],
"language": {
"lengthMenu": "Show _MENU_ entries",
"search": "Live Search:"
},
"order": [[0, 'desc']],
"dom": 't<"bottom"ip>',
"columnDefs": [
{
"orderable": true, // 정렬 활성화
"targets": [0, 1, 2, 3, 4, 5, 6, 7, 8] // 정렬 가능하도록 설정할 열 인덱스
},
{
"orderable": false, // 정렬 비활성화
"targets": [9, 10, 11, 12] // 나머지 열 (계좌, 만기일자, 배서일자) 비활성화
}
],
"footerCallback": function (row, data, start, end, display) {
var api = this.api();
var intVal = function (i) {
return typeof i === 'string' ?
i.replace(/[\$,]/g, '')*1 :
typeof i === 'number' ?
i : 0;
};
// Calculate the totals for Income, Expense, and Balance
// 컬럼숫자 입력
var totalIncomeAmount = api.column(6, { page: 'current' }).data().reduce(function (a, b) { return intVal(a) + intVal(b); }, 0);
var totalExpenseAmount = api.column(7, { page: 'current' }).data().reduce(function (a, b) { return intVal(a) + intVal(b); }, 0);
// Update the header with the calculated totals
$('#totalIncomeAmount').html(numberWithCommas(totalIncomeAmount));
$('#totalExpenseAmount').html(numberWithCommas(totalExpenseAmount));
$('#totalBalanceAmount').html(numberWithCommas(finalBalance));
}
});
});
</script>
<script>
let isSaving = false;
var ajaxRequest = null;
var ajaxRequest_SubOption = null;
// PHP 변수를 JS 에 전달
const bulkTimeKey = "<?= $bulkTimeKey ?>";
document.addEventListener('DOMContentLoaded', function() {
$("#newBtn").on("click", function() {
loadForm('insert');
});
$("#searchBtn").on("click", function() {
$("#board_form").submit();
});
// 복사 버튼 클릭 이벤트
$(document).on("click", "#copyBtn", function() {
document.querySelector(".modal-body .custom-card").innerHTML = '';
$("#myModal").hide();
var num = $("#num").val();
loadForm('copy', num);
});
// 전자어음 선택 버튼 클릭 이벤트
$(document).on("click", "#selectElectronicBillBtn", function() {
// 거래처가 먼저 선택되어 있는지 확인
const secondordnum = document.getElementById('secondordnum').value;
if (!secondordnum || secondordnum.trim() === '') {
alert('전자어음을 선택하기 전에 먼저 거래처를 검색하여 선택해주세요.');
return;
}
loadElectronicBills();
});
});
// 모달창에 내용을 넣는 구조임 모달을 부르고 내용을 동적으로 넣는다.
function loadForm(mode, num = null) {
// 로딩 오버레이 보여주기
$("#loadingOverlay").show();
if (num == null || mode == 'copy') {
$("#mode").val('insert');
} else {
$("#mode").val('update');
$("#num").val(num);
}
if (ajaxRequest !== null) {
ajaxRequest.abort();
}
ajaxRequest = $.ajax({
type: "POST",
url: "fetch_modal.php",
data: { mode: mode, num: num },
dataType: "html",
success: function(response) {
document.querySelector(".modal-body .custom-card").innerHTML = response;
$("#myModal").show();
// PHP 데이터를 JSON으로 인코딩
const incomeOptions = <?php echo json_encode($incomeOptions, JSON_UNESCAPED_UNICODE); ?>;
const expenseOptions = <?php echo json_encode($expenseOptions, JSON_UNESCAPED_UNICODE); ?>;
console.log('Income Options:', incomeOptions);
console.log('Expense Options:', expenseOptions);
function updateDescription() {
const contentSelect = document.getElementById('content');
const descriptionDiv = document.getElementById('content_description');
const selectedValue = contentSelect.value;
// 수입인지 지출인지에 따라 설명 변경
const descriptions = document.querySelector('input[name="inoutsep"]:checked').value === '수입' ? incomeOptions : expenseOptions;
descriptionDiv.innerText = descriptions[selectedValue] || '';
// '거래처 수금' 또는 계좌가 '전자어음'일 때 검색 버튼 추가
const bankbookSelect = document.getElementById('bankbook');
const isElectronicBill = bankbookSelect && bankbookSelect.value === '전자어음';
if (selectedValue === '거래처 수금' || isElectronicBill) {
// contentSub를 '외상매출금'으로 설정 (거래처 수금일 때만)
if (selectedValue === '거래처 수금') {
const contentSubSelect = document.getElementById('contentSub');
if (contentSubSelect) {
contentSubSelect.innerHTML = '<option value="외상매출금">외상매출금</option>';
contentSubSelect.value = '외상매출금';
}
}
// 검색 버튼이 이미 있는지 확인
let searchBtn = document.getElementById('phonebookSearchBtn');
if (!searchBtn) {
searchBtn = document.createElement('button');
searchBtn.id = 'phonebookSearchBtn';
searchBtn.type = 'button';
searchBtn.className = 'btn btn-primary btn-sm ms-2 w120px';
searchBtn.innerHTML = '거래처 <i class="bi bi-search"></i> ';
descriptionDiv.parentNode.insertBefore(searchBtn, descriptionDiv.nextSibling);
// 검색 버튼 클릭 이벤트
searchBtn.addEventListener('click', function() {
phonebookBtn('');
});
}
} else {
// '거래처 수금'이 아닌 경우 검색 버튼 제거
const searchBtn = document.getElementById('phonebookSearchBtn');
if (searchBtn) {
searchBtn.remove();
}
}
}
function updateContentOptions() {
console.log('updateContentOptions');
const contentSelect = document.getElementById('content');
if (contentSelect) {
contentSelect.innerHTML = '';
const selectedType = document.querySelector('input[name="inoutsep"]:checked').value;
let options;
if (selectedType === '최초전월이월') {
options = {'최초전월이월': '최초전월이월'};
} else {
options = selectedType === '수입' ? incomeOptions : expenseOptions;
}
for (const [value, text] of Object.entries(options)) {
const option = document.createElement('option');
option.value = value;
option.text = value;
contentSelect.appendChild(option);
}
// 수입 선택 시 자동으로 '거래처 수금' 선택
if (selectedType === '수입') {
contentSelect.value = '거래처 수금';
}
updateDescription();
}
}
function phonebookBtn(search)
{
returnID = '수금등록';
href = '/phonebook/list.php?search=' + search + '&returnID=' + returnID;
popupCenter(href, '전화번호 검색', 1800, 800);
}
$(document).on("click", "#closeBtn", function() {
$("#myModal").hide();
});
// loadForm() 성공 콜백 안에서
// 1) 기존에 붙어 있던 saveBtn 클릭 핸들러 제거
$(document).off("click", "#saveBtn");
// 2) 새로 핸들러 바인딩
$(document).on("click", "#saveBtn", function() {
// if (isSaving) return;
// isSaving = true;
// AJAX 요청을 보냄
if (ajaxRequest !== null) {
ajaxRequest.abort();
}
ajaxRequest = $.ajax({
url: "/account/insert.php",
type: "post",
data: {
mode: $("#mode").val(),
num: $("#num").val(),
update_log: $("#update_log").val(),
registDate: $("#registDate").val(),
inoutsep: $("input[name='inoutsep']:checked").val(),
content: $("#content").val(),
amount: $("#amount").val(),
dueDate: $("#dueDate").val(),
first_writer: $("#first_writer").val(),
content_detail: $("#content_detail").val(),
contentSub: $("#contentSub").val(),
bankbook: $("#bankbook").val(),
secondordnum: $("#secondordnum").val(),
endorsementDate: $("#endorsementDate").val(),
parentEBNum: $("#parentEBNum").val()
},
dataType: "json",
success: function(response) {
Toastify({
text: "저장 완료",
duration: 3000,
close: true,
gravity: "top",
position: "center",
backgroundColor: "#4fbe87",
}).showToast();
setTimeout(function() {
$("#myModal").hide();
location.reload();
}, 1500); // 1.5초 후 실행
},
error: function(jqxhr, status, error) {
console.log("AJAX Error: ", status, error);
// isSaving = false;
}
});
});
$(document).on("click", "#deleteBtn", function() {
var level = '<?= $_SESSION["level"] ?>';
if (level !== '1') {
Swal.fire({
title: '삭제불가',
text: "관리자만 삭제 가능합니다.",
icon: 'error',
confirmButtonText: '확인'
});
return;
}
Swal.fire({
title: '자료 삭제',
text: "삭제는 신중! 정말 삭제하시겠습니까?",
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: '삭제',
cancelButtonText: '취소'
}).then((result) => {
if (result.isConfirmed) {
$("#mode").val('delete');
var formData = $("#board_form").serialize();
$.ajax({
url: "/account/insert.php",
type: "post",
data: formData,
success: function(response) {
Toastify({
text: "파일 삭제완료",
duration: 2000,
close: true,
gravity: "top",
position: "center",
backgroundColor: "#4fbe87",
}).showToast();
$("#myModal").hide();
location.reload();
},
error: function(jqxhr, status, error) {
console.log(jqxhr, status, error);
}
});
}
});
});
$(".close").on("click", function() {
$("#myModal").hide();
});
// 항목 선택 변경 시 설명 업데이트
$(document).on("change", "#content", updateDescription);
$(document).on("change", "input[name='inoutsep']", updateContentOptions);
// 계좌 선택 변경 시 배서일자 필드 표시/숨김 처리
$(document).on("change", "#bankbook", function() {
const endorsementDateContainer = document.getElementById('endorsementDateContainer');
const selectElectronicBillBtn = document.getElementById('selectElectronicBillBtn');
if (endorsementDateContainer) {
endorsementDateContainer.style.display = this.value === '전자어음' ? 'inline-block' : 'none';
}
if (selectElectronicBillBtn) {
selectElectronicBillBtn.style.display = this.value === '전자어음' ? 'inline-block' : 'none';
}
// 계좌가 바뀌면 거래처 검색 버튼 표시/숨김도 갱신
if (typeof updateDescription === 'function') updateDescription();
// 전자어음 선택 시 그리기 버튼 표시
const drawBtn = document.getElementById('drawBtn');
if (drawBtn) {
if (this.value === '전자어음') {
drawBtn.style.display = 'inline-block';
} else {
drawBtn.style.display = 'none';
// 그리기 모드가 활성화되어 있다면 비활성화
if (document.body.classList.contains('drawing-mode')) {
toggleDrawingMode();
}
}
}
});
// 전자어음 선택 버튼 클릭 이벤트
$(document).on("click", "#selectElectronicBillBtn", function() {
loadElectronicBills();
});
// 기존 이미지 불러오기 (Google Drive에서 가져오기)
function displayImageLoad() {
$('#displayImage').show();
var data = <?php echo json_encode($saveimagename_arr); ?>;
$("#displayImage").html('');
if (Array.isArray(data) && data.length > 0) {
data.forEach(function (fileData, i) {
const realName = fileData.realname || '다운로드 파일';
const thumbnail = fileData.thumbnail || '/assets/default-thumbnail.png';
const link = fileData.link || '#';
const fileId = fileData.fileId || null;
const rotation = fileData.rotation || 0;
const mode = '<?php echo $mode; ?>';
if (!fileId) {
console.error("fileId가 누락되었습니다. index: " + i, fileData);
return;
}
// 구글 드라이브 이미지 팝업 링크 생성
let deleteButton = '';
if (mode !== 'view') {
deleteButton = `<button type="button" class="btn btn-danger btn-sm mx-3" id="delImage${i}" onclick="delImageFn('${i}', '${fileId}')">
<i class="bi bi-trash"></i>
</button>`;
}
$("#displayImage").append(
"<div class='row mb-3'>" +
"<div class='col d-flex align-items-center justify-content-center'>" +
"<div class='position-relative'>" +
"<a href='#' onclick=\"openTmpImagePopup('" + link + "', 'image" + i + "'); return false;\">" +
"<img id='image" + i + "' src='" + thumbnail + "' style='width:100px; height:auto; transform: rotate(" + rotation + "deg);'>" +
"</a>" +
(mode !== 'view' ?
"<div class='position-absolute top-0 end-0 mt-1 me-1'>" +
"<button type='button' class='btn btn-primary btn-sm rotate-btn' onclick=\"rotateImage('" + fileId + "', 'image" + i + "')\">" +
"<i class='bi bi-arrow-clockwise'></i>" +
"</button>" +
"</div>" : "") +
"</div>" +
deleteButton +
"</div>" +
"</div>"
);
});
} else {
$("#displayImage").append(
"<div class='text-center text-muted'>No files</div>"
);
}
}
displayImageLoad(); // 기존이미지 업로드 보이기
// 모달 로드 완료 후 초기 상태 설정
if (typeof updateDescription === 'function') {
updateDescription();
}
},
error: function(jqxhr, status, error) {
console.log("AJAX error in loadForm:", status, error);
},
complete: function() {
// 성공이든 실패든 로딩 오버레이 숨기기
$("#loadingOverlay").hide();
}
});
}
function updateSubOptions() {
const contentSelect = document.getElementById('content');
const contentSubSelect = document.getElementById('contentSub');
const selectedValue = contentSelect.value;
const inoutsepValue = document.querySelector('input[name="inoutsep"]:checked')?.value || '지출';
if (ajaxRequest !== null) {
ajaxRequest.abort();
}
// AJAX 요청으로 세부항목 가져오기
ajaxRequest = $.ajax({
url: 'fetch_modal.php',
type: 'POST',
data: {
action: 'getSubOptions',
selectedKey: selectedValue,
inoutsep: inoutsepValue // 수입/지출 구분 추가
},
dataType: 'json',
success: function(response) {
// 기존 옵션 초기화
contentSubSelect.innerHTML = '';
if (response.subOptions && response.subOptions.length > 0) {
// 새로운 옵션 추가
response.subOptions.forEach(item => {
for (const key in item) {
const option = document.createElement('option');
option.value = key;
option.text = key;
contentSubSelect.appendChild(option);
}
});
} else {
// 세부항목이 없는 경우 기본값 처리
const option = document.createElement('option');
option.value = '';
option.text = '세부항목 없음';
contentSubSelect.appendChild(option);
}
},
error: function(jqxhr, status, error) {
console.log("AJAX Error:", status, error);
}
});
}
// content 선택 변경 이벤트
$(document).on('change', '#content', updateSubOptions);
</script>
<script>
function generateExcel() {
var table = document.getElementById('myTable');
var rows = table.getElementsByTagName('tr');
var data = [];
// 각 행을 반복하여 데이터 수집
for (var i = 1; i < rows.length; i++) { // 헤더 행을 건너뜀
var cells = rows[i].getElementsByTagName('td');
var rowData = {};
rowData['number'] = cells[0]?.innerText || '';
rowData['registDate'] = cells[1]?.innerText || '';
rowData['content'] = cells[2]?.innerText || '';
rowData['contentSub'] = cells[3]?.innerText || '';
rowData['contentDetail'] = cells[4]?.innerText || '';
rowData['income'] = cells[5]?.innerText || '';
rowData['expense'] = cells[6]?.innerText || '';
rowData['balance'] = cells[7]?.innerText || '';
rowData['dueDate'] = cells[8]?.innerText || '';
data.push(rowData);
}
// saveExcel.php에 데이터 전송
var xhr = new XMLHttpRequest();
xhr.open("POST", "saveExcel.php", true);
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
try {
var response = JSON.parse(xhr.responseText);
if (response.success) {
console.log('Excel file generated successfully.');
// 다운로드 스크립트로 리디렉션
window.location.href = 'saveExcel.php?download=' + encodeURIComponent(response.filename);
} else {
console.log('Failed to generate Excel file: ' + response.message);
}
} catch (e) {
console.log('Error parsing response: ' + e.message + '\nResponse text: ' + xhr.responseText);
}
} else {
console.log('Failed to generate Excel file: Server returned status ' + xhr.status);
}
}
};
xhr.send(JSON.stringify(data));
}
function settings() {
// 계정설정
const url = `settings.php`;
customPopup(url, '계정 관리', 600, 850);
}
function detail() {
// detail.php로 이동할 URL 생성
const url = `detail.php`;
// customPopup을 사용하여 detail.php를 팝업으로 열기
customPopup(url, '상세 내역', 800, 900);
}
function openPopup(url, title, width, height) {
// 화면 중앙에 팝업을 띄우도록 좌표 계산
const left = (window.screen.width / 2) - (width / 2);
const top = (window.screen.height / 2) - (height / 2);
// 팝업 창 생성
const popupWindow = window.open(
url,
title,
`width=${width},height=${height},top=${top},left=${left},scrollbars=yes,resizable=yes`
);
// 오버레이 생성
const overlay = document.createElement('div');
overlay.id = 'overlay';
overlay.style.position = 'fixed';
overlay.style.top = 0;
overlay.style.left = 0;
overlay.style.width = '100%';
overlay.style.height = '100%';
overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'; // 반투명 검은색
overlay.style.zIndex = 10000; // 최상위 레이어
overlay.style.cursor = 'not-allowed'; // 사용자가 클릭하지 못하도록 마우스 커서를 변경
document.body.appendChild(overlay);
// 팝업이 닫히면 오버레이 제거
const interval = setInterval(() => {
if (popupWindow.closed) {
clearInterval(interval);
document.body.removeChild(overlay);
}
}, 500);
// 팝업 창에 포커스 이동
if (window.focus) {
popupWindow.focus();
}
}
function enter() {
$("#board_form").submit();
}
</script>
<!-- 부트스트랩 툴팁 -->
<script>
document.addEventListener('DOMContentLoaded', function () {
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl);
});
// $("#order_form_write").modal("show");
});
</script>
<script>
// PHP 데이터를 JavaScript 변수로 변환
const incomeOptions = <?php echo json_encode($incomeOptions, JSON_UNESCAPED_UNICODE); ?>;
const expenseOptions = <?php echo json_encode($expenseOptions, JSON_UNESCAPED_UNICODE); ?>;
// 수입/지출 선택에 따른 계정과목 업데이트
document.getElementById('inoutsep_select').addEventListener('change', function() {
const contentSelect = document.getElementById('content_select');
const selectedType = this.value;
// 기존 옵션 제거 (전체항목 제외)
while (contentSelect.options.length > 1) {
contentSelect.remove(1);
}
// 선택된 타입에 따라 옵션 추가
const options = selectedType === '수입' ? incomeOptions : expenseOptions;
// 옵션 추가
Object.keys(options).forEach(key => {
const option = document.createElement('option');
option.value = key;
option.textContent = key;
contentSelect.appendChild(option);
});
// 전체항목으로 초기화
contentSelect.value = '';
});
$(document).ready(function(){
// 방문기록 남김
var title = '<?php echo $title_message; ?>';
saveMenuLog(title);
});
// account/list.php 파일의 기존 <script> 태그 안에 추가
// --- 대량등록 관련 스크립트 시작 ---
$(document).ready(function() {
// 배경 스크롤 방지 함수
function disableBodyScroll() {
$('body').css('overflow', 'hidden');
}
// 배경 스크롤 복원 함수
function enableBodyScroll() {
$('body').css('overflow', 'auto');
}
// '대량등록' 버튼 클릭 시 모달 열기
$("#bulkNewBtn").on("click", function() {
// 테이블 내용 초기화
$("#bulkEntryTable tbody").empty();
// 첫 행 추가
addRow_BulkEntry();
// 배경 스크롤 방지
disableBodyScroll();
// 모달 표시
$("#bulkEntryModal").show();
});
// 모달 닫기 버튼
$("#bulkEntryModal .close").on("click", function() {
$("#bulkEntryModal").hide();
// 배경 스크롤 복원
enableBodyScroll();
});
// 행 추가 버튼 (+)
$(document).on('click', '#bulkEntryTable .add-row', function() {
addRow_BulkEntry();
});
// 행 삭제 버튼 (-)
$(document).on('click', '#bulkEntryTable .remove-row', function() {
if ($("#bulkEntryTable tbody tr").length > 1) { // 최소 1개의 행은 유지
$(this).closest('tr').remove();
}
});
// '전체 저장' 버튼 클릭 이벤트
$("#saveBulkBtn").on("click", function() {
saveBulkData();
});
// '구분' 변경 시 '항목' 드롭다운 업데이트
$(document).on('change', '.bulk-inoutsep', function() {
updateBulkContentOptions($(this));
});
// '항목' 변경 시 '세부항목' 드롭다운 업데이트
$(document).on('change', '.bulk-content', function() {
updateBulkSubOptions($(this));
});
// '계좌' 변경 시 배서일자 필드 표시/숨김
$(document).on('change', '.bulk-bankbook', function() {
const $row = $(this).closest('tr');
const $endorsementDateField = $row.find('.bulk-endorsementDate');
const $selectElectronicBillBtn = $row.find('.bulk-select-electronic-bill-btn');
if (this.value === '전자어음') {
$endorsementDateField.show();
$selectElectronicBillBtn.show();
// 전자어음 선택 시 오늘날짜로 설정
// 지출이 선택된 경우에만 오늘 날짜로 설정
if (!$endorsementDateField.val() && $row.find('.bulk-inoutsep').val() === '지출') {
$endorsementDateField.val(new Date().toISOString().slice(0, 10));
}
} else {
$endorsementDateField.hide();
$selectElectronicBillBtn.hide();
}
});
// 대량등록에서 전자어음 선택 버튼 클릭 이벤트
$(document).on('click', '.bulk-select-electronic-bill-btn', function() {
const $row = $(this).closest('tr');
const secondordnum = $row.find('.bulk-secondordnum').val();
// 거래처가 먼저 선택되어 있는지 확인
if (!secondordnum || secondordnum.trim() === '') {
alert('전자어음을 선택하기 전에 먼저 거래처를 검색하여 선택해주세요.');
return;
}
loadElectronicBillsForBulk($row);
});
// 대량등록 모달 바깥 영역 클릭 시 닫기
$("#bulkEntryModal").on('click', function(e) {
if (e.target === this) {
$("#bulkEntryModal").hide();
// 배경 스크롤 복원
enableBodyScroll();
}
});
});
/**
* 대량등록 테이블에 새로운 행을 추가하는 함수
*/
function addRow_BulkEntry() {
// 현재 행의 등록일자 가져오기
const currentRow = $(event.target).closest('tr');
const currentDate = currentRow ? currentRow.find('.bulk-registDate').val() : new Date().toISOString().slice(0, 10);
const bankbookOptions = `<?php
$optionsHtml = "";
$jsonFile = $_SERVER['DOCUMENT_ROOT'] . "/account/accoutlist.json";
if (file_exists($jsonFile)) {
$accounts = json_decode(file_get_contents($jsonFile), true);
if (is_array($accounts)) {
foreach ($accounts as $account) {
$displayText = htmlspecialchars($account['company'] . ' ' . $account['number'] . (!empty($account['memo']) ? ' (' . $account['memo'] . ')' : ''), ENT_QUOTES);
$optionsHtml .= "<option value='" . $displayText . "'>" . $displayText . "</option>";
}
}
}
echo $optionsHtml;
?><option value="전자어음">전자어음</option>`;
const newRow = `
<tr>
<td class="text-center">
<button type="button" class="btn btn-sm btn-outline-primary add-row" style="padding: 2px 5px;">+</button>
<button type="button" class="btn btn-sm btn-outline-danger remove-row" style="padding: 2px 6px;">-</button>
<button type="button" class="btn btn-sm btn-outline-secondary copy-row" style="padding: 2px 6px;">
<i class="bi bi-files"></i>
</button>
</td>
<td><input type="date" class="form-control form-control-sm bulk-registDate noborder-input" value="${currentDate}"></td>
<td>
<select class="form-select form-select-sm bulk-inoutsep">
<option value="지출" selected>지출</option>
<option value="수입">수입</option>
<option value="최초전월이월">최초전월이월</option>
</select>
</td>
<td><select class="form-select form-select-sm bulk-bankbook">${bankbookOptions}</select></td>
<td><select class="form-select form-select-sm bulk-content"></select></td>
<td><select class="form-select form-select-sm bulk-contentSub"></select></td>
<td>
<button type="button" class="btn btn-sm btn-outline-primary bulk-search-company">
<i class="bi bi-search"></i>
</button>
</td>
<td><input type="text" class="form-control form-control-sm bulk-secondordnum noborder-input" autocomplete="off"></td>
<td><input type="date" class="form-control form-control-sm bulk-dueDate noborder-input"></td>
<td>
<input type="date" class="form-control form-control-sm bulk-endorsementDate noborder-input" value="" style="display: none;">
<button type="button" class="btn btn-outline-primary btn-sm bulk-select-electronic-bill-btn" style="display: none;">
<i class="bi bi-search"></i>
</button>
</td>
<td><input type="text" class="form-control form-control-sm bulk-content_detail noborder-input text-start" autocomplete="off"></td>
<td><input type="text" class="form-control form-control-sm bulk-amount text-end noborder-input" onkeyup="inputNumberFormat(this)" autocomplete="off"></td>
<td>
<input type="file"
class="form-control form-control-sm bulk-image-input"
multiple
accept="image/*">
</td>
</tr>
`;
if (currentRow && currentRow.length) {
// 현재 행이 있는 경우 해당 행 다음에 추가
currentRow.after(newRow);
currentRow.next().find('.bulk-inoutsep').trigger('change');
} else {
// 현재 행이 없는 경우(첫 행 추가) 테이블에 추가
$('#bulkEntryTable tbody').append(newRow);
$('#bulkEntryTable tbody tr:last .bulk-inoutsep').trigger('change');
}
}
/**
* '구분' (수입/지출/최초전월이월) 선택에 따라 '항목' 드롭다운 메뉴를 업데이트하는 함수
*/
function updateBulkContentOptions($selectElement) {
const selectedType = $selectElement.val();
const contentSelect = $selectElement.closest('tr').find('.bulk-content');
let options;
contentSelect.empty();
if(selectedType == '최초전월이월') {
contentSelect.append(`<option value="최초전월이월">최초전월이월</option>`);
options = incomeOptions;
} else {
options = (selectedType === '수입') ? incomeOptions : expenseOptions;
}
// 나머지 옵션들 추가
for (const key in options) {
if (key !== '전월이월') { // 전월이월은 이미 추가했으므로 건너뜀
contentSelect.append(`<option value="${key}">${key}</option>`);
}
}
contentSelect.trigger('change'); // 항목이 변경되었으므로 세부항목도 업데이트
}
/**
* '항목' 선택에 따라 '세부항목' 드롭다운 메뉴를 업데이트하는 함수
*/
function updateBulkSubOptions($selectElement) {
const selectedKey = $selectElement.val();
const inoutsepValue = $selectElement.closest('tr').find('.bulk-inoutsep').val() || '지출';
console.log('updateBulkSubOptions 함수 호출 후 selectedKey : ', selectedKey, ', inoutsep:', inoutsepValue);
const contentSubSelect = $selectElement.closest('tr').find('.bulk-contentSub');
$.ajax({
url: 'fetch_modal.php',
type: 'POST',
data: {
action: 'getSubOptions',
selectedKey: selectedKey,
inoutsep: inoutsepValue // 수입/지출 구분 추가
},
dataType: 'json',
success: function(response) {
contentSubSelect.empty();
console.log(response);
if (response.subOptions && response.subOptions.length > 0) {
response.subOptions.forEach(item => {
for (const key in item) {
contentSubSelect.append(`<option value="${key}">${key}</option>`);
}
});
} else {
contentSubSelect.append(`<option value="">없음</option>`);
}
},
error: function() {
contentSubSelect.empty().append('<option value="">없음</option>');
}
});
}
/**
* 대량 등록 모달의 모든 데이터를 서버로 전송하여 저장하는 함수
*/
function saveBulkData() {
// 1) 행 데이터 수집 (entries 배열)
let entries = [];
$("#bulkEntryTable tbody tr").each(function() {
const $r = $(this);
const amt = $r.find(".bulk-amount").val().replace(/,/g,'');
const registDate = $r.find(".bulk-registDate").val();
if (!amt || !registDate || registDate === '0000-00-00') {
Swal.fire({
title: '등록일과 금액은 필수입니다.',
icon: 'warning',
confirmButtonText: '확인'
});
return;
}
if (!amt) return; // 금액 없으면 건너뜀
entries.push({
registDate: $r.find(".bulk-registDate").val(),
inoutsep: $r.find(".bulk-inoutsep").val(),
bankbook: $r.find(".bulk-bankbook").val(),
content: $r.find(".bulk-content").val() || '',
contentSub: $r.find(".bulk-contentSub").val() || '',
content_detail: $r.find(".bulk-content_detail").val() || '',
amount: amt,
secondordnum:$r.find(".bulk-secondordnum").val()|| '',
dueDate: $r.find(".bulk-dueDate").val() || '',
endorsementDate: $r.find(".bulk-endorsementDate").val() || '',
// **여기에 timekey 추가**
timekey: bulkTimeKey
});
});
if (entries.length === 0) {
return Swal.fire('입력 없음','저장할 데이터가 없습니다.','info');
}
// 2) 서버에 bulk insert
$.ajax({
url: "/account/insert_bulk.php",
method: "POST",
data: { entries: JSON.stringify(entries) },
dataType: "json"
}).done(function(resp) {
if (resp.status !== 'success') {
return Swal.fire('저장 실패', resp.message || 'Bulk insert 오류','error');
}
// resp.nums 는 [num1, num2, …] 형태로, entries 순서와 같은 인덱스 매칭
const nums = resp.nums;
let uploads = []; // Promise 배열
nums.forEach((num, idx) => {
const input = $("#bulkEntryTable tbody tr").eq(idx).find(".bulk-image-input")[0];
if (input && input.files.length > 0) {
// FormData 로 이미지만 전송
const fd = new FormData();
fd.append("tablename", "account");
fd.append("item", "image");
fd.append("upfilename","bulkImage");
fd.append("folderPath","경동기업/uploads");
fd.append("DBtable", "picuploads");
// **여기도 timekey 사용**
fd.append("timekey", bulkTimeKey);
fd.append("num", num); // 실제 num 업뎃 후에도 num 포함해 두면 안전합니다
Array.from(input.files).forEach(file => {
fd.append("bulkImage[]", file);
});
uploads.push(
$.ajax({
url: "/filedrive/fileprocess.php",
method: "POST",
data: fd,
processData: false,
contentType: false
})
);
}
});
// 3) 모든 이미지 업로드가 끝나면 리로드
Promise.all(uploads)
.then(() => {
Toastify({
text: `${entries.length}건 저장 완료`,
duration: 2000,
close: true,
gravity: "top", position: "center",
backgroundColor: "#4fbe87"
}).showToast();
})
.catch(err => {
console.error("이미지 업로드 중 오류:", err);
Toastify({
text: "일부 이미지 업로드에 실패했습니다.",
duration: 3000,
close: true,
gravity: "top", position: "center",
backgroundColor: "#f44336"
}).showToast();
})
.finally(() => {
setTimeout(()=> {
$("#bulkEntryModal").hide();
// 배경 스크롤 복원
enableBodyScroll();
location.reload();
}, 1500);
});
}).fail((jq,status,err) => {
Swal.fire('서버 오류','대량 저장 중 오류가 발생했습니다.','error');
console.error(status, err);
});
}
// --- 대량등록 관련 스크립트 끝 ---
$(function() {
var $modal = $('#bulkEntryModal');
var $openBtn = $('#openAccountModal');
var $closeBtns = $('#closeAccountModal, #closeAccountModal2');
var $dateInput = $('#accountDate');
var $accountCompany = $('#accountCompany');
var $secondord = $('#secondord');
var $saveBtn = $('#saveAccountBtn');
var $body = $('body');
// 모달 열기
$openBtn.on('click', function() {
$modal.show();
// 날짜 초기화
if (!$dateInput.val()) {
var today = new Date();
var yyyy = today.getFullYear();
var mm = String(today.getMonth() + 1).padStart(2, '0');
var dd = String(today.getDate()).padStart(2, '0');
$dateInput.val(yyyy + '-' + mm + '-' + dd);
}
// 거래처 초기화
if ($secondord.val()) {
$accountCompany.val($secondord.val());
}
$body.addClass('modal-open'); // 스크롤 방지
});
// 모달 닫기 (× 버튼들)
$closeBtns.on('click', function() {
$modal.hide();
$body.removeClass('modal-open');
});
// 저장 버튼 클릭
$saveBtn.on('click', function() {
saveData_account(); // 사용자가 정의한 함수 호출
$modal.hide();
$body.removeClass('modal-open');
});
// 바깥 영역 클릭 시 닫기
$modal.on('click', function(e) {
if (e.target === this) {
$modal.hide();
$body.removeClass('modal-open');
}
});
});
</script>
<script>
// 거래처 검색 버튼 클릭 이벤트
$(document).on('click', '.bulk-search-company', function() {
const $row = $(this).closest('tr');
const $secondordnum = $row.find('.bulk-secondordnum');
const $contentDetail = $row.find('.bulk-content_detail');
returnID = '수금등록';
href = '/phonebook/list.php?search=&returnID=' + returnID;
popupCenter(href, '전화번호 검색', 1800, 800);
});
// 거래처 선택 시 처리
function setCompanyInfo(companyCode, companyName) {
const $activeRow = $('#bulkEntryTable tbody tr:last');
$activeRow.find('.bulk-secondordnum').val(companyCode);
$activeRow.find('.bulk-content_detail').val(companyName);
}
// 팝업 중앙 정렬 함수
function popupCenter(url, title, w, h) {
var left = (screen.width/2)-(w/2);
var top = (screen.height/2)-(h/2);
return window.open(url, title, 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes, copyhistory=no, width='+w+', height='+h+', top='+top+', left='+left);
}
// 행 복사 이벤트
$(document).on('click', '.copy-row', function() {
const $currentRow = $(this).closest('tr');
const $newRow = $currentRow.clone();
// 현재 행의 값들 저장
const currentInoutsep = $currentRow.find('.bulk-inoutsep').val();
const currentBankbook = $currentRow.find('.bulk-bankbook').val();
const currentContent = $currentRow.find('.bulk-content').val();
const currentContentSub = $currentRow.find('.bulk-contentSub').val();
const currentSecondordnum = $currentRow.find('.bulk-secondordnum').val();
const currentContentDetail = $currentRow.find('.bulk-content_detail').val();
const currentAmount = $currentRow.find('.bulk-amount').val();
const currentDueDate = $currentRow.find('.bulk-dueDate').val();
const currentEndorsementDate = $currentRow.find('.bulk-endorsementDate').val();
const currentRegistDate = $currentRow.find('.bulk-registDate').val();
// 현재 행 바로 아래에 삽입
$currentRow.after($newRow);
// 모든 값들을 새 행에 설정
$newRow.find('.bulk-registDate').val(currentRegistDate);
$newRow.find('.bulk-inoutsep').val(currentInoutsep);
$newRow.find('.bulk-bankbook').val(currentBankbook);
$newRow.find('.bulk-secondordnum').val(currentSecondordnum);
$newRow.find('.bulk-content_detail').val(currentContentDetail);
$newRow.find('.bulk-amount').val(currentAmount);
$newRow.find('.bulk-dueDate').val(currentDueDate);
$newRow.find('.bulk-endorsementDate').val(currentEndorsementDate);
// 구분 변경 이벤트 트리거
$newRow.find('.bulk-inoutsep').trigger('change');
// 항목과 세부항목 설정을 위한 지연 처리
setTimeout(function() {
$newRow.find('.bulk-content').val(currentContent);
$newRow.find('.bulk-content').trigger('change');
// 세부항목 설정을 위한 추가 지연
setTimeout(function() {
$newRow.find('.bulk-contentSub').val(currentContentSub);
}, 100);
}, 100);
// 토스트 메시지 표시
Toastify({
text: "행이 복사되었습니다",
duration: 2000,
close: true,
gravity: "top",
position: "center",
backgroundColor: "#4fbe87",
}).showToast();
});
// 항목 선택 변경 이벤트 핸들러 수정
$(document).on('change', '.bulk-content', function() {
const $row = $(this).closest('tr');
const selectedKey = $(this).val();
const inoutsepValue = $row.find('.bulk-inoutsep').val() || '지출';
const $contentSubSelect = $row.find('.bulk-contentSub');
// 현재 선택된 세부항목 값 저장
const currentSubValue = $contentSubSelect.val();
$.ajax({
url: 'fetch_modal.php',
type: 'POST',
data: {
action: 'getSubOptions',
selectedKey: selectedKey,
inoutsep: inoutsepValue // 수입/지출 구분 추가
},
dataType: 'json',
success: function(response) {
$contentSubSelect.empty();
if (response.subOptions && response.subOptions.length > 0) {
response.subOptions.forEach(item => {
for (const key in item) {
const option = document.createElement('option');
option.value = key;
option.text = key;
$contentSubSelect.append(option);
}
});
// 이전에 선택된 값이 있으면 다시 선택
if (currentSubValue) {
$contentSubSelect.val(currentSubValue);
}
} else {
$contentSubSelect.append(`<option value="">없음</option>`);
}
},
error: function() {
$contentSubSelect.empty().append('<option value="">없음</option>');
}
});
});
function getGoogleDriveFileId(link) {
// 구글드라이브 파일ID 추출
var match = link.match(/\/d\/([a-zA-Z0-9_-]+)/);
return match ? match[1] : '';
}
// --- 여기부터 수정 및 추가된 함수 ---
// 로딩 모달을 보여주는 함수 (새로 추가)
function showImageLoadingModal() {
$('#loadingImageModal').modal('show');
}
// 로딩 모달을 숨기는 함수 (새로 추가)
function hideImageLoadingModal() {
$('#loadingImageModal').modal('hide');
}
// 이미지 팝업을 여는 함수 (보완됨)
function openTmpImagePopup(link, imageId) {
showImageLoadingModal(); // 이미지 클릭 즉시 로딩 모달 표시
console.log('link : ', link);
console.log('imageId : ', imageId);
var fileId = getGoogleDriveFileId(link);
if (!fileId) {
alert('구글드라이브 파일ID 추출 실패');
hideImageLoadingModal(); // 오류 발생 시 모달 숨김
return;
}
const imgElement = document.getElementById(imageId);
let currentRotation = 0;
if (imgElement) {
const transformStyle = imgElement.style.transform;
currentRotation = transformStyle
? parseInt(transformStyle.replace('rotate(', '').replace('deg)', '')) || 0
: 0;
} else {
console.warn('이미지 요소가 존재하지 않습니다:', imageId);
}
$.post('/filedrive/download_and_rotate.php', { fileId: fileId, rotation: currentRotation }, function(res) {
if (res.success) {
// 팝업 창 열기. 팝업 창이 로딩 모달을 닫는 역할을 함.
var popupWindow = popupCenter(
'/filedrive/view_tmpimg.php?img=' + encodeURIComponent(res.imgUrl) + '&rotation=' + res.rotation,
'imagePopup', 800, 600
);
if (!popupWindow) {
alert('팝업 창을 여는 데 실패했습니다. 브라우저의 팝업 차단 설정을 확인해주세요.');
hideImageLoadingModal();
}
} else {
alert(res.msg || '이미지 처리 실패');
hideImageLoadingModal();
}
}, 'json').fail(function() {
alert('서버와 통신 중 오류가 발생했습니다.');
hideImageLoadingModal();
});
}
// 전자어음 데이터 로드 함수
function loadElectronicBills() {
$.ajax({
url: 'get_electronic_bills.php',
type: 'GET',
dataType: 'json',
success: function(response) {
if (response.success) {
displayElectronicBills(response.data);
$('#electronicBillModal').modal('show');
} else {
alert('전자어음 데이터를 불러오는데 실패했습니다.');
}
},
error: function() {
alert('서버와 통신 중 오류가 발생했습니다.');
}
});
}
// 전자어음 목록 표시 함수
function displayElectronicBills(data) {
const tbody = $('#electronicBillTableBody');
tbody.empty();
if (data.length === 0) {
tbody.append('<tr><td colspan="8" class="text-center">배서일자가 없는 전자어음이 없습니다.</td></tr>');
return;
}
data.forEach(function(item) {
const row = `
<tr>
<td>${item.num}</td>
<td>${item.registDate}</td>
<td>${item.content || ''}</td>
<td>${item.contentSub || ''}</td>
<td>${item.content_detail || ''}</td>
<td class="text-end">${numberWithCommas(item.amount)}</td>
<td>${item.dueDate || ''}</td>
<td>
<button type="button" class="btn btn-primary btn-sm" onclick="selectElectronicBill('${item.num}', '${item.content}', '${item.contentSub}', '${item.content_detail}', '${item.amount}', '${item.dueDate}')">
선택
</button>
</td>
</tr>
`;
tbody.append(row);
});
}
// 전자어음 선택 함수
function selectElectronicBill(num, content, contentSub, contentDetail, amount, dueDate) {
// 모달 닫기
$('#electronicBillModal').modal('hide');
// 구분이 '지출'인 경우 항목을 '외상매출채권(전자어음)'으로 설정
const inoutsep = document.getElementById('inoutsep') ? document.getElementById('inoutsep').value : '';
if (inoutsep === '지출') {
$('#content').val('외상매출채권(전자어음)');
$('#contentSub').val('없음');
} else {
$('#content').val(content);
$('#contentSub').val(contentSub);
}
$('#content_detail').val(contentDetail);
$('#amount').val(numberWithCommas(amount));
$('#dueDate').val(dueDate);
$('#parentEBNum').val(num);
// 항목 변경 이벤트 트리거
$('#content').trigger('change');
// 토스트 메시지 표시
Toastify({
text: "전자어음 데이터가 적용되었습니다",
duration: 2000,
close: true,
gravity: "top",
position: "center",
backgroundColor: "#4fbe87",
}).showToast();
}
// 대량등록용 전자어음 데이터 로드 함수
function loadElectronicBillsForBulk($row) {
$.ajax({
url: 'get_electronic_bills.php',
type: 'GET',
dataType: 'json',
success: function(response) {
if (response.success) {
displayElectronicBillsForBulk(response.data, $row);
$('#electronicBillModal').modal('show');
} else {
alert('전자어음 데이터를 불러오는데 실패했습니다.');
}
},
error: function() {
alert('서버와 통신 중 오류가 발생했습니다.');
}
});
}
// 대량등록용 전자어음 목록 표시 함수
function displayElectronicBillsForBulk(data, $row) {
const tbody = $('#electronicBillTableBody');
tbody.empty();
if (data.length === 0) {
tbody.append('<tr><td colspan="8" class="text-center">배서일자가 없는 전자어음이 없습니다.</td></tr>');
return;
}
data.forEach(function(item) {
const rowIndex = $row.index();
const row = `
<tr>
<td>${item.num}</td>
<td>${item.registDate}</td>
<td>${item.content || ''}</td>
<td>${item.contentSub || ''}</td>
<td>${item.content_detail || ''}</td>
<td class="text-end">${numberWithCommas(item.amount)}</td>
<td>${item.dueDate || ''}</td>
<td>
<button type="button" class="btn btn-primary btn-sm" onclick="selectElectronicBillForBulk('${item.num}', '${item.content || ''}', '${item.contentSub || ''}', '${item.content_detail || ''}', '${item.amount}', '${item.dueDate || ''}', ${rowIndex})">
선택
</button>
</td>
</tr>
`;
tbody.append(row);
});
}
// 대량등록용 전자어음 선택 함수
function selectElectronicBillForBulk(num, content, contentSub, contentDetail, amount, dueDate, rowIndex) {
// 모달 닫기
$('#electronicBillModal').modal('hide');
// 해당 행의 필드에 데이터 적용
const $row = $('#bulkEntryTable tbody tr').eq(rowIndex);
// 구분이 '지출'인 경우 항목을 '외상매출채권(전자어음)'으로 설정
const inoutsep = $row.find('.bulk-inoutsep').val();
if (inoutsep === '지출') {
$row.find('.bulk-content').val('외상매출채권(전자어음)');
$row.find('.bulk-contentSub').val('없음');
} else {
$row.find('.bulk-content').val(content);
$row.find('.bulk-contentSub').val(contentSub);
}
$row.find('.bulk-content_detail').val(contentDetail);
$row.find('.bulk-amount').val(numberWithCommas(amount));
$row.find('.bulk-dueDate').val(dueDate);
// 항목 변경 이벤트 트리거
$row.find('.bulk-content').trigger('change');
// 토스트 메시지 표시
Toastify({
text: "전자어음 데이터가 적용되었습니다",
duration: 2000,
close: true,
gravity: "top",
position: "center",
backgroundColor: "#4fbe87",
}).showToast();
}
// 전자어음 목록 불러오기
// 그리기 모드 토글 함수
function toggleDrawingMode() {
const body = document.body;
const isDrawingMode = body.classList.contains('drawing-mode');
if (isDrawingMode) {
// 그리기 모드 비활성화
body.classList.remove('drawing-mode');
// 그리기 관련 컨트롤들 숨기기
const drawingControls = document.querySelectorAll('.drawing-controls .btn, .drawing-controls select, .drawing-controls input[type="color"], .drawing-controls input[type="range"], .drawing-controls span');
drawingControls.forEach(control => {
if (control.id !== 'drawBtn') {
control.style.display = 'none';
}
});
// 캔버스 제거
const canvas = document.querySelector('.drawing-canvas');
if (canvas) {
canvas.remove();
}
} else {
// 그리기 모드 활성화
body.classList.add('drawing-mode');
// 그리기 관련 컨트롤들 표시
const drawingControls = document.querySelectorAll('.drawing-controls .btn, .drawing-controls select, .drawing-controls input[type="color"], .drawing-controls input[type="range"], .drawing-controls span');
drawingControls.forEach(control => {
if (control.id !== 'drawBtn') {
control.style.display = 'inline-block';
}
});
// 캔버스 생성
createDrawingCanvas();
}
}
// 그리기 캔버스 생성 함수
function createDrawingCanvas() {
const previewContainer = document.getElementById('previewContainer');
if (!previewContainer) return;
// 기존 캔버스 제거
const existingCanvas = document.querySelector('.drawing-canvas');
if (existingCanvas) {
existingCanvas.remove();
}
// 새 캔버스 생성
const canvas = document.createElement('canvas');
canvas.className = 'drawing-canvas';
canvas.width = previewContainer.offsetWidth;
canvas.height = previewContainer.offsetHeight;
previewContainer.appendChild(canvas);
// 그리기 기능 초기화
initDrawingCanvas(canvas);
}
// 그리기 기능 초기화
function initDrawingCanvas(canvas) {
const ctx = canvas.getContext('2d');
let isDrawing = false;
let lastX = 0;
let lastY = 0;
// 마우스 이벤트 리스너
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', stopDrawing);
canvas.addEventListener('mouseout', stopDrawing);
function startDrawing(e) {
isDrawing = true;
[lastX, lastY] = [e.offsetX, e.offsetY];
}
function draw(e) {
if (!isDrawing) return;
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(e.offsetX, e.offsetY);
ctx.strokeStyle = document.getElementById('drawColor').value;
ctx.lineWidth = document.getElementById('eraserSize').value;
ctx.lineCap = 'round';
ctx.stroke();
[lastX, lastY] = [e.offsetX, e.offsetY];
}
function stopDrawing() {
isDrawing = false;
}
}
// 그리기 버튼 클릭 이벤트
$(document).on("click", "#drawBtn", function() {
toggleDrawingMode();
});
// 지우개 크기 조절
$(document).on("input", "#eraserSize", function() {
document.getElementById('eraserSizeLabel').textContent = this.value + 'px';
});
// 그리기 초기화 버튼
$(document).on("click", "#clearDrawingBtn", function() {
const canvas = document.querySelector('.drawing-canvas');
if (canvas) {
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
});
// 그리기 저장 버튼
$(document).on("click", "#saveDrawingBtn", function() {
const canvas = document.querySelector('.drawing-canvas');
if (canvas) {
const dataURL = canvas.toDataURL('image/png');
// 여기에 저장 로직 추가
console.log('그리기 저장:', dataURL);
}
});
</script>
</body>
</html>