@yorha2b-lab/autodev 1.0.46 → 2.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/README.md +28 -85
- package/README_EN.md +46 -100
- package/bin/autodev.js +29 -44
- package/config.js +7 -25
- package/example/example.json +46 -50
- package/package.json +1 -1
- package/src/commands/handlers/api-handler.js +80 -0
- package/src/commands/handlers/page-handler.js +92 -0
- package/src/commands/handlers/part-handler.js +76 -0
- package/src/commands/watch.js +96 -0
- package/src/core/react-compiler.js +45 -32
- package/src/prompts/mock.js +2 -2
- package/src/prompts/react/watch-page.js +6 -2
- package/src/prompts/react/watch-part.js +30 -25
- package/src/services/llm.js +2 -24
- package/src/utils/utils.js +7 -28
- package/templates/react/handlebars/MySearchForm.hbs +1 -0
- package/templates/react/handlebars/MyTable.hbs +26 -0
- package/templates/react/handlebars/functionButtonsBlock.hbs +16 -0
- package/templates/react/handlebars/handleBlock.hbs +52 -0
- package/templates/react/handlebars/hookBlock.hbs +9 -0
- package/templates/react/handlebars/stateBlock.hbs +11 -0
- package/templates/react/handlebars/tableOperate.hbs +10 -0
- package/templates/react/index.hbs +6 -121
- package/src/commands/watch-api.js +0 -68
- package/src/commands/watch-page.js +0 -155
- package/src/commands/watch-part.js +0 -77
|
@@ -1,27 +1,32 @@
|
|
|
1
1
|
module.exports = `
|
|
2
|
-
识别图片页面结构输出一个JSON
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
2
|
+
识别图片页面结构输出一个JSON对象
|
|
3
|
+
|
|
4
|
+
1. 严禁包含任何 Markdown 标签。
|
|
5
|
+
2. 严禁包含注释或解释文字。
|
|
6
|
+
3. 必须严格遵守以下字段规范。
|
|
7
|
+
|
|
8
|
+
## 1. 表格 (Table)
|
|
9
|
+
- 结构: { columns: [{ title: '', dataIndex: '' }] }
|
|
10
|
+
- ⚠️ 字段白名单: [title, dataIndex, sorter, render, filters, onFilter]
|
|
11
|
+
- 禁止输出: 严禁在 columns 中包含“操作”列。
|
|
12
|
+
- 特殊逻辑:
|
|
13
|
+
- 时间列: render 必须为 _CODE_text=>timeRender({time:text})_CODE_
|
|
14
|
+
- 序号列: render 必须为 _CODE_(_, record, index) => index + 1_CODE_
|
|
15
|
+
- 下拉映射列: render 必须为 _CODE_text=>对应的options.find(item=>item.value===text)?.label_CODE_
|
|
16
|
+
|
|
17
|
+
## 2. 表单 (Form)
|
|
18
|
+
- 结构: formItems: [{label:'',name:'',type:'',options:[]}]
|
|
19
|
+
- ⚠️ 属性精简规则:
|
|
20
|
+
- 默认输入框: 仅保留 [label, name] 属性。**严禁出现 type 属性**。
|
|
21
|
+
- 非默认组件: 仅当类型为 [auto, date, radio, select, upload, checkbox, textarea, daterange] 时才允许添加 type 属性。
|
|
22
|
+
- 命名规范:
|
|
23
|
+
- daterange: name 必须设为 '字段英文名start,字段英文名end'。
|
|
24
|
+
- 选择类 (radio/select/checkbox): options 必须设为 _CODE_字段英文名Options_CODE_。
|
|
25
|
+
- 增强属性:
|
|
26
|
+
- 必填校验: 若图片中 label 前有红色星号,必须加入 rules:[{required:true,message:'xxx不能为空'}]。
|
|
27
|
+
- 文字单位: 若项末尾有单位(如 元/kg),必须存入 unit 属性。
|
|
28
|
+
|
|
29
|
+
## 3. 下拉选项字典 (OptionDict)
|
|
30
|
+
- 结构: optionDict: { _CODE_字段名Options_CODE_: [] }
|
|
31
|
+
- 内容: 数组元素必须为 {label: '', value: ''} 格式。
|
|
27
32
|
`
|
package/src/services/llm.js
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
const path = require('path')
|
|
3
3
|
const chalk = require('chalk')
|
|
4
|
-
const { language, getConfig
|
|
4
|
+
const { language, getConfig } = require('../utils/utils.js')
|
|
5
5
|
|
|
6
6
|
let client = null
|
|
7
7
|
|
|
8
|
-
/**
|
|
9
|
-
* 获取 OpenAI 客户端实例(单例模式)
|
|
10
|
-
*/
|
|
11
8
|
const getOpenAI = () => {
|
|
12
9
|
if (!client) {
|
|
13
10
|
const OpenAI = require('openai')
|
|
@@ -21,11 +18,7 @@ const getOpenAI = () => {
|
|
|
21
18
|
return client
|
|
22
19
|
}
|
|
23
20
|
|
|
24
|
-
/**
|
|
25
|
-
* 调用 AI 模型并解析响应
|
|
26
|
-
*/
|
|
27
21
|
const askAI = async (model, messages, retryCount = 0) => {
|
|
28
|
-
// 最终重试失败:YoRHa 司令部连接中断
|
|
29
22
|
if (retryCount > 3) {
|
|
30
23
|
throw new Error(language(
|
|
31
24
|
'YoRHa 司令部连接中断:请检查网络状态或黑盒共鸣情况。',
|
|
@@ -50,14 +43,12 @@ const askAI = async (model, messages, retryCount = 0) => {
|
|
|
50
43
|
const statusCode = err.status || err.response?.status
|
|
51
44
|
const isAuthError = err.message.includes('401') || err.message.includes('402') || [401, 402].includes(statusCode)
|
|
52
45
|
if (isAuthError) {
|
|
53
|
-
// 权限错误:司令部拒绝访问
|
|
54
46
|
throw new Error(language(
|
|
55
47
|
'[系统警告] YoRHa 司令部拒绝访问:API Key 无效或额度耗尽,请检查!',
|
|
56
48
|
'[SYSTEM ALERT] YoRHa Command Center Access Denied: Invalid API Key or quota exhausted!'
|
|
57
49
|
))
|
|
58
50
|
}
|
|
59
51
|
|
|
60
|
-
// 重试警告:神经云网络连接不稳
|
|
61
52
|
console.warn(chalk.yellow(language(
|
|
62
53
|
`[系统警告] 神经云网络连接不稳,正在尝试重新链接... (第 ${retryCount + 1} 次重试)`,
|
|
63
54
|
`[SYSTEM ALERT] Neural Network instability detected. Attempting to re-establish link... (Retry #${retryCount + 1})`
|
|
@@ -68,9 +59,6 @@ const askAI = async (model, messages, retryCount = 0) => {
|
|
|
68
59
|
}
|
|
69
60
|
|
|
70
61
|
module.exports = {
|
|
71
|
-
/**
|
|
72
|
-
* 生成 Mock 数据
|
|
73
|
-
*/
|
|
74
62
|
generateMock: async (columns, fileName) => {
|
|
75
63
|
const config = getConfig()
|
|
76
64
|
const mockPrompt = require('../prompts/mock.js')
|
|
@@ -83,10 +71,6 @@ module.exports = {
|
|
|
83
71
|
]
|
|
84
72
|
)
|
|
85
73
|
},
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* 识别页面截图
|
|
89
|
-
*/
|
|
90
74
|
recognizePage: async (prompt, filePath) => {
|
|
91
75
|
const config = getConfig()
|
|
92
76
|
const { UI_DESIGNER } = require('../prompts/system.js')
|
|
@@ -111,16 +95,10 @@ module.exports = {
|
|
|
111
95
|
]
|
|
112
96
|
)
|
|
113
97
|
},
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* 对齐 Response 接口字段
|
|
117
|
-
*/
|
|
118
98
|
alignResponseFields: async (options, responseStr, resourceStr) => {
|
|
119
99
|
const config = getConfig()
|
|
120
100
|
const { API_DESIGNER } = require('../prompts/system.js')
|
|
121
|
-
const
|
|
122
|
-
checkPromptPath(promptPath)
|
|
123
|
-
const apiPrompt = require(promptPath)
|
|
101
|
+
const apiPrompt = require(`../prompts/${options.template}/watch-api.js`)
|
|
124
102
|
return askAI(
|
|
125
103
|
config.textModel,
|
|
126
104
|
[
|
package/src/utils/utils.js
CHANGED
|
@@ -25,7 +25,6 @@ const getConfig = () => {
|
|
|
25
25
|
* 大模型输出的标准 JSON 无法携带 render: (text) => <Tag> 等箭头函数。
|
|
26
26
|
* 我们在 Prompt 中要求大模型用 _CODE_ 占位符包裹函数字符串,
|
|
27
27
|
* 在此处用正则剥离外层的双引号和占位符,将其还原为真正的可执行 JS 代码。
|
|
28
|
-
*
|
|
29
28
|
* @param {string} str - 大模型返回的 JSON 字符串
|
|
30
29
|
* @returns {string} 清理后的可执行 JS 代码
|
|
31
30
|
*/
|
|
@@ -41,22 +40,6 @@ const cleanCode = str => {
|
|
|
41
40
|
.trim() + '\n'
|
|
42
41
|
}
|
|
43
42
|
|
|
44
|
-
/**
|
|
45
|
-
* 检查 Prompt 文件是否存在
|
|
46
|
-
* @param {string} promptPath - Prompt 文件路径
|
|
47
|
-
* @returns {void}
|
|
48
|
-
*/
|
|
49
|
-
const checkPromptPath = promptPath => {
|
|
50
|
-
const promptAbsPath = path.resolve(__dirname, promptPath)
|
|
51
|
-
if (!fs.existsSync(promptAbsPath)) {
|
|
52
|
-
const displayPath = promptPath.slice(3)
|
|
53
|
-
throw new Error(language(
|
|
54
|
-
`🤖 Pod 042: [警告] 侦测到未知的构筑协议 ${displayPath},地堡数据库暂无此类资料。`,
|
|
55
|
-
`🤖 Pod 042: [Warning] Unknown construction protocol ${displayPath}. No such protocol found in the bunker database.`
|
|
56
|
-
))
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
43
|
/**
|
|
61
44
|
* 获取已有的页面菜单配置
|
|
62
45
|
* @param {string} dir - 页面目录路径(默认 'src/pages')
|
|
@@ -73,24 +56,21 @@ const getExistingMenus = (dir = 'src/pages') => {
|
|
|
73
56
|
/**
|
|
74
57
|
* 生成智能导入语句
|
|
75
58
|
* 根据代码中实际使用的依赖,自动生成对应的 import 语句
|
|
76
|
-
*
|
|
77
59
|
* @param {string} codeStr - 生成的代码字符串
|
|
78
60
|
* @param {boolean} hasTabs - 是否包含标签页
|
|
79
61
|
* @returns {string} 拼接后的 import 语句
|
|
80
62
|
*/
|
|
81
63
|
const generateSmartImports = (codeStr, hasTabs) => {
|
|
82
|
-
const hooksLib = ['useTableQuery']
|
|
83
|
-
const reactLib = ['useState', 'useEffect', 'useRef', 'useMemo']
|
|
84
|
-
const componentsLib = ['MyTable', 'MyModalForm', 'MySearchForm']
|
|
85
|
-
const antdLib = ['Card', 'Space', 'Modal', 'Button', 'Alert', 'Table', 'Input', 'Select']
|
|
64
|
+
const hooksLib = ['useTableQuery']
|
|
65
|
+
const reactLib = ['useState', 'useEffect', 'useRef', 'useMemo']
|
|
66
|
+
const componentsLib = ['MyTable', 'MyModalForm', 'MySearchForm']
|
|
67
|
+
const antdLib = ['Card', 'Space', 'Modal', 'Button', 'Alert', 'Table', 'Input', 'Select']
|
|
86
68
|
|
|
87
|
-
// 检测代码中实际使用的组件
|
|
88
69
|
const usedAntd = antdLib.filter(name => new RegExp(`\\b${name}\\b`).test(codeStr))
|
|
89
70
|
const usedHooks = hooksLib.filter(name => new RegExp(`\\b${name}\\b`).test(codeStr))
|
|
90
71
|
const usedReact = reactLib.filter(name => new RegExp(`\\b${name}\\b`).test(codeStr))
|
|
91
72
|
const usedComps = componentsLib.filter(name => new RegExp(`\\b${name}\\b`).test(codeStr))
|
|
92
73
|
|
|
93
|
-
// 构建 import 语句数组
|
|
94
74
|
const imports = [
|
|
95
75
|
usedReact.length && `import { ${usedReact.join(', ')} } from 'react'`,
|
|
96
76
|
`import { request } from '../../utils/request'`,
|
|
@@ -99,9 +79,9 @@ const generateSmartImports = (codeStr, hasTabs) => {
|
|
|
99
79
|
...usedHooks.map(hook => `import { ${hook} } from '../../hooks/${hook}'`),
|
|
100
80
|
...usedComps.map(comp => `import { ${comp} } from '../../components/${comp}'`),
|
|
101
81
|
usedAntd.length && `import { Form, ${usedAntd.join(', ')} } from 'antd'`
|
|
102
|
-
].sort((a, b) => a.length - b.length)
|
|
82
|
+
].sort((a, b) => a.length - b.length)
|
|
103
83
|
|
|
104
|
-
return imports.filter(Boolean).join('\n')
|
|
84
|
+
return imports.filter(Boolean).join('\n')
|
|
105
85
|
}
|
|
106
86
|
|
|
107
87
|
/**
|
|
@@ -124,5 +104,4 @@ const copyTemplateDir = (options, templateSubDir, targetSubDir) => {
|
|
|
124
104
|
})
|
|
125
105
|
}
|
|
126
106
|
|
|
127
|
-
|
|
128
|
-
module.exports = { language, getConfig, cleanCode, getExistingMenus, copyTemplateDir, checkPromptPath, generateSmartImports }
|
|
107
|
+
module.exports = { language, getConfig, cleanCode, getExistingMenus, copyTemplateDir, generateSmartImports }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<MySearchForm form={form} search={search} initialValues={query} loading={loading} setSearch={setSearch} formItems={ {{formItems}} } />
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<MyTable
|
|
2
|
+
rowKey='id'
|
|
3
|
+
query={query}
|
|
4
|
+
loading={loading}
|
|
5
|
+
dataSource={dataSource}
|
|
6
|
+
columns={ {{columnsValue}} }
|
|
7
|
+
{{#if hasExpandable}}
|
|
8
|
+
{{{{raw}}}}
|
|
9
|
+
expandable={{ onExpand, expandedRowKeys, expandedRowRender, columnWidth: 24 }}
|
|
10
|
+
{{{{/raw}}}}
|
|
11
|
+
{{/if}}
|
|
12
|
+
{{#if hasPagination}}
|
|
13
|
+
{{{{raw}}}}
|
|
14
|
+
pagination={{ total, showSizeChanger: true, current: search.pageNo, pageSize: search.pageSize }}
|
|
15
|
+
onChange={(pagination, filters, sorter) => setSearch({ ...search , pageNo: pagination.current, pageSize: pagination.pageSize, orderBy: sorter.column ? sorter.field : undefined })}
|
|
16
|
+
{{{{/raw}}}}
|
|
17
|
+
{{/if}}
|
|
18
|
+
{{#if hasRowSelection}}
|
|
19
|
+
{{{{raw}}}}
|
|
20
|
+
rowSelection={{
|
|
21
|
+
selectedRowKeys: selectedRows.map(item => item.id),
|
|
22
|
+
onChange: (keys, rows) => setSelectedRows(rows)
|
|
23
|
+
}}
|
|
24
|
+
{{{{/raw}}}}
|
|
25
|
+
{{/if}}
|
|
26
|
+
/>
|
|
@@ -0,0 +1,16 @@
|
|
|
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}}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{{#each operations}}
|
|
2
|
+
const {{this.action}} = async record => {
|
|
3
|
+
const response = await request('/api')
|
|
4
|
+
if({{{../responseSuccess}}}){
|
|
5
|
+
refresh()
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
{{/each}}
|
|
10
|
+
|
|
11
|
+
{{#each functionButtons}}
|
|
12
|
+
const {{this.action}} = () => {
|
|
13
|
+
Modal.confirm({
|
|
14
|
+
title: '确认',
|
|
15
|
+
centered: true,
|
|
16
|
+
content: '确认{{this.btn}}吗?',
|
|
17
|
+
onOk: async () => {
|
|
18
|
+
const response = await request('/api')
|
|
19
|
+
if({{{../responseSuccess}}}){
|
|
20
|
+
refresh()
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
{{/each}}
|
|
27
|
+
|
|
28
|
+
{{#if hasTabs}}
|
|
29
|
+
const onTabChange = key => {
|
|
30
|
+
setActiveKey(key)
|
|
31
|
+
{{#if hasRowSelection}}setSelectedRows([]){{/if}}
|
|
32
|
+
setSearch({ pageNo: 1, pageSize: 10, type: key })
|
|
33
|
+
}
|
|
34
|
+
{{/if}}
|
|
35
|
+
|
|
36
|
+
{{#if hasExpandable}}
|
|
37
|
+
const onExpand = async (expanded, record) => {
|
|
38
|
+
if (expanded) {
|
|
39
|
+
setExpandedRowKeys([...expandedRowKeys, record.key])
|
|
40
|
+
} else {
|
|
41
|
+
setExpandedRowKeys(expandedRowKeys.filter(item => item !== record.key))
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const expandedRowRender = record => (<div>自定义渲染</div>)
|
|
46
|
+
|
|
47
|
+
{{/if}}
|
|
48
|
+
|
|
49
|
+
const modalSubmit = async values => {
|
|
50
|
+
const response = await request('/api')
|
|
51
|
+
refresh()
|
|
52
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const initParams = {{#if hasTabs}}{ type: tabs[0].key }{{else}}{}{{/if}}
|
|
2
|
+
|
|
3
|
+
const query = formatQuery(Object.fromEntries(new URLSearchParams(location.search).entries()), {{formItems}})
|
|
4
|
+
|
|
5
|
+
const { total, loading, dataSource, search, setSearch, refresh } = useTableQuery(
|
|
6
|
+
async params => await request('/api/{{fileName}}', { method: 'POST', body: params }),
|
|
7
|
+
response => ({ data: response?.data ?? [], total: response?.total ?? 0 }),
|
|
8
|
+
{...initParams, ...query},
|
|
9
|
+
)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const [form] = Form.useForm()
|
|
2
|
+
const [modal, setModal] = useState({})
|
|
3
|
+
{{#if hasRowSelection}}
|
|
4
|
+
const [selectedRows, setSelectedRows] = useState([])
|
|
5
|
+
{{/if}}
|
|
6
|
+
{{#if hasTabs}}
|
|
7
|
+
const [activeKey, setActiveKey] = useState(tabs[0].key)
|
|
8
|
+
{{/if}}
|
|
9
|
+
{{#if hasExpandable}}
|
|
10
|
+
const [expandedRowKeys, setExpandedRowKeys] = useState([])
|
|
11
|
+
{{/if}}
|
|
@@ -1,91 +1,13 @@
|
|
|
1
1
|
export default props => {
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
const [modal, setModal] = useState({})
|
|
5
|
-
{{#if hasTabs}}
|
|
6
|
-
const [activeKey, setActiveKey] = useState(tabs[0].key)
|
|
7
|
-
{{/if}}
|
|
8
|
-
{{#if hasExpandable}}
|
|
9
|
-
const [expandedRowKeys, setExpandedRowKeys] = useState([])
|
|
10
|
-
{{/if}}
|
|
11
|
-
{{#if hasRowSelection}}
|
|
12
|
-
const [selectedRows, setSelectedRows] = useState([])
|
|
13
|
-
{{/if}}
|
|
14
|
-
|
|
15
|
-
const initParams = {{#if hasTabs}}{ type: tabs[0].key }{{else}}{}{{/if}}
|
|
16
|
-
|
|
17
|
-
const query = formatQuery(Object.fromEntries(new URLSearchParams(location.search).entries()), {{#if hasTabs}}formItems[activeKey]{{else}}formItems{{/if}})
|
|
18
|
-
|
|
19
|
-
const { total, loading, dataSource, search, setSearch, refresh } = useTableQuery(
|
|
20
|
-
async params => await request('/api/{{fileName}}', { method: 'POST', body: params }),
|
|
21
|
-
response => ({ data: response?.data ?? [], total: response?.total ?? 0 }),
|
|
22
|
-
{...initParams, ...query},
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
{{#each operations}}
|
|
26
|
-
const {{this.action}} = async record => {
|
|
27
|
-
const response = await request('/api')
|
|
28
|
-
if({{{../responseSuccess}}}){
|
|
29
|
-
refresh()
|
|
30
|
-
}
|
|
31
|
-
}
|
|
3
|
+
{{> stateBlock }}
|
|
32
4
|
|
|
33
|
-
{{
|
|
34
|
-
|
|
35
|
-
{{#each functionButtons}}
|
|
36
|
-
const {{this.action}} = () => {
|
|
37
|
-
Modal.confirm({
|
|
38
|
-
title: '确认',
|
|
39
|
-
centered: true,
|
|
40
|
-
content: '确认{{this.btn}}吗?',
|
|
41
|
-
onOk: async () => {
|
|
42
|
-
const response = await request('/api')
|
|
43
|
-
if({{{../responseSuccess}}}){
|
|
44
|
-
refresh()
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
})
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
{{/each}}
|
|
51
|
-
|
|
52
|
-
{{#if hasTabs}}
|
|
53
|
-
const onTabChange = key => {
|
|
54
|
-
setActiveKey(key)
|
|
55
|
-
{{#if hasRowSelection}}setSelectedRows([]){{/if}}
|
|
56
|
-
setSearch({ pageNo: 1, pageSize: 10, type: key })
|
|
57
|
-
}
|
|
58
|
-
{{/if}}
|
|
59
|
-
|
|
60
|
-
{{#if hasExpandable}}
|
|
61
|
-
const onExpand = async (expanded, record) => {
|
|
62
|
-
if (expanded) {
|
|
63
|
-
setExpandedRowKeys([...expandedRowKeys, record.key])
|
|
64
|
-
} else {
|
|
65
|
-
setExpandedRowKeys(expandedRowKeys.filter(item => item !== record.key))
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const expandedRowRender = record => (<div>自定义渲染</div>)
|
|
70
|
-
|
|
71
|
-
{{/if}}
|
|
5
|
+
{{> hookBlock }}
|
|
72
6
|
|
|
73
|
-
|
|
74
|
-
const response = await request('/api')
|
|
75
|
-
refresh()
|
|
76
|
-
}
|
|
7
|
+
{{> handleBlock }}
|
|
77
8
|
|
|
78
9
|
{{#if hasOperate}}
|
|
79
|
-
|
|
80
|
-
title: '操作',
|
|
81
|
-
render: (_, record) => (
|
|
82
|
-
<Space>
|
|
83
|
-
{{#each operations}}
|
|
84
|
-
<a onClick={()=> {{this.action}}(record)}>{{this.label}}</a>
|
|
85
|
-
{{/each}}
|
|
86
|
-
</Space>
|
|
87
|
-
)
|
|
88
|
-
}
|
|
10
|
+
{{> tableOperate }}
|
|
89
11
|
{{/if}}
|
|
90
12
|
|
|
91
13
|
{{#if hasTabs}}
|
|
@@ -100,46 +22,9 @@ export default props => {
|
|
|
100
22
|
return (
|
|
101
23
|
<Card {{#if hasTabs}}tabList={tabs} activeTabKey={activeKey} onTabChange={onTabChange}{{/if}}>
|
|
102
24
|
{modal.visible && <MyModalForm {...modal} formItems={modalItems} submit={modalSubmit} setModal={setModal} />}
|
|
103
|
-
|
|
104
|
-
{{
|
|
105
|
-
{{#each tabs}}
|
|
106
|
-
{activeKey === '{{this.key}}' &&
|
|
107
|
-
<Space style=\{{ marginBottom: 16 }}>
|
|
108
|
-
{{#each ../functionButtons}}
|
|
109
|
-
<Button type='primary' onClick={ {{this.action}} }>{{this.btn}}</Button>
|
|
110
|
-
{{/each}}
|
|
111
|
-
</Space>}
|
|
25
|
+
{{#each pageStruct as |partialName|}}
|
|
26
|
+
{{> (partialName) @root }}
|
|
112
27
|
{{/each}}
|
|
113
|
-
{{else}}
|
|
114
|
-
<Space style=\{{ marginBottom: 16 }}>
|
|
115
|
-
{{#each functionButtons}}
|
|
116
|
-
<Button type='primary' onClick={ {{this.action}} }>{{this.btn}}</Button>
|
|
117
|
-
{{/each}}
|
|
118
|
-
</Space>
|
|
119
|
-
{{/if}}
|
|
120
|
-
{{#if hasStaticInfo}}
|
|
121
|
-
<Alert showIcon title='{{staticInfoText}}' type='info' style=\{{ marginBottom: 16 }} />
|
|
122
|
-
{{/if}}
|
|
123
|
-
<MyTable
|
|
124
|
-
rowKey='id'
|
|
125
|
-
query={query}
|
|
126
|
-
loading={loading}
|
|
127
|
-
dataSource={dataSource}
|
|
128
|
-
columns={ {{columnsValue}} }
|
|
129
|
-
{{#if hasExpandable}}
|
|
130
|
-
expandable=\{{ onExpand, expandedRowKeys, expandedRowRender, columnWidth: 24 }}
|
|
131
|
-
{{/if}}
|
|
132
|
-
{{#if hasPagination}}
|
|
133
|
-
pagination=\{{ total, showSizeChanger: true, current: search.pageNo, pageSize: search.pageSize }}
|
|
134
|
-
onChange={(pagination, filters, sorter) => setSearch({ ...search , pageNo: pagination.current, pageSize: pagination.pageSize, orderBy: sorter.column ? sorter.field : undefined })}
|
|
135
|
-
{{/if}}
|
|
136
|
-
{{#if hasRowSelection}}
|
|
137
|
-
rowSelection=\{{
|
|
138
|
-
selectedRowKeys: selectedRows.map(item => item.id),
|
|
139
|
-
onChange: (keys, rows) => setSelectedRows(rows)
|
|
140
|
-
}}
|
|
141
|
-
{{/if}}
|
|
142
|
-
/>
|
|
143
28
|
</Card>
|
|
144
29
|
)
|
|
145
30
|
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
const fs = require('fs')
|
|
2
|
-
const ora = require('ora')
|
|
3
|
-
const path = require('path')
|
|
4
|
-
const chalk = require('chalk')
|
|
5
|
-
const chokidar = require('chokidar')
|
|
6
|
-
|
|
7
|
-
const watchApi = options => {
|
|
8
|
-
// 导入配置文件和多语言函数
|
|
9
|
-
const { getConfig, language } = require('../utils/utils.js')
|
|
10
|
-
const { alignResponseFields } = require('../services/llm.js')
|
|
11
|
-
|
|
12
|
-
const config = getConfig()
|
|
13
|
-
|
|
14
|
-
const watcher = chokidar.watch('./response', {
|
|
15
|
-
persistent: true,
|
|
16
|
-
ignored: /(^|[\/\\])\../,
|
|
17
|
-
awaitWriteFinish: {
|
|
18
|
-
stabilityThreshold: 500,
|
|
19
|
-
pollInterval: 100
|
|
20
|
-
}
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
watcher.on('add', async filePath => {
|
|
24
|
-
const startTime = Date.now()
|
|
25
|
-
const fileName = path.basename(filePath, path.extname(filePath))
|
|
26
|
-
|
|
27
|
-
// 使用 language 函数包装 Pod 153 的启动报告
|
|
28
|
-
const spinner = ora(chalk.cyan(language(
|
|
29
|
-
`🤖 Pod 153: [报告] 侦测到未知的 Response 数据源 [${fileName}],开始进行语义对齐...`,
|
|
30
|
-
`🤖 Pod 153: [Report] Detected unknown Response data source [${fileName}]. Commencing semantic alignment...`
|
|
31
|
-
)))
|
|
32
|
-
spinner.start()
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
const responseStr = fs.readFileSync(filePath, 'utf8')
|
|
36
|
-
let resourceStr = fs.readFileSync(`./${config.pagesDir}/${fileName}/resource.js`, 'utf8')
|
|
37
|
-
|
|
38
|
-
// 调用 AI 服务进行字段对齐
|
|
39
|
-
const result = await alignResponseFields(options, responseStr, resourceStr)
|
|
40
|
-
|
|
41
|
-
Object.entries(result).forEach(([oldField, newField]) => {
|
|
42
|
-
if (oldField === newField) return
|
|
43
|
-
const regex = new RegExp(`(dataIndex|name)\\s*:\\s*['"]${oldField}['"]`, 'g')
|
|
44
|
-
resourceStr = resourceStr.replace(regex, `$1: '${newField}'`)
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
fs.writeFileSync(path.join(`./${config.pagesDir}/${fileName}/resource.js`), resourceStr)
|
|
48
|
-
const endTime = Date.now()
|
|
49
|
-
|
|
50
|
-
// 成功报告:带上 9S 的骇客梗
|
|
51
|
-
spinner.succeed(chalk.green(language(
|
|
52
|
-
`🤖 Pod 153: [肯定] 字段对齐协议执行完毕:耗时 ${(endTime - startTime) / 1000} 秒。9S 的骇客任务很顺利。`,
|
|
53
|
-
`🤖 Pod 153: [Affirmative] Field alignment protocol executed. Time: ${(endTime - startTime) / 1000}s. 9S's hacking mission was successful.`
|
|
54
|
-
)))
|
|
55
|
-
if (fs.existsSync(filePath)) {
|
|
56
|
-
fs.unlinkSync(filePath)
|
|
57
|
-
}
|
|
58
|
-
} catch (error) {
|
|
59
|
-
// 失败报告:提到“防火墙”
|
|
60
|
-
spinner.fail(chalk.red(language(
|
|
61
|
-
`🤖 Pod 153: [警告] 骇入 [${fileName}] 失败。接口数据遭遇强力防火墙:${error}`,
|
|
62
|
-
`🤖 Pod 153: [Warning] Hacking into [${fileName}] failed. Encountered a powerful firewall in API data: ${error}`
|
|
63
|
-
)))
|
|
64
|
-
}
|
|
65
|
-
})
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
module.exports = watchApi
|