package controllers import ( "strings" "time" "server/models" beego "github.com/beego/beego/v2/server/web" ) // ============================================================= // 平台官网 - 导航菜单 /platform/website/nav/* // - 友情链接 /platform/website/link/* // - 单页管理 /platform/website/page/* // 表:yz_platform_website_nav / yz_platform_website_link / yz_platform_website_page // ============================================================= type PlatformWebsiteNavController struct { beego.Controller } type platformWebsiteNavPayload struct { Pid *uint64 `json:"pid"` Title *string `json:"title"` Type *int8 `json:"type"` Path *string `json:"path"` ComponentPath *string `json:"component_path"` Icon *string `json:"icon"` Sort *int `json:"sort"` Status *int8 `json:"status"` IsVisible *int8 `json:"is_visible"` Permission *string `json:"permission"` } // normalize 按菜单类型规范化字段,并返回校验错误信息 func (p *platformWebsiteNavPayload) normalize() (path, componentPath string, errMsg string) { navType := int8(1) if p.Type != nil { navType = *p.Type } if navType < 1 || navType > 4 { return "", "", "菜单类型不正确" } if p.Path != nil { path = strings.TrimSpace(*p.Path) } if p.ComponentPath != nil { componentPath = strings.TrimSpace(*p.ComponentPath) } switch navType { case 3: // 外链 if path == "" { return "", "", "外链地址不能为空" } if !strings.HasPrefix(path, "http://") && !strings.HasPrefix(path, "https://") { return "", "", "外链地址需以 http:// 或 https:// 开头" } componentPath = "" case 2: // 页面 if path == "" { return "", "", "路由地址不能为空" } if componentPath == "" { return "", "", "页面类型需填写组件路径" } default: // 目录 / 单页 if path == "" { return "", "", "路由地址不能为空" } componentPath = "" } return path, componentPath, "" } // List GET /platform/website/nav/list — 全量平铺返回,前端自行组树 func (c *PlatformWebsiteNavController) List() { if _, ok := websiteAuth(&c.Controller); !ok { return } var rows []models.PlatformWebsiteNav if _, err := models.Orm.QueryTable(new(models.PlatformWebsiteNav)). Filter("delete_time__isnull", true). OrderBy("sort", "id"). All(&rows); err != nil { jsonErr(&c.Controller, 500, 500, "获取失败: "+err.Error()) return } websiteOK(&c.Controller, rows) } // Create POST /platform/website/nav func (c *PlatformWebsiteNavController) Create() { if _, ok := websiteAuth(&c.Controller); !ok { return } var p platformWebsiteNavPayload if !websiteBind(&c.Controller, &p) { return } if p.Title == nil || strings.TrimSpace(*p.Title) == "" { jsonErr(&c.Controller, 400, 400, "菜单名称不能为空") return } path, componentPath, errMsg := p.normalize() if errMsg != "" { jsonErr(&c.Controller, 400, 400, errMsg) return } row := models.PlatformWebsiteNav{ Title: strings.TrimSpace(*p.Title), Path: path, ComponentPath: componentPath, Status: 1, IsVisible: 1, Type: 1, } if p.Pid != nil { row.Pid = *p.Pid } if p.Type != nil { row.Type = *p.Type } if p.Icon != nil { row.Icon = strings.TrimSpace(*p.Icon) } if p.Sort != nil { row.Sort = *p.Sort } if p.Status != nil { row.Status = *p.Status } if p.IsVisible != nil { row.IsVisible = *p.IsVisible } if p.Permission != nil { row.Permission = strings.TrimSpace(*p.Permission) } id, err := models.Orm.Insert(&row) if err != nil { jsonErr(&c.Controller, 500, 500, "创建失败: "+err.Error()) return } websiteOK(&c.Controller, map[string]interface{}{"id": id}) } // Update POST /platform/website/nav/:id func (c *PlatformWebsiteNavController) Update() { if _, ok := websiteAuth(&c.Controller); !ok { return } id, ok := websiteID(&c.Controller) if !ok { return } var p platformWebsiteNavPayload if !websiteBind(&c.Controller, &p) { return } // 类型/路由/组件路径需要联合校验,先取当前记录作为基线 var current models.PlatformWebsiteNav if err := models.Orm.QueryTable(new(models.PlatformWebsiteNav)). Filter("id", id). Filter("delete_time__isnull", true). One(¤t); err != nil { jsonErr(&c.Controller, 404, 404, "菜单不存在") return } merged := platformWebsiteNavPayload{ Type: p.Type, Path: p.Path, ComponentPath: p.ComponentPath, } if merged.Type == nil { t := current.Type merged.Type = &t } if merged.Path == nil { v := current.Path merged.Path = &v } if merged.ComponentPath == nil { v := current.ComponentPath merged.ComponentPath = &v } path, componentPath, errMsg := merged.normalize() if errMsg != "" { jsonErr(&c.Controller, 400, 400, errMsg) return } up := map[string]interface{}{ "path": path, "component_path": componentPath, "type": *merged.Type, } if p.Pid != nil { if *p.Pid == id { jsonErr(&c.Controller, 400, 400, "父级菜单不能是自己") return } up["pid"] = *p.Pid } if p.Title != nil { title := strings.TrimSpace(*p.Title) if title == "" { jsonErr(&c.Controller, 400, 400, "菜单名称不能为空") return } up["title"] = title } if p.Icon != nil { up["icon"] = strings.TrimSpace(*p.Icon) } if p.Sort != nil { up["sort"] = *p.Sort } if p.Status != nil { up["status"] = *p.Status } if p.IsVisible != nil { up["is_visible"] = *p.IsVisible } if p.Permission != nil { up["permission"] = strings.TrimSpace(*p.Permission) } up["update_time"] = time.Now() n, err := models.Orm.QueryTable(new(models.PlatformWebsiteNav)). Filter("id", id). Filter("delete_time__isnull", true). Update(up) if err != nil { jsonErr(&c.Controller, 500, 500, "更新失败: "+err.Error()) return } if n == 0 { jsonErr(&c.Controller, 404, 404, "菜单不存在") return } websiteOK(&c.Controller, nil) } // Delete DELETE /platform/website/nav/:id — 有子菜单时禁止删除 func (c *PlatformWebsiteNavController) Delete() { if _, ok := websiteAuth(&c.Controller); !ok { return } id, ok := websiteID(&c.Controller) if !ok { return } child, err := models.Orm.QueryTable(new(models.PlatformWebsiteNav)). Filter("pid", id). Filter("delete_time__isnull", true). Count() if err != nil { jsonErr(&c.Controller, 500, 500, "删除失败: "+err.Error()) return } if child > 0 { jsonErr(&c.Controller, 400, 400, "该菜单下存在子菜单,请先删除子菜单") return } now := time.Now() n, err := models.Orm.QueryTable(new(models.PlatformWebsiteNav)). Filter("id", id). Filter("delete_time__isnull", true). Update(map[string]interface{}{"delete_time": now, "update_time": now}) if err != nil { jsonErr(&c.Controller, 500, 500, "删除失败: "+err.Error()) return } if n == 0 { jsonErr(&c.Controller, 404, 404, "菜单不存在") return } websiteOK(&c.Controller, nil) } // ============================================================= // 友情链接 // ============================================================= type PlatformWebsiteLinkController struct { beego.Controller } type platformWebsiteLinkPayload struct { LinkName *string `json:"link_name"` LinkURL *string `json:"link_url"` LinkLogo *string `json:"link_logo"` Description *string `json:"description"` Sort *int `json:"sort"` Status *int8 `json:"status"` } // List GET /platform/website/link/list?page&pageSize(limit)&keyword&status func (c *PlatformWebsiteLinkController) List() { if _, ok := websiteAuth(&c.Controller); !ok { return } page, pageSize := websitePaging(&c.Controller) qs := models.Orm.QueryTable(new(models.PlatformWebsiteLink)). Filter("delete_time__isnull", true) if kw := strings.TrimSpace(c.GetString("keyword")); kw != "" { qs = qs.Filter("link_name__icontains", kw) } if st := websiteStatusParam(&c.Controller); st >= 0 { qs = qs.Filter("status", st) } total, err := qs.Count() if err != nil { jsonErr(&c.Controller, 500, 500, "获取失败: "+err.Error()) return } var rows []models.PlatformWebsiteLink if _, err = qs.OrderBy("sort", "-id").Limit(pageSize, (page-1)*pageSize).All(&rows); err != nil { jsonErr(&c.Controller, 500, 500, "获取失败: "+err.Error()) return } websiteOK(&c.Controller, map[string]interface{}{"list": rows, "total": total}) } // All GET /platform/website/link/all — 全量(仅启用),供官网/下拉使用 func (c *PlatformWebsiteLinkController) All() { if _, ok := websiteAuth(&c.Controller); !ok { return } var rows []models.PlatformWebsiteLink if _, err := models.Orm.QueryTable(new(models.PlatformWebsiteLink)). Filter("delete_time__isnull", true). Filter("status", 1). OrderBy("sort", "-id"). All(&rows); err != nil { jsonErr(&c.Controller, 500, 500, "获取失败: "+err.Error()) return } websiteOK(&c.Controller, rows) } // Create POST /platform/website/link func (c *PlatformWebsiteLinkController) Create() { if _, ok := websiteAuth(&c.Controller); !ok { return } var p platformWebsiteLinkPayload if !websiteBind(&c.Controller, &p) { return } if p.LinkName == nil || strings.TrimSpace(*p.LinkName) == "" { jsonErr(&c.Controller, 400, 400, "链接名称不能为空") return } if p.LinkURL == nil || strings.TrimSpace(*p.LinkURL) == "" { jsonErr(&c.Controller, 400, 400, "链接地址不能为空") return } row := models.PlatformWebsiteLink{ LinkName: strings.TrimSpace(*p.LinkName), LinkURL: strings.TrimSpace(*p.LinkURL), Status: 1, } if p.LinkLogo != nil { row.LinkLogo = strings.ReplaceAll(*p.LinkLogo, "\\", "/") } if p.Description != nil { row.Description = *p.Description } if p.Sort != nil { row.Sort = *p.Sort } if p.Status != nil { row.Status = *p.Status } id, err := models.Orm.Insert(&row) if err != nil { jsonErr(&c.Controller, 500, 500, "创建失败: "+err.Error()) return } websiteOK(&c.Controller, map[string]interface{}{"id": id}) } // Update PUT /platform/website/link/:id — 也支持只传部分字段(如仅 status) func (c *PlatformWebsiteLinkController) Update() { if _, ok := websiteAuth(&c.Controller); !ok { return } id, ok := websiteID(&c.Controller) if !ok { return } var p platformWebsiteLinkPayload if !websiteBind(&c.Controller, &p) { return } up := map[string]interface{}{} if p.LinkName != nil { name := strings.TrimSpace(*p.LinkName) if name == "" { jsonErr(&c.Controller, 400, 400, "链接名称不能为空") return } up["link_name"] = name } if p.LinkURL != nil { url := strings.TrimSpace(*p.LinkURL) if url == "" { jsonErr(&c.Controller, 400, 400, "链接地址不能为空") return } up["link_url"] = url } if p.LinkLogo != nil { up["link_logo"] = strings.ReplaceAll(*p.LinkLogo, "\\", "/") } if p.Description != nil { up["description"] = *p.Description } if p.Sort != nil { up["sort"] = *p.Sort } if p.Status != nil { up["status"] = *p.Status } if len(up) == 0 { jsonErr(&c.Controller, 400, 400, "无更新字段") return } up["update_time"] = time.Now() n, err := models.Orm.QueryTable(new(models.PlatformWebsiteLink)). Filter("id", id). Filter("delete_time__isnull", true). Update(up) if err != nil { jsonErr(&c.Controller, 500, 500, "更新失败: "+err.Error()) return } if n == 0 { jsonErr(&c.Controller, 404, 404, "链接不存在") return } websiteOK(&c.Controller, nil) } // Delete DELETE /platform/website/link/:id func (c *PlatformWebsiteLinkController) Delete() { if _, ok := websiteAuth(&c.Controller); !ok { return } id, ok := websiteID(&c.Controller) if !ok { return } now := time.Now() n, err := models.Orm.QueryTable(new(models.PlatformWebsiteLink)). Filter("id", id). Filter("delete_time__isnull", true). Update(map[string]interface{}{"delete_time": now, "update_time": now}) if err != nil { jsonErr(&c.Controller, 500, 500, "删除失败: "+err.Error()) return } if n == 0 { jsonErr(&c.Controller, 404, 404, "链接不存在") return } websiteOK(&c.Controller, nil) } // BatchDelete POST /platform/website/link/batchdelete — body { ids: [] } func (c *PlatformWebsiteLinkController) BatchDelete() { if _, ok := websiteAuth(&c.Controller); !ok { return } var raw struct { IDs []uint64 `json:"ids"` } if !websiteBind(&c.Controller, &raw) || len(raw.IDs) == 0 { jsonErr(&c.Controller, 400, 400, "请选择要删除的链接") return } now := time.Now() if _, err := models.Orm.QueryTable(new(models.PlatformWebsiteLink)). Filter("id__in", raw.IDs). Filter("delete_time__isnull", true). Update(map[string]interface{}{"delete_time": now, "update_time": now}); err != nil { jsonErr(&c.Controller, 500, 500, "删除失败: "+err.Error()) return } websiteOK(&c.Controller, nil) } // ============================================================= // 单页管理 // ============================================================= type PlatformWebsitePageController struct { beego.Controller } type platformWebsitePagePayload struct { Title *string `json:"title"` Path *string `json:"path"` Content *string `json:"content"` Sort *int `json:"sort"` Status *int8 `json:"status"` } // normalizePath 统一去掉前导斜杠,与前端提交约定保持一致 func normalizePath(raw string) string { return strings.Trim(strings.TrimSpace(raw), "/") } // All GET /platform/website/page/all — 全量返回 func (c *PlatformWebsitePageController) All() { if _, ok := websiteAuth(&c.Controller); !ok { return } var rows []models.PlatformWebsitePage if _, err := models.Orm.QueryTable(new(models.PlatformWebsitePage)). Filter("delete_time__isnull", true). OrderBy("sort", "id"). All(&rows); err != nil { jsonErr(&c.Controller, 500, 500, "获取失败: "+err.Error()) return } websiteOK(&c.Controller, rows) } // Get GET /platform/website/page/:id func (c *PlatformWebsitePageController) Get() { if _, ok := websiteAuth(&c.Controller); !ok { return } id, ok := websiteID(&c.Controller) if !ok { return } var row models.PlatformWebsitePage if err := models.Orm.QueryTable(new(models.PlatformWebsitePage)). Filter("id", id). Filter("delete_time__isnull", true). One(&row); err != nil { jsonErr(&c.Controller, 404, 404, "单页不存在") return } websiteOK(&c.Controller, row) } // Create POST /platform/website/page func (c *PlatformWebsitePageController) Create() { if _, ok := websiteAuth(&c.Controller); !ok { return } var p platformWebsitePagePayload if !websiteBind(&c.Controller, &p) { return } if p.Title == nil || strings.TrimSpace(*p.Title) == "" { jsonErr(&c.Controller, 400, 400, "单页标题不能为空") return } path := "" if p.Path != nil { path = normalizePath(*p.Path) } if path == "" { jsonErr(&c.Controller, 400, 400, "路由不能为空") return } exist, err := models.Orm.QueryTable(new(models.PlatformWebsitePage)). Filter("path", path). Filter("delete_time__isnull", true). Count() if err != nil { jsonErr(&c.Controller, 500, 500, "创建失败: "+err.Error()) return } if exist > 0 { jsonErr(&c.Controller, 400, 400, "该路由已存在") return } row := models.PlatformWebsitePage{ Title: strings.TrimSpace(*p.Title), Path: path, Status: 1, } if p.Content != nil { row.Content = *p.Content } if p.Sort != nil { row.Sort = *p.Sort } if p.Status != nil { row.Status = *p.Status } id, err := models.Orm.Insert(&row) if err != nil { jsonErr(&c.Controller, 500, 500, "创建失败: "+err.Error()) return } websiteOK(&c.Controller, map[string]interface{}{"id": id}) } // Update POST /platform/website/page/:id func (c *PlatformWebsitePageController) Update() { if _, ok := websiteAuth(&c.Controller); !ok { return } id, ok := websiteID(&c.Controller) if !ok { return } var p platformWebsitePagePayload if !websiteBind(&c.Controller, &p) { return } up := map[string]interface{}{} if p.Title != nil { title := strings.TrimSpace(*p.Title) if title == "" { jsonErr(&c.Controller, 400, 400, "单页标题不能为空") return } up["title"] = title } if p.Path != nil { path := normalizePath(*p.Path) if path == "" { jsonErr(&c.Controller, 400, 400, "路由不能为空") return } dup, err := models.Orm.QueryTable(new(models.PlatformWebsitePage)). Filter("path", path). Filter("delete_time__isnull", true). Exclude("id", id). Count() if err != nil { jsonErr(&c.Controller, 500, 500, "更新失败: "+err.Error()) return } if dup > 0 { jsonErr(&c.Controller, 400, 400, "该路由已存在") return } up["path"] = path } if p.Content != nil { up["content"] = *p.Content } if p.Sort != nil { up["sort"] = *p.Sort } if p.Status != nil { up["status"] = *p.Status } if len(up) == 0 { jsonErr(&c.Controller, 400, 400, "无更新字段") return } up["update_time"] = time.Now() n, err := models.Orm.QueryTable(new(models.PlatformWebsitePage)). Filter("id", id). Filter("delete_time__isnull", true). Update(up) if err != nil { jsonErr(&c.Controller, 500, 500, "更新失败: "+err.Error()) return } if n == 0 { jsonErr(&c.Controller, 404, 404, "单页不存在") return } websiteOK(&c.Controller, nil) } // Delete DELETE /platform/website/page/:id func (c *PlatformWebsitePageController) Delete() { if _, ok := websiteAuth(&c.Controller); !ok { return } id, ok := websiteID(&c.Controller) if !ok { return } now := time.Now() n, err := models.Orm.QueryTable(new(models.PlatformWebsitePage)). Filter("id", id). Filter("delete_time__isnull", true). Update(map[string]interface{}{"delete_time": now, "update_time": now}) if err != nil { jsonErr(&c.Controller, 500, 500, "删除失败: "+err.Error()) return } if n == 0 { jsonErr(&c.Controller, 404, 404, "单页不存在") return } websiteOK(&c.Controller, nil) }