diff --git a/0000_gb_points_temp/.env b/0000_gb_points_temp/.env
new file mode 100644
index 0000000..09344c1
--- /dev/null
+++ b/0000_gb_points_temp/.env
@@ -0,0 +1,5 @@
+# 平台本地运行端口号
+VITE_PORT = 8848
+
+# 是否隐藏首页 隐藏 true 不隐藏 false (勿删除,VITE_HIDE_HOME只需在.env文件配置)
+VITE_HIDE_HOME = false
diff --git a/0000_gb_points_temp/.env.development b/0000_gb_points_temp/.env.development
new file mode 100644
index 0000000..c057c2a
--- /dev/null
+++ b/0000_gb_points_temp/.env.development
@@ -0,0 +1,11 @@
+# 平台本地运行端口号
+VITE_PORT = 8848
+
+# 开发环境读取配置文件路径
+VITE_PUBLIC_PATH = ./
+
+# 网站前缀
+VITE_BASE_URL = "vc1cccd1s325c.dagf7.top"
+
+# 开发环境路由历史模式(Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数")
+VITE_ROUTER_HISTORY = "hash"
diff --git a/0000_gb_points_temp/.env.production b/0000_gb_points_temp/.env.production
new file mode 100644
index 0000000..dc643cf
--- /dev/null
+++ b/0000_gb_points_temp/.env.production
@@ -0,0 +1,16 @@
+# 网站前缀
+VITE_BASE_URL=/
+
+# 线上环境平台打包路径
+VITE_PUBLIC_PATH = ./
+
+# 线上环境路由历史模式(Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数")
+VITE_ROUTER_HISTORY = "hash"
+
+# 是否在打包时使用cdn替换本地库 替换 true 不替换 false
+VITE_CDN = false
+
+# 是否启用gzip压缩或brotli压缩(分两种情况,删除原始文件和不删除原始文件)
+# 压缩时不删除原始文件的配置:gzip、brotli、both(同时开启 gzip 与 brotli 压缩)、none(不开启压缩,默认)
+# 压缩时删除原始文件的配置:gzip-clear、brotli-clear、both-clear(同时开启 gzip 与 brotli 压缩)、none(不开启压缩,默认)
+VITE_COMPRESSION = "none"
diff --git a/0000_gb_points_temp/.eslintrc.cjs b/0000_gb_points_temp/.eslintrc.cjs
new file mode 100644
index 0000000..bc94687
--- /dev/null
+++ b/0000_gb_points_temp/.eslintrc.cjs
@@ -0,0 +1,25 @@
+/* eslint-env node */
+require('@rushstack/eslint-patch/modern-module-resolution')
+
+module.exports = {
+ root: true,
+ 'extends': [
+ 'plugin:vue/vue3-essential',
+ 'eslint:recommended',
+ '@vue/eslint-config-typescript',
+ '@vue/eslint-config-prettier'
+ ],
+ overrides: [
+ {
+ files: [
+ 'cypress/e2e/**/*.{cy,spec}.{js,ts,jsx,tsx}'
+ ],
+ 'extends': [
+ 'plugin:cypress/recommended'
+ ]
+ }
+ ],
+ parserOptions: {
+ ecmaVersion: 'latest'
+ }
+}
diff --git a/0000_gb_points_temp/.gitignore b/0000_gb_points_temp/.gitignore
new file mode 100644
index 0000000..38adffa
--- /dev/null
+++ b/0000_gb_points_temp/.gitignore
@@ -0,0 +1,28 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+.DS_Store
+dist
+dist-ssr
+coverage
+*.local
+
+/cypress/videos/
+/cypress/screenshots/
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/0000_gb_points_temp/.prettierrc.json b/0000_gb_points_temp/.prettierrc.json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/0000_gb_points_temp/.prettierrc.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/0000_gb_points_temp/.vscode/extensions.json b/0000_gb_points_temp/.vscode/extensions.json
new file mode 100644
index 0000000..c0a6e5a
--- /dev/null
+++ b/0000_gb_points_temp/.vscode/extensions.json
@@ -0,0 +1,3 @@
+{
+ "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
+}
diff --git a/0000_gb_points_temp/README.md b/0000_gb_points_temp/README.md
new file mode 100644
index 0000000..10ac830
--- /dev/null
+++ b/0000_gb_points_temp/README.md
@@ -0,0 +1,69 @@
+# vue3-clean-architecture
+
+This template should help get you started developing with Vue 3 in Vite.
+
+## Recommended IDE Setup
+
+[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
+
+## Type Support for `.vue` Imports in TS
+
+TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin) to make the TypeScript language service aware of `.vue` types.
+
+If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a [Take Over Mode](https://github.com/johnsoncodehk/volar/discussions/471#discussioncomment-1361669) that is more performant. You can enable it by the following steps:
+
+1. Disable the built-in TypeScript Extension
+ 1) Run `Extensions: Show Built-in Extensions` from VSCode's command palette
+ 2) Find `TypeScript and JavaScript Language Features`, right click and select `Disable (Workspace)`
+2. Reload the VSCode window by running `Developer: Reload Window` from the command palette.
+
+## Customize configuration
+
+See [Vite Configuration Reference](https://vitejs.dev/config/).
+
+## Project Setup
+
+```sh
+npm install
+```
+
+### Compile and Hot-Reload for Development
+
+```sh
+npm run dev
+```
+
+### Type-Check, Compile and Minify for Production
+
+```sh
+npm run build
+```
+
+### Run Unit Tests with [Vitest](https://vitest.dev/)
+
+```sh
+npm run test:unit
+```
+
+### Run End-to-End Tests with [Cypress](https://www.cypress.io/)
+
+```sh
+npm run test:e2e:dev
+```
+
+This runs the end-to-end tests against the Vite development server.
+It is much faster than the production build.
+
+But it's still recommended to test the production build with `test:e2e` before deploying (e.g. in CI environments):
+
+```sh
+npm run build
+npm run test:e2e
+```
+
+### Lint with [ESLint](https://eslint.org/)
+
+```sh
+npm run lint
+```
+```
\ No newline at end of file
diff --git a/0000_gb_points_temp/Theme1使用说明.md b/0000_gb_points_temp/Theme1使用说明.md
new file mode 100644
index 0000000..71aed1d
--- /dev/null
+++ b/0000_gb_points_temp/Theme1使用说明.md
@@ -0,0 +1,80 @@
+# Theme1 多语言使用说明
+
+## 已完成的修改
+
+### 1. 集成项目多语言系统
+- ✅ 在 `src/locales/en/index.ts` 中添加了 Theme1 的英文文案
+- ✅ 在 `src/locales/cn/index.ts` 中添加了 Theme1 的中文文案
+- ✅ 在 `src/locales/es/index.ts` 中添加了 Theme1 的西班牙语文案
+- ✅ Theme1 组件使用 `useI18n()` 自动获取当前语言
+
+### 2. 样式优化
+- ✅ 取消顶部背景渐变效果(改为纯色)
+- ✅ 取消按钮渐变效果(改为纯色)
+- ✅ 取消所有阴影效果
+- ✅ 保留简洁的现代设计
+
+### 3. 文案 Key 列表
+```typescript
+"Points Inquiry" // 主标题
+"Enter your phone number to check available points" // 副标题
+"Real-time" // 特性1
+"Rich Rewards" // 特性2
+"Secure" // 特性3
+"Check My Points" // 查询卡片标题
+"Please enter your phone number to query" // 查询卡片副标题
+"Phone number" // 手机号标签
+"Enter phone number" // 输入框占位符
+"Query Now" // 查询按钮
+"Your information will be securely encrypted and not used for other purposes" // 安全提示
+```
+
+## 使用方式
+
+### 添加新语言
+在 `src/locales/` 目录下创建新的语言文件,例如 `tr/index.ts`(土耳其语):
+
+```typescript
+export default {
+ // ... 其他翻译 ...
+
+ // Theme1 texts
+ "Points Inquiry": "Puan Sorgulama",
+ "Enter your phone number to check available points": "Mevcut puanlarınızı kontrol etmek için telefon numaranızı girin",
+ "Real-time": "Gerçek Zamanlı",
+ "Rich Rewards": "Zengin Ödüller",
+ "Secure": "Güvenli",
+ "Check My Points": "Puanlarımı Kontrol Et",
+ "Please enter your phone number to query": "Lütfen sorgulamak için telefon numaranızı girin",
+ "Phone number": "Telefon Numarası",
+ "Enter phone number": "Telefon numarasını girin",
+ "Query Now": "Şimdi Sorgula",
+ "Your information will be securely encrypted and not used for other purposes": "Bilgileriniz güvenli bir şekilde şifrelenecek ve başka amaçlarla kullanılmayacaktır",
+};
+```
+
+### 主题配置
+```typescript
+// 配置主题(在 goodsConfig 中)
+goodsConfig.homeTheme = 1; // 使用 Theme1
+```
+
+### 语言切换
+项目的语言切换由 vue-i18n 自动管理,组件会自动响应语言更改。
+
+## 技术细节
+
+- 使用 `vue-i18n` 的 `useI18n()` 获取 `t()` 翻译函数
+- 所有文案通过 `t("key")` 方式获取
+- 颜色配置通过 props 传递(`colors`)
+- 移除了渐变和阴影,使用纯色设计
+- CSS 变量只保留 `--primary-color` 和 `--primary-light`
+
+## 文件修改记录
+
+1. **Theme1.vue**: 集成 useI18n,移除 texts prop,取消渐变和阴影
+2. **PhoneView.vue**: 移除 texts 相关导入和传递
+3. **locales/en/index.ts**: 添加英文文案
+4. **locales/cn/index.ts**: 添加中文文案
+5. **locales/es/index.ts**: 添加西班牙语文案
+6. **删除**: theme-texts.ts(不再需要独立的多语言配置)
diff --git a/0000_gb_points_temp/cardloading.svg b/0000_gb_points_temp/cardloading.svg
new file mode 100644
index 0000000..7c8170a
--- /dev/null
+++ b/0000_gb_points_temp/cardloading.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/0000_gb_points_temp/cypress.config.ts b/0000_gb_points_temp/cypress.config.ts
new file mode 100644
index 0000000..0f66080
--- /dev/null
+++ b/0000_gb_points_temp/cypress.config.ts
@@ -0,0 +1,8 @@
+import { defineConfig } from 'cypress'
+
+export default defineConfig({
+ e2e: {
+ specPattern: 'cypress/e2e/**/*.{cy,spec}.{js,jsx,ts,tsx}',
+ baseUrl: 'http://localhost:4173'
+ }
+})
diff --git a/0000_gb_points_temp/cypress/e2e/example.cy.ts b/0000_gb_points_temp/cypress/e2e/example.cy.ts
new file mode 100644
index 0000000..7a8c909
--- /dev/null
+++ b/0000_gb_points_temp/cypress/e2e/example.cy.ts
@@ -0,0 +1,8 @@
+// https://docs.cypress.io/api/introduction/api.html
+
+describe('My First Test', () => {
+ it('visits the app root url', () => {
+ cy.visit('/')
+ cy.contains('h1', 'You did it!')
+ })
+})
diff --git a/0000_gb_points_temp/cypress/e2e/tsconfig.json b/0000_gb_points_temp/cypress/e2e/tsconfig.json
new file mode 100644
index 0000000..be213ae
--- /dev/null
+++ b/0000_gb_points_temp/cypress/e2e/tsconfig.json
@@ -0,0 +1,10 @@
+{
+ "extends": "@vue/tsconfig/tsconfig.web.json",
+ "include": ["./**/*", "../support/**/*"],
+ "compilerOptions": {
+ "isolatedModules": false,
+ "target": "es5",
+ "lib": ["es5", "dom"],
+ "types": ["cypress"]
+ }
+}
diff --git a/0000_gb_points_temp/cypress/fixtures/example.json b/0000_gb_points_temp/cypress/fixtures/example.json
new file mode 100644
index 0000000..02e4254
--- /dev/null
+++ b/0000_gb_points_temp/cypress/fixtures/example.json
@@ -0,0 +1,5 @@
+{
+ "name": "Using fixtures to represent data",
+ "email": "hello@cypress.io",
+ "body": "Fixtures are a great way to mock data for responses to routes"
+}
diff --git a/0000_gb_points_temp/cypress/support/commands.ts b/0000_gb_points_temp/cypress/support/commands.ts
new file mode 100644
index 0000000..9b7bb8e
--- /dev/null
+++ b/0000_gb_points_temp/cypress/support/commands.ts
@@ -0,0 +1,39 @@
+///
+// ***********************************************
+// This example commands.ts shows you how to
+// create various custom commands and overwrite
+// existing commands.
+//
+// For more comprehensive examples of custom
+// commands please read more here:
+// https://on.cypress.io/custom-commands
+// ***********************************************
+//
+//
+// -- This is a parent command --
+// Cypress.Commands.add('login', (email, password) => { ... })
+//
+//
+// -- This is a child command --
+// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
+//
+//
+// -- This is a dual command --
+// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
+//
+//
+// -- This will overwrite an existing command --
+// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
+//
+// declare global {
+// namespace Cypress {
+// interface Chainable {
+// login(email: string, password: string): Chainable
+// drag(subject: string, options?: Partial): Chainable
+// dismiss(subject: string, options?: Partial): Chainable
+// visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable
+// }
+// }
+// }
+
+export {}
diff --git a/0000_gb_points_temp/cypress/support/e2e.ts b/0000_gb_points_temp/cypress/support/e2e.ts
new file mode 100644
index 0000000..d68db96
--- /dev/null
+++ b/0000_gb_points_temp/cypress/support/e2e.ts
@@ -0,0 +1,20 @@
+// ***********************************************************
+// This example support/index.js is processed and
+// loaded automatically before your test files.
+//
+// This is a great place to put global configuration and
+// behavior that modifies Cypress.
+//
+// You can change the location of this file or turn off
+// automatically serving support files with the
+// 'supportFile' configuration option.
+//
+// You can read more here:
+// https://on.cypress.io/configuration
+// ***********************************************************
+
+// Import commands.js using ES2015 syntax:
+import './commands'
+
+// Alternatively you can use CommonJS syntax:
+// require('./commands')
diff --git a/0000_gb_points_temp/env.d.ts b/0000_gb_points_temp/env.d.ts
new file mode 100644
index 0000000..e3315ce
--- /dev/null
+++ b/0000_gb_points_temp/env.d.ts
@@ -0,0 +1,18 @@
+///
+interface ImportMetaEnv {
+ VITE_BASE_URL: string;
+}
+
+// Asset module declarations for older @vue/tsconfig compatibility
+declare module '*.svg' {
+ const src: string;
+ export default src;
+}
+declare module '*.jpg' {
+ const src: string;
+ export default src;
+}
+declare module '*.png' {
+ const src: string;
+ export default src;
+}
diff --git a/0000_gb_points_temp/extract-resources.js b/0000_gb_points_temp/extract-resources.js
new file mode 100644
index 0000000..a1c9052
--- /dev/null
+++ b/0000_gb_points_temp/extract-resources.js
@@ -0,0 +1,453 @@
+/**
+ * 静态资源提取脚本
+ * 从 header.html 和 footer.html 中提取 base64 图片、内联 CSS 和字体
+ *
+ * 功能:
+ * 1. 提取 base64 图片到 assets/images/
+ * 2. 提取所有内联 CSS 到 assets/css/
+ * 3. 提取字体文件到 assets/fonts/
+ * 4. 去除所有 meta 标签
+ * 5. 去除所有 script 标签
+ * 6. 只保留 body 内的内容
+ * 7. 把引入的 style 放到顶部
+ * 8. 给所有 HTML 属性值自动加上双引号
+ *
+ * 使用方法:
+ * - node extract-resources.js # 正常运行,从备份恢复
+ * - node extract-resources.js --keep # 保持当前文件,不从备份恢复
+ */
+
+const fs = require('fs');
+const path = require('path');
+
+// 检查命令行参数
+const KEEP_CURRENT = process.argv.includes('--keep');
+
+const PUBLIC_DIR = path.join(__dirname, 'public/pages');
+const STATIC_DIR = path.join(__dirname, 'pages');
+const FILES_TO_PROCESS = ['header.html', 'footer.html'];
+// const FILES_TO_PROCESS = ['home.html', 'page2.html', 'page3.html', 'page4.html', 'page5.html'];
+
+// 创建资源目录 (public)
+const ASSETS_DIR = path.join(PUBLIC_DIR, 'assets');
+const IMG_DIR = path.join(ASSETS_DIR, 'images');
+const CSS_DIR = path.join(ASSETS_DIR, 'css');
+const FONTS_DIR = path.join(ASSETS_DIR, 'fonts');
+
+// 创建资源目录 (static)
+const STATIC_ASSETS_DIR = path.join(STATIC_DIR, 'assets');
+const STATIC_IMG_DIR = path.join(STATIC_ASSETS_DIR, 'images');
+const STATIC_CSS_DIR = path.join(STATIC_ASSETS_DIR, 'css');
+const STATIC_FONTS_DIR = path.join(STATIC_ASSETS_DIR, 'fonts');
+
+// 清理旧资源文件的函数
+function cleanDirectory(dir) {
+ if (fs.existsSync(dir)) {
+ const files = fs.readdirSync(dir);
+ files.forEach(file => {
+ const filePath = path.join(dir, file);
+ if (fs.statSync(filePath).isFile()) {
+ fs.unlinkSync(filePath);
+ }
+ });
+ }
+}
+
+[ASSETS_DIR, IMG_DIR, CSS_DIR, FONTS_DIR].forEach(dir => {
+ if (!fs.existsSync(dir)) {
+ fs.mkdirSync(dir, { recursive: true });
+ }
+});
+
+// 清理旧资源文件
+console.log('🧹 清理旧资源文件...');
+cleanDirectory(IMG_DIR);
+cleanDirectory(CSS_DIR);
+cleanDirectory(FONTS_DIR);
+
+console.log('🚀 开始提取静态资源...\n');
+console.log(`📂 工作目录: ${PUBLIC_DIR}\n`);
+
+FILES_TO_PROCESS.forEach(filename => {
+ const filePath = path.join(PUBLIC_DIR, filename);
+ const backupPath = filePath + '.backup';
+
+ if (!fs.existsSync(filePath)) {
+ console.log(`⚠️ 文件不存在: ${filename}`);
+ return;
+ }
+
+ // 创建备份
+ if (!fs.existsSync(backupPath)) {
+ fs.copyFileSync(filePath, backupPath);
+ console.log(`📄 处理文件: ${filename} (已创建备份)`);
+ } else if (!KEEP_CURRENT) {
+ // 如果备份存在且未指定 --keep,从备份恢复
+ fs.copyFileSync(backupPath, filePath);
+ console.log(`📄 处理文件: ${filename} (从备份恢复)`);
+ } else {
+ console.log(`📄 处理文件: ${filename} (保持当前版本)`);
+ }
+
+ let content = fs.readFileSync(filePath, 'utf8');
+ const originalSize = content.length;
+
+ let imageCount = 0;
+ let cssCount = 0;
+ let fontCount = 0;
+
+ // 1. 提取 base64 图片
+ console.log(' 提取 base64 图片...');
+ content = content.replace(/url\s*\(\s*["']?(data:image\/([^;]+);base64,([^"')]+))["']?\s*\)/gi,
+ (match, dataUrl, imageType, base64Data) => {
+ imageCount++;
+ // 修复图片扩展名,处理 svg+xml 等情况
+ let ext = imageType.split('/').pop();
+ if (ext.includes('svg')) {
+ ext = 'svg';
+ } else if (ext.includes('+')) {
+ ext = ext.split('+')[0];
+ }
+ const imageName = `${filename.replace('.html', '')}_img_${imageCount}.${ext}`;
+ const imagePath = path.join(IMG_DIR, imageName);
+
+ try {
+ const buffer = Buffer.from(base64Data, 'base64');
+ fs.writeFileSync(imagePath, buffer);
+ return `url("/pages/assets/images/${imageName}")`;
+ } catch (e) {
+ console.log(` ⚠️ 无法保存图片 ${imageName}:`, e.message);
+ return match;
+ }
+ }
+ );
+
+ // 2. 提取 img src 中的 base64 (有引号的)
+ content = content.replace(/
]*?)src\s*=\s*["'](data:image\/([^;]+);base64,([^"']+))["']([^>]*)>/gi,
+ (match, beforeAttrs, dataUrl, imageType, base64Data, afterAttrs) => {
+ imageCount++;
+ // 修复图片扩展名
+ let ext = imageType.split('/').pop();
+ if (ext.includes('svg')) {
+ ext = 'svg';
+ } else if (ext.includes('+')) {
+ ext = ext.split('+')[0];
+ }
+ const imageName = `${filename.replace('.html', '')}_inline_${imageCount}.${ext}`;
+ const imagePath = path.join(IMG_DIR, imageName);
+
+ try {
+ const buffer = Buffer.from(base64Data, 'base64');
+ fs.writeFileSync(imagePath, buffer);
+ // 确保属性间有正确的空格
+ const before = beforeAttrs ? ' ' + beforeAttrs.trim() : '';
+ const after = afterAttrs ? ' ' + afterAttrs.trim() : '';
+ return `
`;
+ } catch (e) {
+ console.log(` ⚠️ 无法保存图片 ${imageName}:`, e.message);
+ return match;
+ }
+ }
+ );
+
+ // 3. 提取 img src 中的 base64 (没有引号的,直到遇到空白字符或>)
+ content = content.replace(/
]*?)src\s*=\s*(data:image\/([^;\s>]+);base64,([^\s>]+))([^>]*)>/gi,
+ (match, beforeAttrs, dataUrl, imageType, base64Data, afterAttrs) => {
+ imageCount++;
+ // 修复图片扩展名
+ let ext = imageType.split('/').pop();
+ if (ext.includes('svg')) {
+ ext = 'svg';
+ } else if (ext.includes('+')) {
+ ext = ext.split('+')[0];
+ }
+ const imageName = `${filename.replace('.html', '')}_inline_${imageCount}.${ext}`;
+ const imagePath = path.join(IMG_DIR, imageName);
+
+ try {
+ const buffer = Buffer.from(base64Data, 'base64');
+ fs.writeFileSync(imagePath, buffer);
+ // 确保属性间有正确的空格
+ const before = beforeAttrs ? ' ' + beforeAttrs.trim() : '';
+ const after = afterAttrs ? ' ' + afterAttrs.trim() : '';
+ return `
`;
+ } catch (e) {
+ console.log(` ⚠️ 无法保存图片 ${imageName}:`, e.message);
+ return match;
+ }
+ }
+ );
+
+ // 4. 提取 CSS 变量中的 base64
+ content = content.replace(/--[^:]+:\s*url\s*\(\s*["']?(data:image\/([^;]+);base64,([^"')]+))["']?\s*\)/gi,
+ (match, dataUrl, imageType, base64Data) => {
+ imageCount++;
+ // 修复图片扩展名
+ let ext = imageType.split('/').pop();
+ if (ext.includes('svg')) {
+ ext = 'svg';
+ } else if (ext.includes('+')) {
+ ext = ext.split('+')[0];
+ }
+ const imageName = `${filename.replace('.html', '')}_var_${imageCount}.${ext}`;
+ const imagePath = path.join(IMG_DIR, imageName);
+
+ try {
+ const buffer = Buffer.from(base64Data, 'base64');
+ fs.writeFileSync(imagePath, buffer);
+ const varName = match.split(':')[0];
+ return `${varName}: url("/pages/assets/images/${imageName}")`;
+ } catch (e) {
+ console.log(` ⚠️ 无法保存图片 ${imageName}:`, e.message);
+ return match;
+ }
+ }
+ );
+
+ // 5. 提取所有内联 CSS (style 标签)
+ console.log(' 提取内联 CSS...');
+ const cssLinks = []; // 用于收集所有 CSS 链接
+ const styleMatches = content.match(/
+
+