Parcourir la source

yico admin & api

Parent
révision
5ff62f718e

+ 31
- 25
app/Filament/Resources/NewsResource.php Voir le fichier

105
                         Radio::make("paragraph_type")->options([
105
                         Radio::make("paragraph_type")->options([
106
                             1 => "圖片",
106
                             1 => "圖片",
107
                             2 => "文字",
107
                             2 => "文字",
108
-                            3 => "影音"
108
+                            3 => "影音",
109
                         ])->label("")->default(1)->Live(),
109
                         ])->label("")->default(1)->Live(),
110
                         Group::make()->schema([
110
                         Group::make()->schema([
111
-                            Translate::make()->schema(fn (string $locale) => [
112
-                                TextInput::make('image_alt')->label("圖片註文")->columnSpan(1),
113
-                            ])->locales(["zh_TW", "en"])
114
-                            ->id(fn ($get) => "para_img_" . $get('item_key')),
115
-                            FileUpload::make('image_url')->label("")->disk("public")
116
-                            // ->helperText('建議寬高限制為:1080*675px,檔案大小限制為1M以下')->maxSize('1024')
117
-                            ->directory("news/paragraph"),
118
-                            TextInput::make('image_link')->label("外連網址")->columnSpanFull()->url(),
111
+                            Section::make('')->schema([
112
+                                Repeater::make("multiple_images")->schema([
113
+                                    TextInput::make('para_img_item_key')
114
+                                        ->default(fn () => Str::random())
115
+                                        ->hidden()
116
+                                        ->afterStateHydrated(function (TextInput $component, $state) {
117
+                                            if (empty($state)) {
118
+                                                $component->state(Str::random());
119
+                                            }
120
+                                        }),
121
+                                    Translate::make()->schema(fn (string $locale) => [
122
+                                        TextInput::make('image_alt')->label("圖片註文"),
123
+                                    ])->locales(["zh_TW", "en"])
124
+                                    ->id(fn ($get) => "para_img_mul_" . $get('para_img_item_key')),
125
+                                    FileUpload::make('image_url')->label("")->disk("public")
126
+                                    // ->helperText('建議寬高限制為:1080*675px,檔案大小限制為1M以下')->maxSize('1024')
127
+                                    ->directory("news/extraPhoto")
128
+                                    ->maxFiles(10),
129
+                                ])
130
+                                ->relationship("photos")
131
+                                ->label("")
132
+                                ->orderColumn('order')
133
+                            ])
119
                         ])->visible(fn (Get $get):bool => $get("paragraph_type") == 1),
134
                         ])->visible(fn (Get $get):bool => $get("paragraph_type") == 1),
120
                         Group::make()->schema([
135
                         Group::make()->schema([
121
                             Translate::make()->schema(fn (string $locale) => [
136
                             Translate::make()->schema(fn (string $locale) => [
141
                                 ])
156
                                 ])
142
                                 ->fileAttachmentsDirectory('attachments')
157
                                 ->fileAttachmentsDirectory('attachments')
143
                                 ->fileAttachmentsVisibility('private'),
158
                                 ->fileAttachmentsVisibility('private'),
144
-                            ])->locales(["zh_TW", "en"])
145
-                                ->id(fn ($get) => "para_text_" . $get('item_key')),
159
+                            ])
160
+                            ->locales(["zh_TW", "en"])
161
+                            ->id(fn ($get) => "para_text_" . $get('item_key')),
146
                         ])->visible(fn (Get $get):bool => $get("paragraph_type") == 2),
162
                         ])->visible(fn (Get $get):bool => $get("paragraph_type") == 2),
147
                             Group::make()->schema([
163
                             Group::make()->schema([
148
                                 Section::make("")->schema([
164
                                 Section::make("")->schema([
150
                                     ->disk("public")
166
                                     ->disk("public")
151
                                     ->directory("news/paragraph/video"),
167
                                     ->directory("news/paragraph/video"),
152
                                     // ->helperText('建議寬高限制為:2000*720px,出血寬度720px,主要圖像範圍為:1280*720px,檔案大小限制為1M以下')->maxSize('1024'),
168
                                     // ->helperText('建議寬高限制為:2000*720px,出血寬度720px,主要圖像範圍為:1280*720px,檔案大小限制為1M以下')->maxSize('1024'),
169
+                                    Translate::make()->schema(fn (string $locale) => [
170
+                                        TextInput::make('video_img_alt')->label("圖片註文")->columnSpan(1),
171
+                                    ])->locales(["zh_TW", "en"])
172
+                                    ->id(fn ($get) => "para_video_img_alt_" . $get('item_key')),
153
                                     Radio::make("video_type")->label("")->options([
173
                                     Radio::make("video_type")->label("")->options([
154
                                         1 => "網址",
174
                                         1 => "網址",
155
                                         2 => "檔案"
175
                                         2 => "檔案"
173
                     ->orderColumn('order')
193
                     ->orderColumn('order')
174
                     ->cloneable()
194
                     ->cloneable()
175
                 ]),
195
                 ]),
176
-                Section::make("額外圖片")->schema([
177
-                    Repeater::make("extra_images")->schema([
178
-                        FileUpload::make('image_url')->label("")->disk("public")
179
-                        ->directory("news/extraPhoto")
180
-                        ->maxFiles(10),
181
-                        TextInput::make('image_link')->label("外連網址")->columnSpanFull()->url(),
182
-                    ])
183
-                    ->helperText('至少需上傳4張圖片才會出現圖片輯')
184
-                    ->relationship("photos")
185
-                    ->label("")
186
-                    ->collapsible()
187
-                    ->orderColumn('order')
188
-                    ->defaultItems(0)
189
-                ])->columns(5)
190
             ]);
196
             ]);
191
     }
197
     }
192
 
198
 

+ 1
- 0
app/Filament/Resources/NewsResource/Pages/CreateNews.php Voir le fichier

17
     }
17
     }
18
     protected function handleRecordCreation(array $data): Model
18
     protected function handleRecordCreation(array $data): Model
19
     {
19
     {
20
+        $data["visible"] = 0;
20
         return static::getModel()::create($data);
21
         return static::getModel()::create($data);
21
     }
22
     }
22
 }
23
 }

+ 87
- 57
app/Http/Controllers/Api/NewsController.php Voir le fichier

24
 
24
 
25
     public function list(Request $request, $locate = 'tw')
25
     public function list(Request $request, $locate = 'tw')
26
     {
26
     {
27
-        $categoryId = $request->input("categoryId", "");
28
         $page = $request->input("page", 1);
27
         $page = $request->input("page", 1);
29
         $per_page = $request->input("per_page", 15);
28
         $per_page = $request->input("per_page", 15);
29
+        $year = $request->input("year", -1);
30
+        $month = $request->input("month", -1);
30
         $locate = $locate == "tw" ? "zh_TW" : $locate;
31
         $locate = $locate == "tw" ? "zh_TW" : $locate;
31
         $result = [];
32
         $result = [];
32
 
33
 
33
-        //年份清單
34
-        $yearList = News::select(DB::raw("DATE_FORMAT(post_date, '%Y') as years"))->distinct()->orderBy("years", "desc")->pluck("years");
35
-        $result["yearList"] = $yearList;
36
-
37
         //文章列表
34
         //文章列表
38
         $news = News::where("visible", 1);
35
         $news = News::where("visible", 1);
39
-        if($categoryId){
40
-            $news->where("news_category_id", $categoryId);
36
+        if($month > 0 || $year > 0){
37
+            $dateFilter = Carbon::now();
38
+            if($year > 0){
39
+                $dateFilter->setYear(intval($year));
40
+                if($month > 0){
41
+                    $dateFilter->setMonth(intval($month));
42
+                    $news = $news->whereBetween("post_date", [$dateFilter->copy()->startOfMonth(), $dateFilter->copy()->endOfMonth()]);
43
+                }else{
44
+                    $news = $news->whereBetween("post_date", [$dateFilter->copy()->startOfYear(), $dateFilter->copy()->endOfYear()]);
45
+                }
46
+            }
41
         }
47
         }
42
         $news = $news->orderByDesc("order")->orderByDesc("post_date");
48
         $news = $news->orderByDesc("order")->orderByDesc("post_date");
43
         $result["pagination"] = [
49
         $result["pagination"] = [
58
             $result["list"][] = [
64
             $result["list"][] = [
59
                 "id" => $item->id,
65
                 "id" => $item->id,
60
                 "categoryId" => $item->newsCategory->id,
66
                 "categoryId" => $item->newsCategory->id,
61
-                "category" => $item->newsCategory->getTranslation("name", $locate),
67
+                "category" => $item->newsCategory->getTranslation("name", $locate, false),
62
                 "postDate" => Carbon::parse($item->post_date)->format("Y.m.d"),
68
                 "postDate" => Carbon::parse($item->post_date)->format("Y.m.d"),
63
-                "title" => $item->getTranslation("title", $locate),
69
+                "title" => $item->getTranslation("title", $locate, false),
64
                 "imgPC" => $item->news_img_pc_url,
70
                 "imgPC" => $item->news_img_pc_url,
65
                 "imgMobile" => $item->news_img_mobile_url,
71
                 "imgMobile" => $item->news_img_mobile_url,
66
-                "written" => $item->getTranslation("written_by", $locate),
67
-                "description" => $item->getTranslation("description", $locate),
72
+                "written" => $item->getTranslation("written_by", $locate, false),
73
+                "description" => $item->getTranslation("description", $locate, false),
68
             ];
74
             ];
69
         }
75
         }
70
         return response()->json(["data" => $result], 200);
76
         return response()->json(["data" => $result], 200);
77
         $result = [];
83
         $result = [];
78
 
84
 
79
         //年份清單
85
         //年份清單
80
-        $yearList = News::select(DB::raw("DATE_FORMAT(post_date, '%Y') as years"))->distinct()->orderBy("years", "desc")->pluck("years");
86
+        $yearList = News::select(DB::raw("DATE_FORMAT(post_date, '%Y/%m') as years"))->distinct()->orderBy("years", "desc")->pluck("years");
81
 
87
 
82
         //文章列表
88
         //文章列表
83
-        $news = News::where("visible", 1);
84
-        if($categoryId){
85
-            $news->where("news_category_id", $categoryId);
86
-        }
87
-        $news = $news->where('on_top', 1)->first();
89
+        $news = News::where("visible", 1)->where('on_top', 1)->first();
90
+        if($news)
88
         $result["data"] = [
91
         $result["data"] = [
89
             "meta" => [
92
             "meta" => [
90
-                "meta_title" => $news->getTranslation("meta_title", $locate),
91
-                "meta_keyword" => $news->getTranslation("meta_keyword", $locate),
92
-                "meta_description" => $news->getTranslation("meta_description", $locate),
93
+                "meta_title" => $news->getTranslation("meta_title", $locate, false),
94
+                "meta_keyword" => $news->getTranslation("meta_keyword", $locate, false),
95
+                "meta_description" => $news->getTranslation("meta_description", $locate, false),
93
                 "imgPC" => $news->news_meta_img,
96
                 "imgPC" => $news->news_meta_img,
94
             ],
97
             ],
95
             "yearList" =>[
98
             "yearList" =>[
98
             "top" => [
101
             "top" => [
99
                 "id" => $news->id,
102
                 "id" => $news->id,
100
                 "categoryId" => $news->newsCategory->id,
103
                 "categoryId" => $news->newsCategory->id,
101
-                "category" => $news->newsCategory->getTranslation("name", $locate),
104
+                "category" => $news->newsCategory->getTranslation("name", $locate, false),
102
                 "postDate" => Carbon::parse($news->post_date)->format("Y/m/d"),
105
                 "postDate" => Carbon::parse($news->post_date)->format("Y/m/d"),
103
-                "title" => $news->getTranslation("title", $locate),
106
+                "title" => $news->getTranslation("title", $locate, false),
104
                 "imgPC" => $news->news_img_pc_url,
107
                 "imgPC" => $news->news_img_pc_url,
105
                 "imgMobile" => $news->news_img_mobile_url,
108
                 "imgMobile" => $news->news_img_mobile_url,
106
-                "written" => $news->getTranslation("written_by", $locate),
107
-                "description" => $news->getTranslation("description", $locate),
109
+                "written" => $news->getTranslation("written_by", $locate, false),
110
+                "description" => $news->getTranslation("description", $locate, false),
108
             ]
111
             ]
109
         ];
112
         ];
110
         return response()->json($result, 200);
113
         return response()->json($result, 200);
149
         ->orderBy('post_date', 'desc')
152
         ->orderBy('post_date', 'desc')
150
         ->orderBy('id', 'desc')
153
         ->orderBy('id', 'desc')
151
         ->first();
154
         ->first();
155
+
152
         if($previous)$otherNewsList["previous"] = [
156
         if($previous)$otherNewsList["previous"] = [
153
             "id" => $previous->id,
157
             "id" => $previous->id,
154
             "categoryId" => $previous->newsCategory->id,
158
             "categoryId" => $previous->newsCategory->id,
155
-            "category" => $previous->newsCategory->getTranslation("name", $locate),
159
+            "category" => $previous->newsCategory->getTranslation("name", $locate, false),
156
             "postDate" => Carbon::parse($previous->post_date)->format("Y/m/d"),
160
             "postDate" => Carbon::parse($previous->post_date)->format("Y/m/d"),
157
-            "title" => $previous->getTranslation("title", $locate),
161
+            "title" => $previous->getTranslation("title", $locate, false),
158
             "imgPC" => $previous->news_img_pc_url,
162
             "imgPC" => $previous->news_img_pc_url,
159
             "imgMobile" => $previous->news_img_mobile_url,
163
             "imgMobile" => $previous->news_img_mobile_url,
160
-            "written" => $previous->getTranslation("written_by", $locate),
161
-            "description" => $previous->getTranslation("description", $locate),
164
+            "written" => $previous->getTranslation("written_by", $locate, false),
165
+            "description" => $previous->getTranslation("description", $locate, false),
162
         ];
166
         ];
163
         if($next)$otherNewsList["next"] = [
167
         if($next)$otherNewsList["next"] = [
164
             "id" => $next->id,
168
             "id" => $next->id,
165
             "categoryId" => $next->newsCategory->id,
169
             "categoryId" => $next->newsCategory->id,
166
-            "category" => $next->newsCategory->getTranslation("name", $locate),
170
+            "category" => $next->newsCategory->getTranslation("name", $locate, false),
167
             "postDate" => Carbon::parse($previous->post_date)->format("Y/m/d"),
171
             "postDate" => Carbon::parse($previous->post_date)->format("Y/m/d"),
168
-            "title" => $next->getTranslation("title", $locate),
172
+            "title" => $next->getTranslation("title", $locate, false),
169
             "imgPC" => $next->news_img_pc_url,
173
             "imgPC" => $next->news_img_pc_url,
170
             "imgMobile" => $next->news_img_mobile_url,
174
             "imgMobile" => $next->news_img_mobile_url,
171
-            "written" => $next->getTranslation("written_by", $locate),
172
-            "description" => $next->getTranslation("description", $locate),
175
+            "written" => $next->getTranslation("written_by", $locate, false),
176
+            "description" => $next->getTranslation("description", $locate, false),
173
         ];
177
         ];
174
 
178
 
175
 
179
 
180
+        // {
181
+        //     "type": "text",
182
+        //     "content": ""
183
+        // },
184
+        // {
185
+        //     "type": "image",
186
+        //     "images":[{"img_url":"", "alt":""}, {"img_url":"", "alt":""}]
187
+        // },
188
+        // {
189
+        //     "type": "video",
190
+        //     "is_yt":false,
191
+        //     "video_img_url":"",
192
+        //     "video_url":"",
193
+        //     "content": ""
194
+        // }
176
         $paragraphs = [];
195
         $paragraphs = [];
177
         foreach($news->paragraphs as $paragraph){
196
         foreach($news->paragraphs as $paragraph){
178
-            $paragraphs[] = [
179
-                "type" => $paragraph->contentType(),
180
-                "imgUrl" => $paragraph->paragraph_img,
181
-                "imgOutLink" => $paragraph->image_link,
182
-                "alt" => $paragraph->getTranslation("image_alt", $locate),
183
-                "content" => nl2br($paragraph->getTranslation("text_content", $locate)),
184
-                "videoImg" => $paragraph->paragraph_video_img,
185
-                "videoType" => $paragraph->paragraph_video_type,
186
-                "link" => $paragraph->paragraph_video_url,
187
-            ];
188
-        }
189
-        $extraPhotos = [];
190
-        foreach($news->photos as $photo){
191
-            $extraPhotos[] = [
192
-                "imgUrl" => $photo->news_photo_img,
193
-                "imgOutLink" => $photo->image_link,
194
-            ];
197
+            $content = [];
198
+            switch ($paragraph->contentType()){
199
+                case "text":
200
+                    $paragraphs[] = [
201
+                        "type" => $paragraph->contentType(),
202
+                        "content" => nl2br($paragraph->getTranslation("text_content", $locate, false)),
203
+                    ];
204
+                    break;
205
+                case "image":
206
+                    $photos = $paragraph->photos;
207
+                    $images = [];
208
+                    foreach($photos as $photo){
209
+                        $images[] = ["img_url" => $photo->img_url, "alt" => $photo->getTranslation("image_alt", $locate, false)];
210
+                    }
211
+                    $paragraphs[] = [
212
+                        "type" => $paragraph->contentType(),
213
+                        "images" => $images,
214
+                    ];
215
+                    break;
216
+                case "video":
217
+                    $paragraphs[] = [
218
+                        "type" => $paragraph->contentType(),
219
+                        "video_img_url" => $paragraph->paragraph_video_img,
220
+                        "is_yt" => $paragraph->video_type == 1 ? true : false,
221
+                        "content" => $paragraph->getTranslation("video_img_alt", $locate, false),
222
+                        "video_url" => $paragraph->paragraph_video_url,
223
+                    ];
224
+                    break;
225
+            }
195
         }
226
         }
196
         $result = [
227
         $result = [
197
             "categoryId" => $news->newsCategory->id,
228
             "categoryId" => $news->newsCategory->id,
198
-            "category" => $news->newsCategory->getTranslation("name", $locate),
229
+            "category" => $news->newsCategory->getTranslation("name", $locate, false),
199
             "postDate" => Carbon::parse($news->post_date)->format("Y/m/d"),
230
             "postDate" => Carbon::parse($news->post_date)->format("Y/m/d"),
200
-            "title" => $news->getTranslation("title", $locate),
201
-            "description" => $news->getTranslation("description", $locate),
202
-            "written" => $news->getTranslation("written_by", $locate),
231
+            "title" => $news->getTranslation("title", $locate, false),
232
+            "description" => $news->getTranslation("description", $locate, false),
233
+            "written" => $news->getTranslation("written_by", $locate, false),
203
             "imgPC" => $news->news_img_pc_url,
234
             "imgPC" => $news->news_img_pc_url,
204
             "imgMobile" => $news->news_img_mobile_url,
235
             "imgMobile" => $news->news_img_mobile_url,
205
-            "metaTitle" => $news->getTranslation("meta_title", $locate),
206
-            "metaKeyword" => $news->getTranslation("meta_keyword", $locate),
207
-            "metaDesc" => $news->getTranslation("meta_description", $locate),
236
+            "metaTitle" => $news->getTranslation("meta_title", $locate, false),
237
+            "metaKeyword" => $news->getTranslation("meta_keyword", $locate, false),
238
+            "metaDesc" => $news->getTranslation("meta_description", $locate, false),
208
             "metaImg" => $news->meta_img,
239
             "metaImg" => $news->meta_img,
209
             "paragraphs" => $paragraphs,
240
             "paragraphs" => $paragraphs,
210
-            "photos" => $extraPhotos,
211
             "otherNews" => $otherNewsList
241
             "otherNews" => $otherNewsList
212
         ];
242
         ];
213
         return response()->json(["data" => $result], 200);
243
         return response()->json(["data" => $result], 200);

+ 0
- 4
app/Models/News.php Voir le fichier

32
     public function paragraphs(){
32
     public function paragraphs(){
33
         return $this->hasMany(NewsParagraph::class)->orderBy('order');
33
         return $this->hasMany(NewsParagraph::class)->orderBy('order');
34
     }
34
     }
35
-
36
-    public function photos(){
37
-        return $this->hasMany(NewsPhoto::class)->orderBy("order");
38
-    }
39
     protected function newsImgPcUrl(): Attribute
35
     protected function newsImgPcUrl(): Attribute
40
     {
36
     {
41
         return Attribute::make(
37
         return Attribute::make(

+ 6
- 7
app/Models/NewsParagraph.php Voir le fichier

19
 
19
 
20
     protected $guarded = ['id'];
20
     protected $guarded = ['id'];
21
     public $timestamps = false;
21
     public $timestamps = false;
22
-    protected $appends = ['paragraph_img', 'paragraph_video_img', 'paragraph_video_type', 'paragraph_video_url'];
23
-    public $translatable = ['text_content', 'image_alt'];
22
+    protected $appends = ['paragraph_video_img', 'paragraph_video_type', 'paragraph_video_url'];
23
+    public $translatable = ['text_content', 'video_img_alt'];
24
 
24
 
25
     public function news(){
25
     public function news(){
26
         return $this->belongsTo(News::class);
26
         return $this->belongsTo(News::class);
39
                 return "";
39
                 return "";
40
         }
40
         }
41
     }
41
     }
42
-    protected function paragraphImg(): Attribute
43
-    {
44
-        return Attribute::make(
45
-            get: fn ($value) => is_null($this->image_url) ? null :Storage::disk('public')->url($this->image_url),
46
-        );
42
+
43
+    public function photos(){
44
+        return $this->hasMany(NewsPhoto::class)->orderBy("order");
47
     }
45
     }
46
+
48
     protected function paragraphVideoType(): Attribute
47
     protected function paragraphVideoType(): Attribute
49
     {
48
     {
50
         return Attribute::make(
49
         return Attribute::make(

+ 2
- 2
app/Models/NewsPhoto.php Voir le fichier

19
     protected $appends = ['news_photo_img'];
19
     protected $appends = ['news_photo_img'];
20
     public $translatable = ['image_alt'];
20
     public $translatable = ['image_alt'];
21
 
21
 
22
-    public function news(){
23
-        return $this->belongsTo(News::class);
22
+    public function paragraph(){
23
+        return $this->belongsTo(NewsParagraph::class);
24
     }
24
     }
25
     protected function newsPhotoImg(): Attribute
25
     protected function newsPhotoImg(): Attribute
26
     {
26
     {

+ 160
- 0
config/livewire.php Voir le fichier

1
+<?php
2
+
3
+return [
4
+
5
+    /*
6
+    |---------------------------------------------------------------------------
7
+    | Class Namespace
8
+    |---------------------------------------------------------------------------
9
+    |
10
+    | This value sets the root class namespace for Livewire component classes in
11
+    | your application. This value will change where component auto-discovery
12
+    | finds components. It's also referenced by the file creation commands.
13
+    |
14
+    */
15
+
16
+    'class_namespace' => 'App\\Livewire',
17
+
18
+    /*
19
+    |---------------------------------------------------------------------------
20
+    | View Path
21
+    |---------------------------------------------------------------------------
22
+    |
23
+    | This value is used to specify where Livewire component Blade templates are
24
+    | stored when running file creation commands like `artisan make:livewire`.
25
+    | It is also used if you choose to omit a component's render() method.
26
+    |
27
+    */
28
+
29
+    'view_path' => resource_path('views/livewire'),
30
+
31
+    /*
32
+    |---------------------------------------------------------------------------
33
+    | Layout
34
+    |---------------------------------------------------------------------------
35
+    | The view that will be used as the layout when rendering a single component
36
+    | as an entire page via `Route::get('/post/create', CreatePost::class);`.
37
+    | In this case, the view returned by CreatePost will render into $slot.
38
+    |
39
+    */
40
+
41
+    'layout' => 'components.layouts.app',
42
+
43
+    /*
44
+    |---------------------------------------------------------------------------
45
+    | Lazy Loading Placeholder
46
+    |---------------------------------------------------------------------------
47
+    | Livewire allows you to lazy load components that would otherwise slow down
48
+    | the initial page load. Every component can have a custom placeholder or
49
+    | you can define the default placeholder view for all components below.
50
+    |
51
+    */
52
+
53
+    'lazy_placeholder' => null,
54
+
55
+    /*
56
+    |---------------------------------------------------------------------------
57
+    | Temporary File Uploads
58
+    |---------------------------------------------------------------------------
59
+    |
60
+    | Livewire handles file uploads by storing uploads in a temporary directory
61
+    | before the file is stored permanently. All file uploads are directed to
62
+    | a global endpoint for temporary storage. You may configure this below:
63
+    |
64
+    */
65
+
66
+    'temporary_file_upload' => [
67
+        'disk' => null,        // Example: 'local', 's3'              | Default: 'default'
68
+        'rules' => 'max:512000',       // Example: ['file', 'mimes:png,jpg']  | Default: ['required', 'file', 'max:12288'] (12MB)
69
+        'directory' => null,   // Example: 'tmp'                      | Default: 'livewire-tmp'
70
+        'middleware' => null,  // Example: 'throttle:5,1'             | Default: 'throttle:60,1'
71
+        'preview_mimes' => [   // Supported file types for temporary pre-signed file URLs...
72
+            'png', 'gif', 'bmp', 'svg', 'wav', 'mp4',
73
+            'mov', 'avi', 'wmv', 'mp3', 'm4a',
74
+            'jpg', 'jpeg', 'mpga', 'webp', 'wma',
75
+        ],
76
+        'max_upload_time' => 5, // Max duration (in minutes) before an upload is invalidated...
77
+        'cleanup' => true, // Should cleanup temporary uploads older than 24 hrs...
78
+    ],
79
+
80
+    /*
81
+    |---------------------------------------------------------------------------
82
+    | Render On Redirect
83
+    |---------------------------------------------------------------------------
84
+    |
85
+    | This value determines if Livewire will run a component's `render()` method
86
+    | after a redirect has been triggered using something like `redirect(...)`
87
+    | Setting this to true will render the view once more before redirecting
88
+    |
89
+    */
90
+
91
+    'render_on_redirect' => false,
92
+
93
+    /*
94
+    |---------------------------------------------------------------------------
95
+    | Eloquent Model Binding
96
+    |---------------------------------------------------------------------------
97
+    |
98
+    | Previous versions of Livewire supported binding directly to eloquent model
99
+    | properties using wire:model by default. However, this behavior has been
100
+    | deemed too "magical" and has therefore been put under a feature flag.
101
+    |
102
+    */
103
+
104
+    'legacy_model_binding' => false,
105
+
106
+    /*
107
+    |---------------------------------------------------------------------------
108
+    | Auto-inject Frontend Assets
109
+    |---------------------------------------------------------------------------
110
+    |
111
+    | By default, Livewire automatically injects its JavaScript and CSS into the
112
+    | <head> and <body> of pages containing Livewire components. By disabling
113
+    | this behavior, you need to use @livewireStyles and @livewireScripts.
114
+    |
115
+    */
116
+
117
+    'inject_assets' => true,
118
+
119
+    /*
120
+    |---------------------------------------------------------------------------
121
+    | Navigate (SPA mode)
122
+    |---------------------------------------------------------------------------
123
+    |
124
+    | By adding `wire:navigate` to links in your Livewire application, Livewire
125
+    | will prevent the default link handling and instead request those pages
126
+    | via AJAX, creating an SPA-like effect. Configure this behavior here.
127
+    |
128
+    */
129
+
130
+    'navigate' => [
131
+        'show_progress_bar' => true,
132
+        'progress_bar_color' => '#2299dd',
133
+    ],
134
+
135
+    /*
136
+    |---------------------------------------------------------------------------
137
+    | HTML Morph Markers
138
+    |---------------------------------------------------------------------------
139
+    |
140
+    | Livewire intelligently "morphs" existing HTML into the newly rendered HTML
141
+    | after each update. To make this process more reliable, Livewire injects
142
+    | "markers" into the rendered Blade surrounding @if, @class & @foreach.
143
+    |
144
+    */
145
+
146
+    'inject_morph_markers' => true,
147
+
148
+    /*
149
+    |---------------------------------------------------------------------------
150
+    | Pagination Theme
151
+    |---------------------------------------------------------------------------
152
+    |
153
+    | When enabling Livewire's pagination feature by using the `WithPagination`
154
+    | trait, Livewire will use Tailwind templates to render pagination views
155
+    | on the page. If you want Bootstrap CSS, you can specify: "bootstrap"
156
+    |
157
+    */
158
+
159
+    'pagination_theme' => 'tailwind',
160
+];

+ 2
- 3
database/migrations/2025_05_20_043735_create_news_paragraphs_table.php Voir le fichier

17
             $table->id();
17
             $table->id();
18
             $table->unsignedBigInteger('news_id')->index();
18
             $table->unsignedBigInteger('news_id')->index();
19
             $table->foreign('news_id')->references('id')->on('news')->comment("關聯文章");
19
             $table->foreign('news_id')->references('id')->on('news')->comment("關聯文章");
20
-            $table->unsignedTinyInteger('paragraph_type')->comment('段落類型 1.image 2.text');
21
-            $table->string('image_url')->nullable()->comment("圖片網址");
22
-            $table->json('image_alt')->nullable()->comment("圖片註釋");
20
+            $table->unsignedTinyInteger('paragraph_type')->comment('段落類型 1.images 2.text 3.video');
23
             $table->json('text_content')->nullable()->comment("文字段落");
21
             $table->json('text_content')->nullable()->comment("文字段落");
24
             $table->integer("video_type")->nullable();
22
             $table->integer("video_type")->nullable();
25
             $table->string("video_img")->nullable();
23
             $table->string("video_img")->nullable();
24
+            $table->json('video_img_alt')->nullable()->comment("圖片註釋");
26
             $table->string("link")->nullable();
25
             $table->string("link")->nullable();
27
             $table->string("video_url")->nullable();
26
             $table->string("video_url")->nullable();
28
             $table->unsignedInteger('order')->default(0)->comment("排序");
27
             $table->unsignedInteger('order')->default(0)->comment("排序");

+ 2
- 2
database/migrations/2025_05_20_043736_create_news_photos_table.php Voir le fichier

15
 
15
 
16
         Schema::create('news_photos', function (Blueprint $table) {
16
         Schema::create('news_photos', function (Blueprint $table) {
17
             $table->id();
17
             $table->id();
18
-            $table->unsignedBigInteger('news_id')->index();
19
-            $table->foreign('news_id')->references('id')->on('news')->comment("關聯文章");
18
+            $table->unsignedBigInteger('news_paragraph_id')->index();
19
+            $table->foreign('news_paragraph_id')->references('id')->on('news_paragraphs')->comment("關聯文章段落");
20
             $table->string('image_url')->nullable()->comment("圖片網址");
20
             $table->string('image_url')->nullable()->comment("圖片網址");
21
             $table->json('image_alt')->nullable()->comment("圖片註釋");
21
             $table->json('image_alt')->nullable()->comment("圖片註釋");
22
             $table->unsignedInteger('order')->default(0)->comment("排序");
22
             $table->unsignedInteger('order')->default(0)->comment("排序");