feat: [approval] 결재선 요약 카드 가로 2분할 (결재선 | 참조선 분리 표시)

- 기안 작성 페이지 결재선 요약 영역을 좌우 2분할 레이아웃으로 변경
- 좌측: 결재선 (결재/합의 카드), 우측: 참조선 (참조 카드)
- 참조자가 없으면 결재선만 전체 너비로 표시
This commit is contained in:
김보곤
2026-03-07 20:57:57 +09:00
parent a032b1a11e
commit 6c683c7d4e

View File

@@ -660,33 +660,36 @@ function updateApprovalLineSummary() {
const editorEl = document.getElementById('approval-line-editor');
if (!editorEl || !editorEl._x_dataStack) return;
const steps = editorEl._x_dataStack[0].steps;
const alpineData = editorEl._x_dataStack[0];
const steps = alpineData.steps;
const references = alpineData.references || [];
const summaryEl = document.getElementById('approval-line-summary');
if (summarySortableInstance) { summarySortableInstance.destroy(); summarySortableInstance = null; }
if (!steps || steps.length === 0) {
if ((!steps || steps.length === 0) && references.length === 0) {
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 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 typeCounters = { approval: 0, agreement: 0 };
const typeLabels = { approval: '결재', agreement: '합의' };
const typeBg = { approval: 'bg-blue-50 border-blue-100', agreement: 'bg-green-50 border-green-100' };
const typeLabelColor = { approval: 'text-blue-600', agreement: 'text-green-600' };
const cards = [];
// 결재선 카드
const approvalCards = [];
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 bg = typeBg[s.step_type] || 'bg-blue-50 border-blue-100';
var labelColor = typeLabelColor[s.step_type] || 'text-blue-600';
var stepLabel = count + '차 ' + label;
var position = s.position || '';
cards.push(
approvalCards.push(
'<div class="step-card text-center px-3 py-2 rounded-lg border ' + bg + '" data-index="' + i + '" style="min-width: 72px;">' +
'<div class="text-xs font-medium ' + labelColor + '">' + escapeHtml(stepLabel) + '</div>' +
(position ? '<div class="text-xs text-gray-400 mt-0.5">' + escapeHtml(position) + '</div>' : '') +
@@ -695,9 +698,45 @@ function updateApprovalLineSummary() {
);
});
// 참조선 카드
const refCards = [];
references.forEach(function(r) {
var position = r.position || '';
refCards.push(
'<div class="text-center px-3 py-2 rounded-lg border bg-gray-50 border-gray-200" style="min-width: 72px;">' +
'<div class="text-xs font-medium text-gray-500">참조</div>' +
(position ? '<div class="text-xs text-gray-400 mt-0.5">' + escapeHtml(position) + '</div>' : '') +
'<div class="text-sm font-semibold text-gray-800 mt-0.5">' + escapeHtml(r.user_name) + '</div>' +
'</div>'
);
});
// 가로 2분할 레이아웃
var html = '<div class="grid gap-3" style="grid-template-columns: ' + (refCards.length > 0 ? '1fr 1fr' : '1fr') + ';">';
// 좌측: 결재선
html += '<div>';
html += '<div class="flex items-center gap-1.5 mb-2"><svg class="w-3.5 h-3.5 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/></svg><span class="text-xs font-semibold text-gray-600">결재선</span><span class="text-xs text-gray-400">(' + steps.length + '명)</span></div>';
if (approvalCards.length > 0) {
html += '<div id="summary-sortable" class="flex flex-wrap gap-2">' + approvalCards.join('') + '</div>';
if (steps.length > 1) html += '<div class="text-xs text-gray-400 mt-1.5">드래그하여 순서 변경</div>';
} else {
html += '<div class="text-xs text-gray-400 py-2">결재자가 없습니다</div>';
}
html += '</div>';
// 우측: 참조선
if (refCards.length > 0) {
html += '<div class="border-l border-gray-200 pl-3">';
html += '<div class="flex items-center gap-1.5 mb-2"><svg class="w-3.5 h-3.5 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"/><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z"/></svg><span class="text-xs font-semibold text-gray-600">참조</span><span class="text-xs text-gray-400">(' + references.length + '명)</span></div>';
html += '<div class="flex flex-wrap gap-2">' + refCards.join('') + '</div>';
html += '</div>';
}
html += '</div>';
summaryEl.className = 'p-3 bg-gray-50 rounded-lg border border-gray-200';
summaryEl.innerHTML = '<div id="summary-sortable" class="flex flex-wrap items-center">' + cards.join('') + '</div>' +
(steps.length > 1 ? '<div class="text-xs text-gray-400 mt-2">드래그하여 순서를 변경할 수 있습니다</div>' : '');
summaryEl.innerHTML = html;
initSummarySortable();
}