@yorha2b-lab/autodev 4.0.1 → 4.1.1

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.
@@ -21,37 +21,33 @@
21
21
  "columns": [
22
22
  {
23
23
  "title": "职业",
24
- "dataIndex": "profession",
25
- "type": "text"
24
+ "dataIndex": "profession"
26
25
  },
27
26
  {
28
27
  "title": "一觉",
29
- "dataIndex": "firstAwakening",
30
- "type": "text"
28
+ "dataIndex": "firstAwakening"
31
29
  },
32
30
  {
33
31
  "title": "一觉立绘",
34
- "dataIndex": "firstAwakeningImage",
32
+ "dataIndex": "firstAwakeningArt",
35
33
  "type": "image"
36
34
  },
37
35
  {
38
36
  "title": "二觉",
39
- "dataIndex": "secondAwakening",
40
- "type": "text"
37
+ "dataIndex": "secondAwakening"
41
38
  },
42
39
  {
43
40
  "title": "二觉立绘",
44
- "dataIndex": "secondAwakeningImage",
41
+ "dataIndex": "secondAwakeningArt",
45
42
  "type": "image"
46
43
  },
47
44
  {
48
45
  "title": "三觉",
49
- "dataIndex": "thirdAwakening",
50
- "type": "text"
46
+ "dataIndex": "thirdAwakening"
51
47
  },
52
48
  {
53
49
  "title": "三觉立绘",
54
- "dataIndex": "thirdAwakeningImage",
50
+ "dataIndex": "thirdAwakeningArt",
55
51
  "type": "image"
56
52
  },
57
53
  {
@@ -61,7 +57,7 @@
61
57
  },
62
58
  {
63
59
  "title": "职业类型",
64
- "dataIndex": "professionType",
60
+ "dataIndex": "jobType",
65
61
  "type": "tag"
66
62
  },
67
63
  {
@@ -72,17 +68,17 @@
72
68
  ],
73
69
  "operation": [
74
70
  {
75
- "uri": "BUNKER_API_ANCHOR_viewByRecord",
71
+ "uri": "BUNKER_API_ANCHOR_view",
76
72
  "label": "查看",
77
73
  "action": "viewByRecord"
78
74
  },
79
75
  {
80
- "uri": "BUNKER_API_ANCHOR_editByRecord",
76
+ "uri": "BUNKER_API_ANCHOR_edit",
81
77
  "label": "编辑",
82
78
  "action": "editByRecord"
83
79
  },
84
80
  {
85
- "uri": "BUNKER_API_ANCHOR_deleteByRecord",
81
+ "uri": "BUNKER_API_ANCHOR_delete",
86
82
  "label": "删除",
87
83
  "action": "deleteByRecord"
88
84
  }
@@ -94,7 +90,7 @@
94
90
  "formItems": [
95
91
  {
96
92
  "label": "转职职业",
97
- "name": "transferProfession",
93
+ "name": "transferJob",
98
94
  "type": "select"
99
95
  },
100
96
  {
@@ -104,13 +100,12 @@
104
100
  },
105
101
  {
106
102
  "label": "职业类型",
107
- "name": "professionType",
103
+ "name": "jobType",
108
104
  "type": "select"
109
105
  },
110
106
  {
111
107
  "label": "觉醒名称关键词",
112
- "name": "awakeningKeyword",
113
- "type": "text"
108
+ "name": "awakeningKeyword"
114
109
  },
115
110
  {
116
111
  "label": "登场时间",
@@ -141,7 +136,7 @@
141
136
  ]
142
137
  },
143
138
  {
144
- "name": "professionTypeOptions",
139
+ "name": "jobTypeOptions",
145
140
  "options": [
146
141
  {
147
142
  "label": "物理",
@@ -154,20 +149,20 @@
154
149
  ]
155
150
  }
156
151
  ],
157
- "pageStruct": [
152
+ "renderTree": [
158
153
  "MySearchForm",
159
- "FunctionButtonsBlock",
154
+ "FunctionButtons",
160
155
  "MyTable"
161
156
  ],
162
157
  "functionButton": [
163
158
  {
164
159
  "btn": "批量删除",
165
- "uri": "BUNKER_API_ANCHOR_batchDeleteBySelected",
160
+ "uri": "BUNKER_API_ANCHOR_batchDelete",
166
161
  "action": "batchDeleteBySelected"
167
162
  },
168
163
  {
169
164
  "btn": "批量导出",
170
- "uri": "BUNKER_API_ANCHOR_exportData",
165
+ "uri": "BUNKER_API_ANCHOR_batchExport",
171
166
  "action": "exportData"
172
167
  }
173
168
  ]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yorha2b-lab/autodev",
3
- "version": "4.0.1",
3
+ "version": "4.1.1",
4
4
  "description": "基于视觉大模型的前端(react+Antd)全自动 CRUD 代码生成器",
5
5
  "bin": {
6
6
  "autodev": "bin/autodev.js"
@@ -9,7 +9,7 @@ module.exports = async filePath => {
9
9
  const { get } = require('../../core/context')
10
10
 
11
11
  const {
12
- config, language, menus,
12
+ config, language, menus, options,
13
13
  pagePrompt, resourceTpl, indexTpl,
14
14
  recognizePage, generateMock, resource, index
15
15
  } = get()
@@ -52,7 +52,7 @@ module.exports = async filePath => {
52
52
  `🤖 Pod 042: 正在上传视觉元数据至司令部进行语义分析...\n`,
53
53
  `🤖 Pod 042: Uploading visual metadata to Command for semantic analysis...\n`
54
54
  ))
55
- pageConfig = await recognizePage(pagePrompt, filePath)
55
+ pageConfig = await recognizePage({ prompt: pagePrompt, filePath, options })
56
56
  }
57
57
 
58
58
  fs.writeFileSync(path.join(targetDir, 'resource.js'), resource({ pageConfig, resourceTpl }))
@@ -6,7 +6,7 @@ const stringify = require('json-stringify-pretty-compact')
6
6
  module.exports = async filePath => {
7
7
 
8
8
  const { get } = require('../../core/context')
9
- const { language, partPrompt, recognizePage } = get()
9
+ const { options, language, partPrompt, recognizePage } = get()
10
10
  const { cleanCode, formatFormItemAndColumns } = require('../../utils/utils')
11
11
 
12
12
  const startTime = Date.now()
@@ -25,7 +25,7 @@ module.exports = async filePath => {
25
25
  `🤖 Pod 042: Extracting UI metadata from neural cloud network...\n`
26
26
  ))
27
27
 
28
- const pageConfig = await recognizePage(partPrompt, filePath, 'part')
28
+ const pageConfig = await recognizePage({ prompt: partPrompt, filePath, options, taskType: 'part' })
29
29
 
30
30
  const { formItems, dictBlocks, processedColumns } = formatFormItemAndColumns({ pageConfig })
31
31
 
@@ -14,6 +14,7 @@ const resource = ({ pageConfig, resourceTpl }) => {
14
14
 
15
15
  const hasTabs = pageConfig.tabs?.length > 0
16
16
  const hasFormItems = pageConfig.formItems?.length > 0
17
+ const tabKeys = pageConfig.tabs.map(tab => tab.key).sort((a, b) => a.length - b.length)
17
18
  const optionDict = pageConfig.optionList?.reduce((acc, item) => ({ ...acc, [item.name]: item.options }), {})
18
19
 
19
20
  const columnsData = processedColumns.map(item => {
@@ -23,11 +24,14 @@ const resource = ({ pageConfig, resourceTpl }) => {
23
24
 
24
25
  const viewData = {
25
26
  hasTabs,
27
+ columnsData,
26
28
  hasFormItems,
27
29
  tabs: pageConfig.tabs,
28
30
  dictBlocks: dictBlocks.map(item => ({ name: item, data: optionDict[item] ?? [] })),
29
- formItemsData: hasTabs ? Object.fromEntries(pageConfig.tabs.map(tab => [tab.key, formItems])) : formItems,
30
- columnsData: hasTabs ? Object.fromEntries(pageConfig.tabs.map(tab => [tab.key, columnsData])) : columnsData,
31
+ tabColumns: stringify.default(Object.fromEntries(tabKeys.map(tab => [tab, '_CODE_commonColumns_CODE_'])), { indent: 4, maxLength: 100 }),
32
+ formItemsData: !hasTabs ?
33
+ `export const formItems = ${stringify.default(formItems, { indent: 4, maxLength: 120 })}` :
34
+ `const searchItems = ${stringify.default(formItems, { indent: 4, maxLength: 120 })}\n\nexport const formItems = ${stringify.default(Object.fromEntries(tabKeys.map(tab => [tab, '_CODE_searchItems_CODE_'])), { indent: 4, maxLength: 100 })}`,
31
35
  }
32
36
 
33
37
  const bodyCode = resourceTpl(viewData)
@@ -50,10 +54,12 @@ const index = ({ config, fileName, indexTpl, pageConfig }) => {
50
54
  const hasFormItems = pageConfig.formItems?.length > 0
51
55
  const hasOperate = pageConfig.table?.operation?.length > 0
52
56
  const hasImageColumn = pageConfig.table?.columns?.some(item => item.type === 'image')
53
- const pageStruct = pageConfig.pageStruct?.filter(item => item.toLowerCase() !== 'tabs') || []
57
+ const renderTree = pageConfig.renderTree?.filter(item => item.toLowerCase() !== 'tabs') || []
54
58
  const functionButtons = pageConfig.functionButton?.filter(item => !['查询', '重置', 'query', 'search', 'reset'].includes(item.btn.toLowerCase().replaceAll(' ', ''))) || []
55
59
  const needRenderAction = hasImageColumn
56
60
 
61
+ const pageStruct = ['stateBlock', 'handleBlock', 'hookBlock', hasOperate ? 'operateBlock' : '', 'renderBlock'].filter(Boolean)
62
+
57
63
  let columnsValue = hasTabs ? 'columns[activeKey]' : 'columns'
58
64
  if (hasOperate) {
59
65
  columnsValue = `${columnsValue}.concat(operate)`
@@ -64,8 +70,8 @@ const index = ({ config, fileName, indexTpl, pageConfig }) => {
64
70
 
65
71
  const viewData = {
66
72
  hasTabs,
73
+ renderTree,
67
74
  pageStruct,
68
- hasOperate,
69
75
  columnsValue,
70
76
  hasFormItems,
71
77
  renderAction,
@@ -50,12 +50,12 @@ module.exports = `
50
50
  - **格式**: [{btn:'显示文本', action:'操作动词BySelected',uri:'BUNKER_API_ANCHOR_动词BySelected'}]。
51
51
  - **导出数据**: action 设为 'exportData' 或 'export+模块名'。
52
52
  - **逻辑锁定**: ⚠️只要页面中出现了非查询、非重置的独立操作按钮,必须识别并存入 [functionButton] 数组。
53
- - **构筑联动**: ⚠️若 [functionButton] 数组不为空,则在下文的 [pageStruct] 中必须包含 "FunctionButtonsBlock"。
53
+ - **构筑联动**: ⚠️若 [functionButton] 数组不为空,则在下文的 [RenderTree] 中必须包含 "FunctionButtons"。
54
54
 
55
- ## 3. 布局逻辑编排 (PageStruct)
55
+ ## 3. 布局逻辑编排 (RenderTree)
56
56
  - **定义**: 定义从上至下的物理堆叠顺序。
57
- - **白名单**: [MyTable, AlertInfo, MySearchForm, FunctionButtonsBlock]
58
- - **注释**: MyTable 是表格主体,AlertInfo 是统计条,MySearchForm 是搜索表单,FunctionButtonsBlock 是全局功能按钮。
57
+ - **白名单**: [MyTable, AlertInfo, MySearchForm, FunctionButtons]
58
+ - **注释**: MyTable 是表格主体,AlertInfo 是统计条,MySearchForm 是搜索表单,FunctionButtons 是全局功能按钮。
59
59
 
60
60
 
61
61
  ## 4. 字典数组 (OptionList)
@@ -10,7 +10,7 @@
10
10
  "formItems",
11
11
  "staticInfo",
12
12
  "optionList",
13
- "pageStruct",
13
+ "renderTree",
14
14
  "functionButton"
15
15
  ],
16
16
  "properties": {
@@ -195,7 +195,7 @@
195
195
  }
196
196
  }
197
197
  },
198
- "pageStruct": {
198
+ "renderTree": {
199
199
  "type": "array",
200
200
  "items": {
201
201
  "type": "string",
@@ -203,7 +203,7 @@
203
203
  "MyTable",
204
204
  "AlertInfo",
205
205
  "MySearchForm",
206
- "FunctionButtonsBlock"
206
+ "FunctionButtons"
207
207
  ]
208
208
  }
209
209
  },
@@ -85,7 +85,7 @@ module.exports = {
85
85
  ]
86
86
  })
87
87
  },
88
- recognizePage: async (prompt, filePath, taskType = 'page') => {
88
+ recognizePage: async ({ prompt, filePath, options, taskType = 'page' }) => {
89
89
  const config = getConfig()
90
90
  const { UI_DESIGNER } = require('../prompts/system.js')
91
91
  const sharp = require('sharp')
@@ -107,7 +107,7 @@ module.exports = {
107
107
  ]
108
108
  }
109
109
  ],
110
- response_format: taskType === 'page' ? { type: 'json_schema', strict: true, json_schema: require('../schema/page.json') } : { type: 'json_object' }
110
+ response_format: taskType === 'page' ? { type: 'json_schema', strict: true, json_schema: require(`../schema/${options.template}/page.json`) } : { type: 'json_object' }
111
111
  })
112
112
  },
113
113
  alignResponseFields: async (options, responseStr, resourceStr) => {
@@ -256,11 +256,9 @@ const formatFormItemAndColumns = ({ pageConfig }) => {
256
256
  const dictBlocks = Array.from(new Set([...formDicts, ...tableDicts]))
257
257
 
258
258
  const formItems = pageConfig.formItems?.map(item => {
259
-
260
259
  if (item.type === 'text') {
261
260
  delete item.type
262
261
  }
263
-
264
262
  return {
265
263
  ...item,
266
264
  ...(item.type === 'select' ? { options: `_CODE_${item.name}Options_CODE_` } : {})
@@ -268,6 +266,9 @@ const formatFormItemAndColumns = ({ pageConfig }) => {
268
266
  })
269
267
 
270
268
  const processedColumns = columns?.map(col => {
269
+ if (col.type === 'text') {
270
+ delete col.type
271
+ }
271
272
  if (['image'].includes(col.type)) {
272
273
  return { ...col, renderAction: true }
273
274
  }
@@ -0,0 +1,11 @@
1
+ {{#if hasTabs}}
2
+ {{#each tabs}}
3
+ {activeKey === '{{this.key}}' && commonButtons}
4
+ {{/each}}
5
+ {{else}}
6
+ <Space style=\{{ marginBottom: 16 }}>
7
+ {{#each functionButtons}}
8
+ <Button type='primary' onClick={ {{this.action}} }>{{this.btn}}</Button>
9
+ {{/each}}
10
+ </Space>
11
+ {{/if}}
@@ -1,3 +1,4 @@
1
+
1
2
  {{#each operations}}
2
3
  const {{this.action}} = async record => {
3
4
  const response = await request('/api/{{this.uri}}',{ method: 'POST', body:{} })
@@ -1,3 +1,4 @@
1
+
1
2
  const initialParams = {{initParams}}
2
3
 
3
4
  const query = formatQuery(Object.fromEntries(new URLSearchParams(location.search).entries()), {{formItems}})
@@ -0,0 +1,22 @@
1
+
2
+ const operate = {
3
+ title: '操作',
4
+ render: (_, record) => (
5
+ <Space>
6
+ {{#each operations}}
7
+ <a onClick={()=> {{this.action}}(record)}>{{this.label}}</a>
8
+ {{/each}}
9
+ </Space>
10
+ )
11
+ }
12
+
13
+ {{#if hasTabs}}
14
+ const commonButtons = (
15
+ <Space style=\{{ marginBottom: 16 }}>
16
+ {{#each functionButtons}}
17
+ <Button type='primary' onClick={ {{this.action}} }>{{this.btn}}</Button>
18
+ {{/each}}
19
+ </Space>
20
+ )
21
+
22
+ {{/if}}
@@ -0,0 +1,9 @@
1
+ return (
2
+ <Card {{#if hasTabs}}tabList={tabs} activeTabKey={activeKey} onTabChange={onTabChange}{{/if}}>
3
+ {{#if hasImageColumn}}{img.visible && <MyImage img={img} setImg={setImg}/>}{{~/if}}
4
+ {modal.visible && <MyModalForm {...modal} submit={modalSubmit} setModal={setModal} />}
5
+ {{#each renderTree as |treeNode|}}
6
+ {{> (treeNode) @root }}
7
+ {{/each}}
8
+ </Card>
9
+ )
@@ -1,31 +1,5 @@
1
1
  export default props => {
2
-
3
- {{> stateBlock }}
4
-
5
- {{> handleBlock }}
6
-
7
- {{> hookBlock }}
8
-
9
- {{#if hasOperate}}
10
- {{> tableOperate }}
11
- {{/if}}
12
-
13
- {{#if hasTabs}}
14
- /**
15
- * 多页签时功能按钮会根据页签数动态循环渲染
16
- * 因为截图限制,其他页签的功能按钮直接复制第一个页签的功能按钮占位
17
- * 如果每个页签的功能按钮都一样,下方循环处需要手动删除;不同则视情况决定是否有必要使用watch:part补充
18
- * resource.js中的columns和formItems同理,自行根据情况调整
19
- */
20
- {{/if}}
21
-
22
- return (
23
- <Card {{#if hasTabs}}tabList={tabs} activeTabKey={activeKey} onTabChange={onTabChange}{{/if}}>
24
- {{#if hasImageColumn}}{img.visible && <MyImage img={img} setImg={setImg}/>}{{~/if}}
25
- {modal.visible && <MyModalForm {...modal} submit={modalSubmit} setModal={setModal} />}
26
- {{#each pageStruct as |partialName|}}
27
- {{> (partialName) @root }}
28
- {{/each}}
29
- </Card>
30
- )
2
+ {{#each pageStruct as |partialName|}}
3
+ {{> (partialName) @root }}
4
+ {{/each}}
31
5
  }
@@ -8,9 +8,15 @@ export const {{this.name}} = {{{stringify this.data 50}}}
8
8
  {{/each}}
9
9
 
10
10
  {{#if hasFormItems}}
11
- export const formItems = {{{stringify formItemsData 150}}}
11
+ {{{formItemsData}}}
12
12
  {{/if}}
13
13
 
14
+ {{#if hasTabs}}
15
+ const commonColumns = {{{stringify columnsData 200}}}
16
+
17
+ export const tableColumns = {{{tabColumns}}}
18
+ {{else}}
14
19
  export const tableColumns = {{{stringify columnsData 200}}}
20
+ {{/if}}
15
21
 
16
22
  export const modalItems = []
@@ -1,16 +0,0 @@
1
- {{#if hasTabs}}
2
- {{#each tabs}}
3
- {activeKey === '{{this.key}}' &&
4
- <Space style=\{{ marginBottom: 16 }}>
5
- {{#each ../functionButtons}}
6
- <Button type='primary' onClick={ {{this.action}} }>{{this.btn}}</Button>
7
- {{/each}}
8
- </Space>}
9
- {{/each}}
10
- {{else}}
11
- <Space style=\{{ marginBottom: 16 }}>
12
- {{#each functionButtons}}
13
- <Button type='primary' onClick={ {{this.action}} }>{{this.btn}}</Button>
14
- {{/each}}
15
- </Space>
16
- {{/if}}
@@ -1,10 +0,0 @@
1
- const operate = {
2
- title: '操作',
3
- render: (_, record) => (
4
- <Space>
5
- {{#each operations}}
6
- <a onClick={()=> {{this.action}}(record)}>{{this.label}}</a>
7
- {{/each}}
8
- </Space>
9
- )
10
- }