fix: 조제 관리 약재 추가 시 마스터 약재명 표시 및 2단계 선택 구조 개선
- 약재 추가 드롭다운에서 제품명 대신 마스터 약재명 표시 - /api/herbs/masters 엔드포인트 사용하여 ingredient_code 기반 약재 목록 로드 - /api/herbs/by-ingredient/<code> 엔드포인트 추가 (제품 목록 조회) - 2단계 선택 구조: 약재(마스터) → 제품 → 원산지/롯트 - 기존 처방 약재와 새로 추가하는 약재의 테이블 구조 통일 (6칼럼) - 원산지 선택 칼럼에 제품/원산지 드롭다운 함께 표시 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
112
static/app.js
112
static/app.js
@@ -617,15 +617,15 @@ $(document).ready(function() {
|
||||
value="${ing.grams_per_cheop}" min="0.1" step="0.1">
|
||||
</td>
|
||||
<td class="total-grams">${totalGrams.toFixed(1)}</td>
|
||||
<td class="product-select-cell">
|
||||
<select class="form-control form-control-sm product-select" ${ing.available_products.length === 0 ? 'disabled' : ''}>
|
||||
${productOptions}
|
||||
</select>
|
||||
</td>
|
||||
<td class="origin-select-cell">
|
||||
<select class="form-control form-control-sm origin-select" disabled>
|
||||
<option value="">제품 먼저 선택</option>
|
||||
</select>
|
||||
<div class="d-flex gap-1">
|
||||
<select class="form-control form-control-sm product-select" style="flex: 1;" ${ing.available_products.length === 0 ? 'disabled' : ''}>
|
||||
${productOptions}
|
||||
</select>
|
||||
<select class="form-control form-control-sm origin-select" style="flex: 1;" disabled>
|
||||
<option value="">제품 먼저 선택</option>
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
<td class="stock-status">대기중</td>
|
||||
<td>
|
||||
@@ -722,7 +722,7 @@ $(document).ready(function() {
|
||||
// 빈 약재 행 추가 함수
|
||||
function addEmptyIngredientRow() {
|
||||
const newRow = $(`
|
||||
<tr>
|
||||
<tr data-ingredient-code="" data-herb-id="">
|
||||
<td>
|
||||
<select class="form-control form-control-sm herb-select-compound">
|
||||
<option value="">약재 선택</option>
|
||||
@@ -734,9 +734,14 @@ $(document).ready(function() {
|
||||
</td>
|
||||
<td class="total-grams">0.0</td>
|
||||
<td class="origin-select-cell">
|
||||
<select class="form-control form-control-sm origin-select" disabled>
|
||||
<option value="">약재 선택 후 표시</option>
|
||||
</select>
|
||||
<div class="d-flex gap-1">
|
||||
<select class="form-control form-control-sm product-select" style="flex: 1;" disabled>
|
||||
<option value="">약재 선택 후 표시</option>
|
||||
</select>
|
||||
<select class="form-control form-control-sm origin-select" style="flex: 1;" disabled>
|
||||
<option value="">제품 선택 후 표시</option>
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
<td class="stock-status">-</td>
|
||||
<td>
|
||||
@@ -750,18 +755,53 @@ $(document).ready(function() {
|
||||
$('#compoundIngredients').append(newRow);
|
||||
|
||||
// 약재 목록 로드
|
||||
loadHerbsForSelect(newRow.find('.herb-select-compound'));
|
||||
const herbSelect = newRow.find('.herb-select-compound');
|
||||
loadHerbsForSelect(herbSelect);
|
||||
|
||||
// 약재 선택 시 원산지 옵션 로드
|
||||
// 약재(마스터) 선택 시 제품 옵션 로드
|
||||
newRow.find('.herb-select-compound').on('change', function() {
|
||||
const herbId = $(this).val();
|
||||
if (herbId) {
|
||||
const ingredientCode = $(this).val();
|
||||
const herbName = $(this).find('option:selected').data('herb-name');
|
||||
if (ingredientCode) {
|
||||
const row = $(this).closest('tr');
|
||||
row.attr('data-ingredient-code', ingredientCode);
|
||||
|
||||
// 제품 목록 로드
|
||||
loadProductOptions(row, ingredientCode, herbName);
|
||||
|
||||
// 제품 선택 활성화
|
||||
row.find('.product-select').prop('disabled', false);
|
||||
|
||||
// 원산지 선택 초기화 및 비활성화
|
||||
row.find('.origin-select').empty().append('<option value="">제품 선택 후 표시</option>').prop('disabled', true);
|
||||
} else {
|
||||
const row = $(this).closest('tr');
|
||||
row.attr('data-ingredient-code', '');
|
||||
row.attr('data-herb-id', '');
|
||||
row.find('.product-select').empty().append('<option value="">약재 선택 후 표시</option>').prop('disabled', true);
|
||||
row.find('.origin-select').empty().append('<option value="">제품 선택 후 표시</option>').prop('disabled', true);
|
||||
}
|
||||
});
|
||||
|
||||
// 제품 선택 이벤트
|
||||
newRow.find('.product-select').on('change', function() {
|
||||
const herbId = $(this).val();
|
||||
const row = $(this).closest('tr');
|
||||
|
||||
if (herbId) {
|
||||
row.attr('data-herb-id', herbId);
|
||||
|
||||
// 원산지 선택 활성화
|
||||
row.find('.origin-select').prop('disabled', false);
|
||||
|
||||
// 원산지 옵션 로드
|
||||
const cheopTotal = parseFloat($('#cheopTotal').val()) || 0;
|
||||
const gramsPerCheop = parseFloat(row.find('.grams-per-cheop').val()) || 0;
|
||||
const totalGrams = gramsPerCheop * cheopTotal;
|
||||
loadOriginOptions(herbId, totalGrams);
|
||||
} else {
|
||||
row.attr('data-herb-id', '');
|
||||
row.find('.origin-select').empty().append('<option value="">제품 선택 후 표시</option>').prop('disabled', true);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1599,14 +1639,48 @@ $(document).ready(function() {
|
||||
}
|
||||
|
||||
function loadHerbsForSelect(selectElement) {
|
||||
$.get('/api/herbs', function(response) {
|
||||
$.get('/api/herbs/masters', function(response) {
|
||||
if (response.success) {
|
||||
selectElement.empty().append('<option value="">약재 선택</option>');
|
||||
|
||||
response.data.forEach(herb => {
|
||||
selectElement.append(`<option value="${herb.herb_item_id}">${herb.herb_name}</option>`);
|
||||
// 재고가 있는 약재만 필터링하여 표시
|
||||
const herbsWithStock = response.data.filter(herb => herb.has_stock === 1);
|
||||
|
||||
herbsWithStock.forEach(herb => {
|
||||
// ingredient_code를 value로 사용하고, 한글명(한자명) 형식으로 표시
|
||||
let displayName = herb.herb_name;
|
||||
if (herb.herb_name_hanja) {
|
||||
displayName += ` (${herb.herb_name_hanja})`;
|
||||
}
|
||||
selectElement.append(`<option value="${herb.ingredient_code}" data-herb-name="${herb.herb_name}">${displayName}</option>`);
|
||||
});
|
||||
}
|
||||
}).fail(function(error) {
|
||||
console.error('Failed to load herbs:', error);
|
||||
});
|
||||
}
|
||||
|
||||
// ingredient_code 기반으로 제품 옵션 로드
|
||||
function loadProductOptions(row, ingredientCode, herbName) {
|
||||
$.get(`/api/herbs/by-ingredient/${ingredientCode}`, function(response) {
|
||||
if (response.success) {
|
||||
const productSelect = row.find('.product-select');
|
||||
productSelect.empty();
|
||||
|
||||
if (response.data.length === 0) {
|
||||
productSelect.append('<option value="">재고 없음</option>');
|
||||
productSelect.prop('disabled', true);
|
||||
} else {
|
||||
productSelect.append('<option value="">제품 선택</option>');
|
||||
response.data.forEach(product => {
|
||||
const stockInfo = product.stock_quantity > 0 ? `(재고: ${product.stock_quantity.toFixed(1)}g)` : '(재고 없음)';
|
||||
productSelect.append(`<option value="${product.herb_item_id}" ${product.stock_quantity === 0 ? 'disabled' : ''}>${product.company_name} ${stockInfo}</option>`);
|
||||
});
|
||||
productSelect.prop('disabled', false);
|
||||
}
|
||||
}
|
||||
}).fail(function() {
|
||||
console.error(`Failed to load products for ingredient code: ${ingredientCode}`);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user