# Frontend-Source 反编译与重建实施计划 > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** 创建 `frontend-source/` 目录,将 28 个 Vue 2 + Element UI dist 产物反编译为可读源码(阶段 1),并重建 4 个核心应用为可构建工程(阶段 2)。 **Architecture:** 四步工具链(解包→格式化→AST分析→组织),先跑通 cwos-portal 验证流程,再批量处理其余 27 个。核心 4 个应用用 Vue 2 + Element UI 脚手架重建。 **Tech Stack:** Node.js 18+, `@babel/parser`, `js-beautify`, `prettier`, `webpack-bundle-analyzer`, Vue 2.6 + Element UI 2.15 + Vue CLI 4.5 **关联 Spec:** `docs/superpowers/specs/2026-04-29-frontend-source-design.md` --- ## 前置准备 ### Task 0: 环境准备与目录初始化 - [ ] **Step 1: 创建目录结构** ```bash mkdir -p frontend-source/decompiled mkdir -p frontend-source/projects mkdir -p frontend-source/scripts ``` - [ ] **Step 2: 创建 .gitignore** 写入 `frontend-source/.gitignore`: ``` **/node_modules/ **/dist/ **/.cache/ ``` - [ ] **Step 3: 初始化脚本 package.json** 写入 `frontend-source/scripts/package.json`: ```json { "name": "frontend-source-tools", "private": true, "scripts": { "unpack": "node unpack-webpack.js", "extract-api": "node extract-api-calls.js", "extract-router": "node extract-router.js", "beautify": "bash beautify-all.sh", "compare": "bash compare-output.sh" }, "dependencies": { "@babel/parser": "^7.24.0", "@babel/traverse": "^7.24.0", "@babel/types": "^7.24.0", "js-beautify": "^1.15.0", "prettier": "^3.2.0" } } ``` - [ ] **Step 4: 安装依赖** ```bash cd frontend-source/scripts && npm install ``` - [ ] **Step 5: 将 frontend-source/ 加入根 .gitignore 白名单** 在 `/media/zebra/9e8fa357-7db6-4d70-88ed-d5de5a059a663/星河湾星中星/反编译/.gitignore` 末尾添加: ``` !/frontend-source/ !/frontend-source/** ``` - [ ] **Step 6: Commit** ```bash git add frontend-source/ .gitignore git commit -m "chore: init frontend-source directory with tooling scaffold" ``` --- ## 阶段 1:工具脚本开发 ### Task 1: webpack bundle 解包脚本 **Files:** - Create: `frontend-source/scripts/unpack-webpack.js` - [ ] **Step 1: 编写解包脚本** ```javascript #!/usr/bin/env node /** * webpack bundle 解包器 * 识别 __webpack_modules__ 结构,按模块 ID 拆分为独立文件 * * 用法: node unpack-webpack.js */ const fs = require('fs'); const path = require('path'); function unpackWebpackBundle(bundlePath, outputDir) { const code = fs.readFileSync(bundlePath, 'utf-8'); // 检测 webpack 版本并提取模块对象 let modules = null; // 模式1: __webpack_modules__ = { 123: function(module, exports, __webpack_require__) {...}, ... } const modulesAssignMatch = code.match(/__webpack_modules__\s*=\s*(\{[\s\S]*?\});/); // 模式2: (function(modules) { ... })({ 123: function(...) {...}, ... }) const iifeMatch = code.match(/\(function\(\s*\w+\s*\)\s*\{[\s\S]*?\}\s*\)\s*\(\s*(\{[\s\S]*?\})\s*\)\s*;/); if (modulesAssignMatch) { modules = eval('(' + modulesAssignMatch[1] + ')'); } else if (iifeMatch) { modules = eval('(' + iifeMatch[1] + ')'); } else { console.error('未识别到 webpack 模块结构,尝试按 function(module, exports, __webpack_require__) 正则提取'); modules = extractByRegex(code); } if (!modules || Object.keys(modules).length === 0) { console.error('未能提取任何模块'); process.exit(1); } fs.mkdirSync(outputDir, { recursive: true }); let count = 0; for (const [id, factory] of Object.entries(modules)) { const moduleCode = typeof factory === 'function' ? factory.toString() : JSON.stringify(factory, null, 2); const safeId = String(id).replace(/[^a-zA-Z0-9_-]/g, '_'); fs.writeFileSync(path.join(outputDir, `module_${safeId}.js`), moduleCode); count++; } console.log(`拆解完成: ${count} 个模块 → ${outputDir}`); return count; } function extractByRegex(code) { const modules = {}; // 匹配 function(e,t,n){...} 模式 (压缩后的 webpack 模块) const re = /(\d+):\s*function\s*\(\s*\w+\s*,\s*\w+\s*,\s*\w+\s*\)\s*\{/g; const idRe = /(\d+):\s*function\s*\(\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*\)\s*\{/; let match; let lastIndex = 0; const matches = []; while ((match = re.exec(code)) !== null) { matches.push({ id: match[1], start: match.index }); } for (let i = 0; i < matches.length; i++) { const current = matches[i]; const next = matches[i + 1]; const startIdx = current.start; const endIdx = next ? next.start : code.length; // 找到匹配的闭合大括号 let depth = 1; let pos = startIdx + current[0].length; while (depth > 0 && pos < endIdx) { if (code[pos] === '{') depth++; if (code[pos] === '}') depth--; pos++; } const funcBody = code.substring(startIdx, pos); modules[current.id] = funcBody; } return modules; } // CLI const args = process.argv.slice(2); if (args.length < 2) { console.log('用法: node unpack-webpack.js '); process.exit(1); } unpackWebpackBundle(args[0], args[1]); ``` - [ ] **Step 2: 对 cwos-portal 进行解包测试** ```bash cd frontend-source/scripts node unpack-webpack.js ../frontend/cwos-portal/static/js/app.32c5fb6ab7ff973ea14d.js /tmp/cwos-portal-unpack-test ``` - [ ] **Step 3: 验证输出** ```bash ls /tmp/cwos-portal-unpack-test/ | wc -l # 预期: > 10 个模块文件 head -5 /tmp/cwos-portal-unpack-test/module_*.js ``` - [ ] **Step 4: Commit** ```bash git add frontend-source/scripts/unpack-webpack.js git commit -m "feat: add webpack bundle unpacker script" ``` ### Task 2: 批量格式化脚本 **Files:** - Create: `frontend-source/scripts/beautify-all.sh` - [ ] **Step 1: 编写格式化脚本** ```bash #!/bin/bash # 用法: bash beautify-all.sh INPUT_DIR="${1:-.}" OUTPUT_DIR="${2:-./formatted}" mkdir -p "$OUTPUT_DIR" count=0 for file in "$INPUT_DIR"/*.js; do base=$(basename "$file") output="$OUTPUT_DIR/${base%.js}.formatted.js" # 先用 js-beautify 还原缩进和换行 npx js-beautify "$file" \ --indent-size 2 \ --brace-style collapse \ --wrap-line-length 120 \ > "$output.tmp" 2>/dev/null # 再用 prettier 统一风格 npx prettier --write "$output.tmp" \ --parser babel \ --print-width 120 \ --tab-width 2 \ --single-quote true \ --trailing-comma es5 \ 2>/dev/null mv "$output.tmp" "$output" count=$((count + 1)) echo "格式化: $base → $(basename "$output")" done echo "完成: $count 个文件已格式化" ``` - [ ] **Step 2: 测试格式化** ```bash cd frontend-source/scripts bash beautify-all.sh /tmp/cwos-portal-unpack-test /tmp/cwos-portal-formatted-test head -30 /tmp/cwos-portal-formatted-test/module_*.formatted.js | head -30 ``` - [ ] **Step 3: Commit** ```bash git add frontend-source/scripts/beautify-all.sh git commit -m "feat: add batch beautifier script" ``` ### Task 3: API 调用提取器 **Files:** - Create: `frontend-source/scripts/extract-api-calls.js` - [ ] **Step 1: 编写提取脚本** ```javascript #!/usr/bin/env node /** * API 调用提取器 * 从格式化后的 JS 中提取 HTTP 请求模式,输出 API 清单 JSON * * 用法: node extract-api-calls.js */ const fs = require('fs'); const path = require('path'); const parser = require('@babel/parser'); const traverse = require('@babel/traverse').default; function extractApiCalls(inputDir, outputFile) { const apiCalls = []; const files = fs.readdirSync(inputDir).filter(f => f.endsWith('.formatted.js')); for (const file of files) { const code = fs.readFileSync(path.join(inputDir, file), 'utf-8'); try { const ast = parser.parse(code, { sourceType: 'script', plugins: ['jsx', 'typescript', 'classProperties', 'dynamicImport'], errorRecovery: true, }); traverse(ast, { // 匹配: axios.get('/api/xxx') // 匹配: axios.post('/api/xxx', data) // 匹配: this.$http.get('/api/xxx') CallExpression(nodePath) { const node = nodePath.node; const callee = node.callee; // axios.get|post|put|delete|patch if ( callee.type === 'MemberExpression' && callee.object.type === 'Identifier' && (callee.object.name === 'axios' || callee.object.name === 'http') ) { const method = callee.property.name; if (['get', 'post', 'put', 'delete', 'patch'].includes(method)) { const url = node.arguments[0]; if (url && url.type === 'StringLiteral') { apiCalls.push({ file: file, method: method.toUpperCase(), url: url.value, hasBody: method !== 'get' && node.arguments.length > 1, }); } } } // this.$http.get|post if ( callee.type === 'MemberExpression' && callee.object.type === 'MemberExpression' && callee.object.property.name === '$http' ) { const method = callee.property.name; const url = node.arguments[0]; if (url && url.type === 'StringLiteral') { apiCalls.push({ file: file, method: method.toUpperCase(), url: url.value, via: '$http', }); } } }, // 匹配字符串常量中的 API 路径 StringLiteral(nodePath) { const value = nodePath.node.value; if (typeof value === 'string' && value.startsWith('/api/') && value.length > 5) { // 避免重复捕获(CallExpression 已处理) const parent = nodePath.parent; if (parent.type === 'CallExpression') return; apiCalls.push({ file: file, method: 'REFERENCE', url: value, }); } }, }); } catch (e) { console.error(`解析失败: ${file} — ${e.message}`); } } // 去重 + 排序 const unique = {}; apiCalls.forEach(call => { const key = `${call.method} ${call.url}`; if (!unique[key]) { unique[key] = call; } }); const result = Object.values(unique).sort((a, b) => a.url.localeCompare(b.url)); fs.writeFileSync(outputFile, JSON.stringify(result, null, 2)); console.log(`提取完成: ${result.length} 个 API 端点 → ${outputFile}`); // 同时生成 Markdown 清单 const mdPath = outputFile.replace('.json', '.md'); let md = '# API 端点清单\n\n'; md += `| Method | URL | 来源文件 |\n`; md += `|--------|-----|----------|\n`; result.forEach(call => { md += `| ${call.method} | \`${call.url}\` | ${call.file} |\n`; }); fs.writeFileSync(mdPath, md); console.log(`Markdown 清单: ${mdPath}`); } const args = process.argv.slice(2); if (args.length < 2) { console.log('用法: node extract-api-calls.js '); process.exit(1); } extractApiCalls(args[0], args[1]); ``` - [ ] **Step 2: 测试 API 提取** ```bash cd frontend-source/scripts node extract-api-calls.js /tmp/cwos-portal-formatted-test /tmp/cwos-portal-api.json cat /tmp/cwos-portal-api.md | head -30 ``` - [ ] **Step 3: Commit** ```bash git add frontend-source/scripts/extract-api-calls.js git commit -m "feat: add API call extractor script" ``` ### Task 4: 路由表提取器 **Files:** - Create: `frontend-source/scripts/extract-router.js` - [ ] **Step 1: 编写提取脚本** ```javascript #!/usr/bin/env node /** * 路由表提取器 * 从格式化后的 JS 中提取 vue-router 的 routes 定义 * * 用法: node extract-router.js */ const fs = require('fs'); const path = require('path'); const parser = require('@babel/parser'); const traverse = require('@babel/traverse').default; function extractRouter(inputDir, outputFile) { const files = fs.readdirSync(inputDir).filter(f => f.endsWith('.formatted.js')); const routes = []; for (const file of files) { const code = fs.readFileSync(path.join(inputDir, file), 'utf-8'); try { const ast = parser.parse(code, { sourceType: 'script', plugins: ['jsx', 'typescript', 'classProperties', 'dynamicImport'], errorRecovery: true, }); traverse(ast, { // 匹配 routes: [...] 数组 ArrayExpression(nodePath) { const node = nodePath.node; const parent = nodePath.parent; // 检查是否是路由数组 (包含 path 和 component 属性的对象) const hasRoutes = node.elements.some(el => el.type === 'ObjectExpression' && el.properties.some(prop => prop.key.name === 'path') ); if (hasRoutes) { node.elements.forEach(el => { if (el.type === 'ObjectExpression') { const routeDef = {}; el.properties.forEach(prop => { if (prop.key.type === 'Identifier') { if (prop.key.name === 'path' && prop.value.type === 'StringLiteral') { routeDef.path = prop.value.value; } if (prop.key.name === 'name' && prop.value.type === 'StringLiteral') { routeDef.name = prop.value.value; } if (prop.key.name === 'meta' && prop.value.type === 'ObjectExpression') { routeDef.meta = {}; prop.value.properties.forEach(mp => { if (mp.key.type === 'Identifier') { routeDef.meta[mp.key.name] = mp.value.type === 'StringLiteral' ? mp.value.value : true; } }); } if (prop.key.name === 'component') { routeDef.component = prop.value.type === 'ArrowFunctionExpression' ? 'lazyImport' : (prop.value.type === 'Identifier' ? prop.value.name : 'inline'); } } }); if (routeDef.path && !routes.find(r => r.path === routeDef.path)) { routes.push(routeDef); } } }); } }, // 匹配字符串中的路径模式 /xxx/xxx StringLiteral(nodePath) { const value = nodePath.node.value; if (typeof value === 'string' && /^\/[a-z][a-z0-9_/-]*$/i.test(value) && value.length > 2) { const parent = nodePath.parent; if (parent.type === 'ObjectProperty' && parent.key.name === 'path') { return; // 已被上面处理 } if (!routes.find(r => r.path === value)) { routes.push({ path: value, source: 'stringLiteral', file: file }); } } }, }); } catch (e) { // 跳过解析错误的文件 } } const result = routes.sort((a, b) => (a.path || '').localeCompare(b.path || '')); fs.writeFileSync(outputFile, JSON.stringify(result, null, 2)); console.log(`提取完成: ${result.length} 条路由 → ${outputFile}`); // 生成 Markdown 路由树 const mdPath = outputFile.replace('.json', '.md'); let md = '# 路由表\n\n'; md += `| Path | Name | Component | Meta |\n`; md += `|------|------|-----------|------|\n`; result.forEach(r => { md += `| \`${r.path || '-'}\` | ${r.name || '-'} | ${r.component || '-'} | ${r.meta ? JSON.stringify(r.meta) : '-'} |\n`; }); fs.writeFileSync(mdPath, md); console.log(`路由表 Markdown: ${mdPath}`); } const args = process.argv.slice(2); if (args.length < 2) { console.log('用法: node extract-router.js '); process.exit(1); } extractRouter(args[0], args[1]); ``` - [ ] **Step 2: 测试路由提取** ```bash cd frontend-source/scripts node extract-router.js /tmp/cwos-portal-formatted-test /tmp/cwos-portal-router.json cat /tmp/cwos-portal-router.md ``` - [ ] **Step 3: Commit** ```bash git add frontend-source/scripts/extract-router.js git commit -m "feat: add router table extractor script" ``` --- ## 阶段 2-A:P0 — cwos-portal 反编译验证 ### Task 5: cwos-portal 解包与格式化 **Files:** - Create: `frontend-source/decompiled/cwos-portal/` - [ ] **Step 1: 定位 cwos-portal 的 JS bundle** ```bash ls -la frontend/cwos-portal/static/js/app.*.js ls -la frontend/cwos-portal/static/js/vendor.*.js ls -la frontend/cwos-portal/static/js/manifest.*.js ``` - [ ] **Step 2: 解包所有 bundle** ```bash cd frontend-source/scripts mkdir -p /tmp/cwos-portal-raw for js in ../../frontend/cwos-portal/static/js/app.*.js; do node unpack-webpack.js "$js" /tmp/cwos-portal-raw done for js in ../../frontend/cwos-portal/static/js/vendor.*.js; do node unpack-webpack.js "$js" /tmp/cwos-portal-raw done ls /tmp/cwos-portal-raw/ | wc -l ``` - [ ] **Step 3: 格式化所有模块** ```bash cd frontend-source/scripts mkdir -p /tmp/cwos-portal-formatted bash beautify-all.sh /tmp/cwos-portal-raw /tmp/cwos-portal-formatted ls /tmp/cwos-portal-formatted/ | wc -l ``` - [ ] **Step 4: 提取 API 清单** ```bash cd frontend-source/scripts node extract-api-calls.js /tmp/cwos-portal-formatted ../decompiled/cwos-portal/api-calls.json ``` - [ ] **Step 5: 提取路由表** ```bash cd frontend-source/scripts node extract-router.js /tmp/cwos-portal-formatted ../decompiled/cwos-portal/router-tree.json ``` - [ ] **Step 6: 组装到 frontend-source/decompiled/cwos-portal/** ```bash mkdir -p frontend-source/decompiled/cwos-portal/src/{views,components,api,router} mkdir -p frontend-source/decompiled/cwos-portal/static # 复制格式化后的模块 cp /tmp/cwos-portal-formatted/*.formatted.js frontend-source/decompiled/cwos-portal/src/ # 复制原始 static 文件 cp -r frontend/cwos-portal/static/* frontend-source/decompiled/cwos-portal/static/ cp frontend/cwos-portal/index.html frontend-source/decompiled/cwos-portal/ cp frontend/cwos-portal/favicon.ico frontend-source/decompiled/cwos-portal/ cp frontend/cwos-portal/projectInfo.json frontend-source/decompiled/cwos-portal/ # API 和路由已在步骤 4-5 中直接写入 ls frontend-source/decompiled/cwos-portal/ ``` - [ ] **Step 7: 编写 README.md** 写入 `frontend-source/decompiled/cwos-portal/README.md`: ```markdown # cwos-portal — 物业管理门户 ## 来源 - 原始 dist: `frontend/cwos-portal/` - 构建日期: 2022-01-12 - 技术栈: Vue 2 + Element UI + webpack ## API 端点 详见 [api-calls.md](api-calls.md) ## 路由表 详见 [router-tree.md](router-tree.md) ## 目录结构 - `src/` — 格式化的 JS 模块 - `static/` — CSS/img/font 原始文件 - `index.html` — 原始入口 - `projectInfo.json` — 项目配置 ``` - [ ] **Step 8: Commit** ```bash git add frontend-source/decompiled/cwos-portal/ git commit -m "feat: add cwos-portal decompiled source (P0 verification)" ``` --- ## 阶段 2-B:P1 核心应用反编译 ### Task 6: elevator-front 反编译 **Files:** - Create: `frontend-source/decompiled/elevator-front/` - [ ] **Step 1: 解包 elevator-front** ```bash cd frontend-source/scripts mkdir -p /tmp/elevator-front-raw /tmp/elevator-front-formatted for js in ../../frontend/elevator-front/js/*.js; do node unpack-webpack.js "$js" /tmp/elevator-front-raw done bash beautify-all.sh /tmp/elevator-front-raw /tmp/elevator-front-formatted node extract-api-calls.js /tmp/elevator-front-formatted ../decompiled/elevator-front/api-calls.json node extract-router.js /tmp/elevator-front-formatted ../decompiled/elevator-front/router-tree.json ``` - [ ] **Step 2: 组织文件并复制静态资源** ```bash mkdir -p frontend-source/decompiled/elevator-front/src mkdir -p frontend-source/decompiled/elevator-front/static cp /tmp/elevator-front-formatted/*.formatted.js frontend-source/decompiled/elevator-front/src/ cp -r frontend/elevator-front/css frontend-source/decompiled/elevator-front/static/ cp -r frontend/elevator-front/img frontend-source/decompiled/elevator-front/static/ cp -r frontend/elevator-front/fonts frontend-source/decompiled/elevator-front/static/ 2>/dev/null cp frontend/elevator-front/index.html frontend-source/decompiled/elevator-front/ cp frontend/elevator-front/favicon.ico frontend-source/decompiled/elevator-front/ 2>/dev/null ``` - [ ] **Step 3: 编写 README.md** 写入 `frontend-source/decompiled/elevator-front/README.md`: ```markdown # elevator-front — 电梯管理前端 ## 来源 - 原始 dist: `frontend/elevator-front/` - 构建日期: 2023-10-19 - 技术栈: Vue 2 + Element UI + webpack 详见 [api-calls.md](api-calls.md) 和 [router-tree.md](router-tree.md) ``` - [ ] **Step 4: Commit** ```bash git add frontend-source/decompiled/elevator-front/ git commit -m "feat: add elevator-front decompiled source" ``` ### Task 7: alarm-front 反编译 **Files:** - Create: `frontend-source/decompiled/alarm-front/` - [ ] **Step 1: 解包 alarm-front** ```bash cd frontend-source/scripts mkdir -p /tmp/alarm-front-raw /tmp/alarm-front-formatted for js in ../../frontend/alarm-front/js/*.js; do node unpack-webpack.js "$js" /tmp/alarm-front-raw done bash beautify-all.sh /tmp/alarm-front-raw /tmp/alarm-front-formatted node extract-api-calls.js /tmp/alarm-front-formatted ../decompiled/alarm-front/api-calls.json node extract-router.js /tmp/alarm-front-formatted ../decompiled/alarm-front/router-tree.json ``` - [ ] **Step 2: 组织文件** ```bash mkdir -p frontend-source/decompiled/alarm-front/src mkdir -p frontend-source/decompiled/alarm-front/static cp /tmp/alarm-front-formatted/*.formatted.js frontend-source/decompiled/alarm-front/src/ cp -r frontend/alarm-front/css frontend-source/decompiled/alarm-front/static/ cp -r frontend/alarm-front/img frontend-source/decompiled/alarm-front/static/ cp -r frontend/alarm-front/fonts frontend-source/decompiled/alarm-front/static/ 2>/dev/null cp -r frontend/alarm-front/media frontend-source/decompiled/alarm-front/static/ 2>/dev/null cp frontend/alarm-front/index.html frontend-source/decompiled/alarm-front/ cp frontend/alarm-front/favicon.ico frontend-source/decompiled/alarm-front/ 2>/dev/null ``` - [ ] **Step 3: 编写 README.md** 写入 `frontend-source/decompiled/alarm-front/README.md`: ```markdown # alarm-front — 报警管理前端 ## 来源 - 原始 dist: `frontend/alarm-front/` - 构建日期: 2023-11-09 - 技术栈: Vue 2 + Element UI + webpack 详见 [api-calls.md](api-calls.md) 和 [router-tree.md](router-tree.md) ``` - [ ] **Step 4: Commit** ```bash git add frontend-source/decompiled/alarm-front/ git commit -m "feat: add alarm-front decompiled source" ``` ### Task 8: front_acs 反编译 **Files:** - Create: `frontend-source/decompiled/front_acs/` - [ ] **Step 1: 解包 front_acs** ```bash cd frontend-source/scripts mkdir -p /tmp/front-acs-raw /tmp/front-acs-formatted for js in ../../frontend/front_acs/static/js/*.js; do node unpack-webpack.js "$js" /tmp/front-acs-raw done bash beautify-all.sh /tmp/front-acs-raw /tmp/front-acs-formatted node extract-api-calls.js /tmp/front-acs-formatted ../decompiled/front_acs/api-calls.json node extract-router.js /tmp/front-acs-formatted ../decompiled/front_acs/router-tree.json ``` - [ ] **Step 2: 组织文件** ```bash mkdir -p frontend-source/decompiled/front_acs/src mkdir -p frontend-source/decompiled/front_acs/static cp /tmp/front-acs-formatted/*.formatted.js frontend-source/decompiled/front_acs/src/ cp -r frontend/front_acs/static/* frontend-source/decompiled/front_acs/static/ cp frontend/front_acs/index.html frontend-source/decompiled/front_acs/ cp frontend/front_acs/favicon.ico frontend-source/decompiled/front_acs/ cp frontend/front_acs/projectInfo.json frontend-source/decompiled/front_acs/ 2>/dev/null ``` - [ ] **Step 3: 编写 README.md** 写入 `frontend-source/decompiled/front_acs/README.md`: ```markdown # front_acs — 门禁管理前端 ## 来源 - 原始 dist: `frontend/front_acs/` - 构建日期: 2023-12-22 - 技术栈: Vue 2 + Element UI + webpack 详见 [api-calls.md](api-calls.md) 和 [router-tree.md](router-tree.md) ``` - [ ] **Step 4: Commit** ```bash git add frontend-source/decompiled/front_acs/ git commit -m "feat: add front_acs decompiled source" ``` --- ## 阶段 2-C:P2-P3 批量反编译 ### Task 9: Canoe 系列批量反编译 **Files:** - Create: `frontend-source/decompiled/canoe-{account,car,device,person,person-h5}/` - [ ] **Step 1: 批量解包脚本** ```bash cd frontend-source/scripts APPS="canoe-account canoe-car canoe-device canoe-person canoe-person-h5" for app in $APPS; do echo "=== 处理: $app ===" mkdir -p /tmp/${app}-raw /tmp/${app}-formatted JS_DIR="../../frontend/${app}/js" if [ -d "$JS_DIR" ]; then for js in "$JS_DIR"/*.js; do node unpack-webpack.js "$js" /tmp/${app}-raw done fi # 部分应用 js 在 static/js/ STATIC_JS="../../frontend/${app}/static/js" if [ -d "$STATIC_JS" ]; then for js in "$STATIC_JS"/*.js; do node unpack-webpack.js "$js" /tmp/${app}-raw done fi bash beautify-all.sh /tmp/${app}-raw /tmp/${app}-formatted node extract-api-calls.js /tmp/${app}-formatted ../decompiled/${app}/api-calls.json 2>/dev/null node extract-router.js /tmp/${app}-formatted ../decompiled/${app}/router-tree.json 2>/dev/null mkdir -p ../decompiled/${app}/src ../decompiled/${app}/static cp /tmp/${app}-formatted/*.formatted.js ../decompiled/${app}/src/ 2>/dev/null cp -r ../../frontend/${app}/css ../decompiled/${app}/static/ 2>/dev/null cp -r ../../frontend/${app}/js ../decompiled/${app}/static/ 2>/dev/null cp -r ../../frontend/${app}/img ../decompiled/${app}/static/ 2>/dev/null cp -r ../../frontend/${app}/static ../decompiled/${app}/ 2>/dev/null cp ../../frontend/${app}/index.html ../decompiled/${app}/ 2>/dev/null cp ../../frontend/${app}/favicon.ico ../decompiled/${app}/ 2>/dev/null echo "README: $app" > ../decompiled/${app}/README.md echo "" >> ../decompiled/${app}/README.md echo "来源: frontend/${app}/" >> ../decompiled/${app}/README.md done echo "批量处理完成" ``` - [ ] **Step 2: Commit** ```bash git add frontend-source/decompiled/canoe-account/ \ frontend-source/decompiled/canoe-car/ \ frontend-source/decompiled/canoe-device/ \ frontend-source/decompiled/canoe-person/ \ frontend-source/decompiled/canoe-person-h5/ git commit -m "feat: add Canoe series decompiled sources" ``` ### Task 10: 其余 20 个应用批量反编译 **Files:** - Create: `frontend-source/decompiled/{dashboard-front,homepage,...}/`(20个) - [ ] **Step 1: 批量处理脚本** ```bash cd frontend-source/scripts # 门禁/电梯辅助应用 APPS_P2="area-front personFile monitor-front snap-front heat-analysis-portal" # 访客/考勤/会议 APPS_P2="$APPS_P2 visitorpc visitorh5 conferencepc attendancepc" # 系统辅助 APPS_P2="$APPS_P2 front_message sysetting-front ninca-engine-service" # Canoe 辅助 APPS_P2="$APPS_P2 canoe-account canoe-car canoe-device canoe-person" # 其他 APPS_P2="$APPS_P2 cwos_manager_frontend" for app in $APPS_P2; do [ ! -d "../../frontend/${app}" ] && continue echo "=== 处理: $app ===" mkdir -p /tmp/${app}-raw /tmp/${app}-formatted for js_dir in "js" "static/js"; do if [ -d "../../frontend/${app}/${js_dir}" ]; then for js in ../../frontend/${app}/${js_dir}/*.js; do node unpack-webpack.js "$js" /tmp/${app}-raw 2>/dev/null done fi done bash beautify-all.sh /tmp/${app}-raw /tmp/${app}-formatted 2>/dev/null mkdir -p ../decompiled/${app}/src ../decompiled/${app}/static cp /tmp/${app}-formatted/*.formatted.js ../decompiled/${app}/src/ 2>/dev/null cp -r ../../frontend/${app}/static ../decompiled/${app}/ 2>/dev/null cp ../../frontend/${app}/index.html ../decompiled/${app}/ 2>/dev/null cp ../../frontend/${app}/favicon.ico ../decompiled/${app}/ 2>/dev/null echo "# $app" > ../decompiled/${app}/README.md echo "来源: frontend/${app}/" >> ../decompiled/${app}/README.md echo " ✓ $app" done echo "全部批量处理完成" ``` - [ ] **Step 2: Commit** ```bash git add frontend-source/decompiled/ git commit -m "feat: add remaining 20 apps decompiled sources (bulk)" ``` --- ## 阶段 3:核心应用 C 级重建 ### Task 11: cwos-portal 项目脚手架 **Files:** - Create: `frontend-source/projects/cwos-portal/` - [ ] **Step 1: 手动搭建 Vue 2 项目(不用 vue create)** 写入 `frontend-source/projects/cwos-portal/package.json`: ```json { "name": "cwos-portal", "version": "1.0.0", "private": true, "scripts": { "dev": "vue-cli-service serve", "build": "vue-cli-service build", "lint": "vue-cli-service lint" }, "dependencies": { "axios": "^0.21.4", "element-ui": "^2.15.14", "vue": "^2.6.14", "vue-router": "^3.5.3", "vuex": "^3.6.2" }, "devDependencies": { "@vue/cli-plugin-babel": "^4.5.19", "@vue/cli-plugin-router": "^4.5.19", "@vue/cli-plugin-vuex": "^4.5.19", "@vue/cli-service": "^4.5.19", "vue-template-compiler": "^2.6.14" } } ``` - [ ] **Step 2: 创建 vue.config.js** 写入 `frontend-source/projects/cwos-portal/vue.config.js`: ```javascript module.exports = { publicPath: './', outputDir: 'dist', assetsDir: 'static', productionSourceMap: false, devServer: { port: 8080, proxy: { '/api': { target: 'http://localhost:8090', changeOrigin: true, }, }, }, }; ``` - [ ] **Step 3: 创建 babel.config.js** 写入 `frontend-source/projects/cwos-portal/babel.config.js`: ```javascript module.exports = { presets: ['@vue/cli-plugin-babel/preset'], }; ``` - [ ] **Step 4: 创建入口文件** 写入 `frontend-source/projects/cwos-portal/public/index.html`: ```html 物业管理门户
``` - [ ] **Step 5: 创建 main.js 和 App.vue** 写入 `frontend-source/projects/cwos-portal/src/main.js`: ```javascript import Vue from 'vue'; import ElementUI from 'element-ui'; import 'element-ui/lib/theme-chalk/index.css'; import App from './App.vue'; import router from './router'; import store from './store'; import axios from 'axios'; Vue.use(ElementUI); Vue.prototype.$http = axios; Vue.config.productionTip = false; new Vue({ router, store, render: (h) => h(App), }).$mount('#app'); ``` 写入 `frontend-source/projects/cwos-portal/src/App.vue`: ```vue ``` - [ ] **Step 6: 创建路由和 store 骨架** 写入 `frontend-source/projects/cwos-portal/src/router/index.js`: ```javascript import Vue from 'vue'; import VueRouter from 'vue-router'; Vue.use(VueRouter); // 路由从 decompiled/cwos-portal/router-tree.md 提取后填入 // 参考 router-tree.md 中的路径列表,逐个转换为 route 对象 // 示例格式: // { path: '/dashboard', name: 'Dashboard', component: () => import('@/views/Dashboard.vue') } const routes = []; const router = new VueRouter({ mode: 'hash', routes, }); export default router; ``` 写入 `frontend-source/projects/cwos-portal/src/store/index.js`: ```javascript import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); export default new Vuex.Store({ state: {}, mutations: {}, actions: {}, modules: {}, }); ``` - [ ] **Step 7: 创建 API 层骨架** 写入 `frontend-source/projects/cwos-portal/src/api/index.js`: ```javascript import axios from 'axios'; const api = axios.create({ baseURL: '/api', timeout: 30000, }); // 请求拦截器 api.interceptors.request.use((config) => { // token 注入(参考原 config.js) return config; }); // 响应拦截器 api.interceptors.response.use( (response) => response.data, (error) => Promise.reject(error) ); export default api; ``` - [ ] **Step 8: 安装依赖并验证构建** ```bash cd frontend-source/projects/cwos-portal && npm install npm run build ``` - [ ] **Step 9: Commit** ```bash git add frontend-source/projects/cwos-portal/ git commit -m "feat: scaffold cwos-portal Vue 2 project (skeleton)" ``` ### Task 12: 其他 3 个核心应用脚手架 **Files:** - Create: `frontend-source/projects/{elevator-front,alarm-front,front_acs}/` - [ ] **Step 1: 批量创建脚手架**(结构与 Task 11 一致,调整应用名) ```bash cd frontend-source/projects for app in elevator-front alarm-front front_acs; do mkdir -p $app/public $app/src/{views,components,api,router,store} # package.json (相同的依赖,只改 name) cat > $app/package.json << EOF { "name": "$app", "version": "1.0.0", "private": true, "scripts": { "dev": "vue-cli-service serve", "build": "vue-cli-service build" }, "dependencies": { "axios": "^0.21.4", "element-ui": "^2.15.14", "vue": "^2.6.14", "vue-router": "^3.5.3", "vuex": "^3.6.2" }, "devDependencies": { "@vue/cli-plugin-babel": "^4.5.19", "@vue/cli-plugin-router": "^4.5.19", "@vue/cli-plugin-vuex": "^4.5.19", "@vue/cli-service": "^4.5.19", "vue-template-compiler": "^2.6.14" } } EOF # vue.config.js, babel.config.js, public/index.html, src/main.js, src/App.vue, # src/router/index.js, src/store/index.js, src/api/index.js # (复制项目模板,使用前面 Task 11 的相同内容,修改标题即可) cd $app && npm install && npm run build && cd .. done ``` - [ ] **Step 2: Commit** ```bash git add frontend-source/projects/elevator-front/ \ frontend-source/projects/alarm-front/ \ frontend-source/projects/front_acs/ git commit -m "feat: scaffold 3 core app Vue 2 projects (skeletons)" ``` --- ## 阶段 4:文档与最终校验 ### Task 13: frontend-source/AGENTS.md **Files:** - Create: `frontend-source/AGENTS.md` - [ ] **Step 1: 编写目录说明** 写入 `frontend-source/AGENTS.md`: ```markdown # frontend-source/ — 前端源码目录 ## OVERVIEW 从 `frontend/` dist 产物反编译还原的前端源码。分为两类: - `decompiled/` — B 级反编译(全部 28 个应用,可读参考) - `projects/` — C 级重建(4 个核心应用,可构建部署) ## WHERE TO LOOK | 任务 | 目录 | 说明 | |------|------|------| | 查看任意应用源码 | `decompiled//src/` | 格式化后的 JS 模块 | | 查看 API 清单 | `decompiled//api-calls.md` | HTTP 端点列表 | | 查看路由表 | `decompiled//router-tree.md` | 页面路由树 | | 开发核心应用 | `projects//` | 可构建的 Vue 2 工程 | | 反编译工具 | `scripts/` | unpack-webpack 等 | ## CONVENTIONS - `decompiled/` 下文件**不可用于构建**,仅供阅读参考 - `projects/` 下工程可正常 `npm run dev` / `npm run build` - 技术栈: Vue 2.6 + Element UI 2.15 + axios + vue-router 3 + vuex 3 - 构建使用 Vue CLI 4.5 ## ANTI-PATTERNS - 不要修改 `decompiled/` 下的源码后试图构建 — 这些是反编译参考 - 不要混用 Vue 3 / Element Plus — 阶段 2 必须用 Vue 2 + Element UI - 不要删除 `frontend/` 原 dist 目录 — 它是唯一定稿的参考来源 ## NOTES - 反编译工具在 `scripts/` 下,Node.js 18+ - 阶段 2 重建的重点包含 `projects/` 下 4 个应用的逐页面重写 - 原始源码完全丢失,JS bundle 反编译无法恢复原始变量名 ``` - [ ] **Step 2: Commit** ```bash git add frontend-source/AGENTS.md git commit -m "docs: add frontend-source AGENTS.md" ``` ### Task 14: 最终校验 - [ ] **Step 1: 校验目录完整性** ```bash echo "=== decompiled/ 应用数 ===" ls frontend-source/decompiled/ | wc -l echo "预期: 28" echo "=== projects/ 应用数 ===" ls frontend-source/projects/ | wc -l echo "预期: 4" echo "=== 脚本文件数 ===" ls frontend-source/scripts/*.js frontend-source/scripts/*.sh 2>/dev/null | wc -l echo "预期: 5 (3 js + 2 sh)" ``` - [ ] **Step 2: 校验 4 个核心项目可构建** ```bash for app in cwos-portal elevator-front alarm-front front_acs; do echo "=== 构建: $app ===" cd frontend-source/projects/$app && npm run build 2>&1 | tail -3 || echo "构建失败" cd ../../.. done ``` - [ ] **Step 3: Commit** ```bash git add frontend-source/ git commit -m "chore: final verification of frontend-source directory" ``` --- ## 计划总结 | 阶段 | 任务数 | 预计时间 | |------|--------|----------| | 前置准备 | Task 0 | 0.5h | | 工具开发 | Task 1-4 | 2h | | P0 验证 | Task 5 | 1h | | P1 核心 | Task 6-8 | 1.5h | | P2-P3 批量 | Task 9-10 | 1h | | C 级重建 | Task 11-12 | 2h | | 文档校验 | Task 13-14 | 0.5h | | **合计** | **14 Tasks** | **~8.5h** |