Skip to content

Commit 8d0e15a

Browse files
committed
新增批量上传文章接口
1 parent dd8dffe commit 8d0e15a

5 files changed

Lines changed: 87 additions & 11 deletions

File tree

src/Http/Controllers/Api/BlogController.php

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Illuminate\Validation\Rule;
99
use Illuminate\Support\Facades\DB;
1010
use Illuminate\Support\Facades\Log;
11+
use Maatwebsite\Excel\Facades\Excel;
1112
use Illuminate\Support\Facades\Cache;
1213
use Illuminate\Support\Facades\Storage;
1314
use NexaMerchant\Blog\Models\BlogArticle;
@@ -16,6 +17,7 @@
1617
use NexaMerchant\Blog\Http\Requests\StoreBlogCategoryRequest;
1718
use NexaMerchant\Blog\Http\Requests\UpdateBlogArticleRequest;
1819
use NexaMerchant\Blog\Http\Requests\UpdateBlogCategoryRequest;
20+
use NexaMerchant\Blog\Import\ArticleImport;
1921

2022
class BlogController extends Controller
2123
{
@@ -314,11 +316,11 @@ public function recommendArticles(Request $request)
314316
/**
315317
* 从HTML内容中提取第一张图片URL
316318
*/
317-
private function extractFirstImageFromContent(string $content): ?string
319+
public function extractFirstImageFromContent(string $content): ?string
318320
{
319321
// 方案1:正则匹配(简单HTML内容)
320322
preg_match('/<img[^>]+src="([^">]+)"/', $content, $matches);
321-
$imageUrl = $matches[1] ?? null;
323+
$imageUrl = $matches[1] ?? '';
322324

323325
// 方案2:DOM解析(更复杂的HTML)
324326
/*
@@ -768,4 +770,40 @@ public function batchDeleteCategory(Request $request)
768770
}
769771
});
770772
}
773+
774+
public function articlesUpload(Request $request)
775+
{
776+
// return response()->json([
777+
// 'success' => false,
778+
// 'message' => $request
779+
// ], 500);
780+
$this->validate(request(), [
781+
'file' => 'required|mimes:xls,xlsx',
782+
]);
783+
784+
// return response()->json([
785+
// 'success' => false,
786+
// 'message' => dump($request)
787+
// ], 500);
788+
789+
try {
790+
Excel::import(new ArticleImport, request()->file('file'));
791+
792+
return response()->json([
793+
'success' => true,
794+
'message' => '导入成功',
795+
], 200);
796+
} catch (\Maatwebsite\Excel\Validators\ValidationException $e) {
797+
$failures = $e->failures();
798+
return response()->json([
799+
'message' => 'Import failed due to validation errors.',
800+
'errors' => $failures,
801+
], 422);
802+
} catch (\Exception $e) {
803+
return response()->json([
804+
'message' => 'An error occurred during import.',
805+
'error' => $e->getMessage(),
806+
], 500);
807+
}
808+
}
771809
}

src/Http/Requests/StoreBlogArticleRequest.php

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,12 @@ public function rules()
1515
{
1616
return [
1717
'title' => 'required|string|max:512',
18-
'content' => 'nullable|string',
19-
'description' => 'sometimes|string',
20-
// 'cover_image' => 'required|string|max:255',
18+
'content' => 'required|string',
19+
'description' => 'nullable|string',
2120
'category_id' => 'required|integer|exists:blog_categories,id',
22-
'seo_meta_title' => 'required|string|max:255',
23-
'seo_meta_keywords' => 'required|string|max:255',
24-
'seo_meta_description' => 'required|string|max:255',
21+
'seo_meta_title' => 'nullable|string|max:512',
22+
'seo_meta_keywords' => 'nullable|string|max:512',
23+
'seo_meta_description' => 'nullable|string',
2524
'seo_url_key' => 'required|string|max:255|unique:blog_articles,seo_url_key'
2625
];
2726
}

src/Http/Requests/UpdateBlogArticleRequest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ public function rules()
2222
'content' => 'sometimes|string',
2323
'category_id' => 'sometimes|integer|exists:blog_categories,id',
2424
'status' => 'sometimes|integer|in:1,2',
25-
'seo_meta_title' => 'sometimes|string|max:255',
26-
'seo_meta_keywords' => 'sometimes|string|max:255',
27-
'seo_meta_description' => 'sometimes|string|max:255',
25+
'seo_meta_title' => 'sometimes|string|max:512',
26+
'seo_meta_keywords' => 'sometimes|string|max:512',
27+
'seo_meta_description' => 'sometimes|string',
2828
'seo_url_key' => [
2929
'sometimes',
3030
'string',

src/Import/ArticleImport.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace NexaMerchant\Blog\Import;
4+
5+
use Maatwebsite\Excel\Concerns\ToModel;
6+
use NexaMerchant\Blog\Models\BlogArticle;
7+
use Maatwebsite\Excel\Concerns\WithHeadingRow;
8+
use NexaMerchant\Blog\Http\Controllers\Api\BlogController;
9+
10+
class ArticleImport implements ToModel, WithHeadingRow
11+
{
12+
public function rules(): array
13+
{
14+
return [
15+
'*.title' => 'required|string|max:512',
16+
'*.content' => 'required|string',
17+
'*.description' => 'sometimes|string',
18+
'*.category_id' => 'required|integer|exists:blog_categories,id',
19+
'*.seo_meta_title' => 'nullable|string|max:512',
20+
'*.seo_meta_keywords' => 'nullable|string|max:512',
21+
'*.seo_meta_description' => 'nullable|string',
22+
'*.seo_url_key' => 'required|string|max:255|unique:blog_articles,seo_url_key'
23+
];
24+
}
25+
26+
public function model(array $row)
27+
{
28+
$blogController = new BlogController();
29+
$row['cover_image'] = $blogController->extractFirstImageFromContent($row['content']);
30+
$row['created_at'] = date('Y-m-d H:i:s');
31+
$row['updated_at'] = date('Y-m-d H:i:s');
32+
33+
$blogArticle = new BlogArticle($row);
34+
$blogArticle->save();
35+
}
36+
}

src/Routes/api.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@
4848
->where('id', '^[0-9,]+$') // 允许数字或逗号分隔的ID
4949
->name('v1.admin.blog.articles.destroy');
5050

51+
// 批量上传文章
52+
Route::post('articles-upload', 'articlesUpload')->name('v1.admin.blog.articles.upload');
53+
5154
// 批量更新文章状态
5255
Route::patch('articles/batch-status', 'batchUpdateArticleStatus')->name('v1.admin.blog.articles.batch_status');
5356

0 commit comments

Comments
 (0)