@@ -0,0 +1,32 @@
|
||||
|
||||
GOPATH:=$(shell go env GOPATH)
|
||||
|
||||
GIT_BRANCH:=$(shell git symbolic-ref --short -q HEAD)
|
||||
GIT_VERSION:=$(shell git log --pretty=oneline -p -1 | head -n 1 | awk '{print $$1}')
|
||||
BUILD_DATE:=$(shell date '+%Y-%m-%d %H:%M:%S %z')
|
||||
BUILD_IP:=$(shell ifconfig | grep inet | grep -v grep | grep -v "inet6" | grep -v "127.0.0.1" | awk '{print $$2}')
|
||||
VERSON_PATH:=miao/pub/srvversion
|
||||
|
||||
WEB_BUILD_FLAG:=-ldflags "-X '$(VERSON_PATH).GIT_BRANCH=$(GIT_BRANCH)' -X '$(VERSON_PATH).GIT_VERSION=$(GIT_VERSION)' -X '$(VERSON_PATH).BUILD_DATE=$(BUILD_DATE)' -X '$(VERSON_PATH).BUILD_IP=$(BUILD_IP)'"
|
||||
|
||||
|
||||
.PHONY: test deploy
|
||||
deploy:
|
||||
go clean
|
||||
rm -f web_91dj_web
|
||||
env GOOS=linux GOARCH=amd64 go build $(WEB_BUILD_FLAG) -o web_91dj_web
|
||||
tar czf web_91dj_web.tar.gz web_91dj_web
|
||||
rm -f web_91dj_web
|
||||
test:
|
||||
go clean
|
||||
rm -f web_91dj_web
|
||||
GOOS=linux GOARCH=amd64 go build $(WEB_BUILD_FLAG) -o web_91dj_web
|
||||
tar czf web_91dj_web.tar.gz web_91dj_web docs
|
||||
rm -f web_91dj_web
|
||||
|
||||
localtest:
|
||||
@echo "test, GOPATH=$(GOPATH)"
|
||||
go build $(WEB_BUILD_FLAG) -o web
|
||||
|
||||
swagger:
|
||||
swag init --parseDependency --parseDepth 4
|
||||
@@ -0,0 +1,76 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"time"
|
||||
"videoweb/pub/common/response"
|
||||
"videoweb/pub/pubdef"
|
||||
)
|
||||
|
||||
// ContactUsListReq web端联系我们分页列表请求
|
||||
type ContactUsListReq struct {
|
||||
// 页码
|
||||
pubdef.Page
|
||||
// 用户ID
|
||||
UserId *int64 `form:"userId" json:"userId"`
|
||||
// 邮箱
|
||||
Email string `form:"email" json:"email"`
|
||||
// 问题类型,1-订单问题、2-账号问题、3-功能问题、4-体验问题、5-其他
|
||||
Type *int32 `form:"type" json:"type"`
|
||||
// 处理状态,0-待处理、1-已处理
|
||||
Status *int32 `form:"status" json:"status"`
|
||||
// 创建开始时间,格式:2026-06-08 00:00:00
|
||||
CreateStartTime string `form:"createStartTime" json:"createStartTime"`
|
||||
// 创建结束时间,格式:2026-06-09 00:00:00
|
||||
CreateEndTime string `form:"createEndTime" json:"createEndTime"`
|
||||
}
|
||||
|
||||
// ContactUsListResp web端联系我们分页列表响应
|
||||
type ContactUsListResp struct {
|
||||
// ID
|
||||
Id int64 `json:"id"`
|
||||
// 用户ID
|
||||
UserId int64 `json:"userId"`
|
||||
// 用户名称
|
||||
UserName string `json:"userName"`
|
||||
// 邮箱
|
||||
Email string `json:"email"`
|
||||
// 问题类型,1-订单问题、2-账号问题、3-功能问题、4-体验问题、5-其他
|
||||
Type int32 `json:"type"`
|
||||
// 标题
|
||||
Title string `json:"title"`
|
||||
// 内容
|
||||
Content string `json:"content"`
|
||||
// 附件地址
|
||||
Attachments []string `json:"attachments"`
|
||||
// 处理状态,0-待处理、1-已处理
|
||||
Status int32 `json:"status"`
|
||||
// 处理备注
|
||||
Remark string `json:"remark"`
|
||||
// 创建时间
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
// 更新时间
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// ContactUsListPageResp web端联系我们分页列表响应
|
||||
type ContactUsListPageResp struct {
|
||||
response.BasePageResp
|
||||
}
|
||||
|
||||
// ContactUsHandleReq web端批量处理联系我们请求
|
||||
type ContactUsHandleReq struct {
|
||||
// 联系我们ID集合
|
||||
Ids []int64 `json:"ids" binding:"required"`
|
||||
// 处理状态,0-待处理、1-已处理
|
||||
Status int32 `json:"status" binding:"required"`
|
||||
// 处理备注
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
// ContactUsHandleResp web端批量处理联系我们响应
|
||||
type ContactUsHandleResp struct {
|
||||
// 命中数量
|
||||
MatchedCount int64 `json:"matchedCount"`
|
||||
// 修改数量
|
||||
ModifiedCount int64 `json:"modifiedCount"`
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"time"
|
||||
"videoweb/pub/common/response"
|
||||
"videoweb/pub/pubdef"
|
||||
)
|
||||
|
||||
// FeedbackListReq web端意见反馈分页列表请求
|
||||
type FeedbackListReq struct {
|
||||
// 页码
|
||||
pubdef.Page
|
||||
// 用户ID
|
||||
UserId *int64 `form:"userId" json:"userId"`
|
||||
// 问题类型,1-功能建议、2-Bug反馈、3-体验问题、4-账号问题、5-其他
|
||||
Type *int32 `form:"type" json:"type"`
|
||||
// 处理状态,0-待处理、1-已处理
|
||||
Status *int32 `form:"status" json:"status"`
|
||||
// 创建开始时间,格式:2026-06-08 00:00:00
|
||||
CreateStartTime string `form:"createStartTime" json:"createStartTime"`
|
||||
// 创建结束时间,格式:2026-06-09 00:00:00
|
||||
CreateEndTime string `form:"createEndTime" json:"createEndTime"`
|
||||
}
|
||||
|
||||
// FeedbackListResp web端意见反馈分页列表响应
|
||||
type FeedbackListResp struct {
|
||||
// ID
|
||||
Id int64 `json:"id"`
|
||||
// 用户ID
|
||||
UserId int64 `json:"userId"`
|
||||
// 用户名称
|
||||
UserName string `json:"userName"`
|
||||
// 问题类型,1-功能建议、2-Bug反馈、3-体验问题、4-账号问题、5-其他
|
||||
Type int32 `json:"type"`
|
||||
// 描述内容
|
||||
Content string `json:"content"`
|
||||
// 问题截图
|
||||
Screenshots []string `json:"screenshots"`
|
||||
// 联系方式
|
||||
Contact string `json:"contact"`
|
||||
// 处理状态,0-待处理、1-已处理
|
||||
Status int32 `json:"status"`
|
||||
// 处理备注
|
||||
Remark string `json:"remark"`
|
||||
// 创建时间
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
// 更新时间
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// FeedbackListPageResp web端意见反馈分页列表响应
|
||||
type FeedbackListPageResp struct {
|
||||
response.BasePageResp
|
||||
}
|
||||
|
||||
// FeedbackHandleReq web端批量处理意见反馈请求
|
||||
type FeedbackHandleReq struct {
|
||||
// 意见反馈ID集合
|
||||
Ids []int64 `json:"ids" binding:"required"`
|
||||
// 处理状态,0-待处理、1-已处理
|
||||
Status int32 `json:"status" binding:"required"`
|
||||
// 处理备注
|
||||
Remark string `json:"remark"`
|
||||
}
|
||||
|
||||
// FeedbackHandleResp web端批量处理意见反馈响应
|
||||
type FeedbackHandleResp struct {
|
||||
// 命中数量
|
||||
MatchedCount int64 `json:"matchedCount"`
|
||||
// 修改数量
|
||||
ModifiedCount int64 `json:"modifiedCount"`
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"time"
|
||||
"videoweb/pub/common/response"
|
||||
)
|
||||
|
||||
// HomeBannerListReq web端首页 banner 分页列表请求
|
||||
type HomeBannerListReq struct {
|
||||
PageNum int64 `form:"pageNum" json:"pageNum"` // 页码,默认1
|
||||
PageSize int64 `form:"pageSize" json:"pageSize"` // 每页数量,默认10,最大100
|
||||
Id *int64 `form:"id" json:"id"` // 首页 banner ID
|
||||
Name string `form:"name" json:"name"` // 名称,支持模糊查询
|
||||
Status *bool `form:"status" json:"status"` // 状态 true-启用 false-停用
|
||||
}
|
||||
|
||||
// HomeBannerListResp web端首页 banner 列表项
|
||||
type HomeBannerListResp struct {
|
||||
Id int64 `json:"id"` // ID
|
||||
Name string `json:"name"` // 名称
|
||||
Image string `json:"image"` // 图片
|
||||
VerticalImage string `json:"verticalImage"` // 竖版图片
|
||||
Url string `json:"url"` // URL
|
||||
Rank int64 `json:"rank"` // 排序
|
||||
Status bool `json:"status"` // 状态 true-启用 false-停用
|
||||
CreatedById int64 `json:"createdById"` // 创建人ID
|
||||
CreatedByName string `json:"createdByName"` // 创建人名称
|
||||
UpdatedByName string `json:"updatedByName"` // 修改人名称
|
||||
CreatedAt time.Time `json:"createdAt"` // 创建时间
|
||||
UpdatedAt time.Time `json:"updatedAt"` // 修改时间
|
||||
}
|
||||
|
||||
// HomeBannerListPageResp web端首页 banner 分页列表响应
|
||||
type HomeBannerListPageResp struct {
|
||||
response.BasePageResp
|
||||
}
|
||||
|
||||
// HomeBannerAddReq web端新增首页 banner 请求
|
||||
type HomeBannerAddReq struct {
|
||||
Name string `json:"name" binding:"required"` // 名称
|
||||
Image string `json:"image" binding:"required"` // 图片
|
||||
VerticalImage string `json:"verticalImage"` // 竖版图片
|
||||
Url string `json:"url"` // URL
|
||||
Rank int64 `json:"rank"` // 排序
|
||||
Status *bool `json:"status" binding:"required"` // 状态 true-启用 false-停用
|
||||
}
|
||||
|
||||
// HomeBannerAddResp web端新增首页 banner 响应
|
||||
type HomeBannerAddResp struct {
|
||||
Id int64 `json:"id"` // ID
|
||||
}
|
||||
|
||||
// HomeBannerUpdateReq web端更新首页 banner 请求
|
||||
type HomeBannerUpdateReq struct {
|
||||
Id int64 `json:"id" binding:"required"` // ID
|
||||
Name *string `json:"name"` // 名称
|
||||
Image *string `json:"image"` // 图片
|
||||
VerticalImage *string `json:"verticalImage"` // 竖版图片
|
||||
Url *string `json:"url"` // URL
|
||||
Rank *int64 `json:"rank"` // 排序
|
||||
Status *bool `json:"status"` // 状态 true-启用 false-停用
|
||||
}
|
||||
|
||||
// HomeBannerDelReq web端删除首页 banner 请求
|
||||
type HomeBannerDelReq struct {
|
||||
Id int64 `json:"id" binding:"required"` // ID
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"time"
|
||||
"videoweb/pub/common/response"
|
||||
"videoweb/pub/pubdef"
|
||||
)
|
||||
|
||||
// HomeConfigListReq web端首页配置分页列表请求
|
||||
type HomeConfigListReq struct {
|
||||
PageNum int64 `form:"pageNum" json:"pageNum"` // 页码,默认1
|
||||
PageSize int64 `form:"pageSize" json:"pageSize"` // 每页数量,默认10,最大100
|
||||
Id *int64 `form:"id" json:"id"` // 首页配置ID
|
||||
Name string `form:"name" json:"name"` // 名称,支持模糊查询
|
||||
Slug string `form:"slug" json:"slug"` // slug,精确匹配
|
||||
Type *int32 `form:"type" json:"type"` // 类型 1-短剧 3-题材
|
||||
SortType *int32 `form:"sortType" json:"sortType"` // 短剧模块排序 1-推荐 2-热播 3-最近更新 4-上架时间 5-分类,题材模块预览按专题详情默认排序
|
||||
Status *bool `form:"status" json:"status"` // 上下架状态 true-上架 false-下架
|
||||
}
|
||||
|
||||
// HomeConfigListResp web端首页配置列表项
|
||||
type HomeConfigListResp struct {
|
||||
Id int64 `json:"id"` // ID
|
||||
Name string `json:"name"` // 名称
|
||||
Slug string `json:"slug"` // slug
|
||||
Desc string `json:"desc"` // 描述
|
||||
Keyword []string `json:"keyword"` // 页面关键字
|
||||
Label string `json:"label"`
|
||||
Style string `json:"style"`
|
||||
CardBackgroundImage string `json:"cardBackgroundImage"`
|
||||
TopicIds []int64 `json:"topicIds"`
|
||||
CategoryId int64 `json:"categoryId"`
|
||||
RecommendType int64 `json:"recommendType"`
|
||||
Type int32 `json:"type"` // 类型 1-短剧 3-题材
|
||||
Rank int64 `json:"rank"` // 排序,越大越靠前
|
||||
Limit int64 `json:"limit"` // 首页展示数量,0 时短剧默认12条、题材默认8个
|
||||
SortType int32 `json:"sortType"` // 短剧模块排序 1-推荐 2-热播 3-最近更新 4-上架时间 5-分类,题材模块预览按专题详情默认排序
|
||||
Status bool `json:"status"` // 上下架状态 true-上架 false-下架
|
||||
SeoInfo pubdef.SeoValue `json:"seoInfo"` // Seo相关信息
|
||||
CreatedAt time.Time `json:"createdAt"` // 创建时间
|
||||
UpdatedAt time.Time `json:"updatedAt"` // 修改时间
|
||||
}
|
||||
|
||||
// HomeConfigListPageResp web端首页配置分页列表响应
|
||||
type HomeConfigListPageResp struct {
|
||||
response.BasePageResp
|
||||
}
|
||||
|
||||
// HomeConfigAddReq web端新增首页配置请求
|
||||
type HomeConfigAddReq struct {
|
||||
Name string `json:"name" binding:"required"` // 名称
|
||||
Slug string `json:"slug"` // slug,不传则按 SEO 关键词或名称自动生成
|
||||
Desc string `json:"desc"` // 描述
|
||||
Keyword []string `json:"keyword"` // 页面关键字,可不传
|
||||
Label string `json:"label"`
|
||||
Style string `json:"style"`
|
||||
CardBackgroundImage string `json:"cardBackgroundImage"`
|
||||
TopicIds []int64 `json:"topicIds"`
|
||||
CategoryId int64 `json:"categoryId"`
|
||||
RecommendType int64 `json:"recommendType"`
|
||||
Type int32 `json:"type" binding:"required"` // 类型 1-短剧 3-题材
|
||||
Rank int64 `json:"rank"` // 排序,越大越靠前
|
||||
Limit int64 `json:"limit"` // 首页展示数量,0 时短剧默认12条、题材默认8个
|
||||
SortType int32 `json:"sortType" binding:"required"` // 短剧模块排序 1-推荐 2-热播 3-最近更新 4-上架时间 5-分类,题材模块预览按专题详情默认排序
|
||||
Status *bool `json:"status" binding:"required"` // 上下架状态 true-上架 false-下架
|
||||
SeoInfo pubdef.SeoValue `json:"seoInfo"` // Seo相关信息
|
||||
}
|
||||
|
||||
// HomeConfigAddResp web端新增首页配置响应
|
||||
type HomeConfigAddResp struct {
|
||||
Id int64 `json:"id"` // ID
|
||||
}
|
||||
|
||||
// HomeConfigUpdateReq web端更新首页配置请求
|
||||
type HomeConfigUpdateReq struct {
|
||||
Id int64 `json:"id" binding:"required"` // ID
|
||||
Name *string `json:"name"` // 名称
|
||||
Slug *string `json:"slug"` // slug,历史数据为空时更新会自动生成
|
||||
Desc *string `json:"desc"` // 描述
|
||||
Keyword *[]string `json:"keyword"` // 不传保持原值,传空数组清空
|
||||
Label *string `json:"label"`
|
||||
Style *string `json:"style"`
|
||||
CardBackgroundImage *string `json:"cardBackgroundImage"`
|
||||
TopicIds *[]int64 `json:"topicIds"`
|
||||
CategoryId *int64 `json:"categoryId"`
|
||||
RecommendType *int64 `json:"recommendType"`
|
||||
Type *int32 `json:"type"` // 类型 1-短剧 3-题材
|
||||
Rank *int64 `json:"rank"` // 排序,越大越靠前
|
||||
Limit *int64 `json:"limit"` // 首页展示数量,0 时短剧默认12条、题材默认8个
|
||||
SortType *int32 `json:"sortType"` // 短剧模块排序 1-推荐 2-热播 3-最近更新 4-上架时间 5-分类,题材模块预览按专题详情默认排序
|
||||
Status *bool `json:"status"` // 上下架状态 true-上架 false-下架
|
||||
SeoInfo *pubdef.SeoValue `json:"seoInfo"` // Seo相关信息
|
||||
}
|
||||
|
||||
// HomeConfigDelReq web端删除首页配置请求
|
||||
type HomeConfigDelReq struct {
|
||||
Id int64 `json:"id" binding:"required"` // ID
|
||||
}
|
||||
|
||||
// HomeTopicOptionsReq 首页短剧题材选项分页请求
|
||||
type HomeTopicOptionsReq struct {
|
||||
PageNum int64 `form:"pageNum"` // 页码,默认 1
|
||||
PageSize int64 `form:"pageSize"` // 每页数量,默认 10,最大 100
|
||||
ConfigId int64 `form:"configId"` // 编辑时传当前首页配置 ID;不传则只查询可选题材
|
||||
}
|
||||
|
||||
// HomeTopicOption 首页短剧题材选项
|
||||
type HomeTopicOption struct {
|
||||
Id int64 `json:"id"` // 题材 ID
|
||||
Name string `json:"name"` // 题材名称
|
||||
Status bool `json:"status"` // 是否上架;已选题材下架后仍可回显
|
||||
}
|
||||
|
||||
// HomeTopicOptionsResp 首页短剧题材选项分页响应
|
||||
type HomeTopicOptionsResp struct {
|
||||
List []*HomeTopicOption `json:"list"` // 当前页可选题材,排除其他启用模块占用的题材
|
||||
SelectedList []*HomeTopicOption `json:"selectedList"` // 当前配置已选题材,不受分页限制
|
||||
TotalCount int64 `json:"totalCount"` // 可选题材总数
|
||||
PageNum int64 `json:"pageNum"` // 当前页码
|
||||
PageSize int64 `json:"pageSize"` // 每页数量
|
||||
}
|
||||
@@ -0,0 +1,708 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"time"
|
||||
"videoweb/pub/common/response"
|
||||
"videoweb/pub/models/playletchaptermod"
|
||||
"videoweb/pub/models/playletmod"
|
||||
"videoweb/pub/pubdef"
|
||||
)
|
||||
|
||||
// PlayletResourceListReq web端短剧媒资列表请求
|
||||
type PlayletResourceListReq struct {
|
||||
Title *string `form:"title" json:"title"` // 标题
|
||||
Tag *string `form:"tag" json:"tag"` // 标签
|
||||
MediaType *int `form:"media_type" json:"media_type"` // 媒体类型 1-动漫 2-漫画 4-漫画短剧 5-短剧 6-普通短剧
|
||||
SyncType *int `form:"sync_type" json:"sync_type"` // 同步类型 1-全量同步 2-增量同步
|
||||
IsAdd *bool `form:"isAdd" json:"isAdd,omitempty"` // 是否已加入后台数据:true只查已加入,false只查未加入,不传查全部
|
||||
PageNumber int `form:"pageNumber" json:"pageNumber"` // 页码
|
||||
PageSize int `form:"pageSize" json:"pageSize"` // 个数
|
||||
}
|
||||
|
||||
// PlayletResourceJHListReq web端嘉华短剧媒资列表请求
|
||||
type PlayletResourceJHListReq struct {
|
||||
Title *string `form:"title"` // 标题
|
||||
Tag *string `form:"tag"` // 标签
|
||||
SyncType *int `form:"sync_type"` // 同步类型 1-全量同步 2-增量同步
|
||||
IsAdd *bool `form:"isAdd" json:"isAdd,omitempty"` // 是否已入库:true只查已入库,false只查未入库,不传查全部
|
||||
PageNumber int `form:"pageNumber"` // 页码
|
||||
PageSize int `form:"pageSize"` // 个数
|
||||
}
|
||||
|
||||
// PlayletResourceMediaActor web端短剧媒资演员
|
||||
type PlayletResourceMediaActor struct {
|
||||
Name string `json:"name"` // 名称
|
||||
Avatar string `json:"avatar"` // 头像
|
||||
Gender int `json:"gender"` // 性别
|
||||
}
|
||||
|
||||
// PlayletResourceListItem web端短剧媒资列表项
|
||||
type PlayletResourceListItem struct {
|
||||
ID uint `json:"id"`
|
||||
VloggerId uint `json:"vlogger_id"`
|
||||
Title string `json:"title"` // 标题
|
||||
SaleCoin uint `json:"sale_coin"` // 整部售价
|
||||
HorizontalCover string `json:"horizontal_cover"` // 横版封面
|
||||
VerticalCover string `json:"vertical_cover"` // 竖版封面
|
||||
Summary string `json:"summary"` // 简介
|
||||
TotalEpisode uint `json:"total_episode"` // 总集数
|
||||
UpdateStatus int `json:"update_status"` // 更新状态 1-连载中 2-已完结
|
||||
MediaType int `json:"media_type"` // 媒体类型
|
||||
Anchor string `json:"anchor"` // 作者
|
||||
TagsText string `json:"tags_text"` // 标签文字
|
||||
DataVersion int8 `json:"data_version"` // 数据版本
|
||||
TerminalCdo string `json:"terminal_cdo"` // 上传者
|
||||
CreateTime int64 `json:"create_time"` // 创建时间
|
||||
UpdateTime int64 `json:"update_time"` // 修改时间
|
||||
IsAdd bool `json:"isAdd"` // 是否已加入后台数据
|
||||
}
|
||||
|
||||
// PlayletResourceJHListItem web端嘉华短剧媒资列表项
|
||||
type PlayletResourceJHListItem struct {
|
||||
ID uint `json:"id"`
|
||||
VloggerId uint `json:"vlogger_id"`
|
||||
Title string `json:"title"` // 标题
|
||||
SaleCoin uint `json:"sale_coin"` // 整部售价
|
||||
HorizontalCover string `json:"horizontal_cover"` // 横版封面
|
||||
VerticalCover string `json:"vertical_cover"` // 竖版封面
|
||||
HorizontalCoverAlt string `json:"horizontalCover"` // 兼容驼峰
|
||||
VerticalCoverAlt string `json:"verticalCover"` // 兼容驼峰
|
||||
Summary string `json:"summary"` // 简介
|
||||
TotalEpisode uint `json:"total_episode"` // 总集数
|
||||
UpdateStatus int `json:"update_status"` // 更新状态
|
||||
MediaType int `json:"media_type"` // 媒体类型
|
||||
Anchor string `json:"anchor"` // 作者
|
||||
Actors []PlayletResourceMediaActor `json:"actors"` // 演员集合
|
||||
TagsText string `json:"tags_text"` // 标签文字
|
||||
DataVersion int8 `json:"data_version"` // 数据版本
|
||||
TerminalCdo string `json:"terminal_cdo"` // 上传者
|
||||
CreateTime int64 `json:"create_time"` // 创建时间
|
||||
UpdateTime int64 `json:"update_time"` // 更新时间
|
||||
IsAdd bool `json:"isAdd"` // 是否已入库
|
||||
}
|
||||
|
||||
// PlayletResourceListResp web端短剧媒资列表响应
|
||||
type PlayletResourceListResp struct {
|
||||
List []*PlayletResourceListItem `json:"list"`
|
||||
Total uint `json:"total"`
|
||||
}
|
||||
|
||||
// PlayletResourceJHListResp web端嘉华短剧媒资列表响应
|
||||
type PlayletResourceJHListResp struct {
|
||||
List []*PlayletResourceJHListItem `json:"list"`
|
||||
Total uint `json:"total"`
|
||||
}
|
||||
|
||||
// PlayletResourceUseReq web端短剧媒资入库请求
|
||||
type PlayletResourceUseReq struct {
|
||||
Ids []uint `json:"ids"` // 媒资中心资源ID集合-多个用逗号隔开,请求示例[28830,28829,28828,28827,28826,28825]
|
||||
}
|
||||
|
||||
// PlayletResourceChapterListReq web端短剧媒资剧集列表请求
|
||||
type PlayletResourceChapterListReq struct {
|
||||
Id uint `form:"id" json:"id" binding:"required"` // 媒资中心资源ID
|
||||
}
|
||||
|
||||
// PlayletResourceChapterItem web端短剧媒资剧集项
|
||||
type PlayletResourceChapterItem struct {
|
||||
Id uint `json:"id"` // 媒资内容ID
|
||||
EpisodeNumber int `json:"episodeNumber"` // 第几集
|
||||
Title string `json:"title"` // 章节名
|
||||
Cover string `json:"cover"` // 封面
|
||||
VideoUrl string `json:"videoUrl"` // 播放地址
|
||||
Height uint `json:"height"` // 高
|
||||
Width uint `json:"width"` // 宽
|
||||
MediaSize uint `json:"mediaSize"` // 资源大小
|
||||
PlayTime uint `json:"playTime"` // 播放时长(秒)
|
||||
SaleCoin uint `json:"saleCoin"` // 单集售价
|
||||
HashId string `json:"hashId"` // 资源hash
|
||||
CreateTime int64 `json:"createTime"` // 创建时间
|
||||
UpdateTime int64 `json:"updateTime"` // 更新时间
|
||||
}
|
||||
|
||||
// PlayletResourceChapterListResp web端短剧媒资剧集列表响应
|
||||
type PlayletResourceChapterListResp struct {
|
||||
MediaId uint `json:"mediaId"` // 媒资中心资源ID
|
||||
Title string `json:"title"` // 短剧标题
|
||||
List []*PlayletResourceChapterItem `json:"list"` // 剧集列表
|
||||
Total int `json:"total"` // 剧集数量
|
||||
}
|
||||
|
||||
// PlayletResourceUseSuccess web端短剧媒资入库成功项
|
||||
type PlayletResourceUseSuccess struct {
|
||||
MediaId uint `json:"mediaId"`
|
||||
PlayletId int64 `json:"playletId"`
|
||||
}
|
||||
|
||||
// PlayletResourceUseFailed web端短剧媒资入库失败项
|
||||
type PlayletResourceUseFailed struct {
|
||||
MediaId uint `json:"mediaId"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
// PlayletResourceUseResp web端短剧媒资入库响应
|
||||
type PlayletResourceUseResp struct {
|
||||
Success []*PlayletResourceUseSuccess `json:"success"`
|
||||
Failed []*PlayletResourceUseFailed `json:"failed"`
|
||||
}
|
||||
|
||||
// PlayletListSortType web端短剧列表排序类型,均为降序
|
||||
type PlayletListSortType int
|
||||
|
||||
const (
|
||||
PlayletListSortCreatedAt PlayletListSortType = 0 // 创建时间(默认)
|
||||
PlayletListSortRecommendRank PlayletListSortType = 1 // 推荐排序
|
||||
PlayletListSortUpdatedAt PlayletListSortType = 2 // 修改时间
|
||||
PlayletListSortCountLike PlayletListSortType = 3 // 点赞数
|
||||
PlayletListSortCountBrowse PlayletListSortType = 4 // 浏览数
|
||||
PlayletListSortCountCollect PlayletListSortType = 5 // 收藏数
|
||||
PlayletListSortOnlineAt PlayletListSortType = 6 // 上架时间
|
||||
)
|
||||
|
||||
// PlayletListReq web端短剧分页列表请求
|
||||
type PlayletListReq struct {
|
||||
pubdef.Page
|
||||
Id *int64 `form:"id" json:"id"`
|
||||
ThemeId *int64 `form:"themeId" json:"themeId"` // 题材id
|
||||
CategoryId *int64 `form:"categoryId" json:"categoryId"` // 分类ID
|
||||
TagId *int64 `form:"tagId" json:"tagId"` // 标签ID
|
||||
ContentType *playletmod.ContentType `form:"contentType" json:"contentType"` // 0短剧 1普通短剧/影集 2漫画短剧 3动漫 4漫画
|
||||
OperateType *playletmod.OperateType `form:"operateType" json:"operateType"` // 运营类型 1-短剧 2-漫剧
|
||||
PayType *playletmod.PayType `form:"payType" json:"payType"` // 支付方式 0-免费 1-金币 2-VIP
|
||||
Status *playletmod.Status `form:"status" json:"status"` // 上架状态(0-下架 1-上架)
|
||||
IsFeatured *bool `form:"isFeatured" json:"isFeatured"` // 是否爆剧(true-是,false-否)
|
||||
IsOriginal *bool `form:"isOriginal" json:"isOriginal"` // 是否原创:true只查原创,false只查非原创,不传查全部
|
||||
ShowOriginal *bool `form:"showOriginal" json:"showOriginal"` // 页面是否展示原创标识,不传查全部
|
||||
IsRecommend *bool `form:"isRecommend" json:"isRecommend"` // 是否原创(推荐)
|
||||
ShowOnBanner *bool `form:"showOnBanner" json:"showOnBanner"`
|
||||
Title string `form:"title" json:"title"`
|
||||
Slug string `form:"slug" json:"slug"` // slug,精确匹配
|
||||
OperatorName string `form:"operatorName" json:"operatorName"` // 最后操作人名称
|
||||
MediaSource *string `form:"mediaSource" json:"mediaSource"` // 媒资来源:不传查全部;空字符串查普通媒资;hg 查黄果媒资
|
||||
SortType PlayletListSortType `form:"sortType" json:"sortType"` // 排序:0创建时间(默认) 1推荐排序(按分类查询时为该分类排序) 2修改时间 3点赞数 4浏览数 5收藏数 6上架时间,均为降序
|
||||
}
|
||||
|
||||
// PlayletListResp web端短剧列表项
|
||||
type PlayletListResp struct {
|
||||
Id int64 `json:"id"`
|
||||
MediaSource string `json:"mediaSource"` // 媒资来源,空为普通媒资,hg 为黄果媒资
|
||||
Status playletmod.Status `json:"status"`
|
||||
IsFeatured bool `json:"isFeatured"` // 是否爆剧(true-是,false-否)
|
||||
IsOriginal bool `json:"isOriginal"` // 是否原创
|
||||
ShowOriginal bool `json:"showOriginal"` // 页面是否展示原创标识
|
||||
MediaBusiness string `json:"mediaBusiness"` // 媒资业务来源,按媒资标题前缀记录,如 CGDJ;空表示未标记
|
||||
IsRecommend bool `json:"isRecommend"`
|
||||
ShowOnBanner bool `json:"showOnBanner"`
|
||||
Banner string `json:"banner"`
|
||||
MobileBanner string `json:"mobileBanner"` // 移动端banner图
|
||||
ReviewAt time.Time `json:"reviewAt"`
|
||||
OnlineAt time.Time `json:"onlineAt"`
|
||||
ThemeIds []int64 `json:"themeIds"`
|
||||
ThemeNames []string `json:"themeNames"`
|
||||
CategoryIds []int64 `json:"categoryIds"` // 分类ID集合
|
||||
CategoryBinds []PlayletCategoryBind `json:"categoryBinds"` // 分类绑定及排序
|
||||
CategoryRank int64 `json:"categoryRank"` // 当前筛选分类下的排序
|
||||
Title string `json:"title"`
|
||||
PlayName string `json:"playName"` // 剧名
|
||||
Description string `json:"description"` // SEO Description
|
||||
Slug string `json:"slug"` // slug
|
||||
Desc string `json:"desc"`
|
||||
Anchor string `json:"anchor"`
|
||||
Cover string `json:"cover"`
|
||||
HorizontalCover string `json:"horizontalCover"` // 横版封面
|
||||
CompressedHorizontalCover string `json:"compressedHorizontalCover"` // 压缩横版封面
|
||||
Preview string `json:"preview"`
|
||||
TagIds []int64 `json:"tagIds"`
|
||||
TagNames []string `json:"tagNames"`
|
||||
ContentType playletmod.ContentType `json:"contentType"`
|
||||
OperateType playletmod.OperateType `json:"operateType"` // 运营类型 1-短剧 2-漫剧
|
||||
PayType playletmod.PayType `json:"payType"` // 支付方式 0-免费 1-金币 2-VIP
|
||||
SingleCoins int64 `json:"singleCoins"` // 单集金币(支付方式为1-金币时候生效)
|
||||
TotalEpisode int64 `json:"totalEpisode"`
|
||||
UpdateStatus int `json:"updateStatus"` // 连载状态 1-连载中 2-已完结
|
||||
TopRank int64 `json:"topRank"`
|
||||
RecommendRank int64 `json:"recommendRank"`
|
||||
CountComment int64 `json:"countComment"`
|
||||
CountBuy int64 `json:"countBuy"`
|
||||
CountBrowse int64 `json:"countBrowse"`
|
||||
HeatValue int64 `json:"heatValue"`
|
||||
CountCollect int64 `json:"countCollect"`
|
||||
CountLike int64 `json:"countLike"` // 真实点赞数
|
||||
VirtualCountLike int64 `json:"virtualCountLike"` // 虚拟点赞数
|
||||
DisplayCountLike int64 `json:"displayCountLike"` // 展示点赞数=真实点赞数+虚拟点赞数
|
||||
CountDisLike int64 `json:"countDisLike"`
|
||||
SeoInfo pubdef.SeoValue `json:"seoInfo"` // Seo相关信息
|
||||
OperatorId int64 `json:"operatorId"` // 最后操作人ID
|
||||
OperatorName string `json:"operatorName"` // 最后操作人名称
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
CompressedCover string `json:"compressedCover"`
|
||||
}
|
||||
|
||||
// PlayletListPageResp web端短剧分页列表响应
|
||||
type PlayletListPageResp struct {
|
||||
response.BasePageResp
|
||||
}
|
||||
|
||||
// PlayletCategoryBind 短剧绑定的分类及该分类下的排序
|
||||
type PlayletCategoryBind struct {
|
||||
Id int64 `json:"id"` // 分类ID
|
||||
Rank int64 `json:"rank"` // 该分类下的排序,越大越靠前
|
||||
}
|
||||
|
||||
// PlayletAddReq web端新增短剧请求
|
||||
type PlayletAddReq struct {
|
||||
ThemeIds []int64 `json:"themeIds"`
|
||||
CategoryIds []int64 `json:"categoryIds"` // 分类ID集合,可为空;不传或空数组表示清空
|
||||
CategoryBinds []PlayletCategoryBind `json:"categoryBinds"` // 分类绑定及排序,优先于categoryIds
|
||||
Title string `json:"title" binding:"required"`
|
||||
PlayName string `json:"playName"` // 剧名
|
||||
Slug string `json:"slug"` // slug,不传则按 SEO 关键词或标题自动生成
|
||||
Desc string `json:"desc"`
|
||||
Anchor string `json:"anchor"`
|
||||
Cover string `json:"cover"`
|
||||
HorizontalCover string `json:"horizontalCover"` // 横版封面
|
||||
Preview string `json:"preview"`
|
||||
TagIds []int64 `json:"tagIds"`
|
||||
ContentType playletmod.ContentType `json:"contentType"`
|
||||
OperateType playletmod.OperateType `json:"operateType"` // 运营类型 1-短剧 2-漫剧,不传默认短剧
|
||||
PayType playletmod.PayType `json:"payType"` // 支付方式 0-免费 1-金币 2-VIP
|
||||
SingleCoins int64 `json:"singleCoins"` // 单集金币(支付方式为1-金币时候生效)
|
||||
TotalEpisode int64 `json:"totalEpisode"`
|
||||
TopRank int64 `json:"topRank"`
|
||||
RecommendRank int64 `json:"recommendRank"`
|
||||
Status playletmod.Status `json:"status"`
|
||||
IsFeatured bool `json:"isFeatured"` // 是否爆剧(true-是,false-否)
|
||||
ShowOriginal bool `json:"showOriginal"` // 页面是否展示原创标识
|
||||
IsRecommend bool `json:"isRecommend"`
|
||||
ShowOnBanner bool `json:"showOnBanner"`
|
||||
Banner string `json:"banner"`
|
||||
MobileBanner string `json:"mobileBanner"` // 移动端banner图
|
||||
SeoInfo pubdef.SeoValue `json:"seoInfo"` // Seo相关信息
|
||||
OnlineAt *time.Time `json:"onlineAt"` // 上架时间,上架时不传则按当前时间
|
||||
}
|
||||
|
||||
// PlayletAddResp web端新增短剧响应
|
||||
type PlayletAddResp struct {
|
||||
Id int64 `json:"id"`
|
||||
}
|
||||
|
||||
// PlayletUpdateReq web端更新短剧请求
|
||||
type PlayletUpdateReq struct {
|
||||
Id int64 `json:"id" binding:"required"`
|
||||
Status *playletmod.Status `json:"status"`
|
||||
IsFeatured *bool `json:"isFeatured"` // 是否爆剧(true-是,false-否)
|
||||
ShowOriginal *bool `json:"showOriginal"` // 页面是否展示原创标识,不传保持原值
|
||||
ShowOnBanner *bool `json:"showOnBanner"`
|
||||
Banner *string `json:"banner"`
|
||||
MobileBanner *string `json:"mobileBanner"` // 移动端banner图;传空字符串可清空
|
||||
ThemeIds *[]int64 `json:"themeIds"`
|
||||
CategoryIds *[]int64 `json:"categoryIds"` // 分类ID集合,可为空;未传categoryBinds时使用
|
||||
CategoryBinds *[]PlayletCategoryBind `json:"categoryBinds"` // 分类绑定及排序,优先于categoryIds
|
||||
Title *string `json:"title"`
|
||||
PlayName *string `json:"playName"` // 剧名
|
||||
Slug *string `json:"slug"` // slug,历史数据为空时更新会自动生成
|
||||
Desc *string `json:"desc"`
|
||||
Anchor *string `json:"anchor"`
|
||||
Cover *string `json:"cover"`
|
||||
HorizontalCover *string `json:"horizontalCover"` // 横版封面
|
||||
Preview *string `json:"preview"`
|
||||
TagIds *[]int64 `json:"tagIds"`
|
||||
ContentType *playletmod.ContentType `json:"contentType"`
|
||||
OperateType *playletmod.OperateType `json:"operateType"` // 运营类型 1-短剧 2-漫剧
|
||||
PayType *playletmod.PayType `json:"payType"` // 支付方式 0-免费 1-金币 2-VIP
|
||||
SingleCoins *int64 `json:"singleCoins"` // 单集金币(支付方式为1-金币时候生效)
|
||||
TotalEpisode *int64 `json:"totalEpisode"`
|
||||
TopRank *int64 `json:"topRank"`
|
||||
RecommendRank *int64 `json:"recommendRank"`
|
||||
IsRecommend *bool `json:"isRecommend"`
|
||||
SeoInfo *pubdef.SeoValue `json:"seoInfo"` // Seo相关信息
|
||||
OnlineAt *time.Time `json:"onlineAt"` // 上架时间,新上架时不传则按当前时间
|
||||
}
|
||||
|
||||
// PlayletDelReq web端单/批量删除短剧请求
|
||||
type PlayletDelReq struct {
|
||||
Ids []int64 `json:"ids"` // 短剧ID集合,传1个表示单条删除,传多个表示批量删除
|
||||
}
|
||||
|
||||
// PlayletPayTypeSetReq web端单/批量设置短剧默认支付方式请求
|
||||
type PlayletPayTypeSetReq struct {
|
||||
Ids []int64 `json:"ids"` // 短剧ID集合,传1个表示单条设置,传多个表示批量设置
|
||||
PayType playletmod.PayType `json:"payType"` // 支付方式 0-免费 1-金币 2-VIP
|
||||
SingleCoins *int64 `json:"singleCoins"` // 单集金币(支付方式为1-金币时必填且需>0)
|
||||
}
|
||||
|
||||
// PlayletWatermarkResetReq web端按短剧ID批量重置剧集水印请求
|
||||
type PlayletWatermarkResetReq struct {
|
||||
Ids []int64 `json:"ids"` // 短剧ID集合,传1个表示单条,传多个表示批量;会重置其下全部剧集水印
|
||||
}
|
||||
|
||||
// PlayletStatusSetReq web端单/批量设置短剧上下架请求
|
||||
type PlayletStatusSetReq struct {
|
||||
Ids []int64 `json:"ids"` // 短剧ID集合,传1个表示单条设置,传多个表示批量设置
|
||||
Status playletmod.Status `json:"status"` // 上架状态 0-下架 1-上架
|
||||
OnlineAt *time.Time `json:"onlineAt"` // 上架时间;传入则使用该时间,未传且从未设置过则用当前时间
|
||||
}
|
||||
|
||||
// PlayletOnlineAtFillResp 回填已上架但上架时间为空的短剧
|
||||
type PlayletOnlineAtFillResp struct {
|
||||
UpdatedCount int64 `json:"updatedCount"` // 本次回填数量
|
||||
}
|
||||
|
||||
// PlayletRecommendSetReq web端单/批量设置短剧推荐请求
|
||||
type PlayletRecommendSetReq struct {
|
||||
Ids []int64 `json:"ids"` // 短剧ID集合,传1个表示单条设置,传多个表示批量设置
|
||||
IsRecommend bool `json:"isRecommend"` // 是否原创(推荐)(true-推荐,false-不推荐)
|
||||
}
|
||||
|
||||
// PlayletFeaturedSetReq web端单/批量设置短剧是否爆剧请求
|
||||
type PlayletFeaturedSetReq struct {
|
||||
Ids []int64 `json:"ids"` // 短剧ID集合,传1个表示单条设置,传多个表示批量设置
|
||||
IsFeatured bool `json:"isFeatured"` // 是否爆剧(true-是,false-否)
|
||||
}
|
||||
|
||||
// PlayletOperateTypeSetReq web端单/批量设置短剧运营类型请求
|
||||
type PlayletOperateTypeSetReq struct {
|
||||
Ids []int64 `json:"ids"` // 短剧ID集合,传1个表示单条设置,传多个表示批量设置
|
||||
OperateType playletmod.OperateType `json:"operateType"` // 运营类型 1-短剧 2-漫剧
|
||||
}
|
||||
|
||||
// PlayletBannerSetReq web端单/批量设置短剧是否显示在首页banner请求
|
||||
type PlayletBannerSetReq struct {
|
||||
Ids []int64 `json:"ids"` // 短剧ID集合,传1个表示单条设置,传多个表示批量设置
|
||||
ShowOnBanner bool `json:"showOnBanner"` // 是否显示在首页banner(true-显示,false-不显示)
|
||||
}
|
||||
|
||||
// PlayletThemeSetReq web端单/批量设置短剧题材请求
|
||||
type PlayletThemeSetReq struct {
|
||||
Ids []int64 `json:"ids"` // 短剧ID集合,传1个表示单条设置,传多个表示批量设置
|
||||
ThemeIds []int64 `json:"themeIds"` // 题材ID集合,可设置多个题材
|
||||
}
|
||||
|
||||
// PlayletTagSetReq web端单/批量设置短剧标签请求
|
||||
type PlayletTagSetReq struct {
|
||||
Ids []int64 `json:"ids"` // 短剧ID集合,传1个表示单条设置,传多个表示批量设置
|
||||
TagIds *[]int64 `json:"tagIds"` // 标签ID集合,可设置多个标签,传空数组表示清空标签,不传表示参数错误
|
||||
}
|
||||
|
||||
// PlayletCategorySetReq web端单/批量设置短剧分类请求
|
||||
type PlayletCategorySetReq struct {
|
||||
Ids []int64 `json:"ids"` // 短剧ID集合,传1个表示单条设置,传多个表示批量设置
|
||||
CategoryIds *[]int64 `json:"categoryIds"` // 分类ID集合,未传categoryBinds时使用,传空数组表示清空分类
|
||||
CategoryBinds *[]PlayletCategoryBind `json:"categoryBinds"` // 分类绑定及排序,优先于categoryIds,传空数组表示清空分类
|
||||
}
|
||||
|
||||
// PlayletVirtualLikeSetReq web端单/批量设置短剧虚拟点赞数请求
|
||||
type PlayletVirtualLikeSetReq struct {
|
||||
Ids []int64 `json:"ids"` // 短剧ID集合,传1个表示单条设置,传多个表示批量设置
|
||||
MinVirtualCountLike int64 `json:"minVirtualCountLike"` // 虚拟点赞数最小值,必须大于等于0
|
||||
MaxVirtualCountLike int64 `json:"maxVirtualCountLike"` // 虚拟点赞数最大值,必须大于等于最小值
|
||||
}
|
||||
|
||||
// PlayletThemeListReq web端题材分页列表请求
|
||||
type PlayletThemeListReq struct {
|
||||
pubdef.Page
|
||||
Id *int64 `form:"id" json:"id"`
|
||||
Name string `form:"name" json:"name"`
|
||||
Slug string `form:"slug" json:"slug"` // slug,精确匹配
|
||||
Status *bool `form:"status" json:"status"`
|
||||
IsRecommend *bool `form:"isRecommend" json:"isRecommend"` // 是否推荐
|
||||
}
|
||||
|
||||
// PlayletThemeListResp web端题材列表项
|
||||
type PlayletThemeListResp struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Slug string `json:"slug"` // slug
|
||||
Icon string `json:"icon"`
|
||||
Status bool `json:"status"`
|
||||
IsRecommend bool `json:"isRecommend"` // 是否推荐
|
||||
Rank int64 `json:"rank"`
|
||||
SeoInfo pubdef.SeoValue `json:"seoInfo"` // Seo相关信息
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// PlayletThemeListPageResp web端题材分页列表响应
|
||||
type PlayletThemeListPageResp struct {
|
||||
response.BasePageResp
|
||||
}
|
||||
|
||||
// PlayletThemeAddReq web端新增题材请求
|
||||
type PlayletThemeAddReq struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
Slug string `json:"slug"` // slug,不传则按 SEO 关键词或名称自动生成
|
||||
Icon string `json:"icon"`
|
||||
Status bool `json:"status"`
|
||||
IsRecommend bool `json:"isRecommend"` // 是否推荐
|
||||
Rank int64 `json:"rank"`
|
||||
SeoInfo pubdef.SeoValue `json:"seoInfo"` // Seo相关信息
|
||||
}
|
||||
|
||||
// PlayletThemeAddResp web端新增题材响应
|
||||
type PlayletThemeAddResp struct {
|
||||
Id int64 `json:"id"`
|
||||
}
|
||||
|
||||
// PlayletThemeUpdateReq web端更新题材请求
|
||||
type PlayletThemeUpdateReq struct {
|
||||
Id int64 `json:"id" binding:"required"`
|
||||
Name *string `json:"name"`
|
||||
Slug *string `json:"slug"` // slug,历史数据为空时更新会自动生成
|
||||
Icon *string `json:"icon"`
|
||||
Status *bool `json:"status"`
|
||||
IsRecommend *bool `json:"isRecommend"` // 是否推荐
|
||||
Rank *int64 `json:"rank"`
|
||||
SeoInfo *pubdef.SeoValue `json:"seoInfo"` // Seo相关信息
|
||||
}
|
||||
|
||||
// PlayletThemeDelReq web端删除题材请求
|
||||
type PlayletThemeDelReq struct {
|
||||
Id int64 `json:"id" binding:"required"`
|
||||
}
|
||||
|
||||
// PlayletThemeRecommendSetReq web端单/批量设置题材是否推荐请求
|
||||
type PlayletThemeRecommendSetReq struct {
|
||||
Ids []int64 `json:"ids"` // 题材ID集合,传1个表示单条设置,传多个表示批量设置
|
||||
IsRecommend bool `json:"isRecommend"` // 是否推荐(true-推荐,false-取消推荐)
|
||||
}
|
||||
|
||||
// PlayletTagListReq web端标签分页列表请求
|
||||
type PlayletTagListReq struct {
|
||||
pubdef.Page
|
||||
Id *int64 `form:"id" json:"id"`
|
||||
Name string `form:"name" json:"name"`
|
||||
Slug string `form:"slug" json:"slug"` // slug,精确匹配
|
||||
Status *bool `form:"status" json:"status"`
|
||||
}
|
||||
|
||||
// PlayletTagListResp web端标签列表项
|
||||
type PlayletTagListResp struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Slug string `json:"slug"` // slug
|
||||
Status bool `json:"status"`
|
||||
Rank int64 `json:"rank"`
|
||||
SeoInfo pubdef.SeoValue `json:"seoInfo"` // Seo相关信息
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// PlayletTagListPageResp web端标签分页列表响应
|
||||
type PlayletTagListPageResp struct {
|
||||
response.BasePageResp
|
||||
}
|
||||
|
||||
// PlayletTagAddReq web端新增标签请求
|
||||
type PlayletTagAddReq struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
Slug string `json:"slug"` // slug,不传则按 SEO 关键词或名称自动生成
|
||||
Status bool `json:"status"`
|
||||
Rank int64 `json:"rank"`
|
||||
SeoInfo pubdef.SeoValue `json:"seoInfo"` // Seo相关信息
|
||||
}
|
||||
|
||||
// PlayletTagAddResp web端新增标签响应
|
||||
type PlayletTagAddResp struct {
|
||||
Id int64 `json:"id"`
|
||||
}
|
||||
|
||||
// PlayletTagUpdateReq web端更新标签请求
|
||||
type PlayletTagUpdateReq struct {
|
||||
Id int64 `json:"id" binding:"required"`
|
||||
Name *string `json:"name"`
|
||||
Slug *string `json:"slug"` // slug,历史数据为空时更新会自动生成
|
||||
Status *bool `json:"status"`
|
||||
Rank *int64 `json:"rank"`
|
||||
SeoInfo *pubdef.SeoValue `json:"seoInfo"` // Seo相关信息
|
||||
}
|
||||
|
||||
// PlayletTagDelReq web端删除标签请求
|
||||
type PlayletTagDelReq struct {
|
||||
Id int64 `json:"id" binding:"required"`
|
||||
}
|
||||
|
||||
// PlayletChapterListReq web端章节分页列表请求
|
||||
type PlayletChapterListReq struct {
|
||||
pubdef.Page
|
||||
PlayletId *int64 `form:"playletId" json:"playletId"`
|
||||
Id *int64 `form:"id" json:"id"`
|
||||
Status *playletchaptermod.Status `form:"status" json:"status"` // 上架状态 0-下架 1-上架
|
||||
WatermarkStatus *playletchaptermod.WatermarkStatus `form:"watermarkStatus" json:"watermarkStatus"`
|
||||
}
|
||||
|
||||
// PlayletChapterListResp web端章节列表项
|
||||
type PlayletChapterListResp struct {
|
||||
Id int64 `json:"id"`
|
||||
PlayletId int64 `json:"playletId"`
|
||||
MediaContentId uint `json:"mediaContentId"`
|
||||
CurrentEpisode int64 `json:"currentEpisode"`
|
||||
Title string `json:"title"`
|
||||
Md5 string `json:"md5"`
|
||||
Hash string `json:"hash"`
|
||||
Height int64 `json:"height"`
|
||||
Width int64 `json:"width"`
|
||||
Ratio float64 `json:"ratio"`
|
||||
VideoUrl string `json:"videoUrl"` // 原片视频地址
|
||||
WatermarkVideoUrl string `json:"watermarkVideoUrl"` // 加水印后的视频地址
|
||||
MediaSize int64 `json:"mediaSize"`
|
||||
MediaTime int64 `json:"mediaTime"`
|
||||
CountComment int64 `json:"countComment"`
|
||||
CountBuy int64 `json:"countBuy"`
|
||||
CountBrowse int64 `json:"countBrowse"`
|
||||
CountCollect int64 `json:"countCollect"`
|
||||
CountLike int64 `json:"countLike"`
|
||||
CountDisLike int64 `json:"countDisLike"`
|
||||
Status playletchaptermod.Status `json:"status"` // 上架状态 0-下架 1-上架
|
||||
PayType playletchaptermod.PayType `json:"payType"`
|
||||
SingleCoins int64 `json:"singleCoins"`
|
||||
WatermarkStatus playletchaptermod.WatermarkStatus `json:"watermarkStatus"`
|
||||
MediaSourceId string `json:"mediaSourceId"`
|
||||
MediaTaskId string `json:"mediaTaskId"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// PlayletChapterListPageResp web端章节分页列表响应
|
||||
type PlayletChapterListPageResp struct {
|
||||
response.BasePageResp
|
||||
}
|
||||
|
||||
// PlayletChapterAddReq web端新增章节请求
|
||||
type PlayletChapterAddReq struct {
|
||||
PlayletId int64 `json:"playletId" binding:"required"`
|
||||
CurrentEpisode int64 `json:"currentEpisode" binding:"required"`
|
||||
Title string `json:"title"`
|
||||
Md5 string `json:"md5"`
|
||||
Hash string `json:"hash"`
|
||||
Height int64 `json:"height"`
|
||||
Width int64 `json:"width"`
|
||||
Ratio float64 `json:"ratio"`
|
||||
VideoUrl string `json:"videoUrl"`
|
||||
MediaSize int64 `json:"mediaSize"`
|
||||
MediaTime int64 `json:"mediaTime"`
|
||||
PayType playletchaptermod.PayType `json:"payType"`
|
||||
SingleCoins int64 `json:"singleCoins"`
|
||||
MediaSourceId string `json:"mediaSourceId"`
|
||||
Status *playletchaptermod.Status `json:"status"` // 上架状态,不传按媒资来源默认
|
||||
}
|
||||
|
||||
// PlayletChapterAddResp web端新增章节响应
|
||||
type PlayletChapterAddResp struct {
|
||||
Id int64 `json:"id"`
|
||||
}
|
||||
|
||||
// PlayletChapterUpdateReq web端更新章节请求
|
||||
type PlayletChapterUpdateReq struct {
|
||||
Id int64 `json:"id" binding:"required"`
|
||||
CurrentEpisode *int64 `json:"currentEpisode"`
|
||||
Title *string `json:"title"`
|
||||
Md5 *string `json:"md5"`
|
||||
Hash *string `json:"hash"`
|
||||
Height *int64 `json:"height"`
|
||||
Width *int64 `json:"width"`
|
||||
Ratio *float64 `json:"ratio"`
|
||||
VideoUrl *string `json:"videoUrl"`
|
||||
MediaSize *int64 `json:"mediaSize"`
|
||||
MediaTime *int64 `json:"mediaTime"`
|
||||
PayType *playletchaptermod.PayType `json:"payType"`
|
||||
SingleCoins *int64 `json:"singleCoins"`
|
||||
Status *playletchaptermod.Status `json:"status"` // 上架状态 0-下架 1-上架
|
||||
}
|
||||
|
||||
// PlayletChapterStatusFillResp 回填历史剧集上架状态响应
|
||||
type PlayletChapterStatusFillResp struct {
|
||||
UpdatedCount int64 `json:"updatedCount"` // 本次回填数量
|
||||
}
|
||||
|
||||
// PlayletChapterStatusSetReq web端单/批量设置章节上架状态请求
|
||||
type PlayletChapterStatusSetReq struct {
|
||||
Ids []int64 `json:"ids"` // 章节ID集合,传1个表示单条设置,传多个表示批量设置
|
||||
Status playletchaptermod.Status `json:"status"` // 上架状态 0-下架 1-上架
|
||||
}
|
||||
|
||||
// PlayletChapterPayTypeSetReq web端单/批量设置章节支付方式请求
|
||||
type PlayletChapterPayTypeSetReq struct {
|
||||
Ids []int64 `json:"ids"` // 章节ID集合,传1个表示单条设置,传多个表示批量设置
|
||||
PayType playletchaptermod.PayType `json:"payType"` // 支付方式 0-免费 1-金币 2-VIP
|
||||
SingleCoins *int64 `json:"singleCoins"` // 单集金币(支付方式为1-金币时必填且需>0)
|
||||
}
|
||||
|
||||
// PlayletChapterDelReq web端单/批量删除章节请求
|
||||
type PlayletChapterDelReq struct {
|
||||
Ids []int64 `json:"ids"` // 章节ID集合,传1个表示单条删除,传多个表示批量删除
|
||||
}
|
||||
|
||||
// PlayletChapterSyncReq web端手动同步短剧剧集请求
|
||||
type PlayletChapterSyncReq struct {
|
||||
PlayletIds []int64 `json:"playletIds" binding:"required"` // 短剧ID集合,传1个表示单条同步,传多个表示批量同步
|
||||
}
|
||||
|
||||
// PlayletChapterSyncResult web端手动同步短剧剧集结果项
|
||||
type PlayletChapterSyncResult struct {
|
||||
PlayletId int64 `json:"playletId"` // 短剧ID
|
||||
NewChapterCount int `json:"newChapterCount"` // 本次新增剧集数量
|
||||
Success bool `json:"success"` // 是否同步成功
|
||||
Reason string `json:"reason"` // 失败原因
|
||||
}
|
||||
|
||||
// PlayletChapterSyncResp web端手动同步短剧剧集响应
|
||||
type PlayletChapterSyncResp struct {
|
||||
Total int `json:"total"` // 同步总数
|
||||
SuccessCount int `json:"successCount"` // 成功数量
|
||||
FailedCount int `json:"failedCount"` // 失败数量
|
||||
List []*PlayletChapterSyncResult `json:"list"` // 同步结果集合
|
||||
}
|
||||
|
||||
// PlayletSlugSyncReq web端同步历史空 slug 请求
|
||||
type PlayletSlugSyncReq struct {
|
||||
MaxSize int64 `json:"maxSize"` // 本次最多处理的空 slug 记录数,默认500,最大2000
|
||||
}
|
||||
|
||||
// PlayletSlugSyncResp web端同步历史空 slug 响应
|
||||
type PlayletSlugSyncResp struct {
|
||||
ThemeUpdated int64 `json:"themeUpdated"` // 本次补齐的题材数
|
||||
TagUpdated int64 `json:"tagUpdated"` // 本次补齐的标签数
|
||||
PlayletUpdated int64 `json:"playletUpdated"` // 本次补齐的短剧数
|
||||
HomeConfigUpdated int64 `json:"homeConfigUpdated"` // 本次补齐的首页配置数
|
||||
HasMore bool `json:"hasMore"` // 是否还有未处理的历史数据
|
||||
}
|
||||
|
||||
// PlayletSalesSortType 销售数据排序,均为降序
|
||||
type PlayletSalesSortType int
|
||||
|
||||
const (
|
||||
PlayletSalesSortUnlock PlayletSalesSortType = 0 // 金币解锁次数
|
||||
PlayletSalesSortLike PlayletSalesSortType = 1 // 点赞数
|
||||
PlayletSalesSortCollect PlayletSalesSortType = 2 // 收藏数
|
||||
)
|
||||
|
||||
// PlayletSalesReq 短剧销售数据列表请求。起止时间均为北京时间,都不传时默认昨天。
|
||||
type PlayletSalesReq struct {
|
||||
Id *int64 `form:"id" json:"id"` // 短剧ID
|
||||
Title string `form:"title" json:"title"` // 标题模糊匹配
|
||||
StartTime string `form:"startTime" json:"startTime"` // 开始时间:2006-01-02 / 2006-01-02 15:04:05 / RFC3339
|
||||
EndTime string `form:"endTime" json:"endTime"` // 结束时间:2006-01-02 / 2006-01-02 15:04:05 / RFC3339
|
||||
SortType PlayletSalesSortType `form:"sortType" json:"sortType"` // 排序:0金币解锁次数 1点赞数 2收藏数
|
||||
}
|
||||
|
||||
// PlayletSalesItem 短剧销售数据列表项,指标均为所选时间段内数据。
|
||||
type PlayletSalesItem struct {
|
||||
Id int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
PlayName string `json:"playName"`
|
||||
Cover string `json:"cover"`
|
||||
Slug string `json:"slug"`
|
||||
Status playletmod.Status `json:"status"`
|
||||
UnlockCount int64 `json:"unlockCount"` // 金币解锁次数
|
||||
UnlockCoins int64 `json:"unlockCoins"` // 金币解锁消耗
|
||||
LikeCount int64 `json:"likeCount"` // 期间新增且当前仍在的短剧点赞数
|
||||
CollectCount int64 `json:"collectCount"` // 期间新增且当前仍在的短剧收藏数
|
||||
}
|
||||
|
||||
// PlayletSalesResp 短剧销售数据列表响应,最多返回 50 条。
|
||||
type PlayletSalesResp struct {
|
||||
StartTime string `json:"startTime"` // 实际统计开始时间(北京时间)
|
||||
EndTime string `json:"endTime"` // 实际统计结束时间(北京时间)
|
||||
List []*PlayletSalesItem `json:"list"`
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"videoweb/pub/models/playlettopicgroupmod"
|
||||
"videoweb/pub/pubdef"
|
||||
)
|
||||
|
||||
// PlayletTopicGroupListReq 专题区块列表请求
|
||||
type PlayletTopicGroupListReq struct {
|
||||
pubdef.Page // 分页参数
|
||||
Status *bool `form:"status"` // 是否启用,不传则查询全部
|
||||
}
|
||||
|
||||
// PlayletTopicGroupListResp 专题区块列表响应
|
||||
type PlayletTopicGroupListResp struct {
|
||||
TotalCount int64 `json:"totalCount"` // 符合条件的区块总数
|
||||
PageNum int `json:"pageNum"` // 当前页码
|
||||
PageSize int `json:"pageSize"` // 每页数量
|
||||
List playlettopicgroupmod.PlayletTopicGroupList `json:"list"` // 专题区块列表
|
||||
}
|
||||
|
||||
// PlayletTopicGroupAddReq 新增专题区块请求
|
||||
type PlayletTopicGroupAddReq struct {
|
||||
Name string `json:"name" binding:"required"` // 专题区块名称
|
||||
Desc string `json:"desc"` // 专题区块描述
|
||||
TopicIds []int64 `json:"topicIds"` // 专题ID顺序即展示顺序
|
||||
Rank int64 `json:"rank"` // 区块排序,越大越靠前
|
||||
Status *bool `json:"status" binding:"required"` // 是否启用
|
||||
}
|
||||
|
||||
// PlayletTopicGroupAddResp 新增专题区块响应
|
||||
type PlayletTopicGroupAddResp struct {
|
||||
Id int64 `json:"id"` // 新增的专题区块ID
|
||||
}
|
||||
|
||||
// PlayletTopicGroupUpdateReq 更新专题区块请求
|
||||
type PlayletTopicGroupUpdateReq struct {
|
||||
Id int64 `json:"id" binding:"required"` // 专题区块ID
|
||||
Name *string `json:"name"` // 专题区块名称,不传则不修改
|
||||
Desc *string `json:"desc"` // 专题区块描述,不传则不修改
|
||||
TopicIds *[]int64 `json:"topicIds"` // 专题ID集合,数组顺序即展示顺序,不传则不修改
|
||||
Rank *int64 `json:"rank"` // 区块排序,越大越靠前,不传则不修改
|
||||
Status *bool `json:"status"` // 是否启用,不传则不修改
|
||||
}
|
||||
|
||||
// PlayletTopicGroupDeleteReq 删除专题区块请求
|
||||
type PlayletTopicGroupDeleteReq struct {
|
||||
Id int64 `json:"id" binding:"required"` // 待删除的专题区块ID
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package proto
|
||||
|
||||
// VideoSlugSyncReq web端同步视频相关历史空 slug 请求
|
||||
type VideoSlugSyncReq struct {
|
||||
MaxSize int64 `json:"maxSize"` // 本次最多处理的空 slug 记录数,默认500,最大2000
|
||||
}
|
||||
|
||||
// VideoSlugSyncResp web端同步视频相关历史空 slug 响应
|
||||
type VideoSlugSyncResp struct {
|
||||
CategoryUpdated int64 `json:"categoryUpdated"` // 本次补齐的分类数
|
||||
TagUpdated int64 `json:"tagUpdated"` // 本次补齐的标签数
|
||||
TopicUpdated int64 `json:"topicUpdated"` // 本次补齐的题材数
|
||||
CreaterUpdated int64 `json:"createrUpdated"` // 本次补齐的作者数
|
||||
VideoUpdated int64 `json:"videoUpdated"` // 本次补齐的视频数
|
||||
HasMore bool `json:"hasMore"` // 是否还有未处理的历史数据
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
package web_acc
|
||||
|
||||
import (
|
||||
"time"
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/crypt"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/google"
|
||||
"videoweb/pub/models/mwacc"
|
||||
"videoweb/web/service/srv_acc"
|
||||
"videoweb/web/service/srv_mwacc"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
// @Tags 账号
|
||||
// @Summary 账号-列表
|
||||
// @Description 账号-列表
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body MwAccListReq true "参数列表"
|
||||
// @Success 200 {object} MwAccListResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/acc/list [GET]
|
||||
func AccGetList(c *gin.Context) {
|
||||
|
||||
var req MwAccListReq
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
search := mwacc.MakeSearch(req.KeyWords, req.Status, req.Page)
|
||||
sort := mwacc.MakeSort(req.PageNum, req.PageSize)
|
||||
|
||||
total, data, _ := mwacc.GetAccList(c, search, sort)
|
||||
|
||||
resp := MwAccListResp{
|
||||
TotalCount: total,
|
||||
AccRec: make([]*MwAccRec, 0),
|
||||
}
|
||||
|
||||
for _, v := range data {
|
||||
resp.AccRec = append(resp.AccRec, &MwAccRec{
|
||||
Id: v.Id,
|
||||
UserName: v.Username,
|
||||
Acc: v.Acc,
|
||||
Email: v.Email,
|
||||
RoleId: v.RoleId,
|
||||
RoleName: v.RoleName,
|
||||
// Base32: v.Base32,
|
||||
IsBase32: v.IsBase32,
|
||||
IsEnb: v.IsEnb,
|
||||
FeedBack: v.Feedback,
|
||||
CreatedAt: v.CreatedAt.Unix(),
|
||||
UpdatedAt: v.UpdatedAt.Unix(),
|
||||
LimitIP: v.LimitIP,
|
||||
})
|
||||
}
|
||||
common.ServerJSON(c, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// @Tags 账号
|
||||
// @Summary 账号-添加
|
||||
// @Description 账号-添加
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body MwAccAddReq true "参数列表"
|
||||
// @Success 200 {object} MwAccAddResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/acc/add [POST]
|
||||
func AccAdd(c *gin.Context) {
|
||||
var req MwAccAddReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
accCount, err := mwacc.AccCountByFilter(c, bson.M{
|
||||
mwacc.FN.MwAcc.Acc: req.Acc,
|
||||
})
|
||||
if accCount > 0 || err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, "用户已存在")
|
||||
return
|
||||
}
|
||||
|
||||
secret := google.NewGoogleAuth().GetSecret()
|
||||
|
||||
insertDoc := &mwacc.AccInsertDoc{
|
||||
UserName: req.Name,
|
||||
Pwd: crypt.StrToMd5(req.Pwd), //md5V(req.Pwd),
|
||||
Acc: req.Acc,
|
||||
Email: req.Email,
|
||||
RoleId: req.RoleId,
|
||||
Base32: secret,
|
||||
IsBase32: false,
|
||||
IsEnb: req.IsEnb,
|
||||
LimitIP: req.LimitIP,
|
||||
}
|
||||
|
||||
_, _, err = mwacc.AccAdd(c, insertDoc)
|
||||
if err != nil {
|
||||
common.ServerJSON(c, srvdef.Failure, MwAccAddResp{Result: false})
|
||||
return
|
||||
}
|
||||
common.ServerJSON(c, srvdef.Success, MwAccAddResp{Result: true})
|
||||
return
|
||||
}
|
||||
|
||||
// @Tags 账号
|
||||
// @Summary 账号-删除
|
||||
// @Description 账号-删除
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body MwAccDelReq true "参数列表"
|
||||
// @Success 200 {object} MwAccDelResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/acc/del [POST]
|
||||
func AccDel(c *gin.Context) {
|
||||
|
||||
var req MwAccDelReq
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
err := mwacc.DelAccByFilter(c, bson.M{
|
||||
mwacc.FN.MwAcc.Id: req.Id,
|
||||
})
|
||||
// 删除对应账号的token
|
||||
_ = mwacc.DeleteOneToken(c, bson.M{
|
||||
mwacc.FN.MwAccToken.AccId: req.Id,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
common.ServerJSON(c, srvdef.Failure, MwAccDelResp{Result: true})
|
||||
return
|
||||
}
|
||||
common.ServerJSON(c, srvdef.Success, MwAccDelResp{Result: true})
|
||||
return
|
||||
}
|
||||
|
||||
// @Tags 账号
|
||||
// @Summary 账号-获取信息
|
||||
// @Description 账号-获取信息
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body MwAccGetInfoReq true "参数列表"
|
||||
// @Success 200 {object} MwAccGetInfoResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/acc/getinfo [GET]
|
||||
func AccGetInfo(c *gin.Context) {
|
||||
var req MwAccGetInfoReq
|
||||
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
rest, err := mwacc.FindOneAccByFilter(c, bson.M{
|
||||
mwacc.FN.MwAcc.Id: req.Id,
|
||||
})
|
||||
if err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
resq := MwAccGetInfoResp{
|
||||
Id: rest.Id,
|
||||
UserName: rest.UserName,
|
||||
Acc: rest.Acc,
|
||||
Pwd: rest.Pwd,
|
||||
Email: rest.Email,
|
||||
RoleId: rest.RoleId,
|
||||
IsEnb: rest.IsEnb,
|
||||
LimitIP: rest.LimitIP,
|
||||
}
|
||||
common.ServerJSON(c, srvdef.Success, resq)
|
||||
return
|
||||
}
|
||||
|
||||
// @Tags 账号
|
||||
// @Summary 账号-更新
|
||||
// @Description 账号-更新
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body MwAccUpReq true "参数列表"
|
||||
// @Success 200 {object} MwAccUpResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/acc/up [POST]
|
||||
func AccUp(c *gin.Context) {
|
||||
var req MwAccUpReq
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
_, err := srv_mwacc.AccUp(c, &srv_mwacc.AccUpDoc{
|
||||
Id: req.Id,
|
||||
UserName: req.UserName,
|
||||
Acc: req.Acc,
|
||||
Email: req.Email,
|
||||
RoleId: req.RoleId,
|
||||
IsEnb: req.IsEnb,
|
||||
LimitIP: req.LimitIP,
|
||||
})
|
||||
if err != nil {
|
||||
common.ServerJSON(c, srvdef.Failure, MwAccUpResp{Result: false})
|
||||
return
|
||||
}
|
||||
common.ServerJSON(c, srvdef.Success, MwAccUpResp{Result: true})
|
||||
return
|
||||
}
|
||||
|
||||
// @Tags 账号
|
||||
// @Summary 账号-获取状态
|
||||
// @Description 账号-获取状态
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body MwAccGetStatusReq true "参数列表"
|
||||
// @Success 200 {object} MwAccGetStatusResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/acc/getstatus [GET]
|
||||
func AccGetStatus(c *gin.Context) {
|
||||
var req MwAccGetStatusReq
|
||||
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
rest, err := mwacc.FindOneAccByFilter(c, bson.M{
|
||||
mwacc.FN.MwAcc.Id: req.Id,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
common.ServerJSON(c, srvdef.Failure, err)
|
||||
return
|
||||
}
|
||||
|
||||
resp := MwAccGetStatusResp{
|
||||
Id: rest.Id,
|
||||
UserName: rest.UserName,
|
||||
IsEnb: rest.IsEnb,
|
||||
FeedBack: rest.Feedback,
|
||||
}
|
||||
|
||||
common.ServerJSON(c, srvdef.Success, resp)
|
||||
return
|
||||
}
|
||||
|
||||
// @Tags 账号
|
||||
// @Summary 账号-保存状态
|
||||
// @Description 账号-保存状态
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body MwAccSaveStatusReq true "参数列表"
|
||||
// @Success 200 {object} MwAccSaveStatusResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/acc/savestatus [POST]
|
||||
func AccSaveStatus(c *gin.Context) {
|
||||
|
||||
var req MwAccSaveStatusReq
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
err := mwacc.UpOneAccByFilter(c, bson.M{
|
||||
mwacc.FN.MwAcc.Id: req.Id,
|
||||
}, bson.M{
|
||||
mwacc.FN.MwAcc.UserName: req.UserName,
|
||||
mwacc.FN.MwAcc.IsEnb: req.IsEnb,
|
||||
mwacc.FN.MwAcc.Feedback: req.FeedBack,
|
||||
mwacc.FN.MwAcc.UpdatedAt: time.Now(),
|
||||
})
|
||||
if err != nil {
|
||||
common.ServerJSON(c, srvdef.Failure, "")
|
||||
return
|
||||
}
|
||||
// 封禁时,删除token
|
||||
if !req.IsEnb {
|
||||
mwacc.DeleteOneToken(c, bson.M{mwacc.FN.MwAccToken.AccId: req.Id})
|
||||
}
|
||||
|
||||
common.ServerJSON(c, srvdef.Success, MwAccSaveStatusResp{Result: true})
|
||||
return
|
||||
}
|
||||
|
||||
// @Tags 账号
|
||||
// @Summary 账号-获取操作记录
|
||||
// @Description 账号-获取操作记录
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body AccOpLogReq true "参数列表"
|
||||
// @Success 200 {object} AccOpLogResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/acc/ops [POST]
|
||||
func GetAccOpRecords(ctx *gin.Context) {
|
||||
var req AccOpLogReq
|
||||
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
total, data, err := srv_acc.GetOpLogs(ctx, &req.OpLogSearch)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, srvdef.Failure, err.Error())
|
||||
return
|
||||
}
|
||||
resp := &AccOpLogResp{total, data}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// @Tags 账号
|
||||
// @Summary 账号-更新密码
|
||||
// @Description 账号-更新密码
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body MwAccUpPwdReq true "参数列表"
|
||||
// @Success 200 {object} MwAccUpPwdReq "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/acc/uppwd [POST]
|
||||
func AccUpdatePwd(c *gin.Context) {
|
||||
var req MwAccUpPwdReq
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
_, err := srv_mwacc.AccUpPwd(c, &srv_mwacc.AccUpPwdDoc{
|
||||
Id: req.Id,
|
||||
Pwd: req.Pwd,
|
||||
})
|
||||
if err != nil {
|
||||
common.ServerJSON(c, srvdef.Failure, MwAccUpPwdResp{Result: false})
|
||||
return
|
||||
}
|
||||
common.ServerJSON(c, srvdef.Success, MwAccUpPwdResp{Result: true})
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package web_acc
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/models/mwacc"
|
||||
"videoweb/web/service/srv_mwacc"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags 登录
|
||||
// @Summary 登录-登录
|
||||
// @Description 登录-登录
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body MainWebLoginReq true "参数列表"
|
||||
// @Success 200 {object} MainWebLoginResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Router /api/web/login/acc [POST]
|
||||
func AccLogin(c *gin.Context) {
|
||||
var req MainWebLoginReq
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
accInfo, err := srv_mwacc.AccLogin(c, req.Acc, req.Pwd, req.Code)
|
||||
if err != nil || accInfo == nil {
|
||||
common.ServerJSON(c, err.Code, err.Msg)
|
||||
return
|
||||
}
|
||||
|
||||
resp := MainWebLoginResp{}
|
||||
|
||||
if len(accInfo.Qurl) != 0 {
|
||||
resp.Qurl = accInfo.Qurl
|
||||
} else {
|
||||
// 成功保存token
|
||||
if ok, _ := mwacc.SaveToken(c, accInfo.Id, accInfo.Token); ok != true {
|
||||
common.ServerJSON(c, srvdef.GenerateTokenFailed, srvdef.GenerateTokenFailed.Msg())
|
||||
}
|
||||
|
||||
resp.AccId = accInfo.Id
|
||||
resp.Acc = accInfo.Acc
|
||||
resp.RoleId = accInfo.RoleId
|
||||
resp.Token = accInfo.Token
|
||||
}
|
||||
common.ServerJSON(c, srvdef.Success, resp)
|
||||
return
|
||||
}
|
||||
|
||||
// SLogin doc
|
||||
// @Summary 管理员sso登陆
|
||||
// @Description 管理员sso登陆
|
||||
// @Tags web-单点登陆
|
||||
// @Accept mpfd,json
|
||||
// @Produce json,html
|
||||
// @Param name formData string true "账号"
|
||||
// @Param password formData string true "密码"
|
||||
// @Success 200 {string} json "{"msg": "管理员信息""}"
|
||||
// @Failure 400 {string} json "{"msg": "操作失败"}"
|
||||
// @Router /api/web/login/slogin [post]
|
||||
func SLogin(c *gin.Context) {
|
||||
var req MainWebLoginReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
accInfo, err := srv_mwacc.AccSLogin(c, req.Acc, req.Pwd)
|
||||
if err != nil || accInfo == nil {
|
||||
common.ServerJSON(c, err.Code, err.Msg)
|
||||
return
|
||||
}
|
||||
resp := MainWebLoginResp{}
|
||||
// 成功保存token
|
||||
if ok, _ := mwacc.SaveToken(c, accInfo.Id, accInfo.Token); ok != true {
|
||||
common.ServerJSON(c, srvdef.GenerateTokenFailed, srvdef.GenerateTokenFailed.Msg())
|
||||
}
|
||||
resp.AccId = accInfo.Id
|
||||
resp.Acc = accInfo.Acc
|
||||
resp.RoleId = accInfo.RoleId
|
||||
resp.Token = accInfo.Token
|
||||
|
||||
common.ServerJSON(c, srvdef.Success, resp)
|
||||
return
|
||||
}
|
||||
|
||||
// @Tags 登录
|
||||
// @Summary 登录-绑定二维码
|
||||
// @Description 登录-绑定二维码
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body BindQurlReq true "参数列表"
|
||||
// @Success 200 {object} BindQurlResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Router /api/web/login/bind [POST]
|
||||
func BindQurl(c *gin.Context) {
|
||||
var req BindQurlReq
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, "tone AccLogin arg error "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
ok, _ := mwacc.BindAccQurl(c, req.Acc)
|
||||
if !ok {
|
||||
common.ServerJSON(c, srvdef.Failure, BindQurlResp{Result: false})
|
||||
return
|
||||
}
|
||||
common.ServerJSON(c, srvdef.Success, BindQurlResp{Result: true})
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,477 @@
|
||||
package web_acc
|
||||
|
||||
import (
|
||||
"time"
|
||||
"videoweb/pub/pubdef"
|
||||
"videoweb/web/service/srv_acc"
|
||||
)
|
||||
|
||||
/////////////////////////登录//////////////////////////
|
||||
/******************主后台登录***********************/
|
||||
// POST /web/login/acc
|
||||
|
||||
// 请求参数
|
||||
type MainWebLoginReq struct {
|
||||
// 账户
|
||||
Acc string `json:"acc,omitempty"`
|
||||
// 密码
|
||||
Pwd string `json:"pwd,omitempty"`
|
||||
// 验证码
|
||||
Code string `json:"code,omitempty"`
|
||||
}
|
||||
|
||||
// 返回参数
|
||||
type MainWebLoginResp struct {
|
||||
// 账户id
|
||||
AccId int64 `json:"accId"`
|
||||
// 账户
|
||||
Acc string `json:"acc"`
|
||||
// 角色id
|
||||
RoleId int64 `json:"roleId"`
|
||||
// token
|
||||
Token string `json:"token"`
|
||||
// 二维码
|
||||
Qurl []byte `json:"qurl"`
|
||||
}
|
||||
|
||||
/******************绑定二维码***********************/
|
||||
// POST /web/login/bind
|
||||
|
||||
// 请求参数
|
||||
type BindQurlReq struct {
|
||||
//账户
|
||||
Acc string `json:"acc,omitempty"`
|
||||
}
|
||||
|
||||
// 返回参数
|
||||
type BindQurlResp struct {
|
||||
// 是否成功 true:成功 false:未成功
|
||||
Result bool `json:"result,omitempty"`
|
||||
}
|
||||
|
||||
/******************绑定二维码***********************/
|
||||
|
||||
/////////////////////////角色//////////////////////////
|
||||
// GET /web/role/list
|
||||
// 请求参数
|
||||
|
||||
// 角色记录
|
||||
type MwRoleRec struct {
|
||||
// 角色Id
|
||||
Id int64 `json:"id"`
|
||||
// 角色名称
|
||||
Name string `json:"name"`
|
||||
// 描述
|
||||
Desc string `json:"desc"`
|
||||
// 是否启用 false:禁用 true:启用
|
||||
IsEnb bool `json:"isEnb"`
|
||||
// 已有权限的api
|
||||
ApiMenus []string `json:"apiMenus"`
|
||||
// 创建时间
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
// 更新时间
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// 返回参数
|
||||
type MwRoleListResp struct {
|
||||
// 总共数量
|
||||
TotalCount int64 `json:"totalCount"`
|
||||
// 当前页配置记录
|
||||
RoleRecs []*MwRoleRec `json:"roleRecs"`
|
||||
}
|
||||
|
||||
/******************角色添加***********************/
|
||||
// POST /web/role/add
|
||||
|
||||
// 请求参数
|
||||
type MwRoleAddReq struct {
|
||||
// 名称
|
||||
Name string `json:"name"`
|
||||
// 描述
|
||||
Desc string `json:"desc"`
|
||||
// 状态
|
||||
IsEnb bool `json:"isEnb"`
|
||||
}
|
||||
|
||||
// 返回参数
|
||||
type MwRoleAddResp struct {
|
||||
// 是否成功 true:成功 false:未成功
|
||||
Result bool `json:"result,omitempty"`
|
||||
}
|
||||
|
||||
/******************角色删除***********************/
|
||||
// POST /web/role/del
|
||||
|
||||
// 请求参数
|
||||
type MwRoleDelReq struct {
|
||||
// 角色id
|
||||
Id int64 `json:"id,omitempty"`
|
||||
}
|
||||
|
||||
// 返回参数
|
||||
type MwRoleDelResp struct {
|
||||
// 是否成功 true:成功 false:未成功
|
||||
Result bool `json:"result,omitempty"`
|
||||
}
|
||||
|
||||
/******************角色获取信息***********************/
|
||||
// GET /web/role/getinfo
|
||||
|
||||
// 请求参数
|
||||
type MwRoleGetInfoReq struct {
|
||||
// 角色id
|
||||
Id int64 `form:"id" json:"id,omitempty"`
|
||||
}
|
||||
|
||||
// 返回参数
|
||||
type MwRoleGetInfoResp struct {
|
||||
RoleRec *MwRoleRec `json:"roleRec"`
|
||||
}
|
||||
|
||||
/******************角色更新***********************/
|
||||
// POST /web/role/up
|
||||
|
||||
// 请求参数
|
||||
type MwRoleUpReq struct {
|
||||
// 角色id
|
||||
Id int64 `json:"id"`
|
||||
// 名称
|
||||
Name string `json:"name"`
|
||||
// 描述
|
||||
Desc string `json:"desc"`
|
||||
// 状态
|
||||
IsEnb bool `json:"isEnb"`
|
||||
}
|
||||
|
||||
// 返回参数
|
||||
type MwRoleUpResp struct {
|
||||
// 是否成功 true:成功 false:未成功
|
||||
Result bool `json:"result,omitempty"`
|
||||
}
|
||||
|
||||
/******************角色使能***********************/
|
||||
// POST /web/role/enable
|
||||
|
||||
// 请求参数
|
||||
type MwRoleEnableReq struct {
|
||||
// 角色id
|
||||
Id int64 `json:"id"`
|
||||
// 状态
|
||||
IsEnb bool `json:"isEnb"`
|
||||
}
|
||||
|
||||
// 返回参数
|
||||
type MwRoleEnableResp struct {
|
||||
// 是否成功 true:成功 false:未成功
|
||||
Result bool `json:"result,omitempty"`
|
||||
}
|
||||
|
||||
/******************角色下拉***********************/
|
||||
// GET /web/role/drop
|
||||
|
||||
// 请求参数
|
||||
|
||||
type MwRoleDrop struct {
|
||||
// 角色Id
|
||||
Id int64 `json:"id,omitempty"`
|
||||
// 角色名称
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
// 返回参数
|
||||
type MwRoleDropResp struct {
|
||||
// 是否成功 true:成功 false:未成功
|
||||
RoleDrop []*MwRoleDrop `json:"roleDrop"`
|
||||
}
|
||||
|
||||
/******************获取权限***********************/
|
||||
// GET /web/role/getauth
|
||||
|
||||
type Router_Meta struct {
|
||||
//
|
||||
Title string `json:"title"`
|
||||
//
|
||||
Icon string `json:"icon"`
|
||||
//
|
||||
NoCache bool `json:"noCache"`
|
||||
}
|
||||
|
||||
type Router_ApiUrl struct {
|
||||
//
|
||||
Url []string `json:"url,omitempty"`
|
||||
//
|
||||
Desc string `json:"desc,omitempty"`
|
||||
//
|
||||
Status bool `json:"status,omitempty"`
|
||||
//
|
||||
Method []string `json:"method,omitempty"`
|
||||
}
|
||||
|
||||
type Router struct {
|
||||
//
|
||||
Path string `json:"path"`
|
||||
//
|
||||
Component string `json:"component"`
|
||||
//
|
||||
Redirect string `json:"redirect"`
|
||||
//
|
||||
Name string `json:"name"`
|
||||
//
|
||||
IsShow bool `json:"isShow"`
|
||||
//
|
||||
Hidden bool `json:"hidden"`
|
||||
//
|
||||
Meta *Router_Meta `json:"meta"`
|
||||
//
|
||||
Children []*Router `json:"children"`
|
||||
ApiUrl []*Router_ApiUrl `json:"apiUrl"`
|
||||
}
|
||||
|
||||
// 请求参数
|
||||
type MwRoleGetAuthReq struct {
|
||||
// 角色id
|
||||
Id int64 `form:"id" json:"id,omitempty"`
|
||||
}
|
||||
|
||||
// 返回参数
|
||||
type MwRoleGetAuthResp struct {
|
||||
// 角色id
|
||||
Id int64 `json:"id,omitempty"`
|
||||
//
|
||||
Router []*Router `json:"router,omitempty"`
|
||||
}
|
||||
|
||||
/******************更新权限***********************/
|
||||
// POST /web/role/upauth
|
||||
|
||||
// 请求参数
|
||||
type MwRoleUpAuthReq struct {
|
||||
// 角色id
|
||||
Id int64 `json:"id,omitempty"`
|
||||
Router []*Router `json:"router,omitempty"`
|
||||
}
|
||||
|
||||
// 返回参数
|
||||
type MwRoleUpAuthResp struct {
|
||||
// 是否成功 true:成功 false:未成功
|
||||
Result bool `json:"result,omitempty"`
|
||||
}
|
||||
|
||||
/////////////////////////账号//////////////////////////
|
||||
|
||||
type MwAccRec struct {
|
||||
// 账号Id
|
||||
Id int64 `json:"id"`
|
||||
// 用户名
|
||||
UserName string `json:"userName"`
|
||||
// 账号
|
||||
Acc string `json:"acc"`
|
||||
// 邮箱
|
||||
Email string `json:"email"`
|
||||
// 角色Id
|
||||
RoleId int64 `json:"roleId"`
|
||||
// 角色名
|
||||
RoleName string `json:"roleName"`
|
||||
// // 二步签名
|
||||
// Base32 string `json:"base32"`
|
||||
// 是否已签名
|
||||
IsBase32 bool `json:"isBase32"`
|
||||
// 使能
|
||||
IsEnb bool `json:"isEnb"`
|
||||
//禁用原因
|
||||
FeedBack string `json:"feedBack"`
|
||||
// 创建时间
|
||||
CreatedAt int64 `json:"createdAt"`
|
||||
// 更新时间
|
||||
UpdatedAt int64 `json:"updatedAt"`
|
||||
// 允许访问的IP
|
||||
LimitIP []string `json:"limitIP"`
|
||||
}
|
||||
|
||||
/******************账号列表***********************/
|
||||
// GET /web/acc/list
|
||||
|
||||
// 请求参数
|
||||
type MwAccListReq struct {
|
||||
// 搜索条件
|
||||
KeyWords string `json:"keyWords" form:"keyWords"`
|
||||
//状态 1正常 2 禁用
|
||||
Status int64 `json:"status" form:"status"`
|
||||
// 页码
|
||||
pubdef.Page
|
||||
}
|
||||
|
||||
// 返回参数
|
||||
type MwAccListResp struct {
|
||||
// 总共数量
|
||||
TotalCount int64 `json:"totalCount"`
|
||||
// 当前页配置记录
|
||||
AccRec []*MwAccRec `json:"accRec"`
|
||||
}
|
||||
|
||||
/******************账号添加***********************/
|
||||
// POST /web/acc/add
|
||||
|
||||
// 请求参数
|
||||
type MwAccAddReq struct {
|
||||
// 名称
|
||||
Name string `json:"name"`
|
||||
// 密码
|
||||
Pwd string `json:"pwd"`
|
||||
// 账户
|
||||
Acc string `json:"acc"`
|
||||
// 邮箱
|
||||
Email string `json:"email"`
|
||||
// 角色ID
|
||||
RoleId int64 `json:"roleId"`
|
||||
// 使能
|
||||
IsEnb bool `json:"isEnb"`
|
||||
// 允许访问的IP
|
||||
LimitIP []string `json:"limitIP"`
|
||||
}
|
||||
|
||||
type MwAccAddResp struct {
|
||||
// 是否成功 true:成功 false:未成功
|
||||
Result bool `json:"result,omitempty"`
|
||||
}
|
||||
|
||||
/******************账号删除***********************/
|
||||
// POST web/mw/acc/del
|
||||
|
||||
// 请求参数
|
||||
type MwAccDelReq struct {
|
||||
// 账号Id
|
||||
Id int64 `json:"id,omitempty"`
|
||||
}
|
||||
|
||||
// 返回参数
|
||||
type MwAccDelResp struct {
|
||||
// 是否成功 true:成功 false:未成功
|
||||
Result bool `json:"result,omitempty"`
|
||||
}
|
||||
|
||||
/******************账号获取信息***********************/
|
||||
// GET /web/acc/getinfo
|
||||
// 请求参数
|
||||
type MwAccGetInfoReq struct {
|
||||
// 角色id
|
||||
Id int64 `form:"id" json:"id,omitempty"`
|
||||
}
|
||||
|
||||
// 返回参数
|
||||
type MwAccGetInfoResp struct {
|
||||
// 账号Id
|
||||
Id int64 `json:"id"`
|
||||
// 用户名
|
||||
UserName string `json:"userName"`
|
||||
// 账号
|
||||
Acc string `json:"acc"`
|
||||
// 密码
|
||||
Pwd string `json:"pwd"`
|
||||
// 邮箱
|
||||
Email string `json:"email"`
|
||||
// 角色Id
|
||||
RoleId int64 `json:"roleId"`
|
||||
// 使能
|
||||
IsEnb bool `json:"isEnb"`
|
||||
// 允许访问的IP
|
||||
LimitIP []string `json:"limitIP"`
|
||||
}
|
||||
|
||||
/******************角色更新***********************/
|
||||
// POST web/mw/acc/up
|
||||
|
||||
// 请求参数
|
||||
type MwAccUpReq struct {
|
||||
// 账号Id
|
||||
Id int64 `json:"id"`
|
||||
// 用户名
|
||||
UserName string `json:"userName"`
|
||||
// 账号
|
||||
Acc string `json:"acc"`
|
||||
// 密码
|
||||
Pwd string `json:"pwd"`
|
||||
// 邮箱
|
||||
Email string `json:"email"`
|
||||
// 角色Id
|
||||
RoleId int64 `json:"roleId"`
|
||||
// 使能
|
||||
IsEnb bool `json:"isEnb"`
|
||||
// 允许访问的IP
|
||||
LimitIP []string `json:"limitIP"`
|
||||
}
|
||||
|
||||
// 返回参数
|
||||
type MwAccUpResp struct {
|
||||
// 是否成功 true:成功 false:未成功
|
||||
Result bool `json:"result,omitempty"`
|
||||
}
|
||||
|
||||
/******************账号获取状态***********************/
|
||||
// GET web/mw/acc/getstatus
|
||||
|
||||
// 请求参数
|
||||
type MwAccGetStatusReq struct {
|
||||
// 角色id
|
||||
Id int64 `form:"id" json:"id,omitempty"`
|
||||
}
|
||||
|
||||
// 返回参数
|
||||
type MwAccGetStatusResp struct {
|
||||
|
||||
// 账号Id
|
||||
Id int64 `json:"id"`
|
||||
// 用户名
|
||||
UserName string `json:"userName"`
|
||||
// 使能
|
||||
IsEnb bool `json:"isEnb"`
|
||||
//禁用原因
|
||||
FeedBack string `json:"feedBack"`
|
||||
}
|
||||
|
||||
/******************账号保存状态***********************/
|
||||
// POST web/mw/acc/savestatus
|
||||
// 请求参数
|
||||
type MwAccSaveStatusReq struct {
|
||||
// 账号Id
|
||||
Id int64 `json:"id"`
|
||||
// 用户名
|
||||
UserName string `json:"userName"`
|
||||
// 使能
|
||||
IsEnb bool `json:"isEnb"`
|
||||
//禁用原因
|
||||
FeedBack string `json:"feedBack"`
|
||||
}
|
||||
|
||||
// 返回参数
|
||||
type MwAccSaveStatusResp struct {
|
||||
// 是否成功 true:成功 false:未成功
|
||||
Result bool `json:"result,omitempty"`
|
||||
}
|
||||
|
||||
/******************获取账号操作列表***********************/
|
||||
// POST web/acc/ops
|
||||
// 请求参数
|
||||
type AccOpLogReq struct {
|
||||
srv_acc.OpLogSearch
|
||||
}
|
||||
|
||||
// AccOpLogResp 返回参数
|
||||
type AccOpLogResp struct {
|
||||
Total int64 `json:"total" bson:"total"`
|
||||
List []*srv_acc.OpLogInfo `json:"list" bson:"list"`
|
||||
}
|
||||
|
||||
// 修改账号密码
|
||||
type MwAccUpPwdReq struct {
|
||||
// 账号Id
|
||||
Id int64 `json:"id" binding:"required"`
|
||||
// 密码
|
||||
Pwd string `json:"pwd"`
|
||||
}
|
||||
|
||||
type MwAccUpPwdResp struct {
|
||||
// 是否成功 true:成功 false:未成功
|
||||
Result bool `json:"result,omitempty"`
|
||||
}
|
||||
@@ -0,0 +1,400 @@
|
||||
package web_acc
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/pageopt"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/models/mwacc"
|
||||
"videoweb/pub/pubdef"
|
||||
"videoweb/web/service/srv_mwacc"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
// @Tags 角色
|
||||
// @Summary 角色-列表
|
||||
// @Description 角色-列表
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body pubdef.Page true "参数列表"
|
||||
// @Success 200 {object} MwRoleListResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/role/list [GET]
|
||||
func RoleGetList(c *gin.Context) {
|
||||
var req pubdef.Page
|
||||
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
if req.PageNum <= 0 {
|
||||
req.PageNum = 1
|
||||
}
|
||||
if req.PageSize <= 0 {
|
||||
req.PageSize = 10
|
||||
}
|
||||
|
||||
skip := (req.PageNum - 1) * req.PageSize
|
||||
limit := req.PageSize
|
||||
|
||||
// 获取分页信息
|
||||
var mats []pageopt.Matcher
|
||||
dbRoleRec, err := mwacc.GetRoleList(c, skip, limit, mats...)
|
||||
if err != nil {
|
||||
common.ServerJSON(c, srvdef.Failure, "")
|
||||
return
|
||||
}
|
||||
|
||||
// 获取总条数
|
||||
roleCount, err := mwacc.RoleCountByFilter(c, bson.M{})
|
||||
|
||||
if err != nil {
|
||||
common.ServerJSON(c, srvdef.Failure, "")
|
||||
return
|
||||
}
|
||||
|
||||
webRoleRec := make([]*MwRoleRec, 0)
|
||||
for _, v := range dbRoleRec {
|
||||
webRoleRec = append(webRoleRec, &MwRoleRec{
|
||||
Id: v.Id,
|
||||
Name: v.Name,
|
||||
Desc: v.Desc,
|
||||
IsEnb: v.IsEnb,
|
||||
ApiMenus: v.ApiMenus[:],
|
||||
CreatedAt: v.CreatedAt,
|
||||
UpdatedAt: v.UpdatedAt,
|
||||
})
|
||||
}
|
||||
|
||||
// 返回正确信息
|
||||
common.ServerJSON(c, srvdef.Success, MwRoleListResp{TotalCount: roleCount, RoleRecs: webRoleRec})
|
||||
return
|
||||
}
|
||||
|
||||
// @Tags 角色
|
||||
// @Summary 角色-添加
|
||||
// @Description 角色-添加
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body MwRoleAddReq true "参数列表"
|
||||
// @Success 200 {object} MwRoleAddResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/role/add [POST]
|
||||
func RoleAdd(c *gin.Context) {
|
||||
var req MwRoleAddReq
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
ok, _ := mwacc.RoleAdd(c, req.Name, req.Desc, req.IsEnb)
|
||||
if !ok {
|
||||
common.ServerJSON(c, srvdef.Failure, "")
|
||||
return
|
||||
}
|
||||
// 返回正确信息
|
||||
common.ServerJSON(c, srvdef.Success, MwRoleAddResp{Result: true})
|
||||
return
|
||||
}
|
||||
|
||||
// @Tags 角色
|
||||
// @Summary 角色-删除
|
||||
// @Description 角色-删除
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body MwRoleDelReq true "参数列表"
|
||||
// @Success 200 {object} MwRoleDelResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/role/del [POST]
|
||||
func RoleDel(c *gin.Context) {
|
||||
var req MwRoleDelReq
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
ok, err := srv_mwacc.RoleDel(c, req.Id)
|
||||
if !ok {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(c, srvdef.Success, MwRoleDelResp{Result: true})
|
||||
return
|
||||
}
|
||||
|
||||
// @Tags 角色
|
||||
// @Summary 角色-获取信息
|
||||
// @Description 角色-获取信息
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body MwRoleGetInfoReq true "参数列表"
|
||||
// @Success 200 {object} MwRoleGetInfoResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/role/getinfo [GET]
|
||||
func RoleGetInfo(c *gin.Context) {
|
||||
|
||||
var req MwRoleGetInfoReq
|
||||
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
roleInfo, err := srv_mwacc.RoleGetInfo(c, req.Id)
|
||||
|
||||
if err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
resq := &MwRoleGetInfoResp{
|
||||
RoleRec: &MwRoleRec{
|
||||
Id: roleInfo.Id,
|
||||
Name: roleInfo.Name,
|
||||
Desc: roleInfo.Desc,
|
||||
IsEnb: roleInfo.IsEnb,
|
||||
ApiMenus: roleInfo.ApiMenus[:],
|
||||
CreatedAt: roleInfo.CreatedAt,
|
||||
UpdatedAt: roleInfo.UpdatedAt,
|
||||
},
|
||||
}
|
||||
common.ServerJSON(c, srvdef.Success, resq)
|
||||
return
|
||||
}
|
||||
|
||||
// @Tags 角色
|
||||
// @Summary 角色-更新
|
||||
// @Description 角色-更新
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body MwRoleUpReq true "参数列表"
|
||||
// @Success 200 {object} MwRoleUpResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/role/up [POST]
|
||||
func RoleUp(c *gin.Context) {
|
||||
|
||||
var req MwRoleUpReq
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// RoleUp
|
||||
_, err := srv_mwacc.RoleUp(c, req.Id, req.Name, req.Desc, req.IsEnb)
|
||||
if err != nil {
|
||||
common.ServerJSON(c, srvdef.Failure, MwRoleUpResp{Result: false})
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(c, srvdef.Success, MwRoleUpResp{Result: true})
|
||||
return
|
||||
}
|
||||
|
||||
// @Tags 角色
|
||||
// @Summary 角色-使能
|
||||
// @Description 角色-使能
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body MwRoleEnableReq true "参数列表"
|
||||
// @Success 200 {object} MwRoleEnableResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/role/enable [POST]
|
||||
func RoleEnable(c *gin.Context) {
|
||||
|
||||
var req MwRoleEnableReq
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
_, err := srv_mwacc.RoleEnable(c, req.Id, req.IsEnb)
|
||||
if err != nil {
|
||||
common.ServerJSON(c, err.Code, err.Msg)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(c, srvdef.Success, MwRoleEnableResp{Result: true})
|
||||
return
|
||||
}
|
||||
|
||||
// @Tags 角色
|
||||
// @Summary 角色-下拉列表
|
||||
// @Description 角色-下拉列表
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} MwRoleDropResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/role/drop [POST]
|
||||
func RoleGetDrop(c *gin.Context) {
|
||||
data, _ := mwacc.RoleDrop(c)
|
||||
|
||||
roleDropArr := make([]*MwRoleDrop, 0)
|
||||
for _, v := range data {
|
||||
roleDropArr = append(roleDropArr, &MwRoleDrop{Id: v.Id, Name: v.Name})
|
||||
}
|
||||
common.ServerJSON(c, srvdef.Success, MwRoleDropResp{RoleDrop: roleDropArr})
|
||||
return
|
||||
}
|
||||
|
||||
func DbRouterToWebRouter(dbRouter *mwacc.Router) (webRouter *Router) {
|
||||
if dbRouter == nil {
|
||||
return
|
||||
}
|
||||
|
||||
webRouter = &Router{
|
||||
Path: dbRouter.Path,
|
||||
Component: dbRouter.Component,
|
||||
Redirect: dbRouter.Redirect,
|
||||
Name: dbRouter.Name,
|
||||
IsShow: dbRouter.IsShow,
|
||||
Hidden: dbRouter.Hidden,
|
||||
Meta: &Router_Meta{
|
||||
Title: dbRouter.Meta.Title,
|
||||
Icon: dbRouter.Meta.Icon,
|
||||
NoCache: dbRouter.Meta.NoCache,
|
||||
},
|
||||
Children: make([]*Router, 0),
|
||||
ApiUrl: make([]*Router_ApiUrl, 0),
|
||||
}
|
||||
for _, v := range dbRouter.Children {
|
||||
webRouter.Children = append(webRouter.Children, DbRouterToWebRouter(&v))
|
||||
}
|
||||
for _, v := range dbRouter.ApiUrl {
|
||||
webRouter.ApiUrl = append(webRouter.ApiUrl, &Router_ApiUrl{
|
||||
Url: v.Url[:],
|
||||
Desc: v.Desc,
|
||||
Status: v.Status,
|
||||
Method: v.Method[:],
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// @Tags 角色
|
||||
// @Summary 角色-获取权限
|
||||
// @Description 角色-获取权限
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body MwRoleGetAuthReq true "参数列表"
|
||||
// @Success 200 {object} MwRoleGetAuthResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/role/getauth [GET]
|
||||
func RoleGetAuth(c *gin.Context) {
|
||||
var req MwRoleGetAuthReq
|
||||
|
||||
if err := c.ShouldBindQuery(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
roleInfo, err := srv_mwacc.RoleGetInfo(c, req.Id)
|
||||
if err != nil {
|
||||
common.ServerJSON(c, srvdef.Failure, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if roleInfo == nil {
|
||||
common.ServerJSON(c, srvdef.Failure, "没找到角色")
|
||||
return
|
||||
}
|
||||
|
||||
if roleInfo.Id == 0 {
|
||||
common.ServerJSON(c, srvdef.Failure, "没找到角色2")
|
||||
return
|
||||
}
|
||||
|
||||
resq := &MwRoleGetAuthResp{
|
||||
Id: req.Id,
|
||||
Router: make([]*Router, 0),
|
||||
}
|
||||
|
||||
for _, v := range roleInfo.Router {
|
||||
|
||||
resq.Router = append(resq.Router, DbRouterToWebRouter(&v))
|
||||
}
|
||||
|
||||
common.ServerJSON(c, srvdef.Success, resq)
|
||||
return
|
||||
}
|
||||
|
||||
// 网站Router转数据库Router
|
||||
func WebRouterToDbRouter(webRouter *Router) (dbRouter *mwacc.Router) {
|
||||
|
||||
if webRouter == nil {
|
||||
return
|
||||
}
|
||||
|
||||
dbRouter = &mwacc.Router{
|
||||
Path: webRouter.Path,
|
||||
Component: webRouter.Component,
|
||||
Redirect: webRouter.Redirect,
|
||||
Name: webRouter.Name,
|
||||
IsShow: webRouter.IsShow,
|
||||
Hidden: webRouter.Hidden,
|
||||
Meta: mwacc.Meta{
|
||||
Title: webRouter.Meta.Title,
|
||||
Icon: webRouter.Meta.Icon,
|
||||
NoCache: webRouter.Meta.NoCache,
|
||||
},
|
||||
Children: make([]mwacc.Router, 0),
|
||||
ApiUrl: make([]mwacc.Apiurl, 0),
|
||||
}
|
||||
for _, v := range webRouter.Children {
|
||||
dbRouter.Children = append(dbRouter.Children, *WebRouterToDbRouter(v))
|
||||
}
|
||||
for _, v := range webRouter.ApiUrl {
|
||||
dbRouter.ApiUrl = append(dbRouter.ApiUrl, mwacc.Apiurl{
|
||||
Url: v.Url[:],
|
||||
Desc: v.Desc,
|
||||
Status: v.Status,
|
||||
Method: v.Method[:],
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// @Tags 角色
|
||||
// @Summary 角色-更新权限
|
||||
// @Description 角色-更新权限
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body MwRoleUpAuthReq true "参数列表"
|
||||
// @Success 200 {object} MwRoleUpAuthResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/role/upauth [GET]
|
||||
func RoleUpAuth(c *gin.Context) {
|
||||
|
||||
var req MwRoleUpAuthReq
|
||||
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
dataSave := make([]*mwacc.Router, 0)
|
||||
for _, v := range req.Router {
|
||||
dataSave = append(dataSave, WebRouterToDbRouter(v))
|
||||
}
|
||||
|
||||
_, err := srv_mwacc.UpAuth(c, req.Id, dataSave)
|
||||
if err != nil {
|
||||
common.ServerJSON(c, srvdef.Failure, MwRoleUpAuthResp{Result: false})
|
||||
return
|
||||
}
|
||||
|
||||
// auth.ClearRoleMap()
|
||||
common.ServerJSON(c, srvdef.Success, MwRoleUpAuthResp{Result: true})
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
package webanalytics
|
||||
|
||||
import (
|
||||
"time"
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/common/utils"
|
||||
"videoweb/pub/models/analyticsdailystat"
|
||||
"videoweb/pub/models/analyticsstat"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
// @Tags 获取统计数据
|
||||
// @Summary 统计数据
|
||||
// @Description 统计数据
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} webanalytics.AnalyticsStat "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/stat/analytics [POST]
|
||||
func GetAnalyticsStat(ctx *gin.Context) {
|
||||
// 当日数据
|
||||
resp := AnalyticsStat{
|
||||
TodayList: make([]LastWebStatInfo, 0),
|
||||
WeekList: make([]LastWebStatInfo, 0),
|
||||
YestodayList: make([]LastWebStatInfo, 0),
|
||||
}
|
||||
now := time.Now()
|
||||
curStatTime := utils.RecentMinute(now, 30) // 按20分钟对齐
|
||||
YestodayTime := curStatTime.AddDate(0, 0, -1)
|
||||
WeekTime := curStatTime.AddDate(0, 0, -7)
|
||||
|
||||
dailyFilter := bson.M{
|
||||
analyticsdailystat.FN.AnalyticsDailyInfo.SumDate: bson.M{"$gt": now.AddDate(0, -1, -1)},
|
||||
}
|
||||
dailyStatList, _ := analyticsdailystat.FindManyAnalyticsDailyInfo(ctx, dailyFilter)
|
||||
|
||||
curFilter := bson.M{
|
||||
analyticsstat.FN.AnalyticsInfo.SumDate: curStatTime,
|
||||
}
|
||||
statList, _ := analyticsstat.FindManyAnalyticsInfo(ctx, curFilter)
|
||||
for _, statInfo := range statList {
|
||||
appStatInfo := LastWebStatInfo{
|
||||
SumDate: statInfo.SumDate,
|
||||
AppId: statInfo.AppId,
|
||||
AppName: statInfo.AppName,
|
||||
ActiveUsers: statInfo.ActiveUsers,
|
||||
YestodayPV: statInfo.YestodayPV,
|
||||
YestodayUV: statInfo.YestodayUV,
|
||||
YestodayActiveUsers: statInfo.YestodayActiveUsers,
|
||||
YestodaySessions: statInfo.YestodaySessions,
|
||||
YestodayNewUsers: statInfo.YestodayNewUsers,
|
||||
}
|
||||
for _, dailyStatInfo := range dailyStatList {
|
||||
if dailyStatInfo.SumDate.Equal(statInfo.DaySumDate) && dailyStatInfo.AppId == statInfo.AppId {
|
||||
appStatInfo.LeadNewCount = dailyStatInfo.LeadNewCount
|
||||
appStatInfo.LeadAmount = dailyStatInfo.LeadAmount
|
||||
}
|
||||
}
|
||||
resp.TodayList = append(resp.TodayList, appStatInfo)
|
||||
}
|
||||
|
||||
yesFilter := bson.M{
|
||||
analyticsstat.FN.AnalyticsInfo.SumDate: YestodayTime,
|
||||
}
|
||||
statList, _ = analyticsstat.FindManyAnalyticsInfo(ctx, yesFilter)
|
||||
for _, statInfo := range statList {
|
||||
appStatInfo := LastWebStatInfo{
|
||||
SumDate: statInfo.SumDate,
|
||||
AppId: statInfo.AppId,
|
||||
AppName: statInfo.AppName,
|
||||
ActiveUsers: statInfo.ActiveUsers,
|
||||
YestodayPV: statInfo.YestodayPV,
|
||||
YestodayUV: statInfo.YestodayUV,
|
||||
YestodayActiveUsers: statInfo.YestodayActiveUsers,
|
||||
YestodaySessions: statInfo.YestodaySessions,
|
||||
YestodayNewUsers: statInfo.YestodayNewUsers,
|
||||
}
|
||||
for _, dailyStatInfo := range dailyStatList {
|
||||
if dailyStatInfo.SumDate.Equal(statInfo.DaySumDate) && dailyStatInfo.AppId == statInfo.AppId {
|
||||
appStatInfo.LeadNewCount = dailyStatInfo.LeadNewCount
|
||||
appStatInfo.LeadAmount = dailyStatInfo.LeadAmount
|
||||
}
|
||||
}
|
||||
resp.YestodayList = append(resp.YestodayList, appStatInfo)
|
||||
}
|
||||
|
||||
weekFilter := bson.M{
|
||||
analyticsstat.FN.AnalyticsInfo.SumDate: WeekTime,
|
||||
}
|
||||
statList, _ = analyticsstat.FindManyAnalyticsInfo(ctx, weekFilter)
|
||||
for _, statInfo := range statList {
|
||||
appStatInfo := LastWebStatInfo{
|
||||
SumDate: statInfo.SumDate,
|
||||
AppId: statInfo.AppId,
|
||||
AppName: statInfo.AppName,
|
||||
ActiveUsers: statInfo.ActiveUsers,
|
||||
YestodayPV: statInfo.YestodayPV,
|
||||
YestodayUV: statInfo.YestodayUV,
|
||||
YestodayActiveUsers: statInfo.YestodayActiveUsers,
|
||||
YestodaySessions: statInfo.YestodaySessions,
|
||||
YestodayNewUsers: statInfo.YestodayNewUsers,
|
||||
}
|
||||
for _, dailyStatInfo := range dailyStatList {
|
||||
if dailyStatInfo.SumDate.Equal(statInfo.DaySumDate) && dailyStatInfo.AppId == statInfo.AppId {
|
||||
appStatInfo.LeadNewCount = dailyStatInfo.LeadNewCount
|
||||
appStatInfo.LeadAmount = dailyStatInfo.LeadAmount
|
||||
}
|
||||
}
|
||||
resp.WeekList = append(resp.WeekList, appStatInfo)
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// @Tags 获取统计数据
|
||||
// @Summary 统计数据
|
||||
// @Description 统计数据
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} webanalytics.AnalyticsDailyStat "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/stat/daily/analytics [POST]
|
||||
func GetAnalyticsDailyStat(ctx *gin.Context) {
|
||||
// 当日数据
|
||||
resp := AnalyticsDailyStat{
|
||||
List: make([]LastWebStatInfo, 0),
|
||||
}
|
||||
now := time.Now()
|
||||
|
||||
curFilter := bson.M{
|
||||
analyticsdailystat.FN.AnalyticsDailyInfo.SumDate: bson.M{"$gt": utils.BeginOfMonth(now.AddDate(0, 0, -1)), "$lte": now},
|
||||
}
|
||||
statList, _ := analyticsdailystat.FindManyAnalyticsDailyInfo(ctx, curFilter)
|
||||
for _, statInfo := range statList {
|
||||
appStatInfo := LastWebStatInfo{
|
||||
SumDate: statInfo.SumDate,
|
||||
AppId: statInfo.AppId,
|
||||
AppName: statInfo.AppName,
|
||||
YestodayPV: statInfo.YestodayPV,
|
||||
YestodayUV: statInfo.YestodayUV,
|
||||
YestodayActiveUsers: statInfo.YestodayActiveUsers,
|
||||
YestodaySessions: statInfo.YestodaySessions,
|
||||
YestodayNewUsers: statInfo.YestodayNewUsers,
|
||||
LeadNewCount: statInfo.LeadNewCount,
|
||||
LeadAmount: statInfo.LeadAmount,
|
||||
}
|
||||
resp.List = append(resp.List, appStatInfo)
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package webanalytics
|
||||
|
||||
import "time"
|
||||
|
||||
type LastWebStatInfo struct {
|
||||
SumDate time.Time `json:"sumDate" bson:"sumDate"` // 时间半小时
|
||||
AppName string `json:"appName" bson:"appName"` // APP名称
|
||||
AppId int64 `json:"appId" bson:"appId"` // appId
|
||||
ActiveUsers int64 `json:"activeUsers" bson:"activeUsers"` // 最近半小时活跃数
|
||||
YestodayPV int64 `json:"yestodayPV" bson:"yestodayPV"` // 页面浏览量 (PV)
|
||||
YestodayUV int64 `json:"yestodayUV" bson:"yestodayUV"` // 独立用户数 (UV)
|
||||
YestodayActiveUsers int64 `json:"yestodayActiveUsers" bson:"yestodayActiveUsers"` // 活跃用户数
|
||||
YestodaySessions int64 `json:"yestodaySessions" bson:"yestodaySessions"` // 会话数
|
||||
YestodayNewUsers int64 `json:"yestodayNewUsers" bson:"yestodayNewUsers"` // 新增数量
|
||||
LeadNewCount float64 `json:"leadNewCount" bson:"leadNewCount"` // 日导量新增
|
||||
LeadAmount float64 `json:"leadAmount" bson:"leadAmount"` // 日导量充值
|
||||
}
|
||||
|
||||
type AnalyticsStat struct {
|
||||
TodayList []LastWebStatInfo `json:"todayList"` //当日数据
|
||||
WeekList []LastWebStatInfo `json:"weekList"` //环比数据
|
||||
YestodayList []LastWebStatInfo `json:"yestodayList"` //同比数据
|
||||
}
|
||||
type AnalyticsDailyStat struct {
|
||||
List []LastWebStatInfo `json:"list"` //当月数据
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package web_announcement
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/service/srv_announcement"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// AnnouncementList
|
||||
// @Tags 公告
|
||||
// @Summary 公告-列表
|
||||
// @Description 公告-列表
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_announcement.GetAnnouncementListReq true "参数列表"
|
||||
// @Success 200 {object} srv_announcement.GetAnnouncementListResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/announcement/list [POST]
|
||||
func AnnouncementList(c *gin.Context) {
|
||||
var req srv_announcement.GetAnnouncementListReq
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
resp, serr := srv_announcement.GetAnnouncementList(c, &req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(c, serr.Code, "")
|
||||
return
|
||||
}
|
||||
common.ServerJSON(c, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// AnnouncementAdd
|
||||
// @Tags 公告
|
||||
// @Summary 公告-增加
|
||||
// @Description 公告-增加
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_announcement.AddAnnouncementReq true "参数列表"
|
||||
// @Success 200 {object} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/announcement/add [POST]
|
||||
func AnnouncementAdd(c *gin.Context) {
|
||||
var req srv_announcement.AddAnnouncementReq
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
serr := srv_announcement.AddAnnouncement(c, &req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(c, serr.Code, "")
|
||||
return
|
||||
}
|
||||
common.ServerJSON(c, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// AnnouncementDel
|
||||
// @Tags 公告
|
||||
// @Summary 公告-删除
|
||||
// @Description 公告-删除
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_announcement.DelAnnouncementReq true "参数列表"
|
||||
// @Success 200 {object} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/announcement/del [POST]
|
||||
func AnnouncementDel(c *gin.Context) {
|
||||
var req srv_announcement.DelAnnouncementReq
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
serr := srv_announcement.DelAnnouncement(c, &req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(c, serr.Code, "")
|
||||
return
|
||||
}
|
||||
common.ServerJSON(c, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// AnnouncementUpdate
|
||||
// @Tags 公告
|
||||
// @Summary 公告-更新
|
||||
// @Description 公告-更新
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_announcement.UpdateAnnouncementReq true "参数列表"
|
||||
// @Success 200 {object} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/announcement/update [POST]
|
||||
func AnnouncementUpdate(c *gin.Context) {
|
||||
var req srv_announcement.UpdateAnnouncementReq
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
serr := srv_announcement.UpdateAnnouncement(c, &req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(c, serr.Code, "")
|
||||
return
|
||||
}
|
||||
common.ServerJSON(c, srvdef.Success, "")
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package web_card
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/service/srv_viporder"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags 会员卡管理
|
||||
// @Summary 查询充值订单列表
|
||||
// @Description 分页查询充值订单,支持按 OrderType 筛选:1会员 2金币;不传 orderType 则返回全部类型
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_viporder.VipOrderReq true "查询参数"
|
||||
// @Success 200 {object} srv_viporder.VipOrderResp "成功"
|
||||
// @Failure 400 {string} string "参数错误"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/card/order/list [POST]
|
||||
func GetOrders(ctx *gin.Context) {
|
||||
var req srv_viporder.VipOrderReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if req.PageNum < 1 {
|
||||
req.PageNum = 1
|
||||
}
|
||||
if req.PageSize < 1 || req.PageSize > 100 {
|
||||
req.PageSize = 20
|
||||
}
|
||||
|
||||
resp, serr := srv_viporder.GetOrders(ctx, &req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// SyncDistrictCode web端同步历史订单渠道码
|
||||
// @Tags 会员卡管理
|
||||
// @Summary 同步历史订单渠道码
|
||||
// @Description 将历史订单中空的渠道码,按用户当前 districtCode 回填。可重复调用,hasMore 为 true 时继续请求。
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_viporder.SyncDistrictCodeReq false "同步参数"
|
||||
// @Success 200 {object} srv_viporder.SyncDistrictCodeResp "成功"
|
||||
// @Failure 400 {string} string "参数错误"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/card/order/district/sync [POST]
|
||||
func SyncDistrictCode(ctx *gin.Context) {
|
||||
var req srv_viporder.SyncDistrictCodeReq
|
||||
if ctx.Request.ContentLength > 0 {
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
resp, serr := srv_viporder.SyncDistrictCode(ctx, &req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package web_cfg
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/service/srv_cfg"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags 系统配置
|
||||
// @Summary 获取系统配置
|
||||
// @Description 获取系统配置
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body GetSysConfigReq true "参数列表"
|
||||
// @Success 200 {object} GetSysConfigResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/syscfg/get [GET]
|
||||
func GetCfg(ctx *gin.Context) {
|
||||
config, err := srv_cfg.GetSystemConfig(ctx)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Error())
|
||||
return
|
||||
}
|
||||
resp := &GetSysConfigResp{config}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// @Tags 系统配置
|
||||
// @Summary 修改系统配置
|
||||
// @Description 修改系统配置
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body SysConfigUpdateReq true "参数列表"
|
||||
// @Success 200 {object} SysConfigUpdateResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/syscfg/update [POST]
|
||||
func UpdateCfg(ctx *gin.Context) {
|
||||
var req SysConfigUpdateReq
|
||||
if err := ctx.ShouldBind(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
if err := srv_cfg.UpdateSystemConfig(ctx, &req.SysCfgUpdate); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Error())
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, &SysConfigUpdateResp{})
|
||||
}
|
||||
|
||||
// @Tags 系统配置
|
||||
// @Summary 设置媒资库 appKey
|
||||
// @Description 单独设置 sys_cfg.appKey,并刷新内存缓存
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body SetAppKeyReq true "参数列表"
|
||||
// @Success 200 {object} SetAppKeyResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/syscfg/appkey [POST]
|
||||
func SetAppKey(ctx *gin.Context) {
|
||||
var req SetAppKeyReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
if err := srv_cfg.SetAppKey(ctx, req.AppKey); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Error())
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, &SetAppKeyResp{})
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package web_cfg
|
||||
|
||||
import (
|
||||
"videoweb/pub/models/cfg"
|
||||
"videoweb/web/service/srv_cfg"
|
||||
)
|
||||
|
||||
type GetSysConfigReq struct {
|
||||
}
|
||||
|
||||
type GetSysConfigResp struct {
|
||||
*cfg.SysCfg
|
||||
}
|
||||
|
||||
type SysConfigUpdateReq struct {
|
||||
srv_cfg.SysCfgUpdate
|
||||
}
|
||||
type SysConfigUpdateResp struct{}
|
||||
|
||||
type SetAppKeyReq struct {
|
||||
AppKey string `json:"appKey"` // 媒资库 appKey
|
||||
}
|
||||
|
||||
type SetAppKeyResp struct{}
|
||||
@@ -0,0 +1,40 @@
|
||||
package web_coin
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/service/srv_cointrans"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags 金币管理
|
||||
// @Summary 查询金币交易记录
|
||||
// @Description 分页查询金币收支流水,支持按用户、收支方向、交易类型、时间范围筛选
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_cointrans.CoinTransReq true "查询参数"
|
||||
// @Success 200 {object} srv_cointrans.CoinTransResp "成功"
|
||||
// @Failure 400 {string} string "参数错误"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/coin/trans [POST]
|
||||
func GetCoinTrans(ctx *gin.Context) {
|
||||
var req srv_cointrans.CoinTransReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if req.PageNum < 1 {
|
||||
req.PageNum = 1
|
||||
}
|
||||
if req.PageSize < 1 || req.PageSize > 100 {
|
||||
req.PageSize = 20
|
||||
}
|
||||
|
||||
resp, serr := srv_cointrans.GetCoinTrans(ctx, &req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
package web_commend
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/service/srv_commend"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags 评论
|
||||
// @Summary 评论列表
|
||||
// @Description 评论列表
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_commend.CommendSearch true "参数列表"
|
||||
// @Success 200 {object} srv_commend.CommendSearchResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Router /api/web/post/comment/list [POST]
|
||||
func SearchManyCommend(ctx *gin.Context) {
|
||||
var req = &srv_commend.CommendSearch{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
|
||||
resp, serr := srv_commend.SearchComandList(ctx, req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
type CommendDelReq struct {
|
||||
Id int64 `json:"id" binding:"required"`
|
||||
}
|
||||
type CommendDelIpReq struct {
|
||||
Ip string `json:"ip"`
|
||||
}
|
||||
|
||||
// @Tags 评论
|
||||
// @Summary 删除一个评论
|
||||
// @Description 删除一个评论
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body CommendDelReq true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Router /api/web/post/comment/del [POST]
|
||||
func DelCommend(ctx *gin.Context) {
|
||||
var req = &CommendDelReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
serr := srv_commend.DelCommend(ctx, req.Id)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, nil)
|
||||
}
|
||||
|
||||
// @Tags 评论
|
||||
// @Summary 删除一个用户所有评论
|
||||
// @Description 删除一个用户所有评论
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body CommendDelIpReq true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Router /api/web/post/comment/user/del [POST]
|
||||
func DelUserCommend(ctx *gin.Context) {
|
||||
var req = &CommendDelIpReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
serr := srv_commend.DelUserCommend(ctx, req.Ip)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, nil)
|
||||
}
|
||||
|
||||
// @Tags 评论
|
||||
// @Summary 回复评论
|
||||
// @Description 回复评论
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_commend.CommendReplay true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Router /api/web/post/comment/replay [POST]
|
||||
func ReplayPostComment(ctx *gin.Context) {
|
||||
var req = &srv_commend.CommendReplay{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
serr := srv_commend.AddPostComment(ctx, req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, nil)
|
||||
}
|
||||
|
||||
type CommendReviewBatchReq struct {
|
||||
Ids *[]int64 `json:"ids"`
|
||||
ReviewStatus int `json:"reviewStatus"`
|
||||
}
|
||||
|
||||
// @Tags 评论
|
||||
// @Summary 批量审核评论
|
||||
// @Description 批量审核评论
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body CommendReviewBatchReq true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/post/comment/reviewBatch [POST]
|
||||
func ReviewCommendBatch(ctx *gin.Context) {
|
||||
var req = &CommendReviewBatchReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
serr := srv_commend.ReviewCommendBatch(ctx, req.Ids, req.ReviewStatus)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, nil)
|
||||
}
|
||||
|
||||
// @Tags 评论
|
||||
// @Summary 审核评论
|
||||
// @Description 审核评论
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_commend.CommendReviewReq true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/post/comment/review [POST]
|
||||
func ReviewComment(ctx *gin.Context) {
|
||||
var req = &srv_commend.CommendReviewReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
serr := srv_commend.ReviewComment(ctx, req.Id, req.ReviewStatus)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, nil)
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package web_contactus
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/api/proto"
|
||||
"videoweb/web/service/srv_contactus"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// List web端联系我们列表
|
||||
// @Tags web联系我们相关接口
|
||||
// @Summary web端联系我们列表 -- by 旺鸣
|
||||
// @Description 分页查询联系我们列表
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params query proto.ContactUsListReq true "web端联系我们列表请求"
|
||||
// @Success 200 {object} proto.ContactUsListPageResp{list=[]proto.ContactUsListResp} "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/contactus/list [get]
|
||||
func List(ctx *gin.Context) {
|
||||
var req proto.ContactUsListReq
|
||||
if err := ctx.ShouldBindQuery(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_contactus.ListContactUs(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// Handle web端处理联系我们
|
||||
// @Tags web联系我们相关接口
|
||||
// @Summary web端处理联系我们 -- by 旺鸣
|
||||
// @Description 批量更新联系我们处理状态
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.ContactUsHandleReq true "web端联系我们处理请求"
|
||||
// @Success 200 {object} proto.ContactUsHandleResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/contactus/handle [post]
|
||||
func Handle(ctx *gin.Context) {
|
||||
var req proto.ContactUsHandleReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_contactus.HandleContactUs(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package web_detailnav
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/service/srv_detailnav"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// DetailNavList
|
||||
// @Tags 详情页导航配置
|
||||
// @Summary 详情页导航配置-列表
|
||||
// @Description 详情页导航配置-列表
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_detailnav.GetDetailNavListReq true "参数列表"
|
||||
// @Success 200 {object} srv_detailnav.GetDetailNavListResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/detailnav/list [POST]
|
||||
func DetailNavList(c *gin.Context) {
|
||||
var req srv_detailnav.GetDetailNavListReq
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
resp, serr := srv_detailnav.GetDetailNavList(c, &req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(c, serr.Code, "")
|
||||
return
|
||||
}
|
||||
common.ServerJSON(c, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// DetailNavAdd
|
||||
// @Tags 详情页导航配置
|
||||
// @Summary 详情页导航配置-增加
|
||||
// @Description 详情页导航配置-增加
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_detailnav.AddDetailNavReq true "参数列表"
|
||||
// @Success 200 {object} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/detailnav/add [POST]
|
||||
func DetailNavAdd(c *gin.Context) {
|
||||
var req srv_detailnav.AddDetailNavReq
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
serr := srv_detailnav.AddDetailNav(c, &req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(c, serr.Code, "")
|
||||
return
|
||||
}
|
||||
common.ServerJSON(c, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// DetailNavDel
|
||||
// @Tags 详情页导航配置
|
||||
// @Summary 详情页导航配置-删除
|
||||
// @Description 详情页导航配置-删除
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_detailnav.DelDetailNavReq true "参数列表"
|
||||
// @Success 200 {object} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/detailnav/del [POST]
|
||||
func DetailNavDel(c *gin.Context) {
|
||||
var req srv_detailnav.DelDetailNavReq
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
serr := srv_detailnav.DelDetailNav(c, &req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(c, serr.Code, "")
|
||||
return
|
||||
}
|
||||
common.ServerJSON(c, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// DetailNavUpdate
|
||||
// @Tags 详情页导航配置
|
||||
// @Summary 详情页导航配置-更新
|
||||
// @Description 详情页导航配置-更新
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_detailnav.UpdateDetailNavReq true "参数列表"
|
||||
// @Success 200 {object} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/detailnav/update [POST]
|
||||
func DetailNavUpdate(c *gin.Context) {
|
||||
var req srv_detailnav.UpdateDetailNavReq
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
serr := srv_detailnav.UpdateDetailNav(c, &req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(c, serr.Code, "")
|
||||
return
|
||||
}
|
||||
common.ServerJSON(c, srvdef.Success, "")
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package web_feedback
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/api/proto"
|
||||
"videoweb/web/service/srv_feedback"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// List web端意见反馈列表
|
||||
// @Tags web意见反馈相关接口
|
||||
// @Summary web端意见反馈列表 -- by 旺鸣
|
||||
// @Description 分页查询用户意见反馈列表
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params query proto.FeedbackListReq true "web端意见反馈列表请求"
|
||||
// @Success 200 {object} proto.FeedbackListPageResp{list=[]proto.FeedbackListResp} "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/feedback/list [get]
|
||||
func List(ctx *gin.Context) {
|
||||
var req proto.FeedbackListReq
|
||||
if err := ctx.ShouldBindQuery(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_feedback.ListFeedback(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// Handle web端处理意见反馈
|
||||
// @Tags web意见反馈相关接口
|
||||
// @Summary web端处理意见反馈 -- by 旺鸣
|
||||
// @Description 批量更新意见反馈处理状态
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.FeedbackHandleReq true "web端意见反馈处理请求"
|
||||
// @Success 200 {object} proto.FeedbackHandleResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/feedback/handle [post]
|
||||
func Handle(ctx *gin.Context) {
|
||||
var req proto.FeedbackHandleReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_feedback.HandleFeedback(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package web_file
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/log"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/storage"
|
||||
"videoweb/pub/storage/proxy"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags 文件上传
|
||||
// @Summary 图片上传
|
||||
// @Description 图片上传
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param file formData file true "文件"
|
||||
// @Success 200 {object}} UploadImageResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Router /api/web/file/uploadImg [POST]
|
||||
func UploadImage(ctx *gin.Context) {
|
||||
f, err := ctx.FormFile("file")
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
imageUpoadDomain := proxy.BucketImageAddressV2
|
||||
p, err := storage.UploadImage(ctx, f, imageUpoadDomain)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ServerError, err.Error())
|
||||
return
|
||||
}
|
||||
resp := &UploadImageResp{Path: p}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// @Tags 文件上传
|
||||
// @Summary 图片批量上传
|
||||
// @Description 图片批量上传
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param file[] formData file true "文件"
|
||||
// @Success 200 {object}} UploadImagesResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Router /api/web/file/uploadImgs [POST]
|
||||
func UploadImages(ctx *gin.Context) {
|
||||
form, err := ctx.MultipartForm()
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
resp := &UploadImagesResp{
|
||||
Paths: make([]string, 0),
|
||||
}
|
||||
domain := proxy.BucketImageAddressV2
|
||||
|
||||
files := form.File["file[]"]
|
||||
for _, f := range files {
|
||||
fi, err := f.Open()
|
||||
defer func() {
|
||||
_ = fi.Close()
|
||||
}()
|
||||
if err != nil {
|
||||
log.Warn("headers Open file wrong ", log.Any("Error", err))
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
byteData, err := ioutil.ReadAll(fi)
|
||||
if err != nil {
|
||||
log.Warn("request multipart wrong ", log.Any("Error", err))
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
path, err := proxy.UploadImg(f.Filename, byteData, domain)
|
||||
if err != nil {
|
||||
log.Warn("request multipart wrong ", log.Any("Error", err))
|
||||
common.ServerJSON(ctx, srvdef.UploadToFileSrvFailed, err.Error())
|
||||
return
|
||||
}
|
||||
resp.Paths = append(resp.Paths, path)
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package web_file
|
||||
|
||||
type UploadImageResp struct {
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
type UploadImagesResp struct {
|
||||
Paths []string `json:"paths"`
|
||||
}
|
||||
|
||||
type UploadVideoBodyResp struct {
|
||||
Id string `json:"id"` // 文件服返回的上传文件Id
|
||||
VideoUri string `json:"videoUri"` // 文件服返回的视频uri
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package web_homebanner
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/api/proto"
|
||||
"videoweb/web/middleware/auth"
|
||||
"videoweb/web/service/srv_homebanner"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// List 首页banner列表
|
||||
// @Tags web首页banner相关接口
|
||||
// @Summary 首页banner列表 -- by 王鸣
|
||||
// @Description 分页查询首页banner配置
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params query proto.HomeBannerListReq true "首页banner列表请求"
|
||||
// @Success 200 {object} proto.HomeBannerListPageResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/home/banner/list [get]
|
||||
func List(ctx *gin.Context) {
|
||||
var req proto.HomeBannerListReq
|
||||
if err := ctx.ShouldBindQuery(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_homebanner.ListHomeBanner(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// Add 新增首页banner
|
||||
// @Tags web首页banner相关接口
|
||||
// @Summary 新增首页banner -- by 王鸣
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.HomeBannerAddReq true "新增首页banner请求"
|
||||
// @Success 200 {object} proto.HomeBannerAddResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/home/banner/add [post]
|
||||
func Add(ctx *gin.Context) {
|
||||
var req proto.HomeBannerAddReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_homebanner.AddHomeBanner(ctx, &req, auth.GetAccount(ctx))
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// Update 更新首页banner
|
||||
// @Tags web首页banner相关接口
|
||||
// @Summary 更新首页banner -- by 王鸣
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.HomeBannerUpdateReq true "更新首页banner请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/home/banner/update [post]
|
||||
func Update(ctx *gin.Context) {
|
||||
var req proto.HomeBannerUpdateReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_homebanner.UpdateHomeBanner(ctx, &req, auth.GetAccount(ctx)); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// Del 删除首页banner
|
||||
// @Tags web首页banner相关接口
|
||||
// @Summary 删除首页banner -- by 王鸣
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.HomeBannerDelReq true "删除首页banner请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/home/banner/del [post]
|
||||
func Del(ctx *gin.Context) {
|
||||
var req proto.HomeBannerDelReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_homebanner.DelHomeBanner(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package web_homeconfig
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/api/proto"
|
||||
"videoweb/web/service/srv_homeconfig"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// List 首页配置列表
|
||||
// @Tags web首页配置相关接口
|
||||
// @Summary 首页配置列表 -- by 王鸣
|
||||
// @Description 分页查询首页配置
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params query proto.HomeConfigListReq true "首页配置列表请求"
|
||||
// @Success 200 {object} proto.HomeConfigListPageResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/home/config/list [get]
|
||||
func List(ctx *gin.Context) {
|
||||
var req proto.HomeConfigListReq
|
||||
if err := ctx.ShouldBindQuery(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_homeconfig.ListHomeConfig(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// Add 新增首页配置
|
||||
// @Tags web首页配置相关接口
|
||||
// @Summary 新增首页配置 -- by 王鸣
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.HomeConfigAddReq true "新增首页配置请求"
|
||||
// @Success 200 {object} proto.HomeConfigAddResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/home/config/add [post]
|
||||
func Add(ctx *gin.Context) {
|
||||
var req proto.HomeConfigAddReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_homeconfig.AddHomeConfig(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// Update 更新首页配置
|
||||
// @Tags web首页配置相关接口
|
||||
// @Summary 更新首页配置 -- by 王鸣
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.HomeConfigUpdateReq true "更新首页配置请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/home/config/update [post]
|
||||
func Update(ctx *gin.Context) {
|
||||
var req proto.HomeConfigUpdateReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_homeconfig.UpdateHomeConfig(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// Del 删除首页配置
|
||||
// @Tags web首页配置相关接口
|
||||
// @Summary 删除首页配置 -- by 王鸣
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.HomeConfigDelReq true "删除首页配置请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/home/config/del [post]
|
||||
func Del(ctx *gin.Context) {
|
||||
var req proto.HomeConfigDelReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_homeconfig.DelHomeConfig(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package web_ipblack
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/service/srv_ipblack"
|
||||
)
|
||||
|
||||
// IpBlackList
|
||||
// @Tags IP黑名单
|
||||
// @Summary IP黑名单-列表
|
||||
// @Description IP黑名单-列表
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_ipblack.GetIPBlackListReq true "参数列表"
|
||||
// @Success 200 {object} srv_ipblack.GetIPBlackListResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/ipblack/list [POST]
|
||||
func IpBlackList(c *gin.Context) {
|
||||
var req srv_ipblack.GetIPBlackListReq
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
resp, err := srv_ipblack.GetIpBlackList(c, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(c, err.Code, "")
|
||||
return
|
||||
}
|
||||
common.ServerJSON(c, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// IpBlackAdd
|
||||
// @Tags IP黑名单
|
||||
// @Summary IP黑名单-增加
|
||||
// @Description IP黑名单-增加
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_ipblack.AddIPBlackListReq true "参数列表"
|
||||
// @Success 200 {object} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/ipblack/add [POST]
|
||||
func IpBlackAdd(c *gin.Context) {
|
||||
var req srv_ipblack.AddIPBlackListReq
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
err := srv_ipblack.AddIpBlack(c, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(c, err.Code, "")
|
||||
return
|
||||
}
|
||||
common.ServerJSON(c, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// IpBlackDel
|
||||
// @Tags IP黑名单
|
||||
// @Summary IP黑名单-删除
|
||||
// @Description IP黑名单-删除
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_ipblack.DelIpBlackListReq true "参数列表"
|
||||
// @Success 200 {object} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/ipblack/del [POST]
|
||||
func IpBlackDel(c *gin.Context) {
|
||||
var req srv_ipblack.DelIpBlackListReq
|
||||
if err := c.ShouldBind(&req); err != nil {
|
||||
common.ServerJSON(c, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
err := srv_ipblack.DelIpBlack(c, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(c, err.Code, "")
|
||||
return
|
||||
}
|
||||
common.ServerJSON(c, srvdef.Success, "")
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
package web_mediaresource
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/log"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/api/proto"
|
||||
"videoweb/web/service/srv_mediaresource"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// ResourceList web端短剧媒资列表
|
||||
// @Tags web媒资库相关接口
|
||||
// @Summary web端短剧媒资列表 -- by 王鸣
|
||||
// @Description 分页查询短剧媒资列表
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params query proto.PlayletResourceListReq true "短剧媒资列表请求"
|
||||
// @Success 200 {object} proto.PlayletResourceListResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/resource/list [get]
|
||||
func ResourceList(ctx *gin.Context) {
|
||||
var req proto.PlayletResourceListReq
|
||||
if err := ctx.ShouldBindQuery(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_mediaresource.ListPlayletResource(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// ResourceJHList web端嘉华短剧媒资列表
|
||||
// @Tags web媒资库相关接口
|
||||
// @Summary web端嘉华短剧媒资列表 -- by 王鸣
|
||||
// @Description 嘉华短剧媒资列表,固定查询 media_type=5,回填是否已入库,支持按 isAdd 筛选
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params query proto.PlayletResourceJHListReq true "嘉华短剧媒资列表请求"
|
||||
// @Success 200 {object} proto.PlayletResourceJHListResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/resource/jh/list [get]
|
||||
func ResourceJHList(ctx *gin.Context) {
|
||||
var req proto.PlayletResourceJHListReq
|
||||
if err := ctx.ShouldBindQuery(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_mediaresource.ListPlayletJHResource(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// ResourceJHImport web端嘉华短剧媒资入库
|
||||
// @Tags web媒资库相关接口
|
||||
// @Summary web端嘉华短剧媒资入库 -- by 王鸣
|
||||
// @Description 提交嘉华短剧媒资入库任务
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletResourceUseReq true "嘉华短剧媒资入库请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/resource/jh/import [post]
|
||||
func ResourceJHImport(ctx *gin.Context) {
|
||||
var req proto.PlayletResourceUseReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
log.Error("嘉华短剧媒资入库参数绑定失败", log.E(err))
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_mediaresource.ImportPlayletJHResource(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err, "")
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// ResourceJHChapters web端嘉华短剧媒资剧集列表
|
||||
// @Tags web媒资库相关接口
|
||||
// @Summary web端嘉华短剧媒资剧集列表 -- by 王鸣
|
||||
// @Description 按媒资ID查询嘉华短剧剧集信息
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id query int true "媒资中心资源ID"
|
||||
// @Success 200 {object} proto.PlayletResourceChapterListResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/resource/jh/chapters [get]
|
||||
func ResourceJHChapters(ctx *gin.Context) {
|
||||
var req proto.PlayletResourceChapterListReq
|
||||
if err := ctx.ShouldBindQuery(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_mediaresource.ListPlayletJHResourceChapters(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// ResourceImport web端短剧媒资入库
|
||||
// @Tags web媒资库相关接口
|
||||
// @Summary web端短剧媒资入库 -- by 王鸣
|
||||
// @Description 提交媒资入库任务,后台从媒资中心同步短剧详情并写入短剧和章节集合
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletResourceUseReq true "短剧媒资入库请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/resource/import [post]
|
||||
func ResourceImport(ctx *gin.Context) {
|
||||
var req proto.PlayletResourceUseReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
log.Error("短剧媒资入库参数绑定失败", log.E(err))
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_mediaresource.ImportPlayletResource(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err, "")
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// ResourceChapters web端短剧媒资剧集列表
|
||||
// @Tags web媒资库相关接口
|
||||
// @Summary web端短剧媒资剧集列表 -- by 王鸣
|
||||
// @Description 按媒资ID查询剧集信息,复用入库时的 mediaSync 接口
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id query int true "媒资中心资源ID"
|
||||
// @Success 200 {object} proto.PlayletResourceChapterListResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/resource/chapters [get]
|
||||
func ResourceChapters(ctx *gin.Context) {
|
||||
var req proto.PlayletResourceChapterListReq
|
||||
if err := ctx.ShouldBindQuery(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_mediaresource.ListPlayletResourceChapters(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package web_playlet
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/api/proto"
|
||||
"videoweb/web/service/srv_homeconfig"
|
||||
)
|
||||
|
||||
// HomeConfigTopicOptions web端首页题材下拉选项
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端分页查询首页题材可选项
|
||||
// @Description 查询短剧题材;排除其他已启用模块占用的题材,configId用于回显当前配置已选项
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params query proto.HomeTopicOptionsReq true "首页题材选项请求"
|
||||
// @Success 200 {object} proto.HomeTopicOptionsResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/home-config/topic/options [get]
|
||||
func HomeConfigTopicOptions(ctx *gin.Context) {
|
||||
var req proto.HomeTopicOptionsReq
|
||||
if err := ctx.ShouldBindQuery(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_homeconfig.ListHomeTopicOptions(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
@@ -0,0 +1,604 @@
|
||||
package web_playlet
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/api/proto"
|
||||
"videoweb/web/service/srv_mediaresource"
|
||||
"videoweb/web/service/srv_playlet"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// List web端短剧列表
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端短剧列表
|
||||
// @Description 分页查询短剧列表
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params query proto.PlayletListReq true "短剧列表请求"
|
||||
// @Success 200 {object} proto.PlayletListPageResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/list [get]
|
||||
func List(ctx *gin.Context) {
|
||||
var req proto.PlayletListReq
|
||||
if err := ctx.ShouldBindQuery(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_playlet.ListPlaylet(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// Add web端新增短剧
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端新增短剧
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletAddReq true "新增短剧请求"
|
||||
// @Success 200 {object} proto.PlayletAddResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/add [post]
|
||||
func Add(ctx *gin.Context) {
|
||||
var req proto.PlayletAddReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_playlet.AddPlaylet(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// Update web端更新短剧
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端更新短剧
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletUpdateReq true "更新短剧请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/update [post]
|
||||
func Update(ctx *gin.Context) {
|
||||
var req proto.PlayletUpdateReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.UpdatePlaylet(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// Del web端单/批量物理删除短剧
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端单/批量物理删除短剧
|
||||
// @Description 根据短剧ID集合物理删除 playlet 与 playlet_chapter 记录;不删除点赞、收藏、评论、观看记录、解锁记录和支付流水
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletDelReq true "单/批量删除短剧请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/del [post]
|
||||
func Del(ctx *gin.Context) {
|
||||
var req proto.PlayletDelReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.DelPlaylet(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// SetStatus web端单/批量设置短剧上下架
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端单/批量设置短剧上下架 --by 王鸣
|
||||
// @Description 根据短剧ID集合批量更新 playlet 集合 status 字段,传1个ID表示单条设置,传多个ID表示批量设置
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletStatusSetReq true "单/批量设置短剧上下架请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/status/set [post]
|
||||
func SetStatus(ctx *gin.Context) {
|
||||
var req proto.PlayletStatusSetReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.SetPlayletStatus(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// FillOnlineAt web端临时回填已上架但上架时间为空的短剧
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary 临时回填空上架时间
|
||||
// @Description 将已上架且上架时间为空的短剧,上架时间设置为该条修改时间
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} proto.PlayletOnlineAtFillResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/online-at/fill [post]
|
||||
func FillOnlineAt(ctx *gin.Context) {
|
||||
resp, err := srv_playlet.FillEmptyPlayletOnlineAt(ctx)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// SetRecommend web端单/批量设置短剧是否推荐
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端单/批量设置短剧是否推荐 --by 王鸣
|
||||
// @Description 根据短剧ID集合批量更新 playlet 集合 isRecommend 字段,传1个ID表示单条设置,传多个ID表示批量设置
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletRecommendSetReq true "单/批量设置短剧是否推荐请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/recommend/set [post]
|
||||
func SetRecommend(ctx *gin.Context) {
|
||||
var req proto.PlayletRecommendSetReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.SetPlayletRecommend(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// SetFeatured web端单/批量设置短剧是否爆剧
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端单/批量设置短剧是否爆剧 --by 王鸣
|
||||
// @Description 根据短剧ID集合批量更新 playlet 集合 isFeatured 字段,传1个ID表示单条设置,传多个ID表示批量设置
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletFeaturedSetReq true "单/批量设置短剧是否爆剧请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/featured/set [post]
|
||||
func SetFeatured(ctx *gin.Context) {
|
||||
var req proto.PlayletFeaturedSetReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.SetPlayletFeatured(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// SetOperateType web端单/批量设置短剧运营类型
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端单/批量设置短剧运营类型
|
||||
// @Description 根据短剧ID集合批量更新 playlet 集合 operateType 字段,1-短剧 2-漫剧
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletOperateTypeSetReq true "单/批量设置短剧运营类型请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/operate-type/set [post]
|
||||
func SetOperateType(ctx *gin.Context) {
|
||||
var req proto.PlayletOperateTypeSetReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.SetPlayletOperateType(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// SetBanner web端单/批量设置短剧是否显示在首页banner
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端单/批量设置短剧是否显示在首页banner --by 王鸣
|
||||
// @Description 根据短剧ID集合批量更新 playlet 集合 showOnBanner 字段,传1个ID表示单条设置,传多个ID表示批量设置
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletBannerSetReq true "单/批量设置短剧是否显示在首页banner请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/banner/set [post]
|
||||
func SetBanner(ctx *gin.Context) {
|
||||
var req proto.PlayletBannerSetReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.SetPlayletBanner(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// SetTheme web端单/批量设置短剧题材
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端单/批量设置短剧题材 --by 王鸣
|
||||
// @Description 根据短剧ID集合批量更新 playlet 集合 themeIds 字段,传1个ID表示单条设置,传多个ID表示批量设置;themeIds 可设置多个题材
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletThemeSetReq true "单/批量设置短剧题材请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/theme/set [post]
|
||||
func SetTheme(ctx *gin.Context) {
|
||||
var req proto.PlayletThemeSetReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.SetPlayletTheme(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// SetTag web端单/批量设置短剧标签
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端单/批量设置短剧标签 --by 王鸣
|
||||
// @Description 根据短剧ID集合批量更新 playlet 集合 tagIds 字段,传1个ID表示单条设置,传多个ID表示批量设置;tagIds 可设置多个标签,传空数组表示清空标签
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletTagSetReq true "单/批量设置短剧标签请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/tag/set [post]
|
||||
func SetTag(ctx *gin.Context) {
|
||||
var req proto.PlayletTagSetReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.SetPlayletTag(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// SetCategory web端单/批量设置短剧分类
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端单/批量设置短剧分类
|
||||
// @Description 根据短剧ID集合批量更新 playlet 集合 categoryIds 字段,传1个ID表示单条设置,传多个ID表示批量设置;categoryIds 可为空,可设置多个分类,不传或空数组表示清空分类
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletCategorySetReq true "单/批量设置短剧分类请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/category/set [post]
|
||||
func SetCategory(ctx *gin.Context) {
|
||||
var req proto.PlayletCategorySetReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.SetPlayletCategory(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// SetVirtualLike web端单/批量设置短剧虚拟点赞数
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端单/批量设置短剧虚拟点赞数 --by 王鸣
|
||||
// @Description 根据短剧ID集合批量更新 playlet 集合 virtualCountLike 字段,每条短剧从最小值和最大值之间随机取不重复数值入库
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletVirtualLikeSetReq true "单/批量随机设置短剧虚拟点赞数请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/like/virtual/set [post]
|
||||
func SetVirtualLike(ctx *gin.Context) {
|
||||
var req proto.PlayletVirtualLikeSetReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.SetPlayletVirtualLike(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// ChapterList web端章节列表
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端章节列表
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params query proto.PlayletChapterListReq true "章节列表请求"
|
||||
// @Success 200 {object} proto.PlayletChapterListPageResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/chapter/list [get]
|
||||
func ChapterList(ctx *gin.Context) {
|
||||
var req proto.PlayletChapterListReq
|
||||
if err := ctx.ShouldBindQuery(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_playlet.ListPlayletChapter(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// ChapterAdd web端新增章节
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端新增章节
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletChapterAddReq true "新增章节请求"
|
||||
// @Success 200 {object} proto.PlayletChapterAddResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/chapter/add [post]
|
||||
func ChapterAdd(ctx *gin.Context) {
|
||||
var req proto.PlayletChapterAddReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_playlet.AddPlayletChapter(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// ChapterUpdate web端更新章节
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端更新章节
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletChapterUpdateReq true "更新章节请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/chapter/update [post]
|
||||
func ChapterUpdate(ctx *gin.Context) {
|
||||
var req proto.PlayletChapterUpdateReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.UpdatePlayletChapter(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// ChapterDel web端单/批量删除章节
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端单/批量删除章节
|
||||
// @Description 根据章节ID集合删除 playlet_chapter 记录,传1个ID表示单条删除,传多个ID表示批量删除;同时清理该剧集的点赞、收藏、解锁记录
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletChapterDelReq true "单/批量删除章节请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/chapter/del [post]
|
||||
func ChapterDel(ctx *gin.Context) {
|
||||
var req proto.PlayletChapterDelReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.DelPlayletChapter(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// ChapterFillStatus web端回填历史剧集上架状态
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary 回填历史剧集为上架
|
||||
// @Description 将未写 status 字段的历史剧集设为上架,发版后调用一次
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} proto.PlayletChapterStatusFillResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/chapter/status/fill [post]
|
||||
func ChapterFillStatus(ctx *gin.Context) {
|
||||
resp, err := srv_playlet.FillPlayletChapterStatusUp(ctx)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// ChapterSetStatus web端单/批量设置章节上架状态
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端单/批量设置章节上架状态 --by 王鸣
|
||||
// @Description 根据章节ID集合批量更新 playlet_chapter 集合 status 字段,传1个ID表示单条设置,传多个ID表示批量设置
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletChapterStatusSetReq true "单/批量设置章节上架状态请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/chapter/status/set [post]
|
||||
func ChapterSetStatus(ctx *gin.Context) {
|
||||
var req proto.PlayletChapterStatusSetReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.SetPlayletChapterStatus(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// ChapterSetPayType web端单/批量设置章节支付方式
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端单/批量设置章节支付方式 --by 王鸣
|
||||
// @Description 根据章节ID集合批量更新 playlet_chapter 集合 payType 字段,传1个ID表示单条设置,传多个ID表示批量设置
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletChapterPayTypeSetReq true "单/批量设置章节支付方式请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/chapter/pay-type/set [post]
|
||||
func ChapterSetPayType(ctx *gin.Context) {
|
||||
var req proto.PlayletChapterPayTypeSetReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.SetPlayletChapterPayType(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// ChapterSync web端手动同步短剧剧集
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端手动单/批量同步短剧剧集 --by 王鸣
|
||||
// @Description 根据短剧ID集合从媒资中心同步新增剧集,playletIds传1个表示单条同步,传多个表示批量同步,允许已完结短剧补集或修正状态
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletChapterSyncReq true "手动单/批量同步短剧剧集请求"
|
||||
// @Success 200 {object} proto.PlayletChapterSyncResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/chapter/sync [post]
|
||||
func ChapterSync(ctx *gin.Context) {
|
||||
var req proto.PlayletChapterSyncReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_mediaresource.SyncPlayletChapters(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// SetPayType web端单/批量设置短剧默认支付方式
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端单/批量设置短剧默认支付方式
|
||||
// @Description 根据短剧ID集合批量更新 playlet 集合 payType/singleCoins;上架且连载中时,新增剧集默认沿用该设置
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletPayTypeSetReq true "单/批量设置短剧默认支付方式请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/pay-type/set [post]
|
||||
func SetPayType(ctx *gin.Context) {
|
||||
var req proto.PlayletPayTypeSetReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.SetPlayletPayType(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// ResetWatermark web端按短剧ID批量重置剧集水印
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端按短剧ID批量重置剧集水印
|
||||
// @Description 根据短剧ID集合,将其下全部剧集水印状态重置为未处理,并清空水印地址与 media 任务关联;原片地址不变,等待定时任务重新加水印
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletWatermarkResetReq true "批量重置短剧水印请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/watermark/reset [post]
|
||||
func ResetWatermark(ctx *gin.Context) {
|
||||
var req proto.PlayletWatermarkResetReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.ResetPlayletWatermark(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// SyncSlug web端同步历史空 slug
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary 同步历史空 slug
|
||||
// @Description 为题材、标签、分类、短剧、首页配置中空的 slug 按 SEO 关键词或名称自动生成。可重复调用,hasMore 为 true 时继续请求。
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body proto.PlayletSlugSyncReq false "同步参数"
|
||||
// @Success 200 {object} proto.PlayletSlugSyncResp "成功"
|
||||
// @Failure 400 {string} string "参数错误"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/slug/sync [POST]
|
||||
func SyncSlug(ctx *gin.Context) {
|
||||
var req proto.PlayletSlugSyncReq
|
||||
if ctx.Request.ContentLength > 0 {
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
resp, serr := srv_playlet.SyncEmptySlugs(ctx, &req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package web_playlet
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/api/proto"
|
||||
"videoweb/web/service/srv_playlet"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// Sales web端短剧销售数据
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端短剧销售数据
|
||||
// @Description 按北京时间区间汇总金币解锁、短剧点赞、短剧收藏,最多返回前50条
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params query proto.PlayletSalesReq true "销售数据筛选"
|
||||
// @Success 200 {object} proto.PlayletSalesResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/sales [get]
|
||||
func Sales(ctx *gin.Context) {
|
||||
var req proto.PlayletSalesReq
|
||||
if err := ctx.ShouldBindQuery(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_playlet.ListPlayletSales(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package web_playlet
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/api/proto"
|
||||
"videoweb/web/service/srv_playlet"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// TagList web端标签列表
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端标签列表
|
||||
// @Description 分页查询短剧标签
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params query proto.PlayletTagListReq true "标签列表请求"
|
||||
// @Success 200 {object} proto.PlayletTagListPageResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/tag/list [get]
|
||||
func TagList(ctx *gin.Context) {
|
||||
var req proto.PlayletTagListReq
|
||||
if err := ctx.ShouldBindQuery(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_playlet.ListPlayletTag(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// TagAdd web端新增标签
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端新增标签
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletTagAddReq true "新增标签请求"
|
||||
// @Success 200 {object} proto.PlayletTagAddResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/tag/add [post]
|
||||
func TagAdd(ctx *gin.Context) {
|
||||
var req proto.PlayletTagAddReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_playlet.AddPlayletTag(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// TagUpdate web端更新标签
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端更新标签
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletTagUpdateReq true "更新标签请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/tag/update [post]
|
||||
func TagUpdate(ctx *gin.Context) {
|
||||
var req proto.PlayletTagUpdateReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.UpdatePlayletTag(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// TagDel web端删除标签
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端删除标签
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletTagDelReq true "删除标签请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/tag/del [post]
|
||||
func TagDel(ctx *gin.Context) {
|
||||
var req proto.PlayletTagDelReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.DelPlayletTag(ctx, req.Id); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package web_playlet
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/api/proto"
|
||||
"videoweb/web/service/srv_playlet"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// ThemeList web端题材列表
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端题材列表
|
||||
// @Description 分页查询短剧题材
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params query proto.PlayletThemeListReq true "题材列表请求"
|
||||
// @Success 200 {object} proto.PlayletThemeListPageResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/theme/list [get]
|
||||
func ThemeList(ctx *gin.Context) {
|
||||
var req proto.PlayletThemeListReq
|
||||
if err := ctx.ShouldBindQuery(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_playlet.ListPlayletTheme(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// ThemeAdd web端新增题材
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端新增题材
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletThemeAddReq true "新增题材请求"
|
||||
// @Success 200 {object} proto.PlayletThemeAddResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/theme/add [post]
|
||||
func ThemeAdd(ctx *gin.Context) {
|
||||
var req proto.PlayletThemeAddReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_playlet.AddPlayletTheme(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// ThemeUpdate web端更新题材
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端更新题材
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletThemeUpdateReq true "更新题材请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/theme/update [post]
|
||||
func ThemeUpdate(ctx *gin.Context) {
|
||||
var req proto.PlayletThemeUpdateReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.UpdatePlayletTheme(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// SetThemeRecommend web端单/批量设置题材是否推荐
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端单/批量设置题材是否推荐
|
||||
// @Description 根据题材ID集合批量更新 playlet_theme 集合 isRecommend 字段
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletThemeRecommendSetReq true "单/批量设置题材是否推荐请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/theme/recommend/set [post]
|
||||
func SetThemeRecommend(ctx *gin.Context) {
|
||||
var req proto.PlayletThemeRecommendSetReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.SetPlayletThemeRecommend(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// ThemeDel web端删除题材
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary web端删除题材
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletThemeDelReq true "删除题材请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/theme/del [post]
|
||||
func ThemeDel(ctx *gin.Context) {
|
||||
var req proto.PlayletThemeDelReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.DelPlayletTheme(ctx, req.Id); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package web_playlet
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/api/proto"
|
||||
"videoweb/web/service/srv_playlet"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// TopicGroupList 查询专题区块
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary 查询专题区块
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params query proto.PlayletTopicGroupListReq true "筛选条件"
|
||||
// @Success 200 {object} proto.PlayletTopicGroupListResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/topic-group/list [get]
|
||||
func TopicGroupList(ctx *gin.Context) {
|
||||
var req proto.PlayletTopicGroupListReq
|
||||
if ctx.ShouldBindQuery(&req) != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_playlet.ListPlayletTopicGroups(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// TopicGroupAdd 新增专题区块
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary 新增专题区块
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletTopicGroupAddReq true "区块数据"
|
||||
// @Success 200 {object} proto.PlayletTopicGroupAddResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/topic-group/add [post]
|
||||
func TopicGroupAdd(ctx *gin.Context) {
|
||||
var req proto.PlayletTopicGroupAddReq
|
||||
if ctx.ShouldBindJSON(&req) != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_playlet.AddPlayletTopicGroup(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// TopicGroupUpdate 更新专题区块
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary 更新专题区块
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletTopicGroupUpdateReq true "区块数据"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/topic-group/update [post]
|
||||
func TopicGroupUpdate(ctx *gin.Context) {
|
||||
var req proto.PlayletTopicGroupUpdateReq
|
||||
if ctx.ShouldBindJSON(&req) != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.UpdatePlayletTopicGroup(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// TopicGroupDel 删除专题区块
|
||||
// @Tags web短剧相关接口
|
||||
// @Summary 删除专题区块
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param params body proto.PlayletTopicGroupDeleteReq true "区块ID"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/playlet/topic-group/del [post]
|
||||
func TopicGroupDel(ctx *gin.Context) {
|
||||
var req proto.PlayletTopicGroupDeleteReq
|
||||
if ctx.ShouldBindJSON(&req) != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_playlet.DeletePlayletTopicGroup(ctx, req.Id); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package web_recharge
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"videoweb/pub/common/log"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/models/vipordermod"
|
||||
"videoweb/pub/payCenter"
|
||||
"videoweb/pub/pubdef"
|
||||
srv_recharge "videoweb/web/service/srv_recharge"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
// newPayCenterCallbackDeps 将查单和入账边界集中,便于用内存替身验证回调不会错误入账。
|
||||
type newPayCenterCallbackDeps struct {
|
||||
findOrder func(context.Context, string) (*vipordermod.VipOrder, *srvdef.SrvErr)
|
||||
queryOrder func(context.Context, string) (payCenter.QueryOrderInfo, error)
|
||||
applyRecharge func(*gin.Context, *srv_recharge.BillCallbackParam) *srvdef.SrvErr
|
||||
}
|
||||
|
||||
// NewPayCenterRchgCallBack 接收新支付中心签名充值通知。
|
||||
// @Tags 支付回调
|
||||
// @Summary 新支付中心充值回调
|
||||
// @Description 校验商户号、MD5签名、金额及平台订单号,查单取得支付时间后按原流程入账;重复成功通知直接应答成功。
|
||||
// @Accept json
|
||||
// @Produce plain
|
||||
// @Param request body payCenter.RechargeCallbackResp true "支付中心签名回调"
|
||||
// @Success 200 {string} string "success"
|
||||
// @Failure 400 {string} string "fail"
|
||||
// @Router /api/web/third/newpaycenter/recharge/callback [POST]
|
||||
func NewPayCenterRchgCallBack(ctx *gin.Context) {
|
||||
deps := newPayCenterCallbackDeps{
|
||||
findOrder: func(c context.Context, tradeNo string) (*vipordermod.VipOrder, *srvdef.SrvErr) {
|
||||
return vipordermod.FindOneVipOrder(c, bson.M{vipordermod.FN.VipOrder.TradeNo: tradeNo})
|
||||
},
|
||||
queryOrder: func(c context.Context, tradeNo string) (payCenter.QueryOrderInfo, error) {
|
||||
return (&payCenter.Recharge{Ctx: c, TradeNo: tradeNo}).QueryOrder(c)
|
||||
},
|
||||
applyRecharge: srv_recharge.OnPayCenterCallback,
|
||||
}
|
||||
handleNewPayCenterRchgCallBack(ctx, deps)
|
||||
}
|
||||
|
||||
func handleNewPayCenterRchgCallBack(ctx *gin.Context, deps newPayCenterCallbackDeps) {
|
||||
if err := processNewPayCenterRchgCallBack(ctx, deps); err != nil {
|
||||
log.Error("【/api/web/third/newpaycenter/recharge/callback】充值回调处理失败", log.E(err))
|
||||
ctx.String(http.StatusBadRequest, "fail")
|
||||
return
|
||||
}
|
||||
ctx.String(http.StatusOK, "success")
|
||||
}
|
||||
|
||||
func processNewPayCenterRchgCallBack(ctx *gin.Context, deps newPayCenterCallbackDeps) error {
|
||||
var callback payCenter.RechargeCallbackResp
|
||||
bindErr := ctx.ShouldBindBodyWith(&callback, binding.JSON)
|
||||
bodyValue, _ := ctx.Get(gin.BodyBytesKey)
|
||||
rawBody, _ := bodyValue.([]byte)
|
||||
log.Info("【/api/web/third/newpaycenter/recharge/callback】收到充值回调",
|
||||
log.Any("tradeNo", callback.TradeNo),
|
||||
log.Any("requestBody", string(rawBody)),
|
||||
log.Any("clientIP", ctx.ClientIP()),
|
||||
)
|
||||
if bindErr != nil {
|
||||
return fmt.Errorf("回调参数解析失败: %w", bindErr)
|
||||
}
|
||||
request := &payCenter.Recharge{TradeNo: callback.TradeNo}
|
||||
if request.GetMercID() == "" || request.GetAppSecret() == "" {
|
||||
return errors.New("新支付中心回调配置缺少 mercID 或 mercSecret")
|
||||
}
|
||||
if callback.Code != http.StatusOK || callback.MercID != request.GetMercID() {
|
||||
return fmt.Errorf("回调状态或商户不匹配,tradeNo=%s", callback.TradeNo)
|
||||
}
|
||||
signSource := strconv.Itoa(callback.Code) + callback.MercID + callback.OID + callback.PayMoney + callback.TradeNo + request.GetAppSecret()
|
||||
if !payCenter.VerifySign(callback.Sign, signSource) {
|
||||
return fmt.Errorf("回调验签失败,tradeNo=%s", callback.TradeNo)
|
||||
}
|
||||
amount, err := payCenter.ParseYuanToFen(callback.PayMoney)
|
||||
if err != nil || amount <= 0 {
|
||||
return fmt.Errorf("回调金额格式错误或非正数,tradeNo=%s", callback.TradeNo)
|
||||
}
|
||||
order, serr := deps.findOrder(ctx, callback.TradeNo)
|
||||
if serr != nil {
|
||||
return fmt.Errorf("查找本地充值订单失败,tradeNo=%s: %w", callback.TradeNo, serr)
|
||||
}
|
||||
if order == nil || order.TradeNo != callback.TradeNo {
|
||||
return fmt.Errorf("本地充值订单不存在,tradeNo=%s", callback.TradeNo)
|
||||
}
|
||||
amountMismatch := amount != order.Amount
|
||||
oidMismatch := order.Oid != "" && callback.OID != order.Oid
|
||||
if amountMismatch || oidMismatch {
|
||||
log.Error("【/api/web/third/newpaycenter/recharge/callback】回调金额或支付中心订单号不匹配",
|
||||
log.Any("tradeNo", callback.TradeNo),
|
||||
log.Any("userId", order.UserId),
|
||||
log.Any("callbackPayMoneyYuan", callback.PayMoney),
|
||||
log.Any("callbackAmountFen", amount),
|
||||
log.Any("orderAmountFen", order.Amount),
|
||||
log.Any("callbackOid", callback.OID),
|
||||
log.Any("orderOid", order.Oid),
|
||||
log.Any("orderStatus", order.Status),
|
||||
log.Any("amountMismatch", amountMismatch),
|
||||
log.Any("oidMismatch", oidMismatch),
|
||||
)
|
||||
return fmt.Errorf("回调金额或支付中心订单号不匹配,tradeNo=%s", callback.TradeNo)
|
||||
}
|
||||
if order.Status == pubdef.VipOrderSuccess {
|
||||
log.Info("【/api/web/third/newpaycenter/recharge/callback】重复成功通知", log.Any("tradeNo", callback.TradeNo))
|
||||
return nil
|
||||
}
|
||||
info, err := deps.queryOrder(ctx, callback.TradeNo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("支付中心查单失败,tradeNo=%s: %w", callback.TradeNo, err)
|
||||
}
|
||||
if (info.MercID != "" && info.MercID != callback.MercID) || (info.TradeNo != "" && info.TradeNo != callback.TradeNo) {
|
||||
return fmt.Errorf("支付中心查单返回了其他商户或订单,tradeNo=%s", callback.TradeNo)
|
||||
}
|
||||
paymentAt, err := time.ParseInLocation(time.RFC3339, info.PayTime, time.Local)
|
||||
if err != nil {
|
||||
return fmt.Errorf("支付中心支付时间无效,tradeNo=%s: %w", callback.TradeNo, err)
|
||||
}
|
||||
param := &srv_recharge.BillCallbackParam{
|
||||
TradeNo: callback.TradeNo,
|
||||
Oid: callback.OID,
|
||||
RealAmount: amount,
|
||||
PaymentAt: paymentAt,
|
||||
}
|
||||
if serr := deps.applyRecharge(ctx, param); serr != nil {
|
||||
return fmt.Errorf("本地充值入账失败,tradeNo=%s: %w", callback.TradeNo, serr)
|
||||
}
|
||||
log.Info("【/api/web/third/newpaycenter/recharge/callback】充值入账成功", log.Any("tradeNo", callback.TradeNo), log.Any("userId", order.UserId), log.Any("amount", amount))
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package web_recharge
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/service/srv_viporder"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// RechargeSummary 统计指定时间范围内的充值汇总
|
||||
// @Tags wbapi统计
|
||||
// @Summary 统计充值汇总
|
||||
// @Description 按北京时间的开始/结束时间汇总支付成功订单金额与笔数
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param startTime query string true "开始时间,北京时间,支持 2006-01-02、2006-01-02 15:04:05、RFC3339"
|
||||
// @Param endTime query string true "结束时间,北京时间,支持 2006-01-02、2006-01-02 15:04:05、RFC3339"
|
||||
// @Success 200 {object} srv_viporder.RechargeSummaryResp "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Router /wbapi/hddjweb/recharge/summary [GET]
|
||||
func RechargeSummary(ctx *gin.Context) {
|
||||
var req srv_viporder.RechargeSummaryReq
|
||||
if err := ctx.ShouldBindQuery(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
resp, serr := srv_viporder.GetRechargeSummary(ctx, &req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr, nil)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
package web_rechargepackage
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/service/srv_rechargepackage"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// List 查询购买套餐列表
|
||||
// @Tags 套餐管理
|
||||
// @Summary 查询购买套餐列表 -- by 王鸣
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_rechargepackage.RechargePackageListReq true "查询参数"
|
||||
// @Success 200 {object} srv_rechargepackage.RechargePackageListResp "成功"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/recharge/package/list [POST]
|
||||
func List(ctx *gin.Context) {
|
||||
var req srv_rechargepackage.RechargePackageListReq
|
||||
if err := ctx.ShouldBind(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, err := srv_rechargepackage.ListRechargePackage(ctx, &req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// VipList 查询会员畅享套餐选项
|
||||
// @Tags 套餐管理
|
||||
// @Summary 查询会员畅享套餐选项 -- by 王鸣
|
||||
// @Description 只返回 PackageType=1 的启用套餐,字段仅包含 id 和 name,不分页
|
||||
// @Produce json
|
||||
// @Success 200 {array} srv_rechargepackage.VipPackageOption "成功"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/recharge/package/vip/list [POST]
|
||||
func VipList(ctx *gin.Context) {
|
||||
resp, err := srv_rechargepackage.ListVipPackageOptions(ctx)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// Add 新增购买套餐
|
||||
// @Tags 套餐管理
|
||||
// @Summary 新增购买套餐 -- by 王鸣
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_rechargepackage.RechargePackageAddReq true "新增参数"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/recharge/package/add [POST]
|
||||
func Add(ctx *gin.Context) {
|
||||
var req srv_rechargepackage.RechargePackageAddReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_rechargepackage.AddRechargePackage(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// Update 更新购买套餐
|
||||
// @Tags 套餐管理
|
||||
// @Summary 更新购买套餐 -- by 王鸣
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_rechargepackage.RechargePackageUpdateReq true "更新参数"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/recharge/package/update [POST]
|
||||
func Update(ctx *gin.Context) {
|
||||
var req srv_rechargepackage.RechargePackageUpdateReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_rechargepackage.UpdateRechargePackage(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// Delete 删除购买套餐
|
||||
// @Tags 套餐管理
|
||||
// @Summary 删除购买套餐 -- by 王鸣
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_rechargepackage.RechargePackageDelReq true "删除参数"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/recharge/package/del [POST]
|
||||
func Delete(ctx *gin.Context) {
|
||||
var req srv_rechargepackage.RechargePackageDelReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_rechargepackage.DeleteRechargePackage(ctx, req.Id); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// SetStatus 单/批量设置购买套餐状态
|
||||
// @Tags 套餐管理
|
||||
// @Summary 单/批量设置购买套餐状态 -- by 王鸣
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_rechargepackage.RechargePackageStatusSetReq true "设置状态参数"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/recharge/package/status/set [POST]
|
||||
func SetStatus(ctx *gin.Context) {
|
||||
var req srv_rechargepackage.RechargePackageStatusSetReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_rechargepackage.SetRechargePackageStatus(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package web_richtextcontent
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/models/richtextcontentmod"
|
||||
"videoweb/web/service/srv_richtextcontent"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags 富文本内容
|
||||
// @Summary 分组分页获取富文本内容
|
||||
// @Description 分组分页获取富文本内容
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_richtextcontent.GetRichTextContentListReq true "参数列表"
|
||||
// @Success 200 {object} srv_richtextcontent.GetRichTextContentResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/richtextcontent/list [POST]
|
||||
func List(ctx *gin.Context) {
|
||||
var req = &srv_richtextcontent.GetRichTextContentListReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, serr := srv_richtextcontent.GetRichTextContentList(ctx, req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// @Tags 富文本内容
|
||||
// @Summary 添加一个富文本内容
|
||||
// @Description 添加一个富文本内容
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body richtextcontentmod.RichTextContentModel true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/richtextcontent/add [POST]
|
||||
func Add(ctx *gin.Context) {
|
||||
var req = &richtextcontentmod.RichTextContentModel{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err)
|
||||
return
|
||||
}
|
||||
serr := srv_richtextcontent.AddRichTextContent(ctx, req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// @Tags 富文本内容
|
||||
// @Summary 删除一个富文本内容
|
||||
// @Description 删除一个富文本内容
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_richtextcontent.DelRichTextContentReq true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/richtextcontent/del [POST]
|
||||
func Del(ctx *gin.Context) {
|
||||
var req = &srv_richtextcontent.DelRichTextContentReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err)
|
||||
return
|
||||
}
|
||||
serr := srv_richtextcontent.DelRichTextContent(ctx, req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// @Tags 富文本内容
|
||||
// @Summary 更新一个富文本内容
|
||||
// @Description 更新一个富文本内容
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_richtextcontent.UpdateRichTextContentReq true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/richtextcontent/update [POST]
|
||||
func Update(ctx *gin.Context) {
|
||||
var req = &srv_richtextcontent.UpdateRichTextContentReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
|
||||
serr := srv_richtextcontent.UpdateRichTextContent(ctx, req.Id, &req.Param)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package web_translation
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/models/translationcategorymod"
|
||||
"videoweb/web/service/srv_translationcategory"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags 导航分类
|
||||
// @Summary 分组分页获取导航分类
|
||||
// @Description 分组分页获取导航分类
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_translationcategory.TranslationCategoryReq true "参数列表"
|
||||
// @Success 200 {object} srv_translationcategory.TranslationCategoryResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/translationcategory/list [POST]
|
||||
func GetTranslationCategory(ctx *gin.Context) {
|
||||
var req = &srv_translationcategory.TranslationCategoryReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, serr := srv_translationcategory.GetTranslationCategorys(ctx, req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// @Tags 导航分类
|
||||
// @Summary 添加一个导航分类
|
||||
// @Description 添加一个导航分类
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body translationcategorymod.TranslationCategory true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/translationcategory/add [POST]
|
||||
func AddOnetTranslationCategory(ctx *gin.Context) {
|
||||
var req = &translationcategorymod.TranslationCategory{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err)
|
||||
return
|
||||
}
|
||||
serr := srv_translationcategory.AddTranslationCategory(ctx, req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// @Tags 导航分类
|
||||
// @Summary 删除一个导航分类
|
||||
// @Description 删除一个导航分类
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_translationcategory.TranslationCategoryDelReq true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/translationcategory/del [POST]
|
||||
func DelOnetTranslationCategory(ctx *gin.Context) {
|
||||
var req = &srv_translationcategory.TranslationCategoryDelReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err)
|
||||
return
|
||||
}
|
||||
serr := srv_translationcategory.DelTranslationCategory(ctx, req.Id)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// @Tags 导航分类
|
||||
// @Summary 更新一个导航分类
|
||||
// @Description 更新一个导航分类
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_translationcategory.TranslationCategoryUpdateReq true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/translationcategory/update [POST]
|
||||
func UpdateOnetTranslationCategory(ctx *gin.Context) {
|
||||
var req = &srv_translationcategory.TranslationCategoryUpdateReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
|
||||
serr := srv_translationcategory.UpdateTranslationCategory(ctx, req.Id, req.Param)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package web_translation
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/models/translationmod"
|
||||
"videoweb/web/service/srv_translation"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags 导航跳转信息
|
||||
// @Summary 分组分页获取导航跳转信息
|
||||
// @Description 分组分页获取导航跳转信息
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_translation.TranslationInfoReq true "参数列表"
|
||||
// @Success 200 {object} srv_translation.TranslationInfoResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/translation/list [POST]
|
||||
func GetTranslation(ctx *gin.Context) {
|
||||
var req = &srv_translation.TranslationInfoReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, serr := srv_translation.GetTranslationInfos(ctx, req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// @Tags 导航跳转信息
|
||||
// @Summary 添加一个导航跳转信息
|
||||
// @Description 添加一个导航跳转信息
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body translationmod.TranslationInfo true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/translation/add [POST]
|
||||
func AddOnetTranslation(ctx *gin.Context) {
|
||||
var req = &translationmod.TranslationInfo{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err)
|
||||
return
|
||||
}
|
||||
serr := srv_translation.AddTranslationInfo(ctx, req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// @Tags 导航跳转信息
|
||||
// @Summary 删除一个导航跳转信息
|
||||
// @Description 删除一个导航跳转信息
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_translation.TranslationInfoDelReq true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/translation/del [POST]
|
||||
func DelOnetTranslation(ctx *gin.Context) {
|
||||
var req = &srv_translation.TranslationInfoDelReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err)
|
||||
return
|
||||
}
|
||||
serr := srv_translation.DelTranslationInfo(ctx, req.Id)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// @Tags 导航跳转信息
|
||||
// @Summary 更新一个导航跳转信息
|
||||
// @Description 更新一个导航跳转信息
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_translation.TranslationInfoUpdateReq true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/translation/update [POST]
|
||||
func UpdateOnetTranslation(ctx *gin.Context) {
|
||||
var req = &srv_translation.TranslationInfoUpdateReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
|
||||
serr := srv_translation.UpdateTranslationInfo(ctx, req.Id, req.Param)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package web_user
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/service/srv_user"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags 用户管理
|
||||
// @Summary 查询用户列表
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_user.UserListReq true "查询参数"
|
||||
// @Success 200 {object} srv_user.UserListResp "成功"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/user/list [POST]
|
||||
func GetUserList(ctx *gin.Context) {
|
||||
var req srv_user.UserListReq
|
||||
if err := ctx.ShouldBind(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, serr := srv_user.GetUsers(ctx, &req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// @Tags 用户管理
|
||||
// @Summary 更新用户信息
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_user.UserUpdateReq true "更新参数"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/user/update [POST]
|
||||
func UpdateUser(ctx *gin.Context) {
|
||||
var req srv_user.UserUpdateReq
|
||||
if err := ctx.ShouldBind(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if serr := srv_user.UpdateUser(ctx, req.Id, req.Param); serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// @Tags 用户管理
|
||||
// @Summary 赠送/扣除用户金币
|
||||
// @Description coin 为正数表示赠送,为负数表示扣除;操作会自动记录金币流水
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_user.GiftCoinReq true "赠送参数"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/user/giftcoin [POST]
|
||||
func GiftCoin(ctx *gin.Context) {
|
||||
var req srv_user.GiftCoinReq
|
||||
if err := ctx.ShouldBind(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if serr := srv_user.GiftCoin(ctx, &req); serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// @Tags 用户管理
|
||||
// @Summary 修改用户会员
|
||||
// @Description 根据会员畅享套餐ID修改用户会员信息,不处理赠送金币
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_user.UpdateVipReq true "修改会员参数"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/user/vip/update [POST]
|
||||
func UpdateVip(ctx *gin.Context) {
|
||||
var req srv_user.UpdateVipReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if serr := srv_user.UpdateVip(ctx, &req); serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// ResetPassword web端按用户ID重置密码
|
||||
// @Tags 用户管理
|
||||
// @Summary 重置用户密码
|
||||
// @Description 传入用户ID和明文密码,服务端按 app 登录相同规则哈希后写入
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_user.ResetPasswordReq true "重置密码参数"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/user/resetPassword [POST]
|
||||
func ResetPassword(ctx *gin.Context) {
|
||||
var req srv_user.ResetPasswordReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if serr := srv_user.ResetPassword(ctx, &req); serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package web_video
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/models/videocategorymod"
|
||||
"videoweb/web/service/srv_videocategory"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags 视频分类
|
||||
// @Summary 分组分页获取视频分类
|
||||
// @Description 分组分页获取视频分类
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_videocategory.VideoCategoryReq true "参数列表"
|
||||
// @Success 200 {object} srv_videocategory.VideoCategoryResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videocategory/list [POST]
|
||||
func GetVideoCategory(ctx *gin.Context) {
|
||||
var req = &srv_videocategory.VideoCategoryReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, serr := srv_videocategory.GetVideoCategorys(ctx, req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// @Tags 视频分类
|
||||
// @Summary 添加一个视频分类
|
||||
// @Description 添加一个视频分类
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body videocategorymod.VideoCategory true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videocategory/add [POST]
|
||||
func AddOneVideoCategory(ctx *gin.Context) {
|
||||
var req = &videocategorymod.VideoCategory{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err)
|
||||
return
|
||||
}
|
||||
serr := srv_videocategory.AddVideoCategory(ctx, req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// @Tags 视频分类
|
||||
// @Summary 删除一个视频分类
|
||||
// @Description 删除一个视频分类
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_videocategory.VideoCategoryDelReq true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videocategory/del [POST]
|
||||
func DelOneVideoCategory(ctx *gin.Context) {
|
||||
var req = &srv_videocategory.VideoCategoryDelReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err)
|
||||
return
|
||||
}
|
||||
serr := srv_videocategory.DelVideoCategory(ctx, req.Id)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// @Tags 视频分类
|
||||
// @Summary 更新一个视频分类
|
||||
// @Description 更新一个视频分类
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_videocategory.VideoCategoryUpdateReq true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videocategory/update [POST]
|
||||
func UpdateOneVideoCategory(ctx *gin.Context) {
|
||||
var req = &srv_videocategory.VideoCategoryUpdateReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
|
||||
serr := srv_videocategory.UpdateVideoCategory(ctx, req.Id, req.Param)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package web_video
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/models/videocreatermod"
|
||||
"videoweb/web/service/srv_videocreater"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags 视频作者
|
||||
// @Summary 分组分页获取视频作者
|
||||
// @Description 分组分页获取视频作者
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_videocreater.VideoCreaterReq true "参数列表"
|
||||
// @Success 200 {object} srv_videocreater.VideoCreaterResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videocreater/list [POST]
|
||||
func GetVideoCreater(ctx *gin.Context) {
|
||||
var req = &srv_videocreater.VideoCreaterReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, serr := srv_videocreater.GetVideoCreaters(ctx, req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// @Tags 视频作者
|
||||
// @Summary 添加一个视频作者
|
||||
// @Description 添加一个视频作者
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body videocreatermod.VideoCreaterInfo true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videocreater/add [POST]
|
||||
func AddOneVideoCreater(ctx *gin.Context) {
|
||||
var req = &videocreatermod.VideoCreaterInfo{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err)
|
||||
return
|
||||
}
|
||||
serr := srv_videocreater.AddVideoCreater(ctx, req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// @Tags 视频作者
|
||||
// @Summary 删除一个视频作者
|
||||
// @Description 删除一个视频作者
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_videocreater.VideoCreaterDelReq true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videocreater/del [POST]
|
||||
func DelOneVideoCreater(ctx *gin.Context) {
|
||||
var req = &srv_videocreater.VideoCreaterDelReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err)
|
||||
return
|
||||
}
|
||||
serr := srv_videocreater.DelVideoCreater(ctx, req.Id)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// @Tags 视频作者
|
||||
// @Summary 更新一个视频作者
|
||||
// @Description 更新一个视频作者
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_videocreater.VideoCreaterUpdateReq true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videocreater/update [POST]
|
||||
func UpdateOneVideoCreater(ctx *gin.Context) {
|
||||
var req = &srv_videocreater.VideoCreaterUpdateReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
|
||||
serr := srv_videocreater.UpdateVideoCreater(ctx, req.Id, req.Param)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package web_video
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/service/srv_videotag"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags 标签管理
|
||||
// @Summary 查询播放量最多的标签
|
||||
// @Description 根据视频累计播放量聚合返回热门标签列表
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param limit query int false "返回条数,默认10,最大1000"
|
||||
// @Success 200 {object} srv_videotag.HotTagResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Router /wbapi/hgdjnet/hottag [GET]
|
||||
func GetVideoPlayData(ctx *gin.Context) {
|
||||
var req = &srv_videotag.HotTagReq{}
|
||||
if err := ctx.ShouldBindQuery(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, serr := srv_videotag.GetHotTagsByPlayData(ctx, req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// @Tags 标签管理
|
||||
// @Summary 查询今日和昨日 IP 去重统计
|
||||
// @Description 返回 app 端同步到 MongoDB 的每日访问 IP 去重数
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} srv_videotag.IpStatResp "成功"
|
||||
// @Router /wbapi/hddjweb/ipstat [GET]
|
||||
func GetIpStatData(ctx *gin.Context) {
|
||||
resp := srv_videotag.FetchIpStat(ctx)
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package web_video
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"io"
|
||||
"net/http"
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/m3u8"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/models/cfg"
|
||||
"videoweb/web/webg"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type fileHandler func(ctx *gin.Context) (contentLength int64, contentType string, reader io.Reader, extraHeaders map[string]string, err error)
|
||||
|
||||
func Play(ctx *gin.Context) {
|
||||
fn := func(c *gin.Context) (contentLength int64, contentType string, reader io.Reader, extraHeaders map[string]string, err error) {
|
||||
m3u8Name := ctx.Param("key")
|
||||
|
||||
var req m3u8.Req
|
||||
if err = ctx.BindQuery(&req); err != nil {
|
||||
return
|
||||
}
|
||||
req.Name = m3u8Name
|
||||
cfgSys, _ := cfg.FindOneSysCfg(ctx, bson.M{})
|
||||
cdnDomain := webg.Conf.CdnDomain
|
||||
if cfgSys != nil {
|
||||
cdnDomain = cfgSys.MediaWebCdn
|
||||
}
|
||||
origDomain := webg.Conf.OrigDomain
|
||||
useNewKey := ctx.Query("useNewKey") == "1" || ctx.Query("newKey") == "1"
|
||||
var buff *bytes.Buffer
|
||||
if useNewKey {
|
||||
// 短剧原片:不追加媒资版本前缀,并使用 conf/newm3u8.key
|
||||
_, buff, err = m3u8.TransformExOriginalPath(req.Name, cdnDomain, origDomain, 3, webg.Conf.TsAuthKey, webg.Conf.LsjMediaConf.M3u8Yuan, "", "/api/web/newenkey")
|
||||
} else {
|
||||
_, buff, err = m3u8.TransFormWithSafely(&req, cdnDomain, origDomain, true, webg.Conf.TsAuthKey, webg.Conf.LsjMediaConf.M3u8Yuan, "")
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
contentType = "application/vnd.apple.mpegurl"
|
||||
reader = bytes.NewReader(buff.Bytes())
|
||||
contentLength = int64(buff.Len())
|
||||
extraHeaders = map[string]string{}
|
||||
return
|
||||
}
|
||||
|
||||
handlerFile(ctx, fn)
|
||||
}
|
||||
|
||||
func Enkey(ctx *gin.Context) {
|
||||
fn := func(c *gin.Context) (contentLength int64, contentType string, reader io.Reader, extraHeaders map[string]string, err error) {
|
||||
buffer, err := m3u8.Enkey(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
contentLength = int64(buffer.Len())
|
||||
contentType = "application/octet-stream"
|
||||
reader = buffer
|
||||
extraHeaders = map[string]string{}
|
||||
return
|
||||
}
|
||||
handlerFile(ctx, fn)
|
||||
}
|
||||
|
||||
// NewEnkey 返回短剧原片使用的新 M3U8 解密密钥(conf/newm3u8.key)。
|
||||
func NewEnkey(ctx *gin.Context) {
|
||||
fn := func(c *gin.Context) (contentLength int64, contentType string, reader io.Reader, extraHeaders map[string]string, err error) {
|
||||
buffer, err := m3u8.NewEnkey(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
contentLength = int64(buffer.Len())
|
||||
contentType = "application/octet-stream"
|
||||
reader = buffer
|
||||
extraHeaders = map[string]string{}
|
||||
return
|
||||
}
|
||||
handlerFile(ctx, fn)
|
||||
}
|
||||
|
||||
// TranscodeM3u8 转码专用 m3u8 接口(不鉴权)。
|
||||
func TranscodeM3u8(ctx *gin.Context) {
|
||||
fn := func(c *gin.Context) (contentLength int64, contentType string, reader io.Reader, extraHeaders map[string]string, err error) {
|
||||
name := ctx.Param("key")
|
||||
_, buff, err := m3u8.TransformForTranscode(name, webg.Conf.OrigDomain, webg.Conf.CdnDomain, webg.Conf.WebM3u8Host, webg.Conf.LsjMediaConf.M3u8Yuan, webg.Conf.LsjMediaConf.TsYuan)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
contentType = "application/vnd.apple.mpegurl"
|
||||
reader = bytes.NewReader(buff.Bytes())
|
||||
contentLength = int64(buff.Len())
|
||||
extraHeaders = map[string]string{}
|
||||
return
|
||||
}
|
||||
handlerFile(ctx, fn)
|
||||
}
|
||||
|
||||
func LsjEnkey(ctx *gin.Context) {
|
||||
fn := func(c *gin.Context) (contentLength int64, contentType string, reader io.Reader, extraHeaders map[string]string, err error) {
|
||||
buffer, err := m3u8.LsjEnkey(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
contentLength = int64(buffer.Len())
|
||||
contentType = "application/octet-stream"
|
||||
reader = buffer
|
||||
extraHeaders = map[string]string{}
|
||||
return
|
||||
}
|
||||
handlerFile(ctx, fn)
|
||||
}
|
||||
|
||||
func handlerFile(ctx *gin.Context, h fileHandler) {
|
||||
contentLength, contentType, reader, extraHeaders, err := h(ctx)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, srvdef.DownloadM3u8File, err)
|
||||
return
|
||||
}
|
||||
ctx.DataFromReader(http.StatusOK, contentLength, contentType, reader, extraHeaders)
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package web_video
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/models/videotagmod"
|
||||
"videoweb/web/service/srv_videotag"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags 标签管理
|
||||
// @Summary 分组分页获取标签管理
|
||||
// @Description 分组分页获取标签管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_videotag.VideoTagInfoReq true "参数列表"
|
||||
// @Success 200 {object} srv_videotag.VideoTagInfoResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videotag/list [POST]
|
||||
func GetVideoTagInfo(ctx *gin.Context) {
|
||||
var req = &srv_videotag.VideoTagInfoReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, serr := srv_videotag.GetVideoTagInfos(ctx, req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// @Tags 标签管理
|
||||
// @Summary 添加一个标签管理
|
||||
// @Description 添加一个标签管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body videotagmod.VideoTagInfo true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videotag/add [POST]
|
||||
func AddOneVideoTagInfo(ctx *gin.Context) {
|
||||
var req = &videotagmod.VideoTagInfo{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err)
|
||||
return
|
||||
}
|
||||
serr := srv_videotag.AddVideoTagInfo(ctx, req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// @Tags 标签管理
|
||||
// @Summary 删除一个标签管理
|
||||
// @Description 删除一个标签管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_videotag.VideoTagInfoDelReq true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videotag/del [POST]
|
||||
func DelOneVideoTagInfo(ctx *gin.Context) {
|
||||
var req = &srv_videotag.VideoTagInfoDelReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err)
|
||||
return
|
||||
}
|
||||
serr := srv_videotag.DelVideoTagInfo(ctx, req.Id)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// @Tags 标签管理
|
||||
// @Summary 更新一个标签管理
|
||||
// @Description 更新一个标签管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_videotag.VideoTagInfoUpdateReq true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videotag/update [POST]
|
||||
func UpdateOneVideoTagInfo(ctx *gin.Context) {
|
||||
var req = &srv_videotag.VideoTagInfoUpdateReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
|
||||
serr := srv_videotag.UpdateVideoTagInfo(ctx, req.Id, req.Param)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package web_video
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/models/videotopicmod"
|
||||
"videoweb/web/service/srv_videotopic"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags 视频专题
|
||||
// @Summary 分组分页获取视频专题
|
||||
// @Description 分组分页获取视频专题
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_videotopic.VideoTopicReq true "参数列表"
|
||||
// @Success 200 {object} srv_videotopic.VideoTopicResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videotopic/list [POST]
|
||||
func GetVideoTopic(ctx *gin.Context) {
|
||||
var req = &srv_videotopic.VideoTopicReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, serr := srv_videotopic.GetVideoTopics(ctx, req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// @Tags 视频专题
|
||||
// @Summary 添加一个视频专题
|
||||
// @Description 添加一个视频专题
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body videotopicmod.VideoTopicModel true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videotopic/add [POST]
|
||||
func AddOneVideoTopic(ctx *gin.Context) {
|
||||
var req = &videotopicmod.VideoTopicModel{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err)
|
||||
return
|
||||
}
|
||||
serr := srv_videotopic.AddVideoTopic(ctx, req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// @Tags 视频专题
|
||||
// @Summary 删除一个视频专题
|
||||
// @Description 删除一个视频专题
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_videotopic.VideoTopicDelReq true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videotopic/del [POST]
|
||||
func DelOneVideoTopic(ctx *gin.Context) {
|
||||
var req = &srv_videotopic.VideoTopicDelReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err)
|
||||
return
|
||||
}
|
||||
serr := srv_videotopic.DelVideoTopic(ctx, req.Id)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// @Tags 视频专题
|
||||
// @Summary 更新一个视频专题
|
||||
// @Description 更新一个视频专题
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_videotopic.VideoTopicUpdateReq true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videotopic/update [POST]
|
||||
func UpdateOneVideoTopic(ctx *gin.Context) {
|
||||
var req = &srv_videotopic.VideoTopicUpdateReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
|
||||
serr := srv_videotopic.UpdateVideoTopic(ctx, req.Id, req.Param)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
package web_video
|
||||
|
||||
import (
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/api/proto"
|
||||
"videoweb/web/middleware/auth"
|
||||
"videoweb/web/service/srv_videoinfo"
|
||||
"videoweb/web/service/srv_videoslug"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// @Tags 视频管理
|
||||
// @Summary 分组分页获取视频管理
|
||||
// @Description 分组分页获取视频管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_videoinfo.VideoInfoReq true "参数列表"
|
||||
// @Success 200 {object} srv_videoinfo.VideoInfoResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videoinfo/list [POST]
|
||||
func GetVideoInfo(ctx *gin.Context) {
|
||||
var req = &srv_videoinfo.VideoInfoReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
resp, serr := srv_videoinfo.GetVideoInfos(ctx, req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// @Tags 视频管理
|
||||
// @Summary 从切片列表同步多个视频
|
||||
// @Description 从切片列表同步多个视频
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_videoinfo.AddVideoReq true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videoinfo/sync [POST]
|
||||
func SyncVideoInfo(ctx *gin.Context) {
|
||||
var req = &srv_videoinfo.AddVideoReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err)
|
||||
return
|
||||
}
|
||||
serr := srv_videoinfo.SyncVideoInfo(ctx, req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// @Tags 视频管理
|
||||
// @Summary 删除一个视频管理
|
||||
// @Description 删除一个视频管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_videoinfo.VideoInfoDelReq true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videoinfo/del [POST]
|
||||
func DelOneVideoInfo(ctx *gin.Context) {
|
||||
var req = &srv_videoinfo.VideoInfoDelReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err)
|
||||
return
|
||||
}
|
||||
serr := srv_videoinfo.DelVideoInfo(ctx, req.Id)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// @Tags 视频管理
|
||||
// @Summary 更新一个视频管理
|
||||
// @Description 更新一个视频管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_videoinfo.VideoInfoUpdateReq true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videoinfo/update [POST]
|
||||
func UpdateOneVideoInfo(ctx *gin.Context) {
|
||||
var req = &srv_videoinfo.VideoInfoUpdateReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
userId := ctx.GetInt64(auth.AccId)
|
||||
ua, _ := common.GetUA(ctx)
|
||||
serr := srv_videoinfo.UpdateVideoInfo(ctx, req.Id, userId, req.Param, ua)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// @Tags 视频管理
|
||||
// @Summary 新增一个视频合集
|
||||
// @Description 新增一个视频合集
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_videoinfo.AddVideoCollectionReq true "参数列表"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videoinfo/addcoll [POST]
|
||||
func AddOneVideoCollection(ctx *gin.Context) {
|
||||
var req = &srv_videoinfo.AddVideoCollectionReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
|
||||
serr := srv_videoinfo.AddVideoCollection(ctx, req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
// SetVideoFakeWatchTimes 单/批量设置视频假观看次数
|
||||
// @Tags 视频管理
|
||||
// @Summary 单/批量设置视频假观看次数 --by 旺鸣
|
||||
// @Description 根据ids批量随机设置视频假观看次数
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_videoinfo.SetFakeWatchTimesReq true "参数列表"
|
||||
// @Success 200 {object} srv_videoinfo.SetFakeCountResp "成功"
|
||||
// @Failure 400 {string} string "获取失败的返回结果"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videoinfo/setFakeWatchTimes [post]
|
||||
func SetVideoFakeWatchTimes(ctx *gin.Context) {
|
||||
req := &srv_videoinfo.SetFakeWatchTimesReq{}
|
||||
if err := ctx.ShouldBind(req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, err.Error())
|
||||
return
|
||||
}
|
||||
resp, err := srv_videoinfo.SetVideoFakeWatchTimes(ctx, req)
|
||||
if err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
|
||||
// SetCategory web端单/批量设置视频分类
|
||||
// @Tags 视频管理
|
||||
// @Summary web端单/批量设置视频分类
|
||||
// @Description 根据视频ID集合批量更新 video_information 集合 categoryIds 字段,传1个ID表示单条设置,传多个ID表示批量设置;categoryIds 可为空,不传或空数组表示清空分类
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body srv_videoinfo.SetVideoCategoryReq true "单/批量设置视频分类请求"
|
||||
// @Success 200 {string} string "成功"
|
||||
// @Failure 400 {string} string "失败"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videoinfo/category/set [post]
|
||||
func SetCategory(ctx *gin.Context) {
|
||||
var req srv_videoinfo.SetVideoCategoryReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if err := srv_videoinfo.SetVideoCategory(ctx, &req); err != nil {
|
||||
common.ServerJSON(ctx, err.Code, err.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, "")
|
||||
}
|
||||
|
||||
type TranscodeVideoReq struct {
|
||||
Id int64 `json:"id" binding:"required"`
|
||||
}
|
||||
|
||||
// @Tags 视频管理
|
||||
// @Summary 提交视频 H265 转码
|
||||
// @Router /api/web/videoinfo/transcode [POST]
|
||||
func TranscodeVideo(ctx *gin.Context) {
|
||||
var req TranscodeVideoReq
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
if serr := srv_videoinfo.TranscodeVideo(ctx, req.Id); serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, nil)
|
||||
}
|
||||
|
||||
// SyncSlug web端同步视频相关历史空 slug
|
||||
// @Tags 视频管理
|
||||
// @Summary 同步历史空 slug
|
||||
// @Description 为分类、标签、题材、作者、视频中空的 slug 按 SEO 关键词或名称自动生成。可重复调用,hasMore 为 true 时继续请求。
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param param body proto.VideoSlugSyncReq false "同步参数"
|
||||
// @Success 200 {object} proto.VideoSlugSyncResp "成功"
|
||||
// @Failure 400 {string} string "参数错误"
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /api/web/videoinfo/slug/sync [POST]
|
||||
func SyncSlug(ctx *gin.Context) {
|
||||
var req proto.VideoSlugSyncReq
|
||||
if ctx.Request.ContentLength > 0 {
|
||||
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||
common.ServerJSON(ctx, srvdef.ErrParamError, nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
resp, serr := srv_videoslug.SyncEmptySlugs(ctx, &req)
|
||||
if serr != nil {
|
||||
common.ServerJSON(ctx, serr.Code, serr.Tips)
|
||||
return
|
||||
}
|
||||
common.ServerJSON(ctx, srvdef.Success, resp)
|
||||
}
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
FILE_NAME="web_mdcom_web"
|
||||
REMOTE_FILE_PATH="/home/server2/web_mdcom/web/"
|
||||
TAG_NAME="web_mdcom_web.tar.gz"
|
||||
|
||||
set -e
|
||||
set -o
|
||||
function send_msg() {
|
||||
msg="@jscdsndj @xiuyuan_Lee @steven0yu %0A服务:SERVER2 站点-91spz.com管理服务(WEB)%0A更新内容:$content%0A创建时间: $(date +%F_%X)%0A操作人:$(git config user.name)"
|
||||
curl -X POST "https://api.telegram.org/bot6357085965:AAEmXfjZnZwnDTicL7Wjbd7cXvYv_G98w8A/sendMessage" -d "chat_id=$1&text=$msg" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
read -p "输入yes, 开始上传: " word
|
||||
if [[ ! "yes" =~ $word ]]; then
|
||||
echo "终止"
|
||||
else
|
||||
read -e -p "本次更新内容(输入q退出编辑): " -r content
|
||||
echo "开始"
|
||||
rm -rf ./$FILE_NAME ./$TAG_NAME ./yinsemd5.txt
|
||||
GOOS=linux GOARCH=amd64 go build -o $FILE_NAME
|
||||
md5sum $FILE_NAME | cut -d ' ' -f1 >yinsemd5.txt
|
||||
tar zvcf $TAG_NAME ./$FILE_NAME yinsemd5.txt
|
||||
md5sum $TAG_NAME | cut -d ' ' -f1 >yinsemd5.txt
|
||||
scp -i ~/.ssh/id_rsa -P 22889 ./yinsemd5.txt server2@116.212.120.2:$REMOTE_FILE_PATH
|
||||
scp -i ~/.ssh/id_rsa -P 22889 ./$TAG_NAME server2@116.212.120.2:$REMOTE_FILE_PATH
|
||||
send_msg -4791758991 #服务器小组
|
||||
fi
|
||||
rm -rf ./$FILE_NAME ./$TAG_NAME ./yinsemd5.txt
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
sudo make test
|
||||
|
||||
scp -P 22889 web_91av_web.tar.gz root@172.104.181.99:/server/web_91av/web/
|
||||
ssh root@172.104.181.99 -p 22889 "cd /server/web_91av/web/ && /bin/tar -xf /server/web_91av/web/web_91av_web.tar.gz && /usr/bin/supervisorctl restart web_91av_web"
|
||||
if [ $? -eq 0 ];then
|
||||
echo -e "\033[32m 91spz.com web更新成功 \033[0m"
|
||||
else
|
||||
echo -e "\033[31m 91spz.com web更新失败 \033[0m"
|
||||
fi
|
||||
rm -f web_91av_web.tar.gz
|
||||
+15274
File diff suppressed because it is too large
Load Diff
+15254
File diff suppressed because it is too large
Load Diff
+10086
File diff suppressed because it is too large
Load Diff
+66
@@ -0,0 +1,66 @@
|
||||
//go:generate swag init --parseDependency --parseDepth 4
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
"videoweb/pub/common/srvversion"
|
||||
"videoweb/web/server"
|
||||
)
|
||||
|
||||
// @title 站群后台接口
|
||||
// @version 1.0
|
||||
// @description 这是站群后台接口服务.
|
||||
// @termsOfService
|
||||
|
||||
// @contact.name
|
||||
// @contact.url
|
||||
// @contact.email
|
||||
|
||||
// @license.name Apache 2.0
|
||||
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
// @host localhost:12667
|
||||
// @BasePath /
|
||||
// @Schemes http https
|
||||
|
||||
// @securityDefinitions.basic BasicAuth
|
||||
|
||||
// @securityDefinitions.apikey ApiKeyAuth
|
||||
// @in header
|
||||
// @name Authorization
|
||||
|
||||
// @securitydefinitions.oauth2.application OAuth2Application
|
||||
// @tokenUrl https://example.com/oauth/token
|
||||
// @scope.write Grants write access
|
||||
// @scope.admin Grants read and write access to administrative information
|
||||
|
||||
// @securitydefinitions.oauth2.implicit OAuth2Implicit
|
||||
// @authorizationUrl https://example.com/oauth/authorize
|
||||
// @scope.write Grants write access
|
||||
// @scope.admin Grants read and write access to administrative information
|
||||
|
||||
// @securitydefinitions.oauth2.password OAuth2Password
|
||||
// @tokenUrl https://example.com/oauth/token
|
||||
// @scope.read Grants read access
|
||||
// @scope.write Grants write access
|
||||
// @scope.admin Grants read and write access to administrative information
|
||||
|
||||
// @securitydefinitions.oauth2.accessCode OAuth2AccessCode
|
||||
// @tokenUrl https://example.com/oauth/token
|
||||
// @authorizationUrl https://example.com/oauth/authorize
|
||||
// @scope.admin Grants read and write access to administrative information
|
||||
|
||||
func cmdLine() {
|
||||
info := flag.Bool("info", false, "show serivce build info")
|
||||
//flagHander := flag.String("handler", "rpc", "set commuic ation type example rpc or mdns, default is rpc")
|
||||
flag.Parse()
|
||||
if *info {
|
||||
srvversion.Info() //内部会自动退进程.
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
cmdLine()
|
||||
server.Run(os.Args)
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package api_security
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func BodyDump() gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
// fmt.Println("=========================== 1")
|
||||
|
||||
// fmt.Printf("%+v\n", ctx.Request.Header)
|
||||
|
||||
// data, e := ioutil.ReadAll(ctx.Request.Body)
|
||||
// if e != nil {
|
||||
// ctx.AbortWithStatusJSON(500, "protosign: read data failed")
|
||||
// return
|
||||
// }
|
||||
|
||||
// fmt.Println("=========================== 3")
|
||||
// fmt.Println(hex.Dump(data))
|
||||
|
||||
// fmt.Println("=========================== 4")
|
||||
// ctx.Request.Body = &signReader{
|
||||
// *bytes.NewReader(data),
|
||||
// ctx.Request.Body,
|
||||
// }
|
||||
// fmt.Println("=========================== 5")
|
||||
// ctx.Next()
|
||||
// fmt.Println("=========================== 6")
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package api_security
|
||||
|
||||
const XProtoSign = "X-Proto-Sign"
|
||||
const XProtoNonce = "X-Proto-Nonce"
|
||||
const XProtoTimestamp = "X-Proto-Timestamp"
|
||||
@@ -0,0 +1,25 @@
|
||||
package api_security
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
func GenerateKey(secret string) []byte {
|
||||
key := sha256.Sum256([]byte(secret))
|
||||
return key[:]
|
||||
}
|
||||
|
||||
func GenerateIV(secret, salt string) []byte {
|
||||
return GenerateKey(secret + salt)[:16]
|
||||
}
|
||||
|
||||
const strPool = "012345679qwertyuioplkjhgfdsazxcvbnmQWERTYUIOPLKJHGFDSAZXCVBNM"
|
||||
|
||||
func GenerateIVSalt() string {
|
||||
var n [16]byte
|
||||
for i := 0; i < 16; i++ {
|
||||
n[i] = byte(strPool[rand.Intn(len(strPool))])
|
||||
}
|
||||
return string(n[:])
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package api_security
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGenerateSalt(t *testing.T) {
|
||||
for i := 0; i < 5; i++ {
|
||||
fmt.Println(GenerateIVSalt())
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkGenerateSalt(b *testing.B) {
|
||||
GenerateIV("asdfasdfasdf", GenerateIVSalt())
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package api_security
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type signReader struct {
|
||||
bytes.Reader
|
||||
RC io.ReadCloser
|
||||
}
|
||||
|
||||
func (thiz *signReader) Close() error {
|
||||
return thiz.RC.Close()
|
||||
}
|
||||
|
||||
func calcSign(kv map[string][]byte) string {
|
||||
keys := make([]string, 0, len(kv))
|
||||
for k := range kv {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
|
||||
h := sha256.New()
|
||||
for _, k := range keys {
|
||||
_, _ = h.Write([]byte(k))
|
||||
_, _ = h.Write(kv[k])
|
||||
}
|
||||
|
||||
return strings.ToLower(hex.EncodeToString(h.Sum(nil)))
|
||||
}
|
||||
|
||||
func ProtoSign(secret []byte,
|
||||
shouldCrypto ShouldCryptoChecker) gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
|
||||
if shouldCrypto != nil && !shouldCrypto(ctx) {
|
||||
ctx.Next()
|
||||
return
|
||||
}
|
||||
|
||||
sign := ctx.GetHeader(XProtoSign)
|
||||
nonce := ctx.GetHeader(XProtoNonce)
|
||||
ts := ctx.GetHeader(XProtoTimestamp)
|
||||
|
||||
if len(sign) != 64 || len(nonce) < 10 || len(ts) < 6 {
|
||||
ctx.AbortWithStatusJSON(500, "protosign: argument invalid")
|
||||
return
|
||||
}
|
||||
|
||||
data, e := ioutil.ReadAll(ctx.Request.Body)
|
||||
if e != nil {
|
||||
ctx.AbortWithStatusJSON(500, "protosign: read data failed")
|
||||
return
|
||||
}
|
||||
|
||||
kv := make(map[string][]byte)
|
||||
kv[XProtoNonce] = []byte(nonce)
|
||||
kv[XProtoTimestamp] = []byte(ts)
|
||||
kv["_METHOD_"] = []byte(ctx.Request.Method)
|
||||
kv["_PATH_"] = []byte(ctx.Request.URL.Path)
|
||||
kv["_SECRET_"] = secret
|
||||
|
||||
queries := map[string][]string(ctx.Request.URL.Query())
|
||||
for k, v := range queries {
|
||||
if len(v) > 0 {
|
||||
kv[fmt.Sprintf("_QUERY_%s_", strings.ToUpper(k))] = []byte(v[0])
|
||||
}
|
||||
}
|
||||
|
||||
if len(data) > 0 {
|
||||
kv["_BODY_"] = []byte(data)
|
||||
}
|
||||
|
||||
if calcSign(kv) != sign {
|
||||
ctx.AbortWithStatusJSON(500, "protosign: verify sign failed")
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Request.Body = &signReader{
|
||||
*bytes.NewReader(data),
|
||||
ctx.Request.Body,
|
||||
}
|
||||
ctx.Next()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package api_security
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestUrl(t *testing.T) {
|
||||
|
||||
u, _ := url.Parse("http://a.b.com/api/a/b/c?a=%20123")
|
||||
fmt.Printf("path: %s\n", u.Path)
|
||||
fmt.Printf("rawpath: %s\n", u.RawQuery)
|
||||
fmt.Printf("escapedpath: %s\n", u.EscapedPath())
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package api_security
|
||||
|
||||
import (
|
||||
"crypto/cipher"
|
||||
"io"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type ShouldCryptoChecker func(ctx *gin.Context) bool
|
||||
|
||||
type cryptoReader struct {
|
||||
S cipher.Stream
|
||||
RC io.ReadCloser
|
||||
}
|
||||
|
||||
func (r *cryptoReader) Read(dst []byte) (n int, err error) {
|
||||
n, err = r.RC.Read(dst)
|
||||
r.S.XORKeyStream(dst[:n], dst[:n])
|
||||
return
|
||||
}
|
||||
|
||||
func (r *cryptoReader) Close() error {
|
||||
return r.RC.Close()
|
||||
}
|
||||
|
||||
type cryptoWriter struct {
|
||||
gin.ResponseWriter
|
||||
writer *cipher.StreamWriter
|
||||
}
|
||||
|
||||
func (g *cryptoWriter) WriteString(s string) (int, error) {
|
||||
return g.writer.Write([]byte(s))
|
||||
}
|
||||
|
||||
func (g *cryptoWriter) Write(data []byte) (int, error) {
|
||||
return g.writer.Write(data)
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package apilimitHandler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type counter struct {
|
||||
Count int
|
||||
WindowStart time.Time
|
||||
}
|
||||
|
||||
type RouteHourlyLimiter struct {
|
||||
mu sync.Mutex
|
||||
limit int
|
||||
window time.Duration
|
||||
counters map[string]*counter
|
||||
}
|
||||
|
||||
func NewRouteHourlyLimiter(limit int) *RouteHourlyLimiter {
|
||||
l := &RouteHourlyLimiter{
|
||||
limit: limit,
|
||||
window: time.Hour,
|
||||
counters: make(map[string]*counter),
|
||||
}
|
||||
go l.cleaner()
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *RouteHourlyLimiter) Middleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// 用 FullPath 做“接口维度”,例如 /api/user/:id
|
||||
route := c.FullPath()
|
||||
if route == "" {
|
||||
// 路由未匹配时兜底
|
||||
route = c.Request.URL.Path
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
|
||||
item, ok := l.counters[route]
|
||||
if !ok || now.Sub(item.WindowStart) >= l.window {
|
||||
l.counters[route] = &counter{
|
||||
Count: 1,
|
||||
WindowStart: now,
|
||||
}
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
if item.Count >= l.limit {
|
||||
c.AbortWithStatusJSON(http.StatusTooManyRequests, gin.H{
|
||||
"code": http.StatusTooManyRequests,
|
||||
"message": "rate limit exceeded: max 100 requests per route per hour",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
item.Count++
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// 定时清理过期窗口,避免 map 无限增长
|
||||
func (l *RouteHourlyLimiter) cleaner() {
|
||||
ticker := time.NewTicker(10 * time.Minute)
|
||||
defer ticker.Stop()
|
||||
|
||||
for now := range ticker.C {
|
||||
l.mu.Lock()
|
||||
for k, v := range l.counters {
|
||||
if now.Sub(v.WindowStart) >= l.window {
|
||||
delete(l.counters, k)
|
||||
}
|
||||
}
|
||||
l.mu.Unlock()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"videoweb/pub/common"
|
||||
"videoweb/pub/common/errors"
|
||||
"videoweb/pub/common/ipaddr"
|
||||
"videoweb/pub/common/log"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/common/utils"
|
||||
"videoweb/pub/models/mwacc"
|
||||
"videoweb/pub/models/oplog"
|
||||
"videoweb/web/webg"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
var (
|
||||
RoleApiMenus = map[int64][]string{} // 角色Api
|
||||
mutex sync.RWMutex
|
||||
)
|
||||
|
||||
var (
|
||||
tokener = utils.NewTokenRedis()
|
||||
)
|
||||
|
||||
const (
|
||||
AccId = "ACC_ID"
|
||||
roleAuthAdrr = "/web/role/getauth"
|
||||
)
|
||||
|
||||
type APIInfo struct {
|
||||
Api string
|
||||
Desc string
|
||||
}
|
||||
|
||||
var (
|
||||
// 白名单,不需要验证token的api
|
||||
whiteList = []string{
|
||||
"/swagger",
|
||||
"/api/web/file/uploadImg",
|
||||
"/api/web/file/uploadImgs",
|
||||
"/api/web/media/videoBody",
|
||||
"/api/web/media/videoOk",
|
||||
"/api/web/m3u8",
|
||||
"/api/web/uploader/m3u8",
|
||||
"/api/web/enkey",
|
||||
"/api/web/newenkey",
|
||||
"/api/web/login/acc",
|
||||
"/api/web/login/bind",
|
||||
"/api/web/login/slogin",
|
||||
"/api/web/stat/media/list",
|
||||
"/api/web/stat/analytics",
|
||||
"/api/web/stat/daily/analytics",
|
||||
"/api/web/sync/video/list",
|
||||
"/api/web/sync/videocollection/list",
|
||||
"/api/web/sync/category/list",
|
||||
"/api/web/sync/creator/list",
|
||||
"/api/web/sync/tag/list",
|
||||
"/wbapi",
|
||||
"/api/web/third/newpaycenter/recharge/callback",
|
||||
}
|
||||
)
|
||||
|
||||
// 读取角色信息
|
||||
func GetRoleApiMenus(ctx context.Context, accid int64) (roles []string, err error) {
|
||||
mutex.RLock()
|
||||
roles, ok := RoleApiMenus[accid]
|
||||
mutex.RUnlock()
|
||||
if !ok {
|
||||
accInfo, dataErr := mwacc.FindOneAccByFilter(nil, bson.M{mwacc.FN.MwAcc.Id: accid})
|
||||
if dataErr != nil || accInfo.Id == 0 {
|
||||
return roles, dataErr
|
||||
}
|
||||
|
||||
roleInfo, roleErr := mwacc.FindOneRoleByFilter(ctx, bson.M{mwacc.FN.MwRole.Id: accInfo.RoleId})
|
||||
|
||||
if roleErr != nil || roleInfo.Id == 0 {
|
||||
return roles, roleErr
|
||||
}
|
||||
|
||||
if roleInfo.Name == "超级管理员" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
mutex.Lock()
|
||||
RoleApiMenus[accid] = roleInfo.ApiMenus
|
||||
mutex.Unlock()
|
||||
roles = roleInfo.ApiMenus
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 是否角色api
|
||||
func HasRoleApi(path string, apis []string) bool {
|
||||
apimap := make(map[string]struct{})
|
||||
for _, v := range apis {
|
||||
apimap[v] = struct{}{}
|
||||
}
|
||||
_, ok := apimap[path]
|
||||
return ok
|
||||
}
|
||||
|
||||
// 角色权限
|
||||
func handleRoles(ctx *gin.Context) (int, error) {
|
||||
path := ctx.Request.URL.Path
|
||||
if strings.HasPrefix(path, roleAuthAdrr) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
accid := ctx.GetInt(AccId)
|
||||
apis, err := GetRoleApiMenus(ctx, int64(accid))
|
||||
if err != nil {
|
||||
return int(errors.RoleErr), err
|
||||
}
|
||||
if apis == nil {
|
||||
return 0, nil
|
||||
}
|
||||
has := HasRoleApi(path, apis)
|
||||
if !has {
|
||||
return int(errors.RoleErr), srvdef.New(srvdef.RoleErr, (srvdef.RoleErr).Msg(), "")
|
||||
}
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// 验证后台账号IP
|
||||
func authMwIP(ctx *gin.Context) (int, error) {
|
||||
|
||||
cIP := ipaddr.ResolveClientIP(ctx)
|
||||
accid := ctx.GetInt64(AccId)
|
||||
accInfo, dataErr := mwacc.FindOneAccByFilter(nil, bson.M{mwacc.FN.MwAcc.Id: accid})
|
||||
if dataErr != nil || accInfo.Id == 0 {
|
||||
return int(errors.RoleErr), dataErr
|
||||
}
|
||||
if len(accInfo.LimitIP) != 0 {
|
||||
for _, v := range accInfo.LimitIP {
|
||||
if v == cIP {
|
||||
return 0, nil
|
||||
}
|
||||
}
|
||||
return int(errors.LimitIPErr), dataErr
|
||||
} else {
|
||||
return int(errors.LimitIPErr), dataErr
|
||||
}
|
||||
|
||||
// return 0, nil
|
||||
}
|
||||
|
||||
// 验证
|
||||
func Auth(ctx *gin.Context) {
|
||||
//for test
|
||||
//ctx.Set(AccId, int64(1000))
|
||||
//return
|
||||
// 对指定 group 跳过
|
||||
if strings.HasPrefix(ctx.Request.URL.Path, "/mdps/mdcom/api/web") {
|
||||
ctx.Next()
|
||||
return
|
||||
}
|
||||
p := ctx.Request.URL.Path
|
||||
if strings.Contains(p, "swagger") {
|
||||
return
|
||||
}
|
||||
for _, w := range whiteList {
|
||||
if strings.HasPrefix(ctx.Request.URL.Path, w) {
|
||||
return
|
||||
}
|
||||
}
|
||||
if v, ok := common.ApiSetMaps[p]; ok {
|
||||
fmt.Println(v.IsWhite)
|
||||
if v.IsWhite {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
doToken := func() (int, error) {
|
||||
checkToken := ctx.Request.Header.Get("Authorization")
|
||||
// 去掉Bearer,如果有
|
||||
checkToken = utils.StripBearerPrefixFromTokenString(checkToken)
|
||||
|
||||
if checkToken == "" {
|
||||
return http.StatusUnauthorized, srvdef.New(srvdef.NoToken, (srvdef.NoToken).Msg(), "")
|
||||
}
|
||||
|
||||
has, err := mwacc.CheckToken(ctx, checkToken)
|
||||
if err != nil {
|
||||
return http.StatusUnauthorized, err
|
||||
}
|
||||
if !has {
|
||||
return http.StatusUnauthorized, srvdef.New(srvdef.ReLogin, (srvdef.ReLogin).Msg(), "")
|
||||
}
|
||||
|
||||
userId, _, err := utils.ParseUserToken(checkToken, webg.Conf.JwtKey)
|
||||
if err != nil {
|
||||
return http.StatusUnauthorized, srvdef.New(srvdef.InvalidToken, (srvdef.InvalidToken).Msg(), "")
|
||||
}
|
||||
// log.Info("Auth test", log.Any("checkToken", checkToken), log.Any("userId", userId))
|
||||
ctx.Set(AccId, userId)
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
statusCode, err := doToken()
|
||||
if err != nil || statusCode != 0 {
|
||||
ctx.AbortWithStatusJSON(statusCode, err)
|
||||
return
|
||||
}
|
||||
|
||||
roleCode, err := handleRoles(ctx)
|
||||
if err != nil || roleCode != 0 {
|
||||
ctx.AbortWithStatusJSON(http.StatusForbidden, err)
|
||||
}
|
||||
|
||||
// authIPCode, err2 := authMwIP(ctx)
|
||||
// if err2 != nil || authIPCode != 0 {
|
||||
// ctx.AbortWithStatusJSON(http.StatusForbidden, err)
|
||||
// }
|
||||
}
|
||||
|
||||
// func userAgentHandler(ctx *gin.Context) {
|
||||
// userAgent := ctx.Request.Header.Get("User-Agent")
|
||||
// if userAgent != "" {
|
||||
// fields := strings.Fields(userAgent)
|
||||
// curVersion := fields[len(fields)-1]
|
||||
// if strings.HasPrefix(curVersion, "version:") {
|
||||
// versionNum := strings.Split(curVersion, ":")[1]
|
||||
// ctx.Set("VERSION", versionNum)
|
||||
// } else {
|
||||
// ctx.Set("VERSION", "")
|
||||
// }
|
||||
// }
|
||||
// if strings.Contains(userAgent, "Android") {
|
||||
// ctx.Set("SYSTEM", "android")
|
||||
// }
|
||||
// if strings.Contains(userAgent, "iPhone") {
|
||||
// ctx.Set("SYSTEM", "ios")
|
||||
// }
|
||||
|
||||
// // 增加 不签名,不加密 开关
|
||||
// }
|
||||
|
||||
// 操作日志
|
||||
func OperateLog(ctx *gin.Context) {
|
||||
desc := ""
|
||||
find := false
|
||||
for _, w := range LogList {
|
||||
if ctx.Request.URL.Path == w.Api {
|
||||
find = true
|
||||
desc = w.Desc
|
||||
}
|
||||
}
|
||||
if !find {
|
||||
ctx.Next()
|
||||
return
|
||||
}
|
||||
|
||||
accId := ctx.GetInt64(AccId)
|
||||
rawData, err := ctx.GetRawData()
|
||||
ip := ipaddr.ResolveClientIP(ctx)
|
||||
if err != nil {
|
||||
ctx.AbortWithStatusJSON(400, err)
|
||||
}
|
||||
|
||||
log.Info("OperateLog Test", log.Any("vmap.Path", ctx.Request.URL.Path))
|
||||
|
||||
err = oplog.AddLog(ctx, ctx.Request.URL.Path, desc, accId, string(rawData), ip)
|
||||
if err != nil {
|
||||
ctx.AbortWithStatusJSON(int(errors.OperateLog), err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Request.Body = ioutil.NopCloser(bytes.NewBuffer(rawData)) // 将取出来的执行条件放回ctx中
|
||||
ctx.Next()
|
||||
}
|
||||
|
||||
func GetAccount(ctx *gin.Context) int64 {
|
||||
return ctx.GetInt64(AccId)
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package auth
|
||||
|
||||
var LogList = []APIInfo{
|
||||
{"/api/web/acc/add", "账号-添加"},
|
||||
{"/api/web/acc/del", "账号-删除"},
|
||||
{"/api/web/acc/up", "账号-更新"},
|
||||
{"/api/web/acc/savestatus", "账号-保存状态"},
|
||||
{"/api/web/acc/uppwd", "账号-更新密码"},
|
||||
{"/api/web/login/acc", "登录-登录"},
|
||||
{"/api/web/login/slogin", "管理员sso登陆"},
|
||||
{"/api/web/role/add", "角色-添加"},
|
||||
{"/api/web/role/del", "角色-删除"},
|
||||
{"/api/web/role/up", "角色-更新"},
|
||||
{"/api/web/role/enable", "角色-使能"},
|
||||
{"/api/web/role/upauth", "角色-更新权限"},
|
||||
{"/api/web/syscfg/update", "修改系统配置"},
|
||||
{"/api/web/syscfg/appkey", "设置媒资库appKey"},
|
||||
{"/api/web/post/comment/del", "删除一个评论"},
|
||||
{"/api/web/post/comment/user/del", "删除一个用户所有评论"},
|
||||
{"/api/web/post/comment/replay", "回复评论"},
|
||||
{"/api/web/post/comment/reviewBatch", "批量审核评论"},
|
||||
{"/api/web/post/comment/review", "审核评论"},
|
||||
{"/api/web/ipblack/add", "IP黑名单-增加"},
|
||||
{"/api/web/ipblack/del", "IP黑名单-删除"},
|
||||
{"/api/web/announcement/add", "公告-增加"},
|
||||
{"/api/web/announcement/del", "公告-删除"},
|
||||
{"/api/web/announcement/update", "公告-更新"},
|
||||
{"/api/web/richtextcontent/add", "添加一个富文本内容"},
|
||||
{"/api/web/richtextcontent/del", "删除一个富文本内容"},
|
||||
{"/api/web/richtextcontent/update", "更新一个富文本内容"},
|
||||
{"/api/web/translationcategory/add", "添加一个导航分类"},
|
||||
{"/api/web/translationcategory/del", "删除一个导航分类"},
|
||||
{"/api/web/translationcategory/update", "更新一个导航分类"},
|
||||
{"/api/web/translation/add", "添加一个导航跳转信息"},
|
||||
{"/api/web/translation/del", "删除一个导航跳转信息"},
|
||||
{"/api/web/translation/update", "更新一个导航跳转信息"},
|
||||
{"/api/web/videocategory/add", "添加一个视频分类"},
|
||||
{"/api/web/videocategory/del", "删除一个视频分类"},
|
||||
{"/api/web/videocategory/update", "更新一个视频分类"},
|
||||
{"/api/web/videocreater/add", "添加一个视频作者"},
|
||||
{"/api/web/videocreater/del", "删除一个视频作者"},
|
||||
{"/api/web/videocreater/update", "更新一个视频作者"},
|
||||
{"/api/web/videotag/add", "添加一个标签管理"},
|
||||
{"/api/web/videotag/del", "删除一个标签管理"},
|
||||
{"/api/web/videotag/update", "更新一个标签管理"},
|
||||
{"/api/web/videoinfo/del", "删除一个视频管理"},
|
||||
{"/api/web/videoinfo/update", "更新一个视频管理"},
|
||||
{"/api/web/videoinfo/setFakeWatchTimes", "设置视频假观看次数"},
|
||||
{"/api/web/videoinfo/category/set", "视频-设置分类"},
|
||||
{"/api/web/videocollection/media/option", "修改合集里的视频列表"},
|
||||
{"/api/web/videocollection/media/rank", "修改合集里的视频排序"},
|
||||
{"/api/web/videoinfo/addcoll", "新增一个视频合集"},
|
||||
{"/api/web/actress/add", "添加一个女优信息"},
|
||||
{"/api/web/actress/del", "删除一个女优信息"},
|
||||
{"/api/web/actress/update", "更新一个女优信息"},
|
||||
{"/api/web/user/updatetype", "修改用户类型"},
|
||||
{"/api/web/user/giftcoin", "赠送/扣除用户金币"},
|
||||
{"/api/web/coin/recharge/add", "新增金币充值配置"},
|
||||
{"/api/web/coin/recharge/del", "删除金币充值配置"},
|
||||
{"/api/web/coin/recharge/update", "更新金币充值配置"},
|
||||
{"/api/web/merchant/list", "手动拉取商家列表"},
|
||||
{"/api/web/merchant/detail", "手动拉取商家详情"},
|
||||
{"/api/web/feedback/handle", "处理用户意见反馈"},
|
||||
{"/api/web/contactus/handle", "处理联系我们"},
|
||||
{"/api/web/home/banner/add", "首页banner-新增"},
|
||||
{"/api/web/home/banner/update", "首页banner-更新"},
|
||||
{"/api/web/home/banner/del", "首页banner-删除"},
|
||||
{"/api/web/home/config/add", "首页配置-新增"},
|
||||
{"/api/web/home/config/update", "首页配置-更新"},
|
||||
{"/api/web/home/config/del", "首页配置-删除"},
|
||||
// 短剧
|
||||
{"/api/web/playlet/add", "短剧-新增"},
|
||||
{"/api/web/playlet/update", "短剧-更新"},
|
||||
{"/api/web/playlet/status/set", "短剧-设置上下架"},
|
||||
{"/api/web/playlet/recommend/set", "短剧-设置推荐"},
|
||||
{"/api/web/playlet/featured/set", "短剧-设置爆剧"},
|
||||
{"/api/web/playlet/operate-type/set", "短剧-设置运营类型"},
|
||||
{"/api/web/playlet/banner/set", "短剧-设置banner展示"},
|
||||
{"/api/web/playlet/theme/set", "短剧-设置题材"},
|
||||
{"/api/web/playlet/theme/recommend/set", "短剧题材-设置推荐"},
|
||||
{"/api/web/playlet/tag/set", "短剧-设置标签"},
|
||||
{"/api/web/playlet/category/set", "短剧-设置分类"},
|
||||
{"/api/web/playlet/pay-type/set", "短剧-设置支付方式"},
|
||||
{"/api/web/playlet/watermark/reset", "短剧-重置水印"},
|
||||
{"/api/web/playlet/slug/sync", "短剧-同步历史slug"},
|
||||
{"/api/web/videoinfo/slug/sync", "视频-同步历史slug"},
|
||||
{"/api/web/playlet/chapter/add", "短剧剧集-新增"},
|
||||
{"/api/web/playlet/chapter/update", "短剧剧集-更新"},
|
||||
{"/api/web/playlet/chapter/del", "短剧剧集-删除"},
|
||||
{"/api/web/playlet/chapter/status/fill", "短剧剧集-回填上架状态"},
|
||||
{"/api/web/playlet/chapter/status/set", "短剧剧集-设置上架状态"},
|
||||
{"/api/web/playlet/chapter/pay-type/set", "短剧剧集-设置支付方式"},
|
||||
{"/api/web/playlet/chapter/sync", "短剧剧集-手动同步"},
|
||||
{"/api/web/playlet/theme/add", "短剧题材-新增"},
|
||||
{"/api/web/playlet/theme/update", "短剧题材-更新"},
|
||||
{"/api/web/playlet/theme/del", "短剧题材-删除"},
|
||||
{"/api/web/playlet/tag/add", "短剧标签-新增"},
|
||||
{"/api/web/playlet/tag/update", "短剧标签-更新"},
|
||||
{"/api/web/playlet/tag/del", "短剧标签-删除"},
|
||||
{"/api/web/resource/import", "短剧媒资-入库"},
|
||||
{"/api/web/card/order/district/sync", "充值订单-同步历史渠道码"},
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package cors
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
Origin *[]string // 传入空指针,表示允许"*", 传入空数组表示禁止跨域
|
||||
Methods []string // Methods
|
||||
AllowedHeaders []string // AllowHeaders
|
||||
ExposedHeaders []string // exposeHeader
|
||||
Credentials bool // cookie
|
||||
MaxAge int64 // 缓存MaxAge
|
||||
PreflightContinue bool // 在遇到Options的时候,继续,而不是返回请求
|
||||
OptionsSuccessStatus int // Options时,返回的状态码,默认204
|
||||
}
|
||||
|
||||
func configureOrigin(o *Options, c *gin.Context) map[string]string {
|
||||
reqOrigin := c.GetHeader("Origin")
|
||||
headers := make(map[string]string)
|
||||
if o.Origin == nil {
|
||||
headers["Access-Control-Allow-Origin"] = "*"
|
||||
} else {
|
||||
isAllowed := false
|
||||
for _, allowed := range *o.Origin {
|
||||
if allowed == reqOrigin {
|
||||
isAllowed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if isAllowed {
|
||||
headers["Access-Control-Allow-Origin"] = reqOrigin
|
||||
} else {
|
||||
headers["Access-Control-Allow-Origin"] = strconv.FormatBool(false)
|
||||
}
|
||||
headers["Vary"] = "Origin"
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func configureMethods(o *Options) map[string]string {
|
||||
headers := make(map[string]string)
|
||||
if len(o.Methods) > 0 {
|
||||
headers["Access-Control-Allow-Methods"] = strings.ToUpper(strings.Join(o.Methods, ","))
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func configureCredentials(o *Options) map[string]string {
|
||||
headers := make(map[string]string)
|
||||
if o.Credentials {
|
||||
headers["Access-Control-Allow-Credentials"] = strconv.FormatBool(true)
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func configureAllowedHeaders(o *Options, c *gin.Context) map[string]string {
|
||||
headers := make(map[string]string)
|
||||
if len(o.AllowedHeaders) > 0 {
|
||||
headers["Access-Control-Allow-Headers"] = strings.Join(o.AllowedHeaders, ",")
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func configureExposedHeaders(o *Options) map[string]string {
|
||||
var headers = make(map[string]string)
|
||||
if len(o.ExposedHeaders) > 0 {
|
||||
headers["Access-Control-Expose-Headers"] = strings.Join(o.ExposedHeaders, ",")
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func configureMaxAge(o *Options) map[string]string {
|
||||
var headers = make(map[string]string)
|
||||
if o.MaxAge >= 0 {
|
||||
headers["Access-Control-Max-Age"] = strconv.FormatInt(o.MaxAge, 10)
|
||||
}
|
||||
return headers
|
||||
}
|
||||
|
||||
func mergeMap(m ...map[string]string) map[string]string {
|
||||
r := make(map[string]string)
|
||||
for _, t := range m {
|
||||
for k, v := range t {
|
||||
r[k] = v
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func applyHeader(c *gin.Context, h map[string]string) {
|
||||
for k, v := range h {
|
||||
c.Header(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
// Cors 跨域处理
|
||||
func Cors(o *Options) gin.HandlerFunc {
|
||||
if o.OptionsSuccessStatus == 0 {
|
||||
o.OptionsSuccessStatus = http.StatusNoContent
|
||||
}
|
||||
return func(c *gin.Context) {
|
||||
method := c.Request.Method
|
||||
// c.Header("Access-Control-Allow-Origin", "*")
|
||||
// c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token,Authorization,Token,Content-Length,Etag,Content-Range,Accept-Ranges,User-Agent,Range,Bucket,Content-Disposition,Signature,X-Forwarded-For,X-Real-Ip")
|
||||
if method == "OPTIONS" {
|
||||
h := mergeMap(
|
||||
configureOrigin(o, c),
|
||||
configureCredentials(o),
|
||||
configureMethods(o),
|
||||
configureAllowedHeaders(o, c),
|
||||
configureMaxAge(o),
|
||||
configureExposedHeaders(o),
|
||||
)
|
||||
applyHeader(c, h)
|
||||
if o.PreflightContinue {
|
||||
c.Next()
|
||||
} else {
|
||||
c.Header("Content-Length", "0")
|
||||
c.AbortWithStatus(o.OptionsSuccessStatus)
|
||||
}
|
||||
} else {
|
||||
h := mergeMap(
|
||||
configureOrigin(o, c),
|
||||
configureCredentials(o),
|
||||
configureExposedHeaders(o),
|
||||
)
|
||||
applyHeader(c, h)
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package ipblacklist
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"videoweb/pub/common/ipaddr"
|
||||
"videoweb/web/service/srv_ipblack"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func IpBlackListMiddleware(ctx *gin.Context) {
|
||||
ip := ipaddr.ResolveClientIP(ctx)
|
||||
if srv_ipblack.CheckIp(ip) {
|
||||
ctx.AbortWithStatusJSON(http.StatusUnauthorized, errors.New("login limit"))
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
package limitHandler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
"videoweb/pub/common"
|
||||
httpUtil "videoweb/pub/common/http"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/web/webg"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/patrickmn/go-cache"
|
||||
)
|
||||
|
||||
var limitURI = []string{
|
||||
"/api/web/login/slogin",
|
||||
"/api/web/login/acc",
|
||||
}
|
||||
|
||||
var (
|
||||
tgBotToken = "2013237388:AAFwvKvEmQfEvcI7wt_64Zkp9KPfgHo8sow"
|
||||
tgGroupId = "-1003735177636"
|
||||
)
|
||||
|
||||
var (
|
||||
limitDuration = time.Minute
|
||||
limitCount = 5
|
||||
)
|
||||
|
||||
var memCache = cache.New(1*time.Minute, 10*time.Minute)
|
||||
|
||||
// LoginLimit 登陆频率限制:按账号维度限制,不依赖 ClientIP(可被伪造)。
|
||||
func LoginLimit(ctx *gin.Context) {
|
||||
path := ctx.Request.URL.Path
|
||||
|
||||
check := false
|
||||
for _, p := range limitURI {
|
||||
if strings.HasPrefix(path, p) {
|
||||
check = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !check {
|
||||
ctx.Next()
|
||||
return
|
||||
}
|
||||
|
||||
// 测试环境不限制
|
||||
if webg.Conf.RunMod != "prod" {
|
||||
ctx.Next()
|
||||
return
|
||||
}
|
||||
|
||||
var params map[string]interface{}
|
||||
var acc string
|
||||
if ctx.Request.Method == http.MethodPost {
|
||||
raw, _ := ctx.GetRawData()
|
||||
ctx.Request.Body = io.NopCloser(bytes.NewBuffer(raw))
|
||||
if err := json.Unmarshal(raw, ¶ms); err == nil {
|
||||
if a, ok := params["acc"].(string); ok {
|
||||
acc = strings.TrimSpace(a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 无账号时无法按账号限流,交由后续登录逻辑处理参数错误
|
||||
if acc == "" {
|
||||
ctx.Next()
|
||||
return
|
||||
}
|
||||
|
||||
key := fmt.Sprintf("web-limit:%s:%s", path, acc)
|
||||
|
||||
count := 1
|
||||
if aCount, ok := memCache.Get(key); ok {
|
||||
if n, ok2 := aCount.(int); ok2 {
|
||||
count = n + 1
|
||||
}
|
||||
}
|
||||
memCache.Set(key, count, limitDuration)
|
||||
|
||||
if count > limitCount {
|
||||
go func(acc, path string, count int, params map[string]interface{}) {
|
||||
message := fmt.Sprintf(
|
||||
"[91猎艳]\n登陆请求频率过高!\n时间: %s\n请求地址: %s\n账号: %s\n请求参数: %+v\n错误次数: %d",
|
||||
time.Now().Format("2006-01-02 15:04:05"),
|
||||
path,
|
||||
acc,
|
||||
params,
|
||||
count,
|
||||
)
|
||||
// 请求地址/参数为不可信输入,去掉非法 UTF-8 字节;不用 parse_mode,避免 Markdown 把内容解析成实体后报错
|
||||
message = strings.ToValidUTF8(message, "")
|
||||
|
||||
url := fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", tgBotToken)
|
||||
req := map[string]interface{}{
|
||||
"chat_id": tgGroupId,
|
||||
"text": message,
|
||||
}
|
||||
jsonBytes, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
header := map[string]string{"Content-Type": "application/json"}
|
||||
resp, _ := httpUtil.Post(url, header, bytes.NewReader(jsonBytes))
|
||||
_ = resp.Data
|
||||
}(acc, path, count, params)
|
||||
|
||||
common.ServerJSON(ctx, srvdef.ErrReqForbidden, nil)
|
||||
ctx.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Next()
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package validator
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
"github.com/go-playground/locales/en"
|
||||
ut "github.com/go-playground/universal-translator"
|
||||
"gopkg.in/go-playground/validator.v9"
|
||||
en_translations "gopkg.in/go-playground/validator.v9/translations/en"
|
||||
)
|
||||
|
||||
var (
|
||||
ValidatorUni *ut.UniversalTranslator
|
||||
)
|
||||
|
||||
type defaultValidator struct {
|
||||
once sync.Once
|
||||
validate *validator.Validate
|
||||
}
|
||||
|
||||
var v binding.StructValidator = &defaultValidator{}
|
||||
|
||||
func init() {
|
||||
v.Engine()
|
||||
}
|
||||
|
||||
func (v *defaultValidator) ValidateStruct(obj interface{}) error {
|
||||
|
||||
if kindOfData(obj) == reflect.Struct {
|
||||
|
||||
v.lazyinit()
|
||||
|
||||
if err := v.validate.Struct(obj); err != nil {
|
||||
return error(err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *defaultValidator) Engine() interface{} {
|
||||
v.lazyinit()
|
||||
return v.validate
|
||||
}
|
||||
|
||||
func (v *defaultValidator) lazyinit() {
|
||||
v.once.Do(func() {
|
||||
v.validate = validator.New()
|
||||
|
||||
// 依旧使用bingding tag兼容v8
|
||||
v.validate.SetTagName("binding")
|
||||
|
||||
// 错误信息转换
|
||||
en := en.New()
|
||||
ValidatorUni = ut.New(en, en)
|
||||
trans, _ := ValidatorUni.GetTranslator("en")
|
||||
en_translations.RegisterDefaultTranslations(v.validate, trans)
|
||||
|
||||
v.validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
|
||||
name := strings.SplitN(fld.Tag.Get("comment"), ",", 2)[0]
|
||||
if name == "-" {
|
||||
return ""
|
||||
}
|
||||
return name
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func kindOfData(data interface{}) reflect.Kind {
|
||||
|
||||
value := reflect.ValueOf(data)
|
||||
valueType := value.Kind()
|
||||
|
||||
if valueType == reflect.Ptr {
|
||||
valueType = value.Elem().Kind()
|
||||
}
|
||||
return valueType
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package validator
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
)
|
||||
|
||||
// 替换gin 默认v8验证器
|
||||
// 改为v9
|
||||
func init() {
|
||||
binding.Validator = new(defaultValidator)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"videoweb/web/api/web_announcement"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func announcementRouter(router *gin.RouterGroup) {
|
||||
group := router.Group("/announcement")
|
||||
{
|
||||
group.POST("/list", web_announcement.AnnouncementList)
|
||||
group.POST("/add", web_announcement.AnnouncementAdd)
|
||||
group.POST("/del", web_announcement.AnnouncementDel)
|
||||
group.POST("/update", web_announcement.AnnouncementUpdate)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
webanalytics "videoweb/web/api/web_analytics"
|
||||
"videoweb/web/api/web_cfg"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func syscfgRouter(router *gin.RouterGroup) {
|
||||
system := router.Group("/syscfg")
|
||||
{
|
||||
system.GET("/get", web_cfg.GetCfg)
|
||||
system.POST("/update", web_cfg.UpdateCfg)
|
||||
system.POST("/appkey", web_cfg.SetAppKey)
|
||||
}
|
||||
|
||||
stat := router.Group("/stat")
|
||||
{
|
||||
stat.GET("/analytics", webanalytics.GetAnalyticsStat)
|
||||
stat.GET("/daily/analytics", webanalytics.GetAnalyticsDailyStat)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"videoweb/web/api/web_card"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func cardRouter(router *gin.RouterGroup) {
|
||||
card := router.Group("/card")
|
||||
{
|
||||
card.POST("/order/list", web_card.GetOrders)
|
||||
card.POST("/order/district/sync", web_card.SyncDistrictCode)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"videoweb/web/api/web_coin"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func coinRouter(router *gin.RouterGroup) {
|
||||
coin := router.Group("/coin")
|
||||
{
|
||||
coin.POST("/trans", web_coin.GetCoinTrans)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"videoweb/web/api/web_commend"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func commentRouter(router *gin.RouterGroup) {
|
||||
group := router.Group("/post")
|
||||
{
|
||||
group.POST("/comment/list", web_commend.SearchManyCommend)
|
||||
group.POST("/comment/replay", web_commend.ReplayPostComment)
|
||||
group.POST("/comment/del", web_commend.DelCommend)
|
||||
group.POST("/comment/user/del", web_commend.DelUserCommend)
|
||||
group.POST("/comment/reviewBatch", web_commend.ReviewCommendBatch)
|
||||
group.POST("/comment/review", web_commend.ReviewComment)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"videoweb/web/api/web_contactus"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func contactUsRouter(router *gin.RouterGroup) {
|
||||
group := router.Group("/contactus")
|
||||
{
|
||||
group.GET("/list", web_contactus.List)
|
||||
group.POST("/handle", web_contactus.Handle)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"videoweb/web/api/web_detailnav"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func detailNavRouter(router *gin.RouterGroup) {
|
||||
group := router.Group("/detailnav")
|
||||
{
|
||||
group.POST("/list", web_detailnav.DetailNavList)
|
||||
group.POST("/add", web_detailnav.DetailNavAdd)
|
||||
group.POST("/del", web_detailnav.DetailNavDel)
|
||||
group.POST("/update", web_detailnav.DetailNavUpdate)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"videoweb/web/api/web_feedback"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func feedbackRouter(router *gin.RouterGroup) {
|
||||
group := router.Group("/feedback")
|
||||
{
|
||||
group.GET("/list", web_feedback.List)
|
||||
group.POST("/handle", web_feedback.Handle)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"videoweb/web/api/web_file"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func fileRouter(router *gin.RouterGroup) {
|
||||
// 文件上传
|
||||
file := router.Group("/file")
|
||||
{
|
||||
file.POST("/uploadImg", web_file.UploadImage)
|
||||
file.POST("/uploadImgs", web_file.UploadImages)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"videoweb/pub/common/errors"
|
||||
"videoweb/pub/common/log"
|
||||
"videoweb/pub/common/useragent"
|
||||
"videoweb/web/middleware/auth"
|
||||
"videoweb/web/middleware/cors"
|
||||
"videoweb/web/middleware/ipblacklist"
|
||||
"videoweb/web/middleware/limitHandler"
|
||||
"videoweb/web/webg"
|
||||
|
||||
swaggerFiles "github.com/swaggo/files"
|
||||
ginSwagger "github.com/swaggo/gin-swagger"
|
||||
|
||||
"github.com/DeanThompson/ginpprof"
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
_ "videoweb/web/docs"
|
||||
)
|
||||
|
||||
func Init() (engine *gin.Engine) {
|
||||
|
||||
// 设置启动模式
|
||||
switch webg.Conf.RunMod {
|
||||
case "dev":
|
||||
gin.SetMode(gin.DebugMode)
|
||||
case "test":
|
||||
gin.SetMode(gin.TestMode)
|
||||
case "prod":
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
default:
|
||||
gin.SetMode(gin.DebugMode)
|
||||
}
|
||||
|
||||
// 初始化gin引擎
|
||||
engine = gin.Default()
|
||||
engine.HandleMethodNotAllowed = true
|
||||
engine.MaxMultipartMemory = 60 << 20
|
||||
|
||||
engine.NoMethod(noMethod)
|
||||
engine.NoRoute(noRoute)
|
||||
|
||||
// 注册中间件
|
||||
registeMiddleware(engine)
|
||||
wbVideoDataRouter(engine)
|
||||
registerRouter(engine)
|
||||
log.Info("setGinSwaggerxxxxx")
|
||||
|
||||
if webg.Conf.RunMod != "prod" {
|
||||
log.Info("setGinSwagger")
|
||||
setGinSwagger(engine)
|
||||
log.Info("setGinSwagger end")
|
||||
}
|
||||
|
||||
// 是否开启监控服务
|
||||
if webg.Conf.Pprof {
|
||||
ginpprof.Wrap(engine)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func noMethod(c *gin.Context) {
|
||||
c.JSON(http.StatusMethodNotAllowed, errors.MakeWithMsg(errors.MethodNotFound, "MethodNotFound"))
|
||||
}
|
||||
|
||||
func noRoute(c *gin.Context) {
|
||||
c.JSON(http.StatusNotFound, errors.MakeWithMsg(errors.ApiNotFound, "ApiNotFound"))
|
||||
}
|
||||
|
||||
func registeMiddleware(engine *gin.Engine) {
|
||||
engine.Use(gin.Recovery())
|
||||
engine.Use(cors.Cors(&cors.Options{
|
||||
Origin: nil, // "*"
|
||||
Methods: []string{http.MethodGet, http.MethodPost, http.MethodPut, http.MethodHead, http.MethodDelete},
|
||||
AllowedHeaders: []string{"Content-Length", "Content-Type", "Authorization", "X-User-Agent", useragent.SDKCommonHeader},
|
||||
ExposedHeaders: []string{"Content-Disposition", "Refresh-Authorization"},
|
||||
OptionsSuccessStatus: http.StatusOK,
|
||||
}))
|
||||
engine.Use(ipblacklist.IpBlackListMiddleware)
|
||||
engine.Use(auth.Auth)
|
||||
engine.Use(limitHandler.LoginLimit)
|
||||
engine.Use(auth.OperateLog)
|
||||
}
|
||||
|
||||
// 设置swag 接口信息
|
||||
func setGinSwagger(router *gin.Engine) {
|
||||
url := ginSwagger.URL(fmt.Sprintf("http://%s:%s/swagger/doc.json", webg.Conf.Host, webg.Conf.ListenAddr))
|
||||
router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, url))
|
||||
}
|
||||
|
||||
func registerRouter(router *gin.Engine) {
|
||||
rootRouter := router.Group("/api/web")
|
||||
{
|
||||
MainWebRouter(rootRouter)
|
||||
syscfgRouter(rootRouter)
|
||||
fileRouter(rootRouter)
|
||||
videoRouter(rootRouter)
|
||||
richTextContent(rootRouter)
|
||||
commentRouter(rootRouter)
|
||||
ipBlackRouter(rootRouter)
|
||||
detailNavRouter(rootRouter)
|
||||
announcementRouter(rootRouter)
|
||||
cardRouter(rootRouter)
|
||||
coinRouter(rootRouter)
|
||||
rechargePackageRouter(rootRouter)
|
||||
userRouter(rootRouter)
|
||||
translationRouter(rootRouter)
|
||||
mediaResourceRouter(rootRouter)
|
||||
playletRouter(rootRouter)
|
||||
homeBannerRouter(rootRouter)
|
||||
homeConfigRouter(rootRouter)
|
||||
feedbackRouter(rootRouter)
|
||||
contactUsRouter(rootRouter)
|
||||
}
|
||||
// 第三方回调路由(免鉴权,挂在 engine 上而非 /api/web 分组)
|
||||
thirdRouter(router)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"videoweb/web/api/web_homebanner"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func homeBannerRouter(router *gin.RouterGroup) {
|
||||
group := router.Group("/home/banner")
|
||||
{
|
||||
group.GET("/list", web_homebanner.List)
|
||||
group.POST("/add", web_homebanner.Add)
|
||||
group.POST("/update", web_homebanner.Update)
|
||||
group.POST("/del", web_homebanner.Del)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"videoweb/web/api/web_homeconfig"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func homeConfigRouter(router *gin.RouterGroup) {
|
||||
group := router.Group("/home/config")
|
||||
{
|
||||
group.GET("/list", web_homeconfig.List)
|
||||
group.POST("/add", web_homeconfig.Add)
|
||||
group.POST("/update", web_homeconfig.Update)
|
||||
group.POST("/del", web_homeconfig.Del)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"videoweb/web/api/web_ipblack"
|
||||
)
|
||||
|
||||
func ipBlackRouter(router *gin.RouterGroup) {
|
||||
// 文件上传
|
||||
group := router.Group("/ipblack")
|
||||
{
|
||||
group.POST("/list", web_ipblack.IpBlackList)
|
||||
group.POST("/add", web_ipblack.IpBlackAdd)
|
||||
group.POST("/del", web_ipblack.IpBlackDel)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"videoweb/web/api/web_mediaresource"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func mediaResourceRouter(router *gin.RouterGroup) {
|
||||
group := router.Group("/resource")
|
||||
{
|
||||
group.GET("/list", web_mediaresource.ResourceList)
|
||||
group.GET("/jh/list", web_mediaresource.ResourceJHList)
|
||||
group.GET("/jh/chapters", web_mediaresource.ResourceJHChapters)
|
||||
group.POST("/jh/import", web_mediaresource.ResourceJHImport)
|
||||
group.GET("/chapters", web_mediaresource.ResourceChapters)
|
||||
group.POST("/import", web_mediaresource.ResourceImport)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"videoweb/web/api/web_playlet"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func playletRouter(router *gin.RouterGroup) {
|
||||
group := router.Group("/playlet")
|
||||
{
|
||||
group.GET("/home-config/topic/options", web_playlet.HomeConfigTopicOptions)
|
||||
group.GET("/list", web_playlet.List)
|
||||
group.GET("/sales", web_playlet.Sales)
|
||||
group.POST("/add", web_playlet.Add)
|
||||
group.POST("/update", web_playlet.Update)
|
||||
group.POST("/del", web_playlet.Del)
|
||||
group.POST("/status/set", web_playlet.SetStatus)
|
||||
group.POST("/online-at/fill", web_playlet.FillOnlineAt)
|
||||
group.POST("/recommend/set", web_playlet.SetRecommend)
|
||||
group.POST("/featured/set", web_playlet.SetFeatured)
|
||||
group.POST("/operate-type/set", web_playlet.SetOperateType)
|
||||
group.POST("/banner/set", web_playlet.SetBanner)
|
||||
group.POST("/theme/set", web_playlet.SetTheme)
|
||||
group.POST("/tag/set", web_playlet.SetTag)
|
||||
group.POST("/category/set", web_playlet.SetCategory)
|
||||
group.POST("/like/virtual/set", web_playlet.SetVirtualLike)
|
||||
group.POST("/pay-type/set", web_playlet.SetPayType)
|
||||
group.POST("/watermark/reset", web_playlet.ResetWatermark)
|
||||
group.POST("/slug/sync", web_playlet.SyncSlug)
|
||||
group.GET("/chapter/list", web_playlet.ChapterList)
|
||||
group.POST("/chapter/add", web_playlet.ChapterAdd)
|
||||
group.POST("/chapter/update", web_playlet.ChapterUpdate)
|
||||
group.POST("/chapter/del", web_playlet.ChapterDel)
|
||||
group.POST("/chapter/status/fill", web_playlet.ChapterFillStatus)
|
||||
group.POST("/chapter/status/set", web_playlet.ChapterSetStatus)
|
||||
group.POST("/chapter/pay-type/set", web_playlet.ChapterSetPayType)
|
||||
group.POST("/chapter/sync", web_playlet.ChapterSync)
|
||||
group.GET("/theme/list", web_playlet.ThemeList)
|
||||
group.GET("/topic-group/list", web_playlet.TopicGroupList)
|
||||
group.POST("/topic-group/add", web_playlet.TopicGroupAdd)
|
||||
group.POST("/topic-group/update", web_playlet.TopicGroupUpdate)
|
||||
group.POST("/topic-group/del", web_playlet.TopicGroupDel)
|
||||
group.POST("/theme/add", web_playlet.ThemeAdd)
|
||||
group.POST("/theme/update", web_playlet.ThemeUpdate)
|
||||
group.POST("/theme/recommend/set", web_playlet.SetThemeRecommend)
|
||||
group.POST("/theme/del", web_playlet.ThemeDel)
|
||||
group.GET("/tag/list", web_playlet.TagList)
|
||||
group.POST("/tag/add", web_playlet.TagAdd)
|
||||
group.POST("/tag/update", web_playlet.TagUpdate)
|
||||
group.POST("/tag/del", web_playlet.TagDel)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"videoweb/web/api/web_rechargepackage"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func rechargePackageRouter(router *gin.RouterGroup) {
|
||||
group := router.Group("/recharge/package")
|
||||
{
|
||||
group.POST("/list", web_rechargepackage.List)
|
||||
group.POST("/vip/list", web_rechargepackage.VipList)
|
||||
group.POST("/add", web_rechargepackage.Add)
|
||||
group.POST("/update", web_rechargepackage.Update)
|
||||
group.POST("/del", web_rechargepackage.Delete)
|
||||
group.POST("/status/set", web_rechargepackage.SetStatus)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"videoweb/web/api/web_richtextcontent"
|
||||
)
|
||||
|
||||
func richTextContent(router *gin.RouterGroup) {
|
||||
// 文件上传
|
||||
file := router.Group("/richtextcontent")
|
||||
{
|
||||
file.POST("/list", web_richtextcontent.List)
|
||||
file.POST("/add", web_richtextcontent.Add)
|
||||
file.POST("/del", web_richtextcontent.Del)
|
||||
file.POST("/update", web_richtextcontent.Update)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"videoweb/web/api/web_acc"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// 主后台路由
|
||||
func MainWebRouter(router *gin.RouterGroup) {
|
||||
login := router.Group("/login")
|
||||
{
|
||||
login.POST("/acc", web_acc.AccLogin)
|
||||
login.POST("/bind", web_acc.BindQurl)
|
||||
login.POST("/slogin", web_acc.SLogin)
|
||||
}
|
||||
|
||||
role := router.Group("/role")
|
||||
{
|
||||
role.GET("/list", web_acc.RoleGetList)
|
||||
role.POST("/add", web_acc.RoleAdd)
|
||||
role.POST("/del", web_acc.RoleDel)
|
||||
role.GET("/getinfo", web_acc.RoleGetInfo)
|
||||
role.POST("/up", web_acc.RoleUp)
|
||||
role.POST("/enable", web_acc.RoleEnable)
|
||||
role.POST("/drop", web_acc.RoleGetDrop)
|
||||
role.GET("/getauth", web_acc.RoleGetAuth)
|
||||
role.POST("/upauth", web_acc.RoleUpAuth)
|
||||
}
|
||||
acc := router.Group("/acc")
|
||||
{
|
||||
acc.GET("/list", web_acc.AccGetList)
|
||||
acc.POST("/add", web_acc.AccAdd)
|
||||
acc.POST("/del", web_acc.AccDel)
|
||||
acc.GET("/getinfo", web_acc.AccGetInfo)
|
||||
acc.POST("/up", web_acc.AccUp)
|
||||
acc.GET("/getstatus", web_acc.AccGetStatus)
|
||||
acc.POST("/savestatus", web_acc.AccSaveStatus)
|
||||
acc.POST("/ops", web_acc.GetAccOpRecords)
|
||||
acc.POST("/uppwd", web_acc.AccUpdatePwd)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"videoweb/web/api/web_recharge"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func thirdRouter(r *gin.Engine) {
|
||||
thirdGroup := r.Group("/api/web/third")
|
||||
{
|
||||
thirdGroup.POST("/newpaycenter/recharge/callback", web_recharge.NewPayCenterRchgCallBack)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"videoweb/web/api/web_translation"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func translationRouter(router *gin.RouterGroup) {
|
||||
translation := router.Group("/translation")
|
||||
{
|
||||
translation.POST("/list", web_translation.GetTranslation)
|
||||
translation.POST("/update", web_translation.UpdateOnetTranslation)
|
||||
translation.POST("/del", web_translation.DelOnetTranslation)
|
||||
translation.POST("/add", web_translation.AddOnetTranslation)
|
||||
}
|
||||
translationcategory := router.Group("/translationcategory")
|
||||
{
|
||||
translationcategory.POST("/list", web_translation.GetTranslationCategory)
|
||||
translationcategory.POST("/update", web_translation.UpdateOnetTranslationCategory)
|
||||
translationcategory.POST("/del", web_translation.DelOnetTranslationCategory)
|
||||
translationcategory.POST("/add", web_translation.AddOnetTranslationCategory)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"videoweb/web/api/web_user"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func userRouter(router *gin.RouterGroup) {
|
||||
user := router.Group("/user")
|
||||
{
|
||||
user.POST("/list", web_user.GetUserList)
|
||||
user.POST("/update", web_user.UpdateUser)
|
||||
user.POST("/giftcoin", web_user.GiftCoin)
|
||||
user.POST("/vip/update", web_user.UpdateVip)
|
||||
user.POST("/resetPassword", web_user.ResetPassword)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"videoweb/web/api/web_video"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func videoRouter(router *gin.RouterGroup) {
|
||||
advitise := router.Group("/videoinfo")
|
||||
{
|
||||
advitise.POST("/list", web_video.GetVideoInfo)
|
||||
advitise.POST("/update", web_video.UpdateOneVideoInfo)
|
||||
advitise.POST("/del", web_video.DelOneVideoInfo)
|
||||
advitise.POST("/sync", web_video.SyncVideoInfo)
|
||||
advitise.POST("/addcoll", web_video.AddOneVideoCollection)
|
||||
advitise.POST("/setFakeWatchTimes", web_video.SetVideoFakeWatchTimes)
|
||||
advitise.POST("/category/set", web_video.SetCategory)
|
||||
advitise.POST("/transcode", web_video.TranscodeVideo)
|
||||
advitise.POST("/slug/sync", web_video.SyncSlug)
|
||||
}
|
||||
videocategory := router.Group("/videocategory")
|
||||
{
|
||||
videocategory.POST("/list", web_video.GetVideoCategory)
|
||||
videocategory.POST("/update", web_video.UpdateOneVideoCategory)
|
||||
videocategory.POST("/del", web_video.DelOneVideoCategory)
|
||||
videocategory.POST("/add", web_video.AddOneVideoCategory)
|
||||
}
|
||||
videotag := router.Group("/videotag")
|
||||
{
|
||||
videotag.POST("/list", web_video.GetVideoTagInfo)
|
||||
videotag.POST("/update", web_video.UpdateOneVideoTagInfo)
|
||||
videotag.POST("/del", web_video.DelOneVideoTagInfo)
|
||||
videotag.POST("/add", web_video.AddOneVideoTagInfo)
|
||||
}
|
||||
|
||||
videocreater := router.Group("/videocreater")
|
||||
{
|
||||
videocreater.POST("/list", web_video.GetVideoCreater)
|
||||
videocreater.POST("/update", web_video.UpdateOneVideoCreater)
|
||||
videocreater.POST("/del", web_video.DelOneVideoCreater)
|
||||
videocreater.POST("/add", web_video.AddOneVideoCreater)
|
||||
}
|
||||
videoTopic := router.Group("/videotopic")
|
||||
{
|
||||
videoTopic.POST("/list", web_video.GetVideoTopic)
|
||||
videoTopic.POST("/update", web_video.UpdateOneVideoTopic)
|
||||
videoTopic.POST("/del", web_video.DelOneVideoTopic)
|
||||
videoTopic.POST("/add", web_video.AddOneVideoTopic)
|
||||
}
|
||||
|
||||
router.GET("/m3u8/*key", web_video.Play)
|
||||
router.GET("/transm3u8/*key", web_video.TranscodeM3u8)
|
||||
router.GET("/enkey", web_video.Enkey)
|
||||
router.GET("/newenkey", web_video.NewEnkey)
|
||||
router.GET("/lsjenkey", web_video.LsjEnkey)
|
||||
router.GET("/videotag/hottag", web_video.GetVideoPlayData)
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"videoweb/web/api/web_recharge"
|
||||
"videoweb/web/api/web_video"
|
||||
"videoweb/web/middleware/apilimitHandler"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func wbVideoDataRouter(r *gin.Engine) {
|
||||
limiter := apilimitHandler.NewRouteHourlyLimiter(100)
|
||||
router := r.Group("/wbapi/hddjweb")
|
||||
{
|
||||
router.Use(limiter.Middleware())
|
||||
//router.GET("/hottag", web_video.GetHotTagByPlayData)
|
||||
router.GET("/ipstat", web_video.GetIpStatData)
|
||||
router.GET("/recharge/summary", web_recharge.RechargeSummary)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
"videoweb/pub/common/laosiji"
|
||||
"videoweb/pub/common/log"
|
||||
"videoweb/pub/common/srvversion"
|
||||
"videoweb/pub/dataReport"
|
||||
"videoweb/pub/esmanager"
|
||||
"videoweb/pub/models"
|
||||
"videoweb/pub/mongos"
|
||||
"videoweb/pub/payCenter"
|
||||
"videoweb/pub/redis"
|
||||
"videoweb/pub/seo/googleindex"
|
||||
"videoweb/pub/storage/proxy"
|
||||
"videoweb/web/router"
|
||||
"videoweb/web/service"
|
||||
"videoweb/web/webg"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
time.Local, _ = time.LoadLocation("Asia/Shanghai")
|
||||
}
|
||||
func Run(args []string) {
|
||||
showVersion()
|
||||
if err := initConfig(); err != nil {
|
||||
log.Error("init config err", log.E(err))
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
|
||||
shopDb := mongos.NewManager(webg.Conf.Mongodb.Addr)
|
||||
if err := shopDb.Init(); err != nil {
|
||||
log.Error("connect shopDb err", log.E(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
mongos.Shop = shopDb
|
||||
|
||||
shopLog := mongos.NewManager(webg.Conf.Mongodb.LogAddr)
|
||||
if err := shopLog.Init(); err != nil {
|
||||
log.Error("connect shopLog err", log.E(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
mongos.ShopLog = shopLog
|
||||
|
||||
if err := redis.Init(redis.Options{
|
||||
Addr: webg.Conf.Redis.Addr,
|
||||
Psw: webg.Conf.Redis.Passwd,
|
||||
Db: webg.Conf.Redis.Db,
|
||||
}); err != nil {
|
||||
log.Error("redis connect err", log.E(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if err := initCollections(); err != nil {
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
|
||||
if err := initElasticSearch(); err != nil {
|
||||
log.Error("init ES failed", log.E(err))
|
||||
os.Exit(1)
|
||||
}
|
||||
//初始化tg机器人
|
||||
if webg.Conf.TgToken != "" {
|
||||
//tgbot.InitTgBot(webg.Conf.TgToken, "[汁乎Web]")
|
||||
}
|
||||
|
||||
proxy.InitBucketVideoAddress(webg.Conf.BucketVideoAddressV2)
|
||||
initLaosiji()
|
||||
mongos.StartLid()
|
||||
initData()
|
||||
initSeoPush()
|
||||
dataReport.Init(dataReport.Config{
|
||||
ApiUrl: webg.Conf.DataReport.Url,
|
||||
RunMod: webg.Conf.RunMod,
|
||||
})
|
||||
|
||||
initHttpServer()
|
||||
|
||||
shutdownHandler()
|
||||
}
|
||||
|
||||
func showVersion() {
|
||||
log.Info(fmt.Sprintf("sevice version:%s", srvversion.SERVICE_VERSION))
|
||||
log.Info(fmt.Sprintf("git version:%s", srvversion.GIT_VERSION))
|
||||
log.Info(fmt.Sprintf("build date:%s", srvversion.BUILD_DATE))
|
||||
log.Info(fmt.Sprintf("build ip:%s", srvversion.BUILD_IP))
|
||||
}
|
||||
|
||||
func initConfig() error {
|
||||
|
||||
buf, err := ioutil.ReadFile("conf/web.yaml")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = yaml.Unmarshal(buf, &webg.Conf); err != nil {
|
||||
return err
|
||||
}
|
||||
payCenter.Init(webg.Conf.NewPayCenter)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// mongo表
|
||||
func initCollections() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 数据
|
||||
func initData() {
|
||||
models.Init()
|
||||
service.Start()
|
||||
}
|
||||
|
||||
// 搜索引擎推送
|
||||
func initSeoPush() {
|
||||
if webg.Conf.RunMod != "prod" {
|
||||
return
|
||||
}
|
||||
googleindex.Init(context.Background())
|
||||
}
|
||||
|
||||
func initElasticSearch() error {
|
||||
es, err := esmanager.NewManager(webg.Conf.Es.Addr,
|
||||
webg.Conf.Es.User, webg.Conf.Es.Pass)
|
||||
if err != nil {
|
||||
log.Info("new es failed", log.Any("err", err))
|
||||
return err
|
||||
}
|
||||
if err = es.ClientConnect(); err != nil {
|
||||
log.Info("connect es failed", log.Any("err", err))
|
||||
return err
|
||||
}
|
||||
esmanager.Instance = es
|
||||
log.Info("es:Init Ok!")
|
||||
return nil
|
||||
}
|
||||
|
||||
func initHttpServer() {
|
||||
|
||||
addr := fmt.Sprintf(":%s", webg.Conf.ListenAddr)
|
||||
srv := &http.Server{
|
||||
Addr: addr,
|
||||
Handler: router.Init(),
|
||||
}
|
||||
|
||||
go func() {
|
||||
log.Info("服务已启动", log.Any("地址", addr))
|
||||
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
log.Fatal("listen:", log.E(err))
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func shutdownHandler() {
|
||||
quit := make(chan os.Signal)
|
||||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM, os.Kill)
|
||||
<-quit
|
||||
log.Warn("Shutdown... server")
|
||||
service.Stop()
|
||||
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
mongos.Shop.DisConnect()
|
||||
mongos.ShopLog.DisConnect()
|
||||
redis.Disconnect()
|
||||
// srv_resource.ClosePrefetch()
|
||||
done <- struct{}{}
|
||||
}()
|
||||
select {
|
||||
case <-time.After(5 * time.Second):
|
||||
log.Warn("shutdown timeout....")
|
||||
case <-done:
|
||||
log.Info("graceful shutdown")
|
||||
}
|
||||
}
|
||||
|
||||
func initLaosiji() {
|
||||
if webg.Conf.LsjMediaConf.ApiUrl == "" {
|
||||
return
|
||||
}
|
||||
cli := laosiji.New(webg.Conf.LsjMediaConf.ApiUrl, webg.Conf.LsjMediaConf.AppId, webg.Conf.LsjMediaConf.ApiKey)
|
||||
d := laosiji.NewDomains(cli)
|
||||
laosiji.LaosijiClient = cli
|
||||
laosiji.LaosijiDomains = d
|
||||
|
||||
hr := webg.Conf.LsjMediaConf.DomainsRefreshHr
|
||||
if hr <= 0 {
|
||||
hr = 3
|
||||
}
|
||||
d.StartAutoRefresh(time.Duration(hr) * time.Hour)
|
||||
|
||||
go func() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
if _, err := d.Refresh(ctx); err != nil {
|
||||
log.Error("Init Laosiji domains 首次拉取失败(后台重试,不影响启动)", log.E(err))
|
||||
} else {
|
||||
log.Info("Init Laosiji OK...")
|
||||
}
|
||||
}()
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"videoweb/web/service/srv_aicomment"
|
||||
"videoweb/web/service/srv_ipblack"
|
||||
"videoweb/web/service/srv_mediaresource"
|
||||
"videoweb/web/skd"
|
||||
"videoweb/web/webg"
|
||||
)
|
||||
|
||||
func Start() {
|
||||
url, appID, secret := webg.Conf.AiComment.Url, webg.Conf.AiComment.AppId, webg.Conf.AiComment.Secret
|
||||
if url == "" && appID == "" && secret == "" {
|
||||
url, appID, secret = webg.Conf.Customer.Url, webg.Conf.Customer.AppId, webg.Conf.Customer.Secret
|
||||
}
|
||||
srv_aicomment.Init(url, appID, secret)
|
||||
skd.Start()
|
||||
srv_ipblack.Init()
|
||||
srv_mediaresource.Start()
|
||||
}
|
||||
|
||||
func Stop() {
|
||||
srv_mediaresource.Stop()
|
||||
skd.Stop()
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package srv_acc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/models/mwacc"
|
||||
"videoweb/pub/models/oplog"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
)
|
||||
|
||||
func GetOpLogs(ctx context.Context, logSearch *OpLogSearch) (
|
||||
int64, OpLogInfoList, *srvdef.SrvErr) {
|
||||
//log.Info("GetOpLogs Test 1")
|
||||
filter, findOption := constructFilterAndOpts(logSearch)
|
||||
total, serr := oplog.CountOpLogs(ctx, filter)
|
||||
if serr != nil {
|
||||
return 0, nil, serr
|
||||
}
|
||||
list := make(OpLogInfoList, 0)
|
||||
if total == 0 {
|
||||
return 0, list, nil
|
||||
}
|
||||
//log.Info("GetOpLogs Test 2", log.Any("filter", filter), log.Any("findOption", findOption))
|
||||
opLogs, serr := oplog.FindManyOpLogs(ctx, filter, findOption)
|
||||
if serr != nil {
|
||||
return 0, nil, serr
|
||||
}
|
||||
//log.Info("GetOpLogs Test 3")
|
||||
actIds := make([]int64, 0)
|
||||
for _, v := range opLogs {
|
||||
actIds = append(actIds, v.ActId)
|
||||
}
|
||||
|
||||
accFilter := bson.M{mwacc.FN.MwAcc.Id: bson.M{"$in": actIds}}
|
||||
accs, serr := mwacc.FindManyAccByFilter(ctx, accFilter)
|
||||
if serr != nil {
|
||||
return 0, nil, serr
|
||||
}
|
||||
|
||||
//log.Info("GetOpLogs Test 4")
|
||||
for _, opLog := range opLogs {
|
||||
olInfo := &OpLogInfo{
|
||||
Path: opLog.Path,
|
||||
ActId: opLog.ActId,
|
||||
Action: opLog.Action,
|
||||
Param: opLog.RawData,
|
||||
CreatedAt: opLog.CreatedAt,
|
||||
}
|
||||
for _, acc := range accs {
|
||||
if acc.Id == olInfo.ActId {
|
||||
olInfo.ActName = acc.UserName
|
||||
break
|
||||
}
|
||||
}
|
||||
list = append(list, olInfo)
|
||||
}
|
||||
//log.Info("GetOpLogs Test 5")
|
||||
return total, list, nil
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package srv_acc
|
||||
|
||||
import "time"
|
||||
|
||||
type OpLogInfo struct {
|
||||
Path string `json:"path" bson:"path"` // 请求接口
|
||||
ActId int64 `json:"actId" bson:"actId"` // 操作人Id
|
||||
Action string `json:"action" bson:"action"` // 操作目的
|
||||
Param string `json:"param" bson:"rawData"` // 操作内容
|
||||
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` // 操作时间
|
||||
ActName string `json:"actName" bson:"actName"` // 操作人
|
||||
}
|
||||
|
||||
type OpLogInfoList []*OpLogInfo
|
||||
|
||||
type OpLogSearch struct {
|
||||
PageNum int64 `json:"pageNum"` // 页码
|
||||
PageSize int64 `json:"pageSize"` //
|
||||
Path *string `json:"path"` // 请求接口
|
||||
Action *string `json:"action"` // 操作目的
|
||||
ActId *int64 `json:"actId"` // 操作人Id
|
||||
StartTime *time.Time `json:"startTime"` // 开始时间
|
||||
EndTime *time.Time `json:"endTime"` // 开始时间
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package srv_acc
|
||||
|
||||
import (
|
||||
"videoweb/pub/models/oplog"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
// constructFilterAndOpts 根据搜索参数构建查询filter和options
|
||||
func constructFilterAndOpts(param *OpLogSearch) (
|
||||
bson.M, *options.FindOptions) {
|
||||
|
||||
filter := bson.M{}
|
||||
if param.Path != nil && *param.Path != "" {
|
||||
filter[oplog.FN.OpLog.Path] = bson.M{"$regex": param.Path}
|
||||
}
|
||||
if param.Action != nil && *param.Action != "" {
|
||||
filter[oplog.FN.OpLog.Action] = param.Action
|
||||
}
|
||||
if param.ActId != nil && *param.ActId > 0 {
|
||||
filter[oplog.FN.OpLog.ActId] = param.ActId
|
||||
}
|
||||
if param.StartTime != nil && param.EndTime != nil {
|
||||
filter[oplog.FN.OpLog.CreatedAt] = bson.M{"$gte": param.StartTime, "$lt": param.EndTime}
|
||||
}
|
||||
sort := bson.M{oplog.FN.OpLog.CreatedAt: -1}
|
||||
opt := &options.FindOptions{}
|
||||
opt.SetSort(sort)
|
||||
skip := (param.PageNum - 1) * param.PageSize
|
||||
opt.SetSkip(skip)
|
||||
opt.SetLimit(param.PageSize)
|
||||
return filter, opt
|
||||
}
|
||||
@@ -0,0 +1,456 @@
|
||||
package srv_aicomment
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"videoweb/pub/common/crypt"
|
||||
"videoweb/pub/common/log"
|
||||
"videoweb/pub/models/aicommentrecord"
|
||||
"videoweb/pub/models/playletmod"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
const (
|
||||
minCommentLengthLimit = 20
|
||||
maxCommentLengthLimit = 50
|
||||
maxSubmitVideoCount = 100
|
||||
maxVideoTitleRunes = 100
|
||||
maxVideoDescriptionRunes = 100
|
||||
maxVideoSubtitleRunes = 500
|
||||
maxVideoTags = 20
|
||||
minSubmitVideoCommentCount = 1
|
||||
minSubmitRequestInterval = 10 * time.Second
|
||||
objectTypePlaylet = 10
|
||||
)
|
||||
|
||||
type VideoItem struct {
|
||||
VideoId string `json:"videoId"`
|
||||
Title string `json:"title"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Subtitle string `json:"subtitle,omitempty"`
|
||||
CommentCount int `json:"commentCount"`
|
||||
ObjType int64 `json:"-"`
|
||||
RetainCount int `json:"-"` // 本次任务结果需要保留的评论数
|
||||
TargetCount int `json:"-"` // 当前内容固定的目标AI评论总数
|
||||
CommentTotal int `json:"-"` // 本次续传还需要生成的评论数
|
||||
CurrentCount int64 `json:"-"` // 内容当前评论数,用于保留已有真实互动
|
||||
}
|
||||
|
||||
type SubmitRequest struct {
|
||||
AppID string `json:"appId"`
|
||||
Sign string `json:"sign"`
|
||||
Videos []VideoItem `json:"videos"`
|
||||
}
|
||||
|
||||
type SubmitResult struct {
|
||||
ID string `json:"id"`
|
||||
VideoId string `json:"videoId"`
|
||||
}
|
||||
|
||||
type SubmitResponse struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data struct {
|
||||
Results []SubmitResult `json:"results"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
type ResultRequest struct {
|
||||
AppID string `json:"appId"`
|
||||
Sign string `json:"sign"`
|
||||
IDs []string `json:"ids"`
|
||||
}
|
||||
|
||||
type Comment struct {
|
||||
Type string `json:"type"`
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
type ResultItem struct {
|
||||
ID string `json:"id"`
|
||||
VideoId string `json:"videoId"`
|
||||
Status int `json:"status,omitempty"`
|
||||
Comments []Comment `json:"comments"`
|
||||
ErrorMsg string `json:"errorMsg,omitempty"`
|
||||
}
|
||||
|
||||
type ResultResponse struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data struct {
|
||||
Results []ResultItem `json:"results"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
type AiCommentService struct {
|
||||
baseURL string
|
||||
appID string
|
||||
appSecret string
|
||||
client *http.Client
|
||||
signMu sync.Mutex
|
||||
lastSignUnixTime int64
|
||||
submitMu sync.Mutex
|
||||
lastSubmitAt time.Time
|
||||
}
|
||||
|
||||
var aiCommentService *AiCommentService
|
||||
|
||||
func Init(baseURL, appID, secret string) {
|
||||
aiCommentService = &AiCommentService{
|
||||
baseURL: normalizeBaseURL(baseURL),
|
||||
appID: strings.TrimSpace(appID),
|
||||
appSecret: strings.TrimSpace(secret),
|
||||
client: &http.Client{
|
||||
Timeout: 30 * time.Second,
|
||||
},
|
||||
}
|
||||
if aiCommentService.Configured() {
|
||||
log.Info("自动评论服务初始化完成", log.Any("baseURL", aiCommentService.baseURL), log.Any("appId", aiCommentService.appID))
|
||||
return
|
||||
}
|
||||
log.Warn("自动评论服务配置不完整,已跳过启用", log.Any("baseURL", aiCommentService.baseURL), log.Any("appId", aiCommentService.appID))
|
||||
}
|
||||
|
||||
func GetAiCommentService() *AiCommentService {
|
||||
if aiCommentService == nil {
|
||||
Init("", "", "")
|
||||
}
|
||||
return aiCommentService
|
||||
}
|
||||
|
||||
func (s *AiCommentService) Configured() bool {
|
||||
return s != nil && s.baseURL != "" && s.appID != "" && s.appSecret != ""
|
||||
}
|
||||
|
||||
func normalizeBaseURL(baseURL string) string {
|
||||
baseURL = strings.TrimRight(strings.TrimSpace(baseURL), "/")
|
||||
if baseURL == "" {
|
||||
return ""
|
||||
}
|
||||
if strings.HasSuffix(baseURL, "/app/customer") {
|
||||
return baseURL
|
||||
}
|
||||
if strings.HasSuffix(baseURL, "/app") {
|
||||
return baseURL + "/customer"
|
||||
}
|
||||
return baseURL + "/app/customer"
|
||||
}
|
||||
|
||||
func (s *AiCommentService) generateSign(ctx context.Context) (string, int64, error) {
|
||||
s.signMu.Lock()
|
||||
defer s.signMu.Unlock()
|
||||
|
||||
timestamp := time.Now().Unix()
|
||||
if timestamp <= s.lastSignUnixTime {
|
||||
timer := time.NewTimer(time.Until(time.Unix(s.lastSignUnixTime+1, 0)))
|
||||
defer timer.Stop()
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return "", 0, ctx.Err()
|
||||
case <-timer.C:
|
||||
}
|
||||
timestamp = time.Now().Unix()
|
||||
}
|
||||
params := url.Values{
|
||||
"appId": {s.appID},
|
||||
"timestamp": {strconv.FormatInt(timestamp, 10)},
|
||||
}
|
||||
cipherBytes, err := crypt.CoreAesEncrypt([]byte(params.Encode()), s.appSecret)
|
||||
if err != nil {
|
||||
return "", 0, fmt.Errorf("AES加密失败: %w", err)
|
||||
}
|
||||
s.lastSignUnixTime = timestamp
|
||||
return hex.EncodeToString(cipherBytes), timestamp, nil
|
||||
}
|
||||
|
||||
func (s *AiCommentService) postJSON(ctx context.Context, path string, reqBody interface{}, respBody interface{}) error {
|
||||
if !s.Configured() {
|
||||
return errors.New("自动评论服务未配置")
|
||||
}
|
||||
jsonData, err := json.Marshal(reqBody)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
reqURL := s.baseURL + path
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, reqURL, bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
log.Info("自动评论HTTP请求", log.Any("url", reqURL), log.Any("bodySize", len(jsonData)))
|
||||
resp, err := s.client.Do(req)
|
||||
if err != nil {
|
||||
log.Error("自动评论HTTP请求失败", log.E(err), log.Any("url", reqURL))
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info("自动评论HTTP响应", log.Any("url", reqURL), log.Any("statusCode", resp.StatusCode), log.Any("body", string(body)))
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("自动评论HTTP状态异常: %d", resp.StatusCode)
|
||||
}
|
||||
if err = json.Unmarshal(body, respBody); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *AiCommentService) SubmitVideos(ctx context.Context, videos []VideoItem) ([]SubmitResult, error) {
|
||||
videos = normalizeVideoItems(videos)
|
||||
if len(videos) == 0 {
|
||||
return []SubmitResult{}, nil
|
||||
}
|
||||
if len(videos) > maxSubmitVideoCount {
|
||||
return nil, fmt.Errorf("单次提交最多100个视频,当前%d个", len(videos))
|
||||
}
|
||||
if err := s.waitForSubmitSlot(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sign, timestamp, err := s.generateSign(ctx)
|
||||
if err != nil {
|
||||
log.Error("自动评论生成签名失败", log.E(err))
|
||||
return nil, err
|
||||
}
|
||||
reqBody := SubmitRequest{AppID: s.appID, Sign: sign, Videos: videos}
|
||||
var submitResp SubmitResponse
|
||||
if err = s.postJSON(ctx, "/videoComments/submit", reqBody, &submitResp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if submitResp.Code != http.StatusOK {
|
||||
return nil, fmt.Errorf("提交任务失败: code=%d, msg=%s, timestamp=%d", submitResp.Code, submitResp.Msg, timestamp)
|
||||
}
|
||||
return submitResp.Data.Results, nil
|
||||
}
|
||||
|
||||
func (s *AiCommentService) waitForSubmitSlot(ctx context.Context) error {
|
||||
s.submitMu.Lock()
|
||||
defer s.submitMu.Unlock()
|
||||
|
||||
wait := time.Until(s.lastSubmitAt.Add(minSubmitRequestInterval))
|
||||
if wait > 0 {
|
||||
timer := time.NewTimer(wait)
|
||||
defer timer.Stop()
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
case <-timer.C:
|
||||
}
|
||||
}
|
||||
s.lastSubmitAt = time.Now()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *AiCommentService) QueryResults(ctx context.Context, taskIDs []string) ([]ResultItem, error) {
|
||||
if len(taskIDs) == 0 {
|
||||
return []ResultItem{}, nil
|
||||
}
|
||||
if len(taskIDs) > 500 {
|
||||
return nil, fmt.Errorf("单次查询最多500个任务,当前%d个", len(taskIDs))
|
||||
}
|
||||
sign, timestamp, err := s.generateSign(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reqBody := ResultRequest{AppID: s.appID, Sign: sign, IDs: taskIDs}
|
||||
var resultResp ResultResponse
|
||||
if err = s.postJSON(ctx, "/videoComments/result", reqBody, &resultResp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resultResp.Code != http.StatusOK {
|
||||
return nil, fmt.Errorf("查询结果失败: code=%d, msg=%s, timestamp=%d", resultResp.Code, resultResp.Msg, timestamp)
|
||||
}
|
||||
return resultResp.Data.Results, nil
|
||||
}
|
||||
|
||||
func (s *AiCommentService) SubmitAndRecord(ctx context.Context, videos []VideoItem) error {
|
||||
videos = normalizeVideoItems(videos)
|
||||
if len(videos) == 0 {
|
||||
return nil
|
||||
}
|
||||
reserved := make([]VideoItem, 0, len(videos))
|
||||
for _, video := range videos {
|
||||
record := &aicommentrecord.AiCommentRecord{
|
||||
Key: aiCommentRecordKey(video),
|
||||
Vid: video.VideoId,
|
||||
Title: video.Title,
|
||||
ObjType: video.ObjType,
|
||||
RetainCount: video.RetainCount,
|
||||
TargetCount: video.TargetCount,
|
||||
Desc: video.Description,
|
||||
}
|
||||
claimed, serr := aicommentrecord.Reserve(ctx, record)
|
||||
if serr != nil {
|
||||
return fmt.Errorf("预留自动评论任务失败: %w", serr)
|
||||
}
|
||||
if claimed {
|
||||
reserved = append(reserved, video)
|
||||
}
|
||||
}
|
||||
if len(reserved) == 0 {
|
||||
return nil
|
||||
}
|
||||
results, err := s.SubmitVideos(ctx, reserved)
|
||||
if err != nil {
|
||||
for _, video := range reserved {
|
||||
_ = aicommentrecord.SetSubmission(ctx, aiCommentRecordKey(video), "", aicommentrecord.StatusFailed, err.Error())
|
||||
}
|
||||
return err
|
||||
}
|
||||
resultByVid := make(map[string]string, len(results))
|
||||
for _, result := range results {
|
||||
resultByVid[result.VideoId] = result.ID
|
||||
}
|
||||
missing := 0
|
||||
for _, video := range reserved {
|
||||
taskID := resultByVid[video.VideoId]
|
||||
status := aicommentrecord.StatusSubmitted
|
||||
desc := video.Description
|
||||
if taskID == "" {
|
||||
status = aicommentrecord.StatusFailed
|
||||
desc = "自动评论服务未返回任务ID"
|
||||
missing++
|
||||
}
|
||||
if serr := aicommentrecord.SetSubmission(ctx, aiCommentRecordKey(video), taskID, status, desc); serr != nil {
|
||||
return fmt.Errorf("保存自动评论任务记录失败: %w", serr)
|
||||
}
|
||||
}
|
||||
if missing > 0 {
|
||||
return fmt.Errorf("自动评论服务缺少%d个任务ID", missing)
|
||||
}
|
||||
log.Info("自动评论提交并记录成功", log.Any("videoCount", len(reserved)))
|
||||
return nil
|
||||
}
|
||||
|
||||
func aiCommentRecordKey(video VideoItem) string {
|
||||
return strconv.FormatInt(video.ObjType, 10) + ":" + video.VideoId
|
||||
}
|
||||
|
||||
func AutoProcessUnsubmittedPlaylets(ctx context.Context, playletIDs []int64) error {
|
||||
if len(playletIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
service := GetAiCommentService()
|
||||
if !service.Configured() {
|
||||
log.Warn("自动评论服务未配置,跳过提交", log.Any("playletIDs", playletIDs))
|
||||
return nil
|
||||
}
|
||||
videos, err := buildPendingPlayletVideoItems(ctx, playletIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = submitAndRecordInBatches(ctx, service, videos); err != nil {
|
||||
return fmt.Errorf("提交AI评论任务失败: %w", err)
|
||||
}
|
||||
log.Info("自动评论处理短剧完成", log.Any("requested", len(playletIDs)), log.Any("pending", len(videos)))
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildPendingPlayletVideoItems(ctx context.Context, playletIDs []int64) ([]VideoItem, error) {
|
||||
if len(playletIDs) == 0 {
|
||||
return []VideoItem{}, nil
|
||||
}
|
||||
playlets, serr := playletmod.FindManyPlaylet(ctx, bson.M{
|
||||
playletmod.FN.Playlet.Id: bson.M{"$in": playletIDs},
|
||||
playletmod.FN.Playlet.Status: playletmod.StatusUp,
|
||||
}, options.Find().SetProjection(homepagePlayletProjection))
|
||||
if serr != nil {
|
||||
return nil, serr
|
||||
}
|
||||
pending, serr := buildHomepagePlayletVideoItems(ctx, playlets)
|
||||
if serr != nil {
|
||||
return nil, serr
|
||||
}
|
||||
return pending, nil
|
||||
}
|
||||
|
||||
func normalizeVideoItems(videos []VideoItem) []VideoItem {
|
||||
if len(videos) == 0 {
|
||||
return []VideoItem{}
|
||||
}
|
||||
result := make([]VideoItem, 0, len(videos))
|
||||
for _, video := range videos {
|
||||
video = normalizeVideoItem(video)
|
||||
if video.VideoId == "" {
|
||||
continue
|
||||
}
|
||||
result = append(result, video)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func normalizeVideoItem(video VideoItem) VideoItem {
|
||||
video.VideoId = strings.TrimSpace(video.VideoId)
|
||||
video.Title = truncateRunes(strings.TrimSpace(video.Title), maxVideoTitleRunes)
|
||||
if video.Title == "" {
|
||||
video.Title = video.VideoId
|
||||
}
|
||||
video.Description = truncateRunes(strings.TrimSpace(video.Description), maxVideoDescriptionRunes)
|
||||
video.Subtitle = truncateRunes(strings.TrimSpace(video.Subtitle), maxVideoSubtitleRunes)
|
||||
video.Tags = normalizeVideoTags(video.Tags)
|
||||
if video.CommentCount < minSubmitVideoCommentCount {
|
||||
video.CommentCount = minSubmitVideoCommentCount
|
||||
}
|
||||
if video.CommentCount > maxCommentLengthLimit {
|
||||
video.CommentCount = maxCommentLengthLimit
|
||||
}
|
||||
if video.ObjType <= 0 {
|
||||
video.ObjType = objectTypePlaylet
|
||||
}
|
||||
return video
|
||||
}
|
||||
|
||||
func randomCommentLengthLimit() int {
|
||||
return randomIntInclusive(minCommentLengthLimit, maxCommentLengthLimit)
|
||||
}
|
||||
|
||||
func normalizeVideoTags(tags []string) []string {
|
||||
if len(tags) == 0 {
|
||||
return nil
|
||||
}
|
||||
result := make([]string, 0, len(tags))
|
||||
seen := make(map[string]struct{}, len(tags))
|
||||
for _, tag := range tags {
|
||||
tag = strings.TrimSpace(tag)
|
||||
if tag == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[tag]; ok {
|
||||
continue
|
||||
}
|
||||
seen[tag] = struct{}{}
|
||||
result = append(result, tag)
|
||||
if len(result) >= maxVideoTags {
|
||||
break
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func truncateRunes(text string, maxLen int) string {
|
||||
if maxLen <= 0 {
|
||||
return ""
|
||||
}
|
||||
runes := []rune(text)
|
||||
if len(runes) <= maxLen {
|
||||
return text
|
||||
}
|
||||
return string(runes[:maxLen])
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
package srv_aicomment
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
|
||||
"videoweb/pub/common/log"
|
||||
"videoweb/pub/common/srvdef"
|
||||
"videoweb/pub/models/playletmod"
|
||||
"videoweb/pub/models/playlettagmod"
|
||||
"videoweb/pub/models/playletthememod"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
const (
|
||||
homepagePlayletCandidateLimit int64 = 60
|
||||
homepagePlayletFeedThemeLimit int64 = 30
|
||||
maxSubmitRequestsPerRun = 7
|
||||
)
|
||||
|
||||
var homepagePlayletProjection = bson.D{
|
||||
{Key: playletmod.FN.Playlet.Id, Value: 1},
|
||||
{Key: playletmod.FN.Playlet.Title, Value: 1},
|
||||
{Key: playletmod.FN.Playlet.Desc, Value: 1},
|
||||
{Key: playletmod.FN.Playlet.TagIds, Value: 1},
|
||||
{Key: playletmod.FN.Playlet.OnlineAt, Value: 1},
|
||||
{Key: playletmod.FN.Playlet.CreatedAt, Value: 1},
|
||||
{Key: playletmod.FN.Playlet.IsFeatured, Value: 1},
|
||||
{Key: playletmod.FN.Playlet.IsRecommend, Value: 1},
|
||||
{Key: playletmod.FN.Playlet.ShowOnBanner, Value: 1},
|
||||
{Key: playletmod.FN.Playlet.TopRank, Value: 1},
|
||||
{Key: playletmod.FN.Playlet.RecommendRank, Value: 1},
|
||||
{Key: playletmod.FN.Playlet.CountBrowse, Value: 1},
|
||||
{Key: playletmod.FN.Playlet.CountComment, Value: 1},
|
||||
}
|
||||
|
||||
var homepageSubmitRunning atomic.Bool
|
||||
|
||||
func AutoProcessHomepageVisibleContent(ctx context.Context) error {
|
||||
if !homepageSubmitRunning.CompareAndSwap(false, true) {
|
||||
log.Debug("首页内容自动评论补提交正在执行中,本次跳过")
|
||||
return nil
|
||||
}
|
||||
defer homepageSubmitRunning.Store(false)
|
||||
|
||||
service := GetAiCommentService()
|
||||
if !service.Configured() {
|
||||
log.Warn("自动评论服务未配置,跳过首页内容补提交")
|
||||
return nil
|
||||
}
|
||||
|
||||
playlets, serr := collectHomepagePlaylets(ctx)
|
||||
if serr != nil {
|
||||
return fmt.Errorf("查询首页短剧失败: %w", serr)
|
||||
}
|
||||
videos, serr := buildHomepagePlayletVideoItems(ctx, playlets)
|
||||
if serr != nil {
|
||||
return fmt.Errorf("组装首页短剧AI评论参数失败: %w", serr)
|
||||
}
|
||||
if err := submitAndRecordInBatches(ctx, service, videos); err != nil {
|
||||
return fmt.Errorf("提交首页短剧AI评论任务失败: %w", err)
|
||||
}
|
||||
log.Info("自动评论首页内容补提交完成",
|
||||
log.Any("playletCandidates", len(playlets)),
|
||||
log.Any("playletPending", len(videos)),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
func submitAndRecordInBatches(ctx context.Context, service *AiCommentService, videos []VideoItem) error {
|
||||
batches, deferred := buildAICommentSubmissionBatches(videos, maxSubmitRequestsPerRun)
|
||||
for _, batch := range batches {
|
||||
if err := service.SubmitAndRecord(ctx, batch); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if deferred {
|
||||
log.Info("自动评论达到单轮提交请求上限,剩余任务等待下次续传",
|
||||
log.Any("requestLimit", maxSubmitRequestsPerRun),
|
||||
log.Any("videoCount", len(videos)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildAICommentSubmissionBatches(videos []VideoItem, requestLimit int) ([][]VideoItem, bool) {
|
||||
batches := make([][]VideoItem, 0)
|
||||
for _, round := range buildAICommentSubmissionRounds(videos) {
|
||||
for start := 0; start < len(round); start += maxSubmitVideoCount {
|
||||
end := start + maxSubmitVideoCount
|
||||
if end > len(round) {
|
||||
end = len(round)
|
||||
}
|
||||
batches = append(batches, round[start:end])
|
||||
}
|
||||
}
|
||||
if requestLimit <= 0 || len(batches) <= requestLimit {
|
||||
return batches, false
|
||||
}
|
||||
return batches[:requestLimit], true
|
||||
}
|
||||
|
||||
func buildAICommentSubmissionRounds(videos []VideoItem) [][]VideoItem {
|
||||
pending := append([]VideoItem(nil), videos...)
|
||||
rounds := make([][]VideoItem, 0)
|
||||
for len(pending) > 0 {
|
||||
round := make([]VideoItem, 0, len(pending))
|
||||
next := make([]VideoItem, 0, len(pending))
|
||||
for _, video := range pending {
|
||||
remaining := video.CommentTotal
|
||||
if remaining <= 0 {
|
||||
remaining = commentsPerGenerationTask
|
||||
}
|
||||
retainCount := min(remaining, commentsPerGenerationTask)
|
||||
taskVideo := video
|
||||
taskVideo.CommentCount = randomCommentLengthLimit()
|
||||
taskVideo.RetainCount = retainCount
|
||||
taskVideo.CommentTotal = 0
|
||||
round = append(round, taskVideo)
|
||||
|
||||
remaining -= retainCount
|
||||
if remaining > 0 {
|
||||
video.CommentTotal = remaining
|
||||
next = append(next, video)
|
||||
}
|
||||
}
|
||||
rounds = append(rounds, round)
|
||||
pending = next
|
||||
}
|
||||
return rounds
|
||||
}
|
||||
|
||||
func collectHomepagePlaylets(ctx context.Context) (playletmod.PlayletList, *srvdef.SrvErr) {
|
||||
playlets := make(playletmod.PlayletList, 0, maxSubmitVideoCount)
|
||||
seen := make(map[int64]struct{})
|
||||
if serr := appendHomepagePlaylets(ctx, &playlets, seen,
|
||||
homepagePlayletFilter(bson.M{playletmod.FN.Playlet.ShowOnBanner: true}),
|
||||
bson.D{
|
||||
{Key: playletmod.FN.Playlet.TopRank, Value: -1},
|
||||
{Key: playletmod.FN.Playlet.MediaUpdatedAt, Value: -1},
|
||||
{Key: playletmod.FN.Playlet.Id, Value: -1},
|
||||
},
|
||||
6,
|
||||
); serr != nil {
|
||||
return nil, serr
|
||||
}
|
||||
if serr := appendHomepageFeedThemePlaylets(ctx, &playlets, seen); serr != nil {
|
||||
return nil, serr
|
||||
}
|
||||
queries := []struct {
|
||||
filter bson.M
|
||||
sort bson.D
|
||||
limit int64
|
||||
}{
|
||||
{
|
||||
filter: homepagePlayletFilter(bson.M{playletmod.FN.Playlet.IsRecommend: true}),
|
||||
sort: bson.D{
|
||||
{Key: playletmod.FN.Playlet.RecommendRank, Value: -1},
|
||||
{Key: playletmod.FN.Playlet.CreatedAt, Value: -1},
|
||||
{Key: playletmod.FN.Playlet.Id, Value: -1},
|
||||
},
|
||||
limit: homepagePlayletCandidateLimit,
|
||||
},
|
||||
{
|
||||
filter: homepagePlayletFilter(nil),
|
||||
sort: bson.D{
|
||||
{Key: playletmod.FN.Playlet.RecommendRank, Value: -1},
|
||||
{Key: playletmod.FN.Playlet.MediaUpdatedAt, Value: -1},
|
||||
{Key: playletmod.FN.Playlet.Id, Value: -1},
|
||||
},
|
||||
limit: homepagePlayletCandidateLimit,
|
||||
},
|
||||
{
|
||||
filter: homepagePlayletFilter(nil),
|
||||
sort: bson.D{
|
||||
{Key: playletmod.FN.Playlet.CountCollect, Value: -1},
|
||||
{Key: playletmod.FN.Playlet.Id, Value: -1},
|
||||
},
|
||||
limit: homepagePlayletCandidateLimit,
|
||||
},
|
||||
{
|
||||
filter: homepagePlayletFilter(nil),
|
||||
sort: bson.D{
|
||||
{Key: playletmod.FN.Playlet.UpdatedAt, Value: -1},
|
||||
{Key: playletmod.FN.Playlet.Id, Value: -1},
|
||||
},
|
||||
limit: homepagePlayletCandidateLimit,
|
||||
},
|
||||
{
|
||||
filter: homepagePlayletFilter(nil),
|
||||
sort: bson.D{
|
||||
{Key: playletmod.FN.Playlet.CountBrowse, Value: -1},
|
||||
{Key: playletmod.FN.Playlet.Id, Value: -1},
|
||||
},
|
||||
limit: homepagePlayletCandidateLimit,
|
||||
},
|
||||
}
|
||||
for _, query := range queries {
|
||||
if serr := appendHomepagePlaylets(ctx, &playlets, seen, query.filter, query.sort, query.limit); serr != nil {
|
||||
return nil, serr
|
||||
}
|
||||
}
|
||||
return playlets, nil
|
||||
}
|
||||
|
||||
func appendHomepageFeedThemePlaylets(ctx context.Context, playlets *playletmod.PlayletList, seen map[int64]struct{}) *srvdef.SrvErr {
|
||||
themes, serr := playletthememod.FindManyPlayletTheme(ctx, bson.M{
|
||||
playletthememod.FN.PlayletTheme.Status: true,
|
||||
}, options.Find().
|
||||
SetProjection(bson.D{{Key: playletthememod.FN.PlayletTheme.Id, Value: 1}}).
|
||||
SetSort(bson.D{
|
||||
{Key: playletthememod.FN.PlayletTheme.Rank, Value: -1},
|
||||
{Key: playletthememod.FN.PlayletTheme.Id, Value: -1},
|
||||
}),
|
||||
)
|
||||
if serr != nil {
|
||||
return serr
|
||||
}
|
||||
sort := bson.D{
|
||||
{Key: playletmod.FN.Playlet.RecommendRank, Value: -1},
|
||||
{Key: playletmod.FN.Playlet.MediaUpdatedAt, Value: -1},
|
||||
{Key: playletmod.FN.Playlet.Id, Value: -1},
|
||||
}
|
||||
for _, theme := range themes {
|
||||
if theme == nil || theme.Id <= 0 {
|
||||
continue
|
||||
}
|
||||
filter := homepagePlayletFilter(bson.M{
|
||||
playletmod.FN.Playlet.ThemeIds: bson.M{"$in": []int64{theme.Id}},
|
||||
})
|
||||
if serr := appendHomepagePlaylets(ctx, playlets, seen, filter, sort, homepagePlayletFeedThemeLimit); serr != nil {
|
||||
return serr
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func appendHomepagePlaylets(ctx context.Context, playlets *playletmod.PlayletList, seen map[int64]struct{}, filter bson.M, sort bson.D, limit int64) *srvdef.SrvErr {
|
||||
list, serr := playletmod.FindManyPlaylet(ctx, filter, options.Find().
|
||||
SetProjection(homepagePlayletProjection).
|
||||
SetSort(sort).
|
||||
SetLimit(limit),
|
||||
)
|
||||
if serr != nil {
|
||||
return serr
|
||||
}
|
||||
for _, playlet := range list {
|
||||
if playlet == nil || playlet.Id <= 0 {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[playlet.Id]; ok {
|
||||
continue
|
||||
}
|
||||
seen[playlet.Id] = struct{}{}
|
||||
*playlets = append(*playlets, playlet)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildHomepagePlayletVideoItems(ctx context.Context, playlets playletmod.PlayletList) ([]VideoItem, *srvdef.SrvErr) {
|
||||
tagNames := loadPlayletTagNames(ctx, playlets)
|
||||
videos := make([]VideoItem, 0, len(playlets))
|
||||
for _, playlet := range playlets {
|
||||
if playlet == nil {
|
||||
continue
|
||||
}
|
||||
videos = append(videos, VideoItem{
|
||||
VideoId: strconv.FormatInt(playlet.Id, 10),
|
||||
Title: playlet.Title,
|
||||
Tags: playletTagNames(playlet.TagIds, tagNames),
|
||||
Description: playlet.Desc,
|
||||
CommentCount: randomCommentLengthLimit(),
|
||||
ObjType: objectTypePlaylet,
|
||||
CommentTotal: aiCommentPlayletTotal,
|
||||
CurrentCount: playlet.CountComment,
|
||||
})
|
||||
}
|
||||
pending, serr := preparePendingAICommentVideos(ctx, videos)
|
||||
if serr != nil {
|
||||
return nil, serr
|
||||
}
|
||||
return pending, nil
|
||||
}
|
||||
|
||||
func homepagePlayletFilter(extra bson.M) bson.M {
|
||||
filter := bson.M{playletmod.FN.Playlet.Status: playletmod.StatusUp}
|
||||
for key, value := range extra {
|
||||
filter[key] = value
|
||||
}
|
||||
return filter
|
||||
}
|
||||
|
||||
func loadPlayletTagNames(ctx context.Context, playlets playletmod.PlayletList) map[int64]string {
|
||||
tagIDs := make([]int64, 0)
|
||||
seen := make(map[int64]struct{})
|
||||
for _, playlet := range playlets {
|
||||
if playlet == nil {
|
||||
continue
|
||||
}
|
||||
for _, tagID := range playlet.TagIds {
|
||||
if tagID <= 0 {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[tagID]; ok {
|
||||
continue
|
||||
}
|
||||
seen[tagID] = struct{}{}
|
||||
tagIDs = append(tagIDs, tagID)
|
||||
}
|
||||
}
|
||||
if len(tagIDs) == 0 {
|
||||
return map[int64]string{}
|
||||
}
|
||||
tags, serr := playlettagmod.FindManyPlayletTag(ctx, bson.M{
|
||||
playlettagmod.FN.PlayletTag.Id: bson.M{"$in": tagIDs},
|
||||
}, options.Find().SetProjection(bson.D{
|
||||
{Key: playlettagmod.FN.PlayletTag.Id, Value: 1},
|
||||
{Key: playlettagmod.FN.PlayletTag.Name, Value: 1},
|
||||
}))
|
||||
if serr != nil {
|
||||
log.Warn("自动评论查询短剧标签失败", log.E(serr), log.Any("tagIDs", tagIDs))
|
||||
return map[int64]string{}
|
||||
}
|
||||
result := make(map[int64]string, len(tags))
|
||||
for _, tag := range tags {
|
||||
if tag != nil {
|
||||
result[tag.Id] = tag.Name
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func playletTagNames(tagIDs []int64, tagNames map[int64]string) []string {
|
||||
result := make([]string, 0, len(tagIDs))
|
||||
seen := make(map[string]struct{}, len(tagIDs))
|
||||
for _, tagID := range tagIDs {
|
||||
name := strings.TrimSpace(tagNames[tagID])
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
if _, ok := seen[name]; ok {
|
||||
continue
|
||||
}
|
||||
seen[name] = struct{}{}
|
||||
result = append(result, name)
|
||||
if len(result) >= maxVideoTags {
|
||||
break
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user