From 59a68b372b660dd2192848249ba8469d50d58bb9 Mon Sep 17 00:00:00 2001 From: tone <3341154833@qq.com> Date: Fri, 16 May 2025 21:58:33 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E6=B7=BB=E5=8A=A0=E5=8D=9A?= =?UTF-8?q?=E5=AE=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tone-page-server/src/admin/admin.module.ts | 2 + .../web/admin-web-blog.controller.ts | 41 +++++++- .../web/admin-web-resource.controller.ts | 6 +- .../admin/dto/admin-web/create-blog.dto.ts | 12 +++ tone-page-server/src/blog/blog.module.ts | 3 +- tone-page-server/src/blog/blog.service.ts | 21 +++- .../src/blog/entity/Blog.entity.ts | 3 - .../web/blog/components/AddBlog.tsx | 99 +++++++++++++++++++ .../web/blog/components/BlogTable.tsx | 61 +++++++----- .../app/console/(with-menu)/web/blog/page.tsx | 16 ++- .../hooks/admin/web/blog/use-blog-list.ts | 24 +++++ tone-page-web/lib/api/admin/web/blog/list.ts | 3 +- tone-page-web/lib/types/blog.ts | 8 +- 13 files changed, 260 insertions(+), 39 deletions(-) create mode 100644 tone-page-server/src/admin/dto/admin-web/create-blog.dto.ts create mode 100644 tone-page-web/app/console/(with-menu)/web/blog/components/AddBlog.tsx create mode 100644 tone-page-web/hooks/admin/web/blog/use-blog-list.ts diff --git a/tone-page-server/src/admin/admin.module.ts b/tone-page-server/src/admin/admin.module.ts index 1cbda7d..a013564 100644 --- a/tone-page-server/src/admin/admin.module.ts +++ b/tone-page-server/src/admin/admin.module.ts @@ -13,6 +13,7 @@ import { AdminUserRoleController } from './controller/admin-user-role.controller import { AdminWebResourceController } from './controller/web/admin-web-resource.controller'; import { AdminWebBlogController } from './controller/web/admin-web-blog.controller'; import { ResourceModule } from 'src/resource/resource.module'; +import { BlogModule } from 'src/blog/blog.module'; @Module({ imports: [ @@ -22,6 +23,7 @@ import { ResourceModule } from 'src/resource/resource.module'; UserModule, RoleModule, ResourceModule, + BlogModule, ], controllers: [ AdminController, diff --git a/tone-page-server/src/admin/controller/web/admin-web-blog.controller.ts b/tone-page-server/src/admin/controller/web/admin-web-blog.controller.ts index a2cacfe..b70203d 100644 --- a/tone-page-server/src/admin/controller/web/admin-web-blog.controller.ts +++ b/tone-page-server/src/admin/controller/web/admin-web-blog.controller.ts @@ -1,6 +1,45 @@ -import { Controller } from "@nestjs/common"; +import { Body, Controller, Delete, Get, Param, ParseUUIDPipe, Post, Put } from "@nestjs/common"; +import { CreateBlogDto } from "src/admin/dto/admin-web/create-blog.dto"; +import { BlogService } from "src/blog/blog.service"; @Controller('/admin/web/blog') export class AdminWebBlogController { + constructor( + private readonly adminWebBlogService: BlogService, + ) { } + + @Get() + async list() { + return this.adminWebBlogService.list(); + } + + @Post() + async create( + @Body() dto: CreateBlogDto, + ) { + return this.adminWebBlogService.create(dto); + } + + @Put(':id') + async update( + @Param('id', new ParseUUIDPipe({ version: '4' })) id: string, + @Body() dto: CreateBlogDto, + ) { + return this.adminWebBlogService.update(id, dto); + } + + @Get(':id') + async get( + @Param('id', new ParseUUIDPipe({ version: '4' })) id: string, + ) { + return this.adminWebBlogService.findById(id); + } + + @Delete(':id') + async remove( + @Param('id', new ParseUUIDPipe({ version: '4' })) id: string, + ) { + return this.adminWebBlogService.remove(id); + } } \ No newline at end of file diff --git a/tone-page-server/src/admin/controller/web/admin-web-resource.controller.ts b/tone-page-server/src/admin/controller/web/admin-web-resource.controller.ts index 8ae92ca..9b13278 100644 --- a/tone-page-server/src/admin/controller/web/admin-web-resource.controller.ts +++ b/tone-page-server/src/admin/controller/web/admin-web-resource.controller.ts @@ -26,14 +26,16 @@ export class AdminWebResourceController { @Put(':id') async update( - @Param('id') id: string, + @Param('id', new ParseUUIDPipe({ version: '4' })) id: string, @Body() data: CreateResourceDto ) { return this.resourceService.update(id, data); } @Delete(':id') - async delete(@Param('id') id: string) { + async delete( + @Param('id', new ParseUUIDPipe({ version: '4' })) id: string, + ) { return this.resourceService.delete(id); } } \ No newline at end of file diff --git a/tone-page-server/src/admin/dto/admin-web/create-blog.dto.ts b/tone-page-server/src/admin/dto/admin-web/create-blog.dto.ts new file mode 100644 index 0000000..07de657 --- /dev/null +++ b/tone-page-server/src/admin/dto/admin-web/create-blog.dto.ts @@ -0,0 +1,12 @@ +import { IsString } from "class-validator"; + +export class CreateBlogDto { + @IsString() + title: string; + + @IsString() + description: string; + + @IsString() + contentUrl: string; +} \ No newline at end of file diff --git a/tone-page-server/src/blog/blog.module.ts b/tone-page-server/src/blog/blog.module.ts index 7ba652f..a186635 100644 --- a/tone-page-server/src/blog/blog.module.ts +++ b/tone-page-server/src/blog/blog.module.ts @@ -7,6 +7,7 @@ import { Blog } from './entity/Blog.entity'; @Module({ imports: [TypeOrmModule.forFeature([Blog])], controllers: [BlogController], - providers: [BlogService] + providers: [BlogService], + exports: [BlogService], }) export class BlogModule { } diff --git a/tone-page-server/src/blog/blog.service.ts b/tone-page-server/src/blog/blog.service.ts index 9aebe23..66f77e4 100644 --- a/tone-page-server/src/blog/blog.service.ts +++ b/tone-page-server/src/blog/blog.service.ts @@ -15,9 +15,28 @@ export class BlogService { return this.blogRepository.find({ where: { deletedAt: null }, order: { - publishAt: 'DESC', + createdAt: 'DESC', } }) } + async create(blog: Partial) { + const newBlog = this.blogRepository.create(blog); + return this.blogRepository.save(newBlog); + } + + async update(id: string, blog: Partial) { + await this.blogRepository.update(id, blog); + return this.blogRepository.findOneBy({ id }); + } + + async remove(id: string) { + const blog = await this.blogRepository.findOneBy({ id }); + if (!blog) return null; + return this.blogRepository.softRemove(blog); + } + + async findById(id: string) { + return this.blogRepository.findOneBy({ id }); + } } diff --git a/tone-page-server/src/blog/entity/Blog.entity.ts b/tone-page-server/src/blog/entity/Blog.entity.ts index d190bb8..d3049aa 100644 --- a/tone-page-server/src/blog/entity/Blog.entity.ts +++ b/tone-page-server/src/blog/entity/Blog.entity.ts @@ -14,9 +14,6 @@ export class Blog { @Column() contentUrl: string; - @Column({ precision: 3 }) - publishAt: Date; - @CreateDateColumn({ precision: 3 }) createdAt: Date; diff --git a/tone-page-web/app/console/(with-menu)/web/blog/components/AddBlog.tsx b/tone-page-web/app/console/(with-menu)/web/blog/components/AddBlog.tsx new file mode 100644 index 0000000..b00daad --- /dev/null +++ b/tone-page-web/app/console/(with-menu)/web/blog/components/AddBlog.tsx @@ -0,0 +1,99 @@ +'use client' + +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog" +import { Input } from "@/components/ui/input"; +import { Label } from "@/components/ui/label"; +import { AdminApi } from "@/lib/api"; +import { useState } from "react"; +import { toast } from "sonner"; + +interface AddBlogProps { + children: React.ReactNode; + onRefresh: () => void; +} + +export default function AddBlog({ children, onRefresh }: AddBlogProps) { + const [open, setOpen] = useState(false); + const [blog, setBlog] = useState({ + title: "", + description: "", + contentUrl: "", + }); + + const handleSubmit = async () => { + try { + const res = await AdminApi.web.blog.create({ + ...blog, + }); + if (res) { + setOpen(false); + onRefresh(); + toast.success("添加成功"); + } else { + throw new Error(); + } + } catch (error) { + toast.error((error as Error).message || "添加失败"); + } + } + + return ( + + + {children} + + + + 添加博客 + +
+
+ + setBlog({ ...blog, title: e.target.value })} + /> +
+
+ + setBlog({ ...blog, description: e.target.value })} + /> +
+
+ + setBlog({ ...blog, contentUrl: e.target.value })} + /> +
+
+ + + + +
+
+ ) +} \ No newline at end of file diff --git a/tone-page-web/app/console/(with-menu)/web/blog/components/BlogTable.tsx b/tone-page-web/app/console/(with-menu)/web/blog/components/BlogTable.tsx index 3bbfffd..7e58f66 100644 --- a/tone-page-web/app/console/(with-menu)/web/blog/components/BlogTable.tsx +++ b/tone-page-web/app/console/(with-menu)/web/blog/components/BlogTable.tsx @@ -8,41 +8,58 @@ import { TableHeader, TableRow, } from "@/components/ui/table" +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip" +import { Blog } from "@/lib/types/blog" interface BlogTableProps { - blogs: { - - }[] + blogs: Blog[], + error?: string, + onRefresh?: () => void, } -export default function BlogTable({ blogs }: BlogTableProps) { +export default function BlogTable({ blogs, error, onRefresh }: BlogTableProps) { return ( - A list of your recent invoices. + { + error && ( + {error} + ) + } - Invoice - Status - Method - Amount + Id + 标题 + 描述 + 文章URL + 操作 - {/* {invoices.map((invoice) => ( - - {invoice.invoice} - {invoice.paymentStatus} - {invoice.paymentMethod} - {invoice.totalAmount} + {blogs.map((blog) => ( + + + + + +
{blog.id}
+
+ +

{blog.id}

+
+
+
+
+ {blog.title} + {blog.description} + {blog.contentUrl} + + {/* onRefresh()}> + + */} +
- ))} */} + ))}
- - - Total - $2,500.00 - -
) } \ No newline at end of file diff --git a/tone-page-web/app/console/(with-menu)/web/blog/page.tsx b/tone-page-web/app/console/(with-menu)/web/blog/page.tsx index 63835f4..2fc2258 100644 --- a/tone-page-web/app/console/(with-menu)/web/blog/page.tsx +++ b/tone-page-web/app/console/(with-menu)/web/blog/page.tsx @@ -1,7 +1,21 @@ +"use client" + +import { useBlogList } from "@/hooks/admin/web/blog/use-blog-list" +import BlogTable from "./components/BlogTable" +import AddBlog from "./components/AddBlog"; +import { Button } from "@/components/ui/button"; + export default function Page() { + const { blogs, error, isLoading, refresh } = useBlogList(); + return ( <> - +
+ + + +
+ ) } \ No newline at end of file diff --git a/tone-page-web/hooks/admin/web/blog/use-blog-list.ts b/tone-page-web/hooks/admin/web/blog/use-blog-list.ts new file mode 100644 index 0000000..a794775 --- /dev/null +++ b/tone-page-web/hooks/admin/web/blog/use-blog-list.ts @@ -0,0 +1,24 @@ +"use client" + +import { AdminApi } from "@/lib/api"; +import { useCallback } from "react"; +import useSWR from "swr"; + +export function useBlogList() { + const { data, error, isLoading, mutate } = useSWR( + ['/admin/web/blog'], + () => AdminApi.web.blog.list() + ) + + const refresh = useCallback(() => { + return mutate() + }, [mutate]) + + return { + blogs: data, + error, + isLoading, + mutate, + refresh, + } +} \ No newline at end of file diff --git a/tone-page-web/lib/api/admin/web/blog/list.ts b/tone-page-web/lib/api/admin/web/blog/list.ts index e108439..b154738 100644 --- a/tone-page-web/lib/api/admin/web/blog/list.ts +++ b/tone-page-web/lib/api/admin/web/blog/list.ts @@ -1,5 +1,6 @@ import fetcher from "@/lib/api/fetcher"; +import { Blog } from "@/lib/types/blog"; export async function list() { - return fetcher('/api/admin/web/blog') + return fetcher('/api/admin/web/blog') } \ No newline at end of file diff --git a/tone-page-web/lib/types/blog.ts b/tone-page-web/lib/types/blog.ts index 0008095..2b86acf 100644 --- a/tone-page-web/lib/types/blog.ts +++ b/tone-page-web/lib/types/blog.ts @@ -1,12 +1,6 @@ -export type BlogPermission = - 'public' | - 'password' | - 'listed'; - export interface Blog { id: string; title: string; description: string; - publish_at: string; - permissions: BlogPermission[]; + contentUrl: string; } \ No newline at end of file