ok(Article::query()->latest('id')->limit(100)->get()); } public function storeArticle(Request $request) { $article = Article::query()->create($this->articleData($request)); $this->audit($request->user(), 'article.create', $article, '新建文章 '.$article->title); return $this->ok($article); } public function updateArticle(Request $request, Article $article) { $data = $this->articleData($request, $article->id); if ($data['status'] === 'published' && ! $article->published_at) { $data['published_at'] = now(); } $article->update($data); $this->audit($request->user(), 'article.update', $article, '更新文章 '.$article->title); return $this->ok($article); } public function destroyArticle(Request $request, Article $article) { $article->delete(); $this->audit($request->user(), 'article.delete', $article, '删除文章 '.$article->title); return $this->ok(null, '已删除'); } public function banners() { return $this->ok(Banner::query()->orderByDesc('sort')->get()); } public function storeBanner(Request $request) { $banner = Banner::query()->create($this->bannerData($request)); $this->audit($request->user(), 'banner.create', $banner, '新建轮播 '.$banner->title); return $this->ok($banner); } public function updateBanner(Request $request, Banner $banner) { $banner->update($this->bannerData($request)); $this->audit($request->user(), 'banner.update', $banner, '更新轮播 '.$banner->title); return $this->ok($banner); } public function destroyBanner(Request $request, Banner $banner) { $banner->delete(); $this->audit($request->user(), 'banner.delete', $banner, '删除轮播 '.$banner->title); return $this->ok(null, '已删除'); } public function navigations() { return $this->ok(Navigation::query()->orderBy('group_name')->orderByDesc('sort')->get()); } public function storeNavigation(Request $request) { $item = Navigation::query()->create($this->navData($request)); $this->audit($request->user(), 'nav.create', $item, '新建导航 '.$item->title); return $this->ok($item); } public function updateNavigation(Request $request, Navigation $navigation) { $navigation->update($this->navData($request)); $this->audit($request->user(), 'nav.update', $navigation, '更新导航 '.$navigation->title); return $this->ok($navigation); } public function destroyNavigation(Request $request, Navigation $navigation) { $navigation->delete(); $this->audit($request->user(), 'nav.delete', $navigation, '删除导航 '.$navigation->title); return $this->ok(null, '已删除'); } public function agreements() { return $this->ok(Agreement::query()->orderBy('type')->get()); } public function updateAgreement(Request $request, Agreement $agreement) { $data = $request->validate([ 'title' => ['required', 'string', 'max:120'], 'body' => ['required', 'string'], ]); $data['body'] = HtmlSanitizer::clean($data['body']); $agreement->update($data); $this->audit($request->user(), 'agreement.update', $agreement, '更新协议 '.$agreement->title); return $this->ok($agreement); } private function articleData(Request $request, ?int $id = null): array { $data = $request->validate([ 'type' => ['required', 'in:help,announcement,page'], 'title' => ['required', 'string', 'max:160'], 'slug' => ['required', 'regex:/^[a-z0-9]+(?:-[a-z0-9]+)*$/', Rule::unique('articles', 'slug')->ignore($id)], 'summary' => ['nullable', 'string', 'max:255'], 'body' => ['required', 'string'], 'status' => ['required', 'in:draft,published'], ]); $data['body'] = HtmlSanitizer::clean($data['body']); if ($data['status'] === 'published') { $data['published_at'] = now(); } return $data; } private function bannerData(Request $request): array { return $request->validate([ 'title' => ['required', 'string', 'max:120'], 'image' => ['nullable', 'string', 'max:500'], 'link' => ['nullable', 'string', 'max:500'], 'sort' => ['nullable', 'integer'], 'starts_at' => ['nullable', 'date'], 'ends_at' => ['nullable', 'date'], 'status' => ['required', 'in:published,hidden'], ]); } private function navData(Request $request): array { return $request->validate([ 'group_name' => ['required', 'in:header,footer'], 'title' => ['required', 'string', 'max:80'], 'link' => ['required', 'string', 'max:500'], 'sort' => ['nullable', 'integer'], 'status' => ['required', 'in:published,hidden'], ]); } }