fix: [approvals] 결재선 요약을 제목 아래로 이동, 카드형 표시

- 결재선 요약 바를 본문 아래에서 제목 아래로 위치 변경
- 표시 형식을 '1차 결재 / 직책 / 이름' 카드형으로 변경
- 결재/합의/참조별 색상 구분 (파랑/초록/회색)
This commit is contained in:
김보곤
2026-02-28 14:48:16 +09:00
parent f5090b48b0
commit 55865155de
2 changed files with 86 additions and 40 deletions

View File

@@ -31,6 +31,20 @@
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
{{-- 결재선 --}}
<div class="mb-4">
<div class="flex items-center justify-between mb-1">
<label class="block text-sm font-medium text-gray-700">결재선</label>
<button type="button" onclick="openApprovalLineModal()"
class="px-3 py-1.5 bg-blue-50 text-blue-600 hover:bg-blue-100 rounded-lg text-xs font-medium transition">
결재선 설정
</button>
</div>
<div id="approval-line-summary" class="p-3 bg-gray-50 rounded-lg border border-gray-200 flex items-center">
<span class="text-sm text-gray-400">결재선이 설정되지 않았습니다.</span>
</div>
</div>
{{-- 긴급 여부 --}}
<div class="mb-4">
<label class="inline-flex items-center gap-2 cursor-pointer">
@@ -55,20 +69,6 @@ class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-
<div id="quill-container" style="display: none; min-height: 300px;"></div>
</div>
{{-- 결재선 요약 --}}
<div class="border-t pt-4 mt-4">
<div class="flex items-center justify-between mb-2">
<label class="text-sm font-medium text-gray-700">결재선</label>
<button type="button" onclick="openApprovalLineModal()"
class="px-3 py-1.5 bg-blue-50 text-blue-600 hover:bg-blue-100 rounded-lg text-xs font-medium transition">
결재선 설정
</button>
</div>
<div id="approval-line-summary" class="text-sm text-gray-400">
결재선이 설정되지 않았습니다.
</div>
</div>
{{-- 액션 버튼 --}}
<div class="border-t pt-4 mt-4 flex gap-2 justify-end">
<button onclick="saveApproval('draft')"
@@ -201,18 +201,41 @@ function updateApprovalLineSummary() {
const summaryEl = document.getElementById('approval-line-summary');
if (!steps || steps.length === 0) {
summaryEl.innerHTML = '<span class="text-gray-400">결재선이 설정되지 않았습니다.</span>';
summaryEl.className = 'p-3 bg-gray-50 rounded-lg border border-gray-200 flex items-center';
summaryEl.innerHTML = '<span class="text-sm text-gray-400">결재선이 설정되지 않았습니다.</span>';
return;
}
const typeCounters = { approval: 0, agreement: 0, reference: 0 };
const typeLabels = { approval: '결재', agreement: '합의', reference: '참조' };
const parts = steps.map(s => {
const label = typeLabels[s.step_type] || s.step_type;
return '<span class="inline-flex items-center gap-1"><strong class="text-gray-800">' + s.user_name + '</strong> <span class="text-gray-400 text-xs">(' + label + ')</span></span>';
const typeBg = { approval: 'bg-blue-50 border-blue-100', agreement: 'bg-green-50 border-green-100', reference: 'bg-gray-100 border-gray-200' };
const typeLabelColor = { approval: 'text-blue-600', agreement: 'text-green-600', reference: 'text-gray-500' };
const cards = [];
steps.forEach(function(s, i) {
typeCounters[s.step_type] = (typeCounters[s.step_type] || 0) + 1;
var count = typeCounters[s.step_type];
var label = typeLabels[s.step_type] || s.step_type;
var bg = typeBg[s.step_type] || typeBg.reference;
var labelColor = typeLabelColor[s.step_type] || typeLabelColor.reference;
var stepLabel = s.step_type === 'reference' ? label : count + '차 ' + label;
var position = s.position || '';
if (i > 0) {
cards.push('<span class="text-gray-300 flex items-center mx-1">&rarr;</span>');
}
cards.push(
'<div class="text-center px-3 py-2 rounded-lg border ' + bg + '" style="min-width: 72px;">' +
'<div class="text-xs font-medium ' + labelColor + '">' + stepLabel + '</div>' +
(position ? '<div class="text-xs text-gray-400 mt-0.5">' + position + '</div>' : '') +
'<div class="text-sm font-semibold text-gray-800 mt-0.5">' + s.user_name + '</div>' +
'</div>'
);
});
summaryEl.innerHTML = '<div class="flex flex-wrap items-center gap-1 text-sm">' +
parts.join('<span class="text-gray-300 mx-0.5">&rarr;</span>') + '</div>';
summaryEl.className = 'p-3 bg-gray-50 rounded-lg border border-gray-200';
summaryEl.innerHTML = '<div class="flex flex-wrap items-center gap-1">' + cards.join('') + '</div>';
}
document.addEventListener('keydown', function(e) {

View File

@@ -54,6 +54,20 @@
class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-blue-500">
</div>
{{-- 결재선 --}}
<div class="mb-4">
<div class="flex items-center justify-between mb-1">
<label class="block text-sm font-medium text-gray-700">결재선</label>
<button type="button" onclick="openApprovalLineModal()"
class="px-3 py-1.5 bg-blue-50 text-blue-600 hover:bg-blue-100 rounded-lg text-xs font-medium transition">
결재선 설정
</button>
</div>
<div id="approval-line-summary" class="p-3 bg-gray-50 rounded-lg border border-gray-200 flex items-center">
<span class="text-sm text-gray-400">결재선이 설정되지 않았습니다.</span>
</div>
</div>
<div class="mb-4">
<label class="inline-flex items-center gap-2 cursor-pointer">
<input type="checkbox" id="is_urgent" {{ $approval->is_urgent ? 'checked' : '' }}
@@ -77,20 +91,6 @@ class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:outline-
<div id="quill-container" style="display: none; min-height: 300px;"></div>
</div>
{{-- 결재선 요약 --}}
<div class="border-t pt-4 mt-4">
<div class="flex items-center justify-between mb-2">
<label class="text-sm font-medium text-gray-700">결재선</label>
<button type="button" onclick="openApprovalLineModal()"
class="px-3 py-1.5 bg-blue-50 text-blue-600 hover:bg-blue-100 rounded-lg text-xs font-medium transition">
결재선 설정
</button>
</div>
<div id="approval-line-summary" class="text-sm text-gray-400">
결재선이 설정되지 않았습니다.
</div>
</div>
{{-- 액션 버튼 --}}
<div class="border-t pt-4 mt-4 flex gap-2 justify-end">
<button onclick="updateApproval('save')"
@@ -235,18 +235,41 @@ function updateApprovalLineSummary() {
const summaryEl = document.getElementById('approval-line-summary');
if (!steps || steps.length === 0) {
summaryEl.innerHTML = '<span class="text-gray-400">결재선이 설정되지 않았습니다.</span>';
summaryEl.className = 'p-3 bg-gray-50 rounded-lg border border-gray-200 flex items-center';
summaryEl.innerHTML = '<span class="text-sm text-gray-400">결재선이 설정되지 않았습니다.</span>';
return;
}
const typeCounters = { approval: 0, agreement: 0, reference: 0 };
const typeLabels = { approval: '결재', agreement: '합의', reference: '참조' };
const parts = steps.map(s => {
const label = typeLabels[s.step_type] || s.step_type;
return '<span class="inline-flex items-center gap-1"><strong class="text-gray-800">' + s.user_name + '</strong> <span class="text-gray-400 text-xs">(' + label + ')</span></span>';
const typeBg = { approval: 'bg-blue-50 border-blue-100', agreement: 'bg-green-50 border-green-100', reference: 'bg-gray-100 border-gray-200' };
const typeLabelColor = { approval: 'text-blue-600', agreement: 'text-green-600', reference: 'text-gray-500' };
const cards = [];
steps.forEach(function(s, i) {
typeCounters[s.step_type] = (typeCounters[s.step_type] || 0) + 1;
var count = typeCounters[s.step_type];
var label = typeLabels[s.step_type] || s.step_type;
var bg = typeBg[s.step_type] || typeBg.reference;
var labelColor = typeLabelColor[s.step_type] || typeLabelColor.reference;
var stepLabel = s.step_type === 'reference' ? label : count + '차 ' + label;
var position = s.position || '';
if (i > 0) {
cards.push('<span class="text-gray-300 flex items-center mx-1">&rarr;</span>');
}
cards.push(
'<div class="text-center px-3 py-2 rounded-lg border ' + bg + '" style="min-width: 72px;">' +
'<div class="text-xs font-medium ' + labelColor + '">' + stepLabel + '</div>' +
(position ? '<div class="text-xs text-gray-400 mt-0.5">' + position + '</div>' : '') +
'<div class="text-sm font-semibold text-gray-800 mt-0.5">' + s.user_name + '</div>' +
'</div>'
);
});
summaryEl.innerHTML = '<div class="flex flex-wrap items-center gap-1 text-sm">' +
parts.join('<span class="text-gray-300 mx-0.5">&rarr;</span>') + '</div>';
summaryEl.className = 'p-3 bg-gray-50 rounded-lg border border-gray-200';
summaryEl.innerHTML = '<div class="flex flex-wrap items-center gap-1">' + cards.join('') + '</div>';
}
document.addEventListener('keydown', function(e) {