Merge branch 'iipbs/st/dev' of https://www.onasys.co.kr:3000/ONAANDALL/frontend into iipbs/st/dev
This commit is contained in:
+1
-1
@@ -25,4 +25,4 @@ apps/fo/.next/**/*
|
||||
pnpm-lock.yaml
|
||||
settings.json
|
||||
.npmrc
|
||||
.cursor
|
||||
.cursor
|
||||
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||
pnpm turbo run build --filter="...[origin/$BRANCH]"
|
||||
@@ -6,16 +6,26 @@ const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
const compat = new FlatCompat({
|
||||
baseDirectory: __dirname,
|
||||
baseDirectory: __dirname,
|
||||
});
|
||||
|
||||
const eslintConfig = [
|
||||
...compat.extends("next/core-web-vitals", "next/typescript"),
|
||||
{
|
||||
rules: {
|
||||
"react-hooks/exhaustive-deps": "off",
|
||||
...compat.extends("next/core-web-vitals", "next/typescript"),
|
||||
{
|
||||
rules: {
|
||||
"react-hooks/exhaustive-deps": "off",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"warn",
|
||||
{
|
||||
argsIgnorePattern: "^_",
|
||||
varsIgnorePattern: "^_",
|
||||
caughtErrorsIgnorePattern: "^_",
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/no-explicit-any": "warn",
|
||||
"@typescript-eslint/no-wrapper-object-types": "warn",
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default eslintConfig;
|
||||
|
||||
@@ -5,35 +5,81 @@ import SearchForm from "@/components/module/SearchForm";
|
||||
import type { ColumnConfig } from "@/components/type/DataGrid.type";
|
||||
|
||||
const StatisticsInputManagement = () => {
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>(
|
||||
[],
|
||||
);
|
||||
|
||||
const columns: ColumnConfig[] = [
|
||||
{ name: 'sido', fieldName: '시도', header: { text: '시도' }, mergeCells: true, editable: false, sortdisable: true },
|
||||
{ name: 'sgg', fieldName: '시군구', header: { text: '시군구' }, mergeCells: true, editable: false, sortdisable: true },
|
||||
{ name: '구분', fieldName: '구분', header: { text: '구분' }, editable: false, sortdisable: true },
|
||||
{ name: '광역자치단체', fieldName: '광역자치단체', header: { text: '광역자치단체' }, editable: false, sortdisable: true },
|
||||
{ name: '공단', fieldName: '공단', header: { text: '공단' }, editable: false, sortdisable: true },
|
||||
{ name: '처리내역', fieldName: '처리내역', header: { text: '처리내역' }, editable: false, sortdisable: true },
|
||||
{
|
||||
name: "sido",
|
||||
fieldName: "시도",
|
||||
header: { text: "시도" },
|
||||
mergeCells: true,
|
||||
editable: false,
|
||||
sortdisable: true,
|
||||
},
|
||||
{
|
||||
name: "sgg",
|
||||
fieldName: "시군구",
|
||||
header: { text: "시군구" },
|
||||
mergeCells: true,
|
||||
editable: false,
|
||||
sortdisable: true,
|
||||
},
|
||||
{
|
||||
name: "구분",
|
||||
fieldName: "구분",
|
||||
header: { text: "구분" },
|
||||
editable: false,
|
||||
sortdisable: true,
|
||||
},
|
||||
{
|
||||
name: "광역자치단체",
|
||||
fieldName: "광역자치단체",
|
||||
header: { text: "광역자치단체" },
|
||||
editable: false,
|
||||
sortdisable: true,
|
||||
},
|
||||
{
|
||||
name: "공단",
|
||||
fieldName: "공단",
|
||||
header: { text: "공단" },
|
||||
editable: false,
|
||||
sortdisable: true,
|
||||
},
|
||||
{
|
||||
name: "처리내역",
|
||||
fieldName: "처리내역",
|
||||
header: { text: "처리내역" },
|
||||
editable: false,
|
||||
sortdisable: true,
|
||||
},
|
||||
];
|
||||
|
||||
const columnLayout = [
|
||||
'sido',
|
||||
'sgg',
|
||||
'구분',
|
||||
"sido",
|
||||
"sgg",
|
||||
"구분",
|
||||
{
|
||||
name: 'groupA',
|
||||
name: "groupA",
|
||||
hideChildHeaders: false,
|
||||
header: { text: '검토내역' },
|
||||
items: ['광역자치단체', '공단', '처리내역'],
|
||||
header: { text: "검토내역" },
|
||||
items: ["광역자치단체", "공단", "처리내역"],
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm sgg={false} sido={false} />
|
||||
<DataGrid columnInfo={{ columns, columnLayout }} rowData={rowData} setRowData={setRowData} isExcelImport={false} isExcelExport={false} />
|
||||
<SearchForm sido={false} />
|
||||
<DataGrid
|
||||
columnInfo={{ columns, columnLayout }}
|
||||
rowData={rowData}
|
||||
setRowData={setRowData}
|
||||
isExcelImport={false}
|
||||
isExcelExport={false}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default StatisticsInputManagement;
|
||||
export default StatisticsInputManagement;
|
||||
|
||||
@@ -3,9 +3,9 @@ import SearchForm from "@/components/module/SearchForm";
|
||||
const StatisticsPopulationManagement = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm sgg={false} sido={false} />
|
||||
<SearchForm sido={false} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default StatisticsPopulationManagement;
|
||||
export default StatisticsPopulationManagement;
|
||||
|
||||
@@ -37,7 +37,7 @@ const TAB_CONFIG = {
|
||||
},
|
||||
} as const;
|
||||
|
||||
type TabValue = keyof typeof TAB_CONFIG;
|
||||
export type TabValue = keyof typeof TAB_CONFIG;
|
||||
|
||||
function VerificationArticleManagement() {
|
||||
const queryClient = useQueryClient();
|
||||
@@ -248,6 +248,7 @@ function VerificationArticleManagement() {
|
||||
))}
|
||||
|
||||
<VerificationTargetDialog
|
||||
tabValue={activeTab}
|
||||
open={dialogOpen}
|
||||
onOpenChange={setDialogOpen}
|
||||
data={selectedData}
|
||||
|
||||
@@ -23,8 +23,10 @@ import {
|
||||
import { useEffect } from "react";
|
||||
import { useForm, Controller } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import type { TabValue } from "./VerificationArticleManagement";
|
||||
|
||||
interface VerificationTargetDialogProps {
|
||||
tabValue: TabValue;
|
||||
open: boolean;
|
||||
onOpenChange: (open: boolean) => void;
|
||||
data: VerificationTargetManagementResponse | null;
|
||||
@@ -33,6 +35,7 @@ interface VerificationTargetDialogProps {
|
||||
}
|
||||
|
||||
export function VerificationTargetDialog({
|
||||
tabValue,
|
||||
open,
|
||||
onOpenChange,
|
||||
data,
|
||||
@@ -51,7 +54,7 @@ export function VerificationTargetDialog({
|
||||
|
||||
useEffect(() => {
|
||||
if (data && open) reset(data);
|
||||
}, [data, open]);
|
||||
}, [data, open, reset]);
|
||||
|
||||
function onSubmit(formData: VerificationTargetManagementFormData) {
|
||||
if (!data) return;
|
||||
@@ -100,11 +103,6 @@ export function VerificationTargetDialog({
|
||||
}
|
||||
placeholder="선택"
|
||||
/>
|
||||
{errors.statsCd && (
|
||||
<p className="text-xs text-red-500">
|
||||
{errors.statsCd.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
@@ -147,11 +145,6 @@ export function VerificationTargetDialog({
|
||||
{...field}
|
||||
placeholder="스키마명"
|
||||
/>
|
||||
{errors.schmNm && (
|
||||
<p className="text-xs text-red-500">
|
||||
{errors.schmNm.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
@@ -172,11 +165,6 @@ export function VerificationTargetDialog({
|
||||
{...field}
|
||||
placeholder="테이블명"
|
||||
/>
|
||||
{errors.tblNm && (
|
||||
<p className="text-xs text-red-500">
|
||||
{errors.tblNm.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
@@ -200,11 +188,6 @@ export function VerificationTargetDialog({
|
||||
{...field}
|
||||
placeholder="컬럼명"
|
||||
/>
|
||||
{errors.colNm && (
|
||||
<p className="text-xs text-red-500">
|
||||
{errors.colNm.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
@@ -225,132 +208,145 @@ export function VerificationTargetDialog({
|
||||
{...field}
|
||||
placeholder="PK 키"
|
||||
/>
|
||||
{errors.pkColNm && (
|
||||
<p className="text-xs text-red-500">
|
||||
{errors.pkColNm.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
||||
<TableRow>
|
||||
<TableHead className="bg-muted font-medium">
|
||||
중요도 계수(μ)
|
||||
</TableHead>
|
||||
<TableCell>
|
||||
<Controller
|
||||
name="ipcrCntVl"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<div className="space-y-1">
|
||||
<Input
|
||||
type="number"
|
||||
step="0.1"
|
||||
value={field.value ?? ""}
|
||||
onChange={(e) =>
|
||||
field.onChange(
|
||||
e.target.value
|
||||
? Number(
|
||||
e.target
|
||||
.value,
|
||||
)
|
||||
: null,
|
||||
)
|
||||
}
|
||||
placeholder="(0 ~ 1)"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableHead className="bg-muted font-medium">
|
||||
백분위수 기준값(pct)
|
||||
</TableHead>
|
||||
<TableCell>
|
||||
<Controller
|
||||
name="pctlCrtrVl"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<div className="space-y-1">
|
||||
<Input
|
||||
type="number"
|
||||
step="0.1"
|
||||
value={field.value ?? ""}
|
||||
onChange={(e) =>
|
||||
field.onChange(
|
||||
e.target.value
|
||||
? Number(
|
||||
e.target
|
||||
.value,
|
||||
)
|
||||
: null,
|
||||
)
|
||||
}
|
||||
placeholder="(0 ~ 0.5)"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{tabValue !== "IMR" && (
|
||||
<TableRow>
|
||||
<TableHead className="bg-muted font-medium">
|
||||
중요도 계수(μ)
|
||||
</TableHead>
|
||||
<TableCell>
|
||||
<Controller
|
||||
name="ipcrCntVl"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<div className="space-y-1">
|
||||
<Input
|
||||
type="number"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.1"
|
||||
value={field.value ?? ""}
|
||||
onChange={(e) =>
|
||||
field.onChange(
|
||||
e.target.value
|
||||
? Number(
|
||||
e.target
|
||||
.value,
|
||||
)
|
||||
: null,
|
||||
)
|
||||
}
|
||||
placeholder="(0 ~ 1, 0.1 단위)"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableHead className="bg-muted font-medium">
|
||||
백분위수 기준값(pct)
|
||||
</TableHead>
|
||||
<TableCell>
|
||||
<Controller
|
||||
name="pctlCrtrVl"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<div className="space-y-1">
|
||||
<Input
|
||||
type="number"
|
||||
min="0"
|
||||
max="0.5"
|
||||
step="0.1"
|
||||
value={field.value ?? ""}
|
||||
onChange={(e) =>
|
||||
field.onChange(
|
||||
e.target.value
|
||||
? Number(
|
||||
e.target
|
||||
.value,
|
||||
)
|
||||
: null,
|
||||
)
|
||||
}
|
||||
placeholder="(0 ~ 0.5, 0.1 단위)"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
|
||||
<TableRow>
|
||||
<TableHead className="bg-muted font-medium">
|
||||
스케일 조정 계수(A)
|
||||
</TableHead>
|
||||
<TableCell>
|
||||
<Controller
|
||||
name="scopCntCntVl"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
type="number"
|
||||
step="0.05"
|
||||
value={field.value ?? ""}
|
||||
onChange={(e) =>
|
||||
field.onChange(
|
||||
e.target.value
|
||||
? Number(
|
||||
e.target
|
||||
.value,
|
||||
)
|
||||
: null,
|
||||
)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableHead className="bg-muted font-medium">
|
||||
임계 계수(c)
|
||||
</TableHead>
|
||||
<TableCell>
|
||||
<Controller
|
||||
name="thrsCntVl"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
type="number"
|
||||
step="1"
|
||||
value={field.value ?? ""}
|
||||
onChange={(e) =>
|
||||
field.onChange(
|
||||
e.target.value
|
||||
? Number(
|
||||
e.target
|
||||
.value,
|
||||
)
|
||||
: null,
|
||||
)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{tabValue !== "IMR" && (
|
||||
<TableRow>
|
||||
<TableHead className="bg-muted font-medium">
|
||||
스케일 조정 계수(A)
|
||||
</TableHead>
|
||||
<TableCell>
|
||||
<Controller
|
||||
name="scopCntCntVl"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<div className="space-y-1">
|
||||
<Input
|
||||
type="number"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.01"
|
||||
value={field.value ?? ""}
|
||||
onChange={(e) =>
|
||||
field.onChange(
|
||||
e.target.value
|
||||
? Number(
|
||||
e.target
|
||||
.value,
|
||||
)
|
||||
: null,
|
||||
)
|
||||
}
|
||||
placeholder="(0 ~ 1, 0.01 단위)"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableHead className="bg-muted font-medium">
|
||||
임계 계수(c)
|
||||
</TableHead>
|
||||
<TableCell>
|
||||
<Controller
|
||||
name="thrsCntVl"
|
||||
control={control}
|
||||
render={({ field }) => (
|
||||
<div className="space-y-1">
|
||||
<Input
|
||||
type="number"
|
||||
min="0"
|
||||
max="100"
|
||||
step="1"
|
||||
value={field.value ?? ""}
|
||||
onChange={(e) =>
|
||||
field.onChange(
|
||||
e.target.value
|
||||
? Number(
|
||||
e.target
|
||||
.value,
|
||||
)
|
||||
: null,
|
||||
)
|
||||
}
|
||||
placeholder="(0 ~ 100, 1 단위)"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
|
||||
@@ -116,15 +116,6 @@ export const imrArticleColumnInfo: ColumnInfo = {
|
||||
editable: false,
|
||||
sortdisable: false,
|
||||
},
|
||||
{
|
||||
name: "ipcrCntVl",
|
||||
fieldName: "ipcrCntVl",
|
||||
header: { text: "μ" },
|
||||
editable: false,
|
||||
sortdisable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: "#,##0.###",
|
||||
},
|
||||
{
|
||||
name: "rgtrNm",
|
||||
fieldName: "rgtrNm",
|
||||
@@ -145,7 +136,6 @@ export const imrArticleColumnInfo: ColumnInfo = {
|
||||
"vrfcTrgtNm",
|
||||
"tblNm",
|
||||
"colNm",
|
||||
"ipcrCntVl",
|
||||
"rgtrNm",
|
||||
"regDt",
|
||||
],
|
||||
@@ -196,5 +186,12 @@ export const validationArticleColumnInfo: ColumnInfo = {
|
||||
sortdisable: false,
|
||||
},
|
||||
],
|
||||
columnLayout: ["statsNm", "vrfcTrgtNm", "tblNm", "colNm", "rgtrNm", "regDt"],
|
||||
columnLayout: [
|
||||
"statsNm",
|
||||
"vrfcTrgtNm",
|
||||
"tblNm",
|
||||
"colNm",
|
||||
"rgtrNm",
|
||||
"regDt",
|
||||
],
|
||||
};
|
||||
|
||||
@@ -10,10 +10,31 @@ export const verificationTargetManagementSchema = z.object({
|
||||
tblNm: z.string().min(1, "테이블명을 입력해주세요"),
|
||||
colNm: z.string().min(1, "컬럼명을 입력해주세요"),
|
||||
pkColNm: z.string().min(1, "PK 키를 입력해주세요"),
|
||||
ipcrCntVl: z.number().optional().nullable(),
|
||||
pctlCrtrVl: z.number().optional().nullable(),
|
||||
scopCntCntVl: z.number().optional().nullable(),
|
||||
thrsCntVl: z.number().optional().nullable(),
|
||||
ipcrCntVl: z
|
||||
.number()
|
||||
.min(0, "중요도 계수는 0 이상이어야 합니다")
|
||||
.max(1, "중요도 계수는 1 이하여야 합니다")
|
||||
.nullable()
|
||||
.optional(),
|
||||
pctlCrtrVl: z
|
||||
.number()
|
||||
.min(0, "백분위수 기준값은 0 이상이어야 합니다")
|
||||
.max(0.5, "백분위수 기준값은 0.5 이하여야 합니다")
|
||||
.nullable()
|
||||
.optional(),
|
||||
scopCntCntVl: z
|
||||
.number()
|
||||
.min(0, "스케일 조정 계수는 0 이상이어야 합니다")
|
||||
.max(1, "스케일 조정 계수는 1 이하여야 합니다")
|
||||
.nullable()
|
||||
.optional(),
|
||||
thrsCntVl: z
|
||||
.number()
|
||||
.int("임계 계수는 정수여야 합니다")
|
||||
.min(0, "임계 계수는 0 이상이어야 합니다")
|
||||
.max(100, "임계 계수는 100 이하여야 합니다")
|
||||
.nullable()
|
||||
.optional(),
|
||||
useYn: z.string().optional(),
|
||||
vrfcTrgtNm: z.string().optional().nullable(),
|
||||
rgtr: z.string().optional().nullable(),
|
||||
|
||||
+4
-2
@@ -25,7 +25,8 @@
|
||||
"dev:fo": "turbo run dev --filter=fo",
|
||||
"dev:dm": "turbo run dev --filter=dm",
|
||||
"preview:components": "turbo run storybook --filter=@common/components",
|
||||
"preinstall": "npx only-allow pnpm"
|
||||
"preinstall": "npx only-allow pnpm",
|
||||
"prepare": "husky"
|
||||
},
|
||||
"dependencies": {
|
||||
"chart.js": "^4.4.8",
|
||||
@@ -38,6 +39,8 @@
|
||||
"@types/node": "^22.13.1",
|
||||
"@types/react": "^19.2.7",
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^16.2.7",
|
||||
"turbo": "2.4.2"
|
||||
},
|
||||
"pnpm": {
|
||||
@@ -46,7 +49,6 @@
|
||||
"@types/react-dom": "^19.2.3",
|
||||
"react": "^19.2.1",
|
||||
"react-dom": "^19.2.1",
|
||||
|
||||
"lodash.isequal": "^4.5.0",
|
||||
"source-map": "^0.7.4"
|
||||
},
|
||||
|
||||
Generated
+403
-200
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user