feat(comp): implement CodeField component with 300ms debounce validation and F2 popup support
Validators (Pushes and Pull Requests) / UI & Storage Validation (push) Failing after 11s
Validators (Pushes and Pull Requests) / Database & Schema Validation (push) Successful in 11s
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) / 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) / UI & Storage Validation (push) Failing after 11s
Validators (Pushes and Pull Requests) / Database & Schema Validation (push) Successful in 11s
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) / 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,77 @@
|
||||
<!-- Typed Field Component Layer: CodeField (WBS-COMP-2.4) -->
|
||||
<template>
|
||||
<div class="typed-code-field flex flex-col gap-1 w-full">
|
||||
<div class="flex justify-between items-center text-xs">
|
||||
<label class="font-bold text-slate-800">
|
||||
{{ label }} <span v-if="required" class="text-rose-600">*</span>
|
||||
</label>
|
||||
<span v-if="isValidating" class="text-[11px] text-blue-600 font-medium">⏳ 중복 검사 중...</span>
|
||||
<span v-else-if="validationStatus === 'VALID'" class="text-[11px] text-emerald-700 font-bold">✓ 사용 가능한 코드</span>
|
||||
<span v-else-if="validationStatus === 'INVALID'" class="text-[11px] text-rose-600 font-bold">🚨 이미 존재하는 코드</span>
|
||||
</div>
|
||||
|
||||
<div class="relative flex items-center">
|
||||
<input
|
||||
type="text"
|
||||
:value="modelValue"
|
||||
:placeholder="placeholder || 'CUST-001'"
|
||||
:readonly="readonly"
|
||||
:disabled="disabled"
|
||||
class="w-full h-9 px-3 pr-16 border border-slate-300 rounded font-mono text-xs text-slate-900 font-bold bg-white placeholder:text-slate-400 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 focus:outline-none disabled:bg-slate-100 disabled:text-slate-500 readonly:bg-slate-50 readonly:text-slate-700 uppercase"
|
||||
@input="handleInput"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
class="absolute right-1 top-1 bottom-1 px-2.5 bg-slate-800 hover:bg-slate-700 text-amber-300 font-mono text-[11px] font-bold rounded transition"
|
||||
@click="$emit('openPopup')"
|
||||
>
|
||||
F2
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
|
||||
const props = defineProps<{
|
||||
label: string;
|
||||
modelValue: string;
|
||||
placeholder?: string;
|
||||
required?: boolean;
|
||||
readonly?: boolean;
|
||||
disabled?: boolean;
|
||||
existingCodes?: string[];
|
||||
}>();
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'openPopup']);
|
||||
|
||||
const isValidating = ref(false);
|
||||
const validationStatus = ref<'NONE' | 'VALID' | 'INVALID'>('NONE');
|
||||
let debounceTimer: any = null;
|
||||
|
||||
const mockExistingCodes = props.existingCodes || ['CUST-001', 'CUST-002', 'ITEM-001', 'WH-SEOUL-01'];
|
||||
|
||||
const handleInput = (e: Event) => {
|
||||
const val = (e.target as HTMLInputElement).value.toUpperCase().trim();
|
||||
emit('update:modelValue', val);
|
||||
|
||||
if (!val) {
|
||||
validationStatus.value = 'NONE';
|
||||
isValidating.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
isValidating.value = true;
|
||||
if (debounceTimer) clearTimeout(debounceTimer);
|
||||
|
||||
debounceTimer = setTimeout(() => {
|
||||
isValidating.value = false;
|
||||
if (mockExistingCodes.includes(val)) {
|
||||
validationStatus.value = 'INVALID';
|
||||
} else {
|
||||
validationStatus.value = 'VALID';
|
||||
}
|
||||
}, 300);
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user