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
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:
@@ -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>
|
||||
Reference in New Issue
Block a user