[st] - feat: realgrid 셀 편집 체크 설정 수정, 컴포넌트 url 방식 테스트 중

This commit is contained in:
2026-05-27 17:04:46 +09:00
parent 99fe41b41d
commit 7e152cacd2
30 changed files with 3973 additions and 652 deletions
+210 -11
View File
@@ -52,6 +52,142 @@ if (typeof window !== "undefined") {
RealGrid.setLicenseKey(process.env.NEXT_PUBLIC_ST_REALGRID_KEY || "");
function isDropDownEditorColumn(column: {
editor?: { type?: string };
values?: string[];
}): boolean {
const type = column.editor?.type;
return (
type === "dropdown" ||
type === "list" ||
type === "dropDown" ||
(column.values != null && column.values.length > 0)
);
}
type GridViewWithSetColumnProperty = {
setColumnProperty?: (col: string, key: string, value: unknown) => void;
};
type GridViewWithEditOptions = {
setEditOptions?: (options: { commitWhenLeave?: boolean }) => void;
};
/** 포커스가 그리드 밖으로 나갈 때 편집 중인 값을 자동 commit */
function applyDefaultGridEditOptions(
gridView: GridViewWithEditOptions | null | undefined,
) {
gridView?.setEditOptions?.({ commitWhenLeave: true });
}
function isDateEditorColumn(column: {
editor?: { type?: string };
}): boolean {
return column.editor?.type === "date";
}
/** RealGrid 날짜(date) 편집기 컬럼 속성 적용 */
function applyColumnDateEditorProperties(
gridView: GridViewWithSetColumnProperty,
column: import("../type/DataGrid.type").ColumnConfig,
) {
if (!gridView.setColumnProperty) return;
const fmt =
column.datetimeFormat ??
column.editor?.datetimeFormat ??
"yyyy-MM-dd";
gridView.setColumnProperty(column.name, "datetimeFormat", fmt);
gridView.setColumnProperty(column.name, "editor", {
type: "date",
datetimeFormat: fmt,
dropDownWhenClick: column.editor?.dropDownWhenClick ?? true,
showToday: column.editor?.showToday ?? true,
});
gridView.setColumnProperty(column.name, "editButtonVisibility", "always");
}
/** RealGrid 드롭다운·날짜 등 컬럼 편집기 속성 적용 */
function applyColumnListEditorProperties(
gridView: GridViewWithSetColumnProperty,
column: import("../type/DataGrid.type").ColumnConfig,
) {
if (!gridView.setColumnProperty) return;
if (isDateEditorColumn(column)) {
applyColumnDateEditorProperties(gridView, column);
return;
}
const values = column.values ?? column.editor?.values;
const labels = column.labels ?? column.editor?.labels ?? values;
const isDropDown = isDropDownEditorColumn(column);
if (!isDropDown) {
if (column.editor) {
gridView.setColumnProperty(column.name, "editor", column.editor);
}
return;
}
if (values?.length) {
gridView.setColumnProperty(column.name, "values", values);
gridView.setColumnProperty(column.name, "labels", labels ?? values);
}
if (column.lookupDisplay) {
gridView.setColumnProperty(column.name, "lookupDisplay", true);
}
gridView.setColumnProperty(column.name, "editor", {
type: "dropdown",
domainOnly: column.editor?.domainOnly ?? true,
textReadOnly: column.editor?.textReadOnly ?? true,
commitOnSelect: column.editor?.commitOnSelect ?? true,
dropDownWhenClick: column.editor?.dropDownWhenClick ?? true,
values,
labels: labels ?? values,
});
gridView.setColumnProperty(column.name, "editButtonVisibility", "always");
}
/** 그리드 마운트·데이터 로드 후 드롭다운 컬럼 재적용용 */
export function applyDropDownColumnToGrid(
gridView: GridViewWithSetColumnProperty | null | undefined,
columnName: string,
options: string[],
) {
if (!gridView?.setColumnProperty || options.length === 0) return;
(
gridView as {
setEditOptions?: (opts: { editable?: boolean }) => void;
}
).setEditOptions?.({ editable: true });
gridView.setColumnProperty(columnName, "editable", true);
gridView.setColumnProperty(columnName, "values", options);
gridView.setColumnProperty(columnName, "labels", options);
gridView.setColumnProperty(columnName, "lookupDisplay", true);
gridView.setColumnProperty(columnName, "editor", {
type: "dropdown",
domainOnly: true,
textReadOnly: true,
commitOnSelect: true,
dropDownWhenClick: true,
values: options,
labels: options,
});
gridView.setColumnProperty(columnName, "editButtonVisibility", "always");
(gridView as { refresh?: () => void }).refresh?.();
}
function reapplyListEditorsOnGrid(
gridView: GridViewWithSetColumnProperty | null | undefined,
cols: import("../type/DataGrid.type").ColumnConfig[],
) {
if (!gridView) return;
cols.forEach((col) => applyColumnListEditorProperties(gridView, col));
if (cols.some((c) => isDropDownEditorColumn(c) || isDateEditorColumn(c))) {
(gridView as { refresh?: () => void }).refresh?.();
}
}
type GridViewWithCheckApi = {
checkItem?: (itemIndex: number, checked: boolean, exclusive?: boolean) => void;
checkRow?: (dataRow: number, checked: boolean, exclusive?: boolean) => void;
@@ -325,6 +461,8 @@ function buildFieldsFromColumns(
columns: {
fieldName: string;
valueType?: ValueType;
datetimeFormat?: string;
editor?: { type?: string; datetimeFormat?: string };
computed?: import("../type/DataGrid.type").ComputedFieldConfig;
}[],
) {
@@ -332,6 +470,7 @@ function buildFieldsFromColumns(
const field: {
fieldName: string;
dataType: string;
datetimeFormat?: string;
valueCallback?: (
prod: unknown,
dataRow: number,
@@ -341,8 +480,19 @@ function buildFieldsFromColumns(
) => number;
} = {
fieldName: col.fieldName,
dataType: col.valueType === ValueType.NUMBER ? "number" : "text",
dataType:
col.editor?.type === "date"
? "datetime"
: col.valueType === ValueType.NUMBER
? "number"
: "text",
};
if (col.editor?.type === "date") {
field.datetimeFormat =
col.datetimeFormat ??
col.editor.datetimeFormat ??
"yyyy-MM-dd";
}
if (col.computed) {
const hasFields =
"fields" in col.computed && col.computed.fields.length > 0;
@@ -844,6 +994,7 @@ const DataGrid = ({
const gridView = gridRef.current.gridView;
const dataProvider = gridRef.current.dataProvider;
applyDefaultGridEditOptions(gridView as GridViewWithEditOptions);
// mergeCells: true인 컬럼이 있으면 onSorting에서 클라이언트 정렬로 처리
const hasMergeCells = columns.some((col) => col.mergeCells === true);
@@ -894,15 +1045,8 @@ const DataGrid = ({
(gridView.header as { showTooltip?: boolean }).showTooltip = true;
}
columns.forEach((column) => {
(
gridView as {
setColumnProperty?: (
col: string,
key: string,
value: unknown,
) => void;
}
).setColumnProperty?.(
const gv = gridView as GridViewWithSetColumnProperty;
gv.setColumnProperty?.(
column.name,
"header",
realGridHeaderWithTooltip({
@@ -910,7 +1054,11 @@ const DataGrid = ({
tooltip: resolveColumnTooltip(column),
}),
);
applyColumnListEditorProperties(gv, column);
});
if (columns.some((c) => isDropDownEditorColumn(c))) {
(gridView as { refresh?: () => void }).refresh?.();
}
(
gridView as {
onShowHeaderTooltip?: (
@@ -1095,6 +1243,12 @@ const DataGrid = ({
(currentGridView as GridViewWithSetColumns).setColumns?.(
columnsWithFooter,
);
columns.forEach((col) =>
applyColumnListEditorProperties(
currentGridView as GridViewWithSetColumnProperty,
col,
),
);
applyFooterSettings(currentGridView);
if (hasFooterUserSpans) {
currentGridView.setColumnLayout?.(columnLayout);
@@ -1499,6 +1653,12 @@ const DataGrid = ({
autoGenerateField={true}
layout={columnLayout}
rows={rowData}
onRGDataColumnsChanged={(grid) => {
reapplyListEditorsOnGrid(
grid as GridViewWithSetColumnProperty,
columnsRef.current,
);
}}
onInitialized={(grid) => {
if (!grid) return;
(
@@ -1538,6 +1698,9 @@ const DataGrid = ({
dataProvider.setRows(rowData);
if (getGridRef) getGridRef.current = gridRef.current;
const gridView = gridRef.current?.gridView ?? grid;
applyDefaultGridEditOptions(
gridView as GridViewWithEditOptions,
);
if (!gridView?.columnByName) return;
setTimeout(() => {
const gv = gridRef.current?.gridView;
@@ -1653,6 +1816,10 @@ const DataGrid = ({
tooltip: resolveColumnTooltip(column),
}),
);
applyColumnListEditorProperties(
gv as GridViewWithSetColumnProperty,
column,
);
if (cellTooltipCallbackRef.current) {
(
gv as {
@@ -1707,9 +1874,15 @@ const DataGrid = ({
{columns.map((column) => {
const baseStyleName = column.styleName;
const columnReactKey =
column.values?.length &&
isDropDownEditorColumn(column)
? `${column.name}-dropdown-${column.values.length}`
: column.name;
return (
<RGDataColumn
key={column.name}
key={columnReactKey}
name={column.name}
fieldName={column.fieldName}
valueType={
@@ -1727,6 +1900,32 @@ const DataGrid = ({
tooltip: resolveColumnTooltip(column),
})}
editable={column.editable}
{...(column.editor != null && {
editor: column.editor,
})}
{...(column.values != null && {
values: column.values,
})}
{...(column.labels != null && {
labels: column.labels,
})}
{...(column.lookupDisplay === true && {
lookupDisplay: true,
})}
{...(isDateEditorColumn(column) && {
field: {
fieldName: column.fieldName,
dataType: ValueType.DATETIME,
datetimeFormat:
column.datetimeFormat ??
column.editor?.datetimeFormat ??
"yyyy-MM-dd",
},
datetimeFormat:
column.datetimeFormat ??
column.editor?.datetimeFormat ??
"yyyy-MM-dd",
})}
{...(column.width != null && {
width: column.width,
})}
+62 -28
View File
@@ -47,6 +47,47 @@ const getSggListFetcher = async (
});
};
function buildSearchFormValues(
props: SearchFormProps,
sidoList: ApiResponse<SearchCondition> | undefined,
defaultYear: number,
): SearchFormValues {
const d = props.defaultValues;
const initialClsfCd: SearchFormClsfCd =
d?.clsfCd === "ALL" || d?.clsfCd === "INPT" || d?.clsfCd === "VRFC"
? d.clsfCd
: "ALL";
if (d?.sido) {
return {
sido: d.sido,
gugun: d.gugun || "",
year: d.year || defaultYear.toString(),
order: d.order || "",
fctName: d.fctName || "",
bsnmCd: d.bsnmCd || "",
isDetail: false,
isSummary: d.isSummary || "",
clsfCd: initialClsfCd,
};
}
const first = sidoList?.data?.sidoList?.[0];
const useFirstSido = (props.sido ?? defaultSearchFormProps.sido) && first;
return {
sido: useFirstSido ? first.sido : "",
gugun: "",
year: d?.year || defaultYear.toString(),
order: d?.order || "",
fctName: d?.fctName || "",
bsnmCd: useFirstSido ? first.bsnmCd : "",
isDetail: false,
isSummary: d?.isSummary || "",
clsfCd: initialClsfCd,
};
}
const SearchForm = (props: SearchFormProps = {}) => {
const { setMessage: alert } = useAlertStore((state) => state);
const userInfo = useUserStore((state) => state.userInfo);
@@ -82,23 +123,27 @@ const SearchForm = (props: SearchFormProps = {}) => {
},
);
const initialClsfCd: SearchFormClsfCd = (() => {
const d = props.defaultValues?.clsfCd;
if (d === "ALL" || d === "INPT" || d === "VRFC") return d;
return "ALL";
})();
// 마운트 시 SWR 캐시의 시도 목록으로 초기값 설정 (탭 닫았다 열 때 API 재호출 없이 동작)
const [values, setValues] = useState<SearchFormValues>(() =>
buildSearchFormValues(props, sidoList, defaultYear),
);
const [values, setValues] = useState<SearchFormValues>({
sido: props.defaultValues?.sido || "",
gugun: props.defaultValues?.gugun || "",
year: props.defaultValues?.year || defaultYear.toString(),
order: props.defaultValues?.order || "",
fctName: props.defaultValues?.fctName || "",
bsnmCd: props.defaultValues?.bsnmCd || "",
isDetail: false,
isSummary: props.defaultValues?.isSummary || "",
clsfCd: initialClsfCd,
});
// 최초 진입만 시도 API가 늦게 오는 경우
useEffect(() => {
if (props.defaultValues?.sido) return;
const first = sidoList?.data?.sidoList?.[0];
if (!first || !mergedProps.sido) return;
setValues((prev) =>
prev.sido
? prev
: {
...prev,
sido: first.sido,
gugun: "",
bsnmCd: first.bsnmCd,
},
);
}, [sidoList, props.defaultValues?.sido, mergedProps.sido]);
const sggKey: [string, string, string, string] | null =
values.sido && values.sido !== "ALL"
@@ -133,18 +178,7 @@ const SearchForm = (props: SearchFormProps = {}) => {
};
const handleReset = () => {
const resetValues: SearchFormValues = {
sido: "",
gugun: "",
year: String(defaultYear),
order: "",
fctName: "",
bsnmCd: "",
isDetail: false,
isSummary: "",
clsfCd: "ALL",
};
setValues(resetValues);
setValues(buildSearchFormValues(props, sidoList, defaultYear));
props.onReset?.();
};
@@ -143,7 +143,6 @@ const verificationResultColumnInfo: ColumnInfo = {
{ name: "nowVlCn", fieldName: "nowVlCn", header: { text: "입력값" }, editable: false },
{ name: "compVlCn", fieldName: "compVlCn", header: { text: "기준값" }, editable: false },
{ name: "prcsYnNm", fieldName: "prcsYnNm", header: { text: "처리여부" }, editable: false },
{ name: "pbcpAprvYn", fieldName: "pbcpAprvYn", header: { text: "공단승인여부" }, editable: false },
{ name: "regDt", fieldName: "regDt", header: { text: "등록일시" }, editable: false },
{ name: "mdfcnDt", fieldName: "mdfcnDt", header: { text: "갱신일시" }, editable: false },
{ name: "prcsYn", fieldName: "prcsYn", header: { text: "검증결과상태코드" }, editable: false, visible: false },
@@ -157,7 +156,6 @@ const verificationResultColumnInfo: ColumnInfo = {
"nowVlCn",
"compVlCn",
"prcsYnNm",
"pbcpAprvYn",
"regDt",
"mdfcnDt",
"prcsYn",