fix ui
All checks were successful
Deploy on Master Change / deploy (push) Successful in 44s

This commit is contained in:
2026-07-01 15:08:31 +07:00
parent 7a9c7a93ff
commit 7e84ddeaf9
8 changed files with 443 additions and 20 deletions

View File

@@ -68,6 +68,7 @@ func AutoMigrate(db *gorm.DB) error {
&models.SystemSetting{},
&models.GuideLink{},
&models.AppDownload{},
&models.AppGuide{},
); err != nil {
return err
}

View File

@@ -0,0 +1,129 @@
package handlers
import (
"strconv"
"server/internal/models"
"github.com/gofiber/fiber/v2"
"gorm.io/gorm"
)
// GET /api/public/app-guides
func ListAppGuidesPublicHandler(db *gorm.DB) fiber.Handler {
return func(c *fiber.Ctx) error {
var guides []models.AppGuide
if err := db.Order("created_at desc").Find(&guides).Error; err != nil {
return c.Status(500).JSON(fiber.Map{"error": "Không thể tải danh sách tài liệu hướng dẫn"})
}
return c.JSON(fiber.Map{"data": guides})
}
}
// GET /api/app-guides
func ListAppGuidesHandler(db *gorm.DB) fiber.Handler {
return func(c *fiber.Ctx) error {
var guides []models.AppGuide
if err := db.Order("created_at desc").Find(&guides).Error; err != nil {
return c.Status(500).JSON(fiber.Map{"error": "Không thể tải danh sách tài liệu hướng dẫn"})
}
return c.JSON(fiber.Map{"data": guides})
}
}
// POST /api/app-guides
func CreateAppGuideHandler(db *gorm.DB) fiber.Handler {
return func(c *fiber.Ctx) error {
if !isSuperAdmin(c) {
return c.Status(403).JSON(fiber.Map{"error": "Bạn không có quyền thực hiện chức năng này"})
}
type Request struct {
Title string `json:"title"`
URL string `json:"url"`
}
var req Request
if err := c.BodyParser(&req); err != nil {
return c.Status(400).JSON(fiber.Map{"error": "Invalid request body"})
}
if req.Title == "" || req.URL == "" {
return c.Status(400).JSON(fiber.Map{"error": "Tiêu đề và đường dẫn không được để trống"})
}
guide := models.AppGuide{
Title: req.Title,
URL: req.URL,
}
if err := db.Create(&guide).Error; err != nil {
return c.Status(500).JSON(fiber.Map{"error": "Lưu tài liệu hướng dẫn thất bại"})
}
return c.JSON(fiber.Map{"ok": true, "data": guide})
}
}
// PUT /api/app-guides/:id
func UpdateAppGuideHandler(db *gorm.DB) fiber.Handler {
return func(c *fiber.Ctx) error {
if !isSuperAdmin(c) {
return c.Status(403).JSON(fiber.Map{"error": "Bạn không có quyền thực hiện chức năng này"})
}
idParam := c.Params("id")
id, err := strconv.ParseUint(idParam, 10, 32)
if err != nil {
return c.Status(400).JSON(fiber.Map{"error": "Invalid ID"})
}
var guide models.AppGuide
if err := db.First(&guide, uint(id)).Error; err != nil {
return c.Status(404).JSON(fiber.Map{"error": "Không tìm thấy tài liệu hướng dẫn"})
}
type Request struct {
Title string `json:"title"`
URL string `json:"url"`
}
var req Request
if err := c.BodyParser(&req); err != nil {
return c.Status(400).JSON(fiber.Map{"error": "Invalid request body"})
}
if req.Title == "" || req.URL == "" {
return c.Status(400).JSON(fiber.Map{"error": "Tiêu đề và đường dẫn không được để trống"})
}
guide.Title = req.Title
guide.URL = req.URL
if err := db.Save(&guide).Error; err != nil {
return c.Status(500).JSON(fiber.Map{"error": "Cập nhật tài liệu hướng dẫn thất bại"})
}
return c.JSON(fiber.Map{"ok": true, "data": guide})
}
}
// DELETE /api/app-guides/:id
func DeleteAppGuideHandler(db *gorm.DB) fiber.Handler {
return func(c *fiber.Ctx) error {
if !isSuperAdmin(c) {
return c.Status(403).JSON(fiber.Map{"error": "Bạn không có quyền thực hiện chức năng này"})
}
idParam := c.Params("id")
id, err := strconv.ParseUint(idParam, 10, 32)
if err != nil {
return c.Status(400).JSON(fiber.Map{"error": "Invalid ID"})
}
var guide models.AppGuide
if err := db.First(&guide, uint(id)).Error; err != nil {
return c.Status(404).JSON(fiber.Map{"error": "Không tìm thấy tài liệu hướng dẫn"})
}
if err := db.Delete(&guide).Error; err != nil {
return c.Status(500).JSON(fiber.Map{"error": "Xóa tài liệu hướng dẫn thất bại"})
}
return c.JSON(fiber.Map{"ok": true})
}
}

View File

@@ -212,4 +212,15 @@ type AppDownload struct {
func (AppDownload) TableName() string { return "app_downloads" }
// AppGuide đại diện cho tài liệu/video hướng dẫn ứng dụng dành cho sinh viên
type AppGuide struct {
ID uint `gorm:"primaryKey" json:"id"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
Title string `gorm:"column:title;size:512;not null" json:"title"`
URL string `gorm:"column:url;size:1024;not null" json:"url"`
}
func (AppGuide) TableName() string { return "app_guides" }

View File

@@ -109,6 +109,7 @@ func main() {
api.Get("/public/app-downloads", handlers.ListAppDownloadsPublicHandler(gormDB))
api.Get("/public/guide-links", handlers.ListGuideLinksPublicHandler(gormDB))
api.Get("/public/app-guides", handlers.ListAppGuidesPublicHandler(gormDB))
// Management — yêu cầu đăng nhập staff
staff := api.Group("", middleware.RequireStaff())
@@ -215,6 +216,11 @@ func main() {
staff.Put("/app-downloads/:id", handlers.UpdateAppDownloadHandler(gormDB))
staff.Delete("/app-downloads/:id", handlers.DeleteAppDownloadHandler(gormDB))
staff.Get("/app-guides", handlers.ListAppGuidesHandler(gormDB))
staff.Post("/app-guides", handlers.CreateAppGuideHandler(gormDB))
staff.Put("/app-guides/:id", handlers.UpdateAppGuideHandler(gormDB))
staff.Delete("/app-guides/:id", handlers.DeleteAppGuideHandler(gormDB))
go func() {
ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop()