自己的客服系统做好了,官网页面也有了,但是没有介绍性的内容文章。网站被收录的太少,这样会导致网站的权重不高,搜索排名比较低。
因此要简单的加上一个小型的内容管理功能。
很简单的两张表,分类表和内容表
DROP TABLE IF EXISTS `cms_cate`;
CREATE TABLE `cms_cate` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`cat_name` varchar(50) NOT NULL DEFAULT '' COMMENT '分类名称',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) COMMENT '自增主键索引'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT 'CMS分类表';
DROP TABLE IF EXISTS `cms_news`;
CREATE TABLE `cms_news` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(500) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '标题',
`content` text COLLATE utf8mb4_general_ci COMMENT '内容',
`cat_id` int(11) NOT NULL DEFAULT '0' COMMENT '分类ID',
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`) COMMENT '自增主键索引'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT 'CMS内容表';
设计两个结构体
type CmsCate struct {
Id uint `json:"id"`
CatName string `json:"cat_name"`
CreatedAt types.Time `json:"created_at"`
}
type CmsNews struct {
Id uint `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
CreatedAt types.Time `json:"created_at"`
}
types.Time类型是我对time.Time类型的包装,用于在序列化为json的时候,可以格式化时间
package types
import (
"database/sql/driver"
"fmt"
"time"
)
type Time struct {
time.Time
}
func (t Time) MarshalJSON() ([]byte, error) {
localTime := t.Format("2006-01-02 15:04:05")
return []byte(fmt.Sprintf(`"%s"`, localTime)), nil
}
func (t Time) Value() (driver.Value, error) {
var zeroTime time.Time
if t.Time.UnixNano() == zeroTime.UnixNano() {
return nil, nil
}
return t.Time, nil
}
func (t *Time) Scan(v interface{}) error {
value, ok := v.(time.Time)
if ok {
*t = Time{Time: value}
return nil
}
return fmt.Errorf("can not convert %v to timestamp", v)
}
分类表和内容表的增删查改
DB就是*gorm.DB类型,这是在链接数据库的时候,已经赋值好的全局变量
/*内容表*/
//根据条件查询条数
func CountCmsNews(query interface{}, args ...interface{}) uint {
var v uint
DB.Table("cms_news").Where(query, args...).Count(&v)
return v
}
//根据条件更新
func (this *CmsNews) SaveCmsNews(query interface{}, args ...interface{}) error {
db := DB.Table("cms_news").Where(query, args...).Update(this)
return db.Error
}
//增加数据
func (this *CmsNews) AddCmsNews() error {
return DB.Create(this).Error
}
//根据条件查询分页列表
func FindCmsNews(page, pagesize int, query interface{}, args ...interface{}) []CmsNews {
offset := (page - 1) * pagesize
var res []CmsNews
DB.Table("cms_news").Where(query, args...).Order("id desc").Offset(offset).Limit(pagesize).Find(&res)
return res
}
//根据条件删除
func DelCmsNews(query interface{}, args ...interface{}) error {
return DB.Where(query, args...).Delete(&CmsNews{}).Error
}
/*分类表*/
//根据条件分类
func (this *CmsCate) SaveCmsCate(query interface{}, args ...interface{}) error {
db := DB.Table("cms_cate").Where(query, args...).Update(this)
return db.Error
}
//增加分类
func (this *CmsCate) AddCmsCate() error {
return DB.Create(this).Error
}
//根据条件查询分类列表
func FindCmsCate(page, pagesize int, query interface{}, args ...interface{}) []CmsCate {
offset := (page - 1) * pagesize
var res []CmsCate
DB.Table("cms_cate").Where(query, args...).Order("id desc").Offset(offset).Limit(pagesize).Find(&res)
return res
}
//根据条件删除分类
func DelCmsCate(query interface{}, args ...interface{}) error {
return DB.Where(query, args...).Delete(&CmsCate{}).Error
}
gin路由入口
//系统相关
systemGroup := engine.Group("/system")
systemGroup.Use()
{
//分类列表
systemGroup.GET("/cmsCate", controller.GetCmsCate)
//删除分类
systemGroup.GET("/delCmsCate", controller.DelCmsCate)
//增加或编辑分类
systemGroup.POST("/cmsCate", controller.PostCmsCate)
//CMS内容列表
systemGroup.GET("/cmsNews", controller.GetCmsNews)
//增加或编辑内容
systemGroup.POST("/cmsNews", controller.PostCmsNews)
//删除内容
systemGroup.GET("/delCmsNews", controller.DelCmsNews)
}
gin框架路由处理逻辑
返回参数部分,我进行了小的封装,可以参考去掉。
只看调用model部分的处理逻辑
package controller
import (
"github.com/gin-gonic/gin"
"kefu/models"
"kefu/types"
"strconv"
)
type CmsCateForm struct {
Id uint `form:"id" json:"id" uri:"id" xml:"id"`
CateName string `form:"cate_name" json:"cate_name" uri:"cate_name" xml:"cate_name" binding:"required"`
}
//分类列表(暂不分页)
func GetCmsCate(c *gin.Context) {
list := models.FindCmsCate(1, 1000, "")
c.JSON(200, gin.H{
"code": types.ApiCode.SUCCESS,
"msg": types.ApiCode.GetMessage(types.ApiCode.SUCCESS),
"result": list,
})
}
//编辑CMS分类
func PostCmsCate(c *gin.Context) {
var form CmsCateForm
err := c.Bind(&form)
if err != nil {
c.JSON(200, gin.H{
"code": types.ApiCode.FAILED,
"msg": types.ApiCode.GetMessage(types.ApiCode.INVALID),
"result": err.Error(),
})
return
}
modelCms := &models.CmsCate{
Id: form.Id,
CatName: form.CateName,
}
//添加分类
if form.Id == 0 {
err := modelCms.AddCmsCate()
if err != nil {
c.JSON(200, gin.H{
"code": types.ApiCode.FAILED,
"msg": err.Error(),
})
return
}
} else {
//修改分类
err := modelCms.SaveCmsCate("id = ?", form.Id)
if err != nil {
c.JSON(200, gin.H{
"code": types.ApiCode.FAILED,
"msg": err.Error(),
})
return
}
}
c.JSON(200, gin.H{
"code": types.ApiCode.SUCCESS,
"msg": types.ApiCode.GetMessage(types.ApiCode.SUCCESS),
})
}
type CmsNewsForm struct {
Id uint `form:"id" json:"id" uri:"id" xml:"id"`
CateId string `form:"cate_id" json:"cate_id" uri:"cate_id" xml:"cate_id" binding:"required"`
Content string `form:"content" json:"content" uri:"content" xml:"content" binding:"required"`
Title string `form:"title" json:"title" uri:"title" xml:"title" binding:"required"`
}
//CMS内容列表
func GetCmsNews(c *gin.Context) {
//分页处理
page, _ := strconv.Atoi(c.Query("page"))
if page <= 0 {
page = 1
}
pagesize, _ := strconv.Atoi(c.Query("pagesize"))
if pagesize <= 0 || pagesize > 50 {
pagesize = 10
}
//判断分类ID条件
catId := c.Query("cat_id")
query := "1=1 "
args := make([]interface{}, 0)
if catId != "" {
query += "and cat_id = ? "
args = append(args, catId)
}
//分页查询
count := models.CountCmsNews(query, args...)
list := models.FindCmsNews(page, pagesize, query, args...)
c.JSON(200, gin.H{
"code": types.ApiCode.SUCCESS,
"msg": types.ApiCode.GetMessage(types.ApiCode.SUCCESS),
"result": gin.H{
"list": list,
"count": count,
"pagesize": pagesize,
"page": page,
},
})
}
//编辑CMS内容
func PostCmsNews(c *gin.Context) {
var form CmsNewsForm
err := c.Bind(&form)
if err != nil {
c.JSON(200, gin.H{
"code": types.ApiCode.FAILED,
"msg": types.ApiCode.GetMessage(types.ApiCode.INVALID),
"result": err.Error(),
})
return
}
modelCms := &models.CmsNews{
Id: form.Id,
CatId: form.CateId,
Title: form.Title,
}
//添加
if form.Id == 0 {
err := modelCms.AddCmsNews()
if err != nil {
c.JSON(200, gin.H{
"code": types.ApiCode.FAILED,
"msg": err.Error(),
})
return
}
} else {
//修改
err := modelCms.SaveCmsNews("id = ?", form.Id)
if err != nil {
c.JSON(200, gin.H{
"code": types.ApiCode.FAILED,
"msg": err.Error(),
})
return
}
}
c.JSON(200, gin.H{
"code": types.ApiCode.SUCCESS,
"msg": types.ApiCode.GetMessage(types.ApiCode.SUCCESS),
})
}
//删除分类
func DelCmsCate(c *gin.Context) {
id := c.Query("id")
err := models.DelCmsCate("id = ?", id)
if err != nil {
c.JSON(200, gin.H{
"code": types.ApiCode.FAILED,
"msg": err.Error(),
})
return
}
c.JSON(200, gin.H{
"code": types.ApiCode.SUCCESS,
"msg": types.ApiCode.GetMessage(types.ApiCode.SUCCESS),
})
}
//删除内容
func DelCmsNews(c *gin.Context) {
id := c.Query("id")
err := models.DelCmsNews("id = ?", id)
if err != nil {
c.JSON(200, gin.H{
"code": types.ApiCode.FAILED,
"msg": err.Error(),
})
return
}
c.JSON(200, gin.H{
"code": types.ApiCode.SUCCESS,
"msg": types.ApiCode.GetMessage(types.ApiCode.SUCCESS),
})
}
可以使用接口测试工具,对接口进行测试

我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]
我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
我正在尝试解析一个CSV文件并使用SQL命令自动为其创建一个表。CSV中的第一行给出了列标题。但我需要推断每个列的类型。Ruby中是否有任何函数可以找到每个字段中内容的类型。例如,CSV行:"12012","Test","1233.22","12:21:22","10/10/2009"应该产生像这样的类型['integer','string','float','time','date']谢谢! 最佳答案 require'time'defto_something(str)if(num=Integer(str)rescueFloat(s
只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您
电脑0x0000001A蓝屏错误怎么U盘重装系统教学分享。有用户电脑开机之后遇到了系统蓝屏的情况。系统蓝屏问题很多时候都是系统bug,只有通过重装系统来进行解决。那么蓝屏问题如何通过U盘重装新系统来解决呢?来看看以下的详细操作方法教学吧。 准备工作: 1、U盘一个(尽量使用8G以上的U盘)。 2、一台正常联网可使用的电脑。 3、ghost或ISO系统镜像文件(Win10系统下载_Win10专业版_windows10正式版下载-系统之家)。 4、在本页面下载U盘启动盘制作工具:系统之家U盘启动工具。 U盘启动盘制作步骤: 注意:制作期间,U盘会被格式化,因此U盘中的重要文件请注
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList()Obt
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO