补充自定义类型的自定义序列化
This commit is contained in:
parent
45f3bfae44
commit
0952098885
@ -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)
|
||||
|
@ -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
|
||||
|
17
vblog/apps/blog/impl/dao.go
Normal file
17
vblog/apps/blog/impl/dao.go
Normal file
@ -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
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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"}
|
||||
|
@ -587,7 +587,7 @@ const deleteBlog = async (id) => {
|
||||
</a-popconfirm>
|
||||
```
|
||||
|
||||
## 文章的创建
|
||||
## 文章的创建和更新
|
||||
|
||||
选择一个mardown的编辑器: https://www.npmjs.com/package/md-editor-v3
|
||||
|
||||
@ -598,3 +598,168 @@ const deleteBlog = async (id) => {
|
||||
```
|
||||
|
||||
创建成功后,进入到保存模式
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div>
|
||||
<!-- 页头 -->
|
||||
<div class="page-header">
|
||||
<a-page-header @back="$router.go(-1)" :title="isEdit ? '编辑文章' : '创建文章'">
|
||||
<template #extra>
|
||||
<a-button :loading="saveLoading" @click="save" type="primary">
|
||||
<template #icon>
|
||||
<icon-save />
|
||||
</template>
|
||||
保存
|
||||
</a-button>
|
||||
</template>
|
||||
</a-page-header>
|
||||
</div>
|
||||
<!-- form表单 -->
|
||||
<a-form ref="formRef" :model="form" layout="vertical">
|
||||
<a-form-item
|
||||
field="title"
|
||||
:rules="{ required: true, message: '请输入文章的标题' }"
|
||||
label="标题"
|
||||
>
|
||||
<a-input v-model="form.title" placeholder="请填写文章的标题" />
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
:rules="{ required: true, message: '请选择文章分类' }"
|
||||
field="category"
|
||||
label="分类"
|
||||
>
|
||||
<a-select v-model="form.category" placeholder="请选择文章分类">
|
||||
<a-option>软件开发</a-option>
|
||||
<a-option>系统运维</a-option>
|
||||
<a-option>软件测试</a-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item field="summary" label="概要">
|
||||
<a-textarea
|
||||
v-model="form.summary"
|
||||
:auto-size="{ minRows: 4, maxRows: 4 }"
|
||||
placeholder="请填写文章的概要信息"
|
||||
allow-clear
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item field="content" label="文章内容">
|
||||
<MdEditor class="editor" v-model="form.content" />
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, reactive, ref, useTemplateRef } from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
import { MdEditor } from 'md-editor-v3'
|
||||
import 'md-editor-v3/lib/style.css'
|
||||
import { CREATE_BLOG, DESCRIBE_BLOG, UPDATE_BLOG } from '@/api/blog'
|
||||
|
||||
const formInstance = useTemplateRef('formRef')
|
||||
|
||||
// 查询当前页面的路由信息
|
||||
const route = useRoute()
|
||||
const isEdit = ref(route.query.id ? true : false)
|
||||
const router = useRouter()
|
||||
|
||||
onMounted(async () => {
|
||||
if (isEdit.value) {
|
||||
const resp = await DESCRIBE_BLOG(route.query.id)
|
||||
Object.assign(form, { ...resp })
|
||||
}
|
||||
})
|
||||
|
||||
const form = reactive({
|
||||
title: '',
|
||||
summary: '',
|
||||
content: '',
|
||||
category: '',
|
||||
tags: {},
|
||||
})
|
||||
|
||||
// 文章的保存
|
||||
const saveLoading = ref(false)
|
||||
const save = () => {
|
||||
if (isEdit.value) {
|
||||
// 更新
|
||||
formInstance.value.validate(async (errors) => {
|
||||
if (errors === undefined) {
|
||||
try {
|
||||
saveLoading.value = true
|
||||
await UPDATE_BLOG(route.query.id, form)
|
||||
} finally {
|
||||
saveLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
} else {
|
||||
// 数据提交给后端之前,我们是需要前端校验数据合法性
|
||||
// formInstance.validate()
|
||||
// formInstance
|
||||
// https://cn.vuejs.org/guide/essentials/template-refs.html
|
||||
formInstance.value.validate(async (errors) => {
|
||||
if (errors === undefined) {
|
||||
try {
|
||||
saveLoading.value = true
|
||||
const resp = await CREATE_BLOG(form)
|
||||
router.replace({ name: 'backend_blog_edit', query: { id: resp.id } })
|
||||
isEdit.value = true
|
||||
} finally {
|
||||
saveLoading.value = false
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
.editor {
|
||||
height: calc(100vh - 100px);
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
## 文章的发布
|
||||
|
||||
后端如何自定义状态展示
|
||||
|
||||
```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
|
||||
)
|
||||
```
|
||||
|
@ -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}`,
|
||||
|
@ -35,6 +35,7 @@
|
||||
<a-table-column title="编码" data-index="id"></a-table-column>
|
||||
<a-table-column title="标题" data-index="title"></a-table-column>
|
||||
<a-table-column title="分类" data-index="category"></a-table-column>
|
||||
<a-table-column title="状态" data-index="stage"></a-table-column>
|
||||
<a-table-column title="更新时间">
|
||||
<template #cell="{ record }">
|
||||
<span>{{ dayjs(record.updated_at).format('YYYY-MM-DD HH:mm:ss') }}</span>
|
||||
@ -49,7 +50,7 @@
|
||||
</template>
|
||||
编辑
|
||||
</a-button>
|
||||
<a-button type="primary" @click="$modal.info({ title: 'Name', content: record.id })">
|
||||
<a-button type="primary" @click="publishBlog(record.id)">
|
||||
<template #icon>
|
||||
<icon-send />
|
||||
</template>
|
||||
@ -81,7 +82,7 @@
|
||||
<script setup>
|
||||
|
||||
import { onMounted, reactive, ref } from 'vue';
|
||||
import { QUERY_BLOG, DELTE_BLOG } from '@/api/blog'
|
||||
import { QUERY_BLOG, DELTE_BLOG, PUBLISH_BLOG } from '@/api/blog'
|
||||
import dayjs from 'dayjs'
|
||||
|
||||
// API 请求数据
|
||||
@ -138,6 +139,21 @@ const pageSizeChanged = (pageSize) => {
|
||||
queryData()
|
||||
}
|
||||
|
||||
|
||||
// 发布
|
||||
const publishLoadding = ref(0)
|
||||
const publishBlog = async (id) => {
|
||||
try {
|
||||
publishLoadding.value = id
|
||||
// 等待这个操作执行完成
|
||||
await PUBLISH_BLOG(id, { stage: "已发布" })
|
||||
// 刷新数据
|
||||
queryData()
|
||||
} finally {
|
||||
publishLoadding.value = 0
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped>
|
||||
|
Loading…
x
Reference in New Issue
Block a user