diff --git a/.gitignore b/.gitignore index 7e9c18f..e3597fc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,13 @@ -.DS_Store -dist/electron/* -dist/web/* -build/ -node_modules/ -npm-debug.log -npm-debug.log.* -thumbs.db -!.gitkeep -.backup/ \ No newline at end of file +.DS_Store +dist/electron/* +dist/web/* +build/ +node_modules/ +npm-debug.log +npm-debug.log.* +thumbs.db +!.gitkeep +.backup/ +# 服务器文件存储目录(用户上传的文件) +api/files/ +design/files/ \ No newline at end of file diff --git a/README.md b/README.md index c212fc8..a4b1328 100644 --- a/README.md +++ b/README.md @@ -1,160 +1,361 @@ -# SoonDesign 设计工具 - -简单易用的桌面设计软件,支持光盘和卡片模板设计。 - ---- - -## 🚀 快速开始 - -### 第一次使用 - -```bash -# 1. 安装依赖(只需一次) -yarn install - -# 2. 启动程序 -yarn start -``` - -> **前置要求**:需要安装 [Node.js](https://nodejs.org/)(推荐 16 或更高版本) - ---- - -## 📦 发布流程(傻瓜式操作) - -### 方式一:一键发布 ⭐ 推荐 - -```bash -# Windows 系统 -yarn release:win - -# Mac 系统 -yarn release:mac - -# Linux 系统 -yarn release:linux -``` - -✅ **自动完成**:加密 → 测试 → 清理 → 打包 -✅ **安装包位置**:`build` 文件夹 - ---- - -### 方式二:分步操作(手动控制) - -#### 步骤 1:加密代码 - -```bash -yarn encrypt:win # Windows -yarn encrypt:linux # Mac/Linux -``` - -✅ 生成 `.jsc` 加密文件(自动覆盖旧文件) - -#### 步骤 2:测试 - -```bash -yarn start -``` - -✅ 确认程序正常运行,无报错 - -#### 步骤 3:清理源文件 - -```bash -yarn cleanup -``` - -✅ 删除 `.js` 源文件,自动备份到 `.backup` 文件夹 - -#### 步骤 4:打包 - -```bash -yarn build:win # Windows -yarn build:mac # Mac -yarn build:linux # Linux -``` - -✅ 生成安装包到 `build` 文件夹 - ---- - -## 🔧 其他常用命令 - -### 恢复源文件 - -```bash -yarn restore -``` - -> 从 `.backup` 文件夹恢复所有源文件(误删除时使用) - -### 清理加密文件 - -```bash -yarn cleanup:jsc -``` - -> 删除所有 `.jsc` 文件(重新加密前使用) - -### 修改文件名映射 - -编辑 `lib/module-map.json`: - -```json -{ - "mappings": { - "design1": { - "core": "core1", // 修改这里 - "output": "output1", - "ui": "ui1" - } - } -} -``` - -然后重新运行 `yarn encrypt:win` - ---- - -## ⚠️ 注意事项 - -- **开发时**:保留 `.js` 源文件,不要运行 `cleanup` -- **发布时**:必须先加密、再清理、最后打包 -- **备份在**:`.backup` 文件夹(不会被打包进应用) - ---- - -## 📁 项目结构 - -``` -lib/ -├── module-map.json - 文件名映射配置 -├── index.js - 首页入口 -├── design1.js - 光盘模板入口 -├── design2.js - 卡片模板入口 -├── design1/ - 光盘模板功能模块 -│ ├── core.js - 核心功能 -│ ├── output.js - 导出/保存 -│ └── ui.js - 界面交互 -└── design2/ - 卡片模板功能模块 - ├── core.js - ├── output.js - └── ui.js - -scripts/encrypt/ - 加密脚本(不会被打包) -.backup/ - 源文件备份(不会被打包) -``` - ---- - -## 🔧 调试模式 - -按 `F12` 或 `Ctrl+Shift+I` 打开开发者工具查看错误信息。 - ---- - -## 📚 更多文档 - -- [加密详细说明](scripts/encrypt/README.md) -- 当前版本:v2.3.017 +# SoonDesign 设计工具 + +专业的卡片和光盘设计软件,支持单面/双面模板设计、二维码/条形码生成、图片编辑等功能。提供**桌面端(Electron)**和**网页端**两种使用方式。 + +--- + +## ✨ 主要功能 + +- 🎨 **模板设计**:支持单面(光盘)和双面(卡片)模板设计 +- 📱 **二维码/条形码**:内置二维码和条形码生成器 +- 🖼️ **图片编辑**:支持图片添加、裁剪、旋转、缩放等操作 +- 📝 **文本编辑**:丰富的文本样式设置(字体、大小、颜色、对齐等) +- 💾 **文件管理**:支持 `.soon` 格式项目文件的保存和打开 +- 🌐 **多端支持**:桌面端(Windows/Mac/Linux)和网页端(现代浏览器) +- 🌍 **多语言**:支持中文简体、中文繁体、英文 + +--- + +## 🚀 快速开始 + +### 系统要求 + +- **Node.js**: >= 16.0.0 +- **npm**: >= 7.0.0 或 **yarn** +- **操作系统**: Windows 7+, macOS 10.12+, Linux (Ubuntu 18.04+) + +### 安装依赖 + +```bash +# 使用 yarn(推荐) +yarn install + +# 或使用 npm +npm install +``` + +### 启动应用 + +```bash +# 桌面端(Electron) +yarn start + +# 或 +npm start +``` + +### 网页端使用 + +#### 方式一:使用本地服务器(推荐)⭐ + +```bash +# 启动本地服务器(自动打开浏览器) +yarn web + +# 或使用 npm +npm run web + +# 开发模式(禁用缓存) +yarn web:dev +``` + +服务器会在 `http://localhost:8080` 启动,并自动打开首页。 + +> 💡 **提示**:使用本地服务器可以避免 CORS 问题,确保所有资源正确加载。 + +#### 方式二:使用 Python 内置服务器 + +```bash +# Python 3 +python -m http.server 8080 + +# Python 2 +python -m SimpleHTTPServer 8080 +``` + +然后在浏览器中访问 `http://localhost:8080/index.web.html` + +#### 方式三:使用其他静态服务器 + +```bash +# 使用 serve(需要先安装: npm install -g serve) +serve -p 8080 + +# 使用 live-server(需要先安装: npm install -g live-server) +live-server --port=8080 +``` + +#### 方式四:直接打开文件 + +直接在浏览器中打开以下文件: + +- **首页**: `index.web.html` +- **单面设计页**: `design1.web.html` +- **双面设计页**: `design2.web.html` + +> ⚠️ **注意**:直接打开文件时,某些浏览器可能因为安全策略限制文件访问,建议使用方式一。 + +#### 网页端数据存储 + +- **sessionStorage**: 存储当前会话的项目数据(关闭标签页后清空) +- **localStorage**: 存储历史记录和用户设置(持久化) +- **文件格式**: 使用 `soondesign_session:文件名.soon` 作为 session key + +#### 服务器文件保存功能 ⭐ 新增 + +网页端默认将文件保存在浏览器缓存中。如果部署在服务器上,可以启用服务器文件保存功能,实现真正的文件持久化: + +1. **自动检测**:程序会自动检测是否在服务器环境(非 localhost) +2. **自动保存**:保存文件时自动上传到服务器 +3. **自动读取**:打开文件时自动从服务器读取 +4. **降级处理**:如果服务器保存失败,自动降级为浏览器下载 + +**部署步骤**: +- 将 `api` 目录下的 PHP 文件上传到服务器的 `/api/` 目录 +- 创建文件存储目录:`/design/files/` +- 详细说明请参考:[api/README.md](api/README.md) + +--- + +## 📦 构建和发布 + +### 方式一:一键发布 ⭐ 推荐 + +```bash +# Windows 系统 +yarn release:win + +# Mac 系统 +yarn release:mac + +# Linux 系统 +yarn release:linux +``` + +✅ **自动完成**:加密 → 测试 → 清理 → 打包 +✅ **安装包位置**:`build` 文件夹 + +### 方式二:分步操作(手动控制) + +#### 步骤 1:加密代码 + +```bash +yarn encrypt:win # Windows +yarn encrypt:linux # Mac/Linux +``` + +✅ 生成 `.jsc` 加密文件(自动覆盖旧文件) + +#### 步骤 2:测试 + +```bash +yarn start +``` + +✅ 确认程序正常运行,无报错 + +#### 步骤 3:清理源文件 + +```bash +yarn cleanup +``` + +✅ 删除 `.js` 源文件,自动备份到 `.backup` 文件夹 + +#### 步骤 4:打包 + +```bash +yarn build:win # Windows +yarn build:mac # Mac +yarn build:linux # Linux +``` + +✅ 生成安装包到 `build` 文件夹 + +--- + +## 🔧 其他常用命令 + +### 开发相关 + +```bash +# 启动开发模式 +yarn start + +# 构建 Web 资源 +yarn dist + +# 使用 electron-packager 打包(旧方式) +yarn package +``` + +### 文件管理 + +```bash +# 恢复源文件 +yarn restore + +# 清理加密文件 +yarn cleanup:jsc +``` + +> 从 `.backup` 文件夹恢复所有源文件(误删除时使用) + +### 修改文件名映射 + +编辑 `lib/module-map.json`: + +```json +{ + "mappings": { + "design1": { + "core": "core1", // 修改这里 + "output": "output1", + "ui": "ui1" + } + } +} +``` + +然后重新运行 `yarn encrypt:win` + +--- + +## 📁 项目结构 + +``` +soonDesign/ +├── lib/ # 核心代码库 +│ ├── platform/ # 平台抽象层 +│ │ ├── web.js # 网页端实现 +│ │ ├── electron.js # Electron 桌面端实现 +│ │ └── bridge.js # 平台桥接层 +│ ├── common/ # 公共工具 +│ ├── design1/ # 单面模板(光盘) +│ │ ├── core.js # 核心功能 +│ │ ├── output.js # 导出/保存 +│ │ └── ui.js # 界面交互 +│ ├── design2/ # 双面模板(卡片) +│ │ ├── core.js +│ │ ├── output.js +│ │ └── ui.js +│ ├── index.js # 首页入口 +│ ├── design1.js # 单面模板入口 +│ └── design2.js # 双面模板入口 +├── public/ # 静态资源 +│ ├── images/ # 图片资源 +│ └── css/ # 样式文件 +├── layui/ # LayUI 框架 +├── scripts/ # 构建脚本 +│ └── encrypt/ # 加密脚本 +├── help/ # 帮助文档 +├── main.js # Electron 主进程入口 +├── index.web.html # 网页端首页 +├── design1.web.html # 网页端单面设计页 +├── design2.web.html # 网页端双面设计页 +├── package.json # 项目配置 +└── README.md # 本文档 +``` + +--- + +## 🛠️ 技术栈 + +- **框架**: Electron 15.x +- **UI 库**: LayUI +- **画布库**: Fabric.js +- **二维码**: jr-qrcode +- **条形码**: jsbarcode +- **构建工具**: electron-builder, webpack +- **语言**: JavaScript (ES5+) + +--- + +## 🌐 网页端特性 + +### 存储机制 + +- **sessionStorage**: 存储当前会话的项目数据(关闭标签页后清空) +- **localStorage**: 存储历史记录和用户设置(持久化) +- **文件格式**: 使用 `soondesign_session:文件名.soon` 作为 session key + +### 功能限制 + +- 文件保存会触发浏览器下载(使用 File System Access API 时除外) +- 关闭标签页后 session 数据会丢失,但历史记录会保留 +- 部分浏览器可能限制脚本关闭页签的功能 + +### 浏览器兼容性 + +- Chrome/Edge 90+ +- Firefox 88+ +- Safari 14+ + +--- + +## ⚠️ 注意事项 + +### 开发时 + +- **保留 `.js` 源文件**,不要运行 `cleanup` +- 使用 `yarn start` 启动开发模式 +- 按 `F12` 打开开发者工具调试 + +### 发布时 + +- **必须先加密、再清理、最后打包** +- 备份文件在 `.backup` 文件夹(不会被打包进应用) +- 确保所有依赖已正确安装 + +### 网页端 + +- 数据存储在浏览器本地,清除浏览器数据会丢失历史记录 +- 建议定期导出 `.soon` 文件作为备份 +- 不同域名下的数据不共享 + +--- + +## 🔧 调试模式 + +### 桌面端 + +按 `F12` 或 `Ctrl+Shift+I`(Mac: `Cmd+Option+I`)打开开发者工具查看错误信息。 + +### 网页端 + +同样使用浏览器开发者工具(F12),查看 Console 面板的日志和错误信息。 + +--- + +## 📚 更多文档 + +- [加密详细说明](scripts/encrypt/README.md) +- [网页端功能清单](docs/网页端功能清单.md) + +--- + +## 📝 版本信息 + +- **当前版本**: v3.2.101 +- **更新日期**: 2026-02-07 + +--- + +## 📄 许可证 + +MIT License + +Copyright © 2023 [CardSoon](https://www.cardsoon.com) + +--- + +## 🤝 贡献 + +欢迎提交 Issue 和 Pull Request! + +--- + +## 📞 联系方式 + +- **官网**: [CardSoon](https://www.cardsoon.com/index.php/cn/products/cardsoonsoft.html) +- **邮箱**: jerry79.xu@gmail.com diff --git a/api/README.md b/api/README.md new file mode 100644 index 0000000..3d405cc --- /dev/null +++ b/api/README.md @@ -0,0 +1,97 @@ +# SoonDesign 网页端服务器文件保存 API + +## 功能说明 + +网页端默认将文件保存在浏览器缓存(localStorage/sessionStorage)中。通过部署这些 API 接口,可以实现将文件保存到服务器,实现真正的文件持久化。 + +## 部署步骤 + +### 1. 上传 API 文件 + +将 `api` 目录下的 PHP 文件上传到服务器的 `/api/` 目录(相对于网站根目录)。 + +例如,如果网站根目录是 `/www/wwwroot/soonWebsite/`,则: +- `save_file.php` → `/www/wwwroot/soonWebsite/api/save_file.php` +- `read_file.php` → `/www/wwwroot/soonWebsite/api/read_file.php` + +### 2. 创建文件存储目录 + +创建用于存储 `.soon` 文件的目录: + +```bash +mkdir -p /www/wwwroot/soonWebsite/design/files +chmod 755 /www/wwwroot/soonWebsite/design/files +``` + +### 3. 配置 Nginx(如果需要) + +确保 Nginx 配置允许访问 `/api/` 和 `/design/files/` 目录: + +```nginx +location /api/ { + try_files $uri $uri/ =404; +} + +location /design/files/ { + alias /www/wwwroot/soonWebsite/design/files/; + # 允许列出文件(可选) + autoindex off; +} +``` + +### 4. 测试 API + +访问以下 URL 测试 API 是否正常工作: + +- 保存文件:`http://114.55.133.123:8888/api/save_file.php` +- 读取文件:`http://114.55.133.123:8888/api/read_file.php?fileName=test.soon` + +## 工作原理 + +1. **自动检测服务器环境**:网页端会自动检测是否在服务器环境(非 localhost/127.0.0.1) +2. **保存文件**:当用户保存文件时,如果是服务器环境,会自动调用 `save_file.php` 将文件上传到服务器 +3. **读取文件**:当打开文件时,如果是服务器文件路径,会自动调用 `read_file.php` 从服务器读取 +4. **降级处理**:如果服务器保存失败,会自动降级为浏览器下载 + +## 文件存储位置 + +所有保存的 `.soon` 文件存储在: +``` +/design/files/ +``` + +文件访问路径为: +``` +http://114.55.133.123:8888/design/files/文件名.soon +``` + +## 安全说明 + +- API 接口已包含文件名清理,防止路径遍历攻击 +- 建议在生产环境中添加身份验证(如 Token 验证) +- 建议限制文件大小和类型 +- 建议定期清理旧文件 + +## 故障排除 + +### 问题:保存时提示"保存失败" + +**可能原因:** +1. API 文件路径不正确 +2. 文件存储目录权限不足 +3. PHP 配置问题 + +**解决方法:** +1. 检查 API 文件是否在正确位置 +2. 检查目录权限:`chmod 755 /www/wwwroot/soonWebsite/design/files` +3. 检查 PHP 错误日志 + +### 问题:文件保存后找不到 + +**可能原因:** +1. 文件保存路径配置错误 +2. Nginx 配置问题 + +**解决方法:** +1. 检查 `save_file.php` 中的 `$saveDir` 路径 +2. 检查 Nginx 配置是否正确指向文件目录 diff --git a/api/read_file.php b/api/read_file.php new file mode 100644 index 0000000..b655b4d --- /dev/null +++ b/api/read_file.php @@ -0,0 +1,75 @@ + false, 'error' => 'Method not allowed']); + exit; +} + +// 获取文件名 +$fileName = isset($_GET['fileName']) ? $_GET['fileName'] : ''; + +// 验证文件名 +if (empty($fileName)) { + http_response_code(400); + echo json_encode(['success' => false, 'error' => '文件名不能为空']); + exit; +} + +// 清理文件名,防止路径遍历攻击 +$fileName = basename($fileName); +if (strpos($fileName, '..') !== false) { + http_response_code(400); + echo json_encode(['success' => false, 'error' => '无效的文件名']); + exit; +} + +// 获取文件路径 +$saveDir = dirname(__DIR__) . '/design/files/'; +$filePath = $saveDir . $fileName; + +// 检查文件是否存在 +if (!file_exists($filePath)) { + http_response_code(404); + echo json_encode(['success' => false, 'error' => '文件不存在']); + exit; +} + +// 读取文件内容 +try { + $content = file_get_contents($filePath); + if ($content === false) { + throw new Exception('文件读取失败'); + } + + // 尝试解析 JSON 验证格式 + $json = json_decode($content, true); + if (json_last_error() !== JSON_ERROR_NONE) { + throw new Exception('文件格式错误: ' . json_last_error_msg()); + } + + echo $content; +} catch (Exception $e) { + http_response_code(500); + echo json_encode([ + 'success' => false, + 'error' => '读取失败: ' . $e->getMessage() + ]); +} +?> diff --git a/api/save_file.php b/api/save_file.php new file mode 100644 index 0000000..c22af92 --- /dev/null +++ b/api/save_file.php @@ -0,0 +1,88 @@ + false, 'error' => 'Method not allowed']); + exit; +} + +// 获取保存目录(相对于网站根目录) +// 如果 API 在 /api/ 目录,文件存储在 /design/files/ +$saveDir = dirname(__DIR__) . '/design/files/'; +// 如果上述路径不正确,请根据实际部署情况修改,例如: +// $saveDir = '/www/wwwroot/soonWebsite/design/files/'; + +// 确保目录存在 +if (!is_dir($saveDir)) { + mkdir($saveDir, 0755, true); +} + +// 获取文件名和内容 +$fileName = isset($_POST['fileName']) ? $_POST['fileName'] : ''; +$fileContent = isset($_POST['fileContent']) ? $_POST['fileContent'] : ''; + +// 验证文件名 +if (empty($fileName)) { + http_response_code(400); + echo json_encode(['success' => false, 'error' => '文件名不能为空']); + exit; +} + +// 清理文件名,防止路径遍历攻击 +$fileName = basename($fileName); +if (strpos($fileName, '..') !== false) { + http_response_code(400); + echo json_encode(['success' => false, 'error' => '无效的文件名']); + exit; +} + +// 确保文件名以 .soon 结尾 +if (substr($fileName, -5) !== '.soon') { + $fileName = preg_replace('/\.soon$/i', '', $fileName) . '.soon'; +} + +// 验证内容 +if (empty($fileContent)) { + http_response_code(400); + echo json_encode(['success' => false, 'error' => '文件内容不能为空']); + exit; +} + +// 保存文件 +$filePath = $saveDir . $fileName; +try { + $result = file_put_contents($filePath, $fileContent); + if ($result === false) { + throw new Exception('文件写入失败'); + } + + echo json_encode([ + 'success' => true, + 'message' => '文件保存成功', + 'filePath' => '/design/files/' . $fileName, + 'fileName' => $fileName + ]); +} catch (Exception $e) { + http_response_code(500); + echo json_encode([ + 'success' => false, + 'error' => '保存失败: ' . $e->getMessage() + ]); +} +?> diff --git a/design1.html b/design1.html index 701d990..4fdca93 100644 --- a/design1.html +++ b/design1.html @@ -873,10 +873,8 @@ (function() { const path = require('path'), fs = require('fs'), remote = require('@electron/remote'); const appPath = (() => { try { return remote.app.getAppPath(); } catch(e) { return __dirname || process.cwd(); } })(); - + try { require(path.join(appPath, 'lib', 'platform', 'electron.js')); } catch (e) { console.warn('platform/electron:', e); } const jsPath = path.join(appPath, 'lib', 'design1.js'); - - // 加载 .js 源文件 if (fs.existsSync(jsPath)) { try { require(jsPath); diff --git a/design1.web.html b/design1.web.html new file mode 100644 index 0000000..9d6077b --- /dev/null +++ b/design1.web.html @@ -0,0 +1,878 @@ + + + +
+ + +
+
+
+
+
' :
- '
';
-
- // 组装 HTML
- str = `
' :
+ '
';
+
+ // 组装 HTML
+ str = `