@axboot-mcp/mcp-server 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +119 -0
- package/MCP_TOOL_PLAN.md +710 -0
- package/MCP_USAGE.md +914 -0
- package/README.md +168 -0
- package/REPOSITORY_CONVENTIONS.md +250 -0
- package/SEARCH_PARAMS_MCP_TOOL_COMPLETE_PLAN.md +646 -0
- package/SEARCH_PARAMS_PLAN.md +2570 -0
- package/STORE_PATTERNS.md +1178 -0
- package/debug-dto.js +72 -0
- package/generate-banner-store.js +62 -0
- package/generation-plan.json +2176 -0
- package/generation-results.json +1817 -0
- package/package.json +45 -0
- package/scripts/batch-generate-all.js +159 -0
- package/scripts/batch-generate-mcp.js +329 -0
- package/scripts/batch-generate-stores-v2.js +272 -0
- package/scripts/batch-generate-stores.js +179 -0
- package/scripts/batch-plan.json +3810 -0
- package/scripts/batch-process.py +90 -0
- package/scripts/batch-regenerate.js +356 -0
- package/scripts/direct-generate.js +227 -0
- package/scripts/execute-batches.js +1911 -0
- package/scripts/generate-all-stores.js +144 -0
- package/scripts/generate-stores-mcp.js +161 -0
- package/scripts/generate-stores-v2.js +450 -0
- package/scripts/generate-stores-v3.js +412 -0
- package/scripts/generate-stores-v4.js +521 -0
- package/scripts/generate-stores.js +382 -0
- package/scripts/repos-to-process.json +1899 -0
- package/src/config/nh-layout-patterns.ts +166 -0
- package/src/docs/HOOK_GENERATION_PLAN.md +2226 -0
- package/src/docs/NH_STORE_PATTERNS.md +297 -0
- package/src/docs/README.md +216 -0
- package/src/docs/index.ts +28 -0
- package/src/docs/loader.ts +568 -0
- package/src/docs/patterns.json +419 -0
- package/src/docs/practical-examples.md +732 -0
- package/src/docs/quick-start.md +257 -0
- package/src/docs/requirements-analysis-guide.md +364 -0
- package/src/docs/rules.json +321 -0
- package/src/docs/store-pattern-analysis.md +664 -0
- package/src/docs/store-patterns-rules.md +1168 -0
- package/src/docs/store-patterns-usage-guide.md +1835 -0
- package/src/docs/troubleshooting.md +544 -0
- package/src/docs/type-selection-guide.md +572 -0
- package/src/docs//354/202/254/354/232/251/353/262/225/AntD-/354/273/264/355/217/254/353/204/214/355/212/270-/354/202/254/354/232/251/353/262/225.md +1515 -0
- package/src/docs//354/202/254/354/232/251/353/262/225/DataGrid-/354/202/254/354/232/251/353/262/225.md +866 -0
- package/src/docs//354/202/254/354/232/251/353/262/225/FormItem-/354/202/254/354/232/251/353/262/225.md +903 -0
- package/src/docs//354/202/254/354/232/251/353/262/225/FormModal-/354/202/254/354/232/251/353/262/225.md +1155 -0
- package/src/docs//354/202/254/354/232/251/353/262/225/MCP-/353/260/224/354/235/264/353/270/214/354/275/224/353/224/251-/352/260/200/354/235/264/353/223/234.md +1133 -0
- package/src/docs//354/202/254/354/232/251/353/262/225/MSW-Mock-/353/215/260/354/235/264/355/204/260-/354/202/254/354/232/251/353/262/225.md +579 -0
- package/src/docs//354/202/254/354/232/251/353/262/225/Search-/354/273/264/355/217/254/353/204/214/355/212/270-/354/202/254/354/232/251/353/262/225.md +738 -0
- package/src/docs//354/202/254/354/232/251/353/262/225/Store-/355/214/250/355/204/264-/354/202/254/354/232/251/353/262/225.md +1135 -0
- package/src/docs//354/202/254/354/232/251/353/262/225//355/231/224/353/251/264/352/265/254/354/204/261-/355/203/200/354/236/205/353/263/204-/352/260/234/353/260/234/354/210/234/354/204/234.md +1805 -0
- package/src/docs//354/202/254/354/232/251/353/262/225//355/231/224/353/251/264/355/203/200/354/236/205/353/263/204-/352/260/234/353/260/234-/355/224/204/353/241/254/355/224/204/355/212/270-/352/260/200/354/235/264/353/223/234.md +946 -0
- package/src/docs//354/202/254/354/232/251/353/262/225//355/231/225/354/236/245/355/231/224/353/251/264/355/203/200/354/236/205/353/263/204-/354/203/201/354/204/270-/355/224/204/353/241/254/355/224/204/355/212/270/352/260/200/354/235/264/353/223/234.md +2422 -0
- package/src/features/store-features.ts +232 -0
- package/src/handlers/analyze-requirements.ts +403 -0
- package/src/handlers/analyze.ts +1373 -0
- package/src/handlers/generate-from-requirements.ts +250 -0
- package/src/handlers/generate-hook.ts +950 -0
- package/src/handlers/generate-interactive.ts +840 -0
- package/src/handlers/generate-listdatagrid.ts +521 -0
- package/src/handlers/generate-multi-stores.ts +577 -0
- package/src/handlers/generate-requirements-from-layout.ts +160 -0
- package/src/handlers/generate-search-params.ts +717 -0
- package/src/handlers/generate.ts +911 -0
- package/src/handlers/list-templates.ts +104 -0
- package/src/handlers/scan-metadata.ts +485 -0
- package/src/handlers/suggest-layout.ts +326 -0
- package/src/index.ts +959 -0
- package/src/prompts/search-params.md +793 -0
- package/src/templates/index.ts +107 -0
- package/src/templates/unified.ts +462 -0
- package/store-generation-error-patterns.md +225 -0
- package/test/useAgentStore.ts +136 -0
- package/test-server.js +78 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* ListDataGrid 컴포넌트 생성 도구
|
|
6
|
+
* NH-FE-B 패턴 기반 ListDataGrid.tsx 파일을 생성합니다.
|
|
7
|
+
*/
|
|
8
|
+
export interface GenerateListDataGridParams {
|
|
9
|
+
/** 생성할 ListDataGrid 파일 경로 (절대 경로) */
|
|
10
|
+
outputPath: string;
|
|
11
|
+
/** ListDataGrid 설정 */
|
|
12
|
+
config: ListDataGridConfig;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ListDataGridConfig {
|
|
16
|
+
/** Store 이름 (예: useProductListStore) */
|
|
17
|
+
storeName: string;
|
|
18
|
+
/** DTO 타입 (예: ProductRes) */
|
|
19
|
+
dtoType: string;
|
|
20
|
+
/** 행 키 (예: id, prdCd) */
|
|
21
|
+
rowKey: string;
|
|
22
|
+
/** 선택 모드 */
|
|
23
|
+
selectionMode?: 'single' | 'multi' | 'none';
|
|
24
|
+
/** FormHeader 포함 여부 */
|
|
25
|
+
withFormHeader?: boolean;
|
|
26
|
+
/** 엑셀 다운로드 포함 여부 */
|
|
27
|
+
withExcel?: boolean;
|
|
28
|
+
/** 컬럼 정의 */
|
|
29
|
+
columns: ColumnConfig[];
|
|
30
|
+
/** onClickItem 동작 타입 */
|
|
31
|
+
onClickType?: 'modal' | 'link' | 'select' | 'none';
|
|
32
|
+
/** 추가적인 import */
|
|
33
|
+
extraImports?: string[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ColumnConfig {
|
|
37
|
+
/** 컬럼 키 (DTO 필드명) */
|
|
38
|
+
key: string;
|
|
39
|
+
/** 라벨 */
|
|
40
|
+
label: string;
|
|
41
|
+
/** 컬럼 타입 */
|
|
42
|
+
type?: 'rowNo' | 'title' | 'money' | 'date' | 'dateTime' | 'user' | 'selectable' | 'custom';
|
|
43
|
+
/** 정렬 */
|
|
44
|
+
align?: 'left' | 'center' | 'right';
|
|
45
|
+
/** 너비 */
|
|
46
|
+
width?: number;
|
|
47
|
+
/** itemRender 코드 (사용자 정의 렌더링) */
|
|
48
|
+
itemRender?: string;
|
|
49
|
+
/** 코드 변수명 (코드 변환시 사용) */
|
|
50
|
+
codeVar?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* ListDataGrid 컴포넌트 생성
|
|
55
|
+
*/
|
|
56
|
+
export async function generateListDataGrid(params: GenerateListDataGridParams): Promise<{
|
|
57
|
+
content: Array<{ type: string; text: string }>;
|
|
58
|
+
}> {
|
|
59
|
+
const { outputPath, config } = params;
|
|
60
|
+
|
|
61
|
+
// 코드 생성
|
|
62
|
+
const code = generateListDataGridCode(config);
|
|
63
|
+
|
|
64
|
+
// 파일에 쓰기
|
|
65
|
+
const dir = path.dirname(outputPath);
|
|
66
|
+
if (!fs.existsSync(dir)) {
|
|
67
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
68
|
+
}
|
|
69
|
+
fs.writeFileSync(outputPath, code, 'utf-8');
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
content: [
|
|
73
|
+
{
|
|
74
|
+
type: 'text',
|
|
75
|
+
text: JSON.stringify({
|
|
76
|
+
success: true,
|
|
77
|
+
outputPath,
|
|
78
|
+
message: `ListDataGrid 파일이 생성되었습니다: ${outputPath}`,
|
|
79
|
+
nextSteps: `
|
|
80
|
+
## 다음 단계
|
|
81
|
+
|
|
82
|
+
### 1. App.tsx에 ListDataGrid import 추가
|
|
83
|
+
\`\`\`typescript
|
|
84
|
+
import { ListDataGrid } from "./ListDataGrid";
|
|
85
|
+
\`\`\`
|
|
86
|
+
|
|
87
|
+
### 2. Store에 필요한 상태/액션 확인
|
|
88
|
+
다음 상태가 Store에 있는지 확인하세요:
|
|
89
|
+
|
|
90
|
+
**필수:**
|
|
91
|
+
- listColWidths, listSortParams, listData, listPage, listSpinning
|
|
92
|
+
- setListColWidths, setListSortParams, changeListPage
|
|
93
|
+
|
|
94
|
+
**단일 선택 모드 시:**
|
|
95
|
+
- selectedItem, setSelectedItem
|
|
96
|
+
|
|
97
|
+
**다중 선택 모드 시:**
|
|
98
|
+
- checkedRowKeys, setCheckedRowKeys
|
|
99
|
+
|
|
100
|
+
**엑셀 다운로드 시:**
|
|
101
|
+
- excelSpinning, callExcelDownloadApi
|
|
102
|
+
|
|
103
|
+
### 3. 컬럼 정의 완료
|
|
104
|
+
생성된 코드에서 컬럼 배열을 완성하세요:
|
|
105
|
+
\`\`\`typescript
|
|
106
|
+
const { columns } = useDataGridColumns<DtoItem>(
|
|
107
|
+
[
|
|
108
|
+
{ key: "${config.rowKey}", label: t("번호"), type: "rowNo" },
|
|
109
|
+
// TODO: 여기에 컬럼 추가
|
|
110
|
+
${config.columns.map(c => `{ key: "${c.key}", label: t("${c.label}")${c.type ? `, type: "${c.type}"` : ''}${c.width ? `, width: ${c.width}` : ''}${c.align ? `, align: "${c.align}"` : ''} }`).join('\n ')}
|
|
111
|
+
],
|
|
112
|
+
{
|
|
113
|
+
colWidths: listColWidths,
|
|
114
|
+
${config.columns.some(c => c.codeVar) ? `deps: [${config.columns.filter(c => c.codeVar).map(c => c.codeVar).join(', ')}],` : ''}
|
|
115
|
+
}
|
|
116
|
+
);
|
|
117
|
+
\`\`\`
|
|
118
|
+
|
|
119
|
+
### 4. onClickItem 핸들러 구현
|
|
120
|
+
onClickType이 "${config.onClickType || 'select'}"이므로 필요한 동작을 구현하세요.
|
|
121
|
+
`.trim(),
|
|
122
|
+
}),
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* ListDataGrid 코드 생성
|
|
130
|
+
*/
|
|
131
|
+
function generateListDataGridCode(config: ListDataGridConfig): string {
|
|
132
|
+
const {
|
|
133
|
+
storeName,
|
|
134
|
+
dtoType,
|
|
135
|
+
rowKey,
|
|
136
|
+
selectionMode = 'none',
|
|
137
|
+
withFormHeader = false,
|
|
138
|
+
withExcel = false,
|
|
139
|
+
columns,
|
|
140
|
+
onClickType = 'select',
|
|
141
|
+
extraImports = [],
|
|
142
|
+
} = config;
|
|
143
|
+
|
|
144
|
+
// Import 생성
|
|
145
|
+
const imports = generateImports(config, extraImports);
|
|
146
|
+
|
|
147
|
+
// Interface 생성
|
|
148
|
+
const interfaces = generateInterfaces(config);
|
|
149
|
+
|
|
150
|
+
// Store 연결
|
|
151
|
+
const storeConnections = generateStoreConnections(config);
|
|
152
|
+
|
|
153
|
+
// 컬럼 정의
|
|
154
|
+
const columnsDefinition = generateColumnsDefinition(config);
|
|
155
|
+
|
|
156
|
+
// 이벤트 핸들러
|
|
157
|
+
const eventHandlers = generateEventHandlers(config);
|
|
158
|
+
|
|
159
|
+
// FormHeader
|
|
160
|
+
const formHeader = generateFormHeader(config);
|
|
161
|
+
|
|
162
|
+
// DataGrid props
|
|
163
|
+
const dataGridProps = generateDataGridProps(config);
|
|
164
|
+
|
|
165
|
+
// Styled Components
|
|
166
|
+
const styledComponents = generateStyledComponents(config);
|
|
167
|
+
|
|
168
|
+
return `${imports}
|
|
169
|
+
|
|
170
|
+
${interfaces}
|
|
171
|
+
|
|
172
|
+
export function ListDataGrid({}: Props) {
|
|
173
|
+
const { t } = useI18n();${withFormHeader || withExcel ? `
|
|
174
|
+
const { messageApi } = useAntApp();` : ''}
|
|
175
|
+
|
|
176
|
+
${storeConnections}
|
|
177
|
+
|
|
178
|
+
${eventHandlers}
|
|
179
|
+
|
|
180
|
+
${columnsDefinition}
|
|
181
|
+
|
|
182
|
+
const sortedListData = useDataGridSortedList<DtoItem>(listData, listSortParams);
|
|
183
|
+
|
|
184
|
+
return (
|
|
185
|
+
${formHeader}
|
|
186
|
+
<Container ref={containerRef}>
|
|
187
|
+
<DataGrid<DtoItem>
|
|
188
|
+
frozenColumnIndex={0}
|
|
189
|
+
width={containerWidth}
|
|
190
|
+
height={containerHeight}
|
|
191
|
+
columns={columns}
|
|
192
|
+
data={sortedListData}
|
|
193
|
+
spinning={listSpinning}
|
|
194
|
+
${dataGridProps}
|
|
195
|
+
/>
|
|
196
|
+
</Container>${withFormHeader ? '\n </>' : ''}
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
${styledComponents}
|
|
201
|
+
`;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Import 생성
|
|
206
|
+
*/
|
|
207
|
+
function generateImports(config: ListDataGridConfig, extraImports: string[] = []): string {
|
|
208
|
+
const imports: string[] = [
|
|
209
|
+
`import { AXDGChangeColumnsInfo, AXDGClickParams } from "@axboot/datagrid";`,
|
|
210
|
+
`import { DataGrid } from "@core/components/DataGrid";`,
|
|
211
|
+
`import ${config.withFormHeader || config.withExcel ? `{ useAntApp } from "@core/hooks";` : `""// { useAntApp } from "@core/hooks";`}${config.withFormHeader || config.withExcel ? '' : ' // 필요시 추가'}`,
|
|
212
|
+
`import { useDataGridColumns } from "@core/hooks/useDataGridColumns";`,
|
|
213
|
+
`import { useDataGridSortedList } from "@core/hooks/useDataGridSortedList";`,
|
|
214
|
+
`import { useContainerSize } from "@core/hooks/useContainerSize";`,
|
|
215
|
+
];
|
|
216
|
+
|
|
217
|
+
if (config.withFormHeader) {
|
|
218
|
+
imports.push(`import { Button, Flex } from "antd";`);
|
|
219
|
+
imports.push(`import { IconDownload } from "components/icon";`);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
imports.push(`import styled from "@emotion/styled";`);
|
|
223
|
+
imports.push(`import { useI18n } from "hooks";`);
|
|
224
|
+
imports.push(`import React from "react";`);
|
|
225
|
+
imports.push(`import { PageLayout } from "styles/pageStyled";`);
|
|
226
|
+
imports.push(`import { errorHandling } from "utils";`);
|
|
227
|
+
imports.push(`import { ${config.dtoType} } from "services";`);
|
|
228
|
+
|
|
229
|
+
// Store import
|
|
230
|
+
const storeFileName = config.storeName.replace(/^use/, '');
|
|
231
|
+
imports.push(`import { ${config.storeName} } from "./${storeFileName}";`);
|
|
232
|
+
|
|
233
|
+
// 컬럼 타입별 필요한 import
|
|
234
|
+
if (config.columns.some(c => c.type === 'money')) {
|
|
235
|
+
imports.push(`// import { formatterNumber } from "@core/utils"; // 금액 포맷 필요시`);
|
|
236
|
+
}
|
|
237
|
+
if (config.columns.some(c => c.type === 'date' || c.type === 'dateTime')) {
|
|
238
|
+
imports.push(`// import { formatterDate } from "@core/utils"; // 날짜 포맷 필요시`);
|
|
239
|
+
imports.push(`// import { DT_FORMAT } from "@types"; // 날짜 포맷 필요시`);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// 추가 imports
|
|
243
|
+
if (extraImports.length > 0) {
|
|
244
|
+
imports.push(...extraImports);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return imports.join('\n');
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Interface 생성
|
|
252
|
+
*/
|
|
253
|
+
function generateInterfaces(config: ListDataGridConfig): string {
|
|
254
|
+
return `interface DtoItem extends ${config.dtoType} {}
|
|
255
|
+
|
|
256
|
+
interface Props {}`;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Store 연결 생성
|
|
261
|
+
*/
|
|
262
|
+
function generateStoreConnections(config: ListDataGridConfig): string {
|
|
263
|
+
const { storeName, selectionMode, withExcel } = config;
|
|
264
|
+
|
|
265
|
+
const connections: string[] = [
|
|
266
|
+
` const listColWidths = ${storeName}((s) => s.listColWidths);`,
|
|
267
|
+
` const listSortParams = ${storeName}((s) => s.listSortParams);`,
|
|
268
|
+
` const listData = ${storeName}((s) => s.listData);`,
|
|
269
|
+
` const listPage = ${storeName}((s) => s.listPage);`,
|
|
270
|
+
` const listSpinning = ${storeName}((s) => s.listSpinning);`,
|
|
271
|
+
` const setListColWidths = ${storeName}((s) => s.setListColWidths);`,
|
|
272
|
+
` const setListSortParams = ${storeName}((s) => s.setListSortParams);`,
|
|
273
|
+
` const changeListPage = ${storeName}((s) => s.changeListPage);`,
|
|
274
|
+
];
|
|
275
|
+
|
|
276
|
+
// programFn
|
|
277
|
+
connections.push(` const programFn = ${storeName}((s) => s.programFn);`);
|
|
278
|
+
|
|
279
|
+
// 선택 모드별 추가 연결
|
|
280
|
+
if (selectionMode === 'single') {
|
|
281
|
+
connections.push(
|
|
282
|
+
``,
|
|
283
|
+
` // 단일 선택`,
|
|
284
|
+
` const selectedItem = ${storeName}((s) => s.selectedItem);`,
|
|
285
|
+
` const setSelectedItem = ${storeName}((s) => s.setSelectedItem);`,
|
|
286
|
+
);
|
|
287
|
+
} else if (selectionMode === 'multi') {
|
|
288
|
+
connections.push(
|
|
289
|
+
``,
|
|
290
|
+
` // 다중 선택`,
|
|
291
|
+
` const checkedRowKeys = ${storeName}((s) => s.checkedRowKeys);`,
|
|
292
|
+
` const setCheckedRowKeys = ${storeName}((s) => s.setCheckedRowKeys);`,
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// 엑셀 다운로드
|
|
297
|
+
if (withExcel) {
|
|
298
|
+
connections.push(
|
|
299
|
+
``,
|
|
300
|
+
` // 엑셀 다운로드`,
|
|
301
|
+
` const excelSpinning = ${storeName}((s) => s.excelSpinning);`,
|
|
302
|
+
` const callExcelDownloadApi = ${storeName}((s) => s.callExcelDownloadApi);`,
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// Container
|
|
307
|
+
connections.push(` const { containerRef, width: containerWidth, height: containerHeight } = useContainerSize();`);
|
|
308
|
+
|
|
309
|
+
return connections.join('\n');
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* 컬럼 정의 생성
|
|
314
|
+
*/
|
|
315
|
+
function generateColumnsDefinition(config: ListDataGridConfig): string {
|
|
316
|
+
const { storeName, columns, rowKey } = config;
|
|
317
|
+
|
|
318
|
+
// 컬럼 배열 생성
|
|
319
|
+
const columnItems = columns.map(col => {
|
|
320
|
+
const { key, label, type, align, width, itemRender, codeVar } = col;
|
|
321
|
+
|
|
322
|
+
// itemRender가 있는 경우
|
|
323
|
+
if (itemRender) {
|
|
324
|
+
return ` { key: "${key}", label: t("${label}")${width ? `, width: ${width}` : ''}${align ? `, align: "${align}"` : ''}, itemRender: ${itemRender} }`;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// 코드 변환이 필요한 경우
|
|
328
|
+
if (codeVar) {
|
|
329
|
+
return ` { key: "${key}", label: t("${label}")${width ? `, width: ${width}` : ''}${align ? `, align: "${align}"` : ''}, itemRender: ({ value }) => ${codeVar}?.find(value)?.label ?? value }`;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// 타입이 있는 경우
|
|
333
|
+
if (type) {
|
|
334
|
+
return ` { key: "${key}", label: t("${label}"), type: "${type}"${width ? `, width: ${width}` : ''}${align ? `, align: "${align}"` : ''} }`;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// 기본
|
|
338
|
+
return ` { key: "${key}", label: t("${label}")${width ? `, width: ${width}` : ''}${align ? `, align: "${align}"` : ''} }`;
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
const hasCodeVar = columns.some(c => c.codeVar);
|
|
342
|
+
|
|
343
|
+
return ` const handleColumnsChange = React.useCallback(
|
|
344
|
+
(columnIndex: number | null, { columns }: AXDGChangeColumnsInfo<DtoItem>) => {
|
|
345
|
+
setListColWidths(columns.map((column) => column.width));
|
|
346
|
+
},
|
|
347
|
+
[setListColWidths],
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
const { columns } = useDataGridColumns<DtoItem>(
|
|
351
|
+
[
|
|
352
|
+
{ key: "${rowKey}", label: t("번호"), type: "rowNo" },
|
|
353
|
+
${columnItems.join(',\n')}
|
|
354
|
+
],
|
|
355
|
+
{
|
|
356
|
+
colWidths: listColWidths,${hasCodeVar ? '\n deps: [' + columns.filter(c => c.codeVar).map(c => c.codeVar!).join(', ') + '],' : ''}
|
|
357
|
+
}
|
|
358
|
+
);`;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* 이벤트 핸들러 생성
|
|
363
|
+
*/
|
|
364
|
+
function generateEventHandlers(config: ListDataGridConfig): string {
|
|
365
|
+
const { storeName, onClickType, withExcel } = config;
|
|
366
|
+
const handlers: string[] = [];
|
|
367
|
+
|
|
368
|
+
// 엑셀 다운로드 핸들러
|
|
369
|
+
if (withExcel) {
|
|
370
|
+
handlers.push(
|
|
371
|
+
` const handleExcelDownload = React.useCallback(async () => {
|
|
372
|
+
try {
|
|
373
|
+
await callExcelDownloadApi();
|
|
374
|
+
messageApi.success("엑셀 다운로드가 완료되었습니다.");
|
|
375
|
+
} catch (err) {
|
|
376
|
+
await errorHandling(err);
|
|
377
|
+
}
|
|
378
|
+
}, [callExcelDownloadApi, messageApi]);`,
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// onClickItem 핸들러
|
|
383
|
+
if (onClickType === 'modal') {
|
|
384
|
+
handlers.push(
|
|
385
|
+
``,
|
|
386
|
+
` const onClickItem = React.useCallback(
|
|
387
|
+
async (params: AXDGClickParams<DtoItem>) => {
|
|
388
|
+
try {
|
|
389
|
+
// TODO: 모달 열기
|
|
390
|
+
// const data = await openFormModal({ query: params.item });
|
|
391
|
+
// if (data.save) {
|
|
392
|
+
// messageApi.info("저장되었습니다.");
|
|
393
|
+
// await callListApi();
|
|
394
|
+
// }
|
|
395
|
+
} catch (err) {
|
|
396
|
+
await errorHandling(err);
|
|
397
|
+
}
|
|
398
|
+
},
|
|
399
|
+
[callListApi, messageApi],
|
|
400
|
+
);`,
|
|
401
|
+
);
|
|
402
|
+
} else if (onClickType === 'link') {
|
|
403
|
+
handlers.push(
|
|
404
|
+
``,
|
|
405
|
+
` const onClickItem = React.useCallback(
|
|
406
|
+
async (params: AXDGClickParams<DtoItem>) => {
|
|
407
|
+
try {
|
|
408
|
+
// TODO: 링크 이동
|
|
409
|
+
// const menu = MENUS_LIST.find((m) => m.progId === "TARGET_PAGE");
|
|
410
|
+
// if (menu) linkByMenu(menu, { id: params.item.${config.rowKey} });
|
|
411
|
+
} catch (err) {
|
|
412
|
+
await errorHandling(err);
|
|
413
|
+
}
|
|
414
|
+
},
|
|
415
|
+
[],
|
|
416
|
+
);`,
|
|
417
|
+
);
|
|
418
|
+
} else if (onClickType === 'select') {
|
|
419
|
+
const { selectionMode } = config;
|
|
420
|
+
if (selectionMode === 'single') {
|
|
421
|
+
handlers.push(
|
|
422
|
+
``,
|
|
423
|
+
` const onClickItem = React.useCallback(
|
|
424
|
+
async (params: AXDGClickParams<DtoItem>) => {
|
|
425
|
+
try {
|
|
426
|
+
await setSelectedItem(params.item);
|
|
427
|
+
} catch (err) {
|
|
428
|
+
await errorHandling(err);
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
[setSelectedItem],
|
|
432
|
+
);`,
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
return handlers.join('\n');
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
/**
|
|
441
|
+
* FormHeader 생성
|
|
442
|
+
*/
|
|
443
|
+
function generateFormHeader(config: ListDataGridConfig): string {
|
|
444
|
+
if (!config.withFormHeader) {
|
|
445
|
+
return ' <>';
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
const { withExcel } = config;
|
|
449
|
+
|
|
450
|
+
let buttons = '';
|
|
451
|
+
if (withExcel) {
|
|
452
|
+
buttons = `
|
|
453
|
+
{programFn?.fn04 && (
|
|
454
|
+
<Button size={"small"} icon={<IconDownload />} onClick={handleExcelDownload} loading={excelSpinning}>
|
|
455
|
+
{t("엑셀다운로드")}
|
|
456
|
+
</Button>
|
|
457
|
+
)}`;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
return ` <>
|
|
461
|
+
<FormHeader>
|
|
462
|
+
목록
|
|
463
|
+
<Flex gap={6} align={"center"}>${buttons}
|
|
464
|
+
</Flex>
|
|
465
|
+
</FormHeader>`;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* DataGrid Props 생성
|
|
470
|
+
*/
|
|
471
|
+
function generateDataGridProps(config: ListDataGridConfig): string {
|
|
472
|
+
const { selectionMode, rowKey } = config;
|
|
473
|
+
const props: string[] = [
|
|
474
|
+
` onClick={onClickItem}`,
|
|
475
|
+
` page={{`,
|
|
476
|
+
` ...listPage,`,
|
|
477
|
+
` loading: false,`,
|
|
478
|
+
` onChange: async (currentPage, pageSize) => {`,
|
|
479
|
+
` await changeListPage(currentPage, pageSize);`,
|
|
480
|
+
` },`,
|
|
481
|
+
` }}`,
|
|
482
|
+
` sort={{`,
|
|
483
|
+
` sortParams: listSortParams,`,
|
|
484
|
+
` onChange: setListSortParams,`,
|
|
485
|
+
` }}`,
|
|
486
|
+
` onChangeColumns={handleColumnsChange}`,
|
|
487
|
+
` rowKey={"${rowKey}"}`,
|
|
488
|
+
];
|
|
489
|
+
|
|
490
|
+
// 선택 모드별 props
|
|
491
|
+
if (selectionMode === 'single') {
|
|
492
|
+
props.push(` selectedRowKey={selectedItem?.${rowKey} ?? ""}`);
|
|
493
|
+
} else if (selectionMode === 'multi') {
|
|
494
|
+
props.push(
|
|
495
|
+
` rowChecked={{`,
|
|
496
|
+
` checkedRowKeys,`,
|
|
497
|
+
` onChange: (checkedIndexes, checkedRowKeys, checkedAll) => {`,
|
|
498
|
+
` setCheckedRowKeys(checkedRowKeys);`,
|
|
499
|
+
` },`,
|
|
500
|
+
` }}`,
|
|
501
|
+
);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
return props.join('\n');
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* Styled Components 생성
|
|
509
|
+
*/
|
|
510
|
+
function generateStyledComponents(config: ListDataGridConfig): string {
|
|
511
|
+
let styled = `const Container = styled.div\`
|
|
512
|
+
flex: 1;
|
|
513
|
+
\`;`;
|
|
514
|
+
|
|
515
|
+
if (config.withFormHeader) {
|
|
516
|
+
styled += `
|
|
517
|
+
const FormHeader = styled(PageLayout.FrameHeader)\`\`;`;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
return styled;
|
|
521
|
+
}
|