├── .air.toml ├── .gitignore ├── .idea ├── .gitignore ├── dataSources.xml ├── gvb_server.iml ├── modules.xml └── vcs.xml ├── README.md ├── api ├── advert_api │ ├── advert_create.go │ ├── advert_list.go │ ├── advert_remove.go │ ├── advert_update.go │ └── enter.go ├── article_api │ ├── article_calendar.go │ ├── article_category_list.go │ ├── article_coll.go │ ├── article_coll_list.go │ ├── article_coll_remove_batch.go │ ├── article_content.go │ ├── article_create.go │ ├── article_detail.go │ ├── article_digg.go │ ├── article_id_title_list.go │ ├── article_list.go │ ├── article_remove.go │ ├── article_tag_list.go │ ├── article_update.go │ ├── enter.go │ └── full_text_search.go ├── chat_api │ ├── chat_group.go │ ├── chat_list.go │ └── enter.go ├── comment_api │ ├── comment_create.go │ ├── comment_digg.go │ ├── comment_list.go │ ├── comment_list_all.go │ ├── comment_remove.go │ └── enter.go ├── data_api │ ├── data_seven_login.go │ ├── data_sum.go │ └── enter.go ├── enter.go ├── images_api │ ├── enter.go │ ├── image_list.go │ ├── image_name_list.go │ ├── image_remove.go │ ├── image_update.go │ ├── image_upload.go │ └── image_upload_data.go ├── log_api │ ├── enter.go │ ├── log_list.go │ └── log_remove.go ├── menu_api │ ├── enter.go │ ├── menu_create.go │ ├── menu_detail.go │ ├── menu_detail_by_path.go │ ├── menu_list.go │ ├── menu_name_list.go │ ├── menu_remove.go │ └── menu_update.go ├── message_api │ ├── enter.go │ ├── message_create.go │ ├── message_list.go │ ├── message_list_all.go │ └── message_record.go ├── new_api │ ├── enter.go │ └── new_list.go ├── settings_api │ ├── enter.go │ ├── settings_info.go │ ├── settings_site_info.go │ ├── settings_site_update.go │ └── settings_update.go ├── tag_api │ ├── enter.go │ ├── tag_create.go │ ├── tag_list.go │ ├── tag_name_list.go │ ├── tag_remove.go │ └── tag_update.go └── user_api │ ├── email_login.go │ ├── enter.go │ ├── qq_login.go │ ├── qq_login_link.go │ ├── user_bind_email.go │ ├── user_create.go │ ├── user_info.go │ ├── user_list.go │ ├── user_logout.go │ ├── user_register.go │ ├── user_remove.go │ ├── user_update_nick_name.go │ ├── user_update_password.go │ └── user_update_role.go ├── config ├── conf_email.go ├── conf_es.go ├── conf_jwt.go ├── conf_logger.go ├── conf_mysql.go ├── conf_qiniu.go ├── conf_qq.go ├── conf_redis.go ├── conf_site_info.go ├── conf_system.go ├── conf_upload.go └── enter.go ├── core ├── addr_db.go ├── conf.go ├── es.go ├── gorm.go ├── logrus.go └── redis.go ├── deploy ├── .env ├── docker-compose.yml └── gvb │ ├── elasticsearch │ └── config │ │ └── elasticsearch.yml │ └── nginx │ ├── conf │ └── nginx.conf │ └── html │ ├── 50x.html │ └── index.html ├── docs ├── docs.go ├── swagger.json └── swagger.yaml ├── flag ├── create_user.go ├── db.go ├── enter.go └── es.go ├── global └── global.go ├── go.mod ├── go.sum ├── gvb_mysql.sql ├── main ├── main.go ├── middleware ├── jwt_auth.go └── tls.go ├── models ├── advert_model.go ├── article_model.go ├── banner_model.go ├── chat_model.go ├── comment_model.go ├── ctype │ ├── array.go │ ├── image_type.go │ ├── msg_type.go │ ├── role_type.go │ └── sign_status_type.go ├── enter.go ├── fade_back_model.go ├── full_text_model.go ├── login_data_model.go ├── menu_banner_model.go ├── menu_model.go ├── message_model.go ├── res │ ├── err_code.go │ ├── err_code.json │ └── response.go ├── tag_model.go ├── user_collect_model.go └── user_model.go ├── plugins ├── email │ └── send_email.go ├── log_stash │ ├── enter.go │ ├── level.go │ └── model.go ├── qiniu │ └── enter.go └── qq │ └── enter.go ├── routers ├── advert_router.go ├── article_router.go ├── chat_router.go ├── comment_router.go ├── data_router.go ├── enter.go ├── images_router.go ├── log_router.go ├── menu_router.go ├── message_router.go ├── news_router.go ├── settings_router.go ├── tag_router.go └── user_router.go ├── service ├── common │ └── service_list.go ├── cron_ser │ ├── enter.go │ ├── sync_article_data.go │ └── sync_comment_data.go ├── enter.go ├── es_ser │ ├── article_search.go │ ├── enter.go │ └── full_text_search.go ├── image_ser │ ├── enter.go │ └── image_upload_service.go ├── redis_ser │ ├── count.go │ ├── enter.go │ ├── logout.go │ └── news.go └── user_ser │ ├── create_user.go │ ├── enter.go │ └── logout.go ├── settings.yaml ├── testdata ├── 0.测试窗口.go ├── 1.错误码读取.go ├── 10.删除全文搜索.go ├── 11.文章评论列表.go ├── 12.切片反转.go ├── 13.新闻测试.go ├── 14.随机生成名称和头像.go ├── 15.日志测试.go ├── 16.ip获取城市.go ├── 17.获取网卡ip.go ├── 2.structs.go ├── 3.jwt测试.go ├── 4.redis.go ├── 5.email.go ├── 6.随机密码.go ├── 7.markdown转html.go ├── 8.全文搜索测试.go ├── 9.同步es数据到全文搜索.go ├── es操作 │ ├── es操作.go │ ├── 文章标签搜索.go │ └── 索引操作.go └── redis操作 │ └── 同步redis到es.go ├── uploads ├── avatar │ └── default.jpg ├── chat_avatar │ ├── 一.png │ ├── 不.png │ ├── 专.png │ ├── 个.png │ ├── 丰.png │ ├── 义.png │ ├── 乐.png │ ├── 乔.png │ ├── 仁.png │ ├── 从.png │ ├── 任.png │ ├── 伊.png │ ├── 优.png │ ├── 会.png │ ├── 传.png │ ├── 伶.png │ ├── 佐.png │ ├── 体.png │ ├── 俊.png │ ├── 俏.png │ ├── 保.png │ ├── 俭.png │ ├── 健.png │ ├── 傲.png │ ├── 傻.png │ ├── 儒.png │ ├── 光.png │ ├── 兴.png │ ├── 典.png │ ├── 内.png │ ├── 冷.png │ ├── 凶.png │ ├── 列.png │ ├── 刻.png │ ├── 加.png │ ├── 务.png │ ├── 动.png │ ├── 勤.png │ ├── 包.png │ ├── 单.png │ ├── 博.png │ ├── 卡.png │ ├── 危.png │ ├── 友.png │ ├── 发.png │ ├── 受.png │ ├── 古.png │ ├── 可.png │ ├── 合.png │ ├── 含.png │ ├── 听.png │ ├── 呆.png │ ├── 和.png │ ├── 哈.png │ ├── 哭.png │ ├── 唠.png │ ├── 善.png │ ├── 喜.png │ ├── 土.png │ ├── 坎.png │ ├── 坚.png │ ├── 坦.png │ ├── 壮.png │ ├── 复.png │ ├── 外.png │ ├── 多.png │ ├── 大.png │ ├── 天.png │ ├── 失.png │ ├── 奋.png │ ├── 如.png │ ├── 妩.png │ ├── 姆.png │ ├── 威.png │ ├── 娇.png │ ├── 孝.png │ ├── 孤.png │ ├── 安.png │ ├── 完.png │ ├── 宙.png │ ├── 害.png │ ├── 寂.png │ ├── 寒.png │ ├── 尊.png │ ├── 小.png │ ├── 尤.png │ ├── 巴.png │ ├── 帅.png │ ├── 干.png │ ├── 平.png │ ├── 年.png │ ├── 幸.png │ ├── 幽.png │ ├── 开.png │ ├── 弗.png │ ├── 强.png │ ├── 彩.png │ ├── 彪.png │ ├── 微.png │ ├── 心.png │ ├── 忐.png │ ├── 忧.png │ ├── 快.png │ ├── 怕.png │ ├── 怡.png │ ├── 悦.png │ ├── 悲.png │ ├── 想.png │ ├── 愉.png │ ├── 感.png │ ├── 愤.png │ ├── 慈.png │ ├── 懦.png │ ├── 懵.png │ ├── 成.png │ ├── 托.png │ ├── 执.png │ ├── 拉.png │ ├── 拼.png │ ├── 搞.png │ ├── 摩.png │ ├── 故.png │ ├── 敏.png │ ├── 整.png │ ├── 文.png │ ├── 斯.png │ ├── 无.png │ ├── 时.png │ ├── 明.png │ ├── 昏.png │ ├── 星.png │ ├── 普.png │ ├── 暴.png │ ├── 曾.png │ ├── 有.png │ ├── 朝.png │ ├── 本.png │ ├── 朴.png │ ├── 机.png │ ├── 柔.png │ ├── 柯.png │ ├── 标.png │ ├── 梅.png │ ├── 欢.png │ ├── 欣.png │ ├── 欧.png │ ├── 正.png │ ├── 殷.png │ ├── 永.png │ ├── 沉.png │ ├── 洁.png │ ├── 活.png │ ├── 济.png │ ├── 淡.png │ ├── 深.png │ ├── 清.png │ ├── 温.png │ ├── 满.png │ ├── 漂.png │ ├── 潇.png │ ├── 激.png │ ├── 火.png │ ├── 灵.png │ ├── 炙.png │ ├── 烂.png │ ├── 热.png │ ├── 爱.png │ ├── 犹.png │ ├── 狂.png │ ├── 独.png │ ├── 玩.png │ ├── 现.png │ ├── 甜.png │ ├── 生.png │ ├── 畅.png │ ├── 留.png │ ├── 疯.png │ ├── 痴.png │ ├── 瘦.png │ ├── 盖.png │ ├── 直.png │ ├── 眯.png │ ├── 眼.png │ ├── 着.png │ ├── 知.png │ ├── 矮.png │ ├── 碧.png │ ├── 神.png │ ├── 秀.png │ ├── 科.png │ ├── 积.png │ ├── 称.png │ ├── 稳.png │ ├── 端.png │ ├── 笑.png │ ├── 笨.png │ ├── 等.png │ ├── 简.png │ ├── 米.png │ ├── 粗.png │ ├── 精.png │ ├── 糊.png │ ├── 糟.png │ ├── 索.png │ ├── 紧.png │ ├── 繁.png │ ├── 约.png │ ├── 纯.png │ ├── 细.png │ ├── 结.png │ ├── 缓.png │ ├── 缥.png │ ├── 罗.png │ ├── 美.png │ ├── 羞.png │ ├── 老.png │ ├── 耍.png │ ├── 聪.png │ ├── 肖.png │ ├── 肯.png │ ├── 背.png │ ├── 能.png │ ├── 腼.png │ ├── 自.png │ ├── 舒.png │ ├── 花.png │ ├── 苏.png │ ├── 苗.png │ ├── 英.png │ ├── 苹.png │ ├── 范.png │ ├── 莫.png │ ├── 萧.png │ ├── 落.png │ ├── 虚.png │ ├── 西.png │ ├── 要.png │ ├── 认.png │ ├── 诚.png │ ├── 调.png │ ├── 谦.png │ ├── 谨.png │ ├── 贝.png │ ├── 负.png │ ├── 贤.png │ ├── 贪.png │ ├── 超.png │ ├── 跳.png │ ├── 踏.png │ ├── 轻.png │ ├── 辛.png │ ├── 迅.png │ ├── 过.png │ ├── 还.png │ ├── 迪.png │ ├── 迷.png │ ├── 追.png │ ├── 酷.png │ ├── 醉.png │ ├── 重.png │ ├── 野.png │ ├── 长.png │ ├── 闪.png │ ├── 阔.png │ ├── 阳.png │ ├── 陶.png │ ├── 隐.png │ ├── 难.png │ ├── 雅.png │ ├── 雪.png │ ├── 震.png │ ├── 霸.png │ ├── 靓.png │ ├── 顺.png │ ├── 风.png │ ├── 飘.png │ ├── 饱.png │ ├── 香.png │ ├── 高.png │ ├── 魁.png │ ├── 魔.png │ ├── 鲁.png │ ├── 鲤.png │ ├── 鳗.png │ ├── 鸣.png │ ├── 默.png │ └── 齐.png ├── file │ ├── 4.png │ ├── ali.png │ ├── checken_logo.png │ ├── login_bg_black.jpg │ ├── login_bg_light.jpg │ ├── qq_logo.png │ ├── qq二维码.jpg │ ├── vue.png │ ├── wechat二维码.jpg │ └── zhangsan │ │ ├── qq_20230803005636.jpg │ │ ├── qq_20230803005740.jpg │ │ ├── wechat_20230803005639.jpg │ │ └── wechat_20230803005743.jpg ├── system │ └── 青鸟华光简美黑.ttf └── test │ ├── A.png │ ├── 无.png │ ├── 柯.png │ └── 西.png └── utils ├── desens └── enter.go ├── get_addr_by_ip.go ├── jwts ├── enter.go ├── gen_token.go └── parse_token.go ├── md5.go ├── net.go ├── print_system.go ├── pwd ├── pwd.go └── pwd_test.go ├── random ├── code.go └── string.go ├── requests └── post.go ├── utils.go └── valid.go /.air.toml: -------------------------------------------------------------------------------- 1 | root = "." 2 | testdata_dir = "testdata" 3 | tmp_dir = "tmp" 4 | 5 | [build] 6 | args_bin = [] 7 | bin = "tmp\\main.exe" 8 | cmd = "go build -o ./tmp/main.exe ." 9 | delay = 0 10 | exclude_dir = ["assets", "tmp", "vendor", "testdata",".idea",".git"] 11 | exclude_file = [] 12 | exclude_regex = ["_test.go"] 13 | exclude_unchanged = false 14 | follow_symlink = false 15 | full_bin = "" 16 | include_dir = [] 17 | include_ext = ["go", "tpl", "tmpl", "html"] 18 | include_file = [] 19 | kill_delay = "0s" 20 | log = "build-errors.log" 21 | rerun = false 22 | rerun_delay = 500 23 | send_interrupt = false 24 | stop_on_error = false 25 | 26 | [color] 27 | app = "" 28 | build = "yellow" 29 | main = "magenta" 30 | runner = "green" 31 | watcher = "cyan" 32 | 33 | [log] 34 | main_only = false 35 | time = false 36 | 37 | [misc] 38 | clean_on_exit = false 39 | 40 | [screen] 41 | clear_on_rebuild = false 42 | keep_scroll = true 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | settings.yaml 3 | local_settings.yaml 4 | .uploads/file 5 | main 6 | main.exe -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/dataSources.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | mysql.8 6 | true 7 | com.mysql.cj.jdbc.Driver 8 | jdbc:mysql://localhost:3306/gvb_db 9 | $ProjectFileDir$ 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/gvb_server.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /api/advert_api/advert_create.go: -------------------------------------------------------------------------------- 1 | package advert_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "gvb_server/global" 6 | "gvb_server/models" 7 | "gvb_server/models/res" 8 | ) 9 | 10 | type AdvertRequest struct { 11 | Title string `json:"title" binding:"required" msg:"请输入标题" structs:"title"` // 显示的标题 12 | Href string `json:"href" binding:"required,url" msg:"跳转链接非法" structs:"href"` // 跳转链接 13 | Images string `json:"images" binding:"required,url" msg:"图片地址非法" structs:"images"` // 图片 14 | IsShow bool `json:"is_show" structs:"is_show"` // 是否展示 15 | } 16 | 17 | // AdvertCreateView 创建广告 18 | // @Tags 广告管理 19 | // @Summary 创建广告 20 | // @Description 创建广告 21 | // @Param data body AdvertRequest true "表示多个参数" 22 | // @Param token header string true "token" 23 | // @Router /api/adverts [post] 24 | // @Produce json 25 | // @Success 200 {object} res.Response{} 26 | func (AdvertApi) AdvertCreateView(c *gin.Context) { 27 | var cr AdvertRequest 28 | err := c.ShouldBindJSON(&cr) 29 | if err != nil { 30 | res.FailWithError(err, &cr, c) 31 | return 32 | } 33 | // 重复的判断 34 | var advert models.AdvertModel 35 | err = global.DB.Take(&advert, "title = ?", cr.Title).Error 36 | if err == nil { 37 | res.FailWithMessage("该广告已存在", c) 38 | return 39 | } 40 | 41 | err = global.DB.Create(&models.AdvertModel{ 42 | Title: cr.Title, 43 | Href: cr.Href, 44 | Images: cr.Images, 45 | IsShow: cr.IsShow, 46 | }).Error 47 | 48 | if err != nil { 49 | global.Log.Error(err) 50 | res.FailWithMessage("添加广告失败", c) 51 | return 52 | } 53 | 54 | res.OkWithMessage("添加广告成功", c) 55 | } 56 | -------------------------------------------------------------------------------- /api/advert_api/advert_list.go: -------------------------------------------------------------------------------- 1 | package advert_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "gvb_server/models" 6 | "gvb_server/models/res" 7 | "gvb_server/service/common" 8 | "strings" 9 | ) 10 | 11 | // AdvertListView 广告列表 12 | // @Tags 广告管理 13 | // @Summary 广告列表 14 | // @Description 广告列表 15 | // @Param data query models.PageInfo false "查询参数" 16 | // @Router /api/adverts [get] 17 | // @Produce json 18 | // @Success 200 {object} res.Response{data=res.ListResponse[models.AdvertModel]} 19 | func (AdvertApi) AdvertListView(c *gin.Context) { 20 | var cr models.PageInfo 21 | if err := c.ShouldBindQuery(&cr); err != nil { 22 | res.FailWithCode(res.ArgumentError, c) 23 | return 24 | } 25 | // 判断 Referer 是否包含admin,如果是,就全部返回,不是,就返回is_show=true 26 | referer := c.GetHeader("Referer") 27 | isShow := true 28 | if strings.Contains(referer, "admin") { 29 | //admin 来的 30 | isShow = false 31 | } 32 | list, count, _ := common.ComList(models.AdvertModel{IsShow: isShow}, common.Option{ 33 | PageInfo: cr, 34 | }) 35 | res.OkWithList(list, count, c) 36 | } 37 | -------------------------------------------------------------------------------- /api/advert_api/advert_remove.go: -------------------------------------------------------------------------------- 1 | package advert_api 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gin-gonic/gin" 6 | "gvb_server/global" 7 | "gvb_server/models" 8 | "gvb_server/models/res" 9 | ) 10 | 11 | // AdvertRemoveView 批量删除广告 12 | // @Tags 广告管理 13 | // @Summary 批量删除广告 14 | // @Description 批量删除广告 15 | // @Param data body models.RemoveRequest true "广告id列表" 16 | // @Param token header string true "token" 17 | // @Router /api/adverts [delete] 18 | // @Produce json 19 | // @Success 200 {object} res.Response{data=string} 20 | func (AdvertApi) AdvertRemoveView(c *gin.Context) { 21 | var cr models.RemoveRequest 22 | err := c.ShouldBindJSON(&cr) 23 | if err != nil { 24 | res.FailWithCode(res.ArgumentError, c) 25 | return 26 | } 27 | 28 | var advertList []models.AdvertModel 29 | count := global.DB.Where("id in (?)", cr.IDList).Find(&advertList).RowsAffected 30 | if count == 0 { 31 | res.FailWithMessage("广告不存在", c) 32 | return 33 | } 34 | global.DB.Delete(&advertList) 35 | res.OkWithMessage(fmt.Sprintf("共删除 %d 个广告", count), c) 36 | } 37 | -------------------------------------------------------------------------------- /api/advert_api/advert_update.go: -------------------------------------------------------------------------------- 1 | package advert_api 2 | 3 | import ( 4 | "fmt" 5 | "github.com/fatih/structs" 6 | "github.com/gin-gonic/gin" 7 | "gvb_server/global" 8 | "gvb_server/models" 9 | "gvb_server/models/res" 10 | ) 11 | 12 | // AdvertUpdateView 更新广告 13 | // @Tags 广告管理 14 | // @Summary 更新广告 15 | // @Description 更新广告 16 | // @Param data body AdvertRequest true "广告的一些参数" 17 | // @Param id path int true "id" 18 | // @Param token header string true "token" 19 | // @Router /api/adverts/{id} [put] 20 | // @Produce json 21 | // @Success 200 {object} res.Response{data=string} 22 | func (AdvertApi) AdvertUpdateView(c *gin.Context) { 23 | 24 | id := c.Param("id") 25 | var cr AdvertRequest 26 | err := c.ShouldBindJSON(&cr) 27 | if err != nil { 28 | res.FailWithError(err, &cr, c) 29 | return 30 | } 31 | // 存在的判断 32 | var advert models.AdvertModel 33 | err = global.DB.Take(&advert, id).Error 34 | if err != nil { 35 | res.FailWithMessage("广告不存在", c) 36 | return 37 | } 38 | 39 | // 结构体转map的第三方包 40 | maps := structs.Map(&cr) 41 | fmt.Println(maps) 42 | err = global.DB.Model(&advert).Updates(maps).Error 43 | 44 | if err != nil { 45 | global.Log.Error(err) 46 | res.FailWithMessage("修改广告失败", c) 47 | return 48 | } 49 | 50 | res.OkWithMessage("修改广告成功", c) 51 | } 52 | -------------------------------------------------------------------------------- /api/advert_api/enter.go: -------------------------------------------------------------------------------- 1 | package advert_api 2 | 3 | type AdvertApi struct { 4 | } 5 | -------------------------------------------------------------------------------- /api/article_api/article_content.go: -------------------------------------------------------------------------------- 1 | package article_api 2 | 3 | import ( 4 | "context" 5 | "github.com/gin-gonic/gin" 6 | "github.com/goccy/go-json" 7 | "gvb_server/global" 8 | "gvb_server/models" 9 | "gvb_server/models/res" 10 | "gvb_server/service/redis_ser" 11 | ) 12 | 13 | // ArticleContentView 获取文章正文 14 | // @Tags 文章管理 15 | // @Summary 获取文章正文 16 | // @Description 获取文章正文 17 | // @Param id path string true "id" 18 | // @Router /api/articles/content/{id} [get] 19 | // @Produce json 20 | // @Success 200 {object} res.Response{} 21 | func (ArticleApi) ArticleContentView(c *gin.Context) { 22 | var cr models.ESIDRequest 23 | err := c.ShouldBindUri(&cr) 24 | if err != nil { 25 | res.FailWithCode(res.ArgumentError, c) 26 | return 27 | } 28 | // 用户浏览量 29 | redis_ser.NewArticleLook().Set(cr.ID) 30 | 31 | result, err := global.ESClient. 32 | Get(). 33 | Index(models.ArticleModel{}.Index()). 34 | Id(cr.ID). 35 | Do(context.Background()) 36 | if err != nil { 37 | res.FailWithMessage("查询失败", c) 38 | return 39 | } 40 | var model models.ArticleModel 41 | err = json.Unmarshal(result.Source, &model) 42 | if err != nil { 43 | return 44 | } 45 | res.OkWithData(model.Content, c) 46 | } 47 | -------------------------------------------------------------------------------- /api/article_api/article_digg.go: -------------------------------------------------------------------------------- 1 | package article_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "gvb_server/models" 6 | "gvb_server/models/res" 7 | "gvb_server/service/redis_ser" 8 | ) 9 | 10 | // ArticleDiggView 文章点赞 11 | // @Tags 文章管理 12 | // @Summary 文章点赞 13 | // @Description 文章点赞 14 | // @Param data body models.ESIDRequest true "表示多个参数" 15 | // @Router /api/article/digg [post] 16 | // @Produce json 17 | // @Success 200 {object} res.Response{data=string} 18 | func (ArticleApi) ArticleDiggView(c *gin.Context) { 19 | var cr models.ESIDRequest 20 | err := c.ShouldBindJSON(&cr) 21 | if err != nil { 22 | res.FailWithCode(res.ArgumentError, c) 23 | return 24 | } 25 | // id长度校验及查es文章是否存在(待补充) 26 | redis_ser.NewDigg().Set(cr.ID) 27 | res.OkWithMessage("文章点赞成功", c) 28 | } 29 | -------------------------------------------------------------------------------- /api/article_api/article_id_title_list.go: -------------------------------------------------------------------------------- 1 | package article_api 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "github.com/gin-gonic/gin" 7 | "github.com/olivere/elastic/v7" 8 | "gvb_server/global" 9 | "gvb_server/models" 10 | "gvb_server/models/res" 11 | ) 12 | 13 | type ArticleIDTitleListResponse struct { 14 | Label string `json:"label"` 15 | Value string `json:"value"` 16 | } 17 | 18 | // ArticleIDTitleListView 文章id-title列表 19 | // @Tags 文章管理 20 | // @Summary 文章id-title列表 21 | // @Description 文章id-title列表 22 | // @Param token header string false "token" 23 | // @Router /api/article_id_title [get] 24 | // @Produce json 25 | // @Success 200 {object} res.Response{data=[]ArticleIDTitleListResponse} 26 | func (ArticleApi) ArticleIDTitleListView(c *gin.Context) { 27 | result, err := global.ESClient. 28 | Search(models.ArticleModel{}.Index()). 29 | Query(elastic.NewBoolQuery()). 30 | Source(`{"_source":["title"]}`). 31 | Size(1000). 32 | Do(context.Background()) 33 | if err != nil { 34 | global.Log.Error(err) 35 | res.FailWithMessage("查询失败", c) 36 | return 37 | } 38 | 39 | var articleIDTitleList = make([]ArticleIDTitleListResponse, 0) 40 | for _, hit := range result.Hits.Hits { 41 | var model models.ArticleModel 42 | json.Unmarshal(hit.Source, &model) 43 | 44 | articleIDTitleList = append(articleIDTitleList, ArticleIDTitleListResponse{ 45 | Value: hit.Id, 46 | Label: model.Title, 47 | }) 48 | } 49 | res.OkWithData(articleIDTitleList, c) 50 | } 51 | -------------------------------------------------------------------------------- /api/article_api/article_remove.go: -------------------------------------------------------------------------------- 1 | package article_api 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/gin-gonic/gin" 7 | "github.com/olivere/elastic/v7" 8 | "gvb_server/global" 9 | "gvb_server/models" 10 | "gvb_server/models/res" 11 | "gvb_server/service/es_ser" 12 | ) 13 | 14 | type IDListRequest struct { 15 | IDList []string `json:"id_list"` 16 | } 17 | 18 | // ArticleRemoveView 批量删除文章 19 | // @Tags 文章管理 20 | // @Summary 批量删除文章 21 | // @Description 批量删除文章 22 | // @Param data body IDListRequest true "文章id列表" 23 | // @Router /api/articles [delete] 24 | // @Param token header string false "token" 25 | // @Produce json 26 | // @Success 200 {object} res.Response{data=string} 27 | func (ArticleApi) ArticleRemoveView(c *gin.Context) { 28 | var cr IDListRequest 29 | err := c.ShouldBindJSON(&cr) 30 | if err != nil { 31 | global.Log.Error(err) 32 | res.FailWithCode(res.ArgumentError, c) 33 | return 34 | } 35 | 36 | // 文章删除后,用户收藏过这篇文章如何处理?(代码待完善) 37 | // 1.删除时把文章关联的收藏也删除 38 | // 2.用户收藏表,新增一个字段,表示文章是否删除,用户可以删除这个收藏记录,但是找不到文章改收藏数 39 | bulkService := global.ESClient.Bulk().Index(models.ArticleModel{}.Index()).Refresh("true") 40 | for _, id := range cr.IDList { 41 | req := elastic.NewBulkDeleteRequest().Id(id) 42 | bulkService.Add(req) 43 | // 异步全文搜索删除 44 | go es_ser.DeleteFullTextByArticleID(id) 45 | } 46 | result, err := bulkService.Do(context.Background()) 47 | if err != nil { 48 | global.Log.Error(err) 49 | res.FailWithMessage("删除失败", c) 50 | return 51 | } 52 | res.OkWithMessage(fmt.Sprintf("成功删除 %d 篇文章", len(result.Succeeded())), c) 53 | } 54 | -------------------------------------------------------------------------------- /api/article_api/enter.go: -------------------------------------------------------------------------------- 1 | package article_api 2 | 3 | type ArticleApi struct { 4 | } 5 | -------------------------------------------------------------------------------- /api/chat_api/chat_list.go: -------------------------------------------------------------------------------- 1 | package chat_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/liu-cn/json-filter/filter" 6 | "gvb_server/models" 7 | "gvb_server/models/res" 8 | "gvb_server/service/common" 9 | ) 10 | 11 | // ChatListView 群聊记录 12 | // @Tags 群聊管理 13 | // @Summary 群聊记录 14 | // @Description 群聊记录 15 | // @Param data query models.PageInfo false "查询参数" 16 | // @Router /api/chat_groups_records [get] 17 | // @Produce json 18 | // @Success 200 {object} res.Response{data=res.ListResponse[models.ChatModel]} 19 | func (ChatApi) ChatListView(c *gin.Context) { 20 | var cr models.PageInfo 21 | err := c.ShouldBindQuery(&cr) 22 | if err != nil { 23 | res.FailWithCode(res.ArgumentError, c) 24 | return 25 | } 26 | 27 | cr.Sort = "created_at desc" 28 | list, count, _ := common.ComList(models.ChatModel{ISGroup: true}, common.Option{ 29 | PageInfo: cr, 30 | }) 31 | 32 | // 判断是否为空 json-filter空值问题 33 | data := filter.Omit("list", list) 34 | _list, _ := data.(filter.Filter) 35 | if string(_list.MustMarshalJSON()) == "{}" { 36 | list = make([]models.ChatModel, 0) 37 | res.OkWithList(list, count, c) 38 | return 39 | } 40 | res.OkWithList(data, count, c) 41 | } 42 | -------------------------------------------------------------------------------- /api/chat_api/enter.go: -------------------------------------------------------------------------------- 1 | package chat_api 2 | 3 | type ChatApi struct { 4 | } 5 | -------------------------------------------------------------------------------- /api/comment_api/comment_digg.go: -------------------------------------------------------------------------------- 1 | package comment_api 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gin-gonic/gin" 6 | "gvb_server/global" 7 | "gvb_server/models" 8 | "gvb_server/models/res" 9 | "gvb_server/service/redis_ser" 10 | ) 11 | 12 | type CommentIDRequest struct { 13 | ID uint `json:"id" form:"id" uri:"id"` 14 | } 15 | 16 | // CommentDigg 评论点赞 17 | // @Tags 评论管理 18 | // @Summary 评论点赞 19 | // @Description 评论点赞 20 | // @Param data body CommentIDRequest true "表示多个参数" 21 | // @Param id path int true "文章id" 22 | // @Router /api/comments/{id} [post] 23 | // @Produce json 24 | // @Success 200 {object} res.Response{} 25 | func (CommentApi) CommentDigg(c *gin.Context) { 26 | var cr CommentIDRequest 27 | err := c.ShouldBindUri(&cr) 28 | if err != nil { 29 | res.FailWithCode(res.ArgumentError, c) 30 | return 31 | } 32 | 33 | // 评论是否存在 34 | var commentModel models.CommentModel 35 | err = global.DB.Take(&commentModel, cr.ID).Error 36 | if err != nil { 37 | res.FailWithMessage("评论不存在", c) 38 | return 39 | } 40 | 41 | redis_ser.NewCommentDigg().Set(fmt.Sprintf("%d", cr.ID)) 42 | res.OkWithMessage("评论点赞成功", c) 43 | } 44 | -------------------------------------------------------------------------------- /api/comment_api/enter.go: -------------------------------------------------------------------------------- 1 | package comment_api 2 | 3 | type CommentApi struct { 4 | } 5 | -------------------------------------------------------------------------------- /api/data_api/enter.go: -------------------------------------------------------------------------------- 1 | package data_api 2 | 3 | type DataApi struct { 4 | } 5 | -------------------------------------------------------------------------------- /api/enter.go: -------------------------------------------------------------------------------- 1 | package api 2 | 3 | import ( 4 | "gvb_server/api/advert_api" 5 | "gvb_server/api/article_api" 6 | "gvb_server/api/chat_api" 7 | "gvb_server/api/comment_api" 8 | "gvb_server/api/data_api" 9 | "gvb_server/api/images_api" 10 | "gvb_server/api/log_api" 11 | "gvb_server/api/menu_api" 12 | "gvb_server/api/message_api" 13 | "gvb_server/api/new_api" 14 | "gvb_server/api/settings_api" 15 | "gvb_server/api/tag_api" 16 | "gvb_server/api/user_api" 17 | ) 18 | 19 | type ApiGroup struct { 20 | SettingApi settings_api.SettingApi 21 | ImagesApi images_api.ImagesApi 22 | AdvertApi advert_api.AdvertApi 23 | MenuApi menu_api.MenuApi 24 | UserApi user_api.UserApi 25 | TagApi tag_api.TagApi 26 | MessageApi message_api.MessageApi 27 | ArticleApi article_api.ArticleApi 28 | CommentApi comment_api.CommentApi 29 | NewsApi new_api.NewsApi 30 | ChatApi chat_api.ChatApi 31 | LogApi log_api.LogApi 32 | DataApi data_api.DataApi 33 | } 34 | 35 | var ApiGroupApp = new(ApiGroup) 36 | -------------------------------------------------------------------------------- /api/images_api/enter.go: -------------------------------------------------------------------------------- 1 | package images_api 2 | 3 | type ImagesApi struct { 4 | } 5 | -------------------------------------------------------------------------------- /api/images_api/image_list.go: -------------------------------------------------------------------------------- 1 | package images_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "gvb_server/models" 6 | "gvb_server/models/res" 7 | "gvb_server/service/common" 8 | ) 9 | 10 | // ImageListView 图片列表 11 | // @Tags 图片管理 12 | // @Summary 图片列表 13 | // @Description 图片列表 14 | // @Param data query models.PageInfo false "查询参数" 15 | // @Router /api/images [get] 16 | // @Produce json 17 | // @Success 200 {object} res.Response{data=res.ListResponse[models.BannerModel]} 18 | func (ImagesApi) ImageListView(c *gin.Context) { 19 | var cr models.PageInfo 20 | err := c.ShouldBindQuery(&cr) 21 | if err != nil { 22 | res.FailWithCode(res.ArgumentError, c) 23 | return 24 | } 25 | 26 | list, count, err := common.ComList(models.BannerModel{}, common.Option{ 27 | PageInfo: cr, 28 | Likes: []string{"name"}, 29 | }) 30 | 31 | res.OkWithList(list, count, c) 32 | return 33 | } 34 | -------------------------------------------------------------------------------- /api/images_api/image_name_list.go: -------------------------------------------------------------------------------- 1 | package images_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "gvb_server/global" 6 | "gvb_server/models" 7 | "gvb_server/models/res" 8 | ) 9 | 10 | type ImageResponse struct { 11 | ID uint `json:"id"` 12 | Path string `json:"path"` // 图片路径 13 | Name string `json:"name"` // 图片名称 14 | } 15 | 16 | // ImageNameListView 图片名称列表 17 | // @Tags 图片管理 18 | // @Summary 图片名称列表 19 | // @Description 图片名称列表 20 | // @Router /api/image_names [get] 21 | // @Produce json 22 | // @Success 200 {object} res.Response{data=[]ImageResponse} 23 | func (ImagesApi) ImageNameListView(c *gin.Context) { 24 | var imageList []ImageResponse 25 | global.DB.Model(models.BannerModel{}).Select("id", "path", "name").Scan(&imageList) 26 | res.OkWithData(imageList, c) 27 | } 28 | -------------------------------------------------------------------------------- /api/images_api/image_remove.go: -------------------------------------------------------------------------------- 1 | package images_api 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gin-gonic/gin" 6 | "gvb_server/global" 7 | "gvb_server/models" 8 | "gvb_server/models/res" 9 | ) 10 | 11 | // ImageRemoveView 批量删除图片 12 | // @Tags 图片管理 13 | // @Summary 批量删除图片 14 | // @Description 批量删除图片 15 | // @Param data body models.RemoveRequest true "图片id列表" 16 | // @Router /api/images [delete] 17 | // @Produce json 18 | // @Success 200 {object} res.Response{data=string} 19 | func (ImagesApi) ImageRemoveView(c *gin.Context) { 20 | var cr models.RemoveRequest 21 | err := c.ShouldBindJSON(&cr) 22 | if err != nil { 23 | res.FailWithCode(res.ArgumentError, c) 24 | return 25 | } 26 | 27 | var imageList []models.BannerModel 28 | count := global.DB.Where("id in (?)", cr.IDList).Find(&imageList, cr.IDList).RowsAffected 29 | if count == 0 { 30 | res.FailWithMessage("文件不存在", c) 31 | return 32 | } 33 | global.DB.Where("id in (?)", cr.IDList).Delete(&imageList) 34 | res.OkWithMessage(fmt.Sprintf("共删除 %d 张图片", count), c) 35 | } 36 | -------------------------------------------------------------------------------- /api/images_api/image_update.go: -------------------------------------------------------------------------------- 1 | package images_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "gvb_server/global" 6 | "gvb_server/models" 7 | "gvb_server/models/res" 8 | ) 9 | 10 | type ImageUpdateRequest struct { 11 | ID uint `json:"id" binding:"required" msg:"请选择文件id"` 12 | Name string `json:"name" binding:"required" msg:"请输入文件名称"` 13 | } 14 | 15 | // ImageUpdateView 更新图片 16 | // @Tags 图片管理 17 | // @Summary 更新图片 18 | // @Description 更新图片 19 | // @Param data body ImageUpdateRequest true "图片的一些参数" 20 | // @Param token header string true "token" 21 | // @Router /api/images/{id} [put] 22 | // @Produce json 23 | // @Success 200 {object} res.Response{data=string} 24 | func (ImagesApi) ImageUpdateView(c *gin.Context) { 25 | var cr ImageUpdateRequest 26 | err := c.ShouldBindJSON(&cr) 27 | if err != nil { 28 | res.FailWithError(err, &cr, c) 29 | return 30 | } 31 | var imageModel models.BannerModel 32 | err = global.DB.Take(&imageModel, cr.ID).Error 33 | if err != nil { 34 | res.FailWithMessage("文件不存在", c) 35 | return 36 | } 37 | err = global.DB.Model(&imageModel).Update("name", cr.Name).Error 38 | if err != nil { 39 | res.FailWithMessage(err.Error(), c) 40 | return 41 | } 42 | res.OkWithMessage("图片名称修改成功", c) 43 | return 44 | 45 | } 46 | -------------------------------------------------------------------------------- /api/log_api/enter.go: -------------------------------------------------------------------------------- 1 | package log_api 2 | 3 | type LogApi struct { 4 | } 5 | -------------------------------------------------------------------------------- /api/log_api/log_list.go: -------------------------------------------------------------------------------- 1 | package log_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "gvb_server/models" 6 | "gvb_server/models/res" 7 | "gvb_server/plugins/log_stash" 8 | "gvb_server/service/common" 9 | ) 10 | 11 | type LogRequest struct { 12 | models.PageInfo 13 | Level log_stash.Level `form:"level"` 14 | } 15 | 16 | // LogListView 日志列表 17 | // @Tags 日志管理 18 | // @Summary 日志列表 19 | // @Description 日志列表 20 | // @Param data query LogRequest false "查询参数" 21 | // @Param level query int false "日志等级" 22 | // @Router /api/logs [get] 23 | // @Produce json 24 | // @Success 200 {object} res.Response{data=res.ListResponse[log_stash.LogStashModel]} 25 | func (LogApi) LogListView(c *gin.Context) { 26 | var cr LogRequest 27 | err := c.ShouldBindQuery(&cr) 28 | if err != nil { 29 | res.FailWithCode(res.ArgumentError, c) 30 | return 31 | } 32 | if cr.Sort == "" { 33 | cr.Sort = "created_at desc" 34 | } 35 | 36 | list, count, _ := common.ComList(log_stash.LogStashModel{Level: cr.Level}, common.Option{ 37 | PageInfo: cr.PageInfo, 38 | Debug: false, 39 | Likes: []string{"ip", "addr"}, 40 | }) 41 | res.OkWithList(list, count, c) 42 | return 43 | 44 | } 45 | -------------------------------------------------------------------------------- /api/log_api/log_remove.go: -------------------------------------------------------------------------------- 1 | package log_api 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gin-gonic/gin" 6 | "gvb_server/global" 7 | "gvb_server/models" 8 | "gvb_server/models/res" 9 | "gvb_server/plugins/log_stash" 10 | ) 11 | 12 | // LogRemoveListView 批量删除日志 13 | // @Tags 日志管理 14 | // @Summary 批量删除日志 15 | // @Description 批量删除日志 16 | // @Param data body models.RemoveRequest true "日志id列表" 17 | // @Param token header string true "token" 18 | // @Router /api/logs [delete] 19 | // @Produce json 20 | // @Success 200 {object} res.Response{data=string} 21 | func (LogApi) LogRemoveListView(c *gin.Context) { 22 | var cr models.RemoveRequest 23 | err := c.ShouldBindJSON(&cr) 24 | if err != nil { 25 | res.FailWithCode(res.ArgumentError, c) 26 | return 27 | } 28 | 29 | var List []log_stash.LogStashModel 30 | count := global.DB.Where("id in (?)", cr.IDList).Find(&List).RowsAffected 31 | if count == 0 { 32 | res.FailWithMessage("日志不存在", c) 33 | return 34 | } 35 | global.DB.Delete(&List) 36 | res.OkWithMessage(fmt.Sprintf("共删除 %d 个日志", count), c) 37 | } 38 | -------------------------------------------------------------------------------- /api/menu_api/enter.go: -------------------------------------------------------------------------------- 1 | package menu_api 2 | 3 | type MenuApi struct { 4 | } 5 | -------------------------------------------------------------------------------- /api/menu_api/menu_detail.go: -------------------------------------------------------------------------------- 1 | package menu_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "gvb_server/global" 6 | "gvb_server/models" 7 | "gvb_server/models/res" 8 | ) 9 | 10 | // MenuDetailView 菜单详情 11 | // @Tags 菜单管理 12 | // @Summary 菜单详情 13 | // @Description 菜单详情 14 | // @Param id path int true "id" 15 | // @Router /api/menus/{id} [get] 16 | // @Produce json 17 | // @Success 200 {object} res.Response{data=MenuResponse} 18 | func (MenuApi) MenuDetailView(c *gin.Context) { 19 | // 先查菜单 20 | id := c.Param("id") 21 | var menuModel models.MenuModel 22 | err := global.DB.Take(&menuModel, id).Error 23 | if err != nil { 24 | res.FailWithMessage("菜单不存在", c) 25 | return 26 | } 27 | 28 | // 查连接表 29 | var menuBanners []models.MenuBannerModel 30 | global.DB.Preload("BannerModel").Order("sort desc").Find(&menuBanners, "menu_id = ?", id) 31 | var banners = make([]Banner, 0) // 解决切片null值问题(如果只声明不赋值且是引用类型,前端显示的null) 32 | for _, banner := range menuBanners { 33 | if menuModel.ID != banner.MenuID { 34 | continue 35 | } 36 | banners = append(banners, Banner{ 37 | ID: banner.BannerID, 38 | Path: banner.BannerModel.Path, 39 | }) 40 | } 41 | menuResponse := MenuResponse{ 42 | MenuModel: menuModel, 43 | Banners: banners, 44 | } 45 | res.OkWithData(menuResponse, c) 46 | return 47 | 48 | } 49 | -------------------------------------------------------------------------------- /api/menu_api/menu_detail_by_path.go: -------------------------------------------------------------------------------- 1 | package menu_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "gvb_server/global" 6 | "gvb_server/models" 7 | "gvb_server/models/res" 8 | ) 9 | 10 | type MenuDetailRequest struct { 11 | Path string `json:"path" form:"path"` 12 | } 13 | 14 | // MenuDetailByPathView 菜单详情,根据路径查 15 | // @Tags 菜单管理 16 | // @Summary 菜单详情,根据路径查 17 | // @Description 菜单详情,根据路径查 18 | // @Param data query MenuDetailRequest true "路径参数" 19 | // @Router /api/menus/detail [get] 20 | // @Produce json 21 | // @Success 200 {object} res.Response{data=MenuResponse} 22 | func (MenuApi) MenuDetailByPathView(c *gin.Context) { 23 | // 先查菜单 24 | var cr MenuDetailRequest 25 | err := c.ShouldBindQuery(&cr) 26 | if err != nil { 27 | res.FailWithCode(res.ArgumentError, c) 28 | return 29 | } 30 | var menuModel models.MenuModel 31 | err = global.DB.Take(&menuModel, "path = ?", cr.Path).Error 32 | if err != nil { 33 | res.FailWithMessage("菜单不存在", c) 34 | return 35 | } 36 | // 查连接表 37 | var menuBanners []models.MenuBannerModel 38 | global.DB.Preload("BannerModel").Order("sort desc").Find(&menuBanners, "menu_id = ?", menuModel.ID) 39 | var banners = make([]Banner, 0) 40 | for _, banner := range menuBanners { 41 | if menuModel.ID != banner.MenuID { 42 | continue 43 | } 44 | banners = append(banners, Banner{ 45 | ID: banner.BannerID, 46 | Path: banner.BannerModel.Path, 47 | }) 48 | } 49 | menuResponse := MenuResponse{ 50 | MenuModel: menuModel, 51 | Banners: banners, 52 | } 53 | res.OkWithData(menuResponse, c) 54 | return 55 | } 56 | -------------------------------------------------------------------------------- /api/menu_api/menu_list.go: -------------------------------------------------------------------------------- 1 | package menu_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "gvb_server/global" 6 | "gvb_server/models" 7 | "gvb_server/models/res" 8 | ) 9 | 10 | type Banner struct { 11 | ID uint `json:"id"` 12 | Path string `json:"path"` 13 | } 14 | 15 | type MenuResponse struct { 16 | models.MenuModel 17 | Banners []Banner `json:"banners"` 18 | } 19 | 20 | // MenuListView 菜单列表 21 | // @Tags 菜单管理 22 | // @Summary 菜单列表 23 | // @Description 菜单列表 24 | // @Router /api/menus [get] 25 | // @Produce json 26 | // @Success 200 {object} res.Response{data=[]MenuResponse} 27 | func (MenuApi) MenuListView(c *gin.Context) { 28 | // 先查菜单 29 | var menuList []models.MenuModel 30 | var menuIDList []uint 31 | global.DB.Order("sort desc").Find(&menuList).Select("id").Scan(&menuIDList) 32 | // 查连接表 33 | var menuBanners []models.MenuBannerModel 34 | global.DB.Preload("BannerModel").Order("sort").Find(&menuBanners, "menu_id in ?", menuIDList) 35 | var menus = make([]MenuResponse, 0) 36 | for _, model := range menuList { 37 | // model就是一个菜单 38 | var banners = make([]Banner, 0) // 解决切片null值问题(如果只声明不赋值且是引用类型,前端显示的null) 39 | for _, banner := range menuBanners { 40 | if model.ID != banner.MenuID { 41 | continue 42 | } 43 | banners = append(banners, Banner{ 44 | ID: banner.BannerID, 45 | Path: banner.BannerModel.Path, 46 | }) 47 | } 48 | menus = append(menus, MenuResponse{ 49 | MenuModel: model, 50 | Banners: banners, 51 | }) 52 | } 53 | 54 | res.OkWithList(menus, int64(len(menus)), c) 55 | return 56 | 57 | } 58 | -------------------------------------------------------------------------------- /api/menu_api/menu_name_list.go: -------------------------------------------------------------------------------- 1 | package menu_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "gvb_server/global" 6 | "gvb_server/models" 7 | "gvb_server/models/res" 8 | ) 9 | 10 | type MenuNameResponse struct { 11 | ID uint `json:"id"` 12 | Title string `json:"title"` 13 | Path string `json:"path"` 14 | } 15 | 16 | // MenuNameList 菜单名称列表 17 | // @Tags 菜单管理 18 | // @Summary 菜单名称列表 19 | // @Description 菜单名称列表 20 | // @Router /api/menu_names [get] 21 | // @Produce json 22 | // @Success 200 {object} res.Response{data=[]MenuNameResponse} 23 | func (MenuApi) MenuNameList(c *gin.Context) { 24 | var menuNameList []MenuNameResponse 25 | global.DB.Model(models.MenuModel{}).Select("id", "title", "path").Scan(&menuNameList) 26 | res.OkWithData(menuNameList, c) 27 | } 28 | -------------------------------------------------------------------------------- /api/menu_api/menu_remove.go: -------------------------------------------------------------------------------- 1 | package menu_api 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gin-gonic/gin" 6 | "gorm.io/gorm" 7 | "gvb_server/global" 8 | "gvb_server/models" 9 | "gvb_server/models/res" 10 | ) 11 | 12 | // MenuRemoveView 批量删除菜单 13 | // @Tags 菜单管理 14 | // @Summary 批量删除菜单 15 | // @Description 批量删除菜单 16 | // @Param data body models.RemoveRequest true "菜单id列表" 17 | // @Router /api/menus [delete] 18 | // @Produce json 19 | // @Success 200 {object} res.Response{data=string} 20 | func (MenuApi) MenuRemoveView(c *gin.Context) { 21 | var cr models.RemoveRequest 22 | err := c.ShouldBindJSON(&cr) 23 | if err != nil { 24 | res.FailWithCode(res.ArgumentError, c) 25 | return 26 | } 27 | 28 | var MenuList []models.MenuModel 29 | count := global.DB.Find(&MenuList, cr.IDList).RowsAffected 30 | if count == 0 { 31 | res.FailWithMessage("菜单不存在", c) 32 | return 33 | } 34 | 35 | // 事务 36 | err = global.DB.Transaction(func(tx *gorm.DB) error { 37 | err = global.DB.Model(&MenuList).Association("Banners").Clear() 38 | if err != nil { 39 | global.Log.Error(err) 40 | return err 41 | } 42 | err = global.DB.Delete(&MenuList).Error 43 | if err != nil { 44 | global.Log.Error(err) 45 | return err 46 | } 47 | return nil 48 | }) 49 | if err != nil { 50 | global.Log.Error(err) 51 | res.FailWithMessage("删除菜单失败", c) 52 | return 53 | } 54 | 55 | res.OkWithMessage(fmt.Sprintf("共删除 %d 个菜单", count), c) 56 | } 57 | -------------------------------------------------------------------------------- /api/message_api/enter.go: -------------------------------------------------------------------------------- 1 | package message_api 2 | 3 | type MessageApi struct { 4 | } 5 | -------------------------------------------------------------------------------- /api/message_api/message_list_all.go: -------------------------------------------------------------------------------- 1 | package message_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "gvb_server/models" 6 | "gvb_server/models/res" 7 | "gvb_server/service/common" 8 | ) 9 | 10 | // MessageListAllView 消息列表 11 | // @Tags 消息管理 12 | // @Summary 消息列表 13 | // @Description 消息列表 14 | // @Param token header string true "token" 15 | // @Router /api/messages_all [get] 16 | // @Produce json 17 | // @Success 200 {object} res.Response{data=res.ListResponse[MessageGroup]} 18 | func (MessageApi) MessageListAllView(c *gin.Context) { 19 | var cr models.PageInfo 20 | if err := c.ShouldBindQuery(&cr); err != nil { 21 | res.FailWithCode(res.ArgumentError, c) 22 | return 23 | } 24 | 25 | list, count, _ := common.ComList(models.MessageModel{}, common.Option{ 26 | PageInfo: cr, 27 | }) 28 | 29 | // 需要展示这个标签下文章的数量 30 | res.OkWithList(list, count, c) 31 | } 32 | -------------------------------------------------------------------------------- /api/message_api/message_record.go: -------------------------------------------------------------------------------- 1 | package message_api 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gin-gonic/gin" 6 | "gvb_server/global" 7 | "gvb_server/models" 8 | "gvb_server/models/res" 9 | "gvb_server/utils/jwts" 10 | ) 11 | 12 | type MessageRecordRequest struct { 13 | UserID uint `json:"user_id" binding:"required" msg:"请输入查询的用户id"` 14 | } 15 | 16 | // MessageRecordView 聊天记录 17 | // @Tags 消息管理 18 | // @Summary 聊天记录 19 | // @Description 聊天记录 20 | // @Param token header string true "token" 21 | // @Router /api/messages_record [post] 22 | // @Produce json 23 | // @Success 200 {object} res.Response{data=res.ListResponse[models.MessageModel]} 24 | func (MessageApi) MessageRecordView(c *gin.Context) { 25 | var cr MessageRecordRequest 26 | err := c.ShouldBindJSON(&cr) 27 | if err != nil { 28 | fmt.Println(err) 29 | res.FailWithError(err, &cr, c) 30 | return 31 | } 32 | _claims, _ := c.Get("claims") 33 | claims := _claims.(*jwts.CustomClaims) 34 | 35 | var _messageList []models.MessageModel 36 | var messageList = make([]models.MessageModel, 0) 37 | global.DB.Order("created_at asc"). 38 | Find(&_messageList, "send_user_id = ? or rev_user_id = ?", claims.UserID, claims.UserID) 39 | for _, model := range _messageList { 40 | // 判断是一个组的条件 41 | // send_user_id 和 rev_user_id 其中一个 42 | // 1 2 2 1 43 | // 1 3 3 1 是一组 44 | if model.RevUserID == cr.UserID || model.SendUserID == cr.UserID { 45 | messageList = append(messageList, model) 46 | } 47 | } 48 | 49 | // 点开消息,里面的每一条消息,都从未读变成已读 50 | 51 | res.OkWithData(messageList, c) 52 | return 53 | } 54 | -------------------------------------------------------------------------------- /api/new_api/enter.go: -------------------------------------------------------------------------------- 1 | package new_api 2 | 3 | type NewsApi struct { 4 | } 5 | -------------------------------------------------------------------------------- /api/settings_api/enter.go: -------------------------------------------------------------------------------- 1 | package settings_api 2 | 3 | type SettingApi struct { 4 | } 5 | -------------------------------------------------------------------------------- /api/settings_api/settings_info.go: -------------------------------------------------------------------------------- 1 | package settings_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "gvb_server/global" 6 | "gvb_server/models/res" 7 | ) 8 | 9 | type SettingsUri struct { 10 | Name string `uri:"name"` 11 | } 12 | 13 | // SettingsInfoView 显示配置信息 14 | // @Tags 配置管理 15 | // @Summary 显示配置信息 16 | // @Description 显示配置信息 email qq qiniu jwt 17 | // @Param name path string true "name" 18 | // @Param token header string true "token" 19 | // @Router /api/settings/{name} [get] 20 | // @Produce json 21 | // @Success 200 {object} res.Response{data=string} 22 | func (s SettingApi) SettingsInfoView(c *gin.Context) { 23 | var cr SettingsUri 24 | err := c.ShouldBindUri(&cr) 25 | if err != nil { 26 | res.FailWithCode(res.ArgumentError, c) 27 | return 28 | } 29 | 30 | switch cr.Name { 31 | case "email": 32 | res.OkWithData(global.Config.Email, c) 33 | case "qq": 34 | res.OkWithData(global.Config.QQ, c) 35 | case "qiniu": 36 | res.OkWithData(global.Config.QiNiu, c) 37 | case "jwt": 38 | res.OkWithData(global.Config.Jwt, c) 39 | default: 40 | res.FailWithMessage("没有对应的配置信息", c) 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /api/settings_api/settings_site_info.go: -------------------------------------------------------------------------------- 1 | package settings_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "gvb_server/global" 6 | "gvb_server/models/res" 7 | ) 8 | 9 | // SettingsSiteInfoView 显示网站信息配置 10 | // @Tags 配置管理 11 | // @Summary 显示网站信息配置 12 | // @Description 显示网站信息配置 13 | // @Router /api/settings/site [get] 14 | // @Produce json 15 | // @Success 200 {object} res.Response{data=config.SiteInfo} 16 | func (s SettingApi) SettingsSiteInfoView(c *gin.Context) { 17 | res.OkWithData(global.Config.SiteInfo, c) 18 | } 19 | -------------------------------------------------------------------------------- /api/settings_api/settings_site_update.go: -------------------------------------------------------------------------------- 1 | package settings_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "gvb_server/config" 6 | "gvb_server/core" 7 | "gvb_server/global" 8 | "gvb_server/models/res" 9 | ) 10 | 11 | // SettingsSiteUpdateView 编辑网站信息配置 12 | // @Tags 配置管理 13 | // @Summary 编辑网站信息配置 14 | // @Description 编辑网站信息配置 15 | // @Param data body config.SiteInfo true "编辑网站信息的参数" 16 | // @Param token header string true "token" 17 | // @Router /api/settings/site [put] 18 | // @Produce json 19 | // @Success 200 {object} res.Response{data=config.SiteInfo} 20 | func (s SettingApi) SettingsSiteUpdateView(c *gin.Context) { 21 | var info config.SiteInfo 22 | err := c.ShouldBindJSON(&info) 23 | if err != nil { 24 | res.FailWithCode(res.ArgumentError, c) 25 | return 26 | } 27 | global.Config.SiteInfo = info 28 | core.SetYaml() 29 | res.OkWithMessage("网站信息更新成功", c) 30 | } 31 | -------------------------------------------------------------------------------- /api/tag_api/enter.go: -------------------------------------------------------------------------------- 1 | package tag_api 2 | 3 | type TagApi struct { 4 | } 5 | -------------------------------------------------------------------------------- /api/tag_api/tag_create.go: -------------------------------------------------------------------------------- 1 | package tag_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "gvb_server/global" 6 | "gvb_server/models" 7 | "gvb_server/models/res" 8 | ) 9 | 10 | type TagRequest struct { 11 | Title string `json:"title" binding:"required" msg:"请输入标题" structs:"title"` // 显示的标题 12 | } 13 | 14 | // TagCreateView 创建标签 15 | // @Tags 标签管理 16 | // @Summary 创建标签 17 | // @Description 创建标签 18 | // @Param data body TagRequest true "表示多个参数" 19 | // @Param token header string true "token" 20 | // @Router /api/tags [post] 21 | // @Produce json 22 | // @Success 200 {object} res.Response{} 23 | func (TagApi) TagCreateView(c *gin.Context) { 24 | var cr TagRequest 25 | err := c.ShouldBindJSON(&cr) 26 | if err != nil { 27 | res.FailWithError(err, &cr, c) 28 | return 29 | } 30 | // 重复的判断 31 | var tag models.TagModel 32 | err = global.DB.Take(&tag, "title = ?", cr.Title).Error 33 | if err == nil { 34 | res.FailWithMessage("该标签已存在", c) 35 | return 36 | } 37 | 38 | err = global.DB.Create(&models.TagModel{ 39 | Title: cr.Title, 40 | }).Error 41 | 42 | if err != nil { 43 | global.Log.Error(err) 44 | res.FailWithMessage("添加标签失败", c) 45 | return 46 | } 47 | 48 | res.OkWithMessage("添加标签成功", c) 49 | } 50 | -------------------------------------------------------------------------------- /api/tag_api/tag_list.go: -------------------------------------------------------------------------------- 1 | package tag_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "gvb_server/models" 6 | "gvb_server/models/res" 7 | "gvb_server/service/common" 8 | ) 9 | 10 | // TagListView 标签列表 11 | // @Tags 标签管理 12 | // @Summary 标签列表 13 | // @Description 标签列表 14 | // @Param data query models.PageInfo false "查询参数" 15 | // @Router /api/tags [get] 16 | // @Produce json 17 | // @Success 200 {object} res.Response{data=res.ListResponse[models.TagModel]} 18 | func (TagApi) TagListView(c *gin.Context) { 19 | var cr models.PageInfo 20 | if err := c.ShouldBindQuery(&cr); err != nil { 21 | res.FailWithCode(res.ArgumentError, c) 22 | return 23 | } 24 | 25 | list, count, _ := common.ComList(models.TagModel{}, common.Option{ 26 | PageInfo: cr, 27 | }) 28 | // 需要展示这个标签下文章的数量 29 | res.OkWithList(list, count, c) 30 | } 31 | -------------------------------------------------------------------------------- /api/tag_api/tag_remove.go: -------------------------------------------------------------------------------- 1 | package tag_api 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gin-gonic/gin" 6 | "gvb_server/global" 7 | "gvb_server/models" 8 | "gvb_server/models/res" 9 | ) 10 | 11 | // TagRemoveView 批量删除标签 12 | // @Tags 标签管理 13 | // @Summary 批量删除标签 14 | // @Description 批量删除标签 15 | // @Param data body models.RemoveRequest true "标签id列表" 16 | // @Param token header string true "token" 17 | // @Router /api/tags [delete] 18 | // @Produce json 19 | // @Success 200 {object} res.Response{data=string} 20 | func (TagApi) TagRemoveView(c *gin.Context) { 21 | var cr models.RemoveRequest 22 | err := c.ShouldBindJSON(&cr) 23 | if err != nil { 24 | res.FailWithCode(res.ArgumentError, c) 25 | return 26 | } 27 | 28 | var tagList []models.TagModel 29 | count := global.DB.Where("id in (?)", cr.IDList).Find(&tagList).RowsAffected 30 | if count == 0 { 31 | res.FailWithMessage("标签不存在", c) 32 | return 33 | } 34 | // 如果这个标签下有文章,怎么办? 35 | global.DB.Delete(&tagList) 36 | res.OkWithMessage(fmt.Sprintf("共删除 %d 个标签", count), c) 37 | } 38 | -------------------------------------------------------------------------------- /api/tag_api/tag_update.go: -------------------------------------------------------------------------------- 1 | package tag_api 2 | 3 | import ( 4 | "fmt" 5 | "github.com/fatih/structs" 6 | "github.com/gin-gonic/gin" 7 | "gvb_server/global" 8 | "gvb_server/models" 9 | "gvb_server/models/res" 10 | ) 11 | 12 | // TagUpdateView 更新标签 13 | // @Tags 标签管理 14 | // @Summary 更新标签 15 | // @Description 更新标签 16 | // @Param data body TagRequest true "标签的一些参数" 17 | // @Param token header string true "token" 18 | // @Router /api/tags/{id} [put] 19 | // @Produce json 20 | // @Success 200 {object} res.Response{data=string} 21 | func (TagApi) TagUpdateView(c *gin.Context) { 22 | 23 | id := c.Param("id") 24 | var cr TagRequest 25 | err := c.ShouldBindJSON(&cr) 26 | if err != nil { 27 | res.FailWithError(err, &cr, c) 28 | return 29 | } 30 | // 存在的判断 31 | var tag models.TagModel 32 | err = global.DB.Take(&tag, id).Error 33 | if err != nil { 34 | res.FailWithMessage("标签不存在", c) 35 | return 36 | } 37 | 38 | // 结构体转map的第三方包 39 | maps := structs.Map(&cr) 40 | fmt.Println(maps) 41 | err = global.DB.Model(&tag).Updates(maps).Error 42 | 43 | if err != nil { 44 | global.Log.Error(err) 45 | res.FailWithMessage("修改标签失败", c) 46 | return 47 | } 48 | 49 | res.OkWithMessage("修改标签成功", c) 50 | } 51 | -------------------------------------------------------------------------------- /api/user_api/enter.go: -------------------------------------------------------------------------------- 1 | package user_api 2 | 3 | type UserApi struct { 4 | } 5 | -------------------------------------------------------------------------------- /api/user_api/qq_login_link.go: -------------------------------------------------------------------------------- 1 | package user_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "gvb_server/global" 6 | "gvb_server/models/res" 7 | ) 8 | 9 | // QQLoginLinkView 获取qq登录的跳转地址 10 | // @Tags 用户管理 11 | // @Summary 获取qq登录的跳转地址 12 | // @Description 获取qq登录的跳转地址,data就是qq的跳转地址 13 | // @Router /api/qq_login_path [get] 14 | // @Produce json 15 | // @Success 200 {object} res.Response{} 16 | func (UserApi) QQLoginLinkView(c *gin.Context) { 17 | path := global.Config.QQ.GetPath() 18 | if path == "" { 19 | res.FailWithMessage("未配置qq登录地址", c) 20 | return 21 | } 22 | 23 | res.OkWithData(path, c) 24 | return 25 | } 26 | -------------------------------------------------------------------------------- /api/user_api/user_create.go: -------------------------------------------------------------------------------- 1 | package user_api 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gin-gonic/gin" 6 | "gvb_server/global" 7 | "gvb_server/models/ctype" 8 | "gvb_server/models/res" 9 | "gvb_server/service/user_ser" 10 | ) 11 | 12 | type UserCreateRequest struct { 13 | NickName string `json:"nick_name" binding:"required" msg:"请输入昵称"` // 昵称 14 | UserName string `json:"user_name" binding:"required" msg:"请输入用户名"` // 用户名 15 | Password string `json:"password" binding:"required" msg:"请输入密码"` // 密码 16 | Role ctype.Role `json:"role" binding:"required" msg:"请选择权限"` // 权限 1 管理员 2 普通用户 3 游客 17 | } 18 | 19 | // UserCreateView 创建用户 20 | // @Tags 用户管理 21 | // @Summary 创建用户 22 | // @Description 创建用户 23 | // @Param data body UserCreateRequest true "表示多个参数" 24 | // @Param token header string true "token" 25 | // @Router /api/users [post] 26 | // @Produce json 27 | // @Success 200 {object} res.Response{} 28 | func (UserApi) UserCreateView(c *gin.Context) { 29 | var cr UserCreateRequest 30 | if err := c.ShouldBindJSON(&cr); err != nil { 31 | res.FailWithError(err, &cr, c) 32 | return 33 | } 34 | err := user_ser.UserService{}.CreateUser(cr.UserName, cr.NickName, cr.Password, cr.Role, "", c.ClientIP()) 35 | if err != nil { 36 | global.Log.Error(err) 37 | res.FailWithMessage(err.Error(), c) 38 | return 39 | } 40 | 41 | res.OkWithMessage(fmt.Sprintf("用户%s创建成功!", cr.UserName), c) 42 | return 43 | } 44 | -------------------------------------------------------------------------------- /api/user_api/user_info.go: -------------------------------------------------------------------------------- 1 | package user_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/liu-cn/json-filter/filter" 6 | "gvb_server/global" 7 | "gvb_server/models" 8 | "gvb_server/models/res" 9 | "gvb_server/utils/jwts" 10 | ) 11 | 12 | // UserInfoView 用户信息 13 | // @Tags 用户管理 14 | // @Summary 用户信息 15 | // @Description 用户信息 16 | // @Router /api/user_info [get] 17 | // @Param token header string true "token" 18 | // @Produce json 19 | // @Success 200 {object} res.Response{data=models.UserModel} 20 | func (UserApi) UserInfoView(c *gin.Context) { 21 | 22 | _claims, _ := c.Get("claims") 23 | claims := _claims.(*jwts.CustomClaims) 24 | 25 | var userInfo models.UserModel 26 | err := global.DB.Take(&userInfo, claims.UserID).Error 27 | if err != nil { 28 | res.FailWithMessage("用户不存在", c) 29 | return 30 | } 31 | 32 | res.OkWithData(filter.Select("info", userInfo), c) 33 | } 34 | -------------------------------------------------------------------------------- /api/user_api/user_logout.go: -------------------------------------------------------------------------------- 1 | package user_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "gvb_server/global" 6 | "gvb_server/models/res" 7 | "gvb_server/service" 8 | "gvb_server/utils/jwts" 9 | ) 10 | 11 | // LogoutView 用户注销 12 | // @Tags 用户管理 13 | // @Summary 用户注销 14 | // @Description 用户注销 15 | // @Param limit query string false "表示单个参数" 16 | // @Param token header string true "token" 17 | // @Router /api/logout [post] 18 | // @Produce json 19 | // @Success 200 {object} res.Response{data=string} 20 | func (UserApi) LogoutView(c *gin.Context) { 21 | _claims, _ := c.Get("claims") 22 | claims := _claims.(*jwts.CustomClaims) 23 | token := c.Request.Header.Get("token") 24 | 25 | err := service.ServiceApp.UserService.Logout(claims, token) 26 | if err != nil { 27 | global.Log.Error(err) 28 | res.FailWithMessage("注销失败", c) 29 | return 30 | } 31 | res.OkWithMessage("注销成功", c) 32 | } 33 | 34 | func (UserApi) name() { 35 | 36 | } 37 | -------------------------------------------------------------------------------- /api/user_api/user_remove.go: -------------------------------------------------------------------------------- 1 | package user_api 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gin-gonic/gin" 6 | "gorm.io/gorm" 7 | "gvb_server/global" 8 | "gvb_server/models" 9 | "gvb_server/models/res" 10 | ) 11 | 12 | // UserRemove 批量删除用户 13 | // @Tags 用户管理 14 | // @Summary 批量删除用户 15 | // @Description 批量删除用户 16 | // @Param data body models.RemoveRequest true "用户id列表" 17 | // @Param token header string true "token" 18 | // @Router /api/users [delete] 19 | // @Produce json 20 | // @Success 200 {object} res.Response{data=string} 21 | func (UserApi) UserRemove(c *gin.Context) { 22 | var cr models.RemoveRequest 23 | err := c.ShouldBindJSON(&cr) 24 | if err != nil { 25 | res.FailWithCode(res.ArgumentError, c) 26 | return 27 | } 28 | 29 | var UserList []models.UserModel 30 | count := global.DB.Find(&UserList, cr.IDList).RowsAffected 31 | if count == 0 { 32 | res.FailWithMessage("用户不存在", c) 33 | return 34 | } 35 | 36 | // 事务 37 | err = global.DB.Transaction(func(tx *gorm.DB) error { 38 | // TODO: 删除用户,消息表,评论表,用户收藏的文章,用户发布的文章 39 | /* 40 | err = global.DB.Model(&UserList).Association("Banners").Clear() 41 | if err != nil { 42 | global.Log.Error(err) 43 | return err 44 | }*/ 45 | err = global.DB.Delete(&UserList).Error 46 | if err != nil { 47 | global.Log.Error(err) 48 | return err 49 | } 50 | return nil 51 | }) 52 | if err != nil { 53 | global.Log.Error(err) 54 | res.FailWithMessage("删除用户失败", c) 55 | return 56 | } 57 | 58 | res.OkWithMessage(fmt.Sprintf("共删除 %d 个用户", count), c) 59 | } 60 | -------------------------------------------------------------------------------- /api/user_api/user_update_password.go: -------------------------------------------------------------------------------- 1 | package user_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "gvb_server/global" 6 | "gvb_server/models" 7 | "gvb_server/models/res" 8 | "gvb_server/utils/jwts" 9 | "gvb_server/utils/pwd" 10 | ) 11 | 12 | type UpdatePasswordRequest struct { 13 | OldPwd string `json:"old_pwd" binding:"required" msg:"请输入旧密码"` // 旧密码 14 | Pwd string `json:"pwd" binding:"required" msg:"请输入新密码"` // 新密码 15 | } 16 | 17 | // UserUpdatePassword 修改用户密码 18 | // @Tags 用户管理 19 | // @Summary 修改用户密码 20 | // @Description 修改用户密码 21 | // @Param data body UpdatePasswordRequest true "新旧密码" 22 | // @Param token header string true "token" 23 | // @Router /api/user_password [put] 24 | // @Produce json 25 | // @Success 200 {object} res.Response{data=string} 26 | func (UserApi) UserUpdatePassword(c *gin.Context) { 27 | _claims, _ := c.Get("claims") 28 | claims := _claims.(*jwts.CustomClaims) 29 | 30 | var cr UpdatePasswordRequest 31 | if err := c.ShouldBindJSON(&cr); err != nil { 32 | res.FailWithError(err, &cr, c) 33 | return 34 | } 35 | 36 | var user models.UserModel 37 | err := global.DB.Take(&user, claims.UserID).Error 38 | if err != nil { 39 | res.FailWithMessage("用户不存在", c) 40 | return 41 | } 42 | // 判断密码是否一致 43 | if !pwd.CheckPwd(user.Password, cr.OldPwd) { 44 | res.OkWithMessage("密码错误", c) 45 | return 46 | } 47 | hashPwd := pwd.HashPwd(cr.Pwd) 48 | err = global.DB.Model(&user).Update("password", hashPwd).Error 49 | if err != nil { 50 | global.Log.Error(err) 51 | res.FailWithMessage("密码修改失败", c) 52 | return 53 | } 54 | res.OkWithMessage("密码修改成功", c) 55 | return 56 | } 57 | -------------------------------------------------------------------------------- /api/user_api/user_update_role.go: -------------------------------------------------------------------------------- 1 | package user_api 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "gvb_server/global" 6 | "gvb_server/models" 7 | "gvb_server/models/ctype" 8 | "gvb_server/models/res" 9 | ) 10 | 11 | type UserRole struct { 12 | Role ctype.Role `json:"role" binding:"required,oneof=1 2 3 4" msg:"权限参数错误"` 13 | NickName string `json:"nick_name"` // 防止用户昵称非法,管理员有能力修改 14 | UserID uint `json:"user_id" binding:"required" msg:"用户id错误"` 15 | } 16 | 17 | // UserUpdateRoleView 用户权限变更 18 | // @Tags 用户管理 19 | // @Summary 用户权限变更 20 | // @Description 用户权限变更 21 | // @Param data body UserRole true "表示多个参数" 22 | // @Param token header string true "token" 23 | // @Router /api/user_role [put] 24 | // @Produce json 25 | // @Success 200 {object} res.Response{data=string} 26 | func (UserApi) UserUpdateRoleView(c *gin.Context) { 27 | var cr UserRole 28 | if err := c.ShouldBindJSON(&cr); err != nil { 29 | global.Log.Error(err) 30 | res.FailWithError(err, &cr, c) 31 | return 32 | } 33 | var user models.UserModel 34 | err := global.DB.Take(&user, cr.UserID).Error 35 | if err != nil { 36 | res.FailWithMessage("用户id不存在,用户不存在", c) 37 | return 38 | } 39 | err = global.DB.Model(&user).Updates(map[string]any{ 40 | "role": cr.Role, 41 | "nick_name": cr.NickName, 42 | }).Error 43 | if err != nil { 44 | global.Log.Error(err) 45 | res.FailWithMessage("修改权限失败", c) 46 | return 47 | } 48 | res.OkWithMessage("修改权限成功", c) 49 | 50 | } 51 | -------------------------------------------------------------------------------- /config/conf_email.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | type Email struct { 4 | Host string `json:"host" yaml:"host"` 5 | Port int `json:"port" yaml:"port"` 6 | User string `json:"user" yaml:"user"` // 发件人邮箱 7 | Password string `json:"password" yaml:"password"` 8 | DefaultFromEmail string `json:"default_from_email" yaml:"default-from-email"` // 默认的发件人名字 9 | UseSSL bool `json:"use_ssl" yaml:"use_ssl"` // 是否使用ssl 10 | UserTls bool `json:"user_tls" yaml:"user_tls"` 11 | } 12 | -------------------------------------------------------------------------------- /config/conf_es.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type ES struct { 8 | Host string `yaml:"host"` 9 | Port int `yaml:"port"` 10 | User string `yaml:"user"` 11 | Password string `yaml:"password"` 12 | } 13 | 14 | func (es ES) URL() string { 15 | return fmt.Sprintf("%s:%d", es.Host, es.Port) 16 | } 17 | -------------------------------------------------------------------------------- /config/conf_jwt.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | type Jwt struct { 4 | Secret string `json:"secret" yaml:"secret"` // 密钥 5 | Expires int `json:"expires" yaml:"expires"` // 过期时间 6 | Issuer string `json:"issuer" yaml:"issuer"` // 颁发人 7 | } 8 | -------------------------------------------------------------------------------- /config/conf_logger.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | type Logger struct { 4 | Level string `yaml:"level"` 5 | Prefix string `yaml:"prefix"` 6 | Director string `yaml:"director"` 7 | ShowLine bool `yaml:"show-line"` // 是否显示文件行号 8 | LogInConsole bool `yaml:"log-in-console"` // 是否显示打印路径 9 | } 10 | -------------------------------------------------------------------------------- /config/conf_mysql.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "strconv" 5 | ) 6 | 7 | type Mysql struct { 8 | Host string `yaml:"host"` 9 | Port int `yaml:"port"` 10 | Config string `yaml:"config"` // 高级配置,例如 charset 11 | DB string `yaml:"db"` 12 | User string `yaml:"user"` 13 | Password string `yaml:"password"` 14 | LogLevel string `yaml:"log_Level"` // 日志等级,debug就是输出全部sql,dev,release 15 | } 16 | 17 | // Dsn 数据源 18 | func (m Mysql) Dsn() string { 19 | dsn := m.User + ":" + m.Password + "@tcp(" + m.Host + ":" + strconv.Itoa(m.Port) + ")/" + m.DB + "?" + m.Config 20 | //fmt.Println(dsn) 21 | return dsn 22 | } 23 | -------------------------------------------------------------------------------- /config/conf_qiniu.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | type QiNiu struct { 4 | Enable bool `json:"enable" yaml:"enable"` // 是否启用七牛云存储 5 | AccessKey string `json:"access_key" yaml:"access_key"` 6 | SecretKey string `json:"secret_key" yaml:"secret_key"` 7 | Bucket string `json:"bucket" yaml:"bucket"` // 存储桶的名字 8 | CDN string `json:"cdn" yaml:"cdn"` // 访问图片的地址的前缀 9 | Zone string `json:"zone" yaml:"zone"` // 存储的地区 10 | Prefix string `json:"prefix" yaml:"prefix"` // 前缀 11 | Size float64 `json:"size" yaml:"size"` // 存储的大小限制,单位是MB 12 | } 13 | -------------------------------------------------------------------------------- /config/conf_qq.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "fmt" 4 | 5 | type QQ struct { 6 | AppID string `json:"app_id" yaml:"app_id"` 7 | Key string `json:"key" yaml:"key"` 8 | Redirect string `json:"redirect" yaml:"redirect"` // 登录后的回调地址 9 | } 10 | 11 | func (q QQ) GetPath() string { 12 | if q.Key == "" || q.AppID == "" || q.Redirect == "" { 13 | return "" 14 | } 15 | return fmt.Sprintf("https://graph.qq.com/oauth2.0/show?which=Login&display=pc&response_type=code&client_id=%s&redirect_uri=%s", q.AppID, q.Redirect) 16 | } 17 | -------------------------------------------------------------------------------- /config/conf_redis.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "fmt" 4 | 5 | type Redis struct { 6 | IP string `json:"ip" yaml:"ip"` 7 | Port int `json:"port" yaml:"port"` 8 | Password string `json:"password" yaml:"password"` 9 | PoolSize int `json:"pool_size" yaml:"pool_size"` 10 | } 11 | 12 | func (r Redis) Addr() string { 13 | return fmt.Sprintf("%s:%d", r.IP, r.Port) 14 | } 15 | -------------------------------------------------------------------------------- /config/conf_site_info.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | type SiteInfo struct { 4 | CreatedAt string `yaml:"created_at" json:"created_at"` 5 | BeiAn string `yaml:"bei_an" json:"bei_an"` 6 | Title string `yaml:"title" json:"title"` 7 | QQImage string `yaml:"qq_image" json:"qq_image"` 8 | Version string `yaml:"version" json:"version"` 9 | Email string `yaml:"email" json:"email"` 10 | WechatImage string `yaml:"wechat_image" json:"wechat_image"` 11 | Name string `yaml:"name" json:"name"` 12 | Job string `yaml:"job" json:"job"` 13 | Addr string `yaml:"addr" json:"addr"` 14 | Slogan string `yaml:"slogan" json:"slogan"` 15 | SloganEn string `yaml:"slogan_en" json:"slogan_en"` 16 | Web string `yaml:"web" json:"web"` 17 | BiliBiliUrl string `yaml:"bilibili_url" json:"bilibili_url"` 18 | GiteeUrl string `yaml:"gitee_url" json:"gitee_url"` 19 | GithubUrl string `yaml:"github_url" json:"github_url"` 20 | } 21 | -------------------------------------------------------------------------------- /config/conf_system.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import "fmt" 4 | 5 | type System struct { 6 | Host string `yaml:"host"` 7 | Port int `yaml:"port"` 8 | Env string `yaml:"env"` 9 | SslPem string `yaml:"ssl-pem"` 10 | SslKey string `yaml:"ssl-key"` 11 | } 12 | 13 | func (s System) Addr() string { 14 | return fmt.Sprintf("%s:%d", s.Host, s.Port) 15 | } 16 | -------------------------------------------------------------------------------- /config/conf_upload.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | type Upload struct { 4 | Size int `yaml:"size" json:"size"` // 图片上传的大小 5 | Path string `yaml:"path" json:"path"` // 图片上传的目录 6 | } 7 | -------------------------------------------------------------------------------- /config/enter.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | type Config struct { 4 | Mysql Mysql `yaml:"mysql"` 5 | Logger Logger `yaml:"logger"` 6 | System System `yaml:"system"` 7 | SiteInfo SiteInfo `yaml:"site-info"` 8 | QQ QQ `yaml:"qq"` 9 | QiNiu QiNiu `yaml:"qiniu"` 10 | Email Email `yaml:"email"` 11 | Jwt Jwt `yaml:"jwt"` 12 | Upload Upload `yaml:"upload"` 13 | Redis Redis `json:"redis"` 14 | ES ES `json:"es"` 15 | } 16 | -------------------------------------------------------------------------------- /core/addr_db.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | geoip2db "github.com/cc14514/go-geoip2-db" 5 | "gvb_server/global" 6 | "log" 7 | ) 8 | 9 | func InitAddrDB() { 10 | db, err := geoip2db.NewGeoipDbByStatik() 11 | if err != nil { 12 | log.Fatal("ip地址数据库加载失败", err) 13 | } 14 | global.AddrDB = db 15 | 16 | } 17 | -------------------------------------------------------------------------------- /core/conf.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "fmt" 5 | "gopkg.in/yaml.v2" 6 | "gvb_server/config" 7 | "gvb_server/global" 8 | "io/fs" 9 | "log" 10 | "os" 11 | ) 12 | 13 | const ConfigFile = "settings.yaml" 14 | 15 | // InitConf 读取yaml文件的配置 16 | func InitConf() { 17 | 18 | c := &config.Config{} 19 | yamlConf, err := os.ReadFile(ConfigFile) 20 | if err != nil { 21 | panic(fmt.Errorf("get yamlConf error:%s", err)) 22 | } 23 | err = yaml.Unmarshal(yamlConf, c) 24 | if err != nil { 25 | log.Fatalf("config Init Unmarshal: %v", err) 26 | } 27 | log.Println("config yamlFile load Init success.") 28 | //fmt.Printf("配置文件加载成功 %s :%#v", ConfigFile, c) 29 | global.Config = c 30 | } 31 | 32 | func SetYaml() error { 33 | byteData, err := yaml.Marshal(global.Config) 34 | if err != nil { 35 | return err 36 | } 37 | 38 | err = os.WriteFile(ConfigFile, byteData, fs.ModePerm) 39 | if err != nil { 40 | return err 41 | } 42 | global.Log.Infof("配置文件修改成功") 43 | return nil 44 | } 45 | -------------------------------------------------------------------------------- /core/es.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "github.com/olivere/elastic/v7" 5 | "github.com/sirupsen/logrus" 6 | "gvb_server/global" 7 | ) 8 | 9 | func EsConnect() *elastic.Client { 10 | var err error 11 | sniffOpt := elastic.SetSniff(false) 12 | c, err := elastic.NewClient( 13 | elastic.SetURL(global.Config.ES.URL()), 14 | sniffOpt, 15 | elastic.SetBasicAuth(global.Config.ES.User, global.Config.ES.Password), 16 | ) 17 | if err != nil { 18 | logrus.Fatalf("es连接失败 %s", err.Error()) 19 | } 20 | return c 21 | } 22 | -------------------------------------------------------------------------------- /core/gorm.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "fmt" 5 | "gorm.io/driver/mysql" 6 | "gorm.io/gorm" 7 | "gorm.io/gorm/logger" 8 | "gvb_server/global" 9 | "time" 10 | ) 11 | 12 | func InitGorm() *gorm.DB { 13 | if global.Config.Mysql.Host == "" { 14 | global.Log.Warnln("未配置mysql,取消gorm连接") 15 | return nil 16 | } 17 | dsn := global.Config.Mysql.Dsn() 18 | 19 | var mysqlLogger logger.Interface 20 | if global.Config.System.Env == "debug" { 21 | mysqlLogger = logger.Default.LogMode(logger.Info) 22 | } else { 23 | mysqlLogger = logger.Default.LogMode(logger.Error) 24 | } 25 | global.MysqlLog = logger.Default.LogMode(logger.Info) 26 | 27 | db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{ 28 | Logger: mysqlLogger, 29 | DisableForeignKeyConstraintWhenMigrating: true, // 忽略外键检查 30 | }) 31 | if err != nil { 32 | global.Log.Fatalf(fmt.Sprintf("[%s] mysql连接失败", dsn)) 33 | } 34 | 35 | sqlDB, _ := db.DB() 36 | sqlDB.SetMaxIdleConns(10) // 最大空闲连接数 37 | sqlDB.SetMaxOpenConns(100) //最多可容纳 38 | sqlDB.SetConnMaxLifetime(time.Hour * 4) // 连接最大复用时间,不能超过mysql的wait_timeout 39 | return db 40 | } 41 | -------------------------------------------------------------------------------- /core/redis.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "context" 5 | "github.com/go-redis/redis" 6 | "github.com/sirupsen/logrus" 7 | "gvb_server/global" 8 | "time" 9 | ) 10 | 11 | func ConnectRedis() *redis.Client { 12 | return ConnectRedisDB(0) 13 | } 14 | 15 | func ConnectRedisDB(db int) *redis.Client { 16 | redisConf := global.Config.Redis 17 | rdb := redis.NewClient(&redis.Options{ 18 | Addr: redisConf.Addr(), 19 | Password: redisConf.Password, // no password set 20 | DB: db, // use default DB 21 | PoolSize: redisConf.PoolSize, // 连接池大小 22 | }) 23 | _, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) 24 | defer cancel() 25 | _, err := rdb.Ping().Result() 26 | if err != nil { 27 | logrus.Errorf("redis连接失败%s", redisConf.Addr()) 28 | return nil 29 | } 30 | return rdb 31 | } 32 | -------------------------------------------------------------------------------- /deploy/.env: -------------------------------------------------------------------------------- 1 | # https://docs.docker.com/compose/migrate/ 2 | # docker-compose.yml 同目录下的 .env 文件会被加载为其环境变量 3 | 4 | # COMPOSE_PROJECT_NAME=gin-vue-blog 5 | 6 | # 数据存储的文件夹位置 (默认在当前路径生成 gvb 文件夹) 7 | GVB_DATA_DIRECTORY=./gvb 8 | 9 | # Redis 10 | REDIS_PORT=6379 11 | REDIS_PASSWORD=12345QWERT 12 | 13 | # MySQL 14 | MYSQL_PORT=3306 15 | MYSQL_ROOT_PASSWORD=12345QWERT 16 | MYSQL_DATABASE=gvb_db 17 | MYSQL_USER=gvb 18 | MYSQL_PASSWORD=12345QWERT 19 | 20 | # Elasticsearch 21 | ELASTICSEARCH_PORT01=9200 22 | ELASTICSEARCH_PORT02=9300 23 | 24 | # Nginx 25 | NGINX_PORT=80 26 | NGINX_GVB_WEB=../gvb/gvb_web # 给nginx映射的前端路径,和nginx.conf里路径对应 27 | NGINX_GVB_SERVER=../gvb/gvb_server # 给nginx映射的后端路径,和nginx.conf里路径对应 28 | 29 | # Docker Network (一般不需要变, 除非发生冲突) 30 | SUBNET=172.12.0.0/24 31 | REDIS_HOST=172.12.0.2 32 | MYSQL_HOST=172.12.0.3 33 | ELASTICSEARCH_HOST=172.12.0.4 34 | NGINX_HOST=172.12.0.5 -------------------------------------------------------------------------------- /deploy/gvb/elasticsearch/config/elasticsearch.yml: -------------------------------------------------------------------------------- 1 | http.host: 0.0.0.0 2 | -------------------------------------------------------------------------------- /deploy/gvb/nginx/html/50x.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Error 5 | 10 | 11 | 12 |

An error occurred.

13 |

Sorry, the page you are looking for is currently unavailable.
14 | Please try again later.

15 |

If you are the system administrator of this resource then you should check 16 | the error log for details.

17 |

Faithfully yours, nginx.

18 | 19 | 20 | -------------------------------------------------------------------------------- /deploy/gvb/nginx/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Welcome to nginx! 5 | 10 | 11 | 12 |

Welcome to nginx!

13 |

If you see this page, the nginx web server is successfully installed and 14 | working. Further configuration is required.

15 | 16 |

For online documentation and support please refer to 17 | nginx.org.
18 | Commercial support is available at 19 | nginx.com.

20 | 21 |

Thank you for using nginx.

22 | 23 | 24 | -------------------------------------------------------------------------------- /flag/create_user.go: -------------------------------------------------------------------------------- 1 | package flag 2 | 3 | import ( 4 | "fmt" 5 | "gvb_server/global" 6 | "gvb_server/models/ctype" 7 | "gvb_server/service/user_ser" 8 | ) 9 | 10 | func CreateUser(permission string) { 11 | // 创建用户的逻辑 12 | // 用户名 昵称 密码 确认密码 邮箱 13 | var ( 14 | userName string 15 | nickName string 16 | password string 17 | rePassword string 18 | email string 19 | ) 20 | // Scan不可空,Scanln可空 21 | fmt.Printf("请输入用户名:") 22 | fmt.Scan(&userName) 23 | fmt.Printf("请输入昵称:") 24 | fmt.Scan(&nickName) 25 | fmt.Printf("请输入邮箱:") 26 | fmt.Scan(&email) 27 | fmt.Printf("请输入密码:") 28 | fmt.Scan(&password) 29 | fmt.Printf("请再次输入密码:") 30 | fmt.Scan(&rePassword) 31 | 32 | // 校验两次密码 33 | if password != rePassword { 34 | global.Log.Error("两次密码不一致,请重新输入") 35 | CreateUser(permission) 36 | return 37 | } 38 | // 普通用户or管理员 39 | role := ctype.PermissionUser 40 | if permission == "admin" { 41 | role = ctype.PermissionAdmin 42 | } 43 | 44 | err := user_ser.UserService{}.CreateUser(userName, nickName, password, role, email, "127.0.0.1") 45 | if err != nil { 46 | global.Log.Error(err) 47 | return 48 | } 49 | 50 | global.Log.Infof("用户 %s 创建成功!", userName) 51 | } 52 | -------------------------------------------------------------------------------- /flag/db.go: -------------------------------------------------------------------------------- 1 | package flag 2 | 3 | import ( 4 | "gvb_server/global" 5 | "gvb_server/models" 6 | "gvb_server/plugins/log_stash" 7 | ) 8 | 9 | // Makemigrations 迁移表 10 | func Makemigrations() { 11 | var err error 12 | //global.DB.SetupJoinTable(&models.UserModel{}, "CollectsModels", &models.UserCollectModel{}) 13 | global.DB.SetupJoinTable(&models.MenuModel{}, "Banners", &models.MenuBannerModel{}) 14 | err = global.DB.Set("gorm:table_options", "ENGINE=InnoDB"). 15 | AutoMigrate( 16 | &models.BannerModel{}, 17 | &models.TagModel{}, 18 | &models.MessageModel{}, 19 | &models.AdvertModel{}, 20 | &models.UserModel{}, 21 | &models.CommentModel{}, 22 | //&models.ArticleModel{}, 23 | &models.UserCollectModel{}, 24 | &models.MenuModel{}, 25 | &models.MenuBannerModel{}, 26 | &models.FadeBackModel{}, 27 | &models.LoginDataModel{}, 28 | &models.ChatModel{}, 29 | &log_stash.LogStashModel{}, 30 | ) 31 | if err != nil { 32 | global.Log.Error("[ error ] 生成数据库表结构失败!") 33 | return 34 | } 35 | global.Log.Infof("[ success ] 生成数据库表结构成功!") 36 | 37 | } 38 | -------------------------------------------------------------------------------- /flag/enter.go: -------------------------------------------------------------------------------- 1 | package flag 2 | 3 | import ( 4 | sys_flag "flag" 5 | "github.com/fatih/structs" 6 | "gvb_server/core" 7 | "gvb_server/global" 8 | ) 9 | 10 | type Option struct { 11 | DB bool 12 | User string // -u admin -u user 13 | ES string // -es create -es delete 14 | } 15 | 16 | // Parse 解析命令行参数 17 | func Parse() Option { 18 | db := sys_flag.Bool("db", false, "初始化数据库") 19 | user := sys_flag.String("u", "", "创建用户") 20 | es := sys_flag.String("es", "", "es操作") 21 | // 解析命令行参数写入注册的flag里 22 | sys_flag.Parse() 23 | return Option{ 24 | DB: *db, 25 | User: *user, 26 | ES: *es, 27 | } 28 | } 29 | 30 | // IsWebStop 是否停止Web项目 31 | func IsWebStop(option Option) (f bool) { 32 | maps := structs.Map(&option) 33 | for _, v := range maps { 34 | switch val := v.(type) { 35 | case string: 36 | if v != "" { 37 | f = true 38 | } 39 | case bool: 40 | if val == true { 41 | f = true 42 | } 43 | } 44 | } 45 | return f 46 | } 47 | 48 | // SwitchOption 根据命令执行不同的函数 49 | func SwitchOption(option Option) { 50 | if option.DB { 51 | Makemigrations() 52 | return 53 | } 54 | 55 | if option.User == "admin" || option.User == "user" { 56 | CreateUser(option.User) 57 | return 58 | } 59 | 60 | if option.ES == "create" { 61 | // 连接es 62 | global.ESClient = core.EsConnect() 63 | EsCreateIndex() 64 | } 65 | //fmt.Printf("%#v\n", option.User) 66 | //sys_flag.Usage() 67 | 68 | } 69 | -------------------------------------------------------------------------------- /flag/es.go: -------------------------------------------------------------------------------- 1 | package flag 2 | 3 | import "gvb_server/models" 4 | 5 | func EsCreateIndex() { 6 | models.ArticleModel{}.CreateIndex() 7 | models.FullTextModel{}.CreateIndex() 8 | } 9 | -------------------------------------------------------------------------------- /global/global.go: -------------------------------------------------------------------------------- 1 | package global 2 | 3 | import ( 4 | "github.com/cc14514/go-geoip2" 5 | "github.com/go-redis/redis" 6 | "github.com/olivere/elastic/v7" 7 | "github.com/sirupsen/logrus" 8 | "gorm.io/gorm" 9 | "gorm.io/gorm/logger" 10 | "gvb_server/config" 11 | ) 12 | 13 | var ( 14 | Config *config.Config 15 | DB *gorm.DB 16 | Log *logrus.Logger 17 | MysqlLog logger.Interface 18 | Redis *redis.Client 19 | ESClient *elastic.Client 20 | AddrDB *geoip2.DBReader 21 | ) 22 | -------------------------------------------------------------------------------- /gvb_mysql.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO gvb.menu_models (id, created_at, updated_at, title, path, slogan, abstract, abstract_time, banner_time, sort) VALUES (1, NOW(), NOW(), '首页', '/', '众神眷恋的幻想乡', '天寒地冻路远马亡又何妨', 5, 5, 1); 2 | INSERT INTO gvb.menu_models (id, created_at, updated_at, title, path, slogan, abstract, abstract_time, banner_time, sort) VALUES (2, NOW(), NOW(), '新闻', '/news', '新闻', '一天一🍎,⛑远离我', 5, 5, 2); 3 | INSERT INTO gvb.menu_models (id, created_at, updated_at, title, path, slogan, abstract, abstract_time, banner_time, sort) VALUES (3, NOW(), NOW(), '文章搜索', '/search', '文章搜索', '文章搜索', 5, 5, 3); 4 | INSERT INTO gvb.menu_models (id, created_at, updated_at, title, path, slogan, abstract, abstract_time, banner_time, sort) VALUES (4, NOW(), NOW(),'聊天室', '/chat_group', '聊天室', '聊天室', 5, 5, 4); 5 | -------------------------------------------------------------------------------- /main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/main -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "gvb_server/core" 5 | _ "gvb_server/docs" 6 | "gvb_server/flag" 7 | "gvb_server/global" 8 | "gvb_server/routers" 9 | "gvb_server/service/cron_ser" 10 | "gvb_server/utils" 11 | ) 12 | 13 | // @title gvb_server API文档 14 | // @version 1.0 15 | // @description API文档 16 | // @host 127.0.0.1:8080 17 | // @BasePath / 18 | func main() { 19 | // 读取配置文件 20 | core.InitConf() 21 | // 初始化日志 22 | global.Log = core.InitLogger() 23 | // 连接数据库 24 | global.DB = core.InitGorm() 25 | // ip地址数据库加载 26 | core.InitAddrDB() 27 | defer global.AddrDB.Close() 28 | 29 | // 命令行参数绑定 30 | option := flag.Parse() 31 | if flag.IsWebStop(option) { 32 | flag.SwitchOption(option) 33 | return 34 | } 35 | 36 | // 连接redis 37 | global.Redis = core.ConnectRedis() 38 | // 连接es 39 | global.ESClient = core.EsConnect() 40 | 41 | // 定时任务,同步redis数据至es和mysql 42 | cron_ser.CronInit() 43 | 44 | router := routers.InitRouter() 45 | 46 | addr := global.Config.System.Addr() 47 | utils.PrintSystem() 48 | err := router.Run(addr) 49 | if err != nil { 50 | global.Log.Fatalf(err.Error()) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /middleware/jwt_auth.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "gvb_server/models/ctype" 6 | "gvb_server/models/res" 7 | "gvb_server/service/redis_ser" 8 | "gvb_server/utils/jwts" 9 | ) 10 | 11 | func JwtAuth() gin.HandlerFunc { 12 | return func(c *gin.Context) { 13 | // 如何判断是管理员 14 | token := c.Request.Header.Get("token") 15 | if token == "" { 16 | res.FailWithMessage("未携带token", c) 17 | c.Abort() 18 | return 19 | } 20 | claims, err := jwts.ParseToken(token) 21 | if err != nil { 22 | res.FailWithMessage("token错误", c) 23 | c.Abort() 24 | return 25 | } 26 | // 判断是否在redis中 27 | if redis_ser.CheckLogout(token) { 28 | res.FailWithMessage("token已失效", c) 29 | c.Abort() 30 | return 31 | } 32 | 33 | // 登陆的用户 34 | c.Set("claims", claims) 35 | } 36 | } 37 | 38 | func JwtAdmin() gin.HandlerFunc { 39 | return func(c *gin.Context) { 40 | // 如何判断是管理员 41 | token := c.Request.Header.Get("token") 42 | if token == "" { 43 | res.FailWithMessage("未携带token", c) 44 | c.Abort() 45 | return 46 | } 47 | claims, err := jwts.ParseToken(token) 48 | if err != nil { 49 | res.FailWithMessage("token错误", c) 50 | c.Abort() 51 | return 52 | } 53 | // 判断是否在redis中 54 | if redis_ser.CheckLogout(token) { 55 | res.FailWithMessage("token已失效", c) 56 | c.Abort() 57 | return 58 | } 59 | // 登陆的用户 60 | if claims.Role != int(ctype.PermissionAdmin) { 61 | res.FailWithMessage("权限错误", c) 62 | c.Abort() 63 | return 64 | } 65 | c.Set("claims", claims) 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /middleware/tls.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "github.com/unrolled/secure" 6 | "gvb_server/global" 7 | ) 8 | 9 | // TlsHandler 中间件开启https,还没捣鼓好 10 | func TlsHandler() gin.HandlerFunc { 11 | return func(c *gin.Context) { 12 | secureMiddleware := secure.New(secure.Options{ 13 | SSLRedirect: true, 14 | SSLHost: global.Config.System.Addr(), 15 | }) 16 | err := secureMiddleware.Process(c.Writer, c.Request) 17 | 18 | // If there was an error, do not continue. 19 | if err != nil { 20 | return 21 | } 22 | 23 | c.Next() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /models/advert_model.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | // AdvertModel 广告表 4 | type AdvertModel struct { 5 | MODEL 6 | Title string `gorm:"size:32" json:"title"` // 显示的标题 7 | Href string `json:"href"` // 跳转链接 8 | Images string `json:"images"` // 图片 9 | IsShow bool `json:"is_show"` // 是否展示 10 | } 11 | -------------------------------------------------------------------------------- /models/banner_model.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | "gvb_server/global" 6 | "gvb_server/models/ctype" 7 | "os" 8 | ) 9 | 10 | // BannerModel 图片表 11 | type BannerModel struct { 12 | MODEL 13 | Path string `json:"path"` // 图片路径 14 | Hash string `json:"hash"` // 图片的hash值,用于判断重复图片 15 | Name string `gorm:"size:38" json:"name"` // 图片名称 16 | ImageType ctype.ImageType `gorm:"default:1" json:"image_type"` // 图片的类型,本地还是七牛 17 | } 18 | 19 | func (u *BannerModel) BeforeDelete(tx *gorm.DB) (err error) { 20 | if u.ImageType == ctype.Local { 21 | // 本地图片,删除,还要删除本地的存储 22 | err = os.Remove(u.Path[1:]) 23 | if err != nil { 24 | global.Log.Error(err) 25 | return err 26 | } 27 | } 28 | return nil 29 | } 30 | -------------------------------------------------------------------------------- /models/chat_model.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import "gvb_server/models/ctype" 4 | 5 | type ChatModel struct { 6 | MODEL `json:","` 7 | NickName string `gorm:"size:15" json:"nick_name"` // 前端自己生成 8 | Avatar string `gorm:"size:128" json:"avatar"` // 头像 9 | Content string `gorm:"size:256" json:"content"` // 聊天的内容 10 | IP string `gorm:"size:32" json:"ip,omit(list)"` // ip 11 | Addr string `gorm:"size:64" json:"addr,omit(list)"` // 地址 12 | ISGroup bool `json:"is_group"` //是否是群组消息 13 | MsgType ctype.MsgType `gorm:"size:4" json:"msg_type"` // 聊天类型 14 | } 15 | -------------------------------------------------------------------------------- /models/comment_model.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | // CommentModel 评论表 4 | type CommentModel struct { 5 | MODEL `json:",select(c)"` 6 | SubComments []CommentModel `gorm:"foreignkey:ParentCommentID" json:"sub_comments,select(c)"` // 子评论列表 7 | ParentCommentModel *CommentModel `gorm:"foreignkey:ParentCommentID" json:"comment_model"` // 父级评论 8 | ParentCommentID *uint `json:"parent_comment_id,select(c)"` // 父评论id 9 | Content string `gorm:"size:256" json:"content,select(c)"` // 评论内容 10 | DiggCount int `gorm:"size:8;default:0;" json:"digg_count,select(c)"` // 点赞数 11 | CommentCount int `gorm:"size:8;default:0;" json:"comment_count,select(c)"` // 子评论数 12 | ArticleID string `gorm:"size:32" json:"article_id,select(c)"` // 文章id 13 | User UserModel `json:"user,select(c)"` //关联的用户 14 | UserID uint `json:"user_id,select(c)"` // 评论的用户 15 | } 16 | -------------------------------------------------------------------------------- /models/ctype/array.go: -------------------------------------------------------------------------------- 1 | package ctype 2 | 3 | import ( 4 | "database/sql/driver" 5 | "strings" 6 | ) 7 | 8 | type Array []string 9 | 10 | func (t *Array) Scan(value interface{}) error { 11 | v, _ := value.([]byte) 12 | if string(v) == "" { 13 | *t = []string{} 14 | return nil 15 | } 16 | *t = strings.Split(string(v), "\n") 17 | return nil 18 | } 19 | 20 | func (t Array) Value() (driver.Value, error) { 21 | // 将数字转换为值 22 | return strings.Join(t, "\n"), nil 23 | } 24 | -------------------------------------------------------------------------------- /models/ctype/image_type.go: -------------------------------------------------------------------------------- 1 | package ctype 2 | 3 | import "encoding/json" 4 | 5 | type ImageType int 6 | 7 | const ( 8 | Local ImageType = 1 // 本地 9 | QiNiu ImageType = 2 // 七牛云 10 | ) 11 | 12 | func (s ImageType) MarshalJSON() ([]byte, error) { 13 | return json.Marshal(s.String()) 14 | } 15 | 16 | func (s ImageType) String() string { 17 | switch s { 18 | case Local: 19 | return "本地" 20 | case QiNiu: 21 | return "七牛云" 22 | default: 23 | return "其他" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /models/ctype/msg_type.go: -------------------------------------------------------------------------------- 1 | package ctype 2 | 3 | type MsgType int 4 | -------------------------------------------------------------------------------- /models/ctype/role_type.go: -------------------------------------------------------------------------------- 1 | package ctype 2 | 3 | import "encoding/json" 4 | 5 | type Role int 6 | 7 | const ( 8 | PermissionAdmin Role = 1 // 管理员 9 | PermissionUser Role = 2 // 用户 10 | PermissionVisitor Role = 3 // 游客 11 | PermissionDisableUser Role = 4 // 黑名单 12 | ) 13 | 14 | func (role Role) MarshalJSON() ([]byte, error) { 15 | return json.Marshal(role.String()) 16 | } 17 | 18 | func (role Role) String() string { 19 | switch role { 20 | case PermissionAdmin: 21 | return "管理员" 22 | case PermissionUser: 23 | return "用户" 24 | case PermissionVisitor: 25 | return "游客" 26 | case PermissionDisableUser: 27 | return "黑名单" 28 | default: 29 | return "其他" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /models/ctype/sign_status_type.go: -------------------------------------------------------------------------------- 1 | package ctype 2 | 3 | import "encoding/json" 4 | 5 | type SignStatus int 6 | 7 | const ( 8 | SignQQ SignStatus = 1 // QQ 9 | SignGitee SignStatus = 2 // Gitee 10 | SignEmail SignStatus = 3 // 邮箱 11 | ) 12 | 13 | func (s SignStatus) MarshalJSON() ([]byte, error) { 14 | return json.Marshal(s.String()) 15 | } 16 | 17 | func (s SignStatus) String() string { 18 | switch s { 19 | case SignQQ: 20 | return "QQ" 21 | case SignGitee: 22 | return "Gitee" 23 | case SignEmail: 24 | return "邮箱" 25 | default: 26 | return "其他" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /models/enter.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import "time" 4 | 5 | type MODEL struct { 6 | ID uint `gorm:"primarykey" json:"id,select($any)" structs:"-"` 7 | CreatedAt time.Time `json:"created_at,select($any)" structs:"-"` 8 | UpdatedAt time.Time `json:"-" structs:"-"` 9 | } 10 | 11 | type RemoveRequest struct { 12 | IDList []uint `json:"id_list" ` 13 | } 14 | 15 | type ESIDRequest struct { 16 | ID string `json:"id" form:"id" uri:"id"` 17 | } 18 | 19 | type ESIDListRequest struct { 20 | IDList []string `json:"id_list" binding:"required"` 21 | } 22 | 23 | type PageInfo struct { 24 | Page int `form:"page"` 25 | Key string `form:"key"` 26 | Limit int `form:"limit"` 27 | Sort string `form:"sort"` 28 | } 29 | -------------------------------------------------------------------------------- /models/fade_back_model.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | type FadeBackModel struct { 4 | MODEL 5 | Email string `gorm:"size:64" json:"email"` 6 | Content string `gorm:"size:128" json:"content"` 7 | ApplyContent string `gorm:"size:128" json:"apply_content"` // 回复的内容 8 | IsApply bool `json:"is_apply"` // 是否回复 9 | } 10 | -------------------------------------------------------------------------------- /models/login_data_model.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import "gvb_server/models/ctype" 4 | 5 | // LoginDataModel 统计用户登录数据 id, 用户id, 用户昵称,用户token,登录设备,登录时间 6 | type LoginDataModel struct { 7 | MODEL 8 | UserID uint `json:"user_id"` 9 | UserModel UserModel `gorm:"foreignKey:UserID" json:"-"` 10 | IP string `gorm:"size:20" json:"ip"` // 登录的ip 11 | NickName string `gorm:"size:42" json:"nick_name"` 12 | Token string `gorm:"size:256" json:"token"` 13 | Device string `gorm:"size:256" json:"device"` // 登录设备 14 | Addr string `gorm:"size:64" json:"addr"` 15 | LoginType ctype.SignStatus `gorm:"size:type=smallint(6)" json:"login_type"` 16 | } 17 | -------------------------------------------------------------------------------- /models/menu_banner_model.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | // MenuBannerModel 自定义菜单和背景图的连接表,方便排序 4 | type MenuBannerModel struct { 5 | MenuID uint `json:"menu_id"` 6 | MenuModel MenuModel `gorm:"foreignKey:MenuID"` 7 | BannerID uint `json:"banner_id"` 8 | BannerModel BannerModel `gorm:"foreignKey:BannerID"` 9 | Sort int `gorm:"size:10" json:"sort"` 10 | } 11 | -------------------------------------------------------------------------------- /models/menu_model.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "gvb_server/models/ctype" 5 | ) 6 | 7 | // MenuModel 菜单表 菜单的路径可以是 /path 也可以是路由别名 8 | type MenuModel struct { 9 | MODEL 10 | Title string `gorm:"size:32" json:"title"` // 标题 11 | Path string `gorm:"size:256" json:"path"` // 路径 12 | Slogan string `gorm:"size:64" json:"slogan"` // slogan 13 | Abstract ctype.Array `gorm:"type:string" json:"abstract"` // 简介 14 | AbstractTime int `json:"abstract_time"` // 简介的切换时间 15 | Banners []BannerModel `gorm:"many2many:menu_banner_models;joinForeignKey:MenuID;JoinReferences:ImageID" json:"banners"` // 菜单的图片列表 16 | BannerTime int `json:"banner_time"` // 菜单图片的切换时间 为 0 表示不切换 17 | Sort int `gorm:"size:10" json:"sort"` // 菜单的顺序 18 | } 19 | -------------------------------------------------------------------------------- /models/message_model.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | // MessageModel 记录消息 4 | type MessageModel struct { 5 | MODEL 6 | SendUserID uint `gorm:"primaryKey" json:"send_user_id"` // 发送人id 7 | SendUserModel UserModel `gorm:"foreignKey:SendUserID" json:"-"` 8 | SendUserNickName string `gorm:"size:42" json:"send_user_nick_name"` 9 | SendUserAvatar string `json:"send_user_avatar"` 10 | 11 | RevUserID uint `gorm:"primaryKey" json:"rev_user_id"` // 接收人id 12 | RevUserModel UserModel `gorm:"foreignKey:RevUserID" json:"-"` 13 | RevUserNickName string `gorm:"size:42" json:"rev_user_nick_name"` 14 | RevUserAvatar string `json:"rev_user_avatar"` 15 | IsRead bool `gorm:"default:false" json:"is_read"` // 接收方是否查看 16 | Content string `json:"content"` // 消息内容 17 | } 18 | -------------------------------------------------------------------------------- /models/res/err_code.go: -------------------------------------------------------------------------------- 1 | package res 2 | 3 | type ErrorCode int 4 | 5 | const ( 6 | SettingsError ErrorCode = 1001 //系统错误 7 | ArgumentError ErrorCode = 1002 //参数错误 8 | ) 9 | 10 | var ( 11 | ErrorMap = map[ErrorCode]string{ 12 | SettingsError: "系统错误", 13 | ArgumentError: "参数错误", 14 | } 15 | ) 16 | -------------------------------------------------------------------------------- /models/res/err_code.json: -------------------------------------------------------------------------------- 1 | { 2 | "1001": "系统错误" 3 | } -------------------------------------------------------------------------------- /models/tag_model.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | // TagModel 标签表 4 | type TagModel struct { 5 | MODEL 6 | Title string `gorm:"size:16" json:"title"` // 标签的名称 7 | //Articles []ArticleModel `gorm:"many2many:article_tag_models" json:"-"` // 关联该标签的文章列表 8 | } 9 | -------------------------------------------------------------------------------- /models/user_collect_model.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import "time" 4 | 5 | // UserCollectModel 自定义第三张表 记录用户什么时候收藏了什么文章 6 | type UserCollectModel struct { 7 | ID uint `gorm:"primarykey" json:"id"` 8 | UserID uint `json:"user_id"` 9 | UserModel UserModel `gorm:"foreignKey:UserID"` 10 | ArticleID string `gorm:"size:32"` 11 | CreatedAt time.Time 12 | } 13 | -------------------------------------------------------------------------------- /models/user_model.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import "gvb_server/models/ctype" 4 | 5 | // UserModel 用户表 6 | type UserModel struct { 7 | MODEL 8 | NickName string `gorm:"size:36" json:"nick_name,select(c|info)"` // 昵称 9 | UserName string `gorm:"size:36" json:"user_name"` // 用户名 10 | Password string `gorm:"size:128" json:"-"` // 密码 11 | Avatar string `gorm:"type=TEXT" json:"avatar,select(c|info)"` // 头像 12 | Email string `gorm:"size:128" json:"email,select(info)"` // 邮箱 13 | Tel string `gorm:"size:18" json:"tel"` // 手机号 14 | Addr string `gorm:"size:64" json:"addr,select(c|info)"` // 地址 15 | Token string `gorm:"size:64" json:"token"` // 其他平台的唯一id 16 | IP string `gorm:"size:20" json:"ip,select(c)"` // ip地址 17 | Role ctype.Role `gorm:"size:4;default:1" json:"role,select(info)"` // 权限 1 管理员 2 普通用户 3 游客 18 | SignStatus ctype.SignStatus `gorm:"type=smallint(6)" json:"sign_status,select(info)"` // 注册来源 19 | Integral int `gorm:"default:0" json:"integral,select(info)"` // 积分 20 | Sign string `gorm:"size:128" json:"sign,select(info)"` // 签名 21 | Link string `gorm:"size:128" json:"link,select(info)"` // 链接地址 22 | } 23 | -------------------------------------------------------------------------------- /plugins/email/send_email.go: -------------------------------------------------------------------------------- 1 | package email 2 | 3 | import ( 4 | "gopkg.in/gomail.v2" 5 | "gvb_server/global" 6 | ) 7 | 8 | type Subject string 9 | 10 | const ( 11 | Code Subject = "平台验证码" 12 | Note Subject = "操作通知" 13 | Alarm Subject = "告警通知" 14 | ) 15 | 16 | type Api struct { 17 | Subject Subject 18 | } 19 | 20 | func (a Api) Send(name, body string) error { 21 | return send(name, string(a.Subject), body) 22 | } 23 | 24 | func NewCode() Api { 25 | return Api{ 26 | Subject: Code, 27 | } 28 | } 29 | func NewNote() Api { 30 | return Api{ 31 | Subject: Note, 32 | } 33 | } 34 | func NewAlarm() Api { 35 | return Api{ 36 | Subject: Alarm, 37 | } 38 | } 39 | 40 | // send 邮件发送 发给谁,主题,正文 41 | func send(name, subject, body string) error { 42 | e := global.Config.Email 43 | return sendMail( 44 | e.User, 45 | e.Password, 46 | e.Host, 47 | e.Port, 48 | name, 49 | e.DefaultFromEmail, 50 | subject, 51 | body, 52 | ) 53 | } 54 | 55 | func sendMail(userName, authCode, host string, port int, mailTo, sendName string, subject, body string) error { 56 | m := gomail.NewMessage() 57 | m.SetHeader("From", m.FormatAddress(userName, sendName)) // 谁发的 58 | m.SetHeader("To", mailTo) // 发送给谁 59 | m.SetHeader("Subject", subject) // 主题 60 | m.SetBody("text/html", body) 61 | d := gomail.NewDialer(host, port, userName, authCode) 62 | err := d.DialAndSend(m) 63 | return err 64 | } 65 | -------------------------------------------------------------------------------- /plugins/log_stash/level.go: -------------------------------------------------------------------------------- 1 | package log_stash 2 | 3 | import "encoding/json" 4 | 5 | type Level int 6 | 7 | const ( 8 | DebugLevel Level = 1 9 | InfoLevel Level = 2 10 | WarnLevel Level = 3 11 | ErrorLevel Level = 4 12 | ) 13 | 14 | func (s Level) MarshalJSON() ([]byte, error) { 15 | return json.Marshal(s.String()) 16 | 17 | } 18 | 19 | func (s Level) String() string { 20 | switch s { 21 | case DebugLevel: 22 | return "debug" 23 | case InfoLevel: 24 | return "info" 25 | case WarnLevel: 26 | return "warn" 27 | case ErrorLevel: 28 | return "error" 29 | default: 30 | return "其他" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /plugins/log_stash/model.go: -------------------------------------------------------------------------------- 1 | package log_stash 2 | 3 | import "time" 4 | 5 | type LogStashModel struct { 6 | ID uint `gorm:"primarykey" json:"id"` 7 | CreatedAt time.Time `json:"created_at"` 8 | IP string `gorm:"size:32" json:"ip"` 9 | Addr string `gorm:"size:64" json:"addr"` 10 | Level Level `gorm:"size:4" json:"level"` // 日志等级 11 | Content string `gorm:"size:128" json:"content"` // 日志消息内容 12 | UserID uint `json:"user_id"` // 登录用户的用户id,需要自己在查询的时候做关联查询 13 | } 14 | -------------------------------------------------------------------------------- /routers/advert_router.go: -------------------------------------------------------------------------------- 1 | package routers 2 | 3 | import ( 4 | "gvb_server/api" 5 | "gvb_server/middleware" 6 | ) 7 | 8 | func (router RouterGroup) AdvertRouter() { 9 | app := api.ApiGroupApp.AdvertApi 10 | router.POST("adverts", middleware.JwtAdmin(), app.AdvertCreateView) 11 | router.GET("adverts", app.AdvertListView) 12 | router.PUT("adverts/:id", middleware.JwtAdmin(), app.AdvertUpdateView) 13 | router.DELETE("adverts", middleware.JwtAdmin(), app.AdvertRemoveView) 14 | } 15 | -------------------------------------------------------------------------------- /routers/chat_router.go: -------------------------------------------------------------------------------- 1 | package routers 2 | 3 | import ( 4 | "gvb_server/api" 5 | ) 6 | 7 | func (router RouterGroup) ChatRouter() { 8 | app := api.ApiGroupApp.ChatApi 9 | router.GET("chat_groups", app.ChatGroupView) 10 | router.GET("chat_groups_records", app.ChatListView) 11 | } 12 | -------------------------------------------------------------------------------- /routers/comment_router.go: -------------------------------------------------------------------------------- 1 | package routers 2 | 3 | import ( 4 | "gvb_server/api" 5 | "gvb_server/middleware" 6 | ) 7 | 8 | func (router RouterGroup) CommentRouter() { 9 | app := api.ApiGroupApp.CommentApi 10 | router.POST("comments", middleware.JwtAuth(), app.CommentCreateView) 11 | router.GET("comments_all", app.CommentListAllView) 12 | router.POST("comments/:id", app.CommentDigg) 13 | router.DELETE("comments/:id", middleware.JwtAuth(), app.CommentRemoveView) 14 | router.GET("comments/:id", app.CommentListView) 15 | } 16 | -------------------------------------------------------------------------------- /routers/data_router.go: -------------------------------------------------------------------------------- 1 | package routers 2 | 3 | import "gvb_server/api" 4 | 5 | func (router RouterGroup) DataRouter() { 6 | app := api.ApiGroupApp.DataApi 7 | router.GET("data_seven_login", app.DataSevenLogin) 8 | router.GET("data_sum", app.DataSumView) 9 | 10 | } 11 | -------------------------------------------------------------------------------- /routers/enter.go: -------------------------------------------------------------------------------- 1 | package routers 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | swaggerFiles "github.com/swaggo/files" 6 | gs "github.com/swaggo/gin-swagger" 7 | "gvb_server/global" 8 | "net/http" 9 | ) 10 | 11 | type RouterGroup struct { 12 | *gin.RouterGroup 13 | } 14 | 15 | func InitRouter() *gin.Engine { 16 | gin.SetMode(global.Config.System.Env) 17 | router := gin.Default() 18 | 19 | // 静态文件路径,静态路由 20 | router.StaticFS("uploads", http.Dir("uploads")) 21 | router.GET("/swagger/*any", gs.WrapHandler(swaggerFiles.Handler)) 22 | apiRouterGroup := router.Group("api") 23 | 24 | routerGroupApp := RouterGroup{apiRouterGroup} 25 | // 系统配置api 26 | routerGroupApp.SettingsRouter() 27 | routerGroupApp.ImagesRouter() 28 | routerGroupApp.AdvertRouter() 29 | routerGroupApp.MenuRouter() 30 | routerGroupApp.UserRouter() 31 | routerGroupApp.TagRouter() 32 | routerGroupApp.MessageRouter() 33 | routerGroupApp.ArticleRouter() 34 | routerGroupApp.CommentRouter() 35 | routerGroupApp.NewsRouter() 36 | routerGroupApp.ChatRouter() 37 | routerGroupApp.LogRouter() 38 | routerGroupApp.DataRouter() 39 | return router 40 | } 41 | -------------------------------------------------------------------------------- /routers/images_router.go: -------------------------------------------------------------------------------- 1 | package routers 2 | 3 | import ( 4 | "gvb_server/api" 5 | "gvb_server/middleware" 6 | ) 7 | 8 | func (router RouterGroup) ImagesRouter() { 9 | app := api.ApiGroupApp.ImagesApi 10 | router.GET("images", app.ImageListView) 11 | router.GET("image_names", app.ImageNameListView) 12 | router.POST("images", middleware.JwtAuth(), app.ImageUploadView) 13 | router.POST("image", middleware.JwtAuth(), app.ImageUploadDataView) 14 | router.DELETE("images", middleware.JwtAdmin(), app.ImageRemoveView) 15 | router.PUT("images", middleware.JwtAdmin(), app.ImageUpdateView) 16 | 17 | } 18 | -------------------------------------------------------------------------------- /routers/log_router.go: -------------------------------------------------------------------------------- 1 | package routers 2 | 3 | import ( 4 | "gvb_server/api" 5 | "gvb_server/middleware" 6 | ) 7 | 8 | func (router RouterGroup) LogRouter() { 9 | app := api.ApiGroupApp.LogApi 10 | router.GET("logs", app.LogListView) 11 | router.DELETE("logs", middleware.JwtAdmin(), app.LogRemoveListView) 12 | } 13 | -------------------------------------------------------------------------------- /routers/menu_router.go: -------------------------------------------------------------------------------- 1 | package routers 2 | 3 | import ( 4 | "gvb_server/api" 5 | "gvb_server/middleware" 6 | ) 7 | 8 | func (router RouterGroup) MenuRouter() { 9 | app := api.ApiGroupApp.MenuApi 10 | router.POST("menus", middleware.JwtAdmin(), app.MenuCreateView) 11 | router.GET("menus", app.MenuListView) 12 | router.GET("menu_names", app.MenuNameList) 13 | router.PUT("menus/:id", middleware.JwtAdmin(), app.MenuUpdateView) 14 | router.DELETE("menus", middleware.JwtAdmin(), app.MenuRemoveView) 15 | router.GET("menus/detail", app.MenuDetailByPathView) 16 | router.GET("menus/:id", app.MenuDetailView) 17 | 18 | } 19 | -------------------------------------------------------------------------------- /routers/message_router.go: -------------------------------------------------------------------------------- 1 | package routers 2 | 3 | import ( 4 | "gvb_server/api" 5 | "gvb_server/middleware" 6 | ) 7 | 8 | func (router RouterGroup) MessageRouter() { 9 | app := api.ApiGroupApp.MessageApi 10 | router.POST("messages", middleware.JwtAuth(), app.MessageCreateView) 11 | router.GET("messages_all", middleware.JwtAdmin(), app.MessageListAllView) 12 | router.GET("messages", middleware.JwtAuth(), app.MessageListView) 13 | router.POST("messages_record", middleware.JwtAuth(), app.MessageRecordView) 14 | } 15 | -------------------------------------------------------------------------------- /routers/news_router.go: -------------------------------------------------------------------------------- 1 | package routers 2 | 3 | import "gvb_server/api" 4 | 5 | func (router RouterGroup) NewsRouter() { 6 | app := api.ApiGroupApp.NewsApi 7 | router.POST("news", app.NewsListView) 8 | 9 | } 10 | -------------------------------------------------------------------------------- /routers/settings_router.go: -------------------------------------------------------------------------------- 1 | package routers 2 | 3 | import ( 4 | "gvb_server/api" 5 | "gvb_server/middleware" 6 | ) 7 | 8 | func (router RouterGroup) SettingsRouter() { 9 | settingsApi := api.ApiGroupApp.SettingApi 10 | router.GET("settings/site", settingsApi.SettingsSiteInfoView) 11 | router.PUT("settings/site", middleware.JwtAdmin(), settingsApi.SettingsSiteUpdateView) 12 | router.GET("settings/:name", middleware.JwtAdmin(), settingsApi.SettingsInfoView) 13 | router.PUT("settings/:name", middleware.JwtAdmin(), settingsApi.SettingsUpdateView) 14 | } 15 | -------------------------------------------------------------------------------- /routers/tag_router.go: -------------------------------------------------------------------------------- 1 | package routers 2 | 3 | import ( 4 | "gvb_server/api" 5 | "gvb_server/middleware" 6 | ) 7 | 8 | func (router RouterGroup) TagRouter() { 9 | app := api.ApiGroupApp.TagApi 10 | router.POST("tags", middleware.JwtAuth(), app.TagCreateView) 11 | router.GET("tags", app.TagListView) 12 | router.GET("tag_names", app.TagNameListView) 13 | router.PUT("tags/:id", middleware.JwtAdmin(), app.TagUpdateView) 14 | router.DELETE("tags", middleware.JwtAdmin(), app.TagRemoveView) 15 | } 16 | -------------------------------------------------------------------------------- /routers/user_router.go: -------------------------------------------------------------------------------- 1 | package routers 2 | 3 | import ( 4 | "github.com/gin-contrib/sessions" 5 | "github.com/gin-contrib/sessions/cookie" 6 | "gvb_server/api" 7 | "gvb_server/middleware" 8 | ) 9 | 10 | var store = cookie.NewStore([]byte("Hb65sd7fk76ul8jg34523")) 11 | 12 | func (router RouterGroup) UserRouter() { 13 | app := api.ApiGroupApp.UserApi 14 | router.Use(sessions.Sessions("sessionid", store)) 15 | router.POST("email_login", app.EmailLoginView) 16 | router.POST("qq_login", app.QQLoginView) 17 | router.GET("qq_login_path", app.QQLoginLinkView) // QQ登录的跳转地址 18 | router.POST("users", middleware.JwtAdmin(), app.UserCreateView) 19 | router.GET("users", middleware.JwtAuth(), app.UserListView) 20 | router.PUT("user_role", middleware.JwtAdmin(), app.UserUpdateRoleView) 21 | router.PUT("user_password", middleware.JwtAuth(), app.UserUpdatePassword) 22 | router.POST("logout", middleware.JwtAuth(), app.LogoutView) 23 | router.DELETE("users", middleware.JwtAdmin(), app.UserRemove) 24 | router.POST("user_bind_email", middleware.JwtAuth(), app.UserBindEmailView) 25 | router.POST("user_register", app.UserRegisterView) // 用户注册 26 | router.GET("user_info", middleware.JwtAuth(), app.UserInfoView) 27 | router.PUT("user_info", middleware.JwtAuth(), app.UserUpdateNickName) 28 | } 29 | -------------------------------------------------------------------------------- /service/common/service_list.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "fmt" 5 | "gorm.io/gorm" 6 | "gvb_server/global" 7 | "gvb_server/models" 8 | ) 9 | 10 | type Option struct { 11 | models.PageInfo 12 | Debug bool 13 | Likes []string // 模糊匹配的字段 14 | Preload []string // 预加载的列表 15 | } 16 | 17 | func ComList[T any](model T, option Option) (list []T, count int64, err error) { 18 | 19 | DB := global.DB 20 | 21 | if option.Debug { 22 | DB = global.DB.Session(&gorm.Session{Logger: global.MysqlLog}) 23 | } 24 | if option.Sort == "" { 25 | option.Sort = "created_at desc" // 默认按照创建时间从大到小 26 | } 27 | DB = DB.Where(model) 28 | for index, column := range option.Likes { 29 | if index == 0 { 30 | DB.Where(fmt.Sprintf("%s like ?", column), fmt.Sprintf("%%%s%%", option.Key)) 31 | continue 32 | } 33 | DB.Or(fmt.Sprintf("%s like ?", column), fmt.Sprintf("%%%s%%", option.Key)) 34 | } 35 | 36 | count = DB.Where(model).Find(&list).RowsAffected 37 | // 这里的query会受上面查询的影响,需要手动复位 38 | query := DB.Where(model) 39 | 40 | for _, preload := range option.Preload { 41 | query = query.Preload(preload) 42 | } 43 | 44 | offset := (option.Page - 1) * option.Limit 45 | if offset < 0 { 46 | offset = 0 47 | } 48 | 49 | err = query.Limit(option.Limit).Offset(offset).Order(option.Sort).Find(&list).Error 50 | 51 | return list, count, err 52 | } 53 | -------------------------------------------------------------------------------- /service/cron_ser/enter.go: -------------------------------------------------------------------------------- 1 | package cron_ser 2 | 3 | import ( 4 | "github.com/robfig/cron/v3" 5 | "time" 6 | ) 7 | 8 | // CronInit 定时任务 9 | func CronInit() { 10 | 11 | timezone, _ := time.LoadLocation("Asia/Shanghai") 12 | Cron := cron.New(cron.WithSeconds(), cron.WithLocation(timezone)) 13 | Cron.AddFunc("*/10 * * * * *", SyncArticleData) 14 | Cron.AddFunc("*/10 * * * * *", SyncCommentData) 15 | Cron.Start() 16 | 17 | } 18 | -------------------------------------------------------------------------------- /service/cron_ser/sync_comment_data.go: -------------------------------------------------------------------------------- 1 | package cron_ser 2 | 3 | import ( 4 | "gorm.io/gorm" 5 | "gvb_server/global" 6 | "gvb_server/models" 7 | "gvb_server/service/redis_ser" 8 | ) 9 | 10 | // SyncCommentData 同步redis评论数据到数据库 11 | func SyncCommentData() { 12 | commentDiggInfo := redis_ser.NewCommentDigg().GetInfo() 13 | for key, count := range commentDiggInfo { 14 | var comment models.CommentModel 15 | err := global.DB.Take(&comment, key).Error 16 | if err != nil { 17 | global.Log.Error(err) 18 | continue 19 | } 20 | err = global.DB.Model(&comment). 21 | Update("digg_count", gorm.Expr("digg + ?", count)).Error 22 | if err != nil { 23 | global.Log.Error(err) 24 | continue 25 | } 26 | global.Log.Infof("%s 更新成功 点赞数为:%d", comment.Content, comment.CommentCount) 27 | } 28 | redis_ser.NewCommentDigg().Clear() 29 | } 30 | -------------------------------------------------------------------------------- /service/enter.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "gvb_server/service/image_ser" 5 | "gvb_server/service/user_ser" 6 | ) 7 | 8 | type ServiceGroup struct { 9 | ImageService image_ser.ImageService 10 | UserService user_ser.UserService 11 | } 12 | 13 | var ServiceApp = new(ServiceGroup) 14 | -------------------------------------------------------------------------------- /service/es_ser/enter.go: -------------------------------------------------------------------------------- 1 | package es_ser 2 | 3 | import ( 4 | "github.com/olivere/elastic/v7" 5 | "gvb_server/models" 6 | ) 7 | 8 | type Option struct { 9 | models.PageInfo 10 | Fields []string 11 | Tag string 12 | Query *elastic.BoolQuery 13 | } 14 | 15 | func (o *Option) GetForm() int { 16 | if o.Page == 0 { 17 | o.Page = 1 18 | } 19 | if o.Limit == 0 { 20 | o.Limit = 10 21 | } 22 | return (o.Page - 1) * o.Limit 23 | } 24 | -------------------------------------------------------------------------------- /service/image_ser/enter.go: -------------------------------------------------------------------------------- 1 | package image_ser 2 | 3 | type ImageService struct { 4 | } 5 | -------------------------------------------------------------------------------- /service/redis_ser/count.go: -------------------------------------------------------------------------------- 1 | package redis_ser 2 | 3 | import ( 4 | "gvb_server/global" 5 | "strconv" 6 | ) 7 | 8 | // CountDB redis构造方法 9 | type CountDB struct { 10 | Index string // 索引前缀 11 | } 12 | 13 | // Set 设置某一个数据,重复执行,重复累加 14 | func (c CountDB) Set(id string) error { 15 | num, _ := global.Redis.HGet(c.Index, id).Int() 16 | num++ 17 | err := global.Redis.HSet(c.Index, id, num).Err() 18 | return err 19 | } 20 | 21 | // SetCount 在原有基础上增加多少 22 | func (c CountDB) SetCount(id string, num int) error { 23 | oldNum, _ := global.Redis.HGet(c.Index, id).Int() 24 | newNum := oldNum + num 25 | err := global.Redis.HSet(c.Index, id, newNum).Err() 26 | return err 27 | } 28 | 29 | // Get 获取某一数据 30 | func (c CountDB) Get(id string) int { 31 | num, _ := global.Redis.HGet(c.Index, id).Int() 32 | return num 33 | } 34 | 35 | // GetInfo 获取数据 36 | func (c CountDB) GetInfo() map[string]int { 37 | var diggInfo = map[string]int{} 38 | maps := global.Redis.HGetAll(c.Index).Val() 39 | for id, val := range maps { 40 | num, _ := strconv.Atoi(val) 41 | diggInfo[id] = num 42 | } 43 | return diggInfo 44 | } 45 | 46 | // Clear 删除数据 47 | func (c CountDB) Clear() { 48 | global.Redis.Del(c.Index) 49 | } 50 | -------------------------------------------------------------------------------- /service/redis_ser/enter.go: -------------------------------------------------------------------------------- 1 | package redis_ser 2 | 3 | const ( 4 | articleCommentCountPrefix = "article_comment_count" 5 | articleLookPrefix = "article_look" 6 | articleDiggPrefix = "article_digg" 7 | commentDiggPrefix = "comment_digg" 8 | ) 9 | 10 | func NewDigg() CountDB { 11 | return CountDB{ 12 | Index: articleDiggPrefix, 13 | } 14 | } 15 | 16 | func NewArticleLook() CountDB { 17 | return CountDB{ 18 | Index: articleLookPrefix, 19 | } 20 | } 21 | 22 | func NewCommentCount() CountDB { 23 | return CountDB{ 24 | Index: articleCommentCountPrefix, 25 | } 26 | } 27 | 28 | func NewCommentDigg() CountDB { 29 | return CountDB{ 30 | Index: commentDiggPrefix, 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /service/redis_ser/logout.go: -------------------------------------------------------------------------------- 1 | package redis_ser 2 | 3 | import ( 4 | "gvb_server/global" 5 | "gvb_server/utils" 6 | "time" 7 | ) 8 | 9 | const prefix = "logout_" 10 | 11 | // Logout 针对注销的操作 12 | func Logout(token string, diff time.Duration) error { 13 | err := global.Redis.Set(prefix+token, "", diff).Err() 14 | return err 15 | } 16 | 17 | func CheckLogout(token string) bool { 18 | keys := global.Redis.Keys(prefix + "*").Val() 19 | if utils.InList(prefix+token, keys) { 20 | return true 21 | } 22 | return false 23 | } 24 | -------------------------------------------------------------------------------- /service/redis_ser/news.go: -------------------------------------------------------------------------------- 1 | package redis_ser 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "gvb_server/global" 7 | "time" 8 | ) 9 | 10 | const newsIndex = "news_index" 11 | 12 | type NewData struct { 13 | Index interface{} `json:"index"` // 这接口index有些是int有些string,不确定的数据类型 14 | Title string `json:"title"` 15 | HotValue string `json:"hotValue"` 16 | Link string `json:"link"` 17 | } 18 | 19 | // SetNews 新闻存入缓存 20 | func SetNews(key string, newData []NewData) error { 21 | byteData, _ := json.Marshal(newData) 22 | // 缓存一小时过期 23 | err := global.Redis.Set(fmt.Sprintf("%s_%s", newsIndex, key), byteData, 1*time.Hour).Err() 24 | //err := global.Redis.HSet(newsIndex, key, byteData).Err() 25 | return err 26 | } 27 | 28 | func GetNews(key string) (newData []NewData, err error) { 29 | res := global.Redis.Get(fmt.Sprintf("%s_%s", newsIndex, key)).Val() 30 | err = json.Unmarshal([]byte(res), &newData) 31 | return 32 | } 33 | -------------------------------------------------------------------------------- /service/user_ser/create_user.go: -------------------------------------------------------------------------------- 1 | package user_ser 2 | 3 | import ( 4 | "errors" 5 | "gvb_server/global" 6 | "gvb_server/models" 7 | "gvb_server/models/ctype" 8 | "gvb_server/utils" 9 | "gvb_server/utils/pwd" 10 | ) 11 | 12 | const Avatar = "/uploads/avatar/default.jpg" 13 | 14 | func (UserService) CreateUser(userName, nickName, password string, role ctype.Role, email string, ip string) error { 15 | // 判断用户名是否存在 16 | var userModel models.UserModel 17 | err := global.DB.Take(&userModel, "user_name = ?", userName).Error 18 | if err == nil { 19 | //存在 20 | return errors.New("用户名已存在,请重新输入") 21 | } 22 | // 对密码进行hash 23 | hashPwd := pwd.HashPwd(password) 24 | 25 | // 头像问题 26 | // 1.默认头像 27 | // 2.随机选择头像 28 | addr := utils.GetAddr(ip) 29 | // 入库 30 | err = global.DB.Create(&models.UserModel{ 31 | NickName: nickName, 32 | UserName: userName, 33 | Password: hashPwd, 34 | Email: email, 35 | Role: role, 36 | Avatar: Avatar, 37 | IP: ip, 38 | Addr: addr, 39 | SignStatus: ctype.SignEmail, 40 | }).Error 41 | if err != nil { 42 | return err 43 | } 44 | return nil 45 | } 46 | -------------------------------------------------------------------------------- /service/user_ser/enter.go: -------------------------------------------------------------------------------- 1 | package user_ser 2 | 3 | type UserService struct { 4 | } 5 | -------------------------------------------------------------------------------- /service/user_ser/logout.go: -------------------------------------------------------------------------------- 1 | package user_ser 2 | 3 | import ( 4 | "gvb_server/service/redis_ser" 5 | "gvb_server/utils/jwts" 6 | "time" 7 | ) 8 | 9 | func (UserService) Logout(claims *jwts.CustomClaims, token string) error { 10 | // 需要计算距离现在的过期时间 11 | exp := claims.ExpiresAt // 过期时间 12 | now := time.Now() 13 | diff := exp.Time.Sub(now) 14 | return redis_ser.Logout(token, diff) 15 | } 16 | -------------------------------------------------------------------------------- /testdata/0.测试窗口.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func main() { 9 | fmt.Println(time.Now()) 10 | 11 | } 12 | -------------------------------------------------------------------------------- /testdata/1.错误码读取.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/sirupsen/logrus" 7 | "gvb_server/models/res" 8 | "os" 9 | ) 10 | 11 | const file = "models/res/err_code.json" 12 | 13 | type ErrResponse struct { 14 | } 15 | 16 | type ErrMap map[res.ErrorCode]string 17 | 18 | func main() { 19 | byteData, err := os.ReadFile(file) 20 | if err != nil { 21 | logrus.Error(err) 22 | return 23 | } 24 | var errMap = ErrMap{} 25 | err = json.Unmarshal(byteData, &errMap) 26 | if err != nil { 27 | logrus.Error(err) 28 | return 29 | } 30 | 31 | fmt.Println(errMap) 32 | fmt.Println(errMap[res.SettingsError]) 33 | 34 | } 35 | -------------------------------------------------------------------------------- /testdata/10.删除全文搜索.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "gvb_server/core" 5 | "gvb_server/global" 6 | "gvb_server/service/es_ser" 7 | ) 8 | 9 | func main() { 10 | core.InitConf() 11 | global.ESClient = core.EsConnect() 12 | es_ser.DeleteFullTextByArticleID("nOaL0ocB_M76BrAWCR03") 13 | } 14 | -------------------------------------------------------------------------------- /testdata/11.文章评论列表.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "gvb_server/core" 6 | "gvb_server/global" 7 | "gvb_server/models" 8 | ) 9 | 10 | func main() { 11 | core.InitConf() 12 | global.Log = core.InitLogger() 13 | global.DB = core.InitGorm() 14 | FindArticleCommentList("XNI61ocBvJkxiQvwtge8") 15 | } 16 | 17 | func FindArticleCommentList(articleID string) { 18 | // 先把文章下的根评论查出 19 | var RootCommentList []*models.CommentModel 20 | global.DB.Find(&RootCommentList, "article_id = ? and parent_comment_id is null", articleID) 21 | // 遍历根评论,递归查根评论下的所有子评论 22 | for _, model := range RootCommentList { 23 | var subCommentList []models.CommentModel 24 | FindSubComment(*model, &subCommentList) 25 | model.SubComments = subCommentList 26 | } 27 | fmt.Println(RootCommentList[0]) 28 | } 29 | 30 | // FindSubComment 递归查某评论下的子评论 31 | func FindSubComment(model models.CommentModel, subCommentList *[]models.CommentModel) { 32 | global.DB.Preload("SubComments").Take(&model) 33 | for _, sub := range model.SubComments { 34 | *subCommentList = append(*subCommentList, sub) 35 | FindSubComment(sub, subCommentList) 36 | } 37 | return 38 | } 39 | -------------------------------------------------------------------------------- /testdata/12.切片反转.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | i := []int{6, 2, 3, 4} 7 | Reverse(i) 8 | fmt.Println(i) //[4 3 2 6] 9 | 10 | s := []string{"哈哈哈", "嘻嘻嘻", "略略略", "lbwnb", "321"} 11 | Reverse(s) 12 | fmt.Println(s) //[321 lbwnb 略略略 嘻嘻嘻 哈哈哈] 13 | } 14 | 15 | // Reverse 切片反转 16 | func Reverse[T any](slice []T) { 17 | for i, j := 0, len(slice)-1; i < j; i, j = i+1, j-1 { 18 | slice[i], slice[j] = slice[j], slice[i] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /testdata/13.新闻测试.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/sirupsen/logrus" 7 | "io" 8 | "net/http" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | type Params struct { 14 | ID string `json:"id"` 15 | } 16 | 17 | type NewsResponse struct { 18 | Code int `json:"code"` 19 | Data []struct { 20 | Index string `json:"index"` 21 | Title string `json:"title"` 22 | HotValue string `json:"hotValue"` 23 | Link string `json:"link"` 24 | } `json:"data"` 25 | Msg string `json:"msg"` 26 | } 27 | 28 | func main() { 29 | var params = Params{ 30 | ID: "mproPpoq6O", 31 | } 32 | reqParam, _ := json.Marshal(params) 33 | reqBody := strings.NewReader(string(reqParam)) 34 | url := "https://api.codelife.cc/api/top/list" 35 | httpReq, err := http.NewRequest("POST", url, reqBody) 36 | if err != nil { 37 | logrus.Error(err) 38 | return 39 | } 40 | httpReq.Header.Add("Content-Type", "application/json") 41 | httpReq.Header.Add("version", "1.3.35") 42 | httpReq.Header.Add("signaturekey", "U2FsdGVkX19R+FnzVgqWm4fp/6b4yAXdeBcmT3Uwods=") 43 | 44 | client := http.Client{ 45 | Timeout: 2 * time.Second, 46 | } 47 | // DO: HTTP请求 48 | httpRsp, err := client.Do(httpReq) 49 | if err != nil { 50 | logrus.Error(err) 51 | return 52 | } 53 | ByteData, err := io.ReadAll(httpRsp.Body) 54 | 55 | var response NewsResponse 56 | err = json.Unmarshal(ByteData, &response) 57 | if err != nil { 58 | logrus.Error(err) 59 | return 60 | } 61 | if response.Code != 200 { 62 | logrus.Error(response.Msg) 63 | return 64 | } 65 | fmt.Println(response) 66 | } 67 | -------------------------------------------------------------------------------- /testdata/15.日志测试.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "gvb_server/core" 6 | "gvb_server/global" 7 | "gvb_server/plugins/log_stash" 8 | ) 9 | 10 | func main() { 11 | core.InitConf() 12 | // 初始化日志 13 | global.Log = core.InitLogger() 14 | // 连接数据库 15 | global.DB = core.InitGorm() 16 | 17 | log := log_stash.New("192.168.100.101", "xxxxx") 18 | log.Error(fmt.Sprintf("%s 我日", "嘻嘻嘻")) 19 | } 20 | -------------------------------------------------------------------------------- /testdata/16.ip获取城市.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/cc14514/go-geoip2" 6 | geoip2db "github.com/cc14514/go-geoip2-db" 7 | "net" 8 | "time" 9 | ) 10 | 11 | var db *geoip2.DBReader 12 | 13 | func init() { 14 | db, _ = geoip2db.NewGeoipDbByStatik() 15 | //defer db.Close() 16 | } 17 | 18 | func main() { 19 | now := time.Now() 20 | fmt.Println(GetAddr("119.129.50.248")) 21 | fmt.Println(GetAddr("127.0.0.1")) 22 | fmt.Println(GetAddr("192.168.100.101")) 23 | fmt.Println(GetAddr("125.65.122.248")) 24 | fmt.Println(GetAddr("153.129.50.248")) 25 | fmt.Println(time.Since(now)) 26 | defer db.Close() 27 | } 28 | 29 | func GetAddr(ip string) string { 30 | parseIP := net.ParseIP(ip) 31 | if IsIntranetIP(parseIP) { 32 | return "内网地址" 33 | } 34 | record, err := db.City(net.ParseIP(ip)) 35 | if err != nil { 36 | return "错误的地址" 37 | } 38 | var province string 39 | if len(record.Subdivisions) > 0 { 40 | province = record.Subdivisions[0].Names["zh-CN"] 41 | } 42 | 43 | city := record.City.Names["zh-CN"] 44 | return fmt.Sprintf("%s-%s", province, city) 45 | } 46 | 47 | // IsIntranetIP 内网地址判断 48 | func IsIntranetIP(ip net.IP) bool { 49 | if ip.IsLoopback() { 50 | return true 51 | } 52 | 53 | ip4 := ip.To4() 54 | if ip4 == nil { 55 | return false 56 | } 57 | fmt.Println(ip4) 58 | // 192.168 59 | // 172.16 -172.31 60 | // 10 61 | // 169.254 62 | return ip4[0] == 192 && ip4[1] == 168 || 63 | (ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31) || 64 | (ip4[0] == 10) || 65 | (ip4[0] == 169 && ip4[1] == 254) 66 | } 67 | -------------------------------------------------------------------------------- /testdata/17.获取网卡ip.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/sirupsen/logrus" 6 | "log" 7 | "net" 8 | ) 9 | 10 | func main() { 11 | interfaces, err := net.Interfaces() 12 | if err != nil { 13 | log.Fatal(err) 14 | } 15 | 16 | for _, i2 := range interfaces { 17 | addrs, err := i2.Addrs() 18 | if err != nil { 19 | logrus.Error(err) 20 | continue 21 | } 22 | for _, addr := range addrs { 23 | ipNet, ok := addr.(*net.IPNet) 24 | if !ok { 25 | continue 26 | } 27 | ip4 := ipNet.IP.To4() 28 | if ip4 == nil { 29 | continue 30 | } 31 | fmt.Println(ip4) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /testdata/2.structs.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/fatih/structs" 6 | "gvb_server/models" 7 | ) 8 | 9 | type AdvertRequest struct { 10 | models.MODEL `structs:"-"` 11 | Title string `json:"title" binding:"required" msg:"请输入标题" structs:"title"` // 显示的标题 12 | Href string `json:"href" binding:"required,url" msg:"跳转链接非法" structs:"-"` // 跳转链接 13 | Images string `json:"images" binding:"required,url" msg:"图片地址非法"` // 图片 14 | IsShow bool `json:"is_show" binding:"required" msg:"请选择是否展示" structs:"is_show"` // 是否展示 15 | } 16 | 17 | func main() { 18 | u1 := AdvertRequest{ 19 | Title: "xxxxxxx", 20 | Href: "xxxxxxx", 21 | Images: "xxxxxxx", 22 | IsShow: true, 23 | } 24 | m3 := structs.Map(&u1) 25 | fmt.Println(m3) 26 | } 27 | -------------------------------------------------------------------------------- /testdata/3.jwt测试.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "gvb_server/core" 6 | "gvb_server/global" 7 | "gvb_server/utils/jwts" 8 | ) 9 | 10 | func main() { 11 | core.InitConf() 12 | global.Log = core.InitLogger() 13 | 14 | fmt.Println(global.Config.Jwt.Secret) 15 | token, err := jwts.GenToken(jwts.JwtPayLoad{ 16 | //Username: "xixi", 17 | NickName: "xxx", 18 | Role: 1, 19 | UserID: 1, 20 | Avatar: "xxx", 21 | }) 22 | fmt.Println(token, err) 23 | 24 | claims, err := jwts.ParseToken(token) 25 | fmt.Println(claims, err) 26 | } 27 | -------------------------------------------------------------------------------- /testdata/4.redis.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "github.com/go-redis/redis" 7 | "github.com/sirupsen/logrus" 8 | "time" 9 | ) 10 | 11 | var rdb *redis.Client 12 | 13 | func init() { 14 | rdb = redis.NewClient(&redis.Options{ 15 | Addr: "127.0.0.1:6379", 16 | //Password: "redis", // no password set 17 | DB: 0, // use default DB 18 | PoolSize: 100, // 连接池大小 19 | }) 20 | _, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) 21 | defer cancel() 22 | _, err := rdb.Ping().Result() 23 | if err != nil { 24 | logrus.Error(err) 25 | return 26 | } 27 | } 28 | 29 | func main() { 30 | // 写入,过期时间10秒 31 | err := rdb.Set("hello", "world", 10*time.Second).Err() 32 | fmt.Println(err) 33 | 34 | // 读取 35 | v := rdb.Get("hello") 36 | fmt.Println(v) 37 | 38 | // 查所有的key 39 | cmd := rdb.Keys("*") 40 | keys, err := cmd.Result() 41 | fmt.Println(keys, err) 42 | } 43 | -------------------------------------------------------------------------------- /testdata/6.随机密码.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "gvb_server/utils/random" 6 | ) 7 | 8 | func main() { 9 | s := random.RandString(16) 10 | fmt.Println(s) 11 | } 12 | -------------------------------------------------------------------------------- /testdata/7.markdown转html.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/PuerkitoBio/goquery" 6 | "github.com/russross/blackfriday" 7 | "strings" 8 | ) 9 | 10 | func main() { 11 | // Markdown转html 12 | unsafe := blackfriday.MarkdownCommon([]byte("### 你好\n ```python\nprint('你好')\n```\n - 123 \n \n\n\n ![图片](http://xxx.com)")) 13 | fmt.Println(string(unsafe)) 14 | fmt.Println("---------------") 15 | doc, _ := goquery.NewDocumentFromReader(strings.NewReader(string(unsafe))) 16 | //fmt.Println(doc.Text()) 17 | doc.Find("script").Remove() 18 | fmt.Println(doc.Text()) 19 | } 20 | -------------------------------------------------------------------------------- /testdata/9.同步es数据到全文搜索.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/olivere/elastic/v7" 8 | "github.com/sirupsen/logrus" 9 | "gvb_server/core" 10 | "gvb_server/global" 11 | "gvb_server/models" 12 | "gvb_server/service/es_ser" 13 | ) 14 | 15 | func main() { 16 | core.InitConf() 17 | core.InitConf() 18 | global.ESClient = core.EsConnect() 19 | 20 | boolSearch := elastic.NewMatchAllQuery() 21 | result, _ := global.ESClient.Search(models.ArticleModel{}.Index()). 22 | Query(boolSearch). 23 | Size(1000). 24 | Do(context.Background()) 25 | 26 | for _, hit := range result.Hits.Hits { 27 | var article models.ArticleModel 28 | _ = json.Unmarshal(hit.Source, &article) 29 | 30 | indexList := es_ser.GetSearchIndexDataByContent(hit.Id, article.Title, article.Content) 31 | 32 | // 批量添加 33 | bulk := global.ESClient.Bulk() 34 | for _, indexData := range indexList { 35 | req := elastic.NewBulkIndexRequest().Index(models.FullTextModel{}.Index()).Doc(indexData) 36 | bulk.Add(req) 37 | } 38 | result, err := bulk.Do(context.Background()) 39 | if err != nil { 40 | fmt.Println(err) 41 | logrus.Error(err) 42 | continue 43 | } 44 | fmt.Println(article.Title, "添加成功", len(result.Succeeded()), "条") 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /uploads/avatar/default.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/avatar/default.jpg -------------------------------------------------------------------------------- /uploads/chat_avatar/一.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/一.png -------------------------------------------------------------------------------- /uploads/chat_avatar/不.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/不.png -------------------------------------------------------------------------------- /uploads/chat_avatar/专.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/专.png -------------------------------------------------------------------------------- /uploads/chat_avatar/个.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/个.png -------------------------------------------------------------------------------- /uploads/chat_avatar/丰.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/丰.png -------------------------------------------------------------------------------- /uploads/chat_avatar/义.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/义.png -------------------------------------------------------------------------------- /uploads/chat_avatar/乐.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/乐.png -------------------------------------------------------------------------------- /uploads/chat_avatar/乔.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/乔.png -------------------------------------------------------------------------------- /uploads/chat_avatar/仁.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/仁.png -------------------------------------------------------------------------------- /uploads/chat_avatar/从.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/从.png -------------------------------------------------------------------------------- /uploads/chat_avatar/任.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/任.png -------------------------------------------------------------------------------- /uploads/chat_avatar/伊.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/伊.png -------------------------------------------------------------------------------- /uploads/chat_avatar/优.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/优.png -------------------------------------------------------------------------------- /uploads/chat_avatar/会.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/会.png -------------------------------------------------------------------------------- /uploads/chat_avatar/传.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/传.png -------------------------------------------------------------------------------- /uploads/chat_avatar/伶.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/伶.png -------------------------------------------------------------------------------- /uploads/chat_avatar/佐.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/佐.png -------------------------------------------------------------------------------- /uploads/chat_avatar/体.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/体.png -------------------------------------------------------------------------------- /uploads/chat_avatar/俊.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/俊.png -------------------------------------------------------------------------------- /uploads/chat_avatar/俏.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/俏.png -------------------------------------------------------------------------------- /uploads/chat_avatar/保.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/保.png -------------------------------------------------------------------------------- /uploads/chat_avatar/俭.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/俭.png -------------------------------------------------------------------------------- /uploads/chat_avatar/健.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/健.png -------------------------------------------------------------------------------- /uploads/chat_avatar/傲.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/傲.png -------------------------------------------------------------------------------- /uploads/chat_avatar/傻.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/傻.png -------------------------------------------------------------------------------- /uploads/chat_avatar/儒.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/儒.png -------------------------------------------------------------------------------- /uploads/chat_avatar/光.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/光.png -------------------------------------------------------------------------------- /uploads/chat_avatar/兴.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/兴.png -------------------------------------------------------------------------------- /uploads/chat_avatar/典.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/典.png -------------------------------------------------------------------------------- /uploads/chat_avatar/内.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/内.png -------------------------------------------------------------------------------- /uploads/chat_avatar/冷.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/冷.png -------------------------------------------------------------------------------- /uploads/chat_avatar/凶.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/凶.png -------------------------------------------------------------------------------- /uploads/chat_avatar/列.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/列.png -------------------------------------------------------------------------------- /uploads/chat_avatar/刻.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/刻.png -------------------------------------------------------------------------------- /uploads/chat_avatar/加.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/加.png -------------------------------------------------------------------------------- /uploads/chat_avatar/务.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/务.png -------------------------------------------------------------------------------- /uploads/chat_avatar/动.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/动.png -------------------------------------------------------------------------------- /uploads/chat_avatar/勤.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/勤.png -------------------------------------------------------------------------------- /uploads/chat_avatar/包.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/包.png -------------------------------------------------------------------------------- /uploads/chat_avatar/单.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/单.png -------------------------------------------------------------------------------- /uploads/chat_avatar/博.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/博.png -------------------------------------------------------------------------------- /uploads/chat_avatar/卡.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/卡.png -------------------------------------------------------------------------------- /uploads/chat_avatar/危.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/危.png -------------------------------------------------------------------------------- /uploads/chat_avatar/友.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/友.png -------------------------------------------------------------------------------- /uploads/chat_avatar/发.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/发.png -------------------------------------------------------------------------------- /uploads/chat_avatar/受.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/受.png -------------------------------------------------------------------------------- /uploads/chat_avatar/古.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/古.png -------------------------------------------------------------------------------- /uploads/chat_avatar/可.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/可.png -------------------------------------------------------------------------------- /uploads/chat_avatar/合.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/合.png -------------------------------------------------------------------------------- /uploads/chat_avatar/含.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/含.png -------------------------------------------------------------------------------- /uploads/chat_avatar/听.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/听.png -------------------------------------------------------------------------------- /uploads/chat_avatar/呆.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/呆.png -------------------------------------------------------------------------------- /uploads/chat_avatar/和.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/和.png -------------------------------------------------------------------------------- /uploads/chat_avatar/哈.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/哈.png -------------------------------------------------------------------------------- /uploads/chat_avatar/哭.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/哭.png -------------------------------------------------------------------------------- /uploads/chat_avatar/唠.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/唠.png -------------------------------------------------------------------------------- /uploads/chat_avatar/善.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/善.png -------------------------------------------------------------------------------- /uploads/chat_avatar/喜.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/喜.png -------------------------------------------------------------------------------- /uploads/chat_avatar/土.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/土.png -------------------------------------------------------------------------------- /uploads/chat_avatar/坎.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/坎.png -------------------------------------------------------------------------------- /uploads/chat_avatar/坚.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/坚.png -------------------------------------------------------------------------------- /uploads/chat_avatar/坦.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/坦.png -------------------------------------------------------------------------------- /uploads/chat_avatar/壮.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/壮.png -------------------------------------------------------------------------------- /uploads/chat_avatar/复.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/复.png -------------------------------------------------------------------------------- /uploads/chat_avatar/外.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/外.png -------------------------------------------------------------------------------- /uploads/chat_avatar/多.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/多.png -------------------------------------------------------------------------------- /uploads/chat_avatar/大.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/大.png -------------------------------------------------------------------------------- /uploads/chat_avatar/天.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/天.png -------------------------------------------------------------------------------- /uploads/chat_avatar/失.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/失.png -------------------------------------------------------------------------------- /uploads/chat_avatar/奋.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/奋.png -------------------------------------------------------------------------------- /uploads/chat_avatar/如.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/如.png -------------------------------------------------------------------------------- /uploads/chat_avatar/妩.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/妩.png -------------------------------------------------------------------------------- /uploads/chat_avatar/姆.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/姆.png -------------------------------------------------------------------------------- /uploads/chat_avatar/威.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/威.png -------------------------------------------------------------------------------- /uploads/chat_avatar/娇.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/娇.png -------------------------------------------------------------------------------- /uploads/chat_avatar/孝.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/孝.png -------------------------------------------------------------------------------- /uploads/chat_avatar/孤.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/孤.png -------------------------------------------------------------------------------- /uploads/chat_avatar/安.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/安.png -------------------------------------------------------------------------------- /uploads/chat_avatar/完.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/完.png -------------------------------------------------------------------------------- /uploads/chat_avatar/宙.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/宙.png -------------------------------------------------------------------------------- /uploads/chat_avatar/害.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/害.png -------------------------------------------------------------------------------- /uploads/chat_avatar/寂.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/寂.png -------------------------------------------------------------------------------- /uploads/chat_avatar/寒.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/寒.png -------------------------------------------------------------------------------- /uploads/chat_avatar/尊.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/尊.png -------------------------------------------------------------------------------- /uploads/chat_avatar/小.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/小.png -------------------------------------------------------------------------------- /uploads/chat_avatar/尤.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/尤.png -------------------------------------------------------------------------------- /uploads/chat_avatar/巴.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/巴.png -------------------------------------------------------------------------------- /uploads/chat_avatar/帅.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/帅.png -------------------------------------------------------------------------------- /uploads/chat_avatar/干.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/干.png -------------------------------------------------------------------------------- /uploads/chat_avatar/平.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/平.png -------------------------------------------------------------------------------- /uploads/chat_avatar/年.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/年.png -------------------------------------------------------------------------------- /uploads/chat_avatar/幸.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/幸.png -------------------------------------------------------------------------------- /uploads/chat_avatar/幽.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/幽.png -------------------------------------------------------------------------------- /uploads/chat_avatar/开.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/开.png -------------------------------------------------------------------------------- /uploads/chat_avatar/弗.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/弗.png -------------------------------------------------------------------------------- /uploads/chat_avatar/强.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/强.png -------------------------------------------------------------------------------- /uploads/chat_avatar/彩.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/彩.png -------------------------------------------------------------------------------- /uploads/chat_avatar/彪.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/彪.png -------------------------------------------------------------------------------- /uploads/chat_avatar/微.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/微.png -------------------------------------------------------------------------------- /uploads/chat_avatar/心.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/心.png -------------------------------------------------------------------------------- /uploads/chat_avatar/忐.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/忐.png -------------------------------------------------------------------------------- /uploads/chat_avatar/忧.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/忧.png -------------------------------------------------------------------------------- /uploads/chat_avatar/快.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/快.png -------------------------------------------------------------------------------- /uploads/chat_avatar/怕.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/怕.png -------------------------------------------------------------------------------- /uploads/chat_avatar/怡.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/怡.png -------------------------------------------------------------------------------- /uploads/chat_avatar/悦.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/悦.png -------------------------------------------------------------------------------- /uploads/chat_avatar/悲.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/悲.png -------------------------------------------------------------------------------- /uploads/chat_avatar/想.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/想.png -------------------------------------------------------------------------------- /uploads/chat_avatar/愉.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/愉.png -------------------------------------------------------------------------------- /uploads/chat_avatar/感.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/感.png -------------------------------------------------------------------------------- /uploads/chat_avatar/愤.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/愤.png -------------------------------------------------------------------------------- /uploads/chat_avatar/慈.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/慈.png -------------------------------------------------------------------------------- /uploads/chat_avatar/懦.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/懦.png -------------------------------------------------------------------------------- /uploads/chat_avatar/懵.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/懵.png -------------------------------------------------------------------------------- /uploads/chat_avatar/成.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/成.png -------------------------------------------------------------------------------- /uploads/chat_avatar/托.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/托.png -------------------------------------------------------------------------------- /uploads/chat_avatar/执.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/执.png -------------------------------------------------------------------------------- /uploads/chat_avatar/拉.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/拉.png -------------------------------------------------------------------------------- /uploads/chat_avatar/拼.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/拼.png -------------------------------------------------------------------------------- /uploads/chat_avatar/搞.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/搞.png -------------------------------------------------------------------------------- /uploads/chat_avatar/摩.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/摩.png -------------------------------------------------------------------------------- /uploads/chat_avatar/故.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/故.png -------------------------------------------------------------------------------- /uploads/chat_avatar/敏.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/敏.png -------------------------------------------------------------------------------- /uploads/chat_avatar/整.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/整.png -------------------------------------------------------------------------------- /uploads/chat_avatar/文.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/文.png -------------------------------------------------------------------------------- /uploads/chat_avatar/斯.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/斯.png -------------------------------------------------------------------------------- /uploads/chat_avatar/无.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/无.png -------------------------------------------------------------------------------- /uploads/chat_avatar/时.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/时.png -------------------------------------------------------------------------------- /uploads/chat_avatar/明.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/明.png -------------------------------------------------------------------------------- /uploads/chat_avatar/昏.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/昏.png -------------------------------------------------------------------------------- /uploads/chat_avatar/星.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/星.png -------------------------------------------------------------------------------- /uploads/chat_avatar/普.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/普.png -------------------------------------------------------------------------------- /uploads/chat_avatar/暴.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/暴.png -------------------------------------------------------------------------------- /uploads/chat_avatar/曾.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/曾.png -------------------------------------------------------------------------------- /uploads/chat_avatar/有.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/有.png -------------------------------------------------------------------------------- /uploads/chat_avatar/朝.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/朝.png -------------------------------------------------------------------------------- /uploads/chat_avatar/本.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/本.png -------------------------------------------------------------------------------- /uploads/chat_avatar/朴.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/朴.png -------------------------------------------------------------------------------- /uploads/chat_avatar/机.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/机.png -------------------------------------------------------------------------------- /uploads/chat_avatar/柔.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/柔.png -------------------------------------------------------------------------------- /uploads/chat_avatar/柯.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/柯.png -------------------------------------------------------------------------------- /uploads/chat_avatar/标.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/标.png -------------------------------------------------------------------------------- /uploads/chat_avatar/梅.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/梅.png -------------------------------------------------------------------------------- /uploads/chat_avatar/欢.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/欢.png -------------------------------------------------------------------------------- /uploads/chat_avatar/欣.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/欣.png -------------------------------------------------------------------------------- /uploads/chat_avatar/欧.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/欧.png -------------------------------------------------------------------------------- /uploads/chat_avatar/正.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/正.png -------------------------------------------------------------------------------- /uploads/chat_avatar/殷.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/殷.png -------------------------------------------------------------------------------- /uploads/chat_avatar/永.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/永.png -------------------------------------------------------------------------------- /uploads/chat_avatar/沉.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/沉.png -------------------------------------------------------------------------------- /uploads/chat_avatar/洁.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/洁.png -------------------------------------------------------------------------------- /uploads/chat_avatar/活.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/活.png -------------------------------------------------------------------------------- /uploads/chat_avatar/济.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/济.png -------------------------------------------------------------------------------- /uploads/chat_avatar/淡.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/淡.png -------------------------------------------------------------------------------- /uploads/chat_avatar/深.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/深.png -------------------------------------------------------------------------------- /uploads/chat_avatar/清.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/清.png -------------------------------------------------------------------------------- /uploads/chat_avatar/温.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/温.png -------------------------------------------------------------------------------- /uploads/chat_avatar/满.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/满.png -------------------------------------------------------------------------------- /uploads/chat_avatar/漂.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/漂.png -------------------------------------------------------------------------------- /uploads/chat_avatar/潇.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/潇.png -------------------------------------------------------------------------------- /uploads/chat_avatar/激.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/激.png -------------------------------------------------------------------------------- /uploads/chat_avatar/火.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/火.png -------------------------------------------------------------------------------- /uploads/chat_avatar/灵.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/灵.png -------------------------------------------------------------------------------- /uploads/chat_avatar/炙.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/炙.png -------------------------------------------------------------------------------- /uploads/chat_avatar/烂.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/烂.png -------------------------------------------------------------------------------- /uploads/chat_avatar/热.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/热.png -------------------------------------------------------------------------------- /uploads/chat_avatar/爱.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/爱.png -------------------------------------------------------------------------------- /uploads/chat_avatar/犹.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/犹.png -------------------------------------------------------------------------------- /uploads/chat_avatar/狂.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/狂.png -------------------------------------------------------------------------------- /uploads/chat_avatar/独.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/独.png -------------------------------------------------------------------------------- /uploads/chat_avatar/玩.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/玩.png -------------------------------------------------------------------------------- /uploads/chat_avatar/现.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/现.png -------------------------------------------------------------------------------- /uploads/chat_avatar/甜.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/甜.png -------------------------------------------------------------------------------- /uploads/chat_avatar/生.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/生.png -------------------------------------------------------------------------------- /uploads/chat_avatar/畅.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/畅.png -------------------------------------------------------------------------------- /uploads/chat_avatar/留.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/留.png -------------------------------------------------------------------------------- /uploads/chat_avatar/疯.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/疯.png -------------------------------------------------------------------------------- /uploads/chat_avatar/痴.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/痴.png -------------------------------------------------------------------------------- /uploads/chat_avatar/瘦.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/瘦.png -------------------------------------------------------------------------------- /uploads/chat_avatar/盖.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/盖.png -------------------------------------------------------------------------------- /uploads/chat_avatar/直.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/直.png -------------------------------------------------------------------------------- /uploads/chat_avatar/眯.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/眯.png -------------------------------------------------------------------------------- /uploads/chat_avatar/眼.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/眼.png -------------------------------------------------------------------------------- /uploads/chat_avatar/着.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/着.png -------------------------------------------------------------------------------- /uploads/chat_avatar/知.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/知.png -------------------------------------------------------------------------------- /uploads/chat_avatar/矮.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/矮.png -------------------------------------------------------------------------------- /uploads/chat_avatar/碧.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/碧.png -------------------------------------------------------------------------------- /uploads/chat_avatar/神.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/神.png -------------------------------------------------------------------------------- /uploads/chat_avatar/秀.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/秀.png -------------------------------------------------------------------------------- /uploads/chat_avatar/科.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/科.png -------------------------------------------------------------------------------- /uploads/chat_avatar/积.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/积.png -------------------------------------------------------------------------------- /uploads/chat_avatar/称.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/称.png -------------------------------------------------------------------------------- /uploads/chat_avatar/稳.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/稳.png -------------------------------------------------------------------------------- /uploads/chat_avatar/端.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/端.png -------------------------------------------------------------------------------- /uploads/chat_avatar/笑.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/笑.png -------------------------------------------------------------------------------- /uploads/chat_avatar/笨.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/笨.png -------------------------------------------------------------------------------- /uploads/chat_avatar/等.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/等.png -------------------------------------------------------------------------------- /uploads/chat_avatar/简.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/简.png -------------------------------------------------------------------------------- /uploads/chat_avatar/米.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/米.png -------------------------------------------------------------------------------- /uploads/chat_avatar/粗.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/粗.png -------------------------------------------------------------------------------- /uploads/chat_avatar/精.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/精.png -------------------------------------------------------------------------------- /uploads/chat_avatar/糊.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/糊.png -------------------------------------------------------------------------------- /uploads/chat_avatar/糟.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/糟.png -------------------------------------------------------------------------------- /uploads/chat_avatar/索.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/索.png -------------------------------------------------------------------------------- /uploads/chat_avatar/紧.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/紧.png -------------------------------------------------------------------------------- /uploads/chat_avatar/繁.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/繁.png -------------------------------------------------------------------------------- /uploads/chat_avatar/约.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/约.png -------------------------------------------------------------------------------- /uploads/chat_avatar/纯.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/纯.png -------------------------------------------------------------------------------- /uploads/chat_avatar/细.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/细.png -------------------------------------------------------------------------------- /uploads/chat_avatar/结.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/结.png -------------------------------------------------------------------------------- /uploads/chat_avatar/缓.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/缓.png -------------------------------------------------------------------------------- /uploads/chat_avatar/缥.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/缥.png -------------------------------------------------------------------------------- /uploads/chat_avatar/罗.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/罗.png -------------------------------------------------------------------------------- /uploads/chat_avatar/美.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/美.png -------------------------------------------------------------------------------- /uploads/chat_avatar/羞.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/羞.png -------------------------------------------------------------------------------- /uploads/chat_avatar/老.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/老.png -------------------------------------------------------------------------------- /uploads/chat_avatar/耍.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/耍.png -------------------------------------------------------------------------------- /uploads/chat_avatar/聪.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/聪.png -------------------------------------------------------------------------------- /uploads/chat_avatar/肖.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/肖.png -------------------------------------------------------------------------------- /uploads/chat_avatar/肯.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/肯.png -------------------------------------------------------------------------------- /uploads/chat_avatar/背.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/背.png -------------------------------------------------------------------------------- /uploads/chat_avatar/能.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/能.png -------------------------------------------------------------------------------- /uploads/chat_avatar/腼.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/腼.png -------------------------------------------------------------------------------- /uploads/chat_avatar/自.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/自.png -------------------------------------------------------------------------------- /uploads/chat_avatar/舒.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/舒.png -------------------------------------------------------------------------------- /uploads/chat_avatar/花.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/花.png -------------------------------------------------------------------------------- /uploads/chat_avatar/苏.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/苏.png -------------------------------------------------------------------------------- /uploads/chat_avatar/苗.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/苗.png -------------------------------------------------------------------------------- /uploads/chat_avatar/英.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/英.png -------------------------------------------------------------------------------- /uploads/chat_avatar/苹.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/苹.png -------------------------------------------------------------------------------- /uploads/chat_avatar/范.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/范.png -------------------------------------------------------------------------------- /uploads/chat_avatar/莫.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/莫.png -------------------------------------------------------------------------------- /uploads/chat_avatar/萧.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/萧.png -------------------------------------------------------------------------------- /uploads/chat_avatar/落.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/落.png -------------------------------------------------------------------------------- /uploads/chat_avatar/虚.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/虚.png -------------------------------------------------------------------------------- /uploads/chat_avatar/西.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/西.png -------------------------------------------------------------------------------- /uploads/chat_avatar/要.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/要.png -------------------------------------------------------------------------------- /uploads/chat_avatar/认.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/认.png -------------------------------------------------------------------------------- /uploads/chat_avatar/诚.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/诚.png -------------------------------------------------------------------------------- /uploads/chat_avatar/调.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/调.png -------------------------------------------------------------------------------- /uploads/chat_avatar/谦.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/谦.png -------------------------------------------------------------------------------- /uploads/chat_avatar/谨.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/谨.png -------------------------------------------------------------------------------- /uploads/chat_avatar/贝.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/贝.png -------------------------------------------------------------------------------- /uploads/chat_avatar/负.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/负.png -------------------------------------------------------------------------------- /uploads/chat_avatar/贤.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/贤.png -------------------------------------------------------------------------------- /uploads/chat_avatar/贪.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/贪.png -------------------------------------------------------------------------------- /uploads/chat_avatar/超.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/超.png -------------------------------------------------------------------------------- /uploads/chat_avatar/跳.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/跳.png -------------------------------------------------------------------------------- /uploads/chat_avatar/踏.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/踏.png -------------------------------------------------------------------------------- /uploads/chat_avatar/轻.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/轻.png -------------------------------------------------------------------------------- /uploads/chat_avatar/辛.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/辛.png -------------------------------------------------------------------------------- /uploads/chat_avatar/迅.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/迅.png -------------------------------------------------------------------------------- /uploads/chat_avatar/过.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/过.png -------------------------------------------------------------------------------- /uploads/chat_avatar/还.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/还.png -------------------------------------------------------------------------------- /uploads/chat_avatar/迪.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/迪.png -------------------------------------------------------------------------------- /uploads/chat_avatar/迷.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/迷.png -------------------------------------------------------------------------------- /uploads/chat_avatar/追.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/追.png -------------------------------------------------------------------------------- /uploads/chat_avatar/酷.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/酷.png -------------------------------------------------------------------------------- /uploads/chat_avatar/醉.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/醉.png -------------------------------------------------------------------------------- /uploads/chat_avatar/重.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/重.png -------------------------------------------------------------------------------- /uploads/chat_avatar/野.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/野.png -------------------------------------------------------------------------------- /uploads/chat_avatar/长.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/长.png -------------------------------------------------------------------------------- /uploads/chat_avatar/闪.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/闪.png -------------------------------------------------------------------------------- /uploads/chat_avatar/阔.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/阔.png -------------------------------------------------------------------------------- /uploads/chat_avatar/阳.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/阳.png -------------------------------------------------------------------------------- /uploads/chat_avatar/陶.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/陶.png -------------------------------------------------------------------------------- /uploads/chat_avatar/隐.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/隐.png -------------------------------------------------------------------------------- /uploads/chat_avatar/难.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/难.png -------------------------------------------------------------------------------- /uploads/chat_avatar/雅.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/雅.png -------------------------------------------------------------------------------- /uploads/chat_avatar/雪.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/雪.png -------------------------------------------------------------------------------- /uploads/chat_avatar/震.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/震.png -------------------------------------------------------------------------------- /uploads/chat_avatar/霸.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/霸.png -------------------------------------------------------------------------------- /uploads/chat_avatar/靓.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/靓.png -------------------------------------------------------------------------------- /uploads/chat_avatar/顺.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/顺.png -------------------------------------------------------------------------------- /uploads/chat_avatar/风.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/风.png -------------------------------------------------------------------------------- /uploads/chat_avatar/飘.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/飘.png -------------------------------------------------------------------------------- /uploads/chat_avatar/饱.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/饱.png -------------------------------------------------------------------------------- /uploads/chat_avatar/香.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/香.png -------------------------------------------------------------------------------- /uploads/chat_avatar/高.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/高.png -------------------------------------------------------------------------------- /uploads/chat_avatar/魁.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/魁.png -------------------------------------------------------------------------------- /uploads/chat_avatar/魔.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/魔.png -------------------------------------------------------------------------------- /uploads/chat_avatar/鲁.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/鲁.png -------------------------------------------------------------------------------- /uploads/chat_avatar/鲤.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/鲤.png -------------------------------------------------------------------------------- /uploads/chat_avatar/鳗.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/鳗.png -------------------------------------------------------------------------------- /uploads/chat_avatar/鸣.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/鸣.png -------------------------------------------------------------------------------- /uploads/chat_avatar/默.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/默.png -------------------------------------------------------------------------------- /uploads/chat_avatar/齐.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/chat_avatar/齐.png -------------------------------------------------------------------------------- /uploads/file/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/file/4.png -------------------------------------------------------------------------------- /uploads/file/ali.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/file/ali.png -------------------------------------------------------------------------------- /uploads/file/checken_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/file/checken_logo.png -------------------------------------------------------------------------------- /uploads/file/login_bg_black.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/file/login_bg_black.jpg -------------------------------------------------------------------------------- /uploads/file/login_bg_light.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/file/login_bg_light.jpg -------------------------------------------------------------------------------- /uploads/file/qq_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/file/qq_logo.png -------------------------------------------------------------------------------- /uploads/file/qq二维码.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/file/qq二维码.jpg -------------------------------------------------------------------------------- /uploads/file/vue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/file/vue.png -------------------------------------------------------------------------------- /uploads/file/wechat二维码.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/file/wechat二维码.jpg -------------------------------------------------------------------------------- /uploads/file/zhangsan/qq_20230803005636.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/file/zhangsan/qq_20230803005636.jpg -------------------------------------------------------------------------------- /uploads/file/zhangsan/qq_20230803005740.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/file/zhangsan/qq_20230803005740.jpg -------------------------------------------------------------------------------- /uploads/file/zhangsan/wechat_20230803005639.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/file/zhangsan/wechat_20230803005639.jpg -------------------------------------------------------------------------------- /uploads/file/zhangsan/wechat_20230803005743.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/file/zhangsan/wechat_20230803005743.jpg -------------------------------------------------------------------------------- /uploads/system/青鸟华光简美黑.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/system/青鸟华光简美黑.ttf -------------------------------------------------------------------------------- /uploads/test/A.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/test/A.png -------------------------------------------------------------------------------- /uploads/test/无.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/test/无.png -------------------------------------------------------------------------------- /uploads/test/柯.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/test/柯.png -------------------------------------------------------------------------------- /uploads/test/西.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fixpng/goblog_server/8b9e5019aad2e2b469581b9093092f95457f3cd3/uploads/test/西.png -------------------------------------------------------------------------------- /utils/desens/enter.go: -------------------------------------------------------------------------------- 1 | package desens 2 | 3 | import "strings" 4 | 5 | // DesensitizationEmail 脱敏邮箱 6 | func DesensitizationEmail(email string) string { 7 | // Congee1997@outlook.com C****@outlook.com 8 | // 897491068@qq.com 8****@qq.com 9 | eList := strings.Split(email, "@") 10 | if len(eList) != 2 { 11 | return "" 12 | } 13 | return eList[0][:1] + "****@" + eList[1] 14 | } 15 | 16 | // DesensitizationTel 脱敏手机号 17 | func DesensitizationTel(tel string) string { 18 | // 18666666371 87666657 19 | // 18******371 87****57 20 | if len(tel) == 11 { 21 | return tel[:3] + "*****" + tel[8:] 22 | } else if len(tel) == 8 { 23 | return tel[:2] + "****" + tel[6:] 24 | } 25 | return "" 26 | } 27 | -------------------------------------------------------------------------------- /utils/get_addr_by_ip.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gin-gonic/gin" 6 | "gvb_server/global" 7 | "net" 8 | ) 9 | 10 | func GetAddrByGin(c *gin.Context) (ip, addr string) { 11 | ip = c.ClientIP() 12 | addr = GetAddr(ip) 13 | return ip, addr 14 | } 15 | 16 | func GetAddr(ip string) string { 17 | parseIP := net.ParseIP(ip) 18 | if IsIntranetIP(parseIP) { 19 | return "内网地址" 20 | } 21 | 22 | record, err := global.AddrDB.City(net.ParseIP(ip)) 23 | if err != nil { 24 | return "错误的地址" 25 | } 26 | var province string 27 | if len(record.Subdivisions) > 0 { 28 | province = record.Subdivisions[0].Names["zh-CN"] 29 | } 30 | 31 | city := record.City.Names["zh-CN"] 32 | return fmt.Sprintf("%s-%s", province, city) 33 | } 34 | 35 | // IsIntranetIP 内网地址判断 36 | func IsIntranetIP(ip net.IP) bool { 37 | if ip.IsLoopback() { 38 | return true 39 | } 40 | 41 | ip4 := ip.To4() 42 | if ip4 == nil { 43 | return false 44 | } 45 | fmt.Println(ip4) 46 | // 192.168 47 | // 172.16 -172.31 48 | // 10 49 | // 169.254 50 | return ip4[0] == 192 && ip4[1] == 168 || 51 | (ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31) || 52 | (ip4[0] == 10) || 53 | (ip4[0] == 169 && ip4[1] == 254) 54 | } 55 | -------------------------------------------------------------------------------- /utils/jwts/enter.go: -------------------------------------------------------------------------------- 1 | package jwts 2 | 3 | import ( 4 | "github.com/dgrijalva/jwt-go/v4" 5 | ) 6 | 7 | // JwtPayLoad jwt中payload数据 8 | type JwtPayLoad struct { 9 | //Username string `json:"username"` // 用户名 10 | NickName string `json:"nick_name"` // 昵称 11 | Role int `json:"role"` // 权限 1 管理员 2 普通用户 3 游客 12 | UserID uint `json:"user_id"` // 用户id 13 | Avatar string `json:"avatar"` 14 | } 15 | 16 | var MySecret []byte 17 | 18 | type CustomClaims struct { 19 | JwtPayLoad 20 | jwt.StandardClaims 21 | } 22 | -------------------------------------------------------------------------------- /utils/jwts/gen_token.go: -------------------------------------------------------------------------------- 1 | package jwts 2 | 3 | import ( 4 | "github.com/dgrijalva/jwt-go/v4" 5 | "gvb_server/global" 6 | "time" 7 | ) 8 | 9 | // GenToken 创建 Token 10 | func GenToken(user JwtPayLoad) (string, error) { 11 | 12 | MySecret = []byte(global.Config.Jwt.Secret) 13 | 14 | claim := CustomClaims{ 15 | user, 16 | jwt.StandardClaims{ 17 | ExpiresAt: jwt.At(time.Now().Add(time.Hour * time.Duration(global.Config.Jwt.Expires))), // 默认2小时过期 18 | Issuer: global.Config.Jwt.Issuer, // 签发人 19 | }, 20 | } 21 | 22 | token := jwt.NewWithClaims(jwt.SigningMethodHS256, claim) 23 | return token.SignedString(MySecret) 24 | } 25 | -------------------------------------------------------------------------------- /utils/jwts/parse_token.go: -------------------------------------------------------------------------------- 1 | package jwts 2 | 3 | import ( 4 | "errors" 5 | "github.com/dgrijalva/jwt-go/v4" 6 | "gvb_server/global" 7 | ) 8 | 9 | // ParseToken 解析 token 10 | func ParseToken(tokenStr string) (*CustomClaims, error) { 11 | MySecret = []byte(global.Config.Jwt.Secret) 12 | token, err := jwt.ParseWithClaims(tokenStr, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) { 13 | return MySecret, nil 14 | }) 15 | if err != nil { 16 | //logrus.Error(fmt.Sprintf("token parse err: %s", err.Error())) 17 | return nil, err 18 | } 19 | if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid { 20 | return claims, nil 21 | } 22 | 23 | return nil, errors.New("invalid token") 24 | } 25 | -------------------------------------------------------------------------------- /utils/md5.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "crypto/md5" 5 | "fmt" 6 | ) 7 | 8 | func MD5(data []byte) string { 9 | has := md5.Sum(data) //切片 10 | md5str := fmt.Sprintf("%x", has) //将[]byte转成16进制 11 | return md5str 12 | } 13 | -------------------------------------------------------------------------------- /utils/net.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "github.com/sirupsen/logrus" 5 | "log" 6 | "net" 7 | ) 8 | 9 | func GetIPList() (ipList []string) { 10 | interfaces, err := net.Interfaces() 11 | if err != nil { 12 | log.Fatal(err) 13 | } 14 | 15 | for _, i2 := range interfaces { 16 | addrs, err := i2.Addrs() 17 | if err != nil { 18 | logrus.Error(err) 19 | continue 20 | } 21 | for _, addr := range addrs { 22 | ipNet, ok := addr.(*net.IPNet) 23 | if !ok { 24 | continue 25 | } 26 | ip4 := ipNet.IP.To4() 27 | if ip4 == nil { 28 | continue 29 | } 30 | ipList = append(ipList, ip4.String()) 31 | } 32 | } 33 | return 34 | } 35 | -------------------------------------------------------------------------------- /utils/print_system.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import "gvb_server/global" 4 | 5 | func PrintSystem() { 6 | ip := global.Config.System.Host 7 | port := global.Config.System.Port 8 | if ip == "0.0.0.0" { 9 | ipList := GetIPList() 10 | for _, i := range ipList { 11 | global.Log.Infof("gvb_server 运行在:http://%s:%d/api", i, port) 12 | global.Log.Infof("gvb_server api文档 运行在:http://%s:%d/swagger/index.html#", i, port) 13 | } 14 | } else { 15 | global.Log.Infof("gvb_server 运行在:http://%s:%d/api", ip, port) 16 | global.Log.Infof("gvb_server api文档 运行在:http://%s:%d/swagger/index.html#", ip, port) 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /utils/pwd/pwd.go: -------------------------------------------------------------------------------- 1 | package pwd 2 | 3 | import ( 4 | "golang.org/x/crypto/bcrypt" 5 | "log" 6 | ) 7 | 8 | // HashPwd hash加密密码 9 | func HashPwd(pwd string) string { 10 | hash, err := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.MinCost) 11 | if err != nil { 12 | log.Println(err) 13 | } 14 | return string(hash) 15 | } 16 | 17 | // CheckPwd 验证密码 hash之后的密码 输入的密码 18 | func CheckPwd(hashPwd string, pwd string) bool { 19 | byteHash := []byte(hashPwd) 20 | 21 | err := bcrypt.CompareHashAndPassword(byteHash, []byte(pwd)) 22 | if err != nil { 23 | log.Println(err) 24 | return false 25 | } 26 | return true 27 | } 28 | -------------------------------------------------------------------------------- /utils/pwd/pwd_test.go: -------------------------------------------------------------------------------- 1 | package pwd 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestHashPwd(t *testing.T) { 9 | fmt.Println(HashPwd("1234")) 10 | } 11 | 12 | func TestCheckPwd(t *testing.T) { 13 | fmt.Println(CheckPwd("$2a$04$JAqrLh3RnDIQQF6fjiRpeua6GT3oIchzFCKadJhCtnaZsPr1WLgfe", "1234")) 14 | } 15 | -------------------------------------------------------------------------------- /utils/random/code.go: -------------------------------------------------------------------------------- 1 | package random 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | var stringCode = "abcdefg" 10 | 11 | func Code(length int) string { 12 | rand.Seed(time.Now().UnixNano()) 13 | code := fmt.Sprintf("%v", rand.Intn(9999999)) 14 | return code[0:length] 15 | } 16 | -------------------------------------------------------------------------------- /utils/random/string.go: -------------------------------------------------------------------------------- 1 | package random 2 | 3 | import ( 4 | "math/rand" 5 | "time" 6 | ) 7 | 8 | var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") 9 | 10 | func RandString(n int) string { 11 | rand.Seed(time.Now().UnixNano()) 12 | b := make([]rune, n) 13 | for i := range b { 14 | b[i] = letters[rand.Intn(len(letters))] 15 | } 16 | return string(b) 17 | } 18 | -------------------------------------------------------------------------------- /utils/requests/post.go: -------------------------------------------------------------------------------- 1 | package requests 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/sirupsen/logrus" 6 | "net/http" 7 | "strconv" 8 | "strings" 9 | "time" 10 | ) 11 | 12 | func Post(url string, data any, headers map[string]interface{}, timeout time.Duration) (resp *http.Response, err error) { 13 | reqParam, _ := json.Marshal(data) 14 | reqBody := strings.NewReader(string(reqParam)) 15 | httpReq, err := http.NewRequest("POST", url, reqBody) 16 | if err != nil { 17 | logrus.Error(err) 18 | return 19 | } 20 | httpReq.Header.Add("Content-Type", "application/json") 21 | for key, val := range headers { 22 | switch v := val.(type) { 23 | case string: 24 | httpReq.Header.Add(key, v) 25 | case int: 26 | httpReq.Header.Add(key, strconv.Itoa(v)) 27 | } 28 | } 29 | client := http.Client{ 30 | Timeout: timeout, 31 | } 32 | // DO: HTTP请求 33 | httpResp, err := client.Do(httpReq) 34 | return httpResp, err 35 | } 36 | -------------------------------------------------------------------------------- /utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | // InList 判断key是否存在于列表中 4 | func InList(key string, list []string) bool { 5 | for _, s := range list { 6 | if key == s { 7 | return true 8 | } 9 | } 10 | return false 11 | } 12 | 13 | // Reverse 切片反转 14 | func Reverse[T any](slice []T) { 15 | for i, j := 0, len(slice)-1; i < j; i, j = i+1, j-1 { 16 | slice[i], slice[j] = slice[j], slice[i] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /utils/valid.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "github.com/go-playground/validator/v10" 5 | "reflect" 6 | ) 7 | 8 | // GetValidMsg 返回结构体中的msg参数 9 | func GetValidMsg(err error, obj any) string { 10 | // 使用的时候,需要传obj的指针 11 | getObj := reflect.TypeOf(obj) 12 | // 将err接口断言为具体类型 13 | if errs, ok := err.(validator.ValidationErrors); ok { 14 | // 断言成功 15 | for _, e := range errs { 16 | // 循环每一个错误信息 17 | // 根据报错字段名,获取结构体的具体字段 18 | if f, exits := getObj.Elem().FieldByName(e.Field()); exits { 19 | msg := f.Tag.Get("msg") 20 | return msg 21 | } 22 | } 23 | } 24 | 25 | return err.Error() 26 | } 27 | --------------------------------------------------------------------------------