@yorha2b-lab/autodev 5.6.2 → 5.7.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.
@@ -5,18 +5,21 @@ module.exports = {
5
5
  dataCamouflage: fileName => `正在突破目標防火牆... 執行資料偽裝程序 [${fileName}]`,
6
6
  },
7
7
  pod042: {
8
+ startScout: '啟動【右鍵一鍵快照】模式...',
9
+ capturedToast: '圖像情報已擷取,開始傳輸...',
8
10
  extractingUiMetadata: '正在從神經雲網路提取 UI 中繼資料...',
9
11
  simulate: '攔截到實際請求。正在空投標準模擬包: example.json',
10
- queueEmpty: '佇列已清空,正在向 Bunker 同步 Menu 路由設定...',
11
- uploadVisualMetadata: '正在上傳視覺中繼資料至司令部,執行語意分析...',
12
- visualPartCaptured: '偵測到局部視覺樣本。正在執行「碎片構築協議」...',
13
12
  partialConstruction: time => `報告:局部構築完成。耗時: ${time}s`,
13
+ visualPartCaptured: '偵測到局部視覺樣本。正在執行「碎片構築協議」...',
14
14
  partialRecommendation: '│ 建議:請手動將上述程式碼區塊整合至目標檔案',
15
+ uploadVisualMetadata: '正在上傳視覺中繼資料至司令部,執行語意分析...',
16
+ scoutReady: '【右鍵快照模式就緒】在瀏覽器頁面任意位置點擊【滑鼠右鍵】即可秒截屏',
15
17
  constructionAborted: virus => `構築中斷。偵測到邏輯病毒或連線逾時:${virus}`,
18
+ capturedPage: pageName => `擷取頁面【${pageName}】-> 已投遞至 screenShot 目錄`,
16
19
  partialConstructionAborted: virus => `[警告] 碎片構築失敗。系統偵測到邏輯干擾:${virus}`,
17
- visualCaptured: fileName => `視覺感測器捕捉完成: [${fileName}]。正在調配 Bunker 資源進行物理構築...`,
18
20
  intercept: fileName => `模組 [${fileName}] 已存在於 Bunker 資料庫中。為避免資料覆蓋,構築協議已跳過`,
19
- assemblyComplete: (fileName, time) => `構築協議執行完成。模組 [${fileName}] 已完成物理裝配。耗時: ${time}s`,
21
+ visualCaptured: fileName => `視覺感測器捕捉完成: [${fileName}]。正在調配 Bunker 資源進行物理構築...`,
22
+ assemblyComplete: (fileName, time) => `構築協議執行完成。模組 [${fileName}] 已完成物理裝配。耗時: ${time}s,開始同步 Menu 路由設定...`,
20
23
  },
21
24
  pod153: {
22
25
  signalLinkFault: virus => `訊號鏈路故障: ${virus}`,
@@ -55,10 +58,7 @@ module.exports = {
55
58
  frameworkNotSupported: template => `暫不支援 [${template}] 框架。歡迎提交 Pull Request 貢獻`,
56
59
  strategicThreshold: (target, current) => `物理複製總數已超越 ${target} 戰略閾值!目前戰力:${current}`,
57
60
  initComplete: cmd => `Bunker 部署完成,為更快速進入戰場,建議手動將 ${cmd} 加入 package.json scripts`,
58
- isLegendary: (unlockAchievement, current, target) =>
59
- unlockAchievement
60
- ? '恭喜您指揮官,您的構築協議已成為人類榮光的一部分'
61
- : `目前構築總數:${current}。距離 ${target} 徽章還剩 ${target - current} 次`,
61
+ isLegendary: (unlockAchievement, current, target) => unlockAchievement ? '恭喜您指揮官,您的構築協議已成為人類榮光的一部分' : `目前構築總數:${current}。距離 ${target} 徽章還剩 ${target - current} 次`,
62
62
  },
63
63
  operator6O: {
64
64
  call2B: '呼叫 2B,Bunker 全頻道聯動監控已準備完成!',
@@ -1,10 +1,116 @@
1
1
  module.exports = ({ utils, engine }) => {
2
2
 
3
3
  const { indexTpl, resourceTpl } = engine
4
+ const { wrapCode, cleanCode, contextStringify } = utils.generator
4
5
  const { needMock, responseSuccess } = utils.foundation.getConfig()
5
- const { cleanCode, contextStringify, generateSmartImports, formatFormItemAndColumns } = utils.generator
6
+
7
+ const formatFormItemAndColumns = ({ pageConfig }) => {
8
+
9
+ const codePresets = {
10
+ money: 'text => moneyRender(text)',
11
+ date: 'text => timeRender({time: text})',
12
+ index: '(_, record, index) => index + 1',
13
+ tag: `text => <Tag color='magenta'>{text}</Tag>`,
14
+ badge: `text => <Badge status='success' text={text} />`,
15
+ enum: dataIndex => `text => ${dataIndex}Options.find(item => item.value === text)?.label ?? text`,
16
+ }
17
+
18
+ const columns = pageConfig.table?.columns ?? pageConfig?.columns ?? []
19
+
20
+ const tableDicts = columns?.filter(item => item.type === 'enum')?.map(item => `${item.dataIndex}Options`) ?? []
21
+ const formDicts = pageConfig.formItems?.filter(item => item.type === 'select')?.map(item => `${item.name}Options`) ?? []
22
+ const dictBlocks = Array.from(new Set([...formDicts, ...tableDicts]))
23
+
24
+ const formItems = pageConfig.formItems?.map(item => {
25
+ if (item.type === 'text') {
26
+ delete item.type
27
+ }
28
+ return {
29
+ ...item,
30
+ ...(item.type === 'select' ? { options: wrapCode(`${item.name}Options`) } : {})
31
+ }
32
+ })
33
+
34
+ const processedColumns = columns?.map(col => {
35
+ if (col.type === 'text') {
36
+ delete col.type
37
+ }
38
+ if (['image'].includes(col.type)) {
39
+ return { ...col, renderAction: true }
40
+ }
41
+ if (col.type && codePresets[col.type]) {
42
+ const renderCode = typeof codePresets[col.type] === 'function' ? codePresets[col.type](col.dataIndex) : codePresets[col.type]
43
+ return { ...col, render: wrapCode(renderCode) }
44
+ }
45
+ return col
46
+ })
47
+
48
+ return { formItems, dictBlocks, processedColumns }
49
+ }
50
+
51
+ const generateSmartImports = ({ module, hasTabs, bodyCode, hasFormItems }) => {
52
+
53
+ const hooksLib = ['useTableQuery']
54
+ const utilsLib = ['timeRender', 'moneyRender']
55
+ const reactLib = ['useState', 'useEffect', 'useRef', 'useMemo']
56
+ const componentsLib = ['MyTable', 'MyImage', 'MyModalForm', 'MySearchForm']
57
+ const antdLib = ['Tag', 'Card', 'Badge', 'Space', 'Modal', 'Alert', 'Image', 'Table', 'Input', 'Select', 'Button']
58
+
59
+ const usedAntd = antdLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
60
+ const usedUtils = utilsLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
61
+ const usedHooks = hooksLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
62
+ const usedReact = reactLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
63
+ const usedComps = componentsLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
64
+
65
+ const imports = [
66
+ usedReact.length && `import { ${usedReact.join(', ')} } from 'react'`,
67
+ usedAntd.length && `import { ${hasFormItems && module === 'index' ? 'Form, ' : ''}${usedAntd.join(', ')} } from 'antd'`,
68
+ ...usedHooks.map(hook => `import { ${hook} } from '../../hooks/${hook}'`),
69
+ ...usedComps.map(comp => `import { ${comp} } from '../../components/${comp}'`),
70
+ ...(module === 'index' ? [
71
+ `import { request } from '../../utils/request'`,
72
+ `import { formatQuery } from '../../utils/utils'`,
73
+ `import { ${hasTabs ? 'tabs, ' : ''}${hasFormItems ? 'formItems, ' : ''}modalItems, tableColumns} from './resource'`
74
+ ] : [
75
+ usedUtils.length && `import { ${usedUtils.join(', ')} } from '../../utils/utils'`
76
+ ]),
77
+ ].sort((a, b) => a.length - b.length)
78
+
79
+ return imports.filter(Boolean).join('\n')
80
+ }
6
81
 
7
82
  return {
83
+ formatFormItemAndColumns,
84
+ resource: ({ pageConfig }) => {
85
+
86
+ const { formItems, processedColumns, dictBlocks } = formatFormItemAndColumns({ pageConfig })
87
+
88
+ const hasTabs = pageConfig.tabs?.length > 0
89
+ const hasFormItems = pageConfig.formItems?.length > 0
90
+ const tabKeys = pageConfig.tabs?.map(tab => tab.key).sort((a, b) => a.length - b.length)
91
+ const optionDict = pageConfig.optionList?.reduce((acc, item) => ({ ...acc, [item.name]: item.options }), {})
92
+
93
+ const columnsData = processedColumns.filter(item => !['操作', 'operation'].includes(item.title?.toLowerCase()))?.map(item => {
94
+ delete item.type
95
+ return item
96
+ })
97
+
98
+ const viewData = {
99
+ hasTabs,
100
+ columnsData,
101
+ hasFormItems,
102
+ tabs: pageConfig.tabs,
103
+ dictBlocks: dictBlocks.map(item => ({ name: item, data: optionDict[item] ?? [] })),
104
+ tabColumns: contextStringify({ context: Object.fromEntries(tabKeys.map(tab => [tab, wrapCode('commonColumns')])), maxLength: 100 }),
105
+ formItemsData: !hasTabs ?
106
+ `export const formItems = ${contextStringify({ context: formItems, maxLength: 120 })}` :
107
+ `const searchItems = ${contextStringify({ context: formItems, maxLength: 120 })}\n\nexport const formItems = ${contextStringify({ context: Object.fromEntries(tabKeys.map(tab => [tab, wrapCode('searchItems')])), maxLength: 100 })}`,
108
+ }
109
+
110
+ const bodyCode = resourceTpl(viewData)
111
+ const importsStr = generateSmartImports({ module: 'resource', hasTabs, bodyCode, hasFormItems })
112
+ return cleanCode(`${importsStr}\n\n${bodyCode}`)
113
+ },
8
114
  index: ({ fileName, pageConfig }) => {
9
115
  const hasTabs = pageConfig.tabs?.length > 0
10
116
  const hasPagination = pageConfig.table.pagination
@@ -21,7 +127,7 @@ module.exports = ({ utils, engine }) => {
21
127
  columnsValue = `${columnsValue}.concat(operate)`
22
128
  }
23
129
 
24
- const imgAction = Object.fromEntries(pageConfig.table?.columns?.filter(item => item.type === 'image')?.map(item => [item.dataIndex, `_CODE_(_, record) => <a onClick={() => showImg(record, '${item.dataIndex}')}>查看图片</a>_CODE_`]))
130
+ const imgAction = Object.fromEntries(pageConfig.table?.columns?.filter(item => item.type === 'image')?.map(item => [item.dataIndex, wrapCode(`(_, record) => <a onClick={() => showImg(record, '${item.dataIndex}')}>查看图片</a>`)]))
25
131
  const renderAction = `{${contextStringify({ context: imgAction, maxLength: 120 })}}`.replace(/\n/g, '\n ')
26
132
 
27
133
  const viewData = {
@@ -50,35 +156,5 @@ module.exports = ({ utils, engine }) => {
50
156
  const importsStr = generateSmartImports({ module: 'index', hasTabs, bodyCode, hasFormItems })
51
157
  return cleanCode(`${importsStr}\n\n${bodyCode}`)
52
158
  },
53
- resource: ({ pageConfig }) => {
54
-
55
- const { formItems, processedColumns, dictBlocks } = formatFormItemAndColumns({ pageConfig })
56
-
57
- const hasTabs = pageConfig.tabs?.length > 0
58
- const hasFormItems = pageConfig.formItems?.length > 0
59
- const tabKeys = pageConfig.tabs.map(tab => tab.key).sort((a, b) => a.length - b.length)
60
- const optionDict = pageConfig.optionList?.reduce((acc, item) => ({ ...acc, [item.name]: item.options }), {})
61
-
62
- const columnsData = processedColumns.map(item => {
63
- delete item.type
64
- return item
65
- })
66
-
67
- const viewData = {
68
- hasTabs,
69
- columnsData,
70
- hasFormItems,
71
- tabs: pageConfig.tabs,
72
- dictBlocks: dictBlocks.map(item => ({ name: item, data: optionDict[item] ?? [] })),
73
- tabColumns: contextStringify({ context: Object.fromEntries(tabKeys.map(tab => [tab, '_CODE_commonColumns_CODE_'])), maxLength: 100 }),
74
- formItemsData: !hasTabs ?
75
- `export const formItems = ${contextStringify({ context: formItems, maxLength: 120 })}` :
76
- `const searchItems = ${contextStringify({ context: formItems, maxLength: 120 })}\n\nexport const formItems = ${contextStringify({ context: Object.fromEntries(tabKeys.map(tab => [tab, '_CODE_searchItems_CODE_'])), maxLength: 100 })}`,
77
- }
78
-
79
- const bodyCode = resourceTpl(viewData)
80
- const importsStr = generateSmartImports({ module: 'resource', hasTabs, bodyCode, hasFormItems })
81
- return cleanCode(`${importsStr}\n\n${bodyCode}`)
82
- }
83
159
  }
84
160
  }
@@ -9,7 +9,7 @@ const { total, columns, loading, dataSource, search, setSearch, setDataSource, r
9
9
  cols:tableColumns,
10
10
  formatResponse: response => {
11
11
  return {
12
- data: response?.data ?? [],
12
+ data: response?.data?.datas ?? [],
13
13
  total: response?.data?.total ?? 0,
14
14
  columns: undefined,//可选,解析接口动态列;优先级高于cols
15
15
  }
@@ -12,11 +12,10 @@ module.exports = {
12
12
  const { index, resource } = generator
13
13
  const { generateMock, recognizePage } = llm
14
14
  const { contextStringify } = utils.generator
15
- const { useDemo, pagesDir, needMock } = utils.foundation.getConfig()
15
+ const { useDemo, pagesDir, utilsDir, needMock } = utils.foundation.getConfig()
16
16
 
17
17
 
18
18
  const startTime = Date.now()
19
- const menus = utils.foundation.getExistingMenus(pagesDir)
20
19
  const fileName = path.basename(filePath, path.extname(filePath))
21
20
  const mockDir = path.join(process.cwd(), 'mock')
22
21
  const targetDir = path.join(process.cwd(), pagesDir, fileName)
@@ -44,10 +43,6 @@ module.exports = {
44
43
  fs.writeFileSync(path.join(targetDir, 'resource.js'), resource({ pageConfig }))
45
44
  fs.writeFileSync(path.join(targetDir, 'index.js'), index({ fileName, pageConfig }))
46
45
 
47
- if (!menus.find(m => m.key === fileName)) {
48
- menus.push({ label: fileName, key: fileName })
49
- }
50
-
51
46
  if (needMock) {
52
47
  nineS.update(spinner, dialog.nineS.dataCamouflage(fileName))
53
48
  const rawContent = await generateMock({ columns: pageConfig.table.columns, fileName })
@@ -60,6 +55,9 @@ module.exports = {
60
55
 
61
56
  if (fs.existsSync(filePath)) {
62
57
  fs.unlinkSync(filePath)
58
+ const cwdUtilsDir = path.join(process.cwd(), utilsDir)
59
+ if (!fs.existsSync(cwdUtilsDir)) fs.mkdirSync(cwdUtilsDir, { recursive: true })
60
+ fs.writeFileSync(path.join(cwdUtilsDir, 'menus.js'), `export const menus = ${contextStringify({ context: utils.foundation.getExistingMenus(pagesDir), maxLength: 50 })}`)
63
61
  }
64
62
 
65
63
  } catch (error) {
@@ -5,12 +5,13 @@ module.exports = {
5
5
  async handle(filePath) {
6
6
 
7
7
  const chalk = require('chalk')
8
- const { llm, utils, yorha, dialog, prompts } = require('../bootstrap').get()
8
+ const { llm, utils, yorha, dialog, prompts, generator } = require('../bootstrap').get()
9
9
 
10
10
  const { pod042 } = yorha
11
11
  const { recognizePage } = llm
12
12
  const { part: prompt } = prompts
13
- const { cleanCode, contextStringify, formatFormItemAndColumns } = utils.generator
13
+ const { formatFormItemAndColumns } = generator
14
+ const { cleanCode, contextStringify } = utils.generator
14
15
 
15
16
  const startTime = Date.now()
16
17
 
@@ -80,7 +80,7 @@ module.exports = {
80
80
  console.log(chalk.magenta(`└────────────────────────────────────────────────────┘`))
81
81
  }
82
82
 
83
- if (enumParams) {
83
+ if (enumParams !== '{}') {
84
84
  console.log(chalk.magenta(`\n┌──────── [ YoRHa Physical Assembly: Enum Genomes ] ────────┐`))
85
85
  console.log(chalk.gray(dialog.bunker.copyEnum))
86
86
  console.log(chalk.white(cleanCode(enumParams)))
@@ -1,4 +1,4 @@
1
- module.exports = (concurrency = 1) => {
1
+ module.exports = (concurrency = 1, { yorha, dialog }) => {
2
2
 
3
3
  let running = 0
4
4
  let queue = []
@@ -14,7 +14,7 @@ module.exports = (concurrency = 1) => {
14
14
  try {
15
15
  await task()
16
16
  } catch (err) {
17
- console.error('任务执行异常:', err)
17
+ yorha.pod153.report(dialog.pod153.signalLinkFault(err.message), 'red')
18
18
  } finally {
19
19
  running--
20
20
  next()
package/src/labs/index.js CHANGED
@@ -2,7 +2,7 @@ module.exports = accessPoint => {
2
2
 
3
3
  const labs = {}
4
4
 
5
- const { apiDoc, needMock, proxyTarget, enableAutoAlignment } = accessPoint.utils.foundation.getConfig()
5
+ const { apiDoc, remains, needMock, proxyTarget, enableAutoAlignment } = accessPoint.utils.foundation.getConfig()
6
6
 
7
7
  if (!needMock && proxyTarget && enableAutoAlignment) {
8
8
  labs.tower = require('../labs/tower')(accessPoint)
@@ -12,5 +12,9 @@ module.exports = accessPoint => {
12
12
  labs.council = require('../labs/council')(accessPoint)
13
13
  }
14
14
 
15
+ if (remains) {
16
+ require('../labs/scout')(accessPoint).archeology(remains)
17
+ }
18
+
15
19
  return labs
16
20
  }
@@ -0,0 +1,110 @@
1
+ const fs = require('fs')
2
+ const path = require('path')
3
+
4
+ let globalBrowser = null
5
+
6
+ module.exports = ({ yorha, dialog }) => {
7
+
8
+ const { pod042 } = yorha
9
+
10
+ const isHttpURL = str => {
11
+ try {
12
+ const url = new URL(str)
13
+ return ['http:', 'https:'].includes(url.protocol)
14
+ } catch {
15
+ return false
16
+ }
17
+ }
18
+
19
+ const derivePageNameFromUrl = rawUrl => {
20
+ const parsed = new URL(rawUrl)
21
+ let routePath = parsed.hash ? parsed.hash.replace(/^#/, '') : parsed.pathname
22
+ routePath = routePath.split('?')[0].replace(/^\/+|\/+$/g, '')
23
+ if (!routePath) return 'Home'
24
+ const parts = routePath.split(/[/\-_]/).filter(Boolean)
25
+ return parts.at(-1) ?? 'capturedPage'
26
+ }
27
+
28
+ return {
29
+ archeology: async targetUrl => {
30
+
31
+ if (!isHttpURL(targetUrl)) {
32
+ return
33
+ }
34
+
35
+ pod042.report(dialog.pod042.startScout, 'green')
36
+
37
+ const puppeteer = require('puppeteer')
38
+ const screenshotDir = path.join(process.cwd(), 'bunker', 'screenShot')
39
+ const sessionDir = path.join(process.cwd(), 'bunker', '.chrome_session')
40
+
41
+ let isBrowserAlive = false
42
+ if (globalBrowser) {
43
+ try {
44
+ await globalBrowser.pages()
45
+ isBrowserAlive = true
46
+ } catch (e) {
47
+ globalBrowser = null
48
+ }
49
+ }
50
+
51
+ if (!isBrowserAlive) {
52
+
53
+ ['SingletonLock', 'SingletonSocket', 'SingletonCookie'].forEach(file => {
54
+ try { fs.unlinkSync(path.join(sessionDir, file)) } catch (e) { }
55
+ })
56
+
57
+ globalBrowser = await puppeteer.launch({
58
+ headless: false,
59
+ handleSIGINT: false,
60
+ defaultViewport: null,
61
+ userDataDir: sessionDir,
62
+ args: ['--start-maximized']
63
+ })
64
+ }
65
+
66
+ const pages = await globalBrowser.pages()
67
+ const page = pages.length > 0 ? pages[0] : await globalBrowser.newPage()
68
+
69
+ try {
70
+ await page.exposeFunction('nodeTakeScreenshot', async () => {
71
+ const currentUrl = await page.url()
72
+ const pageName = derivePageNameFromUrl(currentUrl)
73
+ const savePath = path.join(screenshotDir, `${pageName}.png`)
74
+ await page.screenshot({ path: savePath, fullPage: true })
75
+ pod042.report(dialog.pod042.capturedPage(pageName), 'green')
76
+ })
77
+
78
+ await page.evaluateOnNewDocument(() => {
79
+ if (window.__hasBunkerListener__) return
80
+ window.__hasBunkerListener__ = true
81
+ window.addEventListener('contextmenu', (e) => {
82
+ e.preventDefault()
83
+ if (window.nodeTakeScreenshot) {
84
+ window.nodeTakeScreenshot()
85
+ }
86
+ const toast = document.createElement('div')
87
+ toast.innerText = dialog.pod042.capturedToast
88
+ toast.style.cssText = `
89
+ position: fixed; top: 20px; right: 20px; z-index: 999999;
90
+ background: rgba(0, 0, 0, 0.85); color: #00ffcc;
91
+ border: 1px solid #00ffcc; padding: 12px 24px;
92
+ font-size: 15px; font-family: monospace; border-radius: 4px;
93
+ box-shadow: 0 0 15px rgba(0, 255, 204, 0.5);
94
+ pointer-events: none; transition: opacity 0.4s ease;
95
+ `
96
+ document.body.appendChild(toast)
97
+ setTimeout(() => {
98
+ toast.style.opacity = '0'
99
+ setTimeout(() => toast.remove(), 400)
100
+ }, 1200)
101
+ })
102
+ })
103
+ } catch (error) { }
104
+
105
+ await page.goto(targetUrl)
106
+ pod042.report(dialog.pod042.scoutReady, 'green')
107
+ return globalBrowser
108
+ }
109
+ }
110
+ }
package/src/labs/tower.js CHANGED
@@ -54,8 +54,8 @@ module.exports = ({ utils, yorha, dialog, handlers }) => {
54
54
  }
55
55
 
56
56
  pod153.report(dialog.pod153.capturedRuntimeSignal(fileName))
57
- // 💡 直接调用 api-handler 物理更新 resource.js
58
- await handlers.api.handle(null, { fileName, data: json })
57
+ // 💡 直接调用 response-handler 物理更新 resource.js
58
+ await handlers.response.handle(null, { fileName, data: json })
59
59
  hackedRegistry.set(fileName, fingerprint)
60
60
  } catch (e) {
61
61
  // 非 JSON 信号,保持静默
@@ -12,6 +12,12 @@ const getConfig = () => {
12
12
  return config
13
13
  }
14
14
 
15
+ const findRoute = (routes, filePath) => {
16
+ const relative = path.relative(path.resolve('bunker'), path.resolve(filePath))
17
+ const root = relative.split(path.sep)[0]
18
+ return routes.find(route => root === route.watch)
19
+ }
20
+
15
21
  const getExistingMenus = (dir = 'src/pages') => {
16
22
  const pagesDir = path.join(process.cwd(), dir)
17
23
  if (!fs.existsSync(pagesDir)) return []
@@ -36,6 +42,7 @@ const copyTemplateDir = (template, templateSubDir, targetSubDir) => {
36
42
 
37
43
  module.exports = {
38
44
  getConfig,
45
+ findRoute,
39
46
  copyTemplateDir,
40
47
  getExistingMenus,
41
48
  }
@@ -1,5 +1,7 @@
1
1
  const stringify = require('json-stringify-pretty-compact')
2
2
 
3
+ const wrapCode = code => `_CODE_${code}_CODE_`
4
+
3
5
  const cleanCode = str => str
4
6
  .replace(/```[a-z]*\n?/gi, '')// 物理超度 Markdown 糖衣(解决```json 报错)
5
7
  .replace(/```/g, '')
@@ -13,86 +15,10 @@ const cleanCode = str => str
13
15
  .replace(/^\s+/, '') // 去掉文件头部的空行
14
16
  .trim() + '\n'
15
17
 
16
- const formatFormItemAndColumns = ({ pageConfig }) => {
17
-
18
- const codePresets = {
19
- money: 'text => moneyRender(text)',
20
- date: 'text => timeRender({time: text})',
21
- index: '(_, record, index) => index + 1',
22
- tag: `text => <Tag color='magenta'>{text}</Tag>`,
23
- badge: `text => <Badge status='success' text={text} />`,
24
- enum: dataIndex => `text => ${dataIndex}Options.find(item => item.value === text)?.label ?? text`,
25
- }
26
-
27
- const columns = pageConfig.table?.columns ?? pageConfig?.columns ?? []
28
-
29
- const tableDicts = columns?.filter(item => item.type === 'enum')?.map(item => `${item.dataIndex}Options`) ?? []
30
- const formDicts = pageConfig.formItems?.filter(item => item.type === 'select')?.map(item => `${item.name}Options`) ?? []
31
- const dictBlocks = Array.from(new Set([...formDicts, ...tableDicts]))
32
-
33
- const formItems = pageConfig.formItems?.map(item => {
34
- if (item.type === 'text') {
35
- delete item.type
36
- }
37
- return {
38
- ...item,
39
- ...(item.type === 'select' ? { options: `_CODE_${item.name}Options_CODE_` } : {})
40
- }
41
- })
42
-
43
- const processedColumns = columns?.map(col => {
44
- if (col.type === 'text') {
45
- delete col.type
46
- }
47
- if (['image'].includes(col.type)) {
48
- return { ...col, renderAction: true }
49
- }
50
- if (col.type && codePresets[col.type]) {
51
- const renderCode = typeof codePresets[col.type] === 'function' ? codePresets[col.type](col.dataIndex) : codePresets[col.type]
52
- return { ...col, render: `_CODE_${renderCode}_CODE_` }
53
- }
54
- return col
55
- })
56
-
57
- return { formItems, dictBlocks, processedColumns }
58
- }
59
-
60
- const generateSmartImports = ({ module, hasTabs, bodyCode, hasFormItems }) => {
61
-
62
- const hooksLib = ['useTableQuery']
63
- const utilsLib = ['timeRender', 'moneyRender']
64
- const reactLib = ['useState', 'useEffect', 'useRef', 'useMemo']
65
- const componentsLib = ['MyTable', 'MyImage', 'MyModalForm', 'MySearchForm']
66
- const antdLib = ['Tag', 'Card', 'Badge', 'Space', 'Modal', 'Alert', 'Image', 'Table', 'Input', 'Select', 'Button']
67
-
68
- const usedAntd = antdLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
69
- const usedUtils = utilsLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
70
- const usedHooks = hooksLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
71
- const usedReact = reactLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
72
- const usedComps = componentsLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
73
-
74
- const imports = [
75
- usedReact.length && `import { ${usedReact.join(', ')} } from 'react'`,
76
- usedAntd.length && `import { ${hasFormItems && module === 'index' ? 'Form, ' : ''}${usedAntd.join(', ')} } from 'antd'`,
77
- ...usedHooks.map(hook => `import { ${hook} } from '../../hooks/${hook}'`),
78
- ...usedComps.map(comp => `import { ${comp} } from '../../components/${comp}'`),
79
- ...(module === 'index' ? [
80
- `import { request } from '../../utils/request'`,
81
- `import { formatQuery } from '../../utils/utils'`,
82
- `import { ${hasTabs ? 'tabs, ' : ''}${hasFormItems ? 'formItems, ' : ''}modalItems, tableColumns} from './resource'`
83
- ] : [
84
- usedUtils.length && `import { ${usedUtils.join(', ')} } from '../../utils/utils'`
85
- ]),
86
- ].sort((a, b) => a.length - b.length)
87
-
88
- return imports.filter(Boolean).join('\n')
89
- }
90
-
91
18
  const contextStringify = ({ context, indent = 4, maxLength = 200 }) => stringify.default(context, { indent, maxLength })
92
19
 
93
20
  module.exports = {
21
+ wrapCode,
94
22
  cleanCode,
95
23
  contextStringify,
96
- generateSmartImports,
97
- formatFormItemAndColumns,
98
24
  }
package/src/utils/ux.js CHANGED
@@ -38,6 +38,13 @@ const yorha = () => {
38
38
 
39
39
  }
40
40
 
41
+ const matchDialog = (locale, dialogs) => {
42
+ if (dialogs[locale]) return dialogs[locale]
43
+ const lang = locale.split('-')[0] // 取 ZH-HANS-CN → ZH
44
+ const matched = Object.keys(dialogs).find(key => key.startsWith(lang + '-'))
45
+ return matched ? dialogs[matched] : null
46
+ }
47
+
41
48
  const bootSequence = async (version, local) => {
42
49
 
43
50
  const lines = [
@@ -58,18 +65,20 @@ const bootSequence = async (version, local) => {
58
65
  }
59
66
  }
60
67
 
61
- const matrixEffect = async (duration = 1500, dialog) => {
68
+ const matrixEffect = async (duration = 1500, dialog, result) => {
62
69
 
63
70
  let currentTotal = 0
64
71
  const MIRROR_URL = 'https://cdn.jsdelivr.net/gh/yorha2b-lab/auto-crud-copilot@github-repo-stats/bunker-stats.json'
65
72
 
66
73
  try {
67
- const controller = new AbortController()
68
- const timeoutId = setTimeout(() => controller.abort(), 800)
69
- const response = await fetch(MIRROR_URL, { signal: controller.signal })
70
- const stats = await response.json()
71
- currentTotal = stats.total_clones || 0
72
- clearTimeout(timeoutId)
74
+ if (result.utils.foundation.getConfig().fetchClone) {
75
+ const controller = new AbortController()
76
+ const timeoutId = setTimeout(() => controller.abort(), 800)
77
+ const response = await fetch(MIRROR_URL, { signal: controller.signal })
78
+ const stats = await response.json()
79
+ currentTotal = stats.total_clones || 0
80
+ clearTimeout(timeoutId)
81
+ }
73
82
  } catch (e) {
74
83
  currentTotal = 0
75
84
  }
@@ -130,6 +139,7 @@ const matrixEffect = async (duration = 1500, dialog) => {
130
139
 
131
140
  module.exports = {
132
141
  yorha,
142
+ matchDialog,
133
143
  bootSequence,
134
144
  matrixEffect
135
145
  }