增加网站管理功能
This commit is contained in:
@@ -0,0 +1,392 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"server/models"
|
||||
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
"github.com/beego/beego/v2/client/orm"
|
||||
)
|
||||
|
||||
// =============================================================
|
||||
// 官网前台只读接口:平台官网内容(yz_platform_website_*)
|
||||
//
|
||||
// 供 website SPA 调用,无需登录(与 /site/setting 同级)。
|
||||
// 数据由 platform 端「官网管理」模块维护;仅返回「已发布」的内容。
|
||||
//
|
||||
// GET /site/news 新闻列表(分页 / 分类 / 关键词)
|
||||
// GET /site/news/categories 新闻分类 + 各分类已发布数量
|
||||
// GET /site/news/:id 新闻详情(正文为 HTML)
|
||||
// GET /site/news/:id/related 相关推荐
|
||||
// POST /site/news/:id/view 浏览量 +1
|
||||
//
|
||||
// 说明:列表与详情中返回的 image 形如 /uploads/xxx,由前端拼接接口域名。
|
||||
// =============================================================
|
||||
|
||||
// 文章状态:与 platform 端「文章管理」保持一致
|
||||
const (
|
||||
articleStatusPublished int8 = 2
|
||||
)
|
||||
|
||||
// 导航菜单类型:与 platform 端「导航菜单」保持一致
|
||||
const (
|
||||
navTypeExternal int8 = 3
|
||||
)
|
||||
|
||||
type IndexWebsiteController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (c *IndexWebsiteController) ok(data interface{}) {
|
||||
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": data}
|
||||
_ = c.ServeJSON()
|
||||
}
|
||||
|
||||
func (c *IndexWebsiteController) fail(httpStatus, bizCode int, msg string) {
|
||||
c.Ctx.Output.SetStatus(httpStatus)
|
||||
c.Data["json"] = map[string]interface{}{"code": bizCode, "msg": msg}
|
||||
_ = c.ServeJSON()
|
||||
}
|
||||
|
||||
// publishedArticleQuery 已发布文章的基础查询条件
|
||||
func publishedArticleCond() *orm.Condition {
|
||||
return orm.NewCondition().
|
||||
And("delete_time__isnull", true).
|
||||
And("status", articleStatusPublished)
|
||||
}
|
||||
|
||||
// articleListItem 列表项(不含正文,减小响应体)
|
||||
// image 与 category_image 分开返回,由前端决定兜底:文章没有封面时用所属分类的图片。
|
||||
func articleListItem(row models.PlatformWebsiteArticle, cate models.PlatformWebsiteCategory, tags []string) map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"id": row.ID,
|
||||
"title": row.Title,
|
||||
"summary": row.Desc,
|
||||
"image": row.Image,
|
||||
"author": row.Author,
|
||||
"views": row.Views,
|
||||
"top": row.Top,
|
||||
"recommend": row.Recommend,
|
||||
"date": row.PublishTime,
|
||||
"category_id": row.CateID,
|
||||
"category_name": cate.Name,
|
||||
"category_desc": cate.Desc,
|
||||
"category_image": cate.Image,
|
||||
"tags": tags,
|
||||
}
|
||||
}
|
||||
|
||||
// navNode 导航菜单节点(递归结构,供页头渲染)
|
||||
type navNode struct {
|
||||
ID uint64 `json:"id"`
|
||||
Pid uint64 `json:"pid"`
|
||||
Title string `json:"title"`
|
||||
Type int8 `json:"type"` // 1 目录 / 2 页面 / 3 外链 / 4 单页
|
||||
Path string `json:"path"`
|
||||
Icon string `json:"icon"`
|
||||
External bool `json:"external"`
|
||||
Children []*navNode `json:"children"`
|
||||
}
|
||||
|
||||
// Nav GET /site/nav
|
||||
// 官网页头导航:仅返回启用且显示中的菜单项,按 pid 组树。
|
||||
// 父级被隐藏/禁用时其子项一并隐藏,避免出现无归属的顶层菜单。
|
||||
func (c *IndexWebsiteController) Nav() {
|
||||
var rows []models.PlatformWebsiteNav
|
||||
if _, err := models.Orm.QueryTable(new(models.PlatformWebsiteNav)).
|
||||
Filter("delete_time__isnull", true).
|
||||
Filter("status", 1).
|
||||
Filter("is_visible", 1).
|
||||
OrderBy("sort", "id").
|
||||
All(&rows, "ID", "Pid", "Title", "Type", "Path", "Icon"); err != nil {
|
||||
c.fail(500, 500, "获取导航菜单失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
nodes := make(map[uint64]*navNode, len(rows))
|
||||
order := make([]uint64, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
nodes[r.ID] = &navNode{
|
||||
ID: r.ID,
|
||||
Pid: r.Pid,
|
||||
Title: r.Title,
|
||||
Type: r.Type,
|
||||
Path: r.Path,
|
||||
Icon: r.Icon,
|
||||
External: r.Type == navTypeExternal || strings.HasPrefix(r.Path, "http://") || strings.HasPrefix(r.Path, "https://"),
|
||||
Children: []*navNode{},
|
||||
}
|
||||
order = append(order, r.ID)
|
||||
}
|
||||
|
||||
roots := make([]*navNode, 0, len(rows))
|
||||
for _, id := range order {
|
||||
node := nodes[id]
|
||||
if node.Pid == 0 {
|
||||
roots = append(roots, node)
|
||||
continue
|
||||
}
|
||||
parent, ok := nodes[node.Pid]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
parent.Children = append(parent.Children, node)
|
||||
}
|
||||
|
||||
c.ok(map[string]interface{}{"list": roots})
|
||||
}
|
||||
|
||||
// News GET /site/news?page=&pageSize=&category=&keyword=
|
||||
func (c *IndexWebsiteController) News() {
|
||||
page, _ := c.GetInt("page", 1)
|
||||
pageSize, _ := c.GetInt("pageSize", 6)
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize < 1 {
|
||||
pageSize = 6
|
||||
}
|
||||
if pageSize > 50 {
|
||||
pageSize = 50
|
||||
}
|
||||
|
||||
cond := publishedArticleCond()
|
||||
if cateStr := strings.TrimSpace(c.GetString("category")); cateStr != "" {
|
||||
if cid, err := strconv.ParseUint(cateStr, 10, 64); err == nil && cid > 0 {
|
||||
cond = cond.And("cate_id", cid)
|
||||
}
|
||||
}
|
||||
if kw := strings.TrimSpace(c.GetString("keyword")); kw != "" {
|
||||
cond = cond.AndCond(orm.NewCondition().
|
||||
Or("title__icontains", kw).
|
||||
Or("desc__icontains", kw))
|
||||
}
|
||||
|
||||
qs := models.Orm.QueryTable(new(models.PlatformWebsiteArticle)).SetCond(cond)
|
||||
total, err := qs.Count()
|
||||
if err != nil {
|
||||
c.fail(500, 500, "获取新闻列表失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var rows []models.PlatformWebsiteArticle
|
||||
if _, err = qs.OrderBy("-top", "-recommend", "-publish_time", "-id").
|
||||
Limit(pageSize, (page-1)*pageSize).
|
||||
All(&rows, "ID", "CateID", "Title", "Author", "Desc", "Image",
|
||||
"Status", "Top", "Recommend", "Views", "PublishTime"); err != nil {
|
||||
c.fail(500, 500, "获取新闻列表失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
articleIDs := make([]uint64, 0, len(rows))
|
||||
cateIDs := make([]uint64, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
articleIDs = append(articleIDs, r.ID)
|
||||
if r.CateID > 0 {
|
||||
cateIDs = append(cateIDs, r.CateID)
|
||||
}
|
||||
}
|
||||
cateMap := models.PlatformWebsiteCategoryMap(cateIDs)
|
||||
tagMap := models.PlatformWebsiteArticleTagNameMap(articleIDs)
|
||||
|
||||
list := make([]map[string]interface{}, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
tags := tagMap[r.ID]
|
||||
if tags == nil {
|
||||
tags = []string{}
|
||||
}
|
||||
list = append(list, articleListItem(r, cateMap[r.CateID], tags))
|
||||
}
|
||||
|
||||
totalPages := int((total + int64(pageSize) - 1) / int64(pageSize))
|
||||
if totalPages < 1 {
|
||||
totalPages = 1
|
||||
}
|
||||
|
||||
c.ok(map[string]interface{}{
|
||||
"list": list,
|
||||
"total": total,
|
||||
"page": page,
|
||||
"pageSize": pageSize,
|
||||
"totalPages": totalPages,
|
||||
})
|
||||
}
|
||||
|
||||
// NewsCategories GET /site/news/categories
|
||||
// 返回启用中的分类及各自已发布文章数量,供列表页筛选条展示。
|
||||
func (c *IndexWebsiteController) NewsCategories() {
|
||||
var cates []models.PlatformWebsiteCategory
|
||||
if _, err := models.Orm.QueryTable(new(models.PlatformWebsiteCategory)).
|
||||
Filter("delete_time__isnull", true).
|
||||
OrderBy("sort", "id").
|
||||
All(&cates, "ID", "Name", "Desc", "Image", "Sort"); err != nil {
|
||||
c.fail(500, 500, "获取分类失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
list := make([]map[string]interface{}, 0, len(cates))
|
||||
for _, item := range cates {
|
||||
cnt, _ := models.Orm.QueryTable(new(models.PlatformWebsiteArticle)).
|
||||
Filter("delete_time__isnull", true).
|
||||
Filter("status", articleStatusPublished).
|
||||
Filter("cate_id", item.ID).
|
||||
Count()
|
||||
list = append(list, map[string]interface{}{
|
||||
"id": item.ID,
|
||||
"name": item.Name,
|
||||
"desc": item.Desc,
|
||||
"image": item.Image,
|
||||
"count": cnt,
|
||||
})
|
||||
}
|
||||
|
||||
total, _ := models.Orm.QueryTable(new(models.PlatformWebsiteArticle)).
|
||||
SetCond(publishedArticleCond()).
|
||||
Count()
|
||||
|
||||
c.ok(map[string]interface{}{"list": list, "total": total})
|
||||
}
|
||||
|
||||
// NewsDetail GET /site/news/:id
|
||||
func (c *IndexWebsiteController) NewsDetail() {
|
||||
id, err := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
c.fail(400, 400, "无效的内容ID")
|
||||
return
|
||||
}
|
||||
|
||||
var row models.PlatformWebsiteArticle
|
||||
if err = models.Orm.QueryTable(new(models.PlatformWebsiteArticle)).
|
||||
SetCond(publishedArticleCond()).
|
||||
Filter("id", id).
|
||||
One(&row); err != nil {
|
||||
c.fail(404, 404, "内容不存在或已下线")
|
||||
return
|
||||
}
|
||||
|
||||
cate := models.PlatformWebsiteCategoryMap([]uint64{row.CateID})[row.CateID]
|
||||
tags := models.PlatformWebsiteArticleTagNameMap([]uint64{row.ID})[row.ID]
|
||||
if tags == nil {
|
||||
tags = []string{}
|
||||
}
|
||||
|
||||
c.ok(map[string]interface{}{
|
||||
"id": row.ID,
|
||||
"title": row.Title,
|
||||
"summary": row.Desc,
|
||||
"image": row.Image,
|
||||
"content": row.Content,
|
||||
"author": row.Author,
|
||||
"views": row.Views,
|
||||
"date": row.PublishTime,
|
||||
"category_id": row.CateID,
|
||||
"category_name": cate.Name,
|
||||
"category_desc": cate.Desc,
|
||||
"category_image": cate.Image,
|
||||
"tags": tags,
|
||||
})
|
||||
}
|
||||
|
||||
// NewsRelated GET /site/news/:id/related?limit=3
|
||||
// 同分类优先,不足时用其它分类补齐。
|
||||
func (c *IndexWebsiteController) NewsRelated() {
|
||||
id, err := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
c.fail(400, 400, "无效的内容ID")
|
||||
return
|
||||
}
|
||||
limit, _ := c.GetInt("limit", 3)
|
||||
if limit < 1 || limit > 12 {
|
||||
limit = 3
|
||||
}
|
||||
|
||||
var current models.PlatformWebsiteArticle
|
||||
if err = models.Orm.QueryTable(new(models.PlatformWebsiteArticle)).
|
||||
SetCond(publishedArticleCond()).
|
||||
Filter("id", id).
|
||||
One(¤t); err != nil {
|
||||
// 当前内容不存在时返回空列表,由前端展示"暂无推荐"
|
||||
c.ok(map[string]interface{}{"list": []interface{}{}})
|
||||
return
|
||||
}
|
||||
|
||||
pick := make([]models.PlatformWebsiteArticle, 0, limit)
|
||||
seen := map[uint64]bool{id: true}
|
||||
|
||||
// 1. 同分类
|
||||
if current.CateID > 0 {
|
||||
var same []models.PlatformWebsiteArticle
|
||||
_, _ = models.Orm.QueryTable(new(models.PlatformWebsiteArticle)).
|
||||
SetCond(publishedArticleCond()).
|
||||
Filter("cate_id", current.CateID).
|
||||
Exclude("id", id).
|
||||
OrderBy("-publish_time", "-id").
|
||||
Limit(limit).
|
||||
All(&same, "ID", "CateID", "Title", "Author", "Desc", "Image",
|
||||
"Top", "Recommend", "Views", "PublishTime")
|
||||
for _, r := range same {
|
||||
if len(pick) >= limit {
|
||||
break
|
||||
}
|
||||
pick = append(pick, r)
|
||||
seen[r.ID] = true
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 不足时用最新其它文章补齐
|
||||
if len(pick) < limit {
|
||||
ids := make([]uint64, 0, len(seen))
|
||||
for k := range seen {
|
||||
ids = append(ids, k)
|
||||
}
|
||||
var others []models.PlatformWebsiteArticle
|
||||
_, _ = models.Orm.QueryTable(new(models.PlatformWebsiteArticle)).
|
||||
SetCond(publishedArticleCond()).
|
||||
Exclude("id__in", ids).
|
||||
OrderBy("-publish_time", "-id").
|
||||
Limit(limit - len(pick)).
|
||||
All(&others, "ID", "CateID", "Title", "Author", "Desc", "Image",
|
||||
"Top", "Recommend", "Views", "PublishTime")
|
||||
pick = append(pick, others...)
|
||||
}
|
||||
|
||||
articleIDs := make([]uint64, 0, len(pick))
|
||||
cateIDs := make([]uint64, 0, len(pick))
|
||||
for _, r := range pick {
|
||||
articleIDs = append(articleIDs, r.ID)
|
||||
if r.CateID > 0 {
|
||||
cateIDs = append(cateIDs, r.CateID)
|
||||
}
|
||||
}
|
||||
cateMap := models.PlatformWebsiteCategoryMap(cateIDs)
|
||||
tagMap := models.PlatformWebsiteArticleTagNameMap(articleIDs)
|
||||
|
||||
list := make([]map[string]interface{}, 0, len(pick))
|
||||
for _, r := range pick {
|
||||
tags := tagMap[r.ID]
|
||||
if tags == nil {
|
||||
tags = []string{}
|
||||
}
|
||||
list = append(list, articleListItem(r, cateMap[r.CateID], tags))
|
||||
}
|
||||
c.ok(map[string]interface{}{"list": list})
|
||||
}
|
||||
|
||||
// NewsView POST /site/news/:id/view — 浏览量 +1(详情页打开时调用)
|
||||
func (c *IndexWebsiteController) NewsView() {
|
||||
id, err := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
c.fail(400, 400, "无效的内容ID")
|
||||
return
|
||||
}
|
||||
if _, err = models.Orm.Raw(
|
||||
"UPDATE yz_platform_website_article SET views = views + 1 WHERE id = ? AND status = ? AND delete_time IS NULL",
|
||||
id, articleStatusPublished,
|
||||
).Exec(); err != nil {
|
||||
c.fail(500, 500, "更新浏览量失败")
|
||||
return
|
||||
}
|
||||
c.ok(nil)
|
||||
}
|
||||
@@ -287,6 +287,34 @@ type platformRenameCateBody struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// protectedFileCateNames 受保护的文件分组名称(平台端)。
|
||||
//
|
||||
// 这些分组由功能模块按「名称」定位,删除或改名都会导致模块找不到分组:
|
||||
// - 删除:素材被分散到未分类,且模块会重新补建一个空分组;
|
||||
// - 改名:模块按名称找不到旧分组,会新建一个同名分组,历史文件被遗留在旧分组里。
|
||||
// 因此统一禁止删除/重命名,需要调整时走 SQL 人工处理。
|
||||
//
|
||||
// 官网素材 官网管理(platform/src/views/website)所有上传的归属分组
|
||||
// (见 platform/src/utils/websiteUpload.js)
|
||||
// appsupgrade 软件升级安装包分组(见 platform/src/views/platform/softwareupgrade)
|
||||
// 图片 平台预留的图片分组,作为官网/后台配图的固定归档位
|
||||
var protectedFileCateNames = []string{
|
||||
"官网素材",
|
||||
"appsupgrade",
|
||||
"图片",
|
||||
}
|
||||
|
||||
// isProtectedFileCate 判断分组是否为受保护的系统默认分组
|
||||
func isProtectedFileCate(name string) bool {
|
||||
name = strings.TrimSpace(name)
|
||||
for _, n := range protectedFileCateNames {
|
||||
if n == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RenameFileCate POST /platform/renamefilecate/:id
|
||||
func (c *PlatformFileController) RenameFileCate() {
|
||||
claims, err := c.platformClaims()
|
||||
@@ -316,6 +344,22 @@ func (c *PlatformFileController) RenameFileCate() {
|
||||
c.jsonErr(400, 400, "分组名称不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
// 受保护分组禁止改名:功能模块按名称定位该分组
|
||||
var existCate models.SystemFilesCategory
|
||||
if err = models.Orm.QueryTable(new(models.SystemFilesCategory)).
|
||||
Filter("id", id).
|
||||
Filter("tid", tid).
|
||||
Filter("delete_time__isnull", true).
|
||||
One(&existCate); err != nil {
|
||||
c.jsonErr(404, 404, "分组不存在")
|
||||
return
|
||||
}
|
||||
if isProtectedFileCate(existCate.Name) {
|
||||
c.jsonErr(400, 400, fmt.Sprintf("「%s」为系统默认分组,不可重命名", existCate.Name))
|
||||
return
|
||||
}
|
||||
|
||||
n, err := models.Orm.QueryTable(new(models.SystemFilesCategory)).
|
||||
Filter("id", id).
|
||||
Filter("tid", tid).
|
||||
@@ -347,6 +391,21 @@ func (c *PlatformFileController) DeleteFileCate() {
|
||||
c.jsonErr(400, 400, "无效的分组ID")
|
||||
return
|
||||
}
|
||||
// 受保护分组禁止删除(先取出分组,便于给出明确提示)
|
||||
var existCate models.SystemFilesCategory
|
||||
if err = models.Orm.QueryTable(new(models.SystemFilesCategory)).
|
||||
Filter("id", id).
|
||||
Filter("tid", tid).
|
||||
Filter("delete_time__isnull", true).
|
||||
One(&existCate); err != nil {
|
||||
c.jsonErr(404, 404, "分组不存在")
|
||||
return
|
||||
}
|
||||
if isProtectedFileCate(existCate.Name) {
|
||||
c.jsonErr(400, 400, fmt.Sprintf("「%s」为系统默认分组,不可删除", existCate.Name))
|
||||
return
|
||||
}
|
||||
|
||||
cnt, err := models.Orm.QueryTable(new(models.SystemFile)).
|
||||
Filter("cate", id).
|
||||
Filter("tid", tid).
|
||||
|
||||
@@ -0,0 +1,832 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"server/models"
|
||||
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
)
|
||||
|
||||
// =============================================================
|
||||
// 平台官网 - 文章管理 /platform/website/article/*
|
||||
// - 分类管理 /platform/website/category/*
|
||||
// 表:yz_platform_website_article / yz_platform_website_category
|
||||
// =============================================================
|
||||
|
||||
type PlatformWebsiteArticleController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
type platformWebsiteArticlePayload struct {
|
||||
Title *string `json:"title"`
|
||||
Author *string `json:"author"`
|
||||
Cate *uint64 `json:"cate"`
|
||||
CateID *uint64 `json:"cate_id"`
|
||||
Content *string `json:"content"`
|
||||
Desc *string `json:"desc"`
|
||||
Image *string `json:"image"`
|
||||
IsTrans *int8 `json:"is_trans"`
|
||||
TransURL *string `json:"transurl"`
|
||||
Status *int8 `json:"status"`
|
||||
Tags []uint64 `json:"tags"`
|
||||
}
|
||||
|
||||
// articleCateID 兼容前端 cate / cate_id 两种传参
|
||||
func (p *platformWebsiteArticlePayload) articleCateID() (uint64, bool) {
|
||||
if p.Cate != nil {
|
||||
return *p.Cate, true
|
||||
}
|
||||
if p.CateID != nil {
|
||||
return *p.CateID, true
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// List GET /platform/website/article/list
|
||||
// query: keyword、cate、status、startDate、endDate、page、pageSize
|
||||
func (c *PlatformWebsiteArticleController) List() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
page, pageSize := websitePaging(&c.Controller)
|
||||
|
||||
qs := models.Orm.QueryTable(new(models.PlatformWebsiteArticle)).
|
||||
Filter("delete_time__isnull", true)
|
||||
if kw := strings.TrimSpace(c.GetString("keyword")); kw != "" {
|
||||
qs = qs.Filter("title__icontains", kw)
|
||||
}
|
||||
if cate, err := c.GetInt64("cate"); err == nil && cate > 0 {
|
||||
qs = qs.Filter("cate_id", cate)
|
||||
}
|
||||
if st := websiteStatusParam(&c.Controller); st >= 0 {
|
||||
qs = qs.Filter("status", st)
|
||||
}
|
||||
if start := strings.TrimSpace(c.GetString("startDate")); start != "" {
|
||||
qs = qs.Filter("publish_time__gte", start+" 00:00:00")
|
||||
}
|
||||
if end := strings.TrimSpace(c.GetString("endDate")); end != "" {
|
||||
qs = qs.Filter("publish_time__lte", end+" 23:59:59")
|
||||
}
|
||||
|
||||
total, err := qs.Count()
|
||||
if err != nil {
|
||||
jsonErr(&c.Controller, 500, 500, "获取失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var rows []models.PlatformWebsiteArticle
|
||||
if _, err = qs.OrderBy("-top", "-recommend", "-id").
|
||||
Limit(pageSize, (page-1)*pageSize).
|
||||
All(&rows,
|
||||
"ID", "CateID", "Title", "Author", "Desc", "Image",
|
||||
"IsTrans", "Status", "Top", "Recommend", "Views", "Likes",
|
||||
"PublishTime", "CreateTime", "UpdateTime"); err != nil {
|
||||
jsonErr(&c.Controller, 500, 500, "获取失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
cateIDs := make([]uint64, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
if r.CateID > 0 {
|
||||
cateIDs = append(cateIDs, r.CateID)
|
||||
}
|
||||
}
|
||||
cateMap := models.PlatformWebsiteCategoryNameMap(cateIDs)
|
||||
|
||||
list := make([]map[string]interface{}, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
list = append(list, map[string]interface{}{
|
||||
"id": r.ID,
|
||||
"cate_id": r.CateID,
|
||||
"cate": cateMap[r.CateID],
|
||||
"title": r.Title,
|
||||
"author": r.Author,
|
||||
"desc": r.Desc,
|
||||
"image": r.Image,
|
||||
"is_trans": r.IsTrans,
|
||||
"status": r.Status,
|
||||
"top": r.Top,
|
||||
"recommend": r.Recommend,
|
||||
"views": r.Views,
|
||||
"likes": r.Likes,
|
||||
"publish_time": r.PublishTime,
|
||||
"create_time": r.CreateTime,
|
||||
"update_time": r.UpdateTime,
|
||||
})
|
||||
}
|
||||
|
||||
websiteOK(&c.Controller, map[string]interface{}{"list": list, "total": total})
|
||||
}
|
||||
|
||||
// ListAll GET /platform/website/article/all — 不分页,供选择/关联使用
|
||||
func (c *PlatformWebsiteArticleController) ListAll() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
qs := models.Orm.QueryTable(new(models.PlatformWebsiteArticle)).
|
||||
Filter("delete_time__isnull", true)
|
||||
if kw := strings.TrimSpace(c.GetString("keyword")); kw != "" {
|
||||
qs = qs.Filter("title__icontains", kw)
|
||||
}
|
||||
if st := websiteStatusParam(&c.Controller); st >= 0 {
|
||||
qs = qs.Filter("status", st)
|
||||
}
|
||||
var rows []models.PlatformWebsiteArticle
|
||||
if _, err := qs.OrderBy("-id").All(&rows, "ID", "Title", "Status", "CateID", "PublishTime"); err != nil {
|
||||
jsonErr(&c.Controller, 500, 500, "获取失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
websiteOK(&c.Controller, rows)
|
||||
}
|
||||
|
||||
// Recycle GET /platform/website/article/recycle — 回收站(已软删除的文章)
|
||||
func (c *PlatformWebsiteArticleController) Recycle() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
page, pageSize := websitePaging(&c.Controller)
|
||||
|
||||
qs := models.Orm.QueryTable(new(models.PlatformWebsiteArticle)).
|
||||
Filter("delete_time__isnull", false)
|
||||
if kw := strings.TrimSpace(c.GetString("keyword")); kw != "" {
|
||||
qs = qs.Filter("title__icontains", kw)
|
||||
}
|
||||
total, err := qs.Count()
|
||||
if err != nil {
|
||||
jsonErr(&c.Controller, 500, 500, "获取失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
var rows []models.PlatformWebsiteArticle
|
||||
if _, err = qs.OrderBy("-delete_time").
|
||||
Limit(pageSize, (page-1)*pageSize).
|
||||
All(&rows, "ID", "CateID", "Title", "Author", "Desc", "Image",
|
||||
"Status", "Top", "Recommend", "Views", "Likes",
|
||||
"PublishTime", "CreateTime", "UpdateTime", "DeleteTime"); err != nil {
|
||||
jsonErr(&c.Controller, 500, 500, "获取失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
cateIDs := make([]uint64, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
if r.CateID > 0 {
|
||||
cateIDs = append(cateIDs, r.CateID)
|
||||
}
|
||||
}
|
||||
cateMap := models.PlatformWebsiteCategoryNameMap(cateIDs)
|
||||
|
||||
list := make([]map[string]interface{}, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
list = append(list, map[string]interface{}{
|
||||
"id": r.ID,
|
||||
"cate_id": r.CateID,
|
||||
"cate": cateMap[r.CateID],
|
||||
"title": r.Title,
|
||||
"author": r.Author,
|
||||
"desc": r.Desc,
|
||||
"image": r.Image,
|
||||
"status": r.Status,
|
||||
"top": r.Top,
|
||||
"recommend": r.Recommend,
|
||||
"views": r.Views,
|
||||
"likes": r.Likes,
|
||||
"publish_time": r.PublishTime,
|
||||
"create_time": r.CreateTime,
|
||||
"update_time": r.UpdateTime,
|
||||
"delete_time": r.DeleteTime,
|
||||
})
|
||||
}
|
||||
|
||||
websiteOK(&c.Controller, map[string]interface{}{"list": list, "total": total})
|
||||
}
|
||||
|
||||
// Restore POST /platform/website/article/:id/restore — 从回收站恢复
|
||||
func (c *PlatformWebsiteArticleController) Restore() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
id, ok := websiteID(&c.Controller)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
// 清空 delete_time 属于「反软删除」,beego 的 Update(map) 不便表达,直接走 SQL
|
||||
res, err := models.Orm.Raw(
|
||||
"UPDATE yz_platform_website_article SET delete_time = NULL, update_time = ? WHERE id = ? AND delete_time IS NOT NULL",
|
||||
time.Now(), id,
|
||||
).Exec()
|
||||
if err != nil {
|
||||
jsonErr(&c.Controller, 500, 500, "恢复失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
if affected, _ := res.RowsAffected(); affected == 0 {
|
||||
jsonErr(&c.Controller, 404, 404, "文章不存在或未被删除")
|
||||
return
|
||||
}
|
||||
websiteOK(&c.Controller, nil)
|
||||
}
|
||||
|
||||
// Purge DELETE /platform/website/article/:id/purge — 彻底删除(仅限回收站中的记录)
|
||||
func (c *PlatformWebsiteArticleController) Purge() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
id, ok := websiteID(&c.Controller)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
n, err := models.Orm.QueryTable(new(models.PlatformWebsiteArticle)).
|
||||
Filter("id", id).
|
||||
Filter("delete_time__isnull", false).
|
||||
Delete()
|
||||
if err != nil {
|
||||
jsonErr(&c.Controller, 500, 500, "彻底删除失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
if n == 0 {
|
||||
jsonErr(&c.Controller, 404, 404, "仅可彻底删除回收站中的文章")
|
||||
return
|
||||
}
|
||||
_ = models.ClearPlatformWebsiteArticleTags(id)
|
||||
websiteOK(&c.Controller, nil)
|
||||
}
|
||||
|
||||
// Get GET /platform/website/article/:id — 详情(含标签ID列表)
|
||||
func (c *PlatformWebsiteArticleController) Get() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
id, ok := websiteID(&c.Controller)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var row models.PlatformWebsiteArticle
|
||||
if err := models.Orm.QueryTable(new(models.PlatformWebsiteArticle)).
|
||||
Filter("id", id).
|
||||
Filter("delete_time__isnull", true).
|
||||
One(&row); err != nil {
|
||||
jsonErr(&c.Controller, 404, 404, "文章不存在")
|
||||
return
|
||||
}
|
||||
|
||||
cateName := ""
|
||||
if row.CateID > 0 {
|
||||
cateName = models.PlatformWebsiteCategoryNameMap([]uint64{row.CateID})[row.CateID]
|
||||
}
|
||||
|
||||
c.Data["json"] = map[string]interface{}{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": map[string]interface{}{
|
||||
"id": row.ID,
|
||||
"cate_id": row.CateID,
|
||||
"cate": cateName,
|
||||
"title": row.Title,
|
||||
"author": row.Author,
|
||||
"desc": row.Desc,
|
||||
"image": row.Image,
|
||||
"content": row.Content,
|
||||
"is_trans": row.IsTrans,
|
||||
"transurl": row.TransURL,
|
||||
"status": row.Status,
|
||||
"top": row.Top,
|
||||
"recommend": row.Recommend,
|
||||
"views": row.Views,
|
||||
"likes": row.Likes,
|
||||
"publisher_id": row.PublisherID,
|
||||
"publish_time": row.PublishTime,
|
||||
"create_time": row.CreateTime,
|
||||
"update_time": row.UpdateTime,
|
||||
"tags": models.PlatformWebsiteArticleTagIDs(row.ID),
|
||||
},
|
||||
}
|
||||
_ = c.ServeJSON()
|
||||
}
|
||||
|
||||
// Create POST /platform/website/article
|
||||
func (c *PlatformWebsiteArticleController) Create() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
var p platformWebsiteArticlePayload
|
||||
if !websiteBind(&c.Controller, &p) {
|
||||
return
|
||||
}
|
||||
title := ""
|
||||
if p.Title != nil {
|
||||
title = strings.TrimSpace(*p.Title)
|
||||
}
|
||||
if title == "" {
|
||||
jsonErr(&c.Controller, 400, 400, "文章标题不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
row := models.PlatformWebsiteArticle{Title: title}
|
||||
if p.Author != nil {
|
||||
row.Author = strings.TrimSpace(*p.Author)
|
||||
}
|
||||
if cate, has := p.articleCateID(); has {
|
||||
row.CateID = cate
|
||||
}
|
||||
if p.Content != nil {
|
||||
row.Content = *p.Content
|
||||
}
|
||||
if p.Desc != nil {
|
||||
row.Desc = *p.Desc
|
||||
}
|
||||
if p.Image != nil {
|
||||
row.Image = strings.ReplaceAll(*p.Image, "\\", "/")
|
||||
}
|
||||
if p.IsTrans != nil {
|
||||
row.IsTrans = *p.IsTrans
|
||||
}
|
||||
if row.IsTrans == 1 && p.TransURL != nil {
|
||||
url := strings.TrimSpace(*p.TransURL)
|
||||
row.TransURL = &url
|
||||
}
|
||||
if p.Status != nil {
|
||||
row.Status = *p.Status
|
||||
}
|
||||
// 直接提交待审核时同步记录发布时间
|
||||
if row.Status == 2 {
|
||||
now := time.Now()
|
||||
row.PublishTime = &now
|
||||
}
|
||||
|
||||
id, err := models.Orm.Insert(&row)
|
||||
if err != nil {
|
||||
jsonErr(&c.Controller, 500, 500, "创建失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
if err = models.SetPlatformWebsiteArticleTags(uint64(id), p.Tags); err != nil {
|
||||
jsonErr(&c.Controller, 500, 500, "标签保存失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
websiteOK(&c.Controller, map[string]interface{}{"id": id})
|
||||
}
|
||||
|
||||
// Update POST /platform/website/article/:id
|
||||
func (c *PlatformWebsiteArticleController) Update() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
id, ok := websiteID(&c.Controller)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var p platformWebsiteArticlePayload
|
||||
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.Author != nil {
|
||||
up["author"] = strings.TrimSpace(*p.Author)
|
||||
}
|
||||
if cate, has := p.articleCateID(); has {
|
||||
up["cate_id"] = cate
|
||||
}
|
||||
if p.Content != nil {
|
||||
up["content"] = *p.Content
|
||||
}
|
||||
if p.Desc != nil {
|
||||
up["desc"] = *p.Desc
|
||||
}
|
||||
if p.Image != nil {
|
||||
up["image"] = strings.ReplaceAll(*p.Image, "\\", "/")
|
||||
}
|
||||
if p.IsTrans != nil {
|
||||
up["is_trans"] = *p.IsTrans
|
||||
}
|
||||
if p.TransURL != nil {
|
||||
url := strings.TrimSpace(*p.TransURL)
|
||||
if url == "" {
|
||||
up["transurl"] = nil
|
||||
} else {
|
||||
up["transurl"] = url
|
||||
}
|
||||
}
|
||||
if p.Status != nil {
|
||||
up["status"] = *p.Status
|
||||
if *p.Status == 2 {
|
||||
up["publish_time"] = time.Now()
|
||||
}
|
||||
}
|
||||
up["update_time"] = time.Now()
|
||||
|
||||
n, err := models.Orm.QueryTable(new(models.PlatformWebsiteArticle)).
|
||||
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
|
||||
}
|
||||
// tags 传了才覆盖,未传则保持原有关联
|
||||
if p.Tags != nil {
|
||||
if err = models.SetPlatformWebsiteArticleTags(id, p.Tags); err != nil {
|
||||
jsonErr(&c.Controller, 500, 500, "标签保存失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
websiteOK(&c.Controller, nil)
|
||||
}
|
||||
|
||||
// Delete DELETE /platform/website/article/:id
|
||||
func (c *PlatformWebsiteArticleController) 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.PlatformWebsiteArticle)).
|
||||
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
|
||||
}
|
||||
_ = models.ClearPlatformWebsiteArticleTags(id)
|
||||
websiteOK(&c.Controller, nil)
|
||||
}
|
||||
|
||||
// Publish POST /platform/website/article/:id/publish
|
||||
// body: { uid } 选填,用于记录发布人(平台管理员ID)
|
||||
func (c *PlatformWebsiteArticleController) Publish() {
|
||||
claims, ok := websiteAuth(&c.Controller)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
id, ok := websiteID(&c.Controller)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var p struct {
|
||||
UID *uint64 `json:"uid"`
|
||||
}
|
||||
// 发布人参数可选,缺失时回退为当前登录管理员
|
||||
websiteBindOptional(&c.Controller, &p)
|
||||
|
||||
publisher := uint64(claims.UserID)
|
||||
if p.UID != nil && *p.UID > 0 {
|
||||
publisher = *p.UID
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
n, err := models.Orm.QueryTable(new(models.PlatformWebsiteArticle)).
|
||||
Filter("id", id).
|
||||
Filter("delete_time__isnull", true).
|
||||
Update(map[string]interface{}{
|
||||
"status": 2,
|
||||
"publish_time": now,
|
||||
"publisher_id": publisher,
|
||||
"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)
|
||||
}
|
||||
|
||||
// UnPublish POST /platform/website/article/:id/unpublish — 下架后状态置为「已隐藏」
|
||||
func (c *PlatformWebsiteArticleController) UnPublish() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
id, ok := websiteID(&c.Controller)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
n, err := models.Orm.QueryTable(new(models.PlatformWebsiteArticle)).
|
||||
Filter("id", id).
|
||||
Filter("delete_time__isnull", true).
|
||||
Update(map[string]interface{}{"status": 3, "update_time": 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)
|
||||
}
|
||||
|
||||
// updateArticleFlag 统一处理推荐/置顶标记
|
||||
func (c *PlatformWebsiteArticleController) updateArticleFlag(field string, value int8, failMsg string) {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
id, ok := websiteID(&c.Controller)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
n, err := models.Orm.QueryTable(new(models.PlatformWebsiteArticle)).
|
||||
Filter("id", id).
|
||||
Filter("delete_time__isnull", true).
|
||||
Update(map[string]interface{}{field: value, "update_time": time.Now()})
|
||||
if err != nil {
|
||||
jsonErr(&c.Controller, 500, 500, failMsg+": "+err.Error())
|
||||
return
|
||||
}
|
||||
if n == 0 {
|
||||
jsonErr(&c.Controller, 404, 404, "文章不存在")
|
||||
return
|
||||
}
|
||||
websiteOK(&c.Controller, nil)
|
||||
}
|
||||
|
||||
// Recommend POST /platform/website/article/:id/recommend
|
||||
func (c *PlatformWebsiteArticleController) Recommend() {
|
||||
c.updateArticleFlag("recommend", 1, "推荐失败")
|
||||
}
|
||||
|
||||
// UnRecommend POST /platform/website/article/:id/unrecommend
|
||||
func (c *PlatformWebsiteArticleController) UnRecommend() {
|
||||
c.updateArticleFlag("recommend", 0, "取消推荐失败")
|
||||
}
|
||||
|
||||
// Top POST /platform/website/article/:id/top
|
||||
func (c *PlatformWebsiteArticleController) Top() {
|
||||
c.updateArticleFlag("top", 1, "置顶失败")
|
||||
}
|
||||
|
||||
// UnTop POST /platform/website/article/:id/untop
|
||||
func (c *PlatformWebsiteArticleController) UnTop() {
|
||||
c.updateArticleFlag("top", 0, "取消置顶失败")
|
||||
}
|
||||
|
||||
// =============================================================
|
||||
// 分类管理
|
||||
// =============================================================
|
||||
|
||||
type PlatformWebsiteCategoryController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
type platformWebsiteCategoryPayload struct {
|
||||
Name *string `json:"name"`
|
||||
CID *uint64 `json:"cid"`
|
||||
Image *string `json:"image"`
|
||||
Desc *string `json:"desc"`
|
||||
Sort *int `json:"sort"`
|
||||
Status *int8 `json:"status"`
|
||||
}
|
||||
|
||||
// All GET /platform/website/category/all — 全量返回(前端自行组树),支持 keyword
|
||||
func (c *PlatformWebsiteCategoryController) All() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
qs := models.Orm.QueryTable(new(models.PlatformWebsiteCategory)).
|
||||
Filter("delete_time__isnull", true)
|
||||
if kw := strings.TrimSpace(c.GetString("keyword")); kw != "" {
|
||||
qs = qs.Filter("name__icontains", kw)
|
||||
}
|
||||
var rows []models.PlatformWebsiteCategory
|
||||
if _, err := qs.OrderBy("sort", "id").All(&rows); err != nil {
|
||||
jsonErr(&c.Controller, 500, 500, "获取失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
websiteOK(&c.Controller, rows)
|
||||
}
|
||||
|
||||
// List GET /platform/website/category/list — 分页
|
||||
func (c *PlatformWebsiteCategoryController) List() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
page, pageSize := websitePaging(&c.Controller)
|
||||
qs := models.Orm.QueryTable(new(models.PlatformWebsiteCategory)).
|
||||
Filter("delete_time__isnull", true)
|
||||
if kw := strings.TrimSpace(c.GetString("keyword")); kw != "" {
|
||||
qs = qs.Filter("name__icontains", kw)
|
||||
}
|
||||
total, err := qs.Count()
|
||||
if err != nil {
|
||||
jsonErr(&c.Controller, 500, 500, "获取失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
var rows []models.PlatformWebsiteCategory
|
||||
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})
|
||||
}
|
||||
|
||||
// Get GET /platform/website/category/:id
|
||||
func (c *PlatformWebsiteCategoryController) Get() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
id, ok := websiteID(&c.Controller)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var row models.PlatformWebsiteCategory
|
||||
if err := models.Orm.QueryTable(new(models.PlatformWebsiteCategory)).
|
||||
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/category
|
||||
func (c *PlatformWebsiteCategoryController) Create() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
var p platformWebsiteCategoryPayload
|
||||
if !websiteBind(&c.Controller, &p) {
|
||||
return
|
||||
}
|
||||
if p.Name == nil || strings.TrimSpace(*p.Name) == "" {
|
||||
jsonErr(&c.Controller, 400, 400, "分类名称不能为空")
|
||||
return
|
||||
}
|
||||
row := models.PlatformWebsiteCategory{
|
||||
Name: strings.TrimSpace(*p.Name),
|
||||
Status: 1,
|
||||
}
|
||||
if p.CID != nil {
|
||||
row.Cid = *p.CID
|
||||
}
|
||||
if p.Image != nil {
|
||||
row.Image = strings.ReplaceAll(*p.Image, "\\", "/")
|
||||
}
|
||||
if p.Desc != nil {
|
||||
row.Desc = *p.Desc
|
||||
}
|
||||
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/category/:id
|
||||
func (c *PlatformWebsiteCategoryController) Update() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
id, ok := websiteID(&c.Controller)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var p platformWebsiteCategoryPayload
|
||||
if !websiteBind(&c.Controller, &p) {
|
||||
return
|
||||
}
|
||||
up := map[string]interface{}{}
|
||||
if p.Name != nil {
|
||||
name := strings.TrimSpace(*p.Name)
|
||||
if name == "" {
|
||||
jsonErr(&c.Controller, 400, 400, "分类名称不能为空")
|
||||
return
|
||||
}
|
||||
up["name"] = name
|
||||
}
|
||||
if p.CID != nil {
|
||||
if *p.CID == id {
|
||||
jsonErr(&c.Controller, 400, 400, "父级分类不能是自己")
|
||||
return
|
||||
}
|
||||
up["cid"] = *p.CID
|
||||
}
|
||||
if p.Image != nil {
|
||||
up["image"] = strings.ReplaceAll(*p.Image, "\\", "/")
|
||||
}
|
||||
if p.Desc != nil {
|
||||
up["desc"] = *p.Desc
|
||||
}
|
||||
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.PlatformWebsiteCategory)).
|
||||
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)
|
||||
}
|
||||
|
||||
// UpdateStatus PATCH /platform/website/category/:id/status — body { status }
|
||||
func (c *PlatformWebsiteCategoryController) UpdateStatus() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
id, ok := websiteID(&c.Controller)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var p struct {
|
||||
Status *int8 `json:"status"`
|
||||
}
|
||||
if !websiteBind(&c.Controller, &p) || p.Status == nil {
|
||||
jsonErr(&c.Controller, 400, 400, "状态参数错误")
|
||||
return
|
||||
}
|
||||
n, err := models.Orm.QueryTable(new(models.PlatformWebsiteCategory)).
|
||||
Filter("id", id).
|
||||
Filter("delete_time__isnull", true).
|
||||
Update(map[string]interface{}{"status": *p.Status, "update_time": 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)
|
||||
}
|
||||
|
||||
// Delete DELETE /platform/website/category/:id — 存在子分类时禁止删除
|
||||
func (c *PlatformWebsiteCategoryController) Delete() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
id, ok := websiteID(&c.Controller)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
child, err := models.Orm.QueryTable(new(models.PlatformWebsiteCategory)).
|
||||
Filter("cid", 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.PlatformWebsiteCategory)).
|
||||
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)
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"server/pkg/jwtutil"
|
||||
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
)
|
||||
|
||||
// =============================================================
|
||||
// 平台官网管理(/platform/website/*)公共工具
|
||||
// 数据表前缀 yz_platform_website_,建表见 docs/sql/create_platform_website.sql
|
||||
// =============================================================
|
||||
|
||||
// websiteAuth 平台管理员鉴权,失败时已写出错误响应,返回 ok=false
|
||||
func websiteAuth(c *beego.Controller) (*jwtutil.Claims, bool) {
|
||||
claims, err := requirePlatform(c)
|
||||
if err != nil {
|
||||
jsonErr(c, 401, 401, err.Error())
|
||||
return nil, false
|
||||
}
|
||||
return claims, true
|
||||
}
|
||||
|
||||
// websiteOK 统一成功响应:{ code:200, msg:"success", data:... }
|
||||
func websiteOK(c *beego.Controller, data interface{}) {
|
||||
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "success", "data": data}
|
||||
_ = c.ServeJSON()
|
||||
}
|
||||
|
||||
// websitePaging 解析分页参数:page 默认 1,pageSize 默认 10(兼容 limit),上限 200
|
||||
func websitePaging(c *beego.Controller) (int, int) {
|
||||
page, _ := c.GetInt("page", 1)
|
||||
pageSize, _ := c.GetInt("pageSize", 0)
|
||||
if pageSize <= 0 {
|
||||
pageSize, _ = c.GetInt("limit", 0)
|
||||
}
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize < 1 {
|
||||
pageSize = 10
|
||||
}
|
||||
if pageSize > 200 {
|
||||
pageSize = 200
|
||||
}
|
||||
return page, pageSize
|
||||
}
|
||||
|
||||
// websiteID 解析路径参数 :id
|
||||
func websiteID(c *beego.Controller) (uint64, bool) {
|
||||
id, err := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
jsonErr(c, 400, 400, "无效ID")
|
||||
return 0, false
|
||||
}
|
||||
return id, true
|
||||
}
|
||||
|
||||
// websiteStatusParam 解析 status 查询参数,未传时返回 -1(表示不过滤)
|
||||
func websiteStatusParam(c *beego.Controller) int {
|
||||
raw := strings.TrimSpace(c.GetString("status"))
|
||||
if raw == "" {
|
||||
return -1
|
||||
}
|
||||
v, err := strconv.Atoi(raw)
|
||||
if err != nil {
|
||||
return -1
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// websiteBind 解析 JSON 请求体到 target,失败时已写出 400
|
||||
func websiteBind(c *beego.Controller, target interface{}) bool {
|
||||
body, err := io.ReadAll(c.Ctx.Request.Body)
|
||||
if err != nil {
|
||||
jsonErr(c, 400, 400, "参数错误")
|
||||
return false
|
||||
}
|
||||
if err = json.Unmarshal(body, target); err != nil {
|
||||
jsonErr(c, 400, 400, "参数错误")
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// websiteBindOptional 宽松解析请求体:body 为空或非法时不作响应,调用方按零值处理
|
||||
func websiteBindOptional(c *beego.Controller, target interface{}) {
|
||||
body, err := io.ReadAll(c.Ctx.Request.Body)
|
||||
if err != nil || len(bytes.TrimSpace(body)) == 0 {
|
||||
return
|
||||
}
|
||||
_ = json.Unmarshal(body, target)
|
||||
}
|
||||
@@ -0,0 +1,461 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"server/models"
|
||||
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
"github.com/beego/beego/v2/client/orm"
|
||||
)
|
||||
|
||||
// =============================================================
|
||||
// 平台官网 - 标签管理 /platform/website/tag/*
|
||||
// - 评论管理 /platform/website/comment/*
|
||||
// 表:yz_platform_website_tag / yz_platform_website_comment
|
||||
// =============================================================
|
||||
|
||||
type PlatformWebsiteTagController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
type platformWebsiteTagPayload struct {
|
||||
Name *string `json:"name"`
|
||||
Sort *int `json:"sort"`
|
||||
Status *int8 `json:"status"`
|
||||
}
|
||||
|
||||
// List GET /platform/website/tag/list — 分页
|
||||
func (c *PlatformWebsiteTagController) List() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
page, pageSize := websitePaging(&c.Controller)
|
||||
qs := models.Orm.QueryTable(new(models.PlatformWebsiteTag)).
|
||||
Filter("delete_time__isnull", true)
|
||||
if kw := strings.TrimSpace(c.GetString("keyword")); kw != "" {
|
||||
qs = qs.Filter("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.PlatformWebsiteTag
|
||||
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/tag/all — 全量返回,供文章编辑选择标签
|
||||
func (c *PlatformWebsiteTagController) All() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
var rows []models.PlatformWebsiteTag
|
||||
if _, err := models.Orm.QueryTable(new(models.PlatformWebsiteTag)).
|
||||
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/tag/:id
|
||||
func (c *PlatformWebsiteTagController) Get() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
id, ok := websiteID(&c.Controller)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var row models.PlatformWebsiteTag
|
||||
if err := models.Orm.QueryTable(new(models.PlatformWebsiteTag)).
|
||||
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/tag
|
||||
func (c *PlatformWebsiteTagController) Create() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
var p platformWebsiteTagPayload
|
||||
if !websiteBind(&c.Controller, &p) {
|
||||
return
|
||||
}
|
||||
if p.Name == nil || strings.TrimSpace(*p.Name) == "" {
|
||||
jsonErr(&c.Controller, 400, 400, "标签名称不能为空")
|
||||
return
|
||||
}
|
||||
name := strings.TrimSpace(*p.Name)
|
||||
// 同名标签去重,避免前台聚合出现重复项
|
||||
exist, err := models.Orm.QueryTable(new(models.PlatformWebsiteTag)).
|
||||
Filter("name", name).
|
||||
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.PlatformWebsiteTag{Name: name, Status: 1}
|
||||
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/tag/:id
|
||||
func (c *PlatformWebsiteTagController) Update() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
id, ok := websiteID(&c.Controller)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var p platformWebsiteTagPayload
|
||||
if !websiteBind(&c.Controller, &p) {
|
||||
return
|
||||
}
|
||||
up := map[string]interface{}{}
|
||||
if p.Name != nil {
|
||||
name := strings.TrimSpace(*p.Name)
|
||||
if name == "" {
|
||||
jsonErr(&c.Controller, 400, 400, "标签名称不能为空")
|
||||
return
|
||||
}
|
||||
dup, err := models.Orm.QueryTable(new(models.PlatformWebsiteTag)).
|
||||
Filter("name", name).
|
||||
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["name"] = name
|
||||
}
|
||||
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.PlatformWebsiteTag)).
|
||||
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)
|
||||
}
|
||||
|
||||
// UpdateStatus PATCH /platform/website/tag/:id/status — body { status }
|
||||
func (c *PlatformWebsiteTagController) UpdateStatus() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
id, ok := websiteID(&c.Controller)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var p struct {
|
||||
Status *int8 `json:"status"`
|
||||
}
|
||||
if !websiteBind(&c.Controller, &p) || p.Status == nil {
|
||||
jsonErr(&c.Controller, 400, 400, "状态参数错误")
|
||||
return
|
||||
}
|
||||
n, err := models.Orm.QueryTable(new(models.PlatformWebsiteTag)).
|
||||
Filter("id", id).
|
||||
Filter("delete_time__isnull", true).
|
||||
Update(map[string]interface{}{"status": *p.Status, "update_time": 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)
|
||||
}
|
||||
|
||||
// Delete DELETE /platform/website/tag/:id
|
||||
func (c *PlatformWebsiteTagController) 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.PlatformWebsiteTag)).
|
||||
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
|
||||
}
|
||||
// 同步清理文章关联,避免前台聚合到已删除标签
|
||||
_, _ = models.Orm.QueryTable(new(models.PlatformWebsiteArticleTag)).
|
||||
Filter("tag_id", id).
|
||||
Delete()
|
||||
websiteOK(&c.Controller, nil)
|
||||
}
|
||||
|
||||
// =============================================================
|
||||
// 评论管理
|
||||
// =============================================================
|
||||
|
||||
type PlatformWebsiteCommentController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
// List GET /platform/website/comment/list
|
||||
// query: keyword(内容/昵称)、status、article_id、page、pageSize
|
||||
func (c *PlatformWebsiteCommentController) List() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
page, pageSize := websitePaging(&c.Controller)
|
||||
|
||||
cond := orm.NewCondition().And("delete_time__isnull", true)
|
||||
if kw := strings.TrimSpace(c.GetString("keyword")); kw != "" {
|
||||
cond = cond.AndCond(orm.NewCondition().
|
||||
Or("content__icontains", kw).
|
||||
Or("nickname__icontains", kw))
|
||||
}
|
||||
if st := websiteStatusParam(&c.Controller); st >= 0 {
|
||||
cond = cond.And("status", st)
|
||||
}
|
||||
if articleID, err := c.GetInt64("article_id"); err == nil && articleID > 0 {
|
||||
cond = cond.And("article_id", articleID)
|
||||
}
|
||||
|
||||
qs := models.Orm.QueryTable(new(models.PlatformWebsiteComment)).SetCond(cond)
|
||||
total, err := qs.Count()
|
||||
if err != nil {
|
||||
jsonErr(&c.Controller, 500, 500, "获取失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
var rows []models.PlatformWebsiteComment
|
||||
if _, err = qs.OrderBy("-id").Limit(pageSize, (page-1)*pageSize).All(&rows); err != nil {
|
||||
jsonErr(&c.Controller, 500, 500, "获取失败: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
articleIDs := make([]uint64, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
if r.ArticleID > 0 {
|
||||
articleIDs = append(articleIDs, r.ArticleID)
|
||||
}
|
||||
}
|
||||
titleMap := models.PlatformWebsiteArticleTitleMap(articleIDs)
|
||||
|
||||
list := make([]map[string]interface{}, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
list = append(list, map[string]interface{}{
|
||||
"id": r.ID,
|
||||
"article_id": r.ArticleID,
|
||||
"article_title": titleMap[r.ArticleID],
|
||||
"nickname": r.Nickname,
|
||||
"email": r.Email,
|
||||
"content": r.Content,
|
||||
"reply": r.Reply,
|
||||
"status": r.Status,
|
||||
"ip": r.IP,
|
||||
"create_time": r.CreateTime,
|
||||
"update_time": r.UpdateTime,
|
||||
})
|
||||
}
|
||||
|
||||
websiteOK(&c.Controller, map[string]interface{}{"list": list, "total": total})
|
||||
}
|
||||
|
||||
// Get GET /platform/website/comment/:id
|
||||
func (c *PlatformWebsiteCommentController) Get() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
id, ok := websiteID(&c.Controller)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var row models.PlatformWebsiteComment
|
||||
if err := models.Orm.QueryTable(new(models.PlatformWebsiteComment)).
|
||||
Filter("id", id).
|
||||
Filter("delete_time__isnull", true).
|
||||
One(&row); err != nil {
|
||||
jsonErr(&c.Controller, 404, 404, "评论不存在")
|
||||
return
|
||||
}
|
||||
websiteOK(&c.Controller, row)
|
||||
}
|
||||
|
||||
// Audit POST /platform/website/comment/:id/audit — body { status: 1 通过 / 2 拒绝 }
|
||||
func (c *PlatformWebsiteCommentController) Audit() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
id, ok := websiteID(&c.Controller)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var p struct {
|
||||
Status *int8 `json:"status"`
|
||||
}
|
||||
if !websiteBind(&c.Controller, &p) || p.Status == nil {
|
||||
jsonErr(&c.Controller, 400, 400, "状态参数错误")
|
||||
return
|
||||
}
|
||||
if *p.Status != 1 && *p.Status != 2 {
|
||||
jsonErr(&c.Controller, 400, 400, "仅支持通过(1)或拒绝(2)")
|
||||
return
|
||||
}
|
||||
n, err := models.Orm.QueryTable(new(models.PlatformWebsiteComment)).
|
||||
Filter("id", id).
|
||||
Filter("delete_time__isnull", true).
|
||||
Update(map[string]interface{}{"status": *p.Status, "update_time": 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)
|
||||
}
|
||||
|
||||
// Reply POST /platform/website/comment/:id/reply — body { reply }
|
||||
func (c *PlatformWebsiteCommentController) Reply() {
|
||||
if _, ok := websiteAuth(&c.Controller); !ok {
|
||||
return
|
||||
}
|
||||
id, ok := websiteID(&c.Controller)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var p struct {
|
||||
Reply *string `json:"reply"`
|
||||
}
|
||||
if !websiteBind(&c.Controller, &p) || p.Reply == nil || strings.TrimSpace(*p.Reply) == "" {
|
||||
jsonErr(&c.Controller, 400, 400, "回复内容不能为空")
|
||||
return
|
||||
}
|
||||
n, err := models.Orm.QueryTable(new(models.PlatformWebsiteComment)).
|
||||
Filter("id", id).
|
||||
Filter("delete_time__isnull", true).
|
||||
Update(map[string]interface{}{
|
||||
"reply": strings.TrimSpace(*p.Reply),
|
||||
"update_time": 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)
|
||||
}
|
||||
|
||||
// Delete DELETE /platform/website/comment/:id
|
||||
func (c *PlatformWebsiteCommentController) 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.PlatformWebsiteComment)).
|
||||
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/comment/batchdelete — body { ids: [] }
|
||||
func (c *PlatformWebsiteCommentController) 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.PlatformWebsiteComment)).
|
||||
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)
|
||||
}
|
||||
@@ -0,0 +1,707 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user