@yorha2b-lab/autodev 1.0.44 → 1.0.46

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 CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  [English](./README_EN.md) | 简体中文
4
4
 
5
- ![Auto CRUD Copilot Banner](你的图片链接)
5
+ ![Auto CRUD Copilot Banner](https://github.com/user-attachments/assets/e168ef33-7616-434c-91e6-e2c9eef017c0)
6
+
6
7
 
7
8
  [![NPM Version](https://img.shields.io/npm/v/@yorha2b-lab/autodev.svg?style=flat-square)](https://www.npmjs.com/package/@yorha2b-lab/autodev)
8
9
  [![NPM Downloads](https://img.shields.io/npm/dm/@yorha2b-lab/autodev.svg?style=flat-square)](https://www.npmjs.com/package/@yorha2b-lab/autodev)
package/README_EN.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  English | [简体中文](./README.md)
4
4
 
5
- ![Auto CRUD Copilot Banner](你的图片链接)
5
+ ![Auto CRUD Copilot Banner](https://github.com/user-attachments/assets/e168ef33-7616-434c-91e6-e2c9eef017c0)
6
6
 
7
7
  [![NPM Version](https://img.shields.io/npm/v/@yorha2b-lab/autodev.svg?style=flat-square)](https://www.npmjs.com/package/@yorha2b-lab/autodev)
8
8
  [![NPM Downloads](https://img.shields.io/npm/dm/@yorha2b-lab/autodev.svg?style=flat-square)](https://www.npmjs.com/package/@yorha2b-lab/autodev)
package/bin/autodev.js CHANGED
@@ -91,7 +91,7 @@ program
91
91
  .description(language('监听 Response,自动对齐真实接口字段', 'Watch responses and auto-align real API fields'))
92
92
  .action(() => {
93
93
  const watchApi = require('../src/commands/watch-api')
94
- watchApi()
94
+ watchApi(program.opts())
95
95
  })
96
96
 
97
97
  program.parse(process.argv)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yorha2b-lab/autodev",
3
- "version": "1.0.44",
3
+ "version": "1.0.46",
4
4
  "description": "基于视觉大模型的前端(react+Antd)全自动 CRUD 代码生成器",
5
5
  "bin": {
6
6
  "autodev": "bin/autodev.js"
@@ -4,7 +4,7 @@ const path = require('path')
4
4
  const chalk = require('chalk')
5
5
  const chokidar = require('chokidar')
6
6
 
7
- const watchApi = () => {
7
+ const watchApi = options => {
8
8
  // 导入配置文件和多语言函数
9
9
  const { getConfig, language } = require('../utils/utils.js')
10
10
  const { alignResponseFields } = require('../services/llm.js')
@@ -36,7 +36,7 @@ const watchApi = () => {
36
36
  let resourceStr = fs.readFileSync(`./${config.pagesDir}/${fileName}/resource.js`, 'utf8')
37
37
 
38
38
  // 调用 AI 服务进行字段对齐
39
- const result = await alignResponseFields(responseStr, resourceStr)
39
+ const result = await alignResponseFields(options, responseStr, resourceStr)
40
40
 
41
41
  Object.entries(result).forEach(([oldField, newField]) => {
42
42
  if (oldField === newField) return
@@ -9,15 +9,20 @@ const chalk = require('chalk')
9
9
  * @param {string} options.template - 前端框架模板
10
10
  */
11
11
  const watchPage = options => {
12
+
13
+ const { language, getConfig, copyTemplateDir, checkPromptPath, getExistingMenus } = require('../utils/utils.js')
14
+
15
+ const promptPath = `../prompts/${options.template}/watch-page.js`
16
+
17
+ checkPromptPath(promptPath)
18
+
12
19
  const chokidar = require('chokidar')
20
+ const pagePrompt = require(promptPath)
13
21
  const Handlebars = require('handlebars')
14
- const pagePrompt = require('../prompts/watch-page.js')
15
22
  const { createTaskQueue } = require('../core/task-queue')
16
23
  const stringify = require('json-stringify-pretty-compact')
17
24
  const { recognizePage, generateMock } = require('../services/llm.js')
18
25
 
19
- const { language, getConfig, copyTemplateDir, getExistingMenus } = require('../utils/utils.js')
20
-
21
26
  const config = getConfig()
22
27
 
23
28
  const compilerPath = path.join(__dirname, `../core/${options.template}-compiler.js`)
@@ -118,8 +123,8 @@ const watchPage = options => {
118
123
  // 4. 生成 Mock 数据
119
124
  if (config.needMock) {
120
125
  console.log(chalk.yellow(language(
121
- `🧑‍💻 9S: 交给我吧 2B!正在骇入并伪造 [${fileName}] 的 Mock 数据...`,
122
- `🧑‍💻 9S: Leave it to me, 2B! Hacking and forging Mock data for [${fileName}]...`
126
+ `\n🧑‍💻 9S: 交给我吧 2B!正在骇入并伪造 [${fileName}] 的 Mock 数据...`,
127
+ `\n🧑‍💻 9S: Leave it to me, 2B! Hacking and forging Mock data for [${fileName}]...`
123
128
  )))
124
129
  const rawContent = await generateMock(pageConfig.table.columns, fileName)
125
130
  fs.writeFileSync(path.join(mockDir, `${fileName}.js`), `export default ${stringify.default(rawContent, { indent: 4, maxLength: 200 })}`)
@@ -4,10 +4,15 @@ const chalk = require('chalk')
4
4
  const chokidar = require('chokidar')
5
5
  const stringify = require('json-stringify-pretty-compact')
6
6
 
7
- const watchPart = () => {
8
- // 导入核心逻辑和多语言函数
7
+ const watchPart = options => {
8
+
9
+ const { language, checkPromptPath } = require('../utils/utils.js')
10
+
11
+ const promptPath = `../prompts/${options.template}/watch-part.js`
12
+
13
+ checkPromptPath(promptPath)
14
+ const partPrompt = require(promptPath)
9
15
  const { recognizePage } = require('../services/llm.js')
10
- const { language } = require('../utils/utils.js')
11
16
 
12
17
  const watcher = chokidar.watch('./screenPart', {
13
18
  persistent: true,
@@ -28,7 +33,6 @@ const watchPart = () => {
28
33
 
29
34
  try {
30
35
  const startTime = Date.now()
31
- const partPrompt = require('../prompts/watch-part.js')
32
36
  const pageConfig = await recognizePage(partPrompt, filePath)
33
37
 
34
38
  const optionDict = pageConfig.optionDict || {}
@@ -1,7 +1,7 @@
1
1
  module.exports = (responseStr, resourceStr) => `
2
2
  responseStr: ${responseStr}
3
3
  resourceStr: ${resourceStr}
4
- resourceStr是前端目前猜测的字段名列表(请从resourceStr中提取dataIndex和name),
4
+ resourceStr是前端目前猜测的字段名(请从resourceStr中提取dataIndex和name),
5
5
  responseStr是后端的真实响应。
6
6
  请比对两者,找出现有前端字段名应该被替换为哪个真实的后端字段名。
7
7
  匹配规则: 1.完全相同 2.下划线/驼峰转换 3.语义相似。
@@ -22,5 +22,6 @@ module.exports = `
22
22
  ⚠️⚠️⚠️注意:
23
23
  type:text/date/daterange/radio/checkbox/select/auto/textarea,如果是text可以省略
24
24
  如果type是auto/radio/select/checkbox,请加入options:_CODE_对应的英文名词Options_CODE_
25
+ 如果表单项末尾有文字描述,请将文字描述放在unit属性中
25
26
  ** 只输出modalItems就可以,不需要对应的formItems和columns **
26
27
  `
@@ -1,10 +1,7 @@
1
1
  const fs = require('fs')
2
2
  const path = require('path')
3
- const JSON5 = require('json5')
4
- const sharp = require('sharp')
5
3
  const chalk = require('chalk')
6
- const OpenAI = require('openai')
7
- const { getConfig, language } = require('../utils/utils.js') // 导入语言助手
4
+ const { language, getConfig, checkPromptPath } = require('../utils/utils.js') // 导入语言助手
8
5
 
9
6
  let client = null
10
7
 
@@ -13,6 +10,7 @@ let client = null
13
10
  */
14
11
  const getOpenAI = () => {
15
12
  if (!client) {
13
+ const OpenAI = require('openai')
16
14
  const localEnv = path.resolve(process.cwd(), '.env')
17
15
  const pkgEnv = path.resolve(__dirname, '../.env')
18
16
  require("dotenv").config({
@@ -42,20 +40,21 @@ const askAI = async (model, messages, retryCount = 0) => {
42
40
  messages,
43
41
  response_format: { type: 'json_object' }
44
42
  })
45
-
46
43
  let raw = response.choices[0].message.content.trim()
47
44
  raw = raw.replace(/^```json\n?/, '').replace(/\n?```$/, '')
48
45
  const match = raw.match(/[\{\[][\s\S]*[\}\]]/)
46
+ const JSON5 = require('json5')
49
47
  return JSON5.parse(match ? match[0] : raw)
50
48
 
51
49
  } catch (err) {
52
- const isAuthError = err.message.includes('401') || err.message.includes('402');
50
+ const statusCode = err.status || err.response?.status
51
+ const isAuthError = err.message.includes('401') || err.message.includes('402') || [401, 402].includes(statusCode)
53
52
  if (isAuthError) {
54
53
  // 权限错误:司令部拒绝访问
55
54
  throw new Error(language(
56
55
  '[系统警告] YoRHa 司令部拒绝访问:API Key 无效或额度耗尽,请检查!',
57
56
  '[SYSTEM ALERT] YoRHa Command Center Access Denied: Invalid API Key or quota exhausted!'
58
- ));
57
+ ))
59
58
  }
60
59
 
61
60
  // 重试警告:神经云网络连接不稳
@@ -91,7 +90,7 @@ module.exports = {
91
90
  recognizePage: async (prompt, filePath) => {
92
91
  const config = getConfig()
93
92
  const { UI_DESIGNER } = require('../prompts/system.js')
94
-
93
+ const sharp = require('sharp')
95
94
  const compressedBuffer = await sharp(filePath)
96
95
  .resize(1280, null, { withoutEnlargement: true })
97
96
  .jpeg({ quality: 80 })
@@ -116,10 +115,12 @@ module.exports = {
116
115
  /**
117
116
  * 对齐 Response 接口字段
118
117
  */
119
- alignResponseFields: async (responseStr, resourceStr) => {
118
+ alignResponseFields: async (options, responseStr, resourceStr) => {
120
119
  const config = getConfig()
121
- const apiPrompt = require('../prompts/watch-api.js')
122
120
  const { API_DESIGNER } = require('../prompts/system.js')
121
+ const promptPath = `../prompts/${options.template}/watch-api.js`
122
+ checkPromptPath(promptPath)
123
+ const apiPrompt = require(promptPath)
123
124
  return askAI(
124
125
  config.textModel,
125
126
  [
@@ -41,6 +41,22 @@ const cleanCode = str => {
41
41
  .trim() + '\n'
42
42
  }
43
43
 
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
+
44
60
  /**
45
61
  * 获取已有的页面菜单配置
46
62
  * @param {string} dir - 页面目录路径(默认 'src/pages')
@@ -109,4 +125,4 @@ const copyTemplateDir = (options, templateSubDir, targetSubDir) => {
109
125
  }
110
126
 
111
127
  // 导出工具函数
112
- module.exports = { language, getConfig, cleanCode, getExistingMenus, copyTemplateDir, generateSmartImports }
128
+ module.exports = { language, getConfig, cleanCode, getExistingMenus, copyTemplateDir, checkPromptPath, generateSmartImports }
@@ -1,10 +1,10 @@
1
- import { Modal } from 'antd'
2
1
  import { MyTable } from './MyTable'
2
+ import { Modal, Button } from 'antd'
3
3
  import { MySearchForm } from './MySearchForm'
4
4
  import { useTableQuery } from '../hooks/useTableQuery'
5
5
 
6
6
 
7
- export const MyModalTable = ({ api, onOk, title, width, footer, visible, columns, setModal, formItems, rowSelection, formatResponse, extraParams = {} }) => {
7
+ export const MyModalTable = ({ api, onOk, title, width, footer, visible, columns, setModal, formItems, rowSelection, formatResponse, functionButtons, extraParams = {} }) => {
8
8
 
9
9
  const { total, loading, dataSource, search, setSearch } = useTableQuery(api, formatResponse, extraParams)
10
10
 
@@ -22,6 +22,7 @@ export const MyModalTable = ({ api, onOk, title, width, footer, visible, columns
22
22
  return (
23
23
  <Modal centered destroyOnClose title={title} width={width} open={visible} onOk={handleOk} footer={footer} onCancel={() => setModal({ visible: false })}>
24
24
  {formItems?.length > 0 && <MySearchForm search={search} formItems={formItems} setSearch={handleSearch} syncUrlParams={false} />}
25
+ {functionButtons?.length > 0 && functionButtons.map(item => <Button key={item.name} type={item.type} onClick={item.onClick}>{item.name}</Button>)}
25
26
  <MyTable
26
27
  loading={loading}
27
28
  columns={columns}