feat: 업무 지시 필드별 인라인 검증 + 제출 버튼 상시 활성화

기존: 제목·담당자 미입력 시 '지시 보내기' 버튼이 비활성화(이유 안내 없음)
변경:
- 버튼 비활성화 해제(제출 중 중복 클릭 방지용 submitting 만 유지)
- 제출 시 validateForm 으로 검증 → 미입력 필드에 인라인 에러 표시
  · 제목: 빨강 placeholder + '업무 제목을 입력해 주세요.'
  · 담당자: combo 빨강 테두리 + '담당자를 1명 이상 지정해 주세요.'
- 해당 필드를 채우면 watch 로 에러 즉시 해제

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-21 11:29:36 +09:00
parent ae6af518dd
commit 9f66c6d0ec
+51 -5
View File
@@ -257,12 +257,28 @@ async function uploadPendingFiles(tid: number): Promise<number> {
// --- 제출 ---
const submitting = ref(false)
const canSubmit = computed(
() => !submitting.value && title.value.trim().length > 0 && assignees.value.length > 0,
// 필드별 인라인 검증 — 제목·담당자 필수. 입력하면 즉시 해제.
const titleError = ref(false)
const assigneeError = ref(false)
watch(title, (v) => {
if (v.trim().length > 0) titleError.value = false
})
watch(
assignees,
(v) => {
if (v.length > 0) assigneeError.value = false
},
{ deep: true },
)
function validateForm(): boolean {
titleError.value = title.value.trim().length === 0
assigneeError.value = assignees.value.length === 0
return !titleError.value && !assigneeError.value
}
async function submitTask() {
if (!canSubmit.value) return
if (submitting.value) return
if (!validateForm()) return
submitting.value = true
try {
const content = contentText.value
@@ -374,7 +390,7 @@ function goBack() {
<button
class="btn primary"
type="button"
:disabled="!canSubmit"
:disabled="submitting"
@click="submitTask"
>
<svg
@@ -401,8 +417,15 @@ function goBack() {
<input
v-model="title"
class="title-input"
:class="{ 'has-error': titleError }"
placeholder="업무 제목을 입력하세요"
>
<div
v-if="titleError"
class="field-error"
>
업무 제목을 입력해 주세요.
</div>
<div class="divider" />
<!-- 업무 내용 -->
@@ -661,7 +684,10 @@ function goBack() {
</div>
<div class="combo">
<!-- 입력칸은 고정 선택된 담당자는 아래에 표기 -->
<div class="combo-field">
<div
class="combo-field"
:class="{ 'has-error': assigneeError }"
>
<input
v-model="assigneeQuery"
class="combo-input"
@@ -729,6 +755,12 @@ function goBack() {
>×</span>
</span>
</div>
<div
v-if="assigneeError"
class="field-error"
>
담당자를 1 이상 지정해 주세요.
</div>
</div>
</div>
@@ -949,6 +981,14 @@ function goBack() {
.title-input::placeholder {
color: #c4c8cf;
}
.title-input.has-error::placeholder {
color: var(--red);
}
.field-error {
font-size: 0.75rem;
color: var(--red);
margin-top: 0.375rem;
}
.divider {
height: 1px;
background: var(--border);
@@ -1429,6 +1469,12 @@ function goBack() {
border-color: var(--accent);
box-shadow: 0 0 0 3px var(--accent-weak);
}
.combo-field.has-error {
border-color: var(--red);
}
.combo-field.has-error:focus-within {
box-shadow: 0 0 0 3px var(--red-weak);
}
.combo-caret {
color: var(--text-3);
display: grid;