diff --git a/vblog/apps/blog/api/api.go b/vblog/apps/blog/api/api.go index 30b1011..1637902 100644 --- a/vblog/apps/blog/api/api.go +++ b/vblog/apps/blog/api/api.go @@ -55,6 +55,7 @@ func (h *BlogApiHandler) Init() error { r.POST("", h.CreateBlog) r.PUT(":id", h.UpdateBlog) r.DELETE(":id", h.DeleteBlog) + r.POST(":id/publish", h.PublishBlog) return nil } @@ -96,6 +97,27 @@ func (h *BlogApiHandler) QueryBlog(ctx *gin.Context) { response.Success(ctx, ins) } +func (h *BlogApiHandler) PublishBlog(ctx *gin.Context) { + idInt, err := strconv.ParseInt(ctx.Param("id"), 10, 64) + if err != nil { + response.Failed(ctx, err) + return + } + + req := blog.NewPublishBlogRequest(uint(idInt)) + if err := ctx.BindJSON(req); err != nil { + response.Failed(ctx, err) + return + } + + ins, err := h.blog.PublishBlog(ctx.Request.Context(), req) + if err != nil { + response.Failed(ctx, err) + return + } + response.Success(ctx, ins) +} + func (h *BlogApiHandler) DescribeBlog(ctx *gin.Context) { idInt, err := strconv.ParseInt(ctx.Param("id"), 10, 64) if err != nil { @@ -131,6 +153,11 @@ func (h *BlogApiHandler) UpdateBlog(ctx *gin.Context) { } in := blog.NewUpdateBlogRequest(uint(idInt)) + if err := ctx.BindJSON(in); err != nil { + response.Failed(ctx, err) + return + } + ins, err := h.blog.UpdateBlog(ctx.Request.Context(), in) if err != nil { response.Failed(ctx, err) diff --git a/vblog/apps/blog/enum.go b/vblog/apps/blog/enum.go index b8ee1ab..6b067f4 100644 --- a/vblog/apps/blog/enum.go +++ b/vblog/apps/blog/enum.go @@ -1,7 +1,43 @@ package blog +import ( + "fmt" + "strings" +) + type STAGE int +func (s STAGE) String() string { + return STAGE_MAPPING[s] +} + +// 自定义 类型的序列化方式 +// "草稿" +func (s STAGE) MarshalJSON() ([]byte, error) { + return []byte(`"` + s.String() + `"`), nil +} + +// UnmarshalJSON([]byte) error +func (s *STAGE) UnmarshalJSON(data []byte) error { + str := strings.Trim(string(data), `"`) + switch str { + case "草稿": + *s = STAGE_DRAFT + // v := STAGE_DRAFT + // s = &v + case "已发布": + *s = STAGE_PUBLISHED + default: + return fmt.Errorf("不支持的发布类型") + } + return nil +} + +var STAGE_MAPPING = map[STAGE]string{ + STAGE_DRAFT: "草稿", + STAGE_PUBLISHED: "已发布", +} + const ( STAGE_DRAFT STAGE = iota STAGE_PUBLISHED diff --git a/vblog/apps/blog/impl/dao.go b/vblog/apps/blog/impl/dao.go new file mode 100644 index 0000000..cbc9939 --- /dev/null +++ b/vblog/apps/blog/impl/dao.go @@ -0,0 +1,17 @@ +package impl + +import ( + "context" + + "github.com/infraboard/mcube/v2/ioc/config/datasource" + "gitlab.com/go-course-project/go17/vblog/apps/blog" +) + +func (b *BlogServiceImpl) update(ctx context.Context, ins *blog.Blog) error { + err := datasource.DBFromCtx(ctx).Where("id = ?", ins.Id).Updates(ins).Error + if err != nil { + return err + } + + return nil +} diff --git a/vblog/apps/blog/impl/impl.go b/vblog/apps/blog/impl/impl.go index aa3c634..24e8c3b 100644 --- a/vblog/apps/blog/impl/impl.go +++ b/vblog/apps/blog/impl/impl.go @@ -100,11 +100,38 @@ func (b *BlogServiceImpl) DescribeBlog(ctx context.Context, in *blog.DescribeBlo } // PublishBlog implements blog.Service. -func (b *BlogServiceImpl) PublishBlog(context.Context, *blog.PublishBlogRequest) (*blog.Blog, error) { - panic("unimplemented") +func (b *BlogServiceImpl) PublishBlog(ctx context.Context, in *blog.PublishBlogRequest) (*blog.Blog, error) { + ins, err := b.DescribeBlog(ctx, blog.NewDescribeBlogRequest(in.Id)) + if err != nil { + return nil, err + } + + ins.Stage = in.Stage + + err = b.update(ctx, ins) + if err != nil { + return nil, err + } + return ins, nil } // UpdateBlog implements blog.Service. -func (b *BlogServiceImpl) UpdateBlog(context.Context, *blog.UpdateBlogRequest) (*blog.Blog, error) { - panic("unimplemented") +func (b *BlogServiceImpl) UpdateBlog(ctx context.Context, in *blog.UpdateBlogRequest) (*blog.Blog, error) { + ins, err := b.DescribeBlog(ctx, blog.NewDescribeBlogRequest(in.Id)) + if err != nil { + return nil, err + } + + // 全量更新 + ins.CreateBlogRequest = in.CreateBlogRequest + if err := ins.Validate(); err != nil { + return nil, err + } + + err = b.update(ctx, ins) + if err != nil { + return nil, err + } + + return ins, nil } diff --git a/vblog/apps/blog/impl_test.go b/vblog/apps/blog/impl_test.go index 9c03795..b2de1fc 100644 --- a/vblog/apps/blog/impl_test.go +++ b/vblog/apps/blog/impl_test.go @@ -29,6 +29,23 @@ func TestCreateBlog(t *testing.T) { t.Log(ins) } +func TestUpdateBlog(t *testing.T) { + ins, err := blog.GetService().DescribeBlog(ctx, blog.NewDescribeBlogRequest(31)) + if err != nil { + t.Fatal(err) + } + + req := blog.NewUpdateBlogRequest(31) + req.CreateBlogRequest = ins.CreateBlogRequest + req.Summary = "for update" + + ins, err = blog.GetService().UpdateBlog(ctx, req) + if err != nil { + t.Fatal(err) + } + t.Log(ins) +} + // SELECT * FROM `blogs` ORDER BY created_at DESC LIMIT 20 func TestQueryBlog(t *testing.T) { req := blog.NewQueryBlogRequest() @@ -42,6 +59,25 @@ func TestQueryBlog(t *testing.T) { t.Log(ins) } +func TestDescribeBlog(t *testing.T) { + req := blog.NewDescribeBlogRequest(31) + ins, err := blog.GetService().DescribeBlog(ctx, req) + if err != nil { + t.Fatal(err) + } + t.Log(ins) +} + +func TestPublishBlog(t *testing.T) { + req := blog.NewPublishBlogRequest(31) + req.Stage = blog.STAGE_PUBLISHED + ins, err := blog.GetService().PublishBlog(ctx, req) + if err != nil { + t.Fatal(err) + } + t.Log(ins) +} + func TestNewQueryBlogRequest(t *testing.T) { req := blog.NewQueryBlogRequest() req.SetTag("key1=value1,key2=value2") diff --git a/vblog/apps/blog/interface.go b/vblog/apps/blog/interface.go index a381c47..ec2c5b9 100644 --- a/vblog/apps/blog/interface.go +++ b/vblog/apps/blog/interface.go @@ -53,6 +53,12 @@ type DeleteBlogRequest struct { utils.GetRequest } +func NewPublishBlogRequest(id uint) *PublishBlogRequest { + return &PublishBlogRequest{ + GetRequest: *utils.NewGetRequest(id), + } +} + type PublishBlogRequest struct { utils.GetRequest StatusSpec diff --git a/vblog/logs/vblog.log b/vblog/logs/vblog.log index 8e26778..ece4c5a 100644 --- a/vblog/logs/vblog.log +++ b/vblog/logs/vblog.log @@ -386,3 +386,106 @@ {"level":"info","component":"server","time":"2025-01-19T11:59:44+08:00","caller":"ioc/server/server.go:76","message":"loaded apis: [blogs.v1 tokens.v1]"} {"level":"info","component":"server","time":"2025-01-19T11:59:44+08:00","caller":"ioc/server/server.go:77","message":"loaded defaults: []"} {"level":"info","component":"http","time":"2025-01-19T11:59:44+08:00","caller":"config/http/http.go:144","message":"HTTP服务启动成功, 监听地址: 127.0.0.1:8080"} +{"level":"info","component":"server","time":"2025-01-19T14:14:40+08:00","caller":"ioc/server/server.go:101","message":"receive signal 'interrupt', start graceful shutdown"} +{"level":"info","component":"http","time":"2025-01-19T14:14:40+08:00","caller":"config/http/http.go:152","message":"start graceful shutdown"} +{"level":"error","component":"http","time":"2025-01-19T14:14:40+08:00","caller":"config/http/http.go:146","message":"http: Server closed"} +{"level":"info","component":"server","time":"2025-01-19T14:14:40+08:00","caller":"ioc/server/server.go:115","message":"http service stop complete"} +{"level":"info","component":"gin_webframework","time":"2025-01-19T14:14:42+08:00","caller":"config/gin/framework.go:41","message":"enable gin recovery"} +{"level":"debug","time":"2025-01-19T14:14:42+08:00","caller":"token/impl/impl.go:39","message":"DefaultExpiredTTL: 3600"} +{"level":"info","component":"server","time":"2025-01-19T14:14:42+08:00","caller":"ioc/server/server.go:74","message":"loaded configs: [app.v1 trace.v1 log.v1 validator.v1 gin_webframework.v1 datasource.v1 grpc.v1 http.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:14:42+08:00","caller":"ioc/server/server.go:75","message":"loaded controllers: [token.v1 user.v1 blog.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:14:42+08:00","caller":"ioc/server/server.go:76","message":"loaded apis: [blogs.v1 tokens.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:14:42+08:00","caller":"ioc/server/server.go:77","message":"loaded defaults: []"} +{"level":"info","component":"http","time":"2025-01-19T14:14:42+08:00","caller":"config/http/http.go:144","message":"HTTP服务启动成功, 监听地址: 127.0.0.1:8080"} +{"level":"info","component":"server","time":"2025-01-19T14:16:02+08:00","caller":"ioc/server/server.go:101","message":"receive signal 'interrupt', start graceful shutdown"} +{"level":"info","component":"http","time":"2025-01-19T14:16:02+08:00","caller":"config/http/http.go:152","message":"start graceful shutdown"} +{"level":"error","component":"http","time":"2025-01-19T14:16:02+08:00","caller":"config/http/http.go:146","message":"http: Server closed"} +{"level":"info","component":"server","time":"2025-01-19T14:16:02+08:00","caller":"ioc/server/server.go:115","message":"http service stop complete"} +{"level":"info","component":"gin_webframework","time":"2025-01-19T14:16:04+08:00","caller":"config/gin/framework.go:41","message":"enable gin recovery"} +{"level":"debug","time":"2025-01-19T14:16:04+08:00","caller":"token/impl/impl.go:39","message":"DefaultExpiredTTL: 3600"} +{"level":"info","component":"server","time":"2025-01-19T14:16:04+08:00","caller":"ioc/server/server.go:74","message":"loaded configs: [app.v1 trace.v1 log.v1 validator.v1 gin_webframework.v1 datasource.v1 grpc.v1 http.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:16:04+08:00","caller":"ioc/server/server.go:75","message":"loaded controllers: [token.v1 user.v1 blog.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:16:04+08:00","caller":"ioc/server/server.go:76","message":"loaded apis: [blogs.v1 tokens.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:16:04+08:00","caller":"ioc/server/server.go:77","message":"loaded defaults: []"} +{"level":"info","component":"http","time":"2025-01-19T14:16:04+08:00","caller":"config/http/http.go:144","message":"HTTP服务启动成功, 监听地址: 127.0.0.1:8080"} +{"level":"info","component":"server","time":"2025-01-19T14:24:36+08:00","caller":"ioc/server/server.go:101","message":"receive signal 'interrupt', start graceful shutdown"} +{"level":"info","component":"http","time":"2025-01-19T14:24:36+08:00","caller":"config/http/http.go:152","message":"start graceful shutdown"} +{"level":"error","component":"http","time":"2025-01-19T14:24:36+08:00","caller":"config/http/http.go:146","message":"http: Server closed"} +{"level":"info","component":"server","time":"2025-01-19T14:24:36+08:00","caller":"ioc/server/server.go:115","message":"http service stop complete"} +{"level":"info","component":"gin_webframework","time":"2025-01-19T14:24:39+08:00","caller":"config/gin/framework.go:41","message":"enable gin recovery"} +{"level":"debug","time":"2025-01-19T14:24:39+08:00","caller":"token/impl/impl.go:39","message":"DefaultExpiredTTL: 3600"} +{"level":"info","component":"server","time":"2025-01-19T14:24:39+08:00","caller":"ioc/server/server.go:74","message":"loaded configs: [app.v1 trace.v1 log.v1 validator.v1 gin_webframework.v1 datasource.v1 grpc.v1 http.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:24:39+08:00","caller":"ioc/server/server.go:75","message":"loaded controllers: [token.v1 user.v1 blog.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:24:39+08:00","caller":"ioc/server/server.go:76","message":"loaded apis: [blogs.v1 tokens.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:24:39+08:00","caller":"ioc/server/server.go:77","message":"loaded defaults: []"} +{"level":"info","component":"http","time":"2025-01-19T14:24:39+08:00","caller":"config/http/http.go:144","message":"HTTP服务启动成功, 监听地址: 127.0.0.1:8080"} +{"level":"info","component":"server","time":"2025-01-19T14:26:25+08:00","caller":"ioc/server/server.go:101","message":"receive signal 'interrupt', start graceful shutdown"} +{"level":"info","component":"http","time":"2025-01-19T14:26:25+08:00","caller":"config/http/http.go:152","message":"start graceful shutdown"} +{"level":"error","component":"http","time":"2025-01-19T14:26:25+08:00","caller":"config/http/http.go:146","message":"http: Server closed"} +{"level":"info","component":"server","time":"2025-01-19T14:26:25+08:00","caller":"ioc/server/server.go:115","message":"http service stop complete"} +{"level":"info","component":"gin_webframework","time":"2025-01-19T14:26:28+08:00","caller":"config/gin/framework.go:41","message":"enable gin recovery"} +{"level":"debug","time":"2025-01-19T14:26:28+08:00","caller":"token/impl/impl.go:39","message":"DefaultExpiredTTL: 3600"} +{"level":"info","component":"server","time":"2025-01-19T14:26:28+08:00","caller":"ioc/server/server.go:74","message":"loaded configs: [app.v1 trace.v1 log.v1 validator.v1 gin_webframework.v1 datasource.v1 grpc.v1 http.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:26:28+08:00","caller":"ioc/server/server.go:75","message":"loaded controllers: [token.v1 user.v1 blog.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:26:28+08:00","caller":"ioc/server/server.go:76","message":"loaded apis: [blogs.v1 tokens.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:26:28+08:00","caller":"ioc/server/server.go:77","message":"loaded defaults: []"} +{"level":"info","component":"http","time":"2025-01-19T14:26:28+08:00","caller":"config/http/http.go:144","message":"HTTP服务启动成功, 监听地址: 127.0.0.1:8080"} +{"level":"info","component":"server","time":"2025-01-19T14:27:10+08:00","caller":"ioc/server/server.go:101","message":"receive signal 'interrupt', start graceful shutdown"} +{"level":"info","component":"http","time":"2025-01-19T14:27:10+08:00","caller":"config/http/http.go:152","message":"start graceful shutdown"} +{"level":"error","component":"http","time":"2025-01-19T14:27:10+08:00","caller":"config/http/http.go:146","message":"http: Server closed"} +{"level":"info","component":"server","time":"2025-01-19T14:27:10+08:00","caller":"ioc/server/server.go:115","message":"http service stop complete"} +{"level":"info","component":"gin_webframework","time":"2025-01-19T14:27:12+08:00","caller":"config/gin/framework.go:41","message":"enable gin recovery"} +{"level":"debug","time":"2025-01-19T14:27:12+08:00","caller":"token/impl/impl.go:39","message":"DefaultExpiredTTL: 3600"} +{"level":"info","component":"server","time":"2025-01-19T14:27:12+08:00","caller":"ioc/server/server.go:74","message":"loaded configs: [app.v1 trace.v1 log.v1 validator.v1 gin_webframework.v1 datasource.v1 grpc.v1 http.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:27:12+08:00","caller":"ioc/server/server.go:75","message":"loaded controllers: [token.v1 user.v1 blog.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:27:12+08:00","caller":"ioc/server/server.go:76","message":"loaded apis: [blogs.v1 tokens.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:27:12+08:00","caller":"ioc/server/server.go:77","message":"loaded defaults: []"} +{"level":"info","component":"http","time":"2025-01-19T14:27:12+08:00","caller":"config/http/http.go:144","message":"HTTP服务启动成功, 监听地址: 127.0.0.1:8080"} +{"level":"info","component":"server","time":"2025-01-19T14:32:57+08:00","caller":"ioc/server/server.go:101","message":"receive signal 'interrupt', start graceful shutdown"} +{"level":"info","component":"http","time":"2025-01-19T14:32:57+08:00","caller":"config/http/http.go:152","message":"start graceful shutdown"} +{"level":"error","component":"http","time":"2025-01-19T14:32:57+08:00","caller":"config/http/http.go:146","message":"http: Server closed"} +{"level":"info","component":"server","time":"2025-01-19T14:32:57+08:00","caller":"ioc/server/server.go:115","message":"http service stop complete"} +{"level":"info","component":"gin_webframework","time":"2025-01-19T14:32:59+08:00","caller":"config/gin/framework.go:41","message":"enable gin recovery"} +{"level":"debug","time":"2025-01-19T14:32:59+08:00","caller":"token/impl/impl.go:39","message":"DefaultExpiredTTL: 3600"} +{"level":"info","component":"server","time":"2025-01-19T14:32:59+08:00","caller":"ioc/server/server.go:74","message":"loaded configs: [app.v1 trace.v1 log.v1 validator.v1 gin_webframework.v1 datasource.v1 grpc.v1 http.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:32:59+08:00","caller":"ioc/server/server.go:75","message":"loaded controllers: [token.v1 user.v1 blog.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:32:59+08:00","caller":"ioc/server/server.go:76","message":"loaded apis: [blogs.v1 tokens.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:32:59+08:00","caller":"ioc/server/server.go:77","message":"loaded defaults: []"} +{"level":"info","component":"http","time":"2025-01-19T14:32:59+08:00","caller":"config/http/http.go:144","message":"HTTP服务启动成功, 监听地址: 127.0.0.1:8080"} +{"level":"info","component":"server","time":"2025-01-19T14:39:58+08:00","caller":"ioc/server/server.go:101","message":"receive signal 'interrupt', start graceful shutdown"} +{"level":"info","component":"http","time":"2025-01-19T14:39:58+08:00","caller":"config/http/http.go:152","message":"start graceful shutdown"} +{"level":"error","component":"http","time":"2025-01-19T14:39:58+08:00","caller":"config/http/http.go:146","message":"http: Server closed"} +{"level":"info","component":"server","time":"2025-01-19T14:39:58+08:00","caller":"ioc/server/server.go:115","message":"http service stop complete"} +{"level":"info","component":"gin_webframework","time":"2025-01-19T14:40:00+08:00","caller":"config/gin/framework.go:41","message":"enable gin recovery"} +{"level":"debug","time":"2025-01-19T14:40:00+08:00","caller":"token/impl/impl.go:39","message":"DefaultExpiredTTL: 3600"} +{"level":"info","component":"server","time":"2025-01-19T14:40:00+08:00","caller":"ioc/server/server.go:74","message":"loaded configs: [app.v1 trace.v1 log.v1 validator.v1 gin_webframework.v1 datasource.v1 grpc.v1 http.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:40:00+08:00","caller":"ioc/server/server.go:75","message":"loaded controllers: [token.v1 user.v1 blog.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:40:00+08:00","caller":"ioc/server/server.go:76","message":"loaded apis: [blogs.v1 tokens.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:40:00+08:00","caller":"ioc/server/server.go:77","message":"loaded defaults: []"} +{"level":"info","component":"http","time":"2025-01-19T14:40:00+08:00","caller":"config/http/http.go:144","message":"HTTP服务启动成功, 监听地址: 127.0.0.1:8080"} +{"level":"info","component":"server","time":"2025-01-19T14:41:34+08:00","caller":"ioc/server/server.go:101","message":"receive signal 'interrupt', start graceful shutdown"} +{"level":"info","component":"http","time":"2025-01-19T14:41:34+08:00","caller":"config/http/http.go:152","message":"start graceful shutdown"} +{"level":"error","component":"http","time":"2025-01-19T14:41:34+08:00","caller":"config/http/http.go:146","message":"http: Server closed"} +{"level":"info","component":"server","time":"2025-01-19T14:41:34+08:00","caller":"ioc/server/server.go:115","message":"http service stop complete"} +{"level":"info","component":"gin_webframework","time":"2025-01-19T14:41:36+08:00","caller":"config/gin/framework.go:41","message":"enable gin recovery"} +{"level":"debug","time":"2025-01-19T14:41:36+08:00","caller":"token/impl/impl.go:39","message":"DefaultExpiredTTL: 3600"} +{"level":"info","component":"server","time":"2025-01-19T14:41:36+08:00","caller":"ioc/server/server.go:74","message":"loaded configs: [app.v1 trace.v1 log.v1 validator.v1 gin_webframework.v1 datasource.v1 grpc.v1 http.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:41:36+08:00","caller":"ioc/server/server.go:75","message":"loaded controllers: [token.v1 user.v1 blog.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:41:36+08:00","caller":"ioc/server/server.go:76","message":"loaded apis: [blogs.v1 tokens.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:41:36+08:00","caller":"ioc/server/server.go:77","message":"loaded defaults: []"} +{"level":"info","component":"http","time":"2025-01-19T14:41:36+08:00","caller":"config/http/http.go:144","message":"HTTP服务启动成功, 监听地址: 127.0.0.1:8080"} +{"level":"info","component":"server","time":"2025-01-19T14:45:34+08:00","caller":"ioc/server/server.go:101","message":"receive signal 'interrupt', start graceful shutdown"} +{"level":"info","component":"http","time":"2025-01-19T14:45:34+08:00","caller":"config/http/http.go:152","message":"start graceful shutdown"} +{"level":"error","component":"http","time":"2025-01-19T14:45:34+08:00","caller":"config/http/http.go:146","message":"http: Server closed"} +{"level":"info","component":"server","time":"2025-01-19T14:45:34+08:00","caller":"ioc/server/server.go:115","message":"http service stop complete"} +{"level":"info","component":"gin_webframework","time":"2025-01-19T14:45:36+08:00","caller":"config/gin/framework.go:41","message":"enable gin recovery"} +{"level":"debug","time":"2025-01-19T14:45:36+08:00","caller":"token/impl/impl.go:39","message":"DefaultExpiredTTL: 3600"} +{"level":"info","component":"server","time":"2025-01-19T14:45:36+08:00","caller":"ioc/server/server.go:74","message":"loaded configs: [app.v1 trace.v1 log.v1 validator.v1 gin_webframework.v1 datasource.v1 grpc.v1 http.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:45:36+08:00","caller":"ioc/server/server.go:75","message":"loaded controllers: [token.v1 user.v1 blog.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:45:36+08:00","caller":"ioc/server/server.go:76","message":"loaded apis: [blogs.v1 tokens.v1]"} +{"level":"info","component":"server","time":"2025-01-19T14:45:36+08:00","caller":"ioc/server/server.go:77","message":"loaded defaults: []"} +{"level":"info","component":"http","time":"2025-01-19T14:45:36+08:00","caller":"config/http/http.go:144","message":"HTTP服务启动成功, 监听地址: 127.0.0.1:8080"} +{"level":"info","component":"server","time":"2025-01-19T14:50:39+08:00","caller":"ioc/server/server.go:101","message":"receive signal 'interrupt', start graceful shutdown"} +{"level":"info","component":"http","time":"2025-01-19T14:50:39+08:00","caller":"config/http/http.go:152","message":"start graceful shutdown"} +{"level":"error","component":"http","time":"2025-01-19T14:50:39+08:00","caller":"config/http/http.go:146","message":"http: Server closed"} +{"level":"info","component":"server","time":"2025-01-19T14:50:39+08:00","caller":"ioc/server/server.go:115","message":"http service stop complete"} diff --git a/vblog/web/README.md b/vblog/web/README.md index dcbb774..3f0dffe 100644 --- a/vblog/web/README.md +++ b/vblog/web/README.md @@ -587,7 +587,7 @@ const deleteBlog = async (id) => { ``` -## 文章的创建 +## 文章的创建和更新 选择一个mardown的编辑器: https://www.npmjs.com/package/md-editor-v3 @@ -598,3 +598,168 @@ const deleteBlog = async (id) => { ``` 创建成功后,进入到保存模式 + +```vue + + + + + +``` + +## 文章的发布 + +后端如何自定义状态展示 + +```go +type STAGE int + +func (s STAGE) String() string { + return STAGE_MAPPING[s] +} + +// 自定义 类型的序列化方式 +// "草稿" +func (s STAGE) MarshalJSON() ([]byte, error) { + return []byte(`"` + s.String() + `"`), nil +} + +// UnmarshalJSON([]byte) error +func (s *STAGE) UnmarshalJSON(data []byte) error { + str := strings.Trim(string(data), `"`) + switch str { + case "草稿": + *s = STAGE_DRAFT + case "已发布": + *s = STAGE_PUBLISHED + default: + return fmt.Errorf("不支持的发布类型") + } + return nil +} + +var STAGE_MAPPING = map[STAGE]string{ + STAGE_DRAFT: "草稿", + STAGE_PUBLISHED: "已发布", +} + +const ( + STAGE_DRAFT STAGE = iota + STAGE_PUBLISHED +) +``` diff --git a/vblog/web/src/api/blog.js b/vblog/web/src/api/blog.js index 05649d9..f51b53f 100644 --- a/vblog/web/src/api/blog.js +++ b/vblog/web/src/api/blog.js @@ -31,6 +31,13 @@ export const UPDATE_BLOG = (blog_id, data) => data, }) +export const PUBLISH_BLOG = (blog_id, data) => + client({ + url: `/api/vblog/v1/blogs/${blog_id}/publish`, + method: 'POST', + data, + }) + export const DELTE_BLOG = (blog_id) => client({ url: `/api/vblog/v1/blogs/${blog_id}`, diff --git a/vblog/web/src/views/backend/blog/ListPage.vue b/vblog/web/src/views/backend/blog/ListPage.vue index 5c9c58b..c5b62aa 100644 --- a/vblog/web/src/views/backend/blog/ListPage.vue +++ b/vblog/web/src/views/backend/blog/ListPage.vue @@ -35,6 +35,7 @@ + 编辑 - + @@ -81,7 +82,7 @@