From 6151f4e2443b70d57828ee95f44875f6c77602b7 Mon Sep 17 00:00:00 2001 From: yanghao05 Date: Wed, 9 Apr 2025 16:40:34 +0800 Subject: [PATCH] feat: add post page --- backend/app/models/medias.go | 7 +- backend/app/models/posts.go | 13 +- backend/app/models/posts_test.go | 35 ++- backend/app/requests/pagination.go | 22 +- backend/test.http | 4 + frontend/admin/src/api/postService.js | 12 ++ frontend/admin/src/api/post_list.json | 297 ++++++++++++++++++++++++++ frontend/admin/src/pages/PostPage.vue | 158 ++++++++------ 8 files changed, 457 insertions(+), 91 deletions(-) create mode 100644 frontend/admin/src/api/postService.js create mode 100644 frontend/admin/src/api/post_list.json diff --git a/backend/app/models/medias.go b/backend/app/models/medias.go index 1e09014..3805120 100644 --- a/backend/app/models/medias.go +++ b/backend/app/models/medias.go @@ -64,15 +64,14 @@ func (m *mediasModel) countByCondition(ctx context.Context, expr BoolExpression) } func (m *mediasModel) List(ctx context.Context, pagination *requests.Pagination) (*requests.Pager, error) { - limit := pagination.GetLimit() - offset := pagination.GetOffset() + pagination.Format() tbl := table.Medias stmt := tbl. SELECT(tbl.AllColumns). ORDER_BY(tbl.ID.DESC()). - LIMIT(limit). - OFFSET(offset) + LIMIT(pagination.Limit). + OFFSET(pagination.Offset) m.log.Infof("sql: %s", stmt.DebugSql()) var medias []model.Medias diff --git a/backend/app/models/posts.go b/backend/app/models/posts.go index 5d31feb..2704724 100644 --- a/backend/app/models/posts.go +++ b/backend/app/models/posts.go @@ -3,6 +3,7 @@ package models import ( "context" "errors" + "time" "quyun/app/requests" "quyun/database/fields" @@ -72,6 +73,9 @@ func (m *postsModel) GetByID(ctx context.Context, id int64) (*model.Posts, error // Create func (m *postsModel) Create(ctx context.Context, model *model.Posts) error { + model.CreatedAt = time.Now() + model.UpdatedAt = time.Now() + tbl := table.Posts stmt := tbl.INSERT(tbl.MutableColumns).MODEL(model) m.log.Infof("sql: %s", stmt.DebugSql()) @@ -86,6 +90,8 @@ func (m *postsModel) Create(ctx context.Context, model *model.Posts) error { // Update func (m *postsModel) Update(ctx context.Context, id int64, model *model.Posts) error { + model.UpdatedAt = time.Now() + tbl := table.Posts stmt := tbl.UPDATE(tbl.MutableColumns).SET(model).WHERE(tbl.ID.EQ(Int64(id))) m.log.Infof("sql: %s", stmt.DebugSql()) @@ -118,16 +124,15 @@ func (m *postsModel) countByCondition(ctx context.Context, expr BoolExpression) } func (m *postsModel) List(ctx context.Context, pagination *requests.Pagination, cond BoolExpression) (*requests.Pager, error) { - limit := pagination.GetLimit() - offset := pagination.GetOffset() + pagination.Format() tbl := table.Posts stmt := tbl. SELECT(tbl.AllColumns). WHERE(cond). ORDER_BY(tbl.ID.DESC()). - LIMIT(limit). - OFFSET(offset) + LIMIT(pagination.Limit). + OFFSET(pagination.Offset) m.log.Infof("sql: %s", stmt.DebugSql()) var posts []model.Posts diff --git a/backend/app/models/posts_test.go b/backend/app/models/posts_test.go index 331efee..664d5d3 100644 --- a/backend/app/models/posts_test.go +++ b/backend/app/models/posts_test.go @@ -2,10 +2,14 @@ package models import ( "context" + "fmt" + "math/rand" "testing" "quyun/app/service/testx" "quyun/database" + "quyun/database/fields" + "quyun/database/schemas/public/model" "quyun/database/schemas/public/table" . "github.com/smartystreets/goconvey/convey" @@ -36,8 +40,37 @@ func Test_Posts(t *testing.T) { }) } -func (s *PostsTestSuite) Test_Demo() { +func (s *PostsTestSuite) Test_BatchInsert() { Convey("Test_Demo", s.T(), func() { database.Truncate(context.Background(), db, table.Posts.TableName()) + + count := 100 + for i := 0; i < count; i++ { + model := model.Posts{ + Status: fields.PostStatusPublished, + Title: fmt.Sprintf("test-title-%d", i), + Description: fmt.Sprintf("test-description-%d", i), + Content: fmt.Sprintf("test-content-%d", i), + Price: rand.Int63n(10000), + Discount: int16(rand.Intn(100)), + Views: rand.Int63n(10000), + Likes: rand.Int63n(10000), + Tags: fields.ToJson([]string{"tag1", "tag2", "tag3"}), + Assets: fields.ToJson([]fields.MediaAsset{ + { + Type: fields.MediaAssetTypeAudio, + Media: rand.Int63n(10000), + }, + { + Type: fields.MediaAssetTypeVideo, + Media: rand.Int63n(10000), + }, + }), + } + + if err := Posts.Create(context.Background(), &model); err != nil { + s.T().Fatal(err) + } + } }) } diff --git a/backend/app/requests/pagination.go b/backend/app/requests/pagination.go index c626318..c1ce90e 100644 --- a/backend/app/requests/pagination.go +++ b/backend/app/requests/pagination.go @@ -9,29 +9,19 @@ type Pager struct { } type Pagination struct { - Page int64 `json:"page" form:"page" query:"page"` - Limit int64 `json:"limit" form:"limit" query:"limit"` + Page int64 `json:"page" form:"page" query:"page"` + Limit int64 `json:"limit" form:"limit" query:"limit"` + Offset int64 `json:"-"` } -func (filter *Pagination) GetOffset() int64 { - return (filter.Page - 1) * filter.Limit -} - -func (filter *Pagination) GetLimit() int64 { - if filter.Limit <= 0 { - return 10 - } - return filter.Limit -} - -func (filter *Pagination) Format() *Pagination { +func (filter *Pagination) Format() { if filter.Page <= 0 { filter.Page = 1 } - if !lo.Contains([]int64{10, 20, 50, 100}, filter.Limit) { + if !lo.Contains([]int64{10, 25, 50, 100}, filter.Limit) { filter.Limit = 10 } - return filter + filter.Offset = (filter.Page - 1) * filter.Limit } diff --git a/backend/test.http b/backend/test.http index a5a3f4a..1c04c34 100644 --- a/backend/test.http +++ b/backend/test.http @@ -35,4 +35,8 @@ Content-Type: application/json ### get medias GET {{host}}/v1/admin/medias HTTP/1.1 +Content-Type: application/json + +### get posts +GET {{host}}/v1/admin/posts HTTP/1.1 Content-Type: application/json \ No newline at end of file diff --git a/frontend/admin/src/api/postService.js b/frontend/admin/src/api/postService.js new file mode 100644 index 0000000..26dbaf9 --- /dev/null +++ b/frontend/admin/src/api/postService.js @@ -0,0 +1,12 @@ +import httpClient from './httpClient'; + +export const postService = { + getPosts({ page = 1, limit = 10 } = {}) { + return httpClient.get('/admin/posts', { + params: { page, limit } + }); + }, + getPost(id) { + return httpClient.get(`/admin/posts/${id}`); + }, +}; \ No newline at end of file diff --git a/frontend/admin/src/api/post_list.json b/frontend/admin/src/api/post_list.json new file mode 100644 index 0000000..441d82b --- /dev/null +++ b/frontend/admin/src/api/post_list.json @@ -0,0 +1,297 @@ +{ + "page": 1, + "limit": 10, + "total": 100, + "items": [ + { + "id": 100, + "created_at": "2025-04-09T14:42:08.721793Z", + "updated_at": "2025-04-09T14:42:08.721793Z", + "deleted_at": null, + "status": 1, + "title": "test-title-99", + "description": "test-description-99", + "content": "test-content-99", + "price": 4205, + "discount": 45, + "views": 8566, + "likes": 2912, + "tags": [ + "tag1", + "tag2", + "tag3" + ], + "assets": [ + { + "type": "audio", + "media": 8775 + }, + { + "type": "video", + "media": 2905 + } + ] + }, + { + "id": 99, + "created_at": "2025-04-09T14:42:08.715622Z", + "updated_at": "2025-04-09T14:42:08.715622Z", + "deleted_at": null, + "status": 1, + "title": "test-title-98", + "description": "test-description-98", + "content": "test-content-98", + "price": 8407, + "discount": 59, + "views": 4779, + "likes": 1514, + "tags": [ + "tag1", + "tag2", + "tag3" + ], + "assets": [ + { + "type": "audio", + "media": 5265 + }, + { + "type": "video", + "media": 9715 + } + ] + }, + { + "id": 98, + "created_at": "2025-04-09T14:42:08.710788Z", + "updated_at": "2025-04-09T14:42:08.710788Z", + "deleted_at": null, + "status": 1, + "title": "test-title-97", + "description": "test-description-97", + "content": "test-content-97", + "price": 1314, + "discount": 15, + "views": 6962, + "likes": 440, + "tags": [ + "tag1", + "tag2", + "tag3" + ], + "assets": [ + { + "type": "audio", + "media": 1321 + }, + { + "type": "video", + "media": 6559 + } + ] + }, + { + "id": 97, + "created_at": "2025-04-09T14:42:08.705116Z", + "updated_at": "2025-04-09T14:42:08.705116Z", + "deleted_at": null, + "status": 1, + "title": "test-title-96", + "description": "test-description-96", + "content": "test-content-96", + "price": 9030, + "discount": 14, + "views": 6942, + "likes": 9185, + "tags": [ + "tag1", + "tag2", + "tag3" + ], + "assets": [ + { + "type": "audio", + "media": 6482 + }, + { + "type": "video", + "media": 2153 + } + ] + }, + { + "id": 96, + "created_at": "2025-04-09T14:42:08.697806Z", + "updated_at": "2025-04-09T14:42:08.697806Z", + "deleted_at": null, + "status": 1, + "title": "test-title-95", + "description": "test-description-95", + "content": "test-content-95", + "price": 6363, + "discount": 41, + "views": 8679, + "likes": 1755, + "tags": [ + "tag1", + "tag2", + "tag3" + ], + "assets": [ + { + "type": "audio", + "media": 6229 + }, + { + "type": "video", + "media": 3559 + } + ] + }, + { + "id": 95, + "created_at": "2025-04-09T14:42:08.693557Z", + "updated_at": "2025-04-09T14:42:08.693557Z", + "deleted_at": null, + "status": 1, + "title": "test-title-94", + "description": "test-description-94", + "content": "test-content-94", + "price": 6819, + "discount": 61, + "views": 9728, + "likes": 1103, + "tags": [ + "tag1", + "tag2", + "tag3" + ], + "assets": [ + { + "type": "audio", + "media": 6464 + }, + { + "type": "video", + "media": 4964 + } + ] + }, + { + "id": 94, + "created_at": "2025-04-09T14:42:08.688664Z", + "updated_at": "2025-04-09T14:42:08.688664Z", + "deleted_at": null, + "status": 1, + "title": "test-title-93", + "description": "test-description-93", + "content": "test-content-93", + "price": 4324, + "discount": 0, + "views": 473, + "likes": 2956, + "tags": [ + "tag1", + "tag2", + "tag3" + ], + "assets": [ + { + "type": "audio", + "media": 3043 + }, + { + "type": "video", + "media": 1234 + } + ] + }, + { + "id": 93, + "created_at": "2025-04-09T14:42:08.681727Z", + "updated_at": "2025-04-09T14:42:08.681727Z", + "deleted_at": null, + "status": 1, + "title": "test-title-92", + "description": "test-description-92", + "content": "test-content-92", + "price": 8068, + "discount": 86, + "views": 3783, + "likes": 3477, + "tags": [ + "tag1", + "tag2", + "tag3" + ], + "assets": [ + { + "type": "audio", + "media": 3623 + }, + { + "type": "video", + "media": 2628 + } + ] + }, + { + "id": 92, + "created_at": "2025-04-09T14:42:08.677622Z", + "updated_at": "2025-04-09T14:42:08.677622Z", + "deleted_at": null, + "status": 1, + "title": "test-title-91", + "description": "test-description-91", + "content": "test-content-91", + "price": 6313, + "discount": 43, + "views": 982, + "likes": 2660, + "tags": [ + "tag1", + "tag2", + "tag3" + ], + "assets": [ + { + "type": "audio", + "media": 3542 + }, + { + "type": "video", + "media": 6605 + } + ] + }, + { + "id": 91, + "created_at": "2025-04-09T14:42:08.674006Z", + "updated_at": "2025-04-09T14:42:08.674006Z", + "deleted_at": null, + "status": 1, + "title": "test-title-90", + "description": "test-description-90", + "content": "test-content-90", + "price": 3659, + "discount": 83, + "views": 76, + "likes": 4807, + "tags": [ + "tag1", + "tag2", + "tag3" + ], + "assets": [ + { + "type": "audio", + "media": 3191 + }, + { + "type": "video", + "media": 2689 + } + ] + } + ] +} \ No newline at end of file diff --git a/frontend/admin/src/pages/PostPage.vue b/frontend/admin/src/pages/PostPage.vue index d26ff87..8e3ef78 100644 --- a/frontend/admin/src/pages/PostPage.vue +++ b/frontend/admin/src/pages/PostPage.vue @@ -1,6 +1,8 @@