Compare commits
3 Commits
88d42470c4
...
40df9604d8
| Author | SHA1 | Date | |
|---|---|---|---|
| 40df9604d8 | |||
| 0185e51396 | |||
| 8e95dada82 |
@@ -28,7 +28,7 @@ type TokenResponse struct {
|
|||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body AuthBody true "请求体"
|
// @Param body body AuthBody true "请求体"
|
||||||
// @Success 200 {object} TokenResponse "成功"
|
// @Success 200 {object} TokenResponse "成功"
|
||||||
// @Router /admin/auth [post]
|
// @Router /admin/v1/auth [post]
|
||||||
// @Bind body body
|
// @Bind body body
|
||||||
func (ctl *auth) Login(ctx fiber.Ctx, body *AuthBody) (*TokenResponse, error) {
|
func (ctl *auth) Login(ctx fiber.Ctx, body *AuthBody) (*TokenResponse, error) {
|
||||||
if body.Username == "pl.yang" && body.Password == "Xixi@0202" {
|
if body.Username == "pl.yang" && body.Password == "Xixi@0202" {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"quyun/v2/providers/ali"
|
"quyun/v2/providers/ali"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v3"
|
"github.com/gofiber/fiber/v3"
|
||||||
|
"go.ipao.vip/gen"
|
||||||
)
|
)
|
||||||
|
|
||||||
// @provider
|
// @provider
|
||||||
@@ -23,11 +24,16 @@ type medias struct {
|
|||||||
// @Param pagination query requests.Pagination false "分页参数"
|
// @Param pagination query requests.Pagination false "分页参数"
|
||||||
// @Param query query ListQuery false "筛选条件"
|
// @Param query query ListQuery false "筛选条件"
|
||||||
// @Success 200 {object} requests.Pager{items=models.Medium} "成功"
|
// @Success 200 {object} requests.Pager{items=models.Medium} "成功"
|
||||||
// @Router /admin/medias [get]
|
// @Router /admin/v1/medias [get]
|
||||||
// @Bind pagination query
|
// @Bind pagination query
|
||||||
// @Bind query query
|
// @Bind query query
|
||||||
func (ctl *medias) List(ctx fiber.Ctx, pagination *requests.Pagination, query *ListQuery) (*requests.Pager, error) {
|
func (ctl *medias) List(ctx fiber.Ctx, pagination *requests.Pagination, query *ListQuery) (*requests.Pager, error) {
|
||||||
return services.Media.List(ctx, pagination, models.MediumQuery.Name.Like(database.WrapLike(*query.Keyword)))
|
conds := []gen.Condition{}
|
||||||
|
if query.Keyword != nil {
|
||||||
|
conds = append(conds, models.MediumQuery.Name.Like(database.WrapLike(*query.Keyword)))
|
||||||
|
}
|
||||||
|
|
||||||
|
return services.Media.List(ctx, pagination, conds...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show media
|
// Show media
|
||||||
@@ -36,7 +42,7 @@ func (ctl *medias) List(ctx fiber.Ctx, pagination *requests.Pagination, query *L
|
|||||||
// @Tags Admin Medias
|
// @Tags Admin Medias
|
||||||
// @Param id path int64 true "媒体 ID"
|
// @Param id path int64 true "媒体 ID"
|
||||||
// @Success 302 {string} string "跳转"
|
// @Success 302 {string} string "跳转"
|
||||||
// @Router /admin/medias/:id [get]
|
// @Router /admin/v1/medias/:id [get]
|
||||||
// @Bind media path key(id) model(id)
|
// @Bind media path key(id) model(id)
|
||||||
func (ctl *medias) Show(ctx fiber.Ctx, media *models.Medium) error {
|
func (ctl *medias) Show(ctx fiber.Ctx, media *models.Medium) error {
|
||||||
url, err := ctl.oss.GetSignedUrl(ctx, media.Path)
|
url, err := ctl.oss.GetSignedUrl(ctx, media.Path)
|
||||||
@@ -54,7 +60,7 @@ func (ctl *medias) Show(ctx fiber.Ctx, media *models.Medium) error {
|
|||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int64 true "媒体 ID"
|
// @Param id path int64 true "媒体 ID"
|
||||||
// @Success 204 {object} any "成功"
|
// @Success 204 {object} any "成功"
|
||||||
// @Router /admin/medias/:id [delete]
|
// @Router /admin/v1/medias/:id [delete]
|
||||||
// @Bind media path key(id) model(id)
|
// @Bind media path key(id) model(id)
|
||||||
func (ctl *medias) Delete(ctx fiber.Ctx, media *models.Medium) error {
|
func (ctl *medias) Delete(ctx fiber.Ctx, media *models.Medium) error {
|
||||||
if err := ctl.oss.Delete(ctx, media.Path); err != nil {
|
if err := ctl.oss.Delete(ctx, media.Path); err != nil {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ type orders struct{}
|
|||||||
// @Param pagination query requests.Pagination false "分页参数"
|
// @Param pagination query requests.Pagination false "分页参数"
|
||||||
// @Param query query OrderListQuery false "筛选条件"
|
// @Param query query OrderListQuery false "筛选条件"
|
||||||
// @Success 200 {object} requests.Pager{items=services.OrderListItem} "成功"
|
// @Success 200 {object} requests.Pager{items=services.OrderListItem} "成功"
|
||||||
// @Router /admin/orders [get]
|
// @Router /admin/v1/orders [get]
|
||||||
// @Bind pagination query
|
// @Bind pagination query
|
||||||
// @Bind query query
|
// @Bind query query
|
||||||
func (ctl *orders) List(
|
func (ctl *orders) List(
|
||||||
@@ -52,7 +52,7 @@ func (ctl *orders) List(
|
|||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int64 true "订单 ID"
|
// @Param id path int64 true "订单 ID"
|
||||||
// @Success 200 {object} any "成功"
|
// @Success 200 {object} any "成功"
|
||||||
// @Router /admin/orders/:id/refund [post]
|
// @Router /admin/v1/orders/:id/refund [post]
|
||||||
// @Bind order path key(id) model(id)
|
// @Bind order path key(id) model(id)
|
||||||
func (ctl *orders) Refund(ctx fiber.Ctx, order *models.Order) error {
|
func (ctl *orders) Refund(ctx fiber.Ctx, order *models.Order) error {
|
||||||
return services.Orders.Refund(ctx, order)
|
return services.Orders.Refund(ctx, order)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package admin
|
|||||||
import (
|
import (
|
||||||
"quyun/v2/app/requests"
|
"quyun/v2/app/requests"
|
||||||
"quyun/v2/app/services"
|
"quyun/v2/app/services"
|
||||||
|
"quyun/v2/database"
|
||||||
"quyun/v2/database/models"
|
"quyun/v2/database/models"
|
||||||
"quyun/v2/pkg/fields"
|
"quyun/v2/pkg/fields"
|
||||||
|
|
||||||
@@ -27,12 +28,13 @@ type posts struct{}
|
|||||||
// @Param pagination query requests.Pagination false "分页参数"
|
// @Param pagination query requests.Pagination false "分页参数"
|
||||||
// @Param query query ListQuery false "筛选条件"
|
// @Param query query ListQuery false "筛选条件"
|
||||||
// @Success 200 {object} requests.Pager{items=PostItem} "成功"
|
// @Success 200 {object} requests.Pager{items=PostItem} "成功"
|
||||||
// @Router /admin/posts [get]
|
// @Router /admin/v1/posts [get]
|
||||||
// @Bind pagination query
|
// @Bind pagination query
|
||||||
// @Bind query query
|
// @Bind query query
|
||||||
func (ctl *posts) List(ctx fiber.Ctx, pagination *requests.Pagination, query *ListQuery) (*requests.Pager, error) {
|
func (ctl *posts) List(ctx fiber.Ctx, pagination *requests.Pagination, query *ListQuery) (*requests.Pager, error) {
|
||||||
conds := []gen.Condition{
|
conds := []gen.Condition{}
|
||||||
models.PostQuery.Title.Like(*query.Keyword),
|
if query.Keyword != nil && *query.Keyword != "" {
|
||||||
|
conds = append(conds, models.PostQuery.Title.Like(database.WrapLike(*query.Keyword)))
|
||||||
}
|
}
|
||||||
pager, err := services.Posts.List(ctx, pagination, conds...)
|
pager, err := services.Posts.List(ctx, pagination, conds...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -81,7 +83,7 @@ type PostForm struct {
|
|||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param form body PostForm true "请求体"
|
// @Param form body PostForm true "请求体"
|
||||||
// @Success 200 {object} any "成功"
|
// @Success 200 {object} any "成功"
|
||||||
// @Router /admin/posts [post]
|
// @Router /admin/v1/posts [post]
|
||||||
// @Bind form body
|
// @Bind form body
|
||||||
func (ctl *posts) Create(ctx fiber.Ctx, form *PostForm) error {
|
func (ctl *posts) Create(ctx fiber.Ctx, form *PostForm) error {
|
||||||
post := models.Post{
|
post := models.Post{
|
||||||
@@ -126,7 +128,7 @@ func (ctl *posts) Create(ctx fiber.Ctx, form *PostForm) error {
|
|||||||
// @Param id path int64 true "作品 ID"
|
// @Param id path int64 true "作品 ID"
|
||||||
// @Param form body PostForm true "请求体"
|
// @Param form body PostForm true "请求体"
|
||||||
// @Success 200 {object} any "成功"
|
// @Success 200 {object} any "成功"
|
||||||
// @Router /admin/posts/:id [put]
|
// @Router /admin/v1/posts/:id [put]
|
||||||
// @Bind post path key(id) model(id)
|
// @Bind post path key(id) model(id)
|
||||||
// @Bind form body
|
// @Bind form body
|
||||||
func (ctl *posts) Update(ctx fiber.Ctx, post *models.Post, form *PostForm) error {
|
func (ctl *posts) Update(ctx fiber.Ctx, post *models.Post, form *PostForm) error {
|
||||||
@@ -167,7 +169,7 @@ func (ctl *posts) Update(ctx fiber.Ctx, post *models.Post, form *PostForm) error
|
|||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int64 true "作品 ID"
|
// @Param id path int64 true "作品 ID"
|
||||||
// @Success 204 {object} any "成功"
|
// @Success 204 {object} any "成功"
|
||||||
// @Router /admin/posts/:id [delete]
|
// @Router /admin/v1/posts/:id [delete]
|
||||||
// @Bind post path key(id) model(id)
|
// @Bind post path key(id) model(id)
|
||||||
func (ctl *posts) Delete(ctx fiber.Ctx, post *models.Post) error {
|
func (ctl *posts) Delete(ctx fiber.Ctx, post *models.Post) error {
|
||||||
if _, err := post.ForceDelete(ctx); err != nil {
|
if _, err := post.ForceDelete(ctx); err != nil {
|
||||||
@@ -189,7 +191,7 @@ type PostItem struct {
|
|||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int64 true "作品 ID"
|
// @Param id path int64 true "作品 ID"
|
||||||
// @Success 200 {object} PostItem "成功"
|
// @Success 200 {object} PostItem "成功"
|
||||||
// @Router /admin/posts/:id [get]
|
// @Router /admin/v1/posts/:id [get]
|
||||||
// @Bind post path key(id) model(id)
|
// @Bind post path key(id) model(id)
|
||||||
func (ctl *posts) Show(ctx fiber.Ctx, post *models.Post) (*PostItem, error) {
|
func (ctl *posts) Show(ctx fiber.Ctx, post *models.Post) (*PostItem, error) {
|
||||||
medias, err := services.Media.GetByIds(ctx, lo.Map(post.Assets.Data(), func(asset fields.MediaAsset, _ int) int64 {
|
medias, err := services.Media.GetByIds(ctx, lo.Map(post.Assets.Data(), func(asset fields.MediaAsset, _ int) int64 {
|
||||||
@@ -212,7 +214,7 @@ func (ctl *posts) Show(ctx fiber.Ctx, post *models.Post) (*PostItem, error) {
|
|||||||
// @Param id path int64 true "作品 ID"
|
// @Param id path int64 true "作品 ID"
|
||||||
// @Param userId path int64 true "用户 ID"
|
// @Param userId path int64 true "用户 ID"
|
||||||
// @Success 200 {object} any "成功"
|
// @Success 200 {object} any "成功"
|
||||||
// @Router /admin/posts/:id/send-to/:userId [post]
|
// @Router /admin/v1/posts/:id/send-to/:userId [post]
|
||||||
// @Bind post path key(id) model(id)
|
// @Bind post path key(id) model(id)
|
||||||
// @Bind user path key(userId) model(id)
|
// @Bind user path key(userId) model(id)
|
||||||
func (ctl *posts) SendTo(ctx fiber.Ctx, post *models.Post, user *models.User) error {
|
func (ctl *posts) SendTo(ctx fiber.Ctx, post *models.Post, user *models.User) error {
|
||||||
|
|||||||
@@ -50,28 +50,28 @@ func (r *Routes) Name() string {
|
|||||||
// Each route is registered with its corresponding controller action and parameter bindings.
|
// Each route is registered with its corresponding controller action and parameter bindings.
|
||||||
func (r *Routes) Register(router fiber.Router) {
|
func (r *Routes) Register(router fiber.Router) {
|
||||||
// Register routes for controller: auth
|
// Register routes for controller: auth
|
||||||
r.log.Debugf("Registering route: Post /admin/auth -> auth.Login")
|
r.log.Debugf("Registering route: Post /admin/v1/auth -> auth.Login")
|
||||||
router.Post("/admin/auth"[len(r.Path()):], DataFunc1(
|
router.Post("/admin/v1/auth"[len(r.Path()):], DataFunc1(
|
||||||
r.auth.Login,
|
r.auth.Login,
|
||||||
Body[AuthBody]("body"),
|
Body[AuthBody]("body"),
|
||||||
))
|
))
|
||||||
// Register routes for controller: medias
|
// Register routes for controller: medias
|
||||||
r.log.Debugf("Registering route: Delete /admin/medias/:id -> medias.Delete")
|
r.log.Debugf("Registering route: Delete /admin/v1/medias/:id -> medias.Delete")
|
||||||
router.Delete("/admin/medias/:id"[len(r.Path()):], Func1(
|
router.Delete("/admin/v1/medias/:id"[len(r.Path()):], Func1(
|
||||||
r.medias.Delete,
|
r.medias.Delete,
|
||||||
func(ctx fiber.Ctx) (*models.Medium, error) {
|
func(ctx fiber.Ctx) (*models.Medium, error) {
|
||||||
v := fiber.Params[int](ctx, "id")
|
v := fiber.Params[int](ctx, "id")
|
||||||
return models.MediumQuery.WithContext(ctx).Where(field.NewUnsafeFieldRaw("id = ?", v)).First()
|
return models.MediumQuery.WithContext(ctx).Where(field.NewUnsafeFieldRaw("id = ?", v)).First()
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
r.log.Debugf("Registering route: Get /admin/medias -> medias.List")
|
r.log.Debugf("Registering route: Get /admin/v1/medias -> medias.List")
|
||||||
router.Get("/admin/medias"[len(r.Path()):], DataFunc2(
|
router.Get("/admin/v1/medias"[len(r.Path()):], DataFunc2(
|
||||||
r.medias.List,
|
r.medias.List,
|
||||||
Query[requests.Pagination]("pagination"),
|
Query[requests.Pagination]("pagination"),
|
||||||
Query[ListQuery]("query"),
|
Query[ListQuery]("query"),
|
||||||
))
|
))
|
||||||
r.log.Debugf("Registering route: Get /admin/medias/:id -> medias.Show")
|
r.log.Debugf("Registering route: Get /admin/v1/medias/:id -> medias.Show")
|
||||||
router.Get("/admin/medias/:id"[len(r.Path()):], Func1(
|
router.Get("/admin/v1/medias/:id"[len(r.Path()):], Func1(
|
||||||
r.medias.Show,
|
r.medias.Show,
|
||||||
func(ctx fiber.Ctx) (*models.Medium, error) {
|
func(ctx fiber.Ctx) (*models.Medium, error) {
|
||||||
v := fiber.Params[int](ctx, "id")
|
v := fiber.Params[int](ctx, "id")
|
||||||
@@ -79,14 +79,14 @@ func (r *Routes) Register(router fiber.Router) {
|
|||||||
},
|
},
|
||||||
))
|
))
|
||||||
// Register routes for controller: orders
|
// Register routes for controller: orders
|
||||||
r.log.Debugf("Registering route: Get /admin/orders -> orders.List")
|
r.log.Debugf("Registering route: Get /admin/v1/orders -> orders.List")
|
||||||
router.Get("/admin/orders"[len(r.Path()):], DataFunc2(
|
router.Get("/admin/v1/orders"[len(r.Path()):], DataFunc2(
|
||||||
r.orders.List,
|
r.orders.List,
|
||||||
Query[requests.Pagination]("pagination"),
|
Query[requests.Pagination]("pagination"),
|
||||||
Query[OrderListQuery]("query"),
|
Query[OrderListQuery]("query"),
|
||||||
))
|
))
|
||||||
r.log.Debugf("Registering route: Post /admin/orders/:id/refund -> orders.Refund")
|
r.log.Debugf("Registering route: Post /admin/v1/orders/:id/refund -> orders.Refund")
|
||||||
router.Post("/admin/orders/:id/refund"[len(r.Path()):], Func1(
|
router.Post("/admin/v1/orders/:id/refund"[len(r.Path()):], Func1(
|
||||||
r.orders.Refund,
|
r.orders.Refund,
|
||||||
func(ctx fiber.Ctx) (*models.Order, error) {
|
func(ctx fiber.Ctx) (*models.Order, error) {
|
||||||
v := fiber.Params[int](ctx, "id")
|
v := fiber.Params[int](ctx, "id")
|
||||||
@@ -94,35 +94,35 @@ func (r *Routes) Register(router fiber.Router) {
|
|||||||
},
|
},
|
||||||
))
|
))
|
||||||
// Register routes for controller: posts
|
// Register routes for controller: posts
|
||||||
r.log.Debugf("Registering route: Delete /admin/posts/:id -> posts.Delete")
|
r.log.Debugf("Registering route: Delete /admin/v1/posts/:id -> posts.Delete")
|
||||||
router.Delete("/admin/posts/:id"[len(r.Path()):], Func1(
|
router.Delete("/admin/v1/posts/:id"[len(r.Path()):], Func1(
|
||||||
r.posts.Delete,
|
r.posts.Delete,
|
||||||
func(ctx fiber.Ctx) (*models.Post, error) {
|
func(ctx fiber.Ctx) (*models.Post, error) {
|
||||||
v := fiber.Params[int](ctx, "id")
|
v := fiber.Params[int](ctx, "id")
|
||||||
return models.PostQuery.WithContext(ctx).Where(field.NewUnsafeFieldRaw("id = ?", v)).First()
|
return models.PostQuery.WithContext(ctx).Where(field.NewUnsafeFieldRaw("id = ?", v)).First()
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
r.log.Debugf("Registering route: Get /admin/posts -> posts.List")
|
r.log.Debugf("Registering route: Get /admin/v1/posts -> posts.List")
|
||||||
router.Get("/admin/posts"[len(r.Path()):], DataFunc2(
|
router.Get("/admin/v1/posts"[len(r.Path()):], DataFunc2(
|
||||||
r.posts.List,
|
r.posts.List,
|
||||||
Query[requests.Pagination]("pagination"),
|
Query[requests.Pagination]("pagination"),
|
||||||
Query[ListQuery]("query"),
|
Query[ListQuery]("query"),
|
||||||
))
|
))
|
||||||
r.log.Debugf("Registering route: Get /admin/posts/:id -> posts.Show")
|
r.log.Debugf("Registering route: Get /admin/v1/posts/:id -> posts.Show")
|
||||||
router.Get("/admin/posts/:id"[len(r.Path()):], DataFunc1(
|
router.Get("/admin/v1/posts/:id"[len(r.Path()):], DataFunc1(
|
||||||
r.posts.Show,
|
r.posts.Show,
|
||||||
func(ctx fiber.Ctx) (*models.Post, error) {
|
func(ctx fiber.Ctx) (*models.Post, error) {
|
||||||
v := fiber.Params[int](ctx, "id")
|
v := fiber.Params[int](ctx, "id")
|
||||||
return models.PostQuery.WithContext(ctx).Where(field.NewUnsafeFieldRaw("id = ?", v)).First()
|
return models.PostQuery.WithContext(ctx).Where(field.NewUnsafeFieldRaw("id = ?", v)).First()
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
r.log.Debugf("Registering route: Post /admin/posts -> posts.Create")
|
r.log.Debugf("Registering route: Post /admin/v1/posts -> posts.Create")
|
||||||
router.Post("/admin/posts"[len(r.Path()):], Func1(
|
router.Post("/admin/v1/posts"[len(r.Path()):], Func1(
|
||||||
r.posts.Create,
|
r.posts.Create,
|
||||||
Body[PostForm]("form"),
|
Body[PostForm]("form"),
|
||||||
))
|
))
|
||||||
r.log.Debugf("Registering route: Post /admin/posts/:id/send-to/:userId -> posts.SendTo")
|
r.log.Debugf("Registering route: Post /admin/v1/posts/:id/send-to/:userId -> posts.SendTo")
|
||||||
router.Post("/admin/posts/:id/send-to/:userId"[len(r.Path()):], Func2(
|
router.Post("/admin/v1/posts/:id/send-to/:userId"[len(r.Path()):], Func2(
|
||||||
r.posts.SendTo,
|
r.posts.SendTo,
|
||||||
func(ctx fiber.Ctx) (*models.Post, error) {
|
func(ctx fiber.Ctx) (*models.Post, error) {
|
||||||
v := fiber.Params[int](ctx, "id")
|
v := fiber.Params[int](ctx, "id")
|
||||||
@@ -133,8 +133,8 @@ func (r *Routes) Register(router fiber.Router) {
|
|||||||
return models.UserQuery.WithContext(ctx).Where(field.NewUnsafeFieldRaw("id = ?", v)).First()
|
return models.UserQuery.WithContext(ctx).Where(field.NewUnsafeFieldRaw("id = ?", v)).First()
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
r.log.Debugf("Registering route: Put /admin/posts/:id -> posts.Update")
|
r.log.Debugf("Registering route: Put /admin/v1/posts/:id -> posts.Update")
|
||||||
router.Put("/admin/posts/:id"[len(r.Path()):], Func2(
|
router.Put("/admin/v1/posts/:id"[len(r.Path()):], Func2(
|
||||||
r.posts.Update,
|
r.posts.Update,
|
||||||
func(ctx fiber.Ctx) (*models.Post, error) {
|
func(ctx fiber.Ctx) (*models.Post, error) {
|
||||||
v := fiber.Params[int](ctx, "id")
|
v := fiber.Params[int](ctx, "id")
|
||||||
@@ -143,40 +143,40 @@ func (r *Routes) Register(router fiber.Router) {
|
|||||||
Body[PostForm]("form"),
|
Body[PostForm]("form"),
|
||||||
))
|
))
|
||||||
// Register routes for controller: statistics
|
// Register routes for controller: statistics
|
||||||
r.log.Debugf("Registering route: Get /admin/statistics -> statistics.statistics")
|
r.log.Debugf("Registering route: Get /admin/v1/statistics -> statistics.statistics")
|
||||||
router.Get("/admin/statistics"[len(r.Path()):], DataFunc0(
|
router.Get("/admin/v1/statistics"[len(r.Path()):], DataFunc0(
|
||||||
r.statistics.statistics,
|
r.statistics.statistics,
|
||||||
))
|
))
|
||||||
// Register routes for controller: uploads
|
// Register routes for controller: uploads
|
||||||
r.log.Debugf("Registering route: Get /admin/uploads/pre-uploaded-check/:md5.:ext -> uploads.PreUploadCheck")
|
r.log.Debugf("Registering route: Get /admin/v1/uploads/pre-uploaded-check/:md5.:ext -> uploads.PreUploadCheck")
|
||||||
router.Get("/admin/uploads/pre-uploaded-check/:md5.:ext"[len(r.Path()):], DataFunc3(
|
router.Get("/admin/v1/uploads/pre-uploaded-check/:md5.:ext"[len(r.Path()):], DataFunc3(
|
||||||
r.uploads.PreUploadCheck,
|
r.uploads.PreUploadCheck,
|
||||||
PathParam[string]("md5"),
|
PathParam[string]("md5"),
|
||||||
PathParam[string]("ext"),
|
PathParam[string]("ext"),
|
||||||
QueryParam[string]("mime"),
|
QueryParam[string]("mime"),
|
||||||
))
|
))
|
||||||
r.log.Debugf("Registering route: Post /admin/uploads/post-uploaded-action -> uploads.PostUploadedAction")
|
r.log.Debugf("Registering route: Post /admin/v1/uploads/post-uploaded-action -> uploads.PostUploadedAction")
|
||||||
router.Post("/admin/uploads/post-uploaded-action"[len(r.Path()):], Func1(
|
router.Post("/admin/v1/uploads/post-uploaded-action"[len(r.Path()):], Func1(
|
||||||
r.uploads.PostUploadedAction,
|
r.uploads.PostUploadedAction,
|
||||||
Body[PostUploadedForm]("body"),
|
Body[PostUploadedForm]("body"),
|
||||||
))
|
))
|
||||||
// Register routes for controller: users
|
// Register routes for controller: users
|
||||||
r.log.Debugf("Registering route: Get /admin/users -> users.List")
|
r.log.Debugf("Registering route: Get /admin/v1/users -> users.List")
|
||||||
router.Get("/admin/users"[len(r.Path()):], DataFunc2(
|
router.Get("/admin/v1/users"[len(r.Path()):], DataFunc2(
|
||||||
r.users.List,
|
r.users.List,
|
||||||
Query[requests.Pagination]("pagination"),
|
Query[requests.Pagination]("pagination"),
|
||||||
Query[UserListQuery]("query"),
|
Query[UserListQuery]("query"),
|
||||||
))
|
))
|
||||||
r.log.Debugf("Registering route: Get /admin/users/:id -> users.Show")
|
r.log.Debugf("Registering route: Get /admin/v1/users/:id -> users.Show")
|
||||||
router.Get("/admin/users/:id"[len(r.Path()):], DataFunc1(
|
router.Get("/admin/v1/users/:id"[len(r.Path()):], DataFunc1(
|
||||||
r.users.Show,
|
r.users.Show,
|
||||||
func(ctx fiber.Ctx) (*models.User, error) {
|
func(ctx fiber.Ctx) (*models.User, error) {
|
||||||
v := fiber.Params[int](ctx, "id")
|
v := fiber.Params[int](ctx, "id")
|
||||||
return models.UserQuery.WithContext(ctx).Where(field.NewUnsafeFieldRaw("id = ?", v)).First()
|
return models.UserQuery.WithContext(ctx).Where(field.NewUnsafeFieldRaw("id = ?", v)).First()
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
r.log.Debugf("Registering route: Get /admin/users/:id/articles -> users.Articles")
|
r.log.Debugf("Registering route: Get /admin/v1/users/:id/articles -> users.Articles")
|
||||||
router.Get("/admin/users/:id/articles"[len(r.Path()):], DataFunc2(
|
router.Get("/admin/v1/users/:id/articles"[len(r.Path()):], DataFunc2(
|
||||||
r.users.Articles,
|
r.users.Articles,
|
||||||
func(ctx fiber.Ctx) (*models.User, error) {
|
func(ctx fiber.Ctx) (*models.User, error) {
|
||||||
v := fiber.Params[int](ctx, "id")
|
v := fiber.Params[int](ctx, "id")
|
||||||
@@ -184,8 +184,8 @@ func (r *Routes) Register(router fiber.Router) {
|
|||||||
},
|
},
|
||||||
Query[requests.Pagination]("pagination"),
|
Query[requests.Pagination]("pagination"),
|
||||||
))
|
))
|
||||||
r.log.Debugf("Registering route: Post /admin/users/:id/balance -> users.Balance")
|
r.log.Debugf("Registering route: Post /admin/v1/users/:id/balance -> users.Balance")
|
||||||
router.Post("/admin/users/:id/balance"[len(r.Path()):], Func2(
|
router.Post("/admin/v1/users/:id/balance"[len(r.Path()):], Func2(
|
||||||
r.users.Balance,
|
r.users.Balance,
|
||||||
func(ctx fiber.Ctx) (*models.User, error) {
|
func(ctx fiber.Ctx) (*models.User, error) {
|
||||||
v := fiber.Params[int](ctx, "id")
|
v := fiber.Params[int](ctx, "id")
|
||||||
@@ -193,6 +193,15 @@ func (r *Routes) Register(router fiber.Router) {
|
|||||||
},
|
},
|
||||||
Body[UserBalance]("balance"),
|
Body[UserBalance]("balance"),
|
||||||
))
|
))
|
||||||
|
r.log.Debugf("Registering route: Post /admin/v1/users/:id/phone -> users.SetPhone")
|
||||||
|
router.Post("/admin/v1/users/:id/phone"[len(r.Path()):], Func2(
|
||||||
|
r.users.SetPhone,
|
||||||
|
func(ctx fiber.Ctx) (*models.User, error) {
|
||||||
|
v := fiber.Params[int](ctx, "id")
|
||||||
|
return models.UserQuery.WithContext(ctx).Where(field.NewUnsafeFieldRaw("id = ?", v)).First()
|
||||||
|
},
|
||||||
|
Body[UserPhoneForm]("form"),
|
||||||
|
))
|
||||||
|
|
||||||
r.log.Info("Successfully registered all routes")
|
r.log.Info("Successfully registered all routes")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ type StatisticsResponse struct {
|
|||||||
// @Tags Admin Statistics
|
// @Tags Admin Statistics
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {object} StatisticsResponse "成功"
|
// @Success 200 {object} StatisticsResponse "成功"
|
||||||
// @Router /admin/statistics [get]
|
// @Router /admin/v1/statistics [get]
|
||||||
func (s *statistics) statistics(ctx fiber.Ctx) (*StatisticsResponse, error) {
|
func (s *statistics) statistics(ctx fiber.Ctx) (*StatisticsResponse, error) {
|
||||||
statistics := &StatisticsResponse{}
|
statistics := &StatisticsResponse{}
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ type PreCheckResp struct {
|
|||||||
// @Param ext path string true "文件扩展名(不含点)"
|
// @Param ext path string true "文件扩展名(不含点)"
|
||||||
// @Param mime query string true "文件 MIME 类型"
|
// @Param mime query string true "文件 MIME 类型"
|
||||||
// @Success 200 {object} PreCheckResp "成功"
|
// @Success 200 {object} PreCheckResp "成功"
|
||||||
// @Router /admin/uploads/pre-uploaded-check/:md5.:ext [get]
|
// @Router /admin/v1/uploads/pre-uploaded-check/:md5.:ext [get]
|
||||||
// @Bind md5 path
|
// @Bind md5 path
|
||||||
// @Bind ext path
|
// @Bind ext path
|
||||||
// @Bind mime query
|
// @Bind mime query
|
||||||
@@ -74,7 +74,7 @@ type PostUploadedForm struct {
|
|||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param body body PostUploadedForm true "请求体"
|
// @Param body body PostUploadedForm true "请求体"
|
||||||
// @Success 200 {object} any "成功"
|
// @Success 200 {object} any "成功"
|
||||||
// @Router /admin/uploads/post-uploaded-action [post]
|
// @Router /admin/v1/uploads/post-uploaded-action [post]
|
||||||
// @Bind body body
|
// @Bind body body
|
||||||
func (up *uploads) PostUploadedAction(ctx fiber.Ctx, body *PostUploadedForm) error {
|
func (up *uploads) PostUploadedAction(ctx fiber.Ctx, body *PostUploadedForm) error {
|
||||||
m, err := services.Media.GetByHash(ctx, body.Md5)
|
m, err := services.Media.GetByHash(ctx, body.Md5)
|
||||||
|
|||||||
@@ -25,12 +25,15 @@ type users struct{}
|
|||||||
// @Param pagination query requests.Pagination false "分页参数"
|
// @Param pagination query requests.Pagination false "分页参数"
|
||||||
// @Param query query UserListQuery false "筛选条件"
|
// @Param query query UserListQuery false "筛选条件"
|
||||||
// @Success 200 {object} requests.Pager{items=models.User} "成功"
|
// @Success 200 {object} requests.Pager{items=models.User} "成功"
|
||||||
// @Router /admin/users [get]
|
// @Router /admin/v1/users [get]
|
||||||
// @Bind pagination query
|
// @Bind pagination query
|
||||||
// @Bind query query
|
// @Bind query query
|
||||||
func (ctl *users) List(ctx fiber.Ctx, pagination *requests.Pagination, query *UserListQuery) (*requests.Pager, error) {
|
func (ctl *users) List(ctx fiber.Ctx, pagination *requests.Pagination, query *UserListQuery) (*requests.Pager, error) {
|
||||||
conds := []gen.Condition{
|
conds := []gen.Condition{}
|
||||||
models.UserQuery.Username.Like(database.WrapLike(*query.Keyword)),
|
if query.Keyword != nil && *query.Keyword != "" {
|
||||||
|
conds = append(conds,
|
||||||
|
models.UserQuery.Phone.Like(database.WrapLike(*query.Keyword)),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return services.Users.List(ctx, pagination, conds...)
|
return services.Users.List(ctx, pagination, conds...)
|
||||||
}
|
}
|
||||||
@@ -42,7 +45,7 @@ func (ctl *users) List(ctx fiber.Ctx, pagination *requests.Pagination, query *Us
|
|||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path int64 true "用户 ID"
|
// @Param id path int64 true "用户 ID"
|
||||||
// @Success 200 {object} models.User "成功"
|
// @Success 200 {object} models.User "成功"
|
||||||
// @Router /admin/users/:id [get]
|
// @Router /admin/v1/users/:id [get]
|
||||||
// @Bind user path key(id) model(id)
|
// @Bind user path key(id) model(id)
|
||||||
func (ctl *users) Show(ctx fiber.Ctx, user *models.User) (*models.User, error) {
|
func (ctl *users) Show(ctx fiber.Ctx, user *models.User) (*models.User, error) {
|
||||||
return user, nil
|
return user, nil
|
||||||
@@ -56,7 +59,7 @@ func (ctl *users) Show(ctx fiber.Ctx, user *models.User) (*models.User, error) {
|
|||||||
// @Param id path int64 true "用户 ID"
|
// @Param id path int64 true "用户 ID"
|
||||||
// @Param pagination query requests.Pagination false "分页参数"
|
// @Param pagination query requests.Pagination false "分页参数"
|
||||||
// @Success 200 {object} requests.Pager{items=models.Post} "成功"
|
// @Success 200 {object} requests.Pager{items=models.Post} "成功"
|
||||||
// @Router /admin/users/:id/articles [get]
|
// @Router /admin/v1/users/:id/articles [get]
|
||||||
// @Bind user path key(id) model(id)
|
// @Bind user path key(id) model(id)
|
||||||
// @Bind pagination query
|
// @Bind pagination query
|
||||||
func (ctl *users) Articles(ctx fiber.Ctx, user *models.User, pagination *requests.Pagination) (*requests.Pager, error) {
|
func (ctl *users) Articles(ctx fiber.Ctx, user *models.User, pagination *requests.Pagination) (*requests.Pager, error) {
|
||||||
@@ -67,6 +70,10 @@ type UserBalance struct {
|
|||||||
Balance int64 `json:"balance"`
|
Balance int64 `json:"balance"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UserPhoneForm struct {
|
||||||
|
Phone string `json:"phone"` // 用户手机号(11 位数字)
|
||||||
|
}
|
||||||
|
|
||||||
// Balance
|
// Balance
|
||||||
//
|
//
|
||||||
// @Summary 调整用户余额
|
// @Summary 调整用户余额
|
||||||
@@ -76,9 +83,25 @@ type UserBalance struct {
|
|||||||
// @Param id path int64 true "用户 ID"
|
// @Param id path int64 true "用户 ID"
|
||||||
// @Param balance body UserBalance true "请求体"
|
// @Param balance body UserBalance true "请求体"
|
||||||
// @Success 200 {object} any "成功"
|
// @Success 200 {object} any "成功"
|
||||||
// @Router /admin/users/:id/balance [post]
|
// @Router /admin/v1/users/:id/balance [post]
|
||||||
// @Bind user path key(id) model(id)
|
// @Bind user path key(id) model(id)
|
||||||
// @Bind balance body
|
// @Bind balance body
|
||||||
func (ctl *users) Balance(ctx fiber.Ctx, user *models.User, balance *UserBalance) error {
|
func (ctl *users) Balance(ctx fiber.Ctx, user *models.User, balance *UserBalance) error {
|
||||||
return services.Users.AddBalance(ctx, user.ID, balance.Balance)
|
return services.Users.AddBalance(ctx, user.ID, balance.Balance)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetPhone
|
||||||
|
//
|
||||||
|
// @Summary 设置用户手机号
|
||||||
|
// @Tags Admin Users
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param id path int64 true "用户 ID"
|
||||||
|
// @Param form body UserPhoneForm true "请求体"
|
||||||
|
// @Success 200 {object} any "成功"
|
||||||
|
// @Router /admin/v1/users/:id/phone [post]
|
||||||
|
// @Bind user path key(id) model(id)
|
||||||
|
// @Bind form body
|
||||||
|
func (ctl *users) SetPhone(ctx fiber.Ctx, user *models.User, form *UserPhoneForm) error {
|
||||||
|
return services.Users.SetPhone(ctx, user.ID, form.Phone)
|
||||||
|
}
|
||||||
|
|||||||
@@ -42,9 +42,12 @@ func (m *users) List(
|
|||||||
conds ...gen.Condition,
|
conds ...gen.Condition,
|
||||||
) (*requests.Pager, error) {
|
) (*requests.Pager, error) {
|
||||||
pagination.Format()
|
pagination.Format()
|
||||||
_, query := models.UserQuery.QueryContext(ctx)
|
tbl, query := models.UserQuery.QueryContext(ctx)
|
||||||
|
|
||||||
items, cnt, err := query.Where(conds...).FindByPage(int(pagination.Offset()), int(pagination.Limit))
|
items, cnt, err := query.
|
||||||
|
Where(conds...).
|
||||||
|
Order(tbl.ID.Desc()).
|
||||||
|
FindByPage(int(pagination.Offset()), int(pagination.Limit))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "query users error")
|
return nil, errors.Wrap(err, "query users error")
|
||||||
}
|
}
|
||||||
@@ -361,3 +364,35 @@ func (m *users) ValidatePhoneCode(ctx context.Context, phone, code string) (*mod
|
|||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetPhone 管理端设置用户手机号。
|
||||||
|
func (m *users) SetPhone(ctx context.Context, userID int64, phone string) error {
|
||||||
|
phone = strings.TrimSpace(phone)
|
||||||
|
if phone == "" {
|
||||||
|
return errors.New("手机号不能为空")
|
||||||
|
}
|
||||||
|
if len(phone) != 11 {
|
||||||
|
return errors.New("手机号必须为 11 位数字")
|
||||||
|
}
|
||||||
|
for _, r := range phone {
|
||||||
|
if r < '0' || r > '9' {
|
||||||
|
return errors.New("手机号必须为 11 位数字")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 业务约束:手机号建议全局唯一(至少在本系统内),避免登录/验证身份混淆。
|
||||||
|
tbl, query := models.UserQuery.QueryContext(ctx)
|
||||||
|
_, err := query.Where(tbl.Phone.Eq(phone), tbl.ID.Neq(userID)).First()
|
||||||
|
if err == nil {
|
||||||
|
return errors.New("手机号已被其他用户占用")
|
||||||
|
}
|
||||||
|
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return errors.Wrap(err, "failed to check phone uniqueness")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 仅更新 phone 字段,避免覆盖其它字段。
|
||||||
|
if _, err := query.Where(tbl.ID.Eq(userID)).Update(tbl.Phone, phone); err != nil {
|
||||||
|
return errors.Wrap(err, "failed to update user phone")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import axios from 'axios';
|
|||||||
|
|
||||||
// Create a base axios instance
|
// Create a base axios instance
|
||||||
export const apiClient = axios.create({
|
export const apiClient = axios.create({
|
||||||
baseURL: import.meta.env.VITE_API_BASE_URL || '/v1',
|
baseURL: import.meta.env.VITE_API_BASE_URL || '',
|
||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
|||||||
@@ -2,6 +2,6 @@ import httpClient from './httpClient';
|
|||||||
|
|
||||||
export const authService = {
|
export const authService = {
|
||||||
login(username, password) {
|
login(username, password) {
|
||||||
return httpClient.post('/admin/auth', { username, password });
|
return httpClient.post('/auth', { username, password });
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import axios from 'axios';
|
|||||||
|
|
||||||
// Create axios instance with default config
|
// Create axios instance with default config
|
||||||
const httpClient = axios.create({
|
const httpClient = axios.create({
|
||||||
baseURL: '/v1',
|
baseURL: '/admin/v1',
|
||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
|||||||
@@ -2,30 +2,30 @@ import httpClient from './httpClient';
|
|||||||
|
|
||||||
export const mediaService = {
|
export const mediaService = {
|
||||||
getMedias({ page = 1, limit = 10 } = {}) {
|
getMedias({ page = 1, limit = 10 } = {}) {
|
||||||
return httpClient.get('/admin/medias', {
|
return httpClient.get('/medias', {
|
||||||
params: { page, limit }
|
params: { page, limit }
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
createMedia(mediaInfo) {
|
createMedia(mediaInfo) {
|
||||||
return httpClient.post('/admin/medias', mediaInfo);
|
return httpClient.post('/medias', mediaInfo);
|
||||||
},
|
},
|
||||||
|
|
||||||
preUploadedCheck(md5, ext, mime) {
|
preUploadedCheck(md5, ext, mime) {
|
||||||
return httpClient.get(`/admin/uploads/pre-uploaded-check/${md5}.${ext}`, {
|
return httpClient.get(`/uploads/pre-uploaded-check/${md5}.${ext}`, {
|
||||||
params: { mime }
|
params: { mime }
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
uploadedSuccess(data) {
|
uploadedSuccess(data) {
|
||||||
return httpClient.post('/admin/uploads/post-uploaded-action', data);
|
return httpClient.post('/uploads/post-uploaded-action', data);
|
||||||
},
|
},
|
||||||
|
|
||||||
getMediaPreviewUrl(id) {
|
getMediaPreviewUrl(id) {
|
||||||
const token = localStorage.getItem('__token');
|
const token = localStorage.getItem('__token');
|
||||||
return `${httpClient.defaults.baseURL}/admin/medias/${id}?token=${token}`;
|
return `${httpClient.defaults.baseURL}/medias/${id}?token=${token}`;
|
||||||
},
|
},
|
||||||
delete(id) {
|
delete(id) {
|
||||||
return httpClient.delete(`/admin/medias/${id}`);
|
return httpClient.delete(`/medias/${id}`);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -2,7 +2,7 @@ import httpClient from './httpClient';
|
|||||||
|
|
||||||
export const orderService = {
|
export const orderService = {
|
||||||
get({ page = 1, limit = 10, keyword = '' } = {}) {
|
get({ page = 1, limit = 10, keyword = '' } = {}) {
|
||||||
return httpClient.get('/admin/orders', {
|
return httpClient.get('/orders', {
|
||||||
params: {
|
params: {
|
||||||
page,
|
page,
|
||||||
limit,
|
limit,
|
||||||
@@ -11,6 +11,6 @@ export const orderService = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
refund(id) {
|
refund(id) {
|
||||||
return httpClient.post(`/admin/orders/${id}/refund`);
|
return httpClient.post(`/orders/${id}/refund`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@ import httpClient from './httpClient';
|
|||||||
|
|
||||||
export const postService = {
|
export const postService = {
|
||||||
getPosts({ page = 1, limit = 10, keyword = '' } = {}) {
|
getPosts({ page = 1, limit = 10, keyword = '' } = {}) {
|
||||||
return httpClient.get('/admin/posts', {
|
return httpClient.get('/posts', {
|
||||||
params: {
|
params: {
|
||||||
page,
|
page,
|
||||||
limit,
|
limit,
|
||||||
@@ -11,19 +11,19 @@ export const postService = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
getPost(id) {
|
getPost(id) {
|
||||||
return httpClient.get(`/admin/posts/${id}`);
|
return httpClient.get(`/posts/${id}`);
|
||||||
},
|
},
|
||||||
createPost(post) {
|
createPost(post) {
|
||||||
return httpClient.post('/admin/posts', post);
|
return httpClient.post('/posts', post);
|
||||||
},
|
},
|
||||||
|
|
||||||
updatePost(id, post) {
|
updatePost(id, post) {
|
||||||
return httpClient.put(`/admin/posts/${id}`, post);
|
return httpClient.put(`/posts/${id}`, post);
|
||||||
},
|
},
|
||||||
deletePost(id) {
|
deletePost(id) {
|
||||||
return httpClient.delete(`/admin/posts/${id}`);
|
return httpClient.delete(`/posts/${id}`);
|
||||||
},
|
},
|
||||||
sendTo(id, userId) {
|
sendTo(id, userId) {
|
||||||
return httpClient.post(`/admin/posts/${id}/send-to/${userId}`);
|
return httpClient.post(`/posts/${id}/send-to/${userId}`);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,6 @@ import httpClient from './httpClient';
|
|||||||
|
|
||||||
export const statisticsService = {
|
export const statisticsService = {
|
||||||
get() {
|
get() {
|
||||||
return httpClient.get('/admin/statistics');
|
return httpClient.get('/statistics');
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@ import httpClient from './httpClient';
|
|||||||
|
|
||||||
export const userService = {
|
export const userService = {
|
||||||
getUsers({ page = 1, limit = 10, keyword = '' } = {}) {
|
getUsers({ page = 1, limit = 10, keyword = '' } = {}) {
|
||||||
return httpClient.get('/admin/users', {
|
return httpClient.get('/users', {
|
||||||
params: {
|
params: {
|
||||||
page,
|
page,
|
||||||
limit,
|
limit,
|
||||||
@@ -11,24 +11,29 @@ export const userService = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
searchUser(id) {
|
searchUser(id) {
|
||||||
return httpClient.get(`/admin/users/${id}`);
|
return httpClient.get(`/users/${id}`);
|
||||||
},
|
},
|
||||||
userBalance(id, balance) {
|
userBalance(id, balance) {
|
||||||
return httpClient.post(`/admin/users/${id}/balance`, {
|
return httpClient.post(`/users/${id}/balance`, {
|
||||||
balance
|
balance
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
setPhone(id, phone) {
|
||||||
|
return httpClient.post(`/users/${id}/phone`, {
|
||||||
|
phone
|
||||||
|
});
|
||||||
|
},
|
||||||
getUser(id) {
|
getUser(id) {
|
||||||
return httpClient.get(`/admin/users/${id}`);
|
return httpClient.get(`/users/${id}`);
|
||||||
},
|
},
|
||||||
deleteUser(id) {
|
deleteUser(id) {
|
||||||
return httpClient.delete(`/admin/users/${id}`);
|
return httpClient.delete(`/users/${id}`);
|
||||||
},
|
},
|
||||||
getUserById(id) {
|
getUserById(id) {
|
||||||
return httpClient.get(`/admin/users/${id}`);
|
return httpClient.get(`/users/${id}`);
|
||||||
},
|
},
|
||||||
getUserArticles(userId, page, limit) {
|
getUserArticles(userId, page, limit) {
|
||||||
return httpClient.get(`/admin/users/${userId}/articles`, {
|
return httpClient.get(`/users/${userId}/articles`, {
|
||||||
params: {
|
params: {
|
||||||
page,
|
page,
|
||||||
limit,
|
limit,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import Button from 'primevue/button';
|
|||||||
import Column from 'primevue/column';
|
import Column from 'primevue/column';
|
||||||
import ConfirmDialog from 'primevue/confirmdialog';
|
import ConfirmDialog from 'primevue/confirmdialog';
|
||||||
import DataTable from 'primevue/datatable';
|
import DataTable from 'primevue/datatable';
|
||||||
|
import Dialog from 'primevue/dialog';
|
||||||
import InputText from 'primevue/inputtext';
|
import InputText from 'primevue/inputtext';
|
||||||
import ProgressSpinner from 'primevue/progressspinner';
|
import ProgressSpinner from 'primevue/progressspinner';
|
||||||
import Toast from 'primevue/toast';
|
import Toast from 'primevue/toast';
|
||||||
@@ -36,6 +37,11 @@ const users = ref({
|
|||||||
const first = ref(0);
|
const first = ref(0);
|
||||||
const rows = ref(10);
|
const rows = ref(10);
|
||||||
|
|
||||||
|
const phoneDialogVisible = ref(false);
|
||||||
|
const phoneSaving = ref(false);
|
||||||
|
const phoneTargetUser = ref(null);
|
||||||
|
const phoneInput = ref('');
|
||||||
|
|
||||||
const fetchUsers = async () => {
|
const fetchUsers = async () => {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
try {
|
try {
|
||||||
@@ -100,6 +106,36 @@ const handleRecharge = (user) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const openPhoneDialog = (user) => {
|
||||||
|
phoneTargetUser.value = user;
|
||||||
|
phoneInput.value = (user?.phone || '').toString();
|
||||||
|
phoneDialogVisible.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const normalizePhone = (v) => v.toString().replace(/\D/g, '').slice(0, 11);
|
||||||
|
|
||||||
|
const savePhone = async () => {
|
||||||
|
if (!phoneTargetUser.value) return;
|
||||||
|
const phone = normalizePhone(phoneInput.value);
|
||||||
|
if (phone.length !== 11) {
|
||||||
|
toast.add({ severity: 'error', summary: '错误', detail: '手机号必须为 11 位数字', life: 3000 });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
phoneSaving.value = true;
|
||||||
|
try {
|
||||||
|
await userService.setPhone(phoneTargetUser.value.id, phone);
|
||||||
|
toast.add({ severity: 'success', summary: '成功', detail: '手机号已更新', life: 3000 });
|
||||||
|
phoneDialogVisible.value = false;
|
||||||
|
await fetchUsers();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to set phone:', error);
|
||||||
|
toast.add({ severity: 'error', summary: '错误', detail: error?.response?.data?.message || '设置手机号失败', life: 3000 });
|
||||||
|
} finally {
|
||||||
|
phoneSaving.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchUsers();
|
fetchUsers();
|
||||||
});
|
});
|
||||||
@@ -108,6 +144,25 @@ onMounted(() => {
|
|||||||
<template>
|
<template>
|
||||||
<Toast />
|
<Toast />
|
||||||
<ConfirmDialog />
|
<ConfirmDialog />
|
||||||
|
<Dialog v-model:visible="phoneDialogVisible" modal header="设置手机号" :style="{ width: '420px' }">
|
||||||
|
<div class="space-y-3">
|
||||||
|
<div class="text-sm text-gray-600" v-if="phoneTargetUser">
|
||||||
|
用户:{{ phoneTargetUser.username }}(ID: {{ phoneTargetUser.id }})
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-sm font-medium text-gray-700 mb-1">手机号</label>
|
||||||
|
<InputText v-model="phoneInput" class="w-full" placeholder="请输入 11 位手机号" inputmode="numeric"
|
||||||
|
maxlength="11" @input="(e) => phoneInput = normalizePhone(e.target.value)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<div class="flex justify-end gap-2">
|
||||||
|
<Button label="取消" text @click="phoneDialogVisible = false" />
|
||||||
|
<Button label="保存" severity="success" :loading="phoneSaving" @click="savePhone" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<div class="flex justify-between items-center mb-6">
|
<div class="flex justify-between items-center mb-6">
|
||||||
@@ -164,7 +219,7 @@ onMounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
</Column>
|
</Column>
|
||||||
|
|
||||||
<Column field="open_id" header="OpenID" sortable></Column>
|
<Column field="phone" header="Phone" sortable></Column>
|
||||||
|
|
||||||
<Column field="status" header="状态" sortable>
|
<Column field="status" header="状态" sortable>
|
||||||
<template #body="{ data }">
|
<template #body="{ data }">
|
||||||
@@ -187,6 +242,8 @@ onMounted(() => {
|
|||||||
<div class="flex justify-center space-x-2">
|
<div class="flex justify-center space-x-2">
|
||||||
<Button icon="pi pi-credit-card" rounded text severity="success"
|
<Button icon="pi pi-credit-card" rounded text severity="success"
|
||||||
@click="handleRecharge(data)" label="充值" />
|
@click="handleRecharge(data)" label="充值" />
|
||||||
|
<Button icon="pi pi-phone" rounded text severity="info" @click="openPhoneDialog(data)"
|
||||||
|
label="设置手机号" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</Column>
|
</Column>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export default defineConfig({
|
|||||||
port: 3000,
|
port: 3000,
|
||||||
open: true,
|
open: true,
|
||||||
proxy: {
|
proxy: {
|
||||||
'/v1': 'http://localhost:8088',
|
'/admin/v1': 'http://localhost:8088',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user