@yorha2b-lab/autodev 2.2.0 → 3.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/bin/autodev.js CHANGED
@@ -4,6 +4,7 @@ const path = require('path')
4
4
  const chalk = require('chalk')
5
5
  const { program } = require('commander')
6
6
  const pkg = require(path.join(__dirname, '../package.json'))
7
+ const bunker = require(path.join(__dirname, '../src/core/context.js'))
7
8
  const { language, matrixEffect, bootSequence } = require(path.join(__dirname, '../src/utils/utils.js'))
8
9
 
9
10
  program
@@ -52,8 +53,11 @@ program
52
53
  .description(language('开启全频道联动监控:支持 Page/Part/API 协同构筑', 'Start full-channel linked monitoring: Coordinated Page/Part/API construction'))
53
54
  .action(() => {
54
55
  bootSequence(pkg.version)
55
- const watch = require('../src/commands/watch')
56
- watch(program.opts())
56
+ bunker.init(program.opts())
57
+ require(path.join(__dirname, '../src/commands/watch'))()
58
+ if (bunker.get().config.proxyTarget) {
59
+ require(path.join(__dirname, '../src/services/proxy-tower'))()
60
+ }
57
61
  process.on('SIGINT', () => {
58
62
  console.log('\n')
59
63
  console.log(chalk.gray('--------------------------------------------------'))
package/config.js CHANGED
@@ -17,5 +17,6 @@ module.exports = {
17
17
  componentsDir: 'src/components',
18
18
 
19
19
  responseSuccess: `response?.code === 200`,
20
+ proxyTarget: 'http://id:port',// 代理目标,例如 http://localhost:3000
20
21
 
21
22
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yorha2b-lab/autodev",
3
- "version": "2.2.0",
3
+ "version": "3.0.0",
4
4
  "description": "基于视觉大模型的前端(react+Antd)全自动 CRUD 代码生成器",
5
5
  "bin": {
6
6
  "autodev": "bin/autodev.js"
@@ -46,5 +46,8 @@
46
46
  "openai": "^6.24.0",
47
47
  "ora": "^5.4.1",
48
48
  "sharp": "^0.34.5"
49
+ },
50
+ "devDependencies": {
51
+ "http-proxy": "^1.18.1"
49
52
  }
50
53
  }
@@ -3,12 +3,13 @@ const ora = require('ora')
3
3
  const path = require('path')
4
4
  const chalk = require('chalk')
5
5
 
6
- module.exports = async (filePath, context) => {
6
+ module.exports = async (filePath, liveResponse = null) => {
7
7
 
8
- const { config, options, language, alignResponseFields } = context
8
+ const { get } = require(path.join(__dirname, '../../core/context'))
9
+ const { config, options, language, unwrapSignal, alignResponseFields } = get()
9
10
 
10
11
  const startTime = Date.now()
11
- const fileName = path.basename(filePath, path.extname(filePath))
12
+ const fileName = liveResponse?.fileName ?? path.basename(filePath, path.extname(filePath))
12
13
  const resourcePath = path.join(process.cwd(), config.pagesDir, fileName, 'resource.js')
13
14
 
14
15
  const spinner = ora({
@@ -27,28 +28,26 @@ module.exports = async (filePath, context) => {
27
28
  ))
28
29
  }
29
30
 
30
- const responseRaw = fs.readFileSync(filePath, 'utf8')
31
- let responseStr = responseRaw
31
+ let rawJson = liveResponse ? liveResponse.data : JSON.parse(fs.readFileSync(filePath, 'utf8'))
32
32
  let resourceStr = fs.readFileSync(resourcePath, 'utf8')
33
33
 
34
- try {
35
- const parsed = JSON.parse(responseRaw)
36
- const normalizedData = Array.isArray(parsed) ? parsed : [parsed]
37
- responseStr = JSON.stringify(normalizedData.slice(0, 1))
38
- } catch (e) {
34
+ const coreArray = unwrapSignal(rawJson)
35
+
36
+ if (!coreArray || coreArray.length === 0) {
39
37
  console.log(chalk.gray(language(
40
38
  ` [System] 数据格式非标准 JSON,将尝试原始字符对齐。`,
41
39
  ` [System] Data format is not standard JSON, will try to align by character.`)
42
40
  ))
43
41
  }
44
42
 
43
+ const sampleData = coreArray && coreArray.length > 0 ? [coreArray[0]] : rawJson
44
+
45
45
  spinner.text = chalk.yellow(language(
46
46
  `🧑‍💻 9S: 正在扫描前后端字段差异... 执行语义桥接任务。`,
47
47
  `🧑‍💻 9S: Scanning field differences... Bridging semantic gaps.`
48
48
  ))
49
49
 
50
- const result = await alignResponseFields(options, responseStr, resourceStr)
51
-
50
+ const result = await alignResponseFields(options, JSON.stringify(sampleData), resourceStr)
52
51
  let changeCount = 0
53
52
  const resultMapping = {}
54
53
  Object.entries(result).forEach(([oldField, newField]) => {
@@ -63,10 +62,27 @@ module.exports = async (filePath, context) => {
63
62
  const endTime = Date.now()
64
63
 
65
64
  spinner.succeed(chalk.green(language(
66
- `🤖 Pod 153: [肯定] 结果映射完成${JSON.stringify(resultMapping)}。已更正 ${changeCount} 处语义偏差。耗时: ${(endTime - startTime) / 1000}s`,
67
- `🤖 Pod 153: [Affirmative] Result mapping completed${JSON.stringify(resultMapping)}. Corrected ${changeCount} semantic deviations. Elapsed: ${(endTime - startTime) / 1000}s`
65
+ `🤖 Pod 153: [肯定] 语义桥接协议执行完毕。已物理修正 ${changeCount} 处字段偏差。耗时: ${(endTime - startTime) / 1000}s`,
66
+ `🤖 Pod 153: [Affirmative] Semantic bridge protocol complete. Corrected ${changeCount} field deviations. Elapsed: ${(endTime - startTime) / 1000}s`
68
67
  )))
69
68
 
69
+ if (changeCount > 0) {
70
+ console.log(chalk.gray(`\n┌────────────────── [ 9S 语义映射表 ] ──────────────────┐`))
71
+ Object.entries(resultMapping).forEach(([oldField, newField]) => {
72
+ // 💡 物理校准:计算空格数量,让箭头对齐在第 15 个字符位
73
+ // 中文字符长度 * 2 是为了抵消它在终端占的双倍宽度
74
+ const padding = " ".repeat(Math.max(1, 15 - oldField.length * 2))
75
+ console.log(
76
+ chalk.gray(` │ `) +
77
+ chalk.yellow(oldField) +
78
+ padding +
79
+ chalk.cyan(` -> `) +
80
+ chalk.white(newField)
81
+ )
82
+ })
83
+ console.log(chalk.gray(`└───────────────────────────────────────────────────────┘\n`))
84
+ }
85
+
70
86
  if (fs.existsSync(filePath)) {
71
87
  fs.unlinkSync(filePath)
72
88
  }
@@ -4,13 +4,15 @@ const path = require('path')
4
4
  const chalk = require('chalk')
5
5
  const stringify = require('json-stringify-pretty-compact')
6
6
 
7
- module.exports = async (filePath, context) => {
7
+ module.exports = async filePath => {
8
+
9
+ const { get } = require(path.join(__dirname, '../../core/context'))
8
10
 
9
11
  const {
10
12
  config, language, menus,
11
13
  pagePrompt, resourceTpl, indexTpl,
12
14
  recognizePage, generateMock, resource, index
13
- } = context
15
+ } = get()
14
16
 
15
17
  const startTime = Date.now()
16
18
  const fileName = path.basename(filePath, path.extname(filePath))
@@ -1,11 +1,13 @@
1
1
  const fs = require('fs')
2
2
  const ora = require('ora')
3
+ const path = require('path')
3
4
  const chalk = require('chalk')
4
5
  const stringify = require('json-stringify-pretty-compact')
5
6
 
6
- module.exports = async (filePath, context) => {
7
+ module.exports = async filePath => {
7
8
 
8
- const { language, partPrompt, recognizePage } = context
9
+ const { get } = require(path.join(__dirname, '../../core/context'))
10
+ const { language, partPrompt, recognizePage } = get()
9
11
 
10
12
  const startTime = Date.now()
11
13
 
@@ -2,19 +2,15 @@ const fs = require('fs')
2
2
  const path = require('path')
3
3
  const chalk = require('chalk')
4
4
  const chokidar = require('chokidar')
5
- const Handlebars = require('handlebars')
6
5
  const stringify = require('json-stringify-pretty-compact')
7
6
 
8
- const { createTaskQueue } = require('../core/task-queue')
9
- const { recognizePage, generateMock, alignResponseFields } = require('../services/llm.js')
10
- const { language, getConfig, getExistingMenus, copyTemplateDir } = require('../utils/utils.js')
7
+ const { get } = require(path.join(__dirname, '../core/context'))
8
+ const { copyTemplateDir } = require(path.join(__dirname, '../utils/utils.js'))
9
+ const { createTaskQueue } = require(path.join(__dirname, '../core/task-queue.js'))
11
10
 
12
- const watch = options => {
11
+ const watch = () => {
13
12
 
14
- const config = getConfig()
15
- const template = options.template
16
- const queue = createTaskQueue(2)
17
- const menus = getExistingMenus()
13
+ const { menus, config, options, template, language, apiHandler, pageHandler, partHandler } = get()
18
14
 
19
15
  const compilerPath = path.join(__dirname, `../core/${template}-compiler.js`)
20
16
  if (!fs.existsSync(compilerPath)) {
@@ -22,8 +18,6 @@ const watch = options => {
22
18
  return
23
19
  }
24
20
 
25
- const { index, resource } = require(compilerPath)
26
-
27
21
  try {
28
22
  if (config.hbsDir === '') {
29
23
  copyTemplateDir(options, 'hooks', config.hooksDir)
@@ -34,23 +28,7 @@ const watch = options => {
34
28
  console.error(language('❌ 模板构筑失败:', '❌ Template construction failed:'), error)
35
29
  }
36
30
 
37
- const tplDir = config.hbsDir !== '' ? path.join(process.cwd(), config.hbsDir) : path.join(__dirname, `../../templates/${template}`)
38
- const indexTpl = Handlebars.compile(fs.readFileSync(path.join(tplDir, 'index.hbs'), 'utf-8'))
39
- const resourceTpl = Handlebars.compile(fs.readFileSync(path.join(tplDir, 'resource.hbs'), 'utf-8'))
40
-
41
- const context = {
42
- menus, language,
43
- config, options,
44
- resource, index,
45
- resourceTpl, indexTpl,
46
- recognizePage, generateMock, alignResponseFields,
47
- pagePrompt: require(path.join(__dirname, `../prompts/${template}/watch-page.js`)),
48
- partPrompt: require(path.join(__dirname, `../prompts/${template}/watch-part.js`))
49
- }
50
-
51
- const apiHandler = require('./handlers/api-handler')
52
- const pageHandler = require('./handlers/page-handler')
53
- const partHandler = require('./handlers/part-handler')
31
+ const queue = createTaskQueue(2)
54
32
 
55
33
  queue.onIdle(() => {
56
34
  console.log(chalk.green(language(
@@ -73,8 +51,8 @@ const watch = options => {
73
51
  })
74
52
 
75
53
  console.log(chalk.magenta(language(
76
- '📡 Operator 6O: 呼叫 2B,地堡全频道联动监控已就绪!\n',
77
- '📡 Operator 6O: Calling 2B, all-channel linked monitoring is ready!\n'
54
+ '📡 Operator 6O: 呼叫 2B,地堡全频道联动监控已就绪!',
55
+ '📡 Operator 6O: Calling 2B, all-channel linked monitoring is ready!'
78
56
  )))
79
57
 
80
58
  watcher.on('add', filePath => {
@@ -82,13 +60,13 @@ const watch = options => {
82
60
  const absolutePath = path.resolve(filePath)
83
61
 
84
62
  if (absolutePath.includes('screenShot')) {
85
- queue.add(() => pageHandler(filePath, context))
63
+ queue.add(() => pageHandler(filePath))
86
64
  }
87
65
  else if (absolutePath.includes('screenPart')) {
88
- queue.add(() => partHandler(filePath, context))
66
+ queue.add(() => partHandler(filePath))
89
67
  }
90
68
  else if (absolutePath.includes('response')) {
91
- queue.add(() => apiHandler(filePath, context))
69
+ queue.add(() => apiHandler(filePath))
92
70
  }
93
71
  })
94
72
  }
@@ -0,0 +1,51 @@
1
+ const fs = require('fs')
2
+ const path = require('path')
3
+ const Handlebars = require('handlebars')
4
+ const apiHandler = require(path.join(__dirname, '../commands/handlers/api-handler'))
5
+ const pageHandler = require(path.join(__dirname, '../commands/handlers/page-handler'))
6
+ const partHandler = require(path.join(__dirname, '../commands/handlers/part-handler'))
7
+ const { recognizePage, generateMock, alignResponseFields } = require(path.join(__dirname, '../services/llm'))
8
+ const { language, getConfig, unwrapSignal, getExistingMenus } = require(path.join(__dirname, '../utils/utils'))
9
+
10
+ let instance = null // 💡 物理封存的全局实例
11
+
12
+ module.exports = {
13
+ /**
14
+ * @description 执行中枢神经元初始化
15
+ */
16
+ init: options => {
17
+
18
+ const config = getConfig()
19
+ const menus = getExistingMenus()
20
+ const template = options.template
21
+
22
+ const compilerPath = path.join(__dirname, `./${template}-compiler.js`)
23
+ const { index, resource } = require(compilerPath)
24
+
25
+ const tplDir = config.hbsDir !== ''
26
+ ? path.join(process.cwd(), config.hbsDir)
27
+ : path.join(__dirname, `../../templates/${template}`)
28
+
29
+ instance = {
30
+ menus, config, options, language, unwrapSignal,
31
+ resource, index, template,
32
+ apiHandler, pageHandler, partHandler,
33
+ recognizePage, generateMock, alignResponseFields,
34
+ indexTpl: Handlebars.compile(fs.readFileSync(path.join(tplDir, 'index.hbs'), 'utf-8')),
35
+ resourceTpl: Handlebars.compile(fs.readFileSync(path.join(tplDir, 'resource.hbs'), 'utf-8')),
36
+ pagePrompt: require(path.join(__dirname, `../prompts/${template}/watch-page.js`)),
37
+ partPrompt: require(path.join(__dirname, `../prompts/${template}/watch-part.js`))
38
+ }
39
+ return instance
40
+ },
41
+
42
+ /**
43
+ * @description 全频道信号接入:获取全局上下文
44
+ */
45
+ get: () => {
46
+ if (!instance) {
47
+ throw new Error(language('🤖 Pod 042 报警:中枢神经元尚未初始化,无法建立信号连接。', '🤖 Pod 042 Warnning:Central neuron not initialized, cannot establish signal connection.'))
48
+ }
49
+ return instance
50
+ }
51
+ }
@@ -2,7 +2,7 @@ const fs = require('fs')
2
2
  const path = require('path')
3
3
  const Handlebars = require('handlebars')
4
4
  const stringify = require('json-stringify-pretty-compact')
5
- const { cleanCode, generateSmartImports } = require('../utils/utils.js')
5
+ const { cleanCode, generateSmartImports } = require(path.join(__dirname, '../utils/utils.js'))
6
6
 
7
7
  Handlebars.registerHelper('raw', options => options.fn())
8
8
  Handlebars.registerHelper('stringify', (context, maxLength = 200) => context ? new Handlebars.SafeString(stringify.default(context, { indent: 4, maxLength })) : '[]')
@@ -68,7 +68,7 @@ const index = ({ config, fileName, indexTpl, pageConfig }) => {
68
68
  hasPagination: pageConfig.table.pagination,
69
69
  operations: pageConfig.table.operation || [],
70
70
  hasRowSelection: pageConfig.table.rowSelection,
71
- formItems: hasTabs ? 'formItems[activeKey]' : 'formItems',
71
+ formItems: hasFormItems ? (hasTabs ? 'formItems[activeKey]' : 'formItems') : '[]',
72
72
  pageStruct: hasFunctionButtons ? pageConfig.pageStruct : pageConfig.pageStruct?.filter(item => item !== 'FunctionButtonsBlock'),
73
73
  }
74
74
 
@@ -94,7 +94,7 @@ const index = ({ config, fileName, indexTpl, pageConfig }) => {
94
94
  Handlebars.registerPartial('handleBlock', `${fs.readFileSync(path.join(__dirname, '../../templates/react/handlebars/handleBlock.hbs'), 'utf-8')}\n`)
95
95
 
96
96
  const bodyCode = indexTpl(viewData)
97
- const importsStr = generateSmartImports(bodyCode, hasTabs)
97
+ const importsStr = generateSmartImports({ bodyCode, hasTabs, hasFormItems })
98
98
  return cleanCode(`${importsStr}\n\n${bodyCode}`)
99
99
  }
100
100
 
@@ -5,7 +5,7 @@ resourceStr是前端目前猜测的字段名(请从resourceStr中提取dataIndex
5
5
  responseStr是后端的真实响应。
6
6
  请比对两者,找出现有前端字段名应该被替换为哪个真实的后端字段名。
7
7
  匹配规则: 1.完全相同 2.下划线/驼峰转换 3.语义相似。
8
- 请只输出一个JSON对象, Key为前端猜测的旧名字, Value为Response里的真实新名字。
8
+ 请只输出一个JSON对象, Key为前端猜测的字段名dataIndex, Value为Response里的真实字段名。
9
9
  例如:{"key_1": "key1"}
10
10
  如果没有找到对应的,请不要包含在结果中。
11
11
  注意:⚠️⚠️如果有语义相近的两个字段优先取中文字段,比如"createByName"和"createBy",则取"createByName"
@@ -1,7 +1,7 @@
1
1
  const fs = require('fs')
2
2
  const path = require('path')
3
3
  const chalk = require('chalk')
4
- const { language, getConfig } = require('../utils/utils.js')
4
+ const { language, getConfig } = require(path.join(__dirname, '../utils/utils.js'))
5
5
 
6
6
  let client = null
7
7
 
@@ -0,0 +1,85 @@
1
+ const http = require('http')
2
+ const path = require('path')
3
+ const zlib = require('zlib')
4
+ const chalk = require('chalk')
5
+ const httpProxy = require('http-proxy')
6
+ const { get } = require(path.join(__dirname, '../core/context'))
7
+
8
+ /**
9
+ * @function startProxyTower
10
+ * @description [地堡 42153 联合波段] 启动流量拦截塔。
11
+ * 独立运行于后台,监听 42153 端口,物理截获联调过程中的 JSON 信号并触发语义对齐。
12
+ */
13
+ module.exports = () => {
14
+
15
+ const { config, language, apiHandler, unwrapSignal } = get()
16
+
17
+ const TOWER_PORT = 42153
18
+ const hackedRegistry = new Map()
19
+ const proxy = httpProxy.createProxyServer({})
20
+
21
+
22
+ // 简单的辅助函数:提取 JSON 的所有 Key 作为“指纹”
23
+ const getJsonFingerprint = obj => {
24
+ if (!obj || typeof obj !== 'object') return ''
25
+ return Object.keys(Array.isArray(obj) ? (obj[0] || {}) : obj).sort().join(',')
26
+ }
27
+
28
+ const server = http.createServer((req, res) => {
29
+
30
+ const target = config.proxyTarget
31
+
32
+ if (!target) {
33
+ // 静默模式:如果不配置 proxyTarget,拦截塔只转发不处理(或报错提示)
34
+ return
35
+ }
36
+
37
+ // 💡 物理监控:劫持响应流
38
+ proxy.on('proxyRes', function (proxyRes, req, res) {
39
+ let body = []
40
+ proxyRes.on('data', chunk => body.push(chunk))
41
+ proxyRes.on('end', async () => {
42
+ const buffer = Buffer.concat(body)
43
+ const encoding = proxyRes.headers['content-encoding']
44
+ try {
45
+ const rawBody = encoding === 'gzip' ? zlib.gunzipSync(buffer) : buffer
46
+ const json = JSON.parse(rawBody.toString())
47
+ const referer = req.headers.referer || ''
48
+ const fileName = referer.split('?')[0].split('/').filter(Boolean).at(-1)
49
+
50
+ const fingerprint = getJsonFingerprint(unwrapSignal(json)) // 获取数据指纹
51
+ const lastFingerprint = hackedRegistry.get(fileName)
52
+
53
+ // 如果指纹没变,说明字段结构是一样的,无需再次骇入
54
+ if (lastFingerprint === fingerprint) {
55
+ return
56
+ }
57
+
58
+ console.log(chalk.cyan(language(
59
+ `\n📡 Pod 153: 截获运行时信号 [${fileName}]。执行自动对齐协议...`,
60
+ `\n📡 Pod 153: Captured runtime signal [${fileName}]. Executing semantic alignment protocol...`
61
+ )))
62
+ // 💡 直接调用 api-handler 物理更新 resource.js
63
+ await apiHandler(null, { fileName, data: json })
64
+ hackedRegistry.set(fileName, fingerprint)
65
+ } catch (e) {
66
+ console.log(e)
67
+ // 非 JSON 信号,保持静默
68
+ }
69
+ })
70
+ })
71
+ // 转发至真实后端
72
+ proxy.web(req, res, { target, changeOrigin: true })
73
+ })
74
+
75
+ server.listen(TOWER_PORT, () => {
76
+ console.log(chalk.magenta(language(
77
+ `✨ YoRHa 联合基站:信号拦截塔已在线 [波段: ${TOWER_PORT}]`,
78
+ `✨ YoRHa Joint Station: Signal Intercept Tower Online [Band: ${TOWER_PORT}]`
79
+ )))
80
+ console.log(chalk.gray(language(
81
+ `💡 指令:请将您的代理目标指向 http://localhost:${TOWER_PORT}`,
82
+ `💡 Command: Please point your local proxy target to http://localhost:${TOWER_PORT}`
83
+ )))
84
+ })
85
+ }
@@ -56,6 +56,30 @@ const cleanCode = str => {
56
56
  .trim() + '\n'
57
57
  }
58
58
 
59
+ /**
60
+ * @function unwrapSignal
61
+ * @description [地堡数据脱水机] 物理扫描 JSON 结构,剥离业务外壳(code/msg/total 等)。
62
+ * 目标:精准定位到核心的 Array。
63
+ */
64
+ const unwrapSignal = (json) => {
65
+ if (Array.isArray(json)) return json
66
+
67
+ // 💡 扫描常见的数据仓库 Key
68
+ const dataKeys = ['data', 'list', 'items', 'datas', 'rows', 'result', 'payload', 'results', 'dataList']
69
+ for (const key of dataKeys) {
70
+ if (json[key] && Array.isArray(json[key])) return json[key]
71
+ }
72
+
73
+ // 💡 递归侦察:处理 data: { list: [...] } 这种二级套娃
74
+ for (const key in json) {
75
+ if (json[key] && typeof json[key] === 'object') {
76
+ const nested = unwrapSignal(json[key])
77
+ if (Array.isArray(nested)) return nested
78
+ }
79
+ }
80
+ return null
81
+ }
82
+
59
83
  /**
60
84
  * 引导序列
61
85
  * 模拟系统引导过程中的动画效果
@@ -174,25 +198,25 @@ const getExistingMenus = (dir = 'src/pages') => {
174
198
  * @param {boolean} hasTabs - 是否包含标签页
175
199
  * @returns {string} 拼接后的 import 语句
176
200
  */
177
- const generateSmartImports = (codeStr, hasTabs) => {
201
+ const generateSmartImports = ({ bodyCode, hasTabs, hasFormItems }) => {
178
202
  const hooksLib = ['useTableQuery']
179
203
  const reactLib = ['useState', 'useEffect', 'useRef', 'useMemo']
180
204
  const componentsLib = ['MyTable', 'MyModalForm', 'MySearchForm']
181
205
  const antdLib = ['Card', 'Space', 'Modal', 'Button', 'Alert', 'Table', 'Input', 'Select']
182
206
 
183
- const usedAntd = antdLib.filter(name => new RegExp(`\\b${name}\\b`).test(codeStr))
184
- const usedHooks = hooksLib.filter(name => new RegExp(`\\b${name}\\b`).test(codeStr))
185
- const usedReact = reactLib.filter(name => new RegExp(`\\b${name}\\b`).test(codeStr))
186
- const usedComps = componentsLib.filter(name => new RegExp(`\\b${name}\\b`).test(codeStr))
207
+ const usedAntd = antdLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
208
+ const usedHooks = hooksLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
209
+ const usedReact = reactLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
210
+ const usedComps = componentsLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
187
211
 
188
212
  const imports = [
189
213
  usedReact.length && `import { ${usedReact.join(', ')} } from 'react'`,
190
214
  `import { request } from '../../utils/request'`,
191
215
  `import { formatQuery } from '../../utils/utils'`,
192
- `import { ${hasTabs ? 'tabs, ' : ''}formItems, modalItems, tableColumns} from './resource'`,
216
+ usedAntd.length && `import { Form, ${usedAntd.join(', ')} } from 'antd'`,
193
217
  ...usedHooks.map(hook => `import { ${hook} } from '../../hooks/${hook}'`),
194
218
  ...usedComps.map(comp => `import { ${comp} } from '../../components/${comp}'`),
195
- usedAntd.length && `import { Form, ${usedAntd.join(', ')} } from 'antd'`
219
+ `import { ${hasTabs ? 'tabs, ' : ''}${hasFormItems ? 'formItems, ' : ''}modalItems, tableColumns} from './resource'`,
196
220
  ].sort((a, b) => a.length - b.length)
197
221
 
198
222
  return imports.filter(Boolean).join('\n')
@@ -218,4 +242,4 @@ const copyTemplateDir = (options, templateSubDir, targetSubDir) => {
218
242
  })
219
243
  }
220
244
 
221
- module.exports = { language, getConfig, cleanCode, matrixEffect, bootSequence, getExistingMenus, copyTemplateDir, generateSmartImports }
245
+ module.exports = { language, getConfig, cleanCode, unwrapSignal, matrixEffect, bootSequence, getExistingMenus, copyTemplateDir, generateSmartImports }
@@ -40,6 +40,7 @@ const AliyunOSSUpload = ({ value, onChange, ...restProps }) => {
40
40
  try {
41
41
  const result = await initOSS(url, options)
42
42
  setOSSData(result)
43
+ return result
43
44
  } catch (err) {
44
45
  console.log(err)
45
46
  }
@@ -79,12 +80,13 @@ const AliyunOSSUpload = ({ value, onChange, ...restProps }) => {
79
80
  * 若令牌已失效(过期),则强行拦截并执行同步刷新协议,同时执行物理路径归一化。
80
81
  */
81
82
  const beforeUpload = async file => {
83
+ let currentOSS = OSSData
82
84
  const expire = Number(OSSData.expire) * 1000
83
85
  if (expire < Date.now()) {
84
- await init()
86
+ currentOSS = await init()
85
87
  }
86
88
  // 💡 物理路径重组:通过正则清除多余的路径分隔符,确保存储节点坐标唯一
87
- file.url = `${OSSData?.dir ?? path}/${file.uid}_${file.name}`.replace(/\/\//g, '/')
89
+ file.url = `${currentOSS?.dir ?? path}/${file.uid}_${file.name}`.replace(/\/\//g, '/')
88
90
  return file
89
91
  }
90
92
 
@@ -1,7 +1,3 @@
1
- {{!--
2
- 📡 [地堡战术响应模组]
3
- 负责物理封存所有交互事件:包含行级操作、全局按钮、页签切换及弹窗构筑提交。
4
- --}}
5
1
  {{#each operations}}
6
2
  const {{this.action}} = async record => {
7
3
  const response = await request('/api')
@@ -1,28 +1,15 @@
1
- {{!--
2
- 📡 [地堡核心驱动引擎]:逻辑链路全自动构筑
3
- 1. 执行“传感器对齐”:从 URL 中提取历史信号,实现状态持久化
4
- 2. 激活“useTableQuery”:物理封存分页、搜索、及动态列加载逻辑
5
- --}}
6
-
7
1
  const initParams = {{#if hasTabs}}{ type: tabs[0].key }{{else}}{}{{/if}}
8
2
 
9
- // 💡 信号自愈协议:将 URL 里的字符串参数解压,并根据零部件定义执行“物理脱水(格式化)”
10
3
  const query = formatQuery(Object.fromEntries(new URLSearchParams(location.search).entries()), {{formItems}})
11
4
 
12
- // 💡 物理启动反应堆:统领全局数据流,具备防竞态与指纹识别功能
13
5
  const { total, columns, loading, dataSource, search, setSearch, setDataSource, refresh } = useTableQuery({
14
- // 执行“远程侦察任务”:通过 POST 协议向地堡后端请求物资
15
6
  api: async params => await request('/api/{{fileName}}', { method: 'POST', body: params }),
16
- // 物理参数对齐:优先级 = [默认值] < [页签预设] < [URL 历史信号]
17
7
  initialParams: { pageNo: 1, pageSize: 10, ...initParams, ...query },
18
- // 基础装配包:加载由 Pod 042 视觉扫描产出的静态列定义
19
8
  cols:tableColumns,
20
- // 信号解码协议:将后端吐出的加密数据包转化为 UI 可读的物理单元
21
9
  formatResponse: response => {
22
10
  return {
23
11
  data: response?.data ?? [],
24
12
  total: response?.data?.total ?? 0,
25
- // 💡 [高阶自愈] 若后端下发了最新的列结构,地堡将自动执行“全频道物理覆盖”
26
13
  columns: undefined,//可选,解析接口动态列;优先级高于cols
27
14
  }
28
15
  },
@@ -1,8 +1,9 @@
1
1
 
2
- {{!-- 📡 [地堡状态模组] 物理信号初始化:驱动弹窗、页签及数据勾选等核心交互单元 --}}
3
2
  const rowKey = 'id'
3
+ {{#if hasFormItems}}
4
4
  const [form] = Form.useForm()
5
- const [modal, setModal] = useState({ visible:false, title:'', formItems:[] })
5
+ {{/if}}
6
+ const [modal, setModal] = useState({ visible:false, title:'', formItems:modalItems })
6
7
  {{#if hasRowSelection}}
7
8
  const [selectedRows, setSelectedRows] = useState([])
8
9
  {{/if}}
@@ -1,16 +1,12 @@
1
1
  export default props => {
2
2
 
3
- {{!-- 💡 初始化状态模组:物理封存 Modal, SelectedRows, Tabs 等信号 --}}
4
3
  {{> stateBlock }}
5
4
 
6
- {{!-- 💡 逻辑驱动引擎:加载 useTableQuery 抗干扰 Hook --}}
7
5
  {{> hookBlock }}
8
6
 
9
- {{!-- 💡 战术响应模组:物理封存点击事件、搜索触发及弹窗调度逻辑 --}}
10
7
  {{> handleBlock }}
11
8
 
12
9
  {{#if hasOperate}}
13
- {{!-- 💡 近战处决协议:当检测到表格操作列信号时,动态注入行级操作逻辑 --}}
14
10
  {{> tableOperate }}
15
11
  {{/if}}
16
12
 
@@ -24,10 +20,8 @@ export default props => {
24
20
  {{/if}}
25
21
 
26
22
  return (
27
- {{!-- 💡 物理外壳:根据是否有页签动态切换 Card 涂装 --}}
28
23
  <Card {{#if hasTabs}}tabList={tabs} activeTabKey={activeKey} onTabChange={onTabChange}{{/if}}>
29
24
  {modal.visible && <MyModalForm {...modal} submit={modalSubmit} setModal={setModal} />}
30
- {{!-- 💡 动态装配流水线:按照图片扫描出的顺序进行物理排列 --}}
31
25
  {{#each pageStruct as |partialName|}}
32
26
  {{> (partialName) @root }}
33
27
  {{/each}}