commit b76fb31890c737b0ed663011bed03de288833c74
Author: Snowz <372492339@qq.com>
Date: Mon Apr 14 16:35:05 2025 +0800
new
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..3f19477
--- /dev/null
+++ b/README.md
@@ -0,0 +1,72 @@
+# Modern QRCode Generator
+
+这是一个基于开源项目 [PHP QR Code](http://phpqrcode.sourceforge.net/) 重构的现代化二维码生成工具。我们对原项目进行了全面的改进和优化,同时保留了其核心功能和开源精神。
+
+## 主要改进
+
+- 使用 Laravel 框架重构后端,提供更好的代码组织和安全性
+- 采用 Vue.js 构建响应式前端界面,提供更好的用户体验
+- 增加二维码样式自定义功能
+- 支持二维码 Logo 添加
+- 实现二维码生成缓存机制
+- 完善的API文档和单元测试
+
+## 技术栈
+
+- 后端:Laravel 10.x
+- 前端:Vue 3 + Vite
+- UI框架:Element Plus
+- 二维码生成:PHP QR Code Library
+- 缓存:Redis
+
+## 快速开始
+
+### 环境要求
+
+- PHP >= 8.1
+- Composer
+- Node.js >= 16
+- Redis
+
+### 安装步骤
+
+1. 克隆项目
+```bash
+git clone [项目地址]
+cd modern-qrcode
+```
+
+2. 安装后端依赖
+```bash
+composer install
+cp .env.example .env
+php artisan key:generate
+```
+
+3. 安装前端依赖
+```bash
+cd frontend
+npm install
+```
+
+4. 启动开发服务器
+```bash
+# 后端
+php artisan serve
+
+# 前端
+cd frontend
+npm run dev
+```
+
+## API文档
+
+访问 `/api/documentation` 查看完整的API文档。
+
+## 致谢
+
+感谢原项目 [PHP QR Code](http://phpqrcode.sourceforge.net/) 提供的优秀代码基础,本项目在其基础上进行了现代化改造。原项目采用LGPL 3协议开源。
+
+## 许可证
+
+本项目采用 MIT 许可证。
\ No newline at end of file
diff --git a/app/Http/Controllers/QRCodeController.php b/app/Http/Controllers/QRCodeController.php
new file mode 100644
index 0000000..78438a2
--- /dev/null
+++ b/app/Http/Controllers/QRCodeController.php
@@ -0,0 +1,73 @@
+qrCodeService = $qrCodeService;
+ }
+
+ public function generate(Request $request)
+ {
+ $validator = Validator::make($request->all(), [
+ 'text' => 'required|string|max:2048',
+ 'size' => 'required|integer|min:100|max:800',
+ 'errorCorrection' => 'required|in:L,M,Q,H',
+ 'logo' => 'nullable|string'
+ ]);
+
+ if ($validator->fails()) {
+ return response()->json(['errors' => $validator->errors()], 422);
+ }
+
+ $cacheKey = md5($request->text . $request->size . $request->errorCorrection . $request->logo);
+
+ try {
+ $qrCode = Cache::remember($cacheKey, 3600, function () use ($request) {
+ return $this->qrCodeService->generate(
+ $request->text,
+ $request->size,
+ $request->errorCorrection,
+ $request->logo
+ );
+ });
+
+ return response($qrCode)
+ ->header('Content-Type', 'image/png')
+ ->header('Cache-Control', 'public, max-age=3600');
+
+ } catch (\Exception $e) {
+ return response()->json(['error' => '二维码生成失败'], 500);
+ }
+ }
+
+ public function uploadLogo(Request $request)
+ {
+ $validator = Validator::make($request->all(), [
+ 'file' => 'required|image|mimes:jpeg,png,jpg|max:2048'
+ ]);
+
+ if ($validator->fails()) {
+ return response()->json(['errors' => $validator->errors()], 422);
+ }
+
+ try {
+ $path = $request->file('file')->store('logos', 'public');
+ return response()->json([
+ 'url' => asset('storage/' . $path)
+ ]);
+ } catch (\Exception $e) {
+ return response()->json(['error' => 'Logo上传失败'], 500);
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/Services/QRCodeService.php b/app/Services/QRCodeService.php
new file mode 100644
index 0000000..ccb7902
--- /dev/null
+++ b/app/Services/QRCodeService.php
@@ -0,0 +1,78 @@
+tempDir = storage_path('app/temp');
+ if (!file_exists($this->tempDir)) {
+ mkdir($this->tempDir, 0777, true);
+ }
+
+ // 引入PHP QR Code库
+ require_once base_path('vendor/phpqrcode/qrlib.php');
+ $this->phpqrcode = new \QRcode();
+ }
+
+ public function generate(string $text, int $size, string $errorCorrection = 'M', ?string $logoPath = null)
+ {
+ $tempFile = $this->tempDir . '/' . md5($text . time()) . '.png';
+
+ // 设置错误纠正级别
+ $errorCorrectionLevel = match($errorCorrection) {
+ 'L' => QR_ECLEVEL_L,
+ 'M' => QR_ECLEVEL_M,
+ 'Q' => QR_ECLEVEL_Q,
+ 'H' => QR_ECLEVEL_H,
+ default => QR_ECLEVEL_M
+ };
+
+ try {
+ // 生成二维码
+ $this->phpqrcode->png($text, $tempFile, $errorCorrectionLevel, $size);
+
+ // 如果提供了Logo,则合并Logo
+ if ($logoPath) {
+ $this->mergeLogo($tempFile, $logoPath);
+ }
+
+ // 读取生成的图片
+ $qrCode = file_get_contents($tempFile);
+
+ // 删除临时文件
+ unlink($tempFile);
+
+ return $qrCode;
+
+ } catch (Exception $e) {
+ if (file_exists($tempFile)) {
+ unlink($tempFile);
+ }
+ throw $e;
+ }
+ }
+
+ protected function mergeLogo(string $qrCodePath, string $logoPath)
+ {
+ $qrCode = Image::make($qrCodePath);
+ $logo = Image::make($logoPath);
+
+ // 调整Logo大小,不超过二维码的1/4
+ $logoSize = min($qrCode->width(), $qrCode->height()) / 4;
+ $logo->resize($logoSize, $logoSize, function ($constraint) {
+ $constraint->aspectRatio();
+ });
+
+ // 在二维码中心添加Logo
+ $qrCode->insert($logo, 'center');
+ $qrCode->save($qrCodePath);
+ }
+}
\ No newline at end of file
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..a58daf8
--- /dev/null
+++ b/composer.json
@@ -0,0 +1 @@
+{"name":"modern-qrcode/generator","type":"project","description":"A modern QR code generator built with Laravel","keywords":["qrcode","laravel","generator"],"license":"MIT","require":{"php":"^8.1","laravel/framework":"^10.0","guzzlehttp/guzzle":"^7.2","intervention/image":"^2.7","predis/predis":"^2.0"},"require-dev":{"fakerphp/faker":"^1.9.1","laravel/pint":"^1.0","laravel/sail":"^1.18","mockery/mockery":"^1.4.4","nunomaduro/collision":"^7.0","phpunit/phpunit":"^10.1","spatie/laravel-ignition":"^2.0"},"autoload":{"psr-4":{"App\\":"app/","Database\\Factories\\":"database/factories/","Database\\Seeders\\":"database/seeders/"}},"autoload-dev":{"psr-4":{"Tests\\":"tests/"}},"scripts":{"post-autoload-dump":["Illuminate\\Foundation\\ComposerScripts::postAutoloadDump","@php artisan package:discover --ansi"],"post-update-cmd":["@php artisan vendor:publish --tag=laravel-assets --ansi --force"],"post-root-package-install":["@php -r \"file_exists('.env') || copy('.env.example', '.env');\""],"post-create-project-cmd":["@php artisan key:generate --ansi"]},"extra":{"laravel":{"dont-discover":[]}},"config":{"optimize-autoloader":true,"preferred-install":"dist","sort-packages":true,"allow-plugins":{"pestphp/pest-plugin":true,"php-http/discovery":true}}}
\ No newline at end of file
diff --git a/frontend/package.json b/frontend/package.json
new file mode 100644
index 0000000..2e4ea5f
--- /dev/null
+++ b/frontend/package.json
@@ -0,0 +1 @@
+{"name":"modern-qrcode-frontend","private":true,"version":"0.0.0","type":"module","scripts":{"dev":"vite","build":"vite build","preview":"vite preview"},"dependencies":{"@element-plus/icons-vue":"^2.1.0","axios":"^1.6.0","element-plus":"^2.4.0","pinia":"^2.1.0","vue":"^3.3.0","vue-router":"^4.2.0"},"devDependencies":{"@vitejs/plugin-vue":"^4.5.0","sass":"^1.69.0","unplugin-auto-import":"^0.16.0","unplugin-vue-components":"^0.25.0","vite":"^5.0.0"}}
\ No newline at end of file
diff --git a/frontend/src/App.vue b/frontend/src/App.vue
new file mode 100644
index 0000000..3e75a63
--- /dev/null
+++ b/frontend/src/App.vue
@@ -0,0 +1,212 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 生成二维码
+
+
+
+
+
+
+
+
+
+
![生成的二维码]()
+
+ 下载二维码
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/frontend/src/main.js b/frontend/src/main.js
new file mode 100644
index 0000000..e3888a1
--- /dev/null
+++ b/frontend/src/main.js
@@ -0,0 +1,15 @@
+import { createApp } from 'vue'
+import { createPinia } from 'pinia'
+import ElementPlus from 'element-plus'
+import 'element-plus/dist/index.css'
+import App from './App.vue'
+import router from './router'
+import './assets/main.css'
+
+const app = createApp(App)
+
+app.use(createPinia())
+app.use(router)
+app.use(ElementPlus)
+
+app.mount('#app')
\ No newline at end of file
diff --git a/frontend/vite.config.js b/frontend/vite.config.js
new file mode 100644
index 0000000..f233ff7
--- /dev/null
+++ b/frontend/vite.config.js
@@ -0,0 +1,25 @@
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue'
+import AutoImport from 'unplugin-auto-import/vite'
+import Components from 'unplugin-vue-components/vite'
+import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
+
+export default defineConfig({
+ plugins: [
+ vue(),
+ AutoImport({
+ resolvers: [ElementPlusResolver()],
+ }),
+ Components({
+ resolvers: [ElementPlusResolver()],
+ }),
+ ],
+ server: {
+ proxy: {
+ '/api': {
+ target: 'http://localhost:8000',
+ changeOrigin: true,
+ }
+ }
+ }
+})
\ No newline at end of file