[as] feat: 행정지원 메뉴(설치인가, 재원협의, 설계자문, 하수도기본계획) 수정
This commit is contained in:
@@ -51,7 +51,6 @@ export interface ElaprPrgrsSttsMyDocSearchParams extends ElaprPrgrsSttsSearchDto
|
|||||||
export interface ElaprProcessRequestDto {
|
export interface ElaprProcessRequestDto {
|
||||||
atrzPrgrsSttsComCd: string;
|
atrzPrgrsSttsComCd: string;
|
||||||
rjctRsn?: string;
|
rjctRsn?: string;
|
||||||
finalApprovalYn?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 백엔드 ElaprApproverChangeRequestDto */
|
/** 백엔드 ElaprApproverChangeRequestDto */
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import { ENDPOINT } from "@/shared/config";
|
|||||||
import type {
|
import type {
|
||||||
SewerBscPlanApplySaveRequestDto,
|
SewerBscPlanApplySaveRequestDto,
|
||||||
SewerBscPlanSaveRequestDto,
|
SewerBscPlanSaveRequestDto,
|
||||||
|
} from "../model/sewer-bsc-plan-apply-payload-schema";
|
||||||
|
import type {
|
||||||
SewerBscPlanSearchRequestDto,
|
SewerBscPlanSearchRequestDto,
|
||||||
SewerBscPlanUpdateRequestDto,
|
SewerBscPlanUpdateRequestDto,
|
||||||
} from "../model/sewer-bsc-plan-interface";
|
} from "../model/sewer-bsc-plan-interface";
|
||||||
|
|||||||
@@ -4,10 +4,12 @@ import type { PageResponse } from "@/shared/model";
|
|||||||
|
|
||||||
import type {
|
import type {
|
||||||
SewerBscPlanApplySaveRequestDto,
|
SewerBscPlanApplySaveRequestDto,
|
||||||
|
SewerBscPlanSaveRequestDto,
|
||||||
|
} from "../model/sewer-bsc-plan-apply-payload-schema";
|
||||||
|
import type {
|
||||||
SewerBscPlanApplySaveResponseDto,
|
SewerBscPlanApplySaveResponseDto,
|
||||||
SewerBscPlanDetResponseDto,
|
SewerBscPlanDetResponseDto,
|
||||||
SewerBscPlanResponseDto,
|
SewerBscPlanResponseDto,
|
||||||
SewerBscPlanSaveRequestDto,
|
|
||||||
SewerBscPlanSearchRequestDto,
|
SewerBscPlanSearchRequestDto,
|
||||||
SewerBscPlanService,
|
SewerBscPlanService,
|
||||||
SewerBscPlanUpdateRequestDto,
|
SewerBscPlanUpdateRequestDto,
|
||||||
|
|||||||
@@ -13,35 +13,52 @@ export {
|
|||||||
} from "./api/queries";
|
} from "./api/queries";
|
||||||
export { sewerBscPlanService } from "./api/sewer-bsc-plan-service";
|
export { sewerBscPlanService } from "./api/sewer-bsc-plan-service";
|
||||||
export type {
|
export type {
|
||||||
AtflMngClientResponseDto,
|
|
||||||
CklstResultItem,
|
CklstResultItem,
|
||||||
CklstRvwRsltTreeDto,
|
|
||||||
EsntlAtchFileItem,
|
EsntlAtchFileItem,
|
||||||
EsntlAtchFileMngTreeResponseDto,
|
|
||||||
SewerBscPlanApplySaveRequestDto,
|
SewerBscPlanApplySaveRequestDto,
|
||||||
SewerBscPlanApplySaveResponseDto,
|
|
||||||
SewerBscPlanBizCstItem,
|
SewerBscPlanBizCstItem,
|
||||||
|
SewerBscPlanDtlSaveRequestDto,
|
||||||
|
SewerBscPlanFnrsCstItem,
|
||||||
|
SewerBscPlanOtlnItem,
|
||||||
|
SewerBscPlanRvwOpnnItem,
|
||||||
|
SewerBscPlanSaveRequestDto,
|
||||||
|
SewerBscPlanSplmntDmndItem,
|
||||||
|
SewerBscPlanTmplntDtlItem,
|
||||||
|
SewerBscPlanTmplntItem,
|
||||||
|
SewerBscPlanTmplntTmprStrgItem,
|
||||||
|
} from "./model/sewer-bsc-plan-apply-payload-schema";
|
||||||
|
export {
|
||||||
|
sewerBscPlanApplySaveSchema,
|
||||||
|
sewerBscPlanBizCstItemSchema,
|
||||||
|
sewerBscPlanCklstResultItemSchema,
|
||||||
|
sewerBscPlanDtlSaveSchema,
|
||||||
|
sewerBscPlanEsntlAtchFileItemSchema,
|
||||||
|
sewerBscPlanFnrsCstItemSchema,
|
||||||
|
sewerBscPlanOtlnItemSchema,
|
||||||
|
sewerBscPlanRvwOpnnItemSchema,
|
||||||
|
sewerBscPlanSaveSchema,
|
||||||
|
sewerBscPlanSplmntDmndItemSchema,
|
||||||
|
sewerBscPlanTmplntDtlItemSchema,
|
||||||
|
sewerBscPlanTmplntItemSchema,
|
||||||
|
sewerBscPlanTmplntTmprStrgItemSchema,
|
||||||
|
} from "./model/sewer-bsc-plan-apply-payload-schema";
|
||||||
|
export type {
|
||||||
|
AtflMngClientResponseDto,
|
||||||
|
CklstRvwRsltTreeDto,
|
||||||
|
EsntlAtchFileMngTreeResponseDto,
|
||||||
|
SewerBscPlanApplySaveResponseDto,
|
||||||
SewerBscPlanBizCstResponseDto,
|
SewerBscPlanBizCstResponseDto,
|
||||||
SewerBscPlanDetResponseDto,
|
SewerBscPlanDetResponseDto,
|
||||||
SewerBscPlanDtlResponseDto,
|
SewerBscPlanDtlResponseDto,
|
||||||
SewerBscPlanDtlSaveRequestDto,
|
|
||||||
SewerBscPlanFnrsCstItem,
|
|
||||||
SewerBscPlanFnrsCstResponseDto,
|
SewerBscPlanFnrsCstResponseDto,
|
||||||
SewerBscPlanOtlnItem,
|
|
||||||
SewerBscPlanOtlnResponseDto,
|
SewerBscPlanOtlnResponseDto,
|
||||||
SewerBscPlanResponseDto,
|
SewerBscPlanResponseDto,
|
||||||
SewerBscPlanRvwOpnnItem,
|
|
||||||
SewerBscPlanRvwOpnnResponseDto,
|
SewerBscPlanRvwOpnnResponseDto,
|
||||||
SewerBscPlanSaveRequestDto,
|
|
||||||
SewerBscPlanSearchRequestDto,
|
SewerBscPlanSearchRequestDto,
|
||||||
SewerBscPlanService,
|
SewerBscPlanService,
|
||||||
SewerBscPlanSplmntDmndItem,
|
|
||||||
SewerBscPlanSplmntDmndResponseDto,
|
SewerBscPlanSplmntDmndResponseDto,
|
||||||
SewerBscPlanTmplntDtlItem,
|
|
||||||
SewerBscPlanTmplntDtlResponseDto,
|
SewerBscPlanTmplntDtlResponseDto,
|
||||||
SewerBscPlanTmplntItem,
|
|
||||||
SewerBscPlanTmplntResponseDto,
|
SewerBscPlanTmplntResponseDto,
|
||||||
SewerBscPlanTmplntTmprStrgItem,
|
|
||||||
SewerBscPlanTmplntTmprStrgResponseDto,
|
SewerBscPlanTmplntTmprStrgResponseDto,
|
||||||
SewerBscPlanUpdateRequestDto,
|
SewerBscPlanUpdateRequestDto,
|
||||||
} from "./model/sewer-bsc-plan-interface";
|
} from "./model/sewer-bsc-plan-interface";
|
||||||
|
|||||||
@@ -0,0 +1,173 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
/** 백엔드 SewerBscPlanSaveRequestDto */
|
||||||
|
export const sewerBscPlanSaveSchema = z.object({
|
||||||
|
sewerBscPlanDocNo: z.string().optional(),
|
||||||
|
admdstCd: z.string().optional(),
|
||||||
|
envoSeComCd: z.string().optional(),
|
||||||
|
sewerBscPlanSeComCd: z.string().optional(),
|
||||||
|
sewerBscPlanNm: z.string().optional(),
|
||||||
|
taskSeComCd: z.string().optional(),
|
||||||
|
prgrsSttsComCd: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 백엔드 SewerBscPlanDtlSaveRequestDto */
|
||||||
|
export const sewerBscPlanDtlSaveSchema = z.object({
|
||||||
|
sewerBscPlanDocNo: z.string().optional(),
|
||||||
|
chgCycl: z.number().optional(),
|
||||||
|
aplcntNm: z.string().optional(),
|
||||||
|
aplcntMblTelno: z.string().optional(),
|
||||||
|
aplcntOgdpNm: z.string().optional(),
|
||||||
|
aplcntEmlAddr: z.string().optional(),
|
||||||
|
dsgnrNm: z.string().optional(),
|
||||||
|
dsgnrTelno: z.string().optional(),
|
||||||
|
dsgnrOgdpNm: z.string().optional(),
|
||||||
|
dsgnrEmlAddr: z.string().optional(),
|
||||||
|
planYr: z.string().optional(),
|
||||||
|
crtrYr: z.string().optional(),
|
||||||
|
bizOtlnCn: z.string().optional(),
|
||||||
|
frlvlGoalYr: z.string().optional(),
|
||||||
|
sclvlGoalYr: z.string().optional(),
|
||||||
|
thlvlGoalYr: z.string().optional(),
|
||||||
|
folvlGoalYr: z.string().optional(),
|
||||||
|
atchFileGroupId: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 백엔드 SewerBscPlanApplySaveRequestDto.SewerBscPlanOtlnItem */
|
||||||
|
export const sewerBscPlanOtlnItemSchema = z.object({
|
||||||
|
planStpNo: z.number().optional(),
|
||||||
|
sewerPlanPpltnCnt: z.number().optional(),
|
||||||
|
sewerPrcsPpltnCnt: z.number().optional(),
|
||||||
|
sewerPsplyRt: z.number().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 백엔드 SewerBscPlanApplySaveRequestDto.CklstResultItem */
|
||||||
|
export const sewerBscPlanCklstResultItemSchema = z.object({
|
||||||
|
cklstRvwSn: z.number().optional(),
|
||||||
|
cklstArtclSn: z.number().optional(),
|
||||||
|
cklstSn: z.number().optional(),
|
||||||
|
rvwStpComCd: z.string(),
|
||||||
|
selected: z.string().optional(),
|
||||||
|
picRvwCn: z.string().nullish(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 백엔드 SewerBscPlanApplySaveRequestDto.SewerBscPlanFnrsCstItem */
|
||||||
|
export const sewerBscPlanFnrsCstItemSchema = z.object({
|
||||||
|
planStpNo: z.number().optional(),
|
||||||
|
gvexpAmt: z.number().optional(),
|
||||||
|
lcexpAmt: z.number().optional(),
|
||||||
|
orgprBdchgAmt: z.number().optional(),
|
||||||
|
etcAmt: z.number().optional(),
|
||||||
|
sumAmt: z.number().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 백엔드 SewerBscPlanApplySaveRequestDto.SewerBscPlanSplmntDmndItem */
|
||||||
|
export const sewerBscPlanSplmntDmndItemSchema = z.object({
|
||||||
|
splmntDmndSn: z.number().nullish(),
|
||||||
|
splmntArtclComCd: z.string().optional(),
|
||||||
|
splmntDmndCn: z.string().optional(),
|
||||||
|
splmntDmndDt: z.string().optional(),
|
||||||
|
splmntDmndAtchFileGroupId: z.string().optional(),
|
||||||
|
splmntCn: z.string().optional(),
|
||||||
|
splmntPicNm: z.string().optional(),
|
||||||
|
splmntCmptnDt: z.string().optional(),
|
||||||
|
splmntAtchFileGroupId: z.string().optional(),
|
||||||
|
cmptnYn: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 백엔드 SewerBscPlanApplySaveRequestDto.SewerBscPlanRvwOpnnItem */
|
||||||
|
export const sewerBscPlanRvwOpnnItemSchema = z.object({
|
||||||
|
rvwOpnnSn: z.number().optional(),
|
||||||
|
opnrSeComCd: z.string().optional(),
|
||||||
|
opnrNm: z.string().optional(),
|
||||||
|
rvwRsltCn: z.string().optional(),
|
||||||
|
rvwRsltAnmlyYn: z.string().optional(),
|
||||||
|
atchFileGroupId: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 백엔드 SewerBscPlanApplySaveRequestDto.EsntlAtchFileItem */
|
||||||
|
export const sewerBscPlanEsntlAtchFileItemSchema = z.object({
|
||||||
|
esntlAtchFileId: z.string().optional(),
|
||||||
|
atchFileGroupId: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 백엔드 SewerBscPlanApplySaveRequestDto.SewerBscPlanBizCstItem */
|
||||||
|
export const sewerBscPlanBizCstItemSchema = z.object({
|
||||||
|
planStpNo: z.number().optional(),
|
||||||
|
acntgSeCd: z.string().optional(),
|
||||||
|
cstrnAmt: z.number().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 백엔드 SewerBscPlanApplySaveRequestDto.SewerBscPlanTmplntDtlItem */
|
||||||
|
export const sewerBscPlanTmplntDtlItemSchema = z.object({
|
||||||
|
planStpNo: z.number().optional(),
|
||||||
|
swtrmtFcltCd: z.string().optional(),
|
||||||
|
prcsZoneArea: z.number().optional(),
|
||||||
|
swtrmtPpltnCnt: z.number().optional(),
|
||||||
|
planSwqty: z.number().optional(),
|
||||||
|
fcltCpct: z.number().optional(),
|
||||||
|
sprsysDrtwPplLen: z.number().optional(),
|
||||||
|
sprsysExlnPplLen: z.number().optional(),
|
||||||
|
cbsysPplLen: z.number().optional(),
|
||||||
|
icptgPplLen: z.number().optional(),
|
||||||
|
drgCnt: z.number().optional(),
|
||||||
|
drtwRlyPumpCnt: z.number().optional(),
|
||||||
|
drtwPumpCnt: z.number().optional(),
|
||||||
|
exlnPumpCnt: z.number().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 백엔드 SewerBscPlanApplySaveRequestDto.SewerBscPlanTmplntItem */
|
||||||
|
export const sewerBscPlanTmplntItemSchema = z.object({
|
||||||
|
swtrmtFcltCd: z.string().optional(),
|
||||||
|
atchFileGroupId: z.string().optional(),
|
||||||
|
sewerBscPlanTmplntDtlList: z.array(sewerBscPlanTmplntDtlItemSchema).optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 백엔드 SewerBscPlanApplySaveRequestDto.SewerBscPlanTmplntTmprStrgItem */
|
||||||
|
export const sewerBscPlanTmplntTmprStrgItemSchema = z.object({
|
||||||
|
dtStrgDt: z.string().optional(),
|
||||||
|
swtrmtFcltCd: z.string().optional(),
|
||||||
|
prcsZoneArea: z.number().optional(),
|
||||||
|
swtrmtPpltnCnt: z.number().optional(),
|
||||||
|
planSwqty: z.number().optional(),
|
||||||
|
fcltCpct: z.number().optional(),
|
||||||
|
sprsysDrtwPplLen: z.number().optional(),
|
||||||
|
sprsysExlnPplLen: z.number().optional(),
|
||||||
|
cbsysPplLen: z.number().optional(),
|
||||||
|
icptgPplLen: z.number().optional(),
|
||||||
|
drgCnt: z.number().optional(),
|
||||||
|
drtwRlyPumpCnt: z.number().optional(),
|
||||||
|
drtwPumpCnt: z.number().optional(),
|
||||||
|
exlnPumpCnt: z.number().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 백엔드 SewerBscPlanApplySaveRequestDto */
|
||||||
|
export const sewerBscPlanApplySaveSchema = z.object({
|
||||||
|
techReViewSaveCd: z.string().optional(),
|
||||||
|
rvwStpCd: z.string().optional(),
|
||||||
|
sewerBscPlan: sewerBscPlanSaveSchema,
|
||||||
|
sewerBscPlanDtl: sewerBscPlanDtlSaveSchema,
|
||||||
|
sewerBscPlanOtlnList: z.array(sewerBscPlanOtlnItemSchema).optional(),
|
||||||
|
cklstResultList: z.array(sewerBscPlanCklstResultItemSchema).optional(),
|
||||||
|
fnrsCstList: z.array(sewerBscPlanFnrsCstItemSchema).optional(),
|
||||||
|
splmntDmndList: z.array(sewerBscPlanSplmntDmndItemSchema).optional(),
|
||||||
|
rvwOpnnList: z.array(sewerBscPlanRvwOpnnItemSchema).optional(),
|
||||||
|
esntlAtchFileList: z.array(sewerBscPlanEsntlAtchFileItemSchema).optional(),
|
||||||
|
bizCstList: z.array(sewerBscPlanBizCstItemSchema).optional(),
|
||||||
|
sewerBscPlanTmplntList: z.array(sewerBscPlanTmplntItemSchema).optional(),
|
||||||
|
tmplntTmprStrgList: z.array(sewerBscPlanTmplntTmprStrgItemSchema).optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type SewerBscPlanSaveRequestDto = z.infer<typeof sewerBscPlanSaveSchema>;
|
||||||
|
export type SewerBscPlanDtlSaveRequestDto = z.infer<typeof sewerBscPlanDtlSaveSchema>;
|
||||||
|
export type SewerBscPlanOtlnItem = z.infer<typeof sewerBscPlanOtlnItemSchema>;
|
||||||
|
export type CklstResultItem = z.infer<typeof sewerBscPlanCklstResultItemSchema>;
|
||||||
|
export type SewerBscPlanFnrsCstItem = z.infer<typeof sewerBscPlanFnrsCstItemSchema>;
|
||||||
|
export type SewerBscPlanSplmntDmndItem = z.infer<typeof sewerBscPlanSplmntDmndItemSchema>;
|
||||||
|
export type SewerBscPlanRvwOpnnItem = z.infer<typeof sewerBscPlanRvwOpnnItemSchema>;
|
||||||
|
export type EsntlAtchFileItem = z.infer<typeof sewerBscPlanEsntlAtchFileItemSchema>;
|
||||||
|
export type SewerBscPlanBizCstItem = z.infer<typeof sewerBscPlanBizCstItemSchema>;
|
||||||
|
export type SewerBscPlanTmplntDtlItem = z.infer<typeof sewerBscPlanTmplntDtlItemSchema>;
|
||||||
|
export type SewerBscPlanTmplntItem = z.infer<typeof sewerBscPlanTmplntItemSchema>;
|
||||||
|
export type SewerBscPlanTmplntTmprStrgItem = z.infer<typeof sewerBscPlanTmplntTmprStrgItemSchema>;
|
||||||
|
export type SewerBscPlanApplySaveRequestDto = z.infer<typeof sewerBscPlanApplySaveSchema>;
|
||||||
@@ -1,35 +1,26 @@
|
|||||||
import type {
|
import type {
|
||||||
AtflMngClientResponseDto,
|
AtflMngClientResponseDto,
|
||||||
CklstResultSaveBase,
|
|
||||||
CklstRvwRsltTreeDto,
|
CklstRvwRsltTreeDto,
|
||||||
EsntlAtchFileMngTreeResponseDto,
|
EsntlAtchFileMngTreeResponseDto,
|
||||||
EsntlAtchFileSaveBase,
|
|
||||||
PageableParams,
|
PageableParams,
|
||||||
PageResponse,
|
PageResponse,
|
||||||
PbadmsApplySaveHeader,
|
|
||||||
RvwOpnnResponseExtension,
|
RvwOpnnResponseExtension,
|
||||||
RvwOpnnSaveBase,
|
RvwOpnnSaveBase,
|
||||||
SplmntDmndResponseExtension,
|
SplmntDmndResponseExtension,
|
||||||
SplmntDmndSaveBase,
|
SplmntDmndSaveBase,
|
||||||
} from "@/shared/model";
|
} from "@/shared/model";
|
||||||
|
|
||||||
|
import type {
|
||||||
|
SewerBscPlanApplySaveRequestDto,
|
||||||
|
SewerBscPlanSaveRequestDto,
|
||||||
|
} from "./sewer-bsc-plan-apply-payload-schema";
|
||||||
|
|
||||||
export type {
|
export type {
|
||||||
AtflMngClientResponseDto,
|
AtflMngClientResponseDto,
|
||||||
CklstRvwRsltTreeDto,
|
CklstRvwRsltTreeDto,
|
||||||
EsntlAtchFileMngTreeResponseDto,
|
EsntlAtchFileMngTreeResponseDto,
|
||||||
} from "@/shared/model";
|
} from "@/shared/model";
|
||||||
|
|
||||||
/** 백엔드 SewerBscPlanSaveRequestDto */
|
|
||||||
export interface SewerBscPlanSaveRequestDto {
|
|
||||||
sewerBscPlanDocNo?: string;
|
|
||||||
admdstCd?: string;
|
|
||||||
envoSeComCd?: string;
|
|
||||||
sewerBscPlanSeComCd?: string;
|
|
||||||
sewerBscPlanNm?: string;
|
|
||||||
taskSeComCd?: string;
|
|
||||||
prgrsSttsComCd?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 백엔드 SewerBscPlanUpdateRequestDto */
|
/** 백엔드 SewerBscPlanUpdateRequestDto */
|
||||||
export interface SewerBscPlanUpdateRequestDto {
|
export interface SewerBscPlanUpdateRequestDto {
|
||||||
admdstCd?: string;
|
admdstCd?: string;
|
||||||
@@ -72,28 +63,6 @@ export interface SewerBscPlanResponseDto {
|
|||||||
mdfcnDt?: string;
|
mdfcnDt?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 백엔드 SewerBscPlanDtlSaveRequestDto */
|
|
||||||
export interface SewerBscPlanDtlSaveRequestDto {
|
|
||||||
sewerBscPlanDocNo?: string;
|
|
||||||
chgCycl?: number;
|
|
||||||
aplcntNm?: string;
|
|
||||||
aplcntMblTelno?: string;
|
|
||||||
aplcntOgdpNm?: string;
|
|
||||||
aplcntEmlAddr?: string;
|
|
||||||
dsgnrNm?: string;
|
|
||||||
dsgnrTelno?: string;
|
|
||||||
dsgnrOgdpNm?: string;
|
|
||||||
dsgnrEmlAddr?: string;
|
|
||||||
planYr?: string;
|
|
||||||
crtrYr?: string;
|
|
||||||
bizOtlnCn?: string;
|
|
||||||
frlvlGoalYr?: string;
|
|
||||||
sclvlGoalYr?: string;
|
|
||||||
thlvlGoalYr?: string;
|
|
||||||
folvlGoalYr?: string;
|
|
||||||
atchFileGroupId?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 백엔드 SewerBscPlanDtlResponseDto */
|
/** 백엔드 SewerBscPlanDtlResponseDto */
|
||||||
export interface SewerBscPlanDtlResponseDto {
|
export interface SewerBscPlanDtlResponseDto {
|
||||||
sewerBscPlanDocNo?: string;
|
sewerBscPlanDocNo?: string;
|
||||||
@@ -210,103 +179,6 @@ export interface SewerBscPlanTmplntTmprStrgResponseDto {
|
|||||||
exlnPumpCnt?: number;
|
exlnPumpCnt?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 백엔드 SewerBscPlanApplySaveRequestDto.SewerBscPlanOtlnItem */
|
|
||||||
export interface SewerBscPlanOtlnItem {
|
|
||||||
planStpNo?: number;
|
|
||||||
sewerPlanPpltnCnt?: number;
|
|
||||||
sewerPrcsPpltnCnt?: number;
|
|
||||||
sewerPsplyRt?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 백엔드 SewerBscPlanApplySaveRequestDto.CklstResultItem */
|
|
||||||
export interface CklstResultItem extends CklstResultSaveBase {
|
|
||||||
selected?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 백엔드 SewerBscPlanApplySaveRequestDto.SewerBscPlanFnrsCstItem */
|
|
||||||
export interface SewerBscPlanFnrsCstItem {
|
|
||||||
planStpNo?: number;
|
|
||||||
gvexpAmt?: number;
|
|
||||||
lcexpAmt?: number;
|
|
||||||
orgprBdchgAmt?: number;
|
|
||||||
etcAmt?: number;
|
|
||||||
sumAmt?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 백엔드 SewerBscPlanApplySaveRequestDto.SewerBscPlanSplmntDmndItem */
|
|
||||||
export type SewerBscPlanSplmntDmndItem = SplmntDmndSaveBase;
|
|
||||||
|
|
||||||
/** 백엔드 SewerBscPlanApplySaveRequestDto.SewerBscPlanRvwOpnnItem */
|
|
||||||
export type SewerBscPlanRvwOpnnItem = RvwOpnnSaveBase;
|
|
||||||
|
|
||||||
/** 백엔드 SewerBscPlanApplySaveRequestDto.EsntlAtchFileItem */
|
|
||||||
export type EsntlAtchFileItem = EsntlAtchFileSaveBase;
|
|
||||||
|
|
||||||
/** 백엔드 SewerBscPlanApplySaveRequestDto.SewerBscPlanBizCstItem */
|
|
||||||
export interface SewerBscPlanBizCstItem {
|
|
||||||
planStpNo?: number;
|
|
||||||
acntgSeCd?: string;
|
|
||||||
cstrnAmt?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 백엔드 SewerBscPlanApplySaveRequestDto.SewerBscPlanTmplntDtlItem */
|
|
||||||
export interface SewerBscPlanTmplntDtlItem {
|
|
||||||
planStpNo?: number;
|
|
||||||
swtrmtFcltCd?: string;
|
|
||||||
prcsZoneArea?: number;
|
|
||||||
swtrmtPpltnCnt?: number;
|
|
||||||
planSwqty?: number;
|
|
||||||
fcltCpct?: number;
|
|
||||||
sprsysDrtwPplLen?: number;
|
|
||||||
sprsysExlnPplLen?: number;
|
|
||||||
cbsysPplLen?: number;
|
|
||||||
icptgPplLen?: number;
|
|
||||||
drgCnt?: number;
|
|
||||||
drtwRlyPumpCnt?: number;
|
|
||||||
drtwPumpCnt?: number;
|
|
||||||
exlnPumpCnt?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 백엔드 SewerBscPlanApplySaveRequestDto.SewerBscPlanTmplntItem */
|
|
||||||
export interface SewerBscPlanTmplntItem {
|
|
||||||
swtrmtFcltCd?: string;
|
|
||||||
atchFileGroupId?: string;
|
|
||||||
sewerBscPlanTmplntDtlList?: SewerBscPlanTmplntDtlItem[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 백엔드 SewerBscPlanApplySaveRequestDto.SewerBscPlanTmplntTmprStrgItem */
|
|
||||||
export interface SewerBscPlanTmplntTmprStrgItem {
|
|
||||||
dtStrgDt?: string;
|
|
||||||
swtrmtFcltCd?: string;
|
|
||||||
prcsZoneArea?: number;
|
|
||||||
swtrmtPpltnCnt?: number;
|
|
||||||
planSwqty?: number;
|
|
||||||
fcltCpct?: number;
|
|
||||||
sprsysDrtwPplLen?: number;
|
|
||||||
sprsysExlnPplLen?: number;
|
|
||||||
cbsysPplLen?: number;
|
|
||||||
icptgPplLen?: number;
|
|
||||||
drgCnt?: number;
|
|
||||||
drtwRlyPumpCnt?: number;
|
|
||||||
drtwPumpCnt?: number;
|
|
||||||
exlnPumpCnt?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 백엔드 SewerBscPlanApplySaveRequestDto */
|
|
||||||
export interface SewerBscPlanApplySaveRequestDto extends PbadmsApplySaveHeader {
|
|
||||||
sewerBscPlan: SewerBscPlanSaveRequestDto;
|
|
||||||
sewerBscPlanDtl: SewerBscPlanDtlSaveRequestDto;
|
|
||||||
sewerBscPlanOtlnList?: SewerBscPlanOtlnItem[];
|
|
||||||
cklstResultList?: CklstResultItem[];
|
|
||||||
fnrsCstList?: SewerBscPlanFnrsCstItem[];
|
|
||||||
splmntDmndList?: SewerBscPlanSplmntDmndItem[];
|
|
||||||
rvwOpnnList?: SewerBscPlanRvwOpnnItem[];
|
|
||||||
esntlAtchFileList?: EsntlAtchFileItem[];
|
|
||||||
bizCstList?: SewerBscPlanBizCstItem[];
|
|
||||||
sewerBscPlanTmplntList?: SewerBscPlanTmplntItem[];
|
|
||||||
tmplntTmprStrgList?: SewerBscPlanTmplntTmprStrgItem[];
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 백엔드 SewerBscPlanApplySaveResponseDto */
|
/** 백엔드 SewerBscPlanApplySaveResponseDto */
|
||||||
export interface SewerBscPlanApplySaveResponseDto {
|
export interface SewerBscPlanApplySaveResponseDto {
|
||||||
sewerBscPlanDocNo: string;
|
sewerBscPlanDocNo: string;
|
||||||
|
|||||||
@@ -15,10 +15,12 @@ import {
|
|||||||
type DesignCnstnMngDetResponseDto,
|
type DesignCnstnMngDetResponseDto,
|
||||||
designCnstnMngService,
|
designCnstnMngService,
|
||||||
} from "@/entities/design-cnstn";
|
} from "@/entities/design-cnstn";
|
||||||
|
import { useEsntlAtchFileMngTree } from "@/entities/esntl";
|
||||||
import {
|
import {
|
||||||
AttachmentsFormSection,
|
AttachmentsFormSection,
|
||||||
BusinessScaleFormSection,
|
BusinessScaleFormSection,
|
||||||
ContactInfoFormSection,
|
ContactInfoFormSection,
|
||||||
|
isFormEsntlAtchComplete,
|
||||||
PrivacyConsentSection,
|
PrivacyConsentSection,
|
||||||
} from "@/widgets/pbadms-sprt";
|
} from "@/widgets/pbadms-sprt";
|
||||||
import { Button } from "@common/components";
|
import { Button } from "@common/components";
|
||||||
@@ -53,6 +55,8 @@ function DesignFormPage({ id, mode, initialData, createDefaults }: DesignFormPag
|
|||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const isEditMode = mode === "edit";
|
const isEditMode = mode === "edit";
|
||||||
|
|
||||||
|
const { data: essentialFiles = [] } = useEsntlAtchFileMngTree({ docSeComCd: "CNFM" });
|
||||||
|
|
||||||
const form = useForm<DesignCnstnRegistFormData>({
|
const form = useForm<DesignCnstnRegistFormData>({
|
||||||
resolver: zodResolver(designCnstnRegistSchema),
|
resolver: zodResolver(designCnstnRegistSchema),
|
||||||
mode: "onChange",
|
mode: "onChange",
|
||||||
@@ -113,6 +117,11 @@ function DesignFormPage({ id, mode, initialData, createDefaults }: DesignFormPag
|
|||||||
async function onApply(data: DesignCnstnRegistFormData) {
|
async function onApply(data: DesignCnstnRegistFormData) {
|
||||||
if (isSubmitting) return;
|
if (isSubmitting) return;
|
||||||
|
|
||||||
|
if (!isFormEsntlAtchComplete(essentialFiles, data.esntlAtchFileList)) {
|
||||||
|
alert("필수 첨부파일을 모두 등록해야 신청이 가능합니다.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
const designCnstnDocNo = await submitForm(data, "CT");
|
const designCnstnDocNo = await submitForm(data, "CT");
|
||||||
|
|||||||
@@ -62,49 +62,51 @@ function AttachmentsSection({ esntlFileList, etcFileList }: AttachmentsSectionPr
|
|||||||
</SectionCollapsible>
|
</SectionCollapsible>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<SectionCollapsible title="기타 첨부파일">
|
{etcFileList.length > 0 && (
|
||||||
<div className="overflow-x-auto">
|
<SectionCollapsible title="기타 첨부파일">
|
||||||
<Table variant="secondary">
|
<div className="overflow-x-auto">
|
||||||
<TableHeader>
|
<Table variant="secondary">
|
||||||
<TableRow>
|
<TableHeader>
|
||||||
<TableHead>파일명</TableHead>
|
|
||||||
<TableHead className="w-[8rem] text-right">크기</TableHead>
|
|
||||||
</TableRow>
|
|
||||||
</TableHeader>
|
|
||||||
<TableBody>
|
|
||||||
{etcFileList.length === 0 ? (
|
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={2} className="py-12 text-center text-muted-foreground">
|
<TableHead>파일명</TableHead>
|
||||||
등록된 기타첨부파일이 없습니다.
|
<TableHead className="w-[8rem] text-right">크기</TableHead>
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
) : (
|
</TableHeader>
|
||||||
etcFileList.map((file) => (
|
<TableBody>
|
||||||
<TableRow key={file.atflId}>
|
{etcFileList.length === 0 ? (
|
||||||
<TableCell className="text-left">
|
<TableRow>
|
||||||
{file.atflCd ? (
|
<TableCell colSpan={2} className="py-12 text-center text-muted-foreground">
|
||||||
<a
|
등록된 기타첨부파일이 없습니다.
|
||||||
className="cursor-pointer text-blue-600 hover:underline"
|
|
||||||
onClick={() => downloadAttachment(file.atflCd)}
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
{file.orgnlFileNm || file.physFileNm || file.atflId}
|
|
||||||
</a>
|
|
||||||
) : (
|
|
||||||
<span>{file.orgnlFileNm || file.physFileNm || file.atflId}</span>
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className="text-right text-gray-500">
|
|
||||||
{formatFileSize(file.atflFlieSz)}
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))
|
) : (
|
||||||
)}
|
etcFileList.map((file) => (
|
||||||
</TableBody>
|
<TableRow key={file.atflId}>
|
||||||
</Table>
|
<TableCell className="text-left">
|
||||||
</div>
|
{file.atflCd ? (
|
||||||
</SectionCollapsible>
|
<a
|
||||||
|
className="cursor-pointer text-blue-600 hover:underline"
|
||||||
|
onClick={() => downloadAttachment(file.atflCd)}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
{file.orgnlFileNm || file.physFileNm || file.atflId}
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<span>{file.orgnlFileNm || file.physFileNm || file.atflId}</span>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-right text-gray-500">
|
||||||
|
{formatFileSize(file.atflFlieSz)}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
</SectionCollapsible>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
|
import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
|
||||||
|
|
||||||
|
import { Paperclip } from "lucide-react";
|
||||||
|
|
||||||
import { PROXY_HOST } from "@/shared/config";
|
import { PROXY_HOST } from "@/shared/config";
|
||||||
import { dayjs, getDefaultFileKey, useTus } from "@/shared/lib";
|
import { dayjs, getDefaultFileKey, useTus } from "@/shared/lib";
|
||||||
import { Field, FieldLabel, FieldSet } from "@/shared/ui/field";
|
import { Field, FieldLabel, FieldSet } from "@/shared/ui/field";
|
||||||
@@ -71,12 +73,10 @@ function hasFormContent(formData: ReviewOpinionFormData) {
|
|||||||
const TechReviewOpinionSection = forwardRef<
|
const TechReviewOpinionSection = forwardRef<
|
||||||
TechReviewOpinionSectionHandle,
|
TechReviewOpinionSectionHandle,
|
||||||
TechReviewOpinionSectionProps
|
TechReviewOpinionSectionProps
|
||||||
>(function TechReviewOpinionSection({
|
>(function TechReviewOpinionSection(
|
||||||
rvwList,
|
{ rvwList, editableReviewStep, atrzSeComCdList = [], isAtrzLoading = false },
|
||||||
editableReviewStep,
|
ref,
|
||||||
atrzSeComCdList = [],
|
) {
|
||||||
isAtrzLoading = false,
|
|
||||||
}, ref) {
|
|
||||||
const canWriteOpinion = !isAtrzLoading && atrzSeComCdList.includes("ATRZ02");
|
const canWriteOpinion = !isAtrzLoading && atrzSeComCdList.includes("ATRZ02");
|
||||||
const [formData, setFormData] = useState<ReviewOpinionFormData>({
|
const [formData, setFormData] = useState<ReviewOpinionFormData>({
|
||||||
...EMPTY_FORM_DATA,
|
...EMPTY_FORM_DATA,
|
||||||
@@ -317,11 +317,12 @@ function TechReviewOpinionTable({ items }: TechReviewOpinionTableProps) {
|
|||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
{item.atchFileInfo?.atflCd ? (
|
{item.atchFileInfo?.atflCd ? (
|
||||||
<a
|
<a
|
||||||
className="text-blue-600 hover:underline"
|
className="inline-flex cursor-pointer items-start gap-1 text-left text-blue-600 hover:underline"
|
||||||
href={`${PROXY_HOST}/attach-service/api/v1/atflcd/download/${item.atchFileInfo.atflCd}`}
|
href={`${PROXY_HOST}/attach-service/api/v1/atflcd/download/${item.atchFileInfo.atflCd}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>
|
>
|
||||||
|
<Paperclip className="my-1 size-5 shrink-0" />
|
||||||
{item.atchFileInfo.orgnlFileNm || "다운로드"}
|
{item.atchFileInfo.orgnlFileNm || "다운로드"}
|
||||||
</a>
|
</a>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ export const fnrsCnsltnRegistSchema = z.object({
|
|||||||
),
|
),
|
||||||
splmntDmndList: z.array(
|
splmntDmndList: z.array(
|
||||||
z.object({
|
z.object({
|
||||||
splmntDmndSn: z.number().optional(),
|
splmntDmndSn: z.number().nullish(),
|
||||||
splmntArtclComCd: z.string().optional(),
|
splmntArtclComCd: z.string().optional(),
|
||||||
splmntArtclCdNm: z.string().nullish(),
|
splmntArtclCdNm: z.string().nullish(),
|
||||||
splmntDmndCn: z.string().optional(),
|
splmntDmndCn: z.string().optional(),
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { useQueryClient } from "@tanstack/react-query";
|
|||||||
|
|
||||||
import { useAlertStore, useUserStore } from "@/shared/lib";
|
import { useAlertStore, useUserStore } from "@/shared/lib";
|
||||||
import { useAcntgSeMngTree } from "@/entities/acntg";
|
import { useAcntgSeMngTree } from "@/entities/acntg";
|
||||||
|
import { useEsntlAtchFileMngTree } from "@/entities/esntl";
|
||||||
import {
|
import {
|
||||||
type FnrsCnsltnApplySaveRequestDto,
|
type FnrsCnsltnApplySaveRequestDto,
|
||||||
fnrsCnsltnMngBaseKey,
|
fnrsCnsltnMngBaseKey,
|
||||||
@@ -27,6 +28,7 @@ import {
|
|||||||
ContactInfoFormSection,
|
ContactInfoFormSection,
|
||||||
FnrsSharFormSection,
|
FnrsSharFormSection,
|
||||||
isFormChecklistComplete,
|
isFormChecklistComplete,
|
||||||
|
isFormEsntlAtchComplete,
|
||||||
PrivacyConsentSection,
|
PrivacyConsentSection,
|
||||||
recalculateFnrsSharTotals,
|
recalculateFnrsSharTotals,
|
||||||
SplmntDmndFormSection,
|
SplmntDmndFormSection,
|
||||||
@@ -67,6 +69,7 @@ function FnrsFormPage({ id, mode, initialData, createDefaults }: FnrsFormPagePro
|
|||||||
|
|
||||||
const { data: masterSharTree = [] } = useFnrsSharSeMngTree();
|
const { data: masterSharTree = [] } = useFnrsSharSeMngTree();
|
||||||
const { data: acntgTree = [] } = useAcntgSeMngTree();
|
const { data: acntgTree = [] } = useAcntgSeMngTree();
|
||||||
|
const { data: essentialFiles = [] } = useEsntlAtchFileMngTree({ docSeComCd: "FNRS" });
|
||||||
const sharTree =
|
const sharTree =
|
||||||
isEditMode && initialData?.fnrsSharList?.length ? initialData.fnrsSharList : masterSharTree;
|
isEditMode && initialData?.fnrsSharList?.length ? initialData.fnrsSharList : masterSharTree;
|
||||||
const sharItems = useMemo(() => buildFnrsSharItems(sharTree), [sharTree]);
|
const sharItems = useMemo(() => buildFnrsSharItems(sharTree), [sharTree]);
|
||||||
@@ -210,6 +213,11 @@ function FnrsFormPage({ id, mode, initialData, createDefaults }: FnrsFormPagePro
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isFormEsntlAtchComplete(essentialFiles, data.esntlAtchFileList)) {
|
||||||
|
alert("필수 첨부파일을 모두 등록해야 신청이 가능합니다.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
const fnrsCnsltnDocNo = await submitForm(data, "ST");
|
const fnrsCnsltnDocNo = await submitForm(data, "ST");
|
||||||
|
|||||||
@@ -19,98 +19,104 @@ function AttachmentsSection({ esntlFileList, etcFileList }: AttachmentsSectionPr
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SectionCollapsible title="필수 첨부파일">
|
{esntlFileList.length > 0 && (
|
||||||
<div className="overflow-x-auto">
|
<SectionCollapsible title="필수 첨부파일">
|
||||||
<Table variant="secondary">
|
<div className="overflow-x-auto">
|
||||||
<TableHeader>
|
<Table variant="secondary">
|
||||||
<TableRow>
|
<TableHeader>
|
||||||
<TableHead>필수 자료명</TableHead>
|
|
||||||
<TableHead>파일명</TableHead>
|
|
||||||
<TableHead className="w-[8rem] text-right">크기</TableHead>
|
|
||||||
</TableRow>
|
|
||||||
</TableHeader>
|
|
||||||
<TableBody>
|
|
||||||
{esntlFileList.length === 0 ? (
|
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={3} className="py-12 text-center text-muted-foreground">
|
<TableHead>필수 자료명</TableHead>
|
||||||
조회된 필수 첨부파일 항목이 없습니다.
|
<TableHead>파일명</TableHead>
|
||||||
</TableCell>
|
<TableHead className="w-[8rem] text-right">크기</TableHead>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
) : (
|
</TableHeader>
|
||||||
esntlFileList.map((file) => (
|
<TableBody>
|
||||||
<TableRow key={file.esntlAtchFileId}>
|
{esntlFileList.length === 0 ? (
|
||||||
<TableCell className="pl-2 text-left">
|
<TableRow>
|
||||||
{file.esntlAtchFileNm}
|
<TableCell colSpan={3} className="py-12 text-center text-muted-foreground">
|
||||||
{file.esntlAtchYn === "Y" ? (
|
조회된 필수 첨부파일 항목이 없습니다.
|
||||||
<span className="ml-1 text-red-500">*</span>
|
|
||||||
) : null}
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="text-left">
|
|
||||||
{file.atflCd ? (
|
|
||||||
<a
|
|
||||||
className="cursor-pointer text-blue-600 hover:underline"
|
|
||||||
onClick={() => downloadAttachment(file.atflCd ?? "")}
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
{file.orgnlFileNm || "다운로드"}
|
|
||||||
</a>
|
|
||||||
) : (
|
|
||||||
<span className="text-gray-500">첨부없음</span>
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className="text-right">{formatFileSize(file.atflFlieSz)}</TableCell>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))
|
) : (
|
||||||
)}
|
esntlFileList.map((file) => (
|
||||||
</TableBody>
|
<TableRow key={file.esntlAtchFileId}>
|
||||||
</Table>
|
<TableCell className="pl-2 text-left">
|
||||||
</div>
|
{file.esntlAtchFileNm}
|
||||||
</SectionCollapsible>
|
{file.esntlAtchYn === "Y" ? (
|
||||||
|
<span className="ml-1 text-red-500">*</span>
|
||||||
|
) : null}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-left">
|
||||||
|
{file.atflCd ? (
|
||||||
|
<a
|
||||||
|
className="cursor-pointer text-blue-600 hover:underline"
|
||||||
|
onClick={() => downloadAttachment(file.atflCd ?? "")}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
{file.orgnlFileNm || "다운로드"}
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<span className="text-gray-500">첨부없음</span>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-right">
|
||||||
|
{formatFileSize(file.atflFlieSz)}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
</SectionCollapsible>
|
||||||
|
)}
|
||||||
|
|
||||||
<SectionCollapsible title="기타 첨부파일">
|
{etcFileList.length > 0 && (
|
||||||
<div className="overflow-x-auto">
|
<SectionCollapsible title="기타 첨부파일">
|
||||||
<Table variant="secondary">
|
<div className="overflow-x-auto">
|
||||||
<TableHeader>
|
<Table variant="secondary">
|
||||||
<TableRow>
|
<TableHeader>
|
||||||
<TableHead>파일명</TableHead>
|
|
||||||
<TableHead className="w-[8rem] text-right">크기</TableHead>
|
|
||||||
</TableRow>
|
|
||||||
</TableHeader>
|
|
||||||
<TableBody>
|
|
||||||
{etcFileList.length === 0 ? (
|
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={2} className="py-12 text-center text-muted-foreground">
|
<TableHead>파일명</TableHead>
|
||||||
등록된 기타첨부파일이 없습니다.
|
<TableHead className="w-[8rem] text-right">크기</TableHead>
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
) : (
|
</TableHeader>
|
||||||
etcFileList.map((file) => (
|
<TableBody>
|
||||||
<TableRow key={file.atflId}>
|
{etcFileList.length === 0 ? (
|
||||||
<TableCell className="text-left">
|
<TableRow>
|
||||||
{file.atflCd ? (
|
<TableCell colSpan={2} className="py-12 text-center text-muted-foreground">
|
||||||
<a
|
등록된 기타첨부파일이 없습니다.
|
||||||
className="cursor-pointer text-blue-600 hover:underline"
|
|
||||||
onClick={() => downloadAttachment(file.atflCd)}
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
{file.orgnlFileNm || file.physFileNm || file.atflId}
|
|
||||||
</a>
|
|
||||||
) : (
|
|
||||||
<span>{file.orgnlFileNm || file.physFileNm || file.atflId}</span>
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className="text-right text-gray-500">
|
|
||||||
{formatFileSize(file.atflFlieSz)}
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))
|
) : (
|
||||||
)}
|
etcFileList.map((file) => (
|
||||||
</TableBody>
|
<TableRow key={file.atflId}>
|
||||||
</Table>
|
<TableCell className="text-left">
|
||||||
</div>
|
{file.atflCd ? (
|
||||||
</SectionCollapsible>
|
<a
|
||||||
|
className="cursor-pointer text-blue-600 hover:underline"
|
||||||
|
onClick={() => downloadAttachment(file.atflCd)}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
{file.orgnlFileNm || file.physFileNm || file.atflId}
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<span>{file.orgnlFileNm || file.physFileNm || file.atflId}</span>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-right text-gray-500">
|
||||||
|
{formatFileSize(file.atflFlieSz)}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
</SectionCollapsible>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,10 @@ function ChecklistSection({
|
|||||||
|
|
||||||
const { total, completed, percent } = progress;
|
const { total, completed, percent } = progress;
|
||||||
|
|
||||||
|
if (cklstResultList.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionCollapsible title="체크리스트">
|
<SectionCollapsible title="체크리스트">
|
||||||
<div className="flex flex-col gap-4 p-2">
|
<div className="flex flex-col gap-4 p-2">
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
|
import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
|
||||||
|
|
||||||
|
import { Paperclip } from "lucide-react";
|
||||||
|
|
||||||
import { PROXY_HOST } from "@/shared/config";
|
import { PROXY_HOST } from "@/shared/config";
|
||||||
import { dayjs, getDefaultFileKey, useTus } from "@/shared/lib";
|
import { dayjs, getDefaultFileKey, useTus } from "@/shared/lib";
|
||||||
import { Field, FieldLabel, FieldSet } from "@/shared/ui/field";
|
import { Field, FieldLabel, FieldSet } from "@/shared/ui/field";
|
||||||
@@ -71,12 +73,10 @@ function hasFormContent(formData: ReviewOpinionFormData) {
|
|||||||
const TechReviewOpinionSection = forwardRef<
|
const TechReviewOpinionSection = forwardRef<
|
||||||
TechReviewOpinionSectionHandle,
|
TechReviewOpinionSectionHandle,
|
||||||
TechReviewOpinionSectionProps
|
TechReviewOpinionSectionProps
|
||||||
>(function TechReviewOpinionSection({
|
>(function TechReviewOpinionSection(
|
||||||
rvwList,
|
{ rvwList, editableReviewStep, atrzSeComCdList = [], isAtrzLoading = false },
|
||||||
editableReviewStep,
|
ref,
|
||||||
atrzSeComCdList = [],
|
) {
|
||||||
isAtrzLoading = false,
|
|
||||||
}, ref) {
|
|
||||||
const canWriteKecoOpinion = !isAtrzLoading && atrzSeComCdList.includes("ATRZ02");
|
const canWriteKecoOpinion = !isAtrzLoading && atrzSeComCdList.includes("ATRZ02");
|
||||||
const [formData, setFormData] = useState<ReviewOpinionFormData>({
|
const [formData, setFormData] = useState<ReviewOpinionFormData>({
|
||||||
...EMPTY_FORM_DATA,
|
...EMPTY_FORM_DATA,
|
||||||
@@ -336,11 +336,12 @@ function TechReviewOpinionTable({ items }: TechReviewOpinionTableProps) {
|
|||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
{item.atchFileInfo?.atflCd ? (
|
{item.atchFileInfo?.atflCd ? (
|
||||||
<a
|
<a
|
||||||
className="text-blue-600 hover:underline"
|
className="inline-flex cursor-pointer items-start gap-1 text-left text-blue-600 hover:underline"
|
||||||
href={`${PROXY_HOST}/attach-service/api/v1/atflcd/download/${item.atchFileInfo.atflCd}`}
|
href={`${PROXY_HOST}/attach-service/api/v1/atflcd/download/${item.atchFileInfo.atflCd}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>
|
>
|
||||||
|
<Paperclip className="my-1 size-5 shrink-0" />
|
||||||
{item.atchFileInfo.orgnlFileNm || "다운로드"}
|
{item.atchFileInfo.orgnlFileNm || "다운로드"}
|
||||||
</a>
|
</a>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ export const instlSncnRegistSchema = z.object({
|
|||||||
),
|
),
|
||||||
splmntDmndList: z.array(
|
splmntDmndList: z.array(
|
||||||
z.object({
|
z.object({
|
||||||
splmntDmndSn: z.number().optional(),
|
splmntDmndSn: z.number().nullish(),
|
||||||
splmntArtclComCd: z.string().optional(),
|
splmntArtclComCd: z.string().optional(),
|
||||||
splmntArtclCdNm: z.string().nullish(),
|
splmntArtclCdNm: z.string().nullish(),
|
||||||
splmntDmndCn: z.string().optional(),
|
splmntDmndCn: z.string().optional(),
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { zodResolver } from "@hookform/resolvers/zod";
|
|||||||
import { useQueryClient } from "@tanstack/react-query";
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
|
|
||||||
import { useAlertStore, useUserStore } from "@/shared/lib";
|
import { useAlertStore, useUserStore } from "@/shared/lib";
|
||||||
|
import { useEsntlAtchFileMngTree } from "@/entities/esntl";
|
||||||
import {
|
import {
|
||||||
type InstlSncnApplySaveRequestDto,
|
type InstlSncnApplySaveRequestDto,
|
||||||
instlSncnKeys,
|
instlSncnKeys,
|
||||||
@@ -22,6 +23,7 @@ import {
|
|||||||
ChecklistFormSection,
|
ChecklistFormSection,
|
||||||
ContactInfoFormSection,
|
ContactInfoFormSection,
|
||||||
isFormChecklistComplete,
|
isFormChecklistComplete,
|
||||||
|
isFormEsntlAtchComplete,
|
||||||
PrivacyConsentSection,
|
PrivacyConsentSection,
|
||||||
SplmntDmndFormSection,
|
SplmntDmndFormSection,
|
||||||
} from "@/widgets/pbadms-sprt";
|
} from "@/widgets/pbadms-sprt";
|
||||||
@@ -57,6 +59,8 @@ function InstlFormPage({ id, mode, initialData, createDefaults }: InstlFormPageP
|
|||||||
const isEditMode = mode === "edit";
|
const isEditMode = mode === "edit";
|
||||||
const isSplmntPrgrsStts = initialData?.detDto.prgrsSttsComCd === "SL";
|
const isSplmntPrgrsStts = initialData?.detDto.prgrsSttsComCd === "SL";
|
||||||
|
|
||||||
|
const { data: essentialFiles = [] } = useEsntlAtchFileMngTree({ docSeComCd: "INSTL" });
|
||||||
|
|
||||||
const form = useForm<InstlSncnRegistFormData>({
|
const form = useForm<InstlSncnRegistFormData>({
|
||||||
resolver: zodResolver(instlSncnRegistSchema),
|
resolver: zodResolver(instlSncnRegistSchema),
|
||||||
mode: "onChange",
|
mode: "onChange",
|
||||||
@@ -172,6 +176,11 @@ function InstlFormPage({ id, mode, initialData, createDefaults }: InstlFormPageP
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isFormEsntlAtchComplete(essentialFiles, data.esntlAtchFileList)) {
|
||||||
|
alert("필수 첨부파일을 모두 등록해야 신청이 가능합니다.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
const instlSncnDocNo = await submitForm(data, "ST");
|
const instlSncnDocNo = await submitForm(data, "ST");
|
||||||
|
|||||||
@@ -19,98 +19,104 @@ function AttachmentsSection({ esntlFileList, etcFileList }: AttachmentsSectionPr
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SectionCollapsible title="필수 첨부파일">
|
{esntlFileList.length > 0 && (
|
||||||
<div className="overflow-x-auto">
|
<SectionCollapsible title="필수 첨부파일">
|
||||||
<Table variant="secondary">
|
<div className="overflow-x-auto">
|
||||||
<TableHeader>
|
<Table variant="secondary">
|
||||||
<TableRow>
|
<TableHeader>
|
||||||
<TableHead>필수 자료명</TableHead>
|
|
||||||
<TableHead>파일명</TableHead>
|
|
||||||
<TableHead className="w-[8rem] text-right">크기</TableHead>
|
|
||||||
</TableRow>
|
|
||||||
</TableHeader>
|
|
||||||
<TableBody>
|
|
||||||
{esntlFileList.length === 0 ? (
|
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={3} className="py-12 text-center text-muted-foreground">
|
<TableHead>필수 자료명</TableHead>
|
||||||
조회된 필수 첨부파일 항목이 없습니다.
|
<TableHead>파일명</TableHead>
|
||||||
</TableCell>
|
<TableHead className="w-[8rem] text-right">크기</TableHead>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
) : (
|
</TableHeader>
|
||||||
esntlFileList.map((file) => (
|
<TableBody>
|
||||||
<TableRow key={file.esntlAtchFileId}>
|
{esntlFileList.length === 0 ? (
|
||||||
<TableCell className="pl-2 text-left">
|
<TableRow>
|
||||||
{file.esntlAtchFileNm}
|
<TableCell colSpan={3} className="py-12 text-center text-muted-foreground">
|
||||||
{file.esntlAtchYn === "Y" ? (
|
조회된 필수 첨부파일 항목이 없습니다.
|
||||||
<span className="ml-1 text-red-500">*</span>
|
|
||||||
) : null}
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="text-left">
|
|
||||||
{file.atflCd ? (
|
|
||||||
<a
|
|
||||||
className="cursor-pointer text-blue-600 hover:underline"
|
|
||||||
onClick={() => downloadAttachment(file.atflCd ?? "")}
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
{file.orgnlFileNm || "다운로드"}
|
|
||||||
</a>
|
|
||||||
) : (
|
|
||||||
<span className="text-gray-500">첨부없음</span>
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className="text-right">{formatFileSize(file.atflFlieSz)}</TableCell>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))
|
) : (
|
||||||
)}
|
esntlFileList.map((file) => (
|
||||||
</TableBody>
|
<TableRow key={file.esntlAtchFileId}>
|
||||||
</Table>
|
<TableCell className="pl-2 text-left">
|
||||||
</div>
|
{file.esntlAtchFileNm}
|
||||||
</SectionCollapsible>
|
{file.esntlAtchYn === "Y" ? (
|
||||||
|
<span className="ml-1 text-red-500">*</span>
|
||||||
|
) : null}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-left">
|
||||||
|
{file.atflCd ? (
|
||||||
|
<a
|
||||||
|
className="cursor-pointer text-blue-600 hover:underline"
|
||||||
|
onClick={() => downloadAttachment(file.atflCd ?? "")}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
{file.orgnlFileNm || "다운로드"}
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<span className="text-gray-500">첨부없음</span>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-right">
|
||||||
|
{formatFileSize(file.atflFlieSz)}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
</SectionCollapsible>
|
||||||
|
)}
|
||||||
|
|
||||||
<SectionCollapsible title="기타 첨부파일">
|
{etcFileList.length > 0 && (
|
||||||
<div className="overflow-x-auto">
|
<SectionCollapsible title="기타 첨부파일">
|
||||||
<Table variant="secondary">
|
<div className="overflow-x-auto">
|
||||||
<TableHeader>
|
<Table variant="secondary">
|
||||||
<TableRow>
|
<TableHeader>
|
||||||
<TableHead>파일명</TableHead>
|
|
||||||
<TableHead className="w-[8rem] text-right">크기</TableHead>
|
|
||||||
</TableRow>
|
|
||||||
</TableHeader>
|
|
||||||
<TableBody>
|
|
||||||
{etcFileList.length === 0 ? (
|
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={2} className="py-12 text-center text-muted-foreground">
|
<TableHead>파일명</TableHead>
|
||||||
등록된 기타첨부파일이 없습니다.
|
<TableHead className="w-[8rem] text-right">크기</TableHead>
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
) : (
|
</TableHeader>
|
||||||
etcFileList.map((file) => (
|
<TableBody>
|
||||||
<TableRow key={file.atflId}>
|
{etcFileList.length === 0 ? (
|
||||||
<TableCell className="text-left">
|
<TableRow>
|
||||||
{file.atflCd ? (
|
<TableCell colSpan={2} className="py-12 text-center text-muted-foreground">
|
||||||
<a
|
등록된 기타첨부파일이 없습니다.
|
||||||
className="cursor-pointer text-blue-600 hover:underline"
|
|
||||||
onClick={() => downloadAttachment(file.atflCd)}
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
{file.orgnlFileNm || file.physFileNm || file.atflId}
|
|
||||||
</a>
|
|
||||||
) : (
|
|
||||||
<span>{file.orgnlFileNm || file.physFileNm || file.atflId}</span>
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className="text-right text-gray-500">
|
|
||||||
{formatFileSize(file.atflFlieSz)}
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))
|
) : (
|
||||||
)}
|
etcFileList.map((file) => (
|
||||||
</TableBody>
|
<TableRow key={file.atflId}>
|
||||||
</Table>
|
<TableCell className="text-left">
|
||||||
</div>
|
{file.atflCd ? (
|
||||||
</SectionCollapsible>
|
<a
|
||||||
|
className="cursor-pointer text-blue-600 hover:underline"
|
||||||
|
onClick={() => downloadAttachment(file.atflCd)}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
{file.orgnlFileNm || file.physFileNm || file.atflId}
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<span>{file.orgnlFileNm || file.physFileNm || file.atflId}</span>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-right text-gray-500">
|
||||||
|
{formatFileSize(file.atflFlieSz)}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
</SectionCollapsible>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,10 @@ function ChecklistSection({
|
|||||||
|
|
||||||
const { total, completed, percent } = progress;
|
const { total, completed, percent } = progress;
|
||||||
|
|
||||||
|
if (cklstResultList.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionCollapsible title="체크리스트">
|
<SectionCollapsible title="체크리스트">
|
||||||
<div className="flex flex-col gap-4 p-2">
|
<div className="flex flex-col gap-4 p-2">
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
|
import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
|
||||||
|
|
||||||
|
import { Paperclip } from "lucide-react";
|
||||||
|
|
||||||
import { PROXY_HOST } from "@/shared/config";
|
import { PROXY_HOST } from "@/shared/config";
|
||||||
import { dayjs, getDefaultFileKey, useTus } from "@/shared/lib";
|
import { dayjs, getDefaultFileKey, useTus } from "@/shared/lib";
|
||||||
import { Field, FieldLabel, FieldSet } from "@/shared/ui/field";
|
import { Field, FieldLabel, FieldSet } from "@/shared/ui/field";
|
||||||
@@ -67,12 +69,10 @@ function hasFormContent(formData: ReviewOpinionFormData) {
|
|||||||
const TechReviewOpinionSection = forwardRef<
|
const TechReviewOpinionSection = forwardRef<
|
||||||
TechReviewOpinionSectionHandle,
|
TechReviewOpinionSectionHandle,
|
||||||
TechReviewOpinionSectionProps
|
TechReviewOpinionSectionProps
|
||||||
>(function TechReviewOpinionSection({
|
>(function TechReviewOpinionSection(
|
||||||
rvwList,
|
{ rvwList, editableReviewStep, atrzSeComCdList = [], isAtrzLoading = false },
|
||||||
editableReviewStep,
|
ref,
|
||||||
atrzSeComCdList = [],
|
) {
|
||||||
isAtrzLoading = false,
|
|
||||||
}, ref) {
|
|
||||||
const canWriteKecoOpinion = !isAtrzLoading && atrzSeComCdList.includes("ATRZ02");
|
const canWriteKecoOpinion = !isAtrzLoading && atrzSeComCdList.includes("ATRZ02");
|
||||||
const [formData, setFormData] = useState<ReviewOpinionFormData>({
|
const [formData, setFormData] = useState<ReviewOpinionFormData>({
|
||||||
...EMPTY_FORM_DATA,
|
...EMPTY_FORM_DATA,
|
||||||
@@ -329,11 +329,12 @@ function TechReviewOpinionTable({ items }: TechReviewOpinionTableProps) {
|
|||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
{item.atchFileInfo?.atflCd ? (
|
{item.atchFileInfo?.atflCd ? (
|
||||||
<a
|
<a
|
||||||
className="text-blue-600 hover:underline"
|
className="inline-flex cursor-pointer items-start gap-1 text-left text-blue-600 hover:underline"
|
||||||
href={`${PROXY_HOST}/attach-service/api/v1/atflcd/download/${item.atchFileInfo.atflCd}`}
|
href={`${PROXY_HOST}/attach-service/api/v1/atflcd/download/${item.atchFileInfo.atflCd}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>
|
>
|
||||||
|
<Paperclip className="my-1 size-5 shrink-0" />
|
||||||
{item.atchFileInfo.orgnlFileNm || "다운로드"}
|
{item.atchFileInfo.orgnlFileNm || "다운로드"}
|
||||||
</a>
|
</a>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
||||||
import type { IUserInfo } from "@/shared/store";
|
import type { IUserInfo } from "@/shared/store";
|
||||||
import type {
|
import type {
|
||||||
SewerBscPlanApplySaveRequestDto,
|
SewerBscPlanApplySaveRequestDto,
|
||||||
SewerBscPlanDetResponseDto,
|
SewerBscPlanDetResponseDto,
|
||||||
} from "@/entities/sewer-bsc-plan";
|
} from "@/entities/sewer-bsc-plan";
|
||||||
|
import { sewerBscPlanApplySaveSchema } from "@/entities/sewer-bsc-plan";
|
||||||
|
|
||||||
import type { BizCstMatrixItem } from "./biz-cst-matrix-utils";
|
import type { BizCstMatrixItem } from "./biz-cst-matrix-utils";
|
||||||
import { recalcFnrsCstSumAmt } from "./fnrs-cst-form-utils";
|
import { recalcFnrsCstSumAmt } from "./fnrs-cst-form-utils";
|
||||||
@@ -245,47 +245,33 @@ export function buildApplyPayload(
|
|||||||
prgrsSttsComCd: "SV" | "LE" | "TE",
|
prgrsSttsComCd: "SV" | "LE" | "TE",
|
||||||
options?: { isEditMode?: boolean; docNo?: string },
|
options?: { isEditMode?: boolean; docNo?: string },
|
||||||
): SewerBscPlanApplySaveRequestDto {
|
): SewerBscPlanApplySaveRequestDto {
|
||||||
const { taskSeComCd, ...sewerBscPlanRest } = data.sewerBscPlan;
|
const docNo = options?.isEditMode ? options.docNo : undefined;
|
||||||
|
|
||||||
return {
|
return sewerBscPlanApplySaveSchema.parse({
|
||||||
sewerBscPlan: {
|
sewerBscPlan: {
|
||||||
...sewerBscPlanRest,
|
...data.sewerBscPlan,
|
||||||
taskSeComCd: taskSeComCd ?? "",
|
sewerBscPlanDocNo: docNo,
|
||||||
sewerBscPlanDocNo: options?.isEditMode ? options.docNo : undefined,
|
taskSeComCd: data.sewerBscPlan.taskSeComCd ?? "",
|
||||||
prgrsSttsComCd,
|
prgrsSttsComCd,
|
||||||
},
|
},
|
||||||
sewerBscPlanDtl: {
|
sewerBscPlanDtl: {
|
||||||
...data.sewerBscPlanDtl,
|
...data.sewerBscPlanDtl,
|
||||||
sewerBscPlanDocNo: options?.isEditMode ? options.docNo : undefined,
|
sewerBscPlanDocNo: docNo,
|
||||||
},
|
},
|
||||||
sewerBscPlanOtlnList: data.sewerBscPlanOtlnList,
|
sewerBscPlanOtlnList: data.sewerBscPlanOtlnList,
|
||||||
bizCstList: data.bizCstList,
|
bizCstList: data.bizCstList,
|
||||||
fnrsCstList: data.fnrsCstList.map((item) => recalcFnrsCstSumAmt(item)),
|
fnrsCstList: data.fnrsCstList.map((item) => recalcFnrsCstSumAmt(item)),
|
||||||
sewerBscPlanTmplntList: data.sewerBscPlanTmplntList.map(
|
sewerBscPlanTmplntList: data.sewerBscPlanTmplntList,
|
||||||
({ atchFileNm, swtrmtFcltNm, ...item }) => ({
|
|
||||||
swtrmtFcltCd: item.swtrmtFcltCd,
|
|
||||||
atchFileGroupId: item.atchFileGroupId,
|
|
||||||
sewerBscPlanTmplntDtlList: item.sewerBscPlanTmplntDtlList,
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
cklstResultList: data.cklstResultList.map((item) => ({
|
cklstResultList: data.cklstResultList.map((item) => ({
|
||||||
...item,
|
...item,
|
||||||
selected: item.selected ?? undefined,
|
selected: item.selected ?? undefined,
|
||||||
})),
|
})),
|
||||||
esntlAtchFileList: data.esntlAtchFileList,
|
esntlAtchFileList: data.esntlAtchFileList,
|
||||||
splmntDmndList: data.splmntDmndList.map(
|
splmntDmndList: data.splmntDmndList.map((item) => ({
|
||||||
({
|
...item,
|
||||||
splmntArtclCdNm,
|
cmptnYn: prgrsSttsComCd === "TE" ? "Y" : item.cmptnYn,
|
||||||
splmntAtchFileNm,
|
})),
|
||||||
splmntAtchFileAtflId,
|
});
|
||||||
splmntDmndAtchFileNm,
|
|
||||||
...item
|
|
||||||
}) => ({
|
|
||||||
...item,
|
|
||||||
...(prgrsSttsComCd === "TE" ? { cmptnYn: "Y" } : null),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export { createEmptyTmplntDtlList };
|
export { createEmptyTmplntDtlList };
|
||||||
|
|||||||
+2
-4
@@ -146,10 +146,8 @@ export function buildSupplementReqPayload(
|
|||||||
toSplmntDmndSaveItem(item),
|
toSplmntDmndSaveItem(item),
|
||||||
);
|
);
|
||||||
|
|
||||||
const nextSn = existingItems.reduce((max, item) => Math.max(max, item.splmntDmndSn ?? 0), 0) + 1;
|
const newItems: SewerBscPlanSplmntDmndItem[] = payload.items.map((item) => ({
|
||||||
|
splmntDmndSn: null,
|
||||||
const newItems: SewerBscPlanSplmntDmndItem[] = payload.items.map((item, index) => ({
|
|
||||||
splmntDmndSn: nextSn + index,
|
|
||||||
splmntArtclComCd: item.splmntArtclComCd,
|
splmntArtclComCd: item.splmntArtclComCd,
|
||||||
splmntDmndCn: item.splmntDmndCn,
|
splmntDmndCn: item.splmntDmndCn,
|
||||||
splmntDmndAtchFileGroupId: item.splmntDmndAtchFileGroupId,
|
splmntDmndAtchFileGroupId: item.splmntDmndAtchFileGroupId,
|
||||||
@@ -1,38 +1,27 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
const tmplntDtlSchema = z.object({
|
import {
|
||||||
planStpNo: z.number(),
|
sewerBscPlanBizCstItemSchema,
|
||||||
swtrmtFcltCd: z.string(),
|
sewerBscPlanCklstResultItemSchema,
|
||||||
prcsZoneArea: z.number().optional(),
|
sewerBscPlanDtlSaveSchema,
|
||||||
swtrmtPpltnCnt: z.number().optional(),
|
sewerBscPlanEsntlAtchFileItemSchema,
|
||||||
planSwqty: z.number().optional(),
|
sewerBscPlanFnrsCstItemSchema,
|
||||||
fcltCpct: z.number().optional(),
|
sewerBscPlanOtlnItemSchema,
|
||||||
sprsysDrtwPplLen: z.number().optional(),
|
sewerBscPlanSaveSchema,
|
||||||
sprsysExlnPplLen: z.number().optional(),
|
sewerBscPlanSplmntDmndItemSchema,
|
||||||
cbsysPplLen: z.number().optional(),
|
sewerBscPlanTmplntDtlItemSchema,
|
||||||
icptgPplLen: z.number().optional(),
|
sewerBscPlanTmplntItemSchema,
|
||||||
drgCnt: z.number().optional(),
|
} from "@/entities/sewer-bsc-plan";
|
||||||
drtwRlyPumpCnt: z.number().optional(),
|
|
||||||
drtwPumpCnt: z.number().optional(),
|
|
||||||
exlnPumpCnt: z.number().optional(),
|
|
||||||
});
|
|
||||||
|
|
||||||
export const sewerBscPlanRegistSchema = z.object({
|
export const sewerBscPlanRegistSchema = z.object({
|
||||||
sewerBscPlan: z.object({
|
sewerBscPlan: sewerBscPlanSaveSchema.extend({
|
||||||
sewerBscPlanDocNo: z.string().optional(),
|
|
||||||
sewerBscPlanNm: z.string().min(1, "기본계획명은 필수입니다"),
|
sewerBscPlanNm: z.string().min(1, "기본계획명은 필수입니다"),
|
||||||
sewerBscPlanSeComCd: z.string().optional(),
|
|
||||||
sewerBscPlanSeCdNm: z.string().optional(),
|
sewerBscPlanSeCdNm: z.string().optional(),
|
||||||
taskSeComCd: z.string().optional(),
|
|
||||||
taskSeCdNm: z.string().optional(),
|
taskSeCdNm: z.string().optional(),
|
||||||
admdstCd: z.string().optional(),
|
|
||||||
envoSeComCd: z.string().optional(),
|
|
||||||
prgrsSttsComCd: z.string().optional(),
|
|
||||||
sido: z.string().optional(),
|
sido: z.string().optional(),
|
||||||
gugun: z.string().optional(),
|
gugun: z.string().nullish(),
|
||||||
}),
|
}),
|
||||||
sewerBscPlanDtl: z.object({
|
sewerBscPlanDtl: sewerBscPlanDtlSaveSchema.extend({
|
||||||
chgCycl: z.number().optional(),
|
|
||||||
planYr: z.string().min(1, "계획년도는 필수입니다"),
|
planYr: z.string().min(1, "계획년도는 필수입니다"),
|
||||||
crtrYr: z.string().min(1, "기준년도는 필수입니다"),
|
crtrYr: z.string().min(1, "기준년도는 필수입니다"),
|
||||||
frlvlGoalYr: z.string().min(1, "1단계 목표연도는 필수입니다"),
|
frlvlGoalYr: z.string().min(1, "1단계 목표연도는 필수입니다"),
|
||||||
@@ -40,10 +29,6 @@ export const sewerBscPlanRegistSchema = z.object({
|
|||||||
thlvlGoalYr: z.string().min(1, "3단계 목표연도는 필수입니다"),
|
thlvlGoalYr: z.string().min(1, "3단계 목표연도는 필수입니다"),
|
||||||
folvlGoalYr: z.string().min(1, "4단계 목표연도는 필수입니다"),
|
folvlGoalYr: z.string().min(1, "4단계 목표연도는 필수입니다"),
|
||||||
bizOtlnCn: z.string().min(1, "계획개요는 필수입니다"),
|
bizOtlnCn: z.string().min(1, "계획개요는 필수입니다"),
|
||||||
aplcntNm: z.string().optional(),
|
|
||||||
aplcntMblTelno: z.string().optional(),
|
|
||||||
aplcntOgdpNm: z.string().optional(),
|
|
||||||
aplcntEmlAddr: z.string().optional(),
|
|
||||||
dsgnrNm: z.string().min(1, "설계자 이름은 필수입니다"),
|
dsgnrNm: z.string().min(1, "설계자 이름은 필수입니다"),
|
||||||
dsgnrTelno: z
|
dsgnrTelno: z
|
||||||
.string()
|
.string()
|
||||||
@@ -54,74 +39,60 @@ export const sewerBscPlanRegistSchema = z.object({
|
|||||||
.string()
|
.string()
|
||||||
.min(1, "설계자 이메일은 필수입니다")
|
.min(1, "설계자 이메일은 필수입니다")
|
||||||
.email("올바른 이메일 형식이 아닙니다"),
|
.email("올바른 이메일 형식이 아닙니다"),
|
||||||
atchFileGroupId: z.string().optional(),
|
|
||||||
}),
|
}),
|
||||||
sewerBscPlanOtlnList: z.array(
|
sewerBscPlanOtlnList: z.array(
|
||||||
z.object({
|
sewerBscPlanOtlnItemSchema.extend({
|
||||||
planStpNo: z.number(),
|
planStpNo: z.number(),
|
||||||
sewerPlanPpltnCnt: z.number().optional(),
|
|
||||||
sewerPrcsPpltnCnt: z.number().optional(),
|
|
||||||
sewerPsplyRt: z.number().optional(),
|
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
bizCstList: z.array(
|
bizCstList: z.array(
|
||||||
z.object({
|
sewerBscPlanBizCstItemSchema.extend({
|
||||||
planStpNo: z.number(),
|
planStpNo: z.number(),
|
||||||
acntgSeCd: z.string(),
|
acntgSeCd: z.string(),
|
||||||
cstrnAmt: z.number(),
|
cstrnAmt: z.number(),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
fnrsCstList: z.array(
|
fnrsCstList: z.array(
|
||||||
z.object({
|
sewerBscPlanFnrsCstItemSchema.extend({
|
||||||
planStpNo: z.number(),
|
planStpNo: z.number(),
|
||||||
gvexpAmt: z.number().optional(),
|
|
||||||
lcexpAmt: z.number().optional(),
|
|
||||||
orgprBdchgAmt: z.number().optional(),
|
|
||||||
etcAmt: z.number().optional(),
|
|
||||||
sumAmt: z.number().optional(),
|
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
sewerBscPlanTmplntList: z.array(
|
sewerBscPlanTmplntList: z.array(
|
||||||
z.object({
|
sewerBscPlanTmplntItemSchema.extend({
|
||||||
swtrmtFcltCd: z.string(),
|
swtrmtFcltCd: z.string(),
|
||||||
swtrmtFcltNm: z.string().nullish(),
|
swtrmtFcltNm: z.string().nullish(),
|
||||||
atchFileGroupId: z.string().optional(),
|
|
||||||
atchFileNm: z.string().optional(),
|
atchFileNm: z.string().optional(),
|
||||||
sewerBscPlanTmplntDtlList: z.array(tmplntDtlSchema).optional(),
|
sewerBscPlanTmplntDtlList: z
|
||||||
|
.array(
|
||||||
|
sewerBscPlanTmplntDtlItemSchema.extend({
|
||||||
|
planStpNo: z.number(),
|
||||||
|
swtrmtFcltCd: z.string(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.optional(),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
cklstResultList: z.array(
|
cklstResultList: z.array(
|
||||||
z.object({
|
sewerBscPlanCklstResultItemSchema.extend({
|
||||||
cklstSn: z.number(),
|
cklstSn: z.number(),
|
||||||
cklstArtclSn: z.number(),
|
cklstArtclSn: z.number(),
|
||||||
cklstRvwSn: z.number(),
|
cklstRvwSn: z.number(),
|
||||||
rvwStpComCd: z.string(),
|
|
||||||
selected: z.enum(["Y", "N"]).nullable(),
|
selected: z.enum(["Y", "N"]).nullable(),
|
||||||
picRvwCn: z.string().nullable().optional(),
|
picRvwCn: z.string().nullable().optional(),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
esntlAtchFileList: z.array(
|
esntlAtchFileList: z.array(
|
||||||
z.object({
|
sewerBscPlanEsntlAtchFileItemSchema.extend({
|
||||||
esntlAtchFileId: z.string(),
|
esntlAtchFileId: z.string(),
|
||||||
atchFileGroupId: z.string(),
|
atchFileGroupId: z.string(),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
splmntDmndList: z.array(
|
splmntDmndList: z.array(
|
||||||
z.object({
|
sewerBscPlanSplmntDmndItemSchema.extend({
|
||||||
splmntDmndSn: z.number().optional(),
|
|
||||||
splmntArtclComCd: z.string().optional(),
|
|
||||||
splmntArtclCdNm: z.string().nullish(),
|
splmntArtclCdNm: z.string().nullish(),
|
||||||
splmntDmndCn: z.string().optional(),
|
|
||||||
splmntDmndDt: z.string().optional(),
|
|
||||||
splmntDmndAtchFileGroupId: z.string().optional(),
|
|
||||||
splmntDmndAtchFileNm: z.string().optional(),
|
splmntDmndAtchFileNm: z.string().optional(),
|
||||||
splmntCn: z.string().optional(),
|
|
||||||
splmntPicNm: z.string().optional(),
|
|
||||||
splmntCmptnDt: z.string().optional(),
|
|
||||||
splmntAtchFileGroupId: z.string().optional(),
|
|
||||||
splmntAtchFileNm: z.string().optional(),
|
splmntAtchFileNm: z.string().optional(),
|
||||||
splmntAtchFileAtflId: z.string().optional(),
|
splmntAtchFileAtflId: z.string().optional(),
|
||||||
cmptnYn: z.string().optional(),
|
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
privacyConsent: z.enum(["Y", "N"], {
|
privacyConsent: z.enum(["Y", "N"], {
|
||||||
@@ -130,6 +101,3 @@ export const sewerBscPlanRegistSchema = z.object({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export type SewerBscPlanRegistFormData = z.infer<typeof sewerBscPlanRegistSchema>;
|
export type SewerBscPlanRegistFormData = z.infer<typeof sewerBscPlanRegistSchema>;
|
||||||
|
|
||||||
/** 체크리스트·필수첨부 docSeComCd — CMS 합의 전 임시값 */
|
|
||||||
export const SEWER_BSC_PLAN_DOC_SE_COM_CD = "SEWER";
|
|
||||||
|
|||||||
@@ -46,8 +46,9 @@ function buildProgressBadges(prgrsSttsComCd: string, prgrsSttsCdNm: string): Pro
|
|||||||
return [
|
return [
|
||||||
{ label: MAIN_STEP_LABELS.save, state: "completed" },
|
{ label: MAIN_STEP_LABELS.save, state: "completed" },
|
||||||
{ label: MAIN_STEP_LABELS.apply, state: "completed" },
|
{ label: MAIN_STEP_LABELS.apply, state: "completed" },
|
||||||
{ label: MAIN_STEP_LABELS.envoReview, state: "completed" },
|
{ label: MAIN_STEP_LABELS.envoReview, state: "action" },
|
||||||
{ label: MAIN_STEP_LABELS.reply, state: "action" },
|
{ label: MAIN_STEP_LABELS.techReview, state: "pending" },
|
||||||
|
{ label: MAIN_STEP_LABELS.reply, state: "pending" },
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,8 +57,8 @@ function buildProgressBadges(prgrsSttsComCd: string, prgrsSttsCdNm: string): Pro
|
|||||||
{ label: MAIN_STEP_LABELS.save, state: "completed" },
|
{ label: MAIN_STEP_LABELS.save, state: "completed" },
|
||||||
{ label: MAIN_STEP_LABELS.apply, state: "completed" },
|
{ label: MAIN_STEP_LABELS.apply, state: "completed" },
|
||||||
{ label: MAIN_STEP_LABELS.envoReview, state: "completed" },
|
{ label: MAIN_STEP_LABELS.envoReview, state: "completed" },
|
||||||
{ label: MAIN_STEP_LABELS.techReview, state: "pending" },
|
|
||||||
{ label: MAIN_STEP_LABELS.supplement, state: "action" },
|
{ label: MAIN_STEP_LABELS.supplement, state: "action" },
|
||||||
|
{ label: MAIN_STEP_LABELS.reply, state: "pending" },
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,16 +72,6 @@ function buildProgressBadges(prgrsSttsComCd: string, prgrsSttsCdNm: string): Pro
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prgrsSttsComCd === "EP") {
|
|
||||||
return [
|
|
||||||
{ label: MAIN_STEP_LABELS.save, state: "completed" },
|
|
||||||
{ label: MAIN_STEP_LABELS.apply, state: "completed" },
|
|
||||||
{ label: MAIN_STEP_LABELS.envoReview, state: "completed" },
|
|
||||||
{ label: MAIN_STEP_LABELS.techReview, state: "completed" },
|
|
||||||
{ label: replyLabel, state: "action" },
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (prgrsSttsComCd === "TA") {
|
if (prgrsSttsComCd === "TA") {
|
||||||
return [
|
return [
|
||||||
{ label: MAIN_STEP_LABELS.save, state: "completed" },
|
{ label: MAIN_STEP_LABELS.save, state: "completed" },
|
||||||
@@ -91,6 +82,16 @@ function buildProgressBadges(prgrsSttsComCd: string, prgrsSttsCdNm: string): Pro
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prgrsSttsComCd === "EP") {
|
||||||
|
return [
|
||||||
|
{ label: MAIN_STEP_LABELS.save, state: "completed" },
|
||||||
|
{ label: MAIN_STEP_LABELS.apply, state: "completed" },
|
||||||
|
{ label: MAIN_STEP_LABELS.envoReview, state: "completed" },
|
||||||
|
{ label: MAIN_STEP_LABELS.techReview, state: "completed" },
|
||||||
|
{ label: replyLabel, state: "completed" },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
return [{ label: prgrsSttsCdNm || prgrsSttsComCd || "-", state: "current" }];
|
return [{ label: prgrsSttsCdNm || prgrsSttsComCd || "-", state: "current" }];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ import {
|
|||||||
buildSupplementReqPayload,
|
buildSupplementReqPayload,
|
||||||
buildTechReviewReplyPayload,
|
buildTechReviewReplyPayload,
|
||||||
toSplmntDmndSaveItem,
|
toSplmntDmndSaveItem,
|
||||||
} from "../../lib/save-payload-utils";
|
} from "../../lib/payload-utils";
|
||||||
import { type ChecklistFormState } from "../../model/view-types";
|
import { type ChecklistFormState } from "../../model/view-types";
|
||||||
import type { TechReviewOpinionSectionHandle } from "../sections/tech-review-opinion-section";
|
import type { TechReviewOpinionSectionHandle } from "../sections/tech-review-opinion-section";
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
|
import { Paperclip } from "lucide-react";
|
||||||
|
|
||||||
import { formatFileSize } from "@/shared/lib/file-utils";
|
import { formatFileSize } from "@/shared/lib/file-utils";
|
||||||
import { useDownloadAttachmentByAtflCd } from "@/entities/attach";
|
import { useDownloadAttachmentByAtflCd } from "@/entities/attach";
|
||||||
import type {
|
import type {
|
||||||
@@ -19,98 +21,105 @@ function AttachmentsSection({ esntlFileList, etcFileList }: AttachmentsSectionPr
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SectionCollapsible title="필수 첨부파일">
|
{esntlFileList.length > 0 && (
|
||||||
<div className="overflow-x-auto">
|
<SectionCollapsible title="필수 첨부파일">
|
||||||
<Table variant="secondary">
|
<div className="overflow-x-auto">
|
||||||
<TableHeader>
|
<Table variant="secondary">
|
||||||
<TableRow>
|
<TableHeader>
|
||||||
<TableHead>필수 자료명</TableHead>
|
|
||||||
<TableHead>파일명</TableHead>
|
|
||||||
<TableHead className="w-[8rem] text-right">크기</TableHead>
|
|
||||||
</TableRow>
|
|
||||||
</TableHeader>
|
|
||||||
<TableBody>
|
|
||||||
{esntlFileList.length === 0 ? (
|
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={3} className="py-12 text-center text-muted-foreground">
|
<TableHead>필수 자료명</TableHead>
|
||||||
조회된 필수 첨부파일 항목이 없습니다.
|
<TableHead>파일명</TableHead>
|
||||||
</TableCell>
|
<TableHead className="w-[8rem] text-right">크기</TableHead>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
) : (
|
</TableHeader>
|
||||||
esntlFileList.map((file) => (
|
<TableBody>
|
||||||
<TableRow key={file.esntlAtchFileId}>
|
{esntlFileList.length === 0 ? (
|
||||||
<TableCell className="pl-2 text-left">
|
<TableRow>
|
||||||
{file.esntlAtchFileNm}
|
<TableCell colSpan={3} className="py-12 text-center text-muted-foreground">
|
||||||
{file.esntlAtchYn === "Y" ? (
|
조회된 필수 첨부파일 항목이 없습니다.
|
||||||
<span className="ml-1 text-red-500">*</span>
|
|
||||||
) : null}
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="text-left">
|
|
||||||
{file.atflCd ? (
|
|
||||||
<a
|
|
||||||
className="cursor-pointer text-blue-600 hover:underline"
|
|
||||||
onClick={() => downloadAttachment(file.atflCd ?? "")}
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
{file.orgnlFileNm || "다운로드"}
|
|
||||||
</a>
|
|
||||||
) : (
|
|
||||||
<span className="text-gray-500">첨부없음</span>
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className="text-right">{formatFileSize(file.atflFlieSz)}</TableCell>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))
|
) : (
|
||||||
)}
|
esntlFileList.map((file) => (
|
||||||
</TableBody>
|
<TableRow key={file.esntlAtchFileId}>
|
||||||
</Table>
|
<TableCell className="pl-2 text-left">
|
||||||
</div>
|
{file.esntlAtchFileNm}
|
||||||
</SectionCollapsible>
|
{file.esntlAtchYn === "Y" ? (
|
||||||
|
<span className="ml-1 text-red-500">*</span>
|
||||||
|
) : null}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-left">
|
||||||
|
{file.atflCd ? (
|
||||||
|
<a
|
||||||
|
className="inline-flex cursor-pointer items-center gap-1 text-blue-600 hover:underline"
|
||||||
|
onClick={() => downloadAttachment(file.atflCd ?? "")}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
<Paperclip className="size-5 shrink-0" />
|
||||||
|
{file.orgnlFileNm || "다운로드"}
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<span className="text-gray-500">첨부없음</span>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-right">
|
||||||
|
{formatFileSize(file.atflFlieSz)}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
</SectionCollapsible>
|
||||||
|
)}
|
||||||
|
|
||||||
<SectionCollapsible title="기타 첨부파일">
|
{etcFileList.length > 0 && (
|
||||||
<div className="overflow-x-auto">
|
<SectionCollapsible title="기타 첨부파일">
|
||||||
<Table variant="secondary">
|
<div className="overflow-x-auto">
|
||||||
<TableHeader>
|
<Table variant="secondary">
|
||||||
<TableRow>
|
<TableHeader>
|
||||||
<TableHead>파일명</TableHead>
|
|
||||||
<TableHead className="w-[8rem] text-right">크기</TableHead>
|
|
||||||
</TableRow>
|
|
||||||
</TableHeader>
|
|
||||||
<TableBody>
|
|
||||||
{etcFileList.length === 0 ? (
|
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={2} className="py-12 text-center text-muted-foreground">
|
<TableHead>파일명</TableHead>
|
||||||
등록된 기타첨부파일이 없습니다.
|
<TableHead className="w-[8rem] text-right">크기</TableHead>
|
||||||
</TableCell>
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
) : (
|
</TableHeader>
|
||||||
etcFileList.map((file) => (
|
<TableBody>
|
||||||
<TableRow key={file.atflId}>
|
{etcFileList.length === 0 ? (
|
||||||
<TableCell className="text-left">
|
<TableRow>
|
||||||
{file.atflCd ? (
|
<TableCell colSpan={2} className="py-12 text-center text-muted-foreground">
|
||||||
<a
|
등록된 기타첨부파일이 없습니다.
|
||||||
className="cursor-pointer text-blue-600 hover:underline"
|
|
||||||
onClick={() => downloadAttachment(file.atflCd)}
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
{file.orgnlFileNm || file.physFileNm || file.atflId}
|
|
||||||
</a>
|
|
||||||
) : (
|
|
||||||
<span>{file.orgnlFileNm || file.physFileNm || file.atflId}</span>
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className="text-right text-gray-500">
|
|
||||||
{formatFileSize(file.atflFlieSz)}
|
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))
|
) : (
|
||||||
)}
|
etcFileList.map((file) => (
|
||||||
</TableBody>
|
<TableRow key={file.atflId}>
|
||||||
</Table>
|
<TableCell className="text-left">
|
||||||
</div>
|
{file.atflCd ? (
|
||||||
</SectionCollapsible>
|
<a
|
||||||
|
className="cursor-pointer text-blue-600 hover:underline"
|
||||||
|
onClick={() => downloadAttachment(file.atflCd)}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
{file.orgnlFileNm || file.physFileNm || file.atflId}
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<span>{file.orgnlFileNm || file.physFileNm || file.atflId}</span>
|
||||||
|
)}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-right text-gray-500">
|
||||||
|
{formatFileSize(file.atflFlieSz)}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
</SectionCollapsible>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import { Controller, useFormContext } from "react-hook-form";
|
import { Controller, useFormContext } from "react-hook-form";
|
||||||
|
|
||||||
|
import { useUserStore } from "@/shared/lib";
|
||||||
import { Field, FieldError } from "@/shared/ui/field";
|
import { Field, FieldError } from "@/shared/ui/field";
|
||||||
import { SectionCollapsible } from "@/widgets/pbadms-sprt";
|
import { SectionCollapsible } from "@/widgets/pbadms-sprt";
|
||||||
import {
|
import {
|
||||||
@@ -23,6 +24,7 @@ import type { SewerBscPlanRegistFormData } from "../../lib/sewer-bsc-plan-regist
|
|||||||
import { getGoalYearOptions, getLinkedGoalYears, getPlanYearOptions } from "../../lib/year-options";
|
import { getGoalYearOptions, getLinkedGoalYears, getPlanYearOptions } from "../../lib/year-options";
|
||||||
|
|
||||||
function BasicInfoFormSection() {
|
function BasicInfoFormSection() {
|
||||||
|
const userInfo = useUserStore((state) => state.userInfo);
|
||||||
const { control, setValue, watch } = useFormContext<SewerBscPlanRegistFormData>();
|
const { control, setValue, watch } = useFormContext<SewerBscPlanRegistFormData>();
|
||||||
const planYearOptions = getPlanYearOptions();
|
const planYearOptions = getPlanYearOptions();
|
||||||
const goalYearOptions = getGoalYearOptions();
|
const goalYearOptions = getGoalYearOptions();
|
||||||
@@ -265,7 +267,7 @@ function BasicInfoFormSection() {
|
|||||||
<TableHead>구분</TableHead>
|
<TableHead>구분</TableHead>
|
||||||
<TableCell>{sewerBscPlanSeLabel}</TableCell>
|
<TableCell>{sewerBscPlanSeLabel}</TableCell>
|
||||||
<TableHead>신청 지자체</TableHead>
|
<TableHead>신청 지자체</TableHead>
|
||||||
<TableCell>{localGovLabel}</TableCell>
|
<TableCell>{localGovLabel || userInfo?.laeSeNm}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
</Table>
|
</Table>
|
||||||
|
|||||||
@@ -71,6 +71,10 @@ function ChecklistSection({
|
|||||||
|
|
||||||
const { total, completed, percent } = progress;
|
const { total, completed, percent } = progress;
|
||||||
|
|
||||||
|
if (cklstResultList.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionCollapsible title="체크리스트">
|
<SectionCollapsible title="체크리스트">
|
||||||
<div className="flex flex-col gap-4 p-2">
|
<div className="flex flex-col gap-4 p-2">
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
|
import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
|
||||||
|
|
||||||
|
import { Paperclip } from "lucide-react";
|
||||||
|
|
||||||
import { PROXY_HOST } from "@/shared/config";
|
import { PROXY_HOST } from "@/shared/config";
|
||||||
import { dayjs, getDefaultFileKey, useTus } from "@/shared/lib";
|
import { dayjs, getDefaultFileKey, useTus } from "@/shared/lib";
|
||||||
import { Field, FieldLabel, FieldSet } from "@/shared/ui/field";
|
import { Field, FieldLabel, FieldSet } from "@/shared/ui/field";
|
||||||
@@ -334,11 +336,12 @@ function TechReviewOpinionTable({ items }: TechReviewOpinionTableProps) {
|
|||||||
<TableCell align="center">
|
<TableCell align="center">
|
||||||
{item.atchFileInfo?.atflCd ? (
|
{item.atchFileInfo?.atflCd ? (
|
||||||
<a
|
<a
|
||||||
className="text-blue-600 hover:underline"
|
className="inline-flex cursor-pointer items-start gap-1 text-left text-blue-600 hover:underline"
|
||||||
href={`${PROXY_HOST}/attach-service/api/v1/atflcd/download/${item.atchFileInfo.atflCd}`}
|
href={`${PROXY_HOST}/attach-service/api/v1/atflcd/download/${item.atchFileInfo.atflCd}`}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>
|
>
|
||||||
|
<Paperclip className="my-1 size-5 shrink-0" />
|
||||||
{item.atchFileInfo.orgnlFileNm || "다운로드"}
|
{item.atchFileInfo.orgnlFileNm || "다운로드"}
|
||||||
</a>
|
</a>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -4,11 +4,10 @@ import { useId, useMemo, useState } from "react";
|
|||||||
import { Controller, useFieldArray, useFormContext, useWatch } from "react-hook-form";
|
import { Controller, useFieldArray, useFormContext, useWatch } from "react-hook-form";
|
||||||
|
|
||||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||||
import { Paperclip } from "lucide-react";
|
|
||||||
|
|
||||||
import { getDefaultFileKey, useTus } from "@/shared/lib";
|
import { getDefaultFileKey, useTus } from "@/shared/lib";
|
||||||
import { Field } from "@/shared/ui/field";
|
import { Field } from "@/shared/ui/field";
|
||||||
import { attachService, useDownloadAttachmentByAtflCd } from "@/entities/attach";
|
import { attachService } from "@/entities/attach";
|
||||||
import { useFacilityList } from "@/entities/bns-if";
|
import { useFacilityList } from "@/entities/bns-if";
|
||||||
import { useNowDmgMtncGnsvy } from "@/entities/dc";
|
import { useNowDmgMtncGnsvy } from "@/entities/dc";
|
||||||
import { SectionCollapsible } from "@/widgets/pbadms-sprt";
|
import { SectionCollapsible } from "@/widgets/pbadms-sprt";
|
||||||
@@ -226,7 +225,6 @@ function TmplntFacilityAttachments({
|
|||||||
}: TmplntFacilityAttachmentsProps) {
|
}: TmplntFacilityAttachmentsProps) {
|
||||||
const formId = useId();
|
const formId = useId();
|
||||||
const { setValue } = useFormContext<SewerBscPlanRegistFormData>();
|
const { setValue } = useFormContext<SewerBscPlanRegistFormData>();
|
||||||
const { mutate: downloadAttachment } = useDownloadAttachmentByAtflCd();
|
|
||||||
const [uploadedFile, setUploadedFile] = useState<UploadedTmplntFile | null>(() =>
|
const [uploadedFile, setUploadedFile] = useState<UploadedTmplntFile | null>(() =>
|
||||||
atchFileGroupId && atchFileNm
|
atchFileGroupId && atchFileNm
|
||||||
? {
|
? {
|
||||||
@@ -254,7 +252,6 @@ function TmplntFacilityAttachments({
|
|||||||
const fileInputId = `${formId}-tmplnt-atch-${facilityIndex}`;
|
const fileInputId = `${formId}-tmplnt-atch-${facilityIndex}`;
|
||||||
const uploading = uploadedFile ? (isUploading[uploadedFile.fileKey] ?? false) : false;
|
const uploading = uploadedFile ? (isUploading[uploadedFile.fileKey] ?? false) : false;
|
||||||
const displayFileName = uploadedFile?.fileName ?? atchFileNm ?? "";
|
const displayFileName = uploadedFile?.fileName ?? atchFileNm ?? "";
|
||||||
const downloadAtflCd = uploadedFile?.atflCd || atchFileGroupId;
|
|
||||||
const hasFile = Boolean(uploadedFile || atchFileNm);
|
const hasFile = Boolean(uploadedFile || atchFileNm);
|
||||||
|
|
||||||
async function handleFileUpload(files: FileList | null) {
|
async function handleFileUpload(files: FileList | null) {
|
||||||
@@ -315,22 +312,14 @@ function TmplntFacilityAttachments({
|
|||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell>{facilityName} 계획평면도</TableCell>
|
<TableHead data-required align="left">
|
||||||
|
{facilityName} 계획평면도
|
||||||
|
</TableHead>
|
||||||
<TableCell className="text-center">{TMPLNT_ATCH_FORMAT_LABEL}</TableCell>
|
<TableCell className="text-center">{TMPLNT_ATCH_FORMAT_LABEL}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
{hasFile ? (
|
{hasFile ? (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{downloadAtflCd ? (
|
<span className="text-xl">{displayFileName}</span>
|
||||||
<a
|
|
||||||
className="inline-flex cursor-pointer items-center gap-1 text-blue-600 hover:underline"
|
|
||||||
onClick={() => downloadAttachment(downloadAtflCd)}
|
|
||||||
>
|
|
||||||
<Paperclip className="size-5 shrink-0" />
|
|
||||||
{displayFileName}
|
|
||||||
</a>
|
|
||||||
) : (
|
|
||||||
<span className="text-xl">{displayFileName}</span>
|
|
||||||
)}
|
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
size="icon"
|
size="icon"
|
||||||
|
|||||||
@@ -245,6 +245,10 @@ function TmplntSection({ tmplntList, det, dtl }: TmplntSectionProps) {
|
|||||||
<div className="mt-6 space-y-2">
|
<div className="mt-6 space-y-2">
|
||||||
<h3 className="mb-4 text-xl font-semibold">처리구역 필수 첨부파일</h3>
|
<h3 className="mb-4 text-xl font-semibold">처리구역 필수 첨부파일</h3>
|
||||||
<Table variant="secondary">
|
<Table variant="secondary">
|
||||||
|
<colgroup>
|
||||||
|
<col width="35%" />
|
||||||
|
<col width="65%" />
|
||||||
|
</colgroup>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead align="left">파일명</TableHead>
|
<TableHead align="left">파일명</TableHead>
|
||||||
|
|||||||
@@ -79,7 +79,9 @@ function SewerBscPlanApplyDialog({ open, onOpenChange, onConfirm }: SewerBscPlan
|
|||||||
setTaskSeComCd("");
|
setTaskSeComCd("");
|
||||||
}, [open]);
|
}, [open]);
|
||||||
|
|
||||||
const canConfirm = Boolean(sidoComCd && sewerBscPlanSeComCd && taskSeComCd);
|
const canSidoGugunSelectable = userInfo?.dtlInstCd !== "ROLE_USER05";
|
||||||
|
const canConfirm =
|
||||||
|
!!sewerBscPlanSeComCd && !!taskSeComCd && (!canSidoGugunSelectable || !!sidoComCd);
|
||||||
|
|
||||||
function handleConfirm() {
|
function handleConfirm() {
|
||||||
if (!canConfirm) return;
|
if (!canConfirm) return;
|
||||||
@@ -118,48 +120,50 @@ function SewerBscPlanApplyDialog({ open, onOpenChange, onConfirm }: SewerBscPlan
|
|||||||
<col width="35%" />
|
<col width="35%" />
|
||||||
</colgroup>
|
</colgroup>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
{canSidoGugunSelectable && (
|
||||||
<TableHead data-required>시도</TableHead>
|
<TableRow>
|
||||||
<TableCell>
|
<TableHead data-required>시도</TableHead>
|
||||||
<Select
|
<TableCell>
|
||||||
value={sidoComCd || undefined}
|
<Select
|
||||||
onValueChange={(value) => {
|
value={sidoComCd || undefined}
|
||||||
setSidoComCd(value);
|
onValueChange={(value) => {
|
||||||
setSggComCd("");
|
setSidoComCd(value);
|
||||||
}}
|
setSggComCd("");
|
||||||
>
|
}}
|
||||||
<SelectTrigger className="w-full">
|
>
|
||||||
<SelectValue placeholder="선택" />
|
<SelectTrigger className="w-full">
|
||||||
</SelectTrigger>
|
<SelectValue placeholder="선택" />
|
||||||
<SelectContent>
|
</SelectTrigger>
|
||||||
{sidoOptions.map((option) => (
|
<SelectContent>
|
||||||
<SelectItem key={option.adstDstrCd} value={option.adstDstrCd}>
|
{sidoOptions.map((option) => (
|
||||||
{option.adstDstrNm}
|
<SelectItem key={option.adstDstrCd} value={option.adstDstrCd}>
|
||||||
</SelectItem>
|
{option.adstDstrNm}
|
||||||
))}
|
</SelectItem>
|
||||||
</SelectContent>
|
))}
|
||||||
</Select>
|
</SelectContent>
|
||||||
</TableCell>
|
</Select>
|
||||||
<TableHead>시군구</TableHead>
|
</TableCell>
|
||||||
<TableCell>
|
<TableHead>시군구</TableHead>
|
||||||
<Select
|
<TableCell>
|
||||||
value={sggComCd || undefined}
|
<Select
|
||||||
onValueChange={setSggComCd}
|
value={sggComCd || undefined}
|
||||||
disabled={!sidoComCd || isGugunPending}
|
onValueChange={setSggComCd}
|
||||||
>
|
disabled={!sidoComCd || isGugunPending}
|
||||||
<SelectTrigger className="w-full">
|
>
|
||||||
<SelectValue placeholder="선택" />
|
<SelectTrigger className="w-full">
|
||||||
</SelectTrigger>
|
<SelectValue placeholder="선택" />
|
||||||
<SelectContent>
|
</SelectTrigger>
|
||||||
{gugunOptions.map((option) => (
|
<SelectContent>
|
||||||
<SelectItem key={option.adstDstrCd} value={option.adstDstrCd}>
|
{gugunOptions.map((option) => (
|
||||||
{option.adstDstrNm}
|
<SelectItem key={option.adstDstrCd} value={option.adstDstrCd}>
|
||||||
</SelectItem>
|
{option.adstDstrNm}
|
||||||
))}
|
</SelectItem>
|
||||||
</SelectContent>
|
))}
|
||||||
</Select>
|
</SelectContent>
|
||||||
</TableCell>
|
</Select>
|
||||||
</TableRow>
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead data-required>계획구분</TableHead>
|
<TableHead data-required>계획구분</TableHead>
|
||||||
<TableCell colSpan={3}>
|
<TableCell colSpan={3}>
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import { useQueryClient } from "@tanstack/react-query";
|
|||||||
|
|
||||||
import { useAlertStore, useUserStore } from "@/shared/lib";
|
import { useAlertStore, useUserStore } from "@/shared/lib";
|
||||||
import { useAcntgSeMngTree } from "@/entities/acntg";
|
import { useAcntgSeMngTree } from "@/entities/acntg";
|
||||||
|
import { useEsntlAtchFileMngTree } from "@/entities/esntl";
|
||||||
import {
|
import {
|
||||||
SewerBscPlanApplySaveResponseDto,
|
SewerBscPlanApplySaveResponseDto,
|
||||||
sewerBscPlanBaseKey,
|
sewerBscPlanBaseKey,
|
||||||
@@ -22,6 +23,7 @@ import {
|
|||||||
ChecklistFormSection,
|
ChecklistFormSection,
|
||||||
ContactInfoFormSection,
|
ContactInfoFormSection,
|
||||||
isFormChecklistComplete,
|
isFormChecklistComplete,
|
||||||
|
isFormEsntlAtchComplete,
|
||||||
PrivacyConsentSection,
|
PrivacyConsentSection,
|
||||||
SplmntDmndFormSection,
|
SplmntDmndFormSection,
|
||||||
} from "@/widgets/pbadms-sprt";
|
} from "@/widgets/pbadms-sprt";
|
||||||
@@ -34,7 +36,6 @@ import {
|
|||||||
mapDetailToFormData,
|
mapDetailToFormData,
|
||||||
} from "../lib/form-data-mapper";
|
} from "../lib/form-data-mapper";
|
||||||
import {
|
import {
|
||||||
SEWER_BSC_PLAN_DOC_SE_COM_CD,
|
|
||||||
type SewerBscPlanRegistFormData,
|
type SewerBscPlanRegistFormData,
|
||||||
sewerBscPlanRegistSchema,
|
sewerBscPlanRegistSchema,
|
||||||
} from "../lib/sewer-bsc-plan-regist-schema";
|
} from "../lib/sewer-bsc-plan-regist-schema";
|
||||||
@@ -76,6 +77,7 @@ function SewerBscPlanFormPage({
|
|||||||
const isSplmntPrgrsStts = initialData?.detDto?.prgrsSttsComCd === "SL";
|
const isSplmntPrgrsStts = initialData?.detDto?.prgrsSttsComCd === "SL";
|
||||||
|
|
||||||
const { data: acntgTree = [] } = useAcntgSeMngTree();
|
const { data: acntgTree = [] } = useAcntgSeMngTree();
|
||||||
|
const { data: essentialFiles = [] } = useEsntlAtchFileMngTree({ docSeComCd: "SEWER" });
|
||||||
const costItems = useMemo(() => buildAcntgCostItems(acntgTree), [acntgTree]);
|
const costItems = useMemo(() => buildAcntgCostItems(acntgTree), [acntgTree]);
|
||||||
|
|
||||||
const form = useForm<SewerBscPlanRegistFormData>({
|
const form = useForm<SewerBscPlanRegistFormData>({
|
||||||
@@ -140,11 +142,21 @@ function SewerBscPlanFormPage({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.sewerBscPlanTmplntList.some((item) => !item.atchFileGroupId?.trim())) {
|
||||||
|
alert("처리구역 필수 첨부파일을 모두 등록해야 신청이 가능합니다.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isFormChecklistComplete(data.cklstResultList)) {
|
if (!isFormChecklistComplete(data.cklstResultList)) {
|
||||||
alert("모든 체크리스트 항목을 체크해야 신청이 가능합니다.");
|
alert("모든 체크리스트 항목을 체크해야 신청이 가능합니다.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isFormEsntlAtchComplete(essentialFiles, data.esntlAtchFileList)) {
|
||||||
|
alert("필수 첨부파일을 모두 등록해야 신청이 가능합니다.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setIsSubmitting(true);
|
setIsSubmitting(true);
|
||||||
const result = await submitForm(data, "LE");
|
const result = await submitForm(data, "LE");
|
||||||
@@ -237,12 +249,9 @@ function SewerBscPlanFormPage({
|
|||||||
<BizCstMatrixFormSection />
|
<BizCstMatrixFormSection />
|
||||||
<FnrsCstFormSection />
|
<FnrsCstFormSection />
|
||||||
<TmplntFormSection />
|
<TmplntFormSection />
|
||||||
<ChecklistFormSection
|
<ChecklistFormSection docSeComCd="SEWER" fieldPrefix="sewerBscPlan" />
|
||||||
docSeComCd={SEWER_BSC_PLAN_DOC_SE_COM_CD}
|
|
||||||
fieldPrefix="sewerBscPlan"
|
|
||||||
/>
|
|
||||||
<AttachmentsFormSection
|
<AttachmentsFormSection
|
||||||
docSeComCd={SEWER_BSC_PLAN_DOC_SE_COM_CD}
|
docSeComCd="SEWER"
|
||||||
fieldPrefix="sewerBscPlanDtl"
|
fieldPrefix="sewerBscPlanDtl"
|
||||||
initialEsntlFiles={isEditMode ? initialData?.esntlFileList : undefined}
|
initialEsntlFiles={isEditMode ? initialData?.esntlFileList : undefined}
|
||||||
initialEtcFiles={isEditMode ? initialData?.etcFileList : undefined}
|
initialEtcFiles={isEditMode ? initialData?.etcFileList : undefined}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import { Skeleton } from "@common/components";
|
|||||||
|
|
||||||
import { needsRoleUser01AtrzResolve } from "../lib/button-config";
|
import { needsRoleUser01AtrzResolve } from "../lib/button-config";
|
||||||
import { getEditableReviewStep } from "../lib/review-step-utils";
|
import { getEditableReviewStep } from "../lib/review-step-utils";
|
||||||
import { SEWER_BSC_PLAN_DOC_SE_COM_CD } from "../lib/sewer-bsc-plan-regist-schema";
|
|
||||||
import { EMPTY_CKLST_RESULT_LIST, useChecklistFormState } from "../lib/use-checklist-form-state";
|
import { EMPTY_CKLST_RESULT_LIST, useChecklistFormState } from "../lib/use-checklist-form-state";
|
||||||
|
|
||||||
import { FloatingActionButtons } from "./components/floating-action-buttons";
|
import { FloatingActionButtons } from "./components/floating-action-buttons";
|
||||||
@@ -121,7 +120,7 @@ function SewerBscPlanViewPage({ id, propChgCycl }: SewerBscPlanViewPageProps) {
|
|||||||
/>
|
/>
|
||||||
<FloatingActionButtons
|
<FloatingActionButtons
|
||||||
data={data}
|
data={data}
|
||||||
docSeComCd={SEWER_BSC_PLAN_DOC_SE_COM_CD}
|
docSeComCd="SEWER"
|
||||||
sewerBscPlanDocNo={detDto.sewerBscPlanDocNo}
|
sewerBscPlanDocNo={detDto.sewerBscPlanDocNo}
|
||||||
chgCycl={chgCycl}
|
chgCycl={chgCycl}
|
||||||
prgrsSttsComCd={detDto.prgrsSttsComCd || ""}
|
prgrsSttsComCd={detDto.prgrsSttsComCd || ""}
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ export interface EsntlAtchFileSaveBase {
|
|||||||
|
|
||||||
/** 보완요구 저장 공통 필드 */
|
/** 보완요구 저장 공통 필드 */
|
||||||
export interface SplmntDmndSaveBase {
|
export interface SplmntDmndSaveBase {
|
||||||
splmntDmndSn?: number;
|
splmntDmndSn?: number | null;
|
||||||
splmntArtclComCd?: string;
|
splmntArtclComCd?: string;
|
||||||
splmntDmndCn?: string;
|
splmntDmndCn?: string;
|
||||||
splmntDmndDt?: string;
|
splmntDmndDt?: string;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ export {
|
|||||||
createEtcUploadKey,
|
createEtcUploadKey,
|
||||||
createUploadKey,
|
createUploadKey,
|
||||||
isEtcFileKey,
|
isEtcFileKey,
|
||||||
|
isFormEsntlAtchComplete,
|
||||||
} from "./lib/attachments-form-utils";
|
} from "./lib/attachments-form-utils";
|
||||||
export {
|
export {
|
||||||
buildAcntgCostItems,
|
buildAcntgCostItems,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { getDefaultFileKey } from "@/shared/lib";
|
import { getDefaultFileKey } from "@/shared/lib";
|
||||||
|
import type { EsntlAtchFileMngTreeResponseDto } from "@/shared/model";
|
||||||
|
|
||||||
export type FieldPrefix =
|
export type FieldPrefix =
|
||||||
| "fnrsCnsltnMng"
|
| "fnrsCnsltnMng"
|
||||||
@@ -9,6 +10,11 @@ export type FieldPrefix =
|
|||||||
|
|
||||||
export const ETC_FILE_KEY_PREFIX = "etc::";
|
export const ETC_FILE_KEY_PREFIX = "etc::";
|
||||||
|
|
||||||
|
interface EsntlAtchFileListItem {
|
||||||
|
esntlAtchFileId: string;
|
||||||
|
atchFileGroupId: string;
|
||||||
|
}
|
||||||
|
|
||||||
export function atchFileGroupIdPath(fieldPrefix: FieldPrefix): string {
|
export function atchFileGroupIdPath(fieldPrefix: FieldPrefix): string {
|
||||||
return `${fieldPrefix}.atchFileGroupId`;
|
return `${fieldPrefix}.atchFileGroupId`;
|
||||||
}
|
}
|
||||||
@@ -35,3 +41,21 @@ export function toFileAccept(rmrk: string | null | undefined): string {
|
|||||||
.map((ext) => (ext.startsWith(".") ? ext : `.${ext}`))
|
.map((ext) => (ext.startsWith(".") ? ext : `.${ext}`))
|
||||||
.join(",");
|
.join(",");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isFormEsntlAtchComplete(
|
||||||
|
essentialFiles: EsntlAtchFileMngTreeResponseDto[],
|
||||||
|
esntlAtchFileList: EsntlAtchFileListItem[],
|
||||||
|
): boolean {
|
||||||
|
if (essentialFiles.length === 0) return true;
|
||||||
|
|
||||||
|
const requiredFiles = essentialFiles.filter((file) => file.esntlAtchYn === "Y");
|
||||||
|
if (requiredFiles.length === 0) return true;
|
||||||
|
|
||||||
|
const attachedIds = new Set(
|
||||||
|
esntlAtchFileList
|
||||||
|
.filter((item) => Boolean(item.atchFileGroupId))
|
||||||
|
.map((item) => item.esntlAtchFileId),
|
||||||
|
);
|
||||||
|
|
||||||
|
return requiredFiles.every((file) => attachedIds.has(file.esntlAtchFileId));
|
||||||
|
}
|
||||||
|
|||||||
@@ -72,7 +72,8 @@ function PbadmsTaskApplyDialog({
|
|||||||
const sidoOptions = sidoData ?? EMPTY_ADST_LIST;
|
const sidoOptions = sidoData ?? EMPTY_ADST_LIST;
|
||||||
const gugunOptions = gugunData ?? EMPTY_ADST_LIST;
|
const gugunOptions = gugunData ?? EMPTY_ADST_LIST;
|
||||||
const isPending = isSidoPending || isTaskSePending;
|
const isPending = isSidoPending || isTaskSePending;
|
||||||
const canConfirm = Boolean(sidoComCd && selectedCodes.length > 0);
|
const canSidoGugunSelectable = userInfo?.dtlInstCd !== "ROLE_USER05";
|
||||||
|
const canConfirm = selectedCodes.length > 0 && (!canSidoGugunSelectable || !!sidoComCd);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!open) return;
|
if (!open) return;
|
||||||
@@ -121,48 +122,50 @@ function PbadmsTaskApplyDialog({
|
|||||||
<col width="35%" />
|
<col width="35%" />
|
||||||
</colgroup>
|
</colgroup>
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
{canSidoGugunSelectable && (
|
||||||
<TableHead data-required>시도</TableHead>
|
<TableRow>
|
||||||
<TableCell>
|
<TableHead data-required>시도</TableHead>
|
||||||
<Select
|
<TableCell>
|
||||||
value={sidoComCd || undefined}
|
<Select
|
||||||
onValueChange={(value) => {
|
value={sidoComCd || undefined}
|
||||||
setSidoComCd(value);
|
onValueChange={(value) => {
|
||||||
setSggComCd("");
|
setSidoComCd(value);
|
||||||
}}
|
setSggComCd("");
|
||||||
>
|
}}
|
||||||
<SelectTrigger className="w-full">
|
>
|
||||||
<SelectValue placeholder="선택" />
|
<SelectTrigger className="w-full">
|
||||||
</SelectTrigger>
|
<SelectValue placeholder="선택" />
|
||||||
<SelectContent>
|
</SelectTrigger>
|
||||||
{sidoOptions.map((option) => (
|
<SelectContent>
|
||||||
<SelectItem key={option.adstDstrCd} value={option.adstDstrCd}>
|
{sidoOptions.map((option) => (
|
||||||
{option.adstDstrNm}
|
<SelectItem key={option.adstDstrCd} value={option.adstDstrCd}>
|
||||||
</SelectItem>
|
{option.adstDstrNm}
|
||||||
))}
|
</SelectItem>
|
||||||
</SelectContent>
|
))}
|
||||||
</Select>
|
</SelectContent>
|
||||||
</TableCell>
|
</Select>
|
||||||
<TableHead>시군구</TableHead>
|
</TableCell>
|
||||||
<TableCell>
|
<TableHead>시군구</TableHead>
|
||||||
<Select
|
<TableCell>
|
||||||
value={sggComCd || undefined}
|
<Select
|
||||||
onValueChange={setSggComCd}
|
value={sggComCd || undefined}
|
||||||
disabled={!sidoComCd || isGugunPending}
|
onValueChange={setSggComCd}
|
||||||
>
|
disabled={!sidoComCd || isGugunPending}
|
||||||
<SelectTrigger className="w-full">
|
>
|
||||||
<SelectValue placeholder="선택" />
|
<SelectTrigger className="w-full">
|
||||||
</SelectTrigger>
|
<SelectValue placeholder="선택" />
|
||||||
<SelectContent>
|
</SelectTrigger>
|
||||||
{gugunOptions.map((option) => (
|
<SelectContent>
|
||||||
<SelectItem key={option.adstDstrCd} value={option.adstDstrCd}>
|
{gugunOptions.map((option) => (
|
||||||
{option.adstDstrNm}
|
<SelectItem key={option.adstDstrCd} value={option.adstDstrCd}>
|
||||||
</SelectItem>
|
{option.adstDstrNm}
|
||||||
))}
|
</SelectItem>
|
||||||
</SelectContent>
|
))}
|
||||||
</Select>
|
</SelectContent>
|
||||||
</TableCell>
|
</Select>
|
||||||
</TableRow>
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
)}
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead data-required>업무구분</TableHead>
|
<TableHead data-required>업무구분</TableHead>
|
||||||
<TableCell colSpan={3}>
|
<TableCell colSpan={3}>
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ interface SupplementDemandSectionProps {
|
|||||||
function SupplementDemandSection({ splmntDmndList }: SupplementDemandSectionProps) {
|
function SupplementDemandSection({ splmntDmndList }: SupplementDemandSectionProps) {
|
||||||
const { mutate: downloadAttachment } = useDownloadAttachmentByAtflCd();
|
const { mutate: downloadAttachment } = useDownloadAttachmentByAtflCd();
|
||||||
|
|
||||||
|
if (splmntDmndList.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SectionCollapsible title="보완요청 및 완료 현황">
|
<SectionCollapsible title="보완요청 및 완료 현황">
|
||||||
<div className="overflow-x-auto">
|
<div className="overflow-x-auto">
|
||||||
|
|||||||
Reference in New Issue
Block a user