// 한약 재고관리 시스템 - Frontend JavaScript
$(document).ready(function() {
// 페이지 네비게이션
$('.sidebar .nav-link').on('click', function(e) {
e.preventDefault();
const page = $(this).data('page');
// Active 상태 변경
$('.sidebar .nav-link').removeClass('active');
$(this).addClass('active');
// 페이지 전환
$('.main-content').removeClass('active');
$(`#${page}`).addClass('active');
// 페이지별 데이터 로드
loadPageData(page);
});
// 초기 데이터 로드
loadPageData('dashboard');
// 페이지별 데이터 로드 함수
function loadPageData(page) {
switch(page) {
case 'dashboard':
loadDashboard();
break;
case 'patients':
loadPatients();
break;
case 'purchase':
loadPurchaseReceipts();
break;
case 'formulas':
loadFormulas();
break;
case 'compound':
loadCompounds();
loadPatientsForSelect();
loadFormulasForSelect();
break;
case 'inventory':
loadInventory();
break;
case 'herbs':
loadHerbs();
break;
}
}
// 대시보드 데이터 로드
function loadDashboard() {
// 환자 수
$.get('/api/patients', function(response) {
if (response.success) {
$('#totalPatients').text(response.data.length);
}
});
// 재고 현황
$.get('/api/inventory/summary', function(response) {
if (response.success) {
$('#totalHerbs').text(response.data.length);
$('#inventoryValue').text(formatCurrency(response.summary.total_value));
}
});
// TODO: 오늘 조제 수, 최근 조제 내역
}
// 환자 목록 로드
function loadPatients() {
$.get('/api/patients', function(response) {
if (response.success) {
const tbody = $('#patientsList');
tbody.empty();
response.data.forEach(patient => {
tbody.append(`
${patient.name}
${patient.phone}
${patient.gender === 'M' ? '남' : patient.gender === 'F' ? '여' : '-'}
${patient.birth_date || '-'}
${patient.notes || '-'}
`);
});
}
});
}
// 환자 등록
$('#savePatientBtn').on('click', function() {
const patientData = {
name: $('#patientName').val(),
phone: $('#patientPhone').val(),
jumin_no: $('#patientJumin').val(),
gender: $('#patientGender').val(),
birth_date: $('#patientBirth').val(),
address: $('#patientAddress').val(),
notes: $('#patientNotes').val()
};
$.ajax({
url: '/api/patients',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify(patientData),
success: function(response) {
if (response.success) {
alert('환자가 등록되었습니다.');
$('#patientModal').modal('hide');
$('#patientForm')[0].reset();
loadPatients();
}
},
error: function(xhr) {
alert('오류: ' + xhr.responseJSON.error);
}
});
});
// 처방 목록 로드
function loadFormulas() {
$.get('/api/formulas', function(response) {
if (response.success) {
const tbody = $('#formulasList');
tbody.empty();
response.data.forEach(formula => {
tbody.append(`
${formula.formula_code || '-'}
${formula.formula_name}
${formula.base_cheop}첩
${formula.base_pouches}파우치
보기
`);
});
// 구성 약재 보기
$('.view-ingredients').on('click', function() {
const formulaId = $(this).data('id');
$.get(`/api/formulas/${formulaId}/ingredients`, function(response) {
if (response.success) {
let ingredientsList = response.data.map(ing =>
`${ing.herb_name}: ${ing.grams_per_cheop}g`
).join(', ');
alert('구성 약재:\n' + ingredientsList);
}
});
});
}
});
}
// 처방 구성 약재 추가 (모달)
let formulaIngredientCount = 0;
$('#addFormulaIngredientBtn').on('click', function() {
formulaIngredientCount++;
$('#formulaIngredients').append(`
약재 선택
`);
// 약재 목록 로드
const selectElement = $(`#formulaIngredients tr[data-row="${formulaIngredientCount}"] .herb-select`);
loadHerbsForSelect(selectElement);
// 삭제 버튼 이벤트
$(`#formulaIngredients tr[data-row="${formulaIngredientCount}"] .remove-ingredient`).on('click', function() {
$(this).closest('tr').remove();
});
});
// 처방 저장
$('#saveFormulaBtn').on('click', function() {
const ingredients = [];
$('#formulaIngredients tr').each(function() {
const herbId = $(this).find('.herb-select').val();
const grams = $(this).find('.grams-input').val();
if (herbId && grams) {
ingredients.push({
herb_item_id: parseInt(herbId),
grams_per_cheop: parseFloat(grams),
notes: $(this).find('.notes-input').val()
});
}
});
const formulaData = {
formula_code: $('#formulaCode').val(),
formula_name: $('#formulaName').val(),
formula_type: $('#formulaType').val(),
base_cheop: parseInt($('#baseCheop').val()),
base_pouches: parseInt($('#basePouches').val()),
description: $('#formulaDescription').val(),
ingredients: ingredients
};
$.ajax({
url: '/api/formulas',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify(formulaData),
success: function(response) {
if (response.success) {
alert('처방이 등록되었습니다.');
$('#formulaModal').modal('hide');
$('#formulaForm')[0].reset();
$('#formulaIngredients').empty();
loadFormulas();
}
},
error: function(xhr) {
alert('오류: ' + xhr.responseJSON.error);
}
});
});
// 조제 관리
$('#newCompoundBtn').on('click', function() {
$('#compoundForm').show();
$('#compoundEntryForm')[0].reset();
$('#compoundIngredients').empty();
});
$('#cancelCompoundBtn').on('click', function() {
$('#compoundForm').hide();
});
// 제수 변경 시 첩수 자동 계산
$('#jeCount').on('input', function() {
const jeCount = parseFloat($(this).val()) || 0;
const cheopTotal = jeCount * 20;
const pouchTotal = jeCount * 30;
$('#cheopTotal').val(cheopTotal);
$('#pouchTotal').val(pouchTotal);
// 약재별 총 용량 재계산
updateIngredientTotals();
});
// 처방 선택 시 구성 약재 로드
$('#compoundFormula').on('change', function() {
const formulaId = $(this).val();
if (!formulaId) {
$('#compoundIngredients').empty();
return;
}
$.get(`/api/formulas/${formulaId}/ingredients`, function(response) {
if (response.success) {
$('#compoundIngredients').empty();
response.data.forEach(ing => {
const cheopTotal = parseFloat($('#cheopTotal').val()) || 0;
const totalGrams = ing.grams_per_cheop * cheopTotal;
$('#compoundIngredients').append(`
${ing.herb_name}
${totalGrams.toFixed(1)}
확인중...
`);
});
// 재고 확인
checkStockForCompound();
// 용량 변경 이벤트
$('.grams-per-cheop').on('input', updateIngredientTotals);
// 삭제 버튼 이벤트
$('.remove-compound-ingredient').on('click', function() {
$(this).closest('tr').remove();
});
}
});
});
// 약재별 총 용량 업데이트
function updateIngredientTotals() {
const cheopTotal = parseFloat($('#cheopTotal').val()) || 0;
$('#compoundIngredients tr').each(function() {
const gramsPerCheop = parseFloat($(this).find('.grams-per-cheop').val()) || 0;
const totalGrams = gramsPerCheop * cheopTotal;
$(this).find('.total-grams').text(totalGrams.toFixed(1));
});
checkStockForCompound();
}
// 재고 확인
function checkStockForCompound() {
$('#compoundIngredients tr').each(function() {
const herbId = $(this).data('herb-id');
const totalGrams = parseFloat($(this).find('.total-grams').text()) || 0;
const $stockStatus = $(this).find('.stock-status');
// TODO: API 호출로 실제 재고 확인
$stockStatus.text('재고 확인 필요');
});
}
// 조제 약재 추가
$('#addIngredientBtn').on('click', function() {
const newRow = $(`
약재 선택
0.0
-
`);
$('#compoundIngredients').append(newRow);
// 약재 목록 로드
loadHerbsForSelect(newRow.find('.herb-select-compound'));
// 이벤트 바인딩
newRow.find('.grams-per-cheop').on('input', updateIngredientTotals);
newRow.find('.remove-compound-ingredient').on('click', function() {
$(this).closest('tr').remove();
});
newRow.find('.herb-select-compound').on('change', function() {
const herbId = $(this).val();
$(this).closest('tr').attr('data-herb-id', herbId);
updateIngredientTotals();
});
});
// 조제 실행
$('#compoundEntryForm').on('submit', function(e) {
e.preventDefault();
const ingredients = [];
$('#compoundIngredients tr').each(function() {
const herbId = $(this).data('herb-id');
const gramsPerCheop = parseFloat($(this).find('.grams-per-cheop').val());
const totalGrams = parseFloat($(this).find('.total-grams').text());
if (herbId && gramsPerCheop) {
ingredients.push({
herb_item_id: parseInt(herbId),
grams_per_cheop: gramsPerCheop,
total_grams: totalGrams
});
}
});
const compoundData = {
patient_id: $('#compoundPatient').val() ? parseInt($('#compoundPatient').val()) : null,
formula_id: $('#compoundFormula').val() ? parseInt($('#compoundFormula').val()) : null,
je_count: parseFloat($('#jeCount').val()),
cheop_total: parseFloat($('#cheopTotal').val()),
pouch_total: parseFloat($('#pouchTotal').val()),
ingredients: ingredients
};
$.ajax({
url: '/api/compounds',
method: 'POST',
contentType: 'application/json',
data: JSON.stringify(compoundData),
success: function(response) {
if (response.success) {
alert(`조제가 완료되었습니다.\n원가: ${formatCurrency(response.total_cost)}`);
$('#compoundForm').hide();
loadCompounds();
}
},
error: function(xhr) {
alert('오류: ' + xhr.responseJSON.error);
}
});
});
// 조제 내역 로드
function loadCompounds() {
// TODO: 조제 내역 API 구현 필요
$('#compoundsList').html('조제 내역이 없습니다. ');
}
// 재고 현황 로드
function loadInventory() {
$.get('/api/inventory/summary', function(response) {
if (response.success) {
const tbody = $('#inventoryList');
tbody.empty();
response.data.forEach(item => {
tbody.append(`
${item.insurance_code || '-'}
${item.herb_name}
${item.total_quantity.toFixed(1)}
${item.lot_count}
${item.avg_price ? formatCurrency(item.avg_price) : '-'}
${formatCurrency(item.total_value)}
`);
});
}
});
}
// 약재 목록 로드
function loadHerbs() {
$.get('/api/herbs', function(response) {
if (response.success) {
const tbody = $('#herbsList');
tbody.empty();
response.data.forEach(herb => {
tbody.append(`
${herb.insurance_code || '-'}
${herb.herb_name}
${herb.specification || '-'}
${herb.current_stock ? herb.current_stock.toFixed(1) + 'g' : '0g'}
`);
});
}
});
}
// 입고장 목록 로드
function loadPurchaseReceipts() {
const startDate = $('#purchaseStartDate').val();
const endDate = $('#purchaseEndDate').val();
const supplierId = $('#purchaseSupplier').val();
let url = '/api/purchase-receipts?';
if (startDate) url += `start_date=${startDate}&`;
if (endDate) url += `end_date=${endDate}&`;
if (supplierId) url += `supplier_id=${supplierId}`;
$.get(url, function(response) {
if (response.success) {
const tbody = $('#purchaseReceiptsList');
tbody.empty();
if (response.data.length === 0) {
tbody.append('입고장이 없습니다. ');
return;
}
response.data.forEach(receipt => {
tbody.append(`
${receipt.receipt_date}
${receipt.supplier_name}
${receipt.line_count}개
${receipt.total_quantity ? receipt.total_quantity.toLocaleString() + 'g' : '-'}
${receipt.total_amount ? formatCurrency(receipt.total_amount) : '-'}
${receipt.source_file || '-'}
상세
`);
});
// 이벤트 바인딩
$('.view-receipt').on('click', function() {
const receiptId = $(this).data('id');
viewReceiptDetail(receiptId);
});
$('.delete-receipt').on('click', function() {
const receiptId = $(this).data('id');
if (confirm('정말 이 입고장을 삭제하시겠습니까? 사용되지 않은 재고만 삭제 가능합니다.')) {
deleteReceipt(receiptId);
}
});
}
});
}
// 입고장 상세 보기
function viewReceiptDetail(receiptId) {
$.get(`/api/purchase-receipts/${receiptId}`, function(response) {
if (response.success) {
const data = response.data;
let linesHtml = '';
data.lines.forEach(line => {
linesHtml += `
${line.herb_name}
${line.insurance_code || '-'}
${line.origin_country || '-'}
${line.quantity_g}g
${formatCurrency(line.unit_price_per_g)}
${formatCurrency(line.line_total)}
${line.current_stock}g
`;
});
const modalHtml = `
입고일: ${data.receipt_date}
공급업체: ${data.supplier_name}
총 금액: ${formatCurrency(data.total_amount)}
약재명
보험코드
원산지
수량
단가
금액
현재고
${linesHtml}
`;
// 기존 모달 제거
$('#receiptDetailModal').remove();
$('body').append(modalHtml);
$('#receiptDetailModal').modal('show');
}
});
}
// 입고장 삭제
function deleteReceipt(receiptId) {
$.ajax({
url: `/api/purchase-receipts/${receiptId}`,
method: 'DELETE',
success: function(response) {
if (response.success) {
alert(response.message);
loadPurchaseReceipts();
}
},
error: function(xhr) {
alert('오류: ' + xhr.responseJSON.error);
}
});
}
// 입고장 조회 버튼
$('#searchPurchaseBtn').on('click', function() {
loadPurchaseReceipts();
});
// 입고장 업로드
$('#purchaseUploadForm').on('submit', function(e) {
e.preventDefault();
const formData = new FormData();
const fileInput = $('#purchaseFile')[0];
if (fileInput.files.length === 0) {
alert('파일을 선택해주세요.');
return;
}
formData.append('file', fileInput.files[0]);
$('#uploadResult').html('업로드 중...
');
$.ajax({
url: '/api/upload/purchase',
method: 'POST',
data: formData,
processData: false,
contentType: false,
success: function(response) {
if (response.success) {
let summaryHtml = '';
if (response.summary) {
summaryHtml = `
형식: ${response.summary.format}
처리: ${response.summary.processed_rows}개 라인
품목: ${response.summary.total_items}종
수량: ${response.summary.total_quantity}
금액: ${response.summary.total_amount}
`;
}
$('#uploadResult').html(
`
${response.message}
${summaryHtml}
`
);
$('#purchaseUploadForm')[0].reset();
// 입고장 목록 새로고침
loadPurchaseReceipts();
}
},
error: function(xhr) {
$('#uploadResult').html(
`
오류: ${xhr.responseJSON.error}
`
);
}
});
});
// 검색 기능
$('#patientSearch').on('keyup', function() {
const value = $(this).val().toLowerCase();
$('#patientsList tr').filter(function() {
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1);
});
});
$('#inventorySearch').on('keyup', function() {
const value = $(this).val().toLowerCase();
$('#inventoryList tr').filter(function() {
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1);
});
});
// 헬퍼 함수들
function loadPatientsForSelect() {
$.get('/api/patients', function(response) {
if (response.success) {
const select = $('#compoundPatient');
select.empty().append('환자를 선택하세요 ');
response.data.forEach(patient => {
select.append(`${patient.name} (${patient.phone}) `);
});
}
});
}
function loadFormulasForSelect() {
$.get('/api/formulas', function(response) {
if (response.success) {
const select = $('#compoundFormula');
select.empty().append('처방을 선택하세요 ');
response.data.forEach(formula => {
select.append(`${formula.formula_name} `);
});
}
});
}
function loadHerbsForSelect(selectElement) {
$.get('/api/herbs', function(response) {
if (response.success) {
selectElement.empty().append('약재 선택 ');
response.data.forEach(herb => {
selectElement.append(`${herb.herb_name} `);
});
}
});
}
function formatCurrency(amount) {
if (amount === null || amount === undefined) return '0원';
return new Intl.NumberFormat('ko-KR', {
style: 'currency',
currency: 'KRW'
}).format(amount);
}
});