From 9334514c71a30ebcf475d7683b0696d2f2c6383a Mon Sep 17 00:00:00 2001 From: bicochan Date: Fri, 2 Oct 2026 14:55:42 +0900 Subject: [PATCH 1/2] =?UTF-8?q?[as]=20chore:=20=ED=96=89=EC=A0=95=EC=A7=80?= =?UTF-8?q?=EC=9B=90=20=ED=8F=BC=20=EC=82=AC=EC=97=85=EA=B8=B0=EA=B0=84=20?= =?UTF-8?q?=EC=8A=A4=ED=82=A4=EB=A7=88=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/design-cnstn/lib/design-cnstn-regist-schema.ts | 4 ++-- .../as/src/pages/fnrs-cnsltn/lib/fnrs-cnsltn-regist-schema.ts | 4 ++-- .../pages/fnrs-cnsltn/ui/sections/basic-info-form-section.tsx | 4 ++-- apps/as/src/pages/instl-sncn/lib/instl-sncn-regist-schema.ts | 4 ++-- .../pages/instl-sncn/ui/sections/basic-info-form-section.tsx | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/apps/as/src/pages/design-cnstn/lib/design-cnstn-regist-schema.ts b/apps/as/src/pages/design-cnstn/lib/design-cnstn-regist-schema.ts index 4efee2be9..a5dda2d38 100644 --- a/apps/as/src/pages/design-cnstn/lib/design-cnstn-regist-schema.ts +++ b/apps/as/src/pages/design-cnstn/lib/design-cnstn-regist-schema.ts @@ -12,11 +12,11 @@ export const designCnstnRegistSchema = z.object({ bizBgngYr: z .string() .min(1, "사업시작연도는 필수입니다") - .regex(/^\d{4}$/, "사업시작연도는 4자리 숫자여야 합니다"), + .regex(/^\d{4}$/, "연도는 4자리 숫자여야 합니다"), bizEndYr: z .string() .min(1, "사업종료연도는 필수입니다") - .regex(/^\d{4}$/, "사업종료연도는 4자리 숫자여야 합니다"), + .regex(/^\d{4}$/, "연도는 4자리 숫자여야 합니다"), bizCn: z.string().min(1, "사업내용은 필수입니다"), taskSeComCd: z.array(z.string()).min(1, "구분은 필수입니다"), dsgnrNm: z.string().min(1, "설계자 이름은 필수입니다"), diff --git a/apps/as/src/pages/fnrs-cnsltn/lib/fnrs-cnsltn-regist-schema.ts b/apps/as/src/pages/fnrs-cnsltn/lib/fnrs-cnsltn-regist-schema.ts index 530d77ed9..402835a64 100644 --- a/apps/as/src/pages/fnrs-cnsltn/lib/fnrs-cnsltn-regist-schema.ts +++ b/apps/as/src/pages/fnrs-cnsltn/lib/fnrs-cnsltn-regist-schema.ts @@ -16,11 +16,11 @@ export const fnrsCnsltnRegistSchema = z.object({ bizBgngYr: z .string() .min(1, "사업시작연도는 필수입니다") - .regex(/^\d{4}$/, "사업시작연도는 4자리 숫자여야 합니다"), + .regex(/^\d{4}$/, "연도는 4자리 숫자여야 합니다"), bizEndYr: z .string() .min(1, "사업종료연도는 필수입니다") - .regex(/^\d{4}$/, "사업종료연도는 4자리 숫자여야 합니다"), + .regex(/^\d{4}$/, "연도는 4자리 숫자여야 합니다"), bizCn: z.string().min(1, "사업내용은 필수입니다"), taskSeComCd: z.array(z.string()).min(1, "구분은 필수입니다"), dsgnrNm: z.string().min(1, "설계자 이름은 필수입니다"), diff --git a/apps/as/src/pages/fnrs-cnsltn/ui/sections/basic-info-form-section.tsx b/apps/as/src/pages/fnrs-cnsltn/ui/sections/basic-info-form-section.tsx index 0e7796dd2..bb1d18530 100644 --- a/apps/as/src/pages/fnrs-cnsltn/ui/sections/basic-info-form-section.tsx +++ b/apps/as/src/pages/fnrs-cnsltn/ui/sections/basic-info-form-section.tsx @@ -92,7 +92,7 @@ function BasicInfoFormSection() { name="fnrsCnsltnMng.bizBgngYr" control={control} render={({ field, fieldState }) => ( - + ( - + ( - + ( - + Date: Fri, 2 Oct 2026 15:14:22 +0900 Subject: [PATCH 2/2] =?UTF-8?q?[as]=20chore:=20=ED=96=89=EC=A0=95=EC=A7=80?= =?UTF-8?q?=EC=9B=90=20=EC=88=AB=EC=9E=90=20=ED=8F=BC=20=EC=9D=8C=EC=88=98?= =?UTF-8?q?=20=EC=9E=85=EB=A0=A5=20=EC=A0=9C=ED=95=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/sections/basic-info-form-section.tsx | 3 +++ .../ui/sections/basic-info-form-section.tsx | 3 +++ .../ui/sections/basic-info-form-section.tsx | 3 +++ .../ui/sections/biz-cst-matrix-form-section.tsx | 4 +++- .../ui/sections/fnrs-cst-form-section.tsx | 4 +++- .../ui/sections/outline-form-section.tsx | 5 ++++- .../ui/sections/tmplnt-form-section.tsx | 10 ++++++++-- apps/as/src/shared/lib/index.ts | 1 + apps/as/src/shared/lib/number-input.ts | 13 +++++++++++++ .../pbadms-sprt/ui/business-cost-form-section.tsx | 12 +++++++++++- .../pbadms-sprt/ui/business-scale-form-section.tsx | 12 +++++++++++- .../pbadms-sprt/ui/fnrs-shar-form-section.tsx | 11 +++++++++-- 12 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 apps/as/src/shared/lib/number-input.ts diff --git a/apps/as/src/pages/design-cnstn/ui/sections/basic-info-form-section.tsx b/apps/as/src/pages/design-cnstn/ui/sections/basic-info-form-section.tsx index 92f80ac9c..a4f96c006 100644 --- a/apps/as/src/pages/design-cnstn/ui/sections/basic-info-form-section.tsx +++ b/apps/as/src/pages/design-cnstn/ui/sections/basic-info-form-section.tsx @@ -3,6 +3,7 @@ import { useState } from "react"; import { Controller, useFormContext } from "react-hook-form"; +import { NON_NEGATIVE_INPUT_PROPS } from "@/shared/lib"; import { SectionCollapsible } from "@/shared/ui"; import { Field, FieldError, FieldGroup } from "@/shared/ui/field"; import { findCodeLabel, useCodeList } from "@/entities/code"; @@ -82,6 +83,7 @@ function BasicInfoFormSection() { item.planStpNo === planStpNo); if (index < 0) return; @@ -154,6 +155,7 @@ function FnrsCstFormSection() { item.planStpNo === planStpNo); @@ -107,6 +109,7 @@ function OutlineFormSection() { ( { - const value = e.target.value.replace(/,/g, ""); + const value = stripMinusSign(e.target.value.replace(/,/g, "")); const normalized = hasDecimals ? truncateDecimals(value, decimals) : value; field.onChange(Number(normalized) || 0); }} diff --git a/apps/as/src/shared/lib/index.ts b/apps/as/src/shared/lib/index.ts index 3c8813abb..b344b56bd 100644 --- a/apps/as/src/shared/lib/index.ts +++ b/apps/as/src/shared/lib/index.ts @@ -2,6 +2,7 @@ export { getCookie, removeCookie, setCookie } from "./cookie"; export { dayjs } from "./dayjs"; export { getListHref, withListQs } from "./list-return-href"; export { matchQueryStatus } from "./match-query-status"; +export { NON_NEGATIVE_INPUT_PROPS, stripMinusSign } from "./number-input"; export { queryClient } from "./query-client"; export { useAlertStore } from "./use-alert-store"; export { useDataTable } from "./use-data-table"; diff --git a/apps/as/src/shared/lib/number-input.ts b/apps/as/src/shared/lib/number-input.ts new file mode 100644 index 000000000..228f6948b --- /dev/null +++ b/apps/as/src/shared/lib/number-input.ts @@ -0,0 +1,13 @@ +import type { KeyboardEvent } from "react"; + +function preventMinusKey(e: KeyboardEvent) { + if (e.key === "-") e.preventDefault(); +} + +/** type="number" Input에 스프레드해 음수 입력(키·스피너)을 막는다 */ +export const NON_NEGATIVE_INPUT_PROPS = { min: 0, onKeyDown: preventMinusKey } as const; + +/** 붙여넣기 등으로 들어온 음수 부호를 제거한다 */ +export function stripMinusSign(value: string): string { + return value.replace(/-/g, ""); +} diff --git a/apps/as/src/widgets/pbadms-sprt/ui/business-cost-form-section.tsx b/apps/as/src/widgets/pbadms-sprt/ui/business-cost-form-section.tsx index 42268c710..fb27309aa 100644 --- a/apps/as/src/widgets/pbadms-sprt/ui/business-cost-form-section.tsx +++ b/apps/as/src/widgets/pbadms-sprt/ui/business-cost-form-section.tsx @@ -3,6 +3,7 @@ import { useEffect, useMemo } from "react"; import { useFormContext, useWatch } from "react-hook-form"; +import { NON_NEGATIVE_INPUT_PROPS, stripMinusSign } from "@/shared/lib"; import { SectionCollapsible } from "@/shared/ui"; import { Field } from "@/shared/ui/field"; import { useAcntgSeMngTree } from "@/entities/acntg"; @@ -79,7 +80,7 @@ function BusinessCostFormSection() { }, [costItems, getValues, setValue]); function handleCostChange(index: number, fieldKey: CostFieldKey, value: string) { - const numValue = Number(truncateDecimals(value, COST_DECIMAL_PLACES)) || 0; + const numValue = Number(truncateDecimals(stripMinusSign(value), COST_DECIMAL_PLACES)) || 0; const draft = [...getValues("bizCstList")]; draft[index] = { ...draft[index], [fieldKey]: numValue }; const next = recalculateBizCstTotals(draft, costItems); @@ -102,6 +103,14 @@ function BusinessCostFormSection() {

(단위: 백만원)

+ + + + + + + + @@ -143,6 +152,7 @@ function BusinessCostFormSection() {
+ + + + + + + 구분 @@ -132,6 +141,7 @@ function BusinessScaleFormSection() { handleSharChange(idx, "exstnAmt", e.target.value)} @@ -247,6 +253,7 @@ function FnrsSharFormSection({ initialSharTree, initialSharAtchFiles }: FnrsShar handleSharChange(idx, "chgRqtAmt", e.target.value)}