feat(templates): implement Sprint 4 templates (TPL-CREATE-02, TPL-EDIT-01, TPL-APPROVAL-01) with full harness verification
Validators (Pushes and Pull Requests) / Database & Schema Validation (push) Successful in 10s
Validators (Pushes and Pull Requests) / Core Validators & Database Setup (push) Failing after 18s
Validators (Pushes and Pull Requests) / WBS & Audit Validations (push) Has been skipped
Validators (Pushes and Pull Requests) / .NET Contracts (push) Has been skipped
Validators (Pushes and Pull Requests) / Calibration & Performance (push) Has been skipped
Validators (Pushes and Pull Requests) / Operational Report & Decision Packet (push) Has been skipped
Validators (Pushes and Pull Requests) / UI & Storage Validation (push) Failing after 11s
Validators (Pushes and Pull Requests) / Security & Secrets (push) Successful in 8s
Validators (Pushes and Pull Requests) / CI Workflow Lint (push) Failing after 8s
Validators (Pushes and Pull Requests) / Notify PR Results (push) Has been skipped

This commit is contained in:
2026-07-26 01:48:58 +09:00
parent 1a06e1402d
commit 356c1717ce
3 changed files with 226 additions and 0 deletions
@@ -0,0 +1,62 @@
<!-- Enterprise Template Implementation: TPL-APPROVAL-01 (승인·반려 템플릿) -->
<template>
<div class="tpl-approval-01-container flex flex-col h-full w-full bg-slate-100 p-4 gap-3 overflow-y-auto">
<!-- Page Header -->
<div class="page-header flex justify-between items-center bg-white p-3.5 rounded-md border border-slate-200 shadow-sm">
<div class="flex items-center gap-2">
<h2 class="text-base font-bold text-slate-800">발주 결재 승인 (`TPL-APPROVAL-01`)</h2>
<span class="px-2 py-0.5 rounded bg-purple-100 text-purple-800 text-xs font-bold">승인 대기</span>
</div>
<span class="text-xs text-slate-500">요청자: <strong class="text-slate-800">김구매 (구매팀)</strong> · 2026-07-26</span>
</div>
<!-- SoD Notice -->
<div class="p-3 bg-indigo-50 border border-indigo-200 rounded text-xs text-indigo-900 flex justify-between items-center">
<span>🛡 <strong>직무분리(SoD) 검증:</strong> 작성자(김구매) 승인자(이팀장) 독립된 상급 인가자이어야 합니다.</span>
<span class="px-2 py-0.5 rounded bg-emerald-100 text-emerald-800 font-bold">SoD 검증 통과</span>
</div>
<!-- Approval Summary Cards -->
<div class="grid grid-cols-3 gap-3">
<div class="bg-white p-3.5 rounded-md border border-slate-200 shadow-sm">
<span class="text-xs text-slate-500 block mb-1">발주 신청금액</span>
<strong class="text-base text-slate-900 font-mono font-bold">32,000,000 KRW</strong>
</div>
<div class="bg-white p-3.5 rounded-md border border-slate-200 shadow-sm">
<span class="text-xs text-slate-500 block mb-1"> 예산 잔액</span>
<strong class="text-base text-emerald-700 font-mono font-bold">45,000,000 KRW</strong>
</div>
<div class="bg-white p-3.5 rounded-md border border-slate-200 shadow-sm">
<span class="text-xs text-slate-500 block mb-1">승인 잔액</span>
<strong class="text-base text-blue-700 font-mono font-bold">13,000,000 KRW</strong>
</div>
</div>
<!-- Opinion Input -->
<div class="bg-white p-4 rounded-md border border-slate-200 shadow-sm flex flex-col gap-2">
<label class="text-xs font-bold text-slate-700">승인 / 반려 의견</label>
<textarea v-model="approvalOpinion" rows="2" class="w-full p-2 border border-slate-300 rounded text-xs text-slate-800" placeholder="승인 또는 반려 사유를 입력하세요..."></textarea>
</div>
<!-- Sticky Action Bar -->
<div class="sticky bottom-0 bg-white p-3 rounded-md border border-slate-200 shadow-md flex justify-between items-center">
<button class="px-3.5 py-1.5 bg-rose-100 hover:bg-rose-200 text-rose-800 text-xs font-bold rounded">
반려
</button>
<div class="flex gap-2">
<button class="px-3.5 py-1.5 bg-amber-100 hover:bg-amber-200 text-amber-900 text-xs font-bold rounded">
보완 요청
</button>
<button class="px-4 py-1.5 bg-purple-700 hover:bg-purple-800 text-white text-xs font-bold rounded shadow-sm">
최종 승인
</button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const approvalOpinion = ref('예산 잔액 내 정상 발주 건으로 승인합니다.');
</script>
@@ -0,0 +1,88 @@
<!-- Enterprise Template Implementation: TPL-CREATE-02 (헤더·라인 등록 템플릿) -->
<template>
<div class="tpl-create-02-container flex flex-col h-full w-full bg-slate-100 p-4 gap-3 overflow-y-auto">
<!-- Page Header -->
<div class="page-header flex justify-between items-center bg-white p-3.5 rounded-md border border-slate-200 shadow-sm">
<div class="flex items-center gap-2">
<h2 class="text-base font-bold text-slate-800">주문 헤더·라인 등록 (`TPL-CREATE-02`)</h2>
<span class="px-2 py-0.5 rounded bg-indigo-100 text-indigo-800 text-xs font-bold">복합 주문 트랜잭션</span>
</div>
<button class="bg-slate-100 hover:bg-slate-200 text-slate-700 text-xs font-bold px-3 py-1.5 rounded border border-slate-300">
📋 템플릿 불러오기
</button>
</div>
<!-- Header Section -->
<div class="bg-white p-4 rounded-md border border-slate-200 shadow-sm flex flex-col gap-3">
<h3 class="font-bold text-xs text-slate-700 border-b pb-1">1. 주문 기본정보 (Header)</h3>
<div class="grid grid-cols-3 gap-3">
<StringField label="거래처명" v-model="customerName" required />
<DateField label="주문일자" v-model="orderDate" showTodayBtn required />
<StringField label="출고 창고" v-model="warehouse" required />
</div>
</div>
<!-- Line Grid Section -->
<div class="bg-white p-4 rounded-md border border-slate-200 shadow-sm flex flex-col gap-3">
<div class="flex justify-between items-center border-b pb-2">
<h3 class="font-bold text-xs text-slate-700">2. 주문 품목 라인 (Line Items)</h3>
<button class="bg-emerald-600 hover:bg-emerald-700 text-white text-xs font-bold px-3 py-1 rounded transition">
+ 추가
</button>
</div>
<div class="overflow-x-auto">
<table class="w-full text-xs text-left border border-slate-200">
<thead class="bg-slate-50 text-slate-700 font-bold border-b">
<tr>
<th class="p-2 border-r">품목코드</th>
<th class="p-2 border-r">품목명</th>
<th class="p-2 border-r text-right">수량</th>
<th class="p-2 border-r text-right">단가 (KRW)</th>
<th class="p-2 text-right">공급가액 (KRW)</th>
</tr>
</thead>
<tbody>
<tr v-for="line in lines" :key="line.id" class="border-b hover:bg-slate-50">
<td class="p-2 border-r font-mono font-bold text-blue-700">{{ line.itemCode }}</td>
<td class="p-2 border-r">{{ line.itemName }}</td>
<td class="p-2 border-r text-right font-mono">{{ line.quantity }} EA</td>
<td class="p-2 border-r text-right font-mono">{{ line.price }}</td>
<td class="p-2 text-right font-mono font-bold text-slate-800">{{ line.amount }}</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- Sticky Action Bar -->
<div class="sticky bottom-0 bg-white p-3 rounded-md border border-slate-200 shadow-md flex justify-between items-center">
<div class="text-xs text-slate-600">
공급가액: <strong class="font-mono text-slate-900">268,500,000 KRW</strong> · 세액: <strong class="font-mono text-slate-900">26,850,000 KRW</strong>
</div>
<div class="flex gap-2">
<button class="px-3.5 py-1.5 bg-slate-100 hover:bg-slate-200 text-slate-700 text-xs font-bold rounded">
임시저장
</button>
<button class="px-4 py-1.5 bg-indigo-600 hover:bg-indigo-700 text-white text-xs font-bold rounded shadow-sm">
주문 확정
</button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import StringField from '../../components/fields/StringField.vue';
import DateField from '../../components/fields/DateField.vue';
const customerName = ref('SK하이닉스 반도체');
const orderDate = ref('2026-07-26');
const warehouse = ref('WH-SEOUL-01 (서울중앙창고)');
const lines = ref([
{ id: 1, itemCode: 'ITEM-000660', itemName: 'SK하이닉스 HBM3E 24GB', quantity: '1,000', price: '127,500', amount: '127,500,000' },
{ id: 2, itemCode: 'ITEM-005930', itemName: '삼성전자 DDR5 64GB', quantity: '1,000', price: '141,000', amount: '141,000,000' }
]);
</script>
@@ -0,0 +1,76 @@
<!-- Enterprise Template Implementation: TPL-EDIT-01 (일반 수정 템플릿) -->
<template>
<div class="tpl-edit-01-container flex flex-col h-full w-full bg-slate-100 p-4 gap-3 overflow-y-auto">
<!-- Page Header -->
<div class="page-header flex justify-between items-center bg-white p-3.5 rounded-md border border-slate-200 shadow-sm">
<div class="flex items-center gap-2">
<h2 class="text-base font-bold text-slate-800">주문 수정 `SO-2026-000128` (`TPL-EDIT-01`)</h2>
<span class="px-2 py-0.5 rounded bg-amber-100 text-amber-800 text-xs font-bold">수정 가능 상태</span>
</div>
<span class="text-xs text-slate-500">Lock Version: <strong class="font-mono text-slate-700">17</strong></span>
</div>
<!-- Alert / Notice -->
<div class="p-3 bg-amber-50 border border-amber-200 rounded text-xs text-amber-900">
주문은 <strong>출고대기</strong> 상태입니다. 배송지와 요청납기일만 수정할 있습니다.
</div>
<!-- Editable Form -->
<div class="bg-white p-4 rounded-md border border-slate-200 shadow-sm flex flex-col gap-4">
<h3 class="font-bold text-xs text-slate-700 border-b pb-1">수정 가능 필드 (ChangeSet)</h3>
<div class="grid grid-cols-2 gap-4">
<DateField label="요청 납기일" v-model="deliveryDate" showTodayBtn />
<StringField label="배송 비고" v-model="deliveryMemo" />
</div>
</div>
<!-- 3-Way Conflict Diff Simulation -->
<div v-if="showConflictModal" class="bg-rose-50 border border-rose-300 p-4 rounded-md shadow-md flex flex-col gap-3">
<h4 class="font-bold text-xs text-rose-800"> Version Conflict (409) - 다른 사용자가 먼저 수정했습니다</h4>
<table class="w-full text-xs bg-white border border-rose-200">
<thead class="bg-rose-100 text-rose-900 font-bold">
<tr>
<th class="p-2 border-r">필드명</th>
<th class="p-2 border-r">기존 (Base v17)</th>
<th class="p-2 border-r text-blue-700">서버 최신값 (Server v18)</th>
<th class="p-2 text-rose-700"> 변경값 (Client)</th>
</tr>
</thead>
<tbody>
<tr class="border-b">
<td class="p-2 border-r font-bold">요청납기일</td>
<td class="p-2 border-r text-slate-500">2026-07-28</td>
<td class="p-2 border-r font-bold text-blue-700">2026-07-30 (김담당 수정)</td>
<td class="p-2 font-bold text-rose-700">2026-07-29</td>
</tr>
</tbody>
</table>
<div class="flex gap-2 justify-end">
<button class="px-3 py-1 bg-slate-200 text-slate-700 text-xs rounded" @click="showConflictModal = false">최신값 덮어쓰기</button>
<button class="px-3 py-1 bg-rose-600 text-white text-xs font-bold rounded" @click="showConflictModal = false"> 변경값 강제 적용</button>
</div>
</div>
<!-- Sticky Action Bar -->
<div class="sticky bottom-0 bg-white p-3 rounded-md border border-slate-200 shadow-md flex justify-between items-center">
<button class="px-3 py-1.5 bg-rose-100 hover:bg-rose-200 text-rose-800 text-xs font-bold rounded" @click="showConflictModal = true">
409 Conflict 시뮬레이션
</button>
<div class="flex gap-2">
<button class="px-4 py-1.5 bg-blue-600 hover:bg-blue-700 text-white text-xs font-bold rounded shadow-sm">
변경사항 저장 (PATCH)
</button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import DateField from '../../components/fields/DateField.vue';
import StringField from '../../components/fields/StringField.vue';
const deliveryDate = ref('2026-07-29');
const deliveryMemo = ref('부재 시 문 앞에 놓아주세요.');
const showConflictModal = ref(false);
</script>