Initial commit

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-15 13:57:10 +08:00
co-authored by Claude Opus 5
commit 8679200f41
1897 changed files with 257900 additions and 0 deletions
+161
View File
@@ -0,0 +1,161 @@
package officialWebsiteser
import (
"91porn-server/common/stderr"
"91porn-server/models/v/officialWebsitemod"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo/options"
)
type AlbumListReq struct {
SortType int64 `json:"sortType" form:"sortType"` // 1: 创建时间 目前仅支持一种排序方式,后续增加后再完善这个字段
PageNumber int64 `json:"pageNumber" form:"pageNumber"`
PageSize int64 `json:"pageSize" form:"pageSize"`
}
type AlbumListResp struct {
HasNext bool `json:"hasNext"`
List []*AlbumResp `json:"list"`
}
type AlbumResp struct {
ID string `json:"id"`
HeroID string `json:"heroID"`
Title string `json:"title"`
SeoSlug string `json:"seoSlug"`
Description string `json:"description"`
Cover string `json:"cover"`
IsHot bool `json:"isHot"`
Tags []string `json:"tags"`
}
func (a *AlbumResp) FromModel(album *officialWebsitemod.Album) {
if album == nil {
return
}
a.ID = album.ID.Hex()
a.HeroID = album.HeroID.Hex()
a.Title = album.Title
a.SeoSlug = album.SeoSlug
a.Description = album.Description
a.Cover = album.Cover
a.IsHot = album.IsHot
a.Tags = make([]string, 0)
for _, tag := range album.Tags {
a.Tags = append(a.Tags, tag.Name)
}
}
func AlbumList(req *AlbumListReq) (resp AlbumListResp, err error) {
var sort = bson.D{}
switch req.SortType { // 目前仅支持一种排序方式,后续增加后再完善这个字段
default:
sort = bson.D{{Key: "createdAt", Value: -1}}
}
var albumMod = &officialWebsitemod.Album{}
var skip, limit = transPageAndPageNumber(req.PageSize, req.PageNumber)
var ops = options.Find().SetSort(sort).SetSkip(skip).SetLimit(limit + 1)
albumsData, err := albumMod.FindMany(bson.M{"isActive": true}, ops)
if err != nil {
return
}
resp = AlbumListResp{
HasNext: len(albumsData) > int(limit),
List: make([]*AlbumResp, 0),
}
for _, v := range albumsData {
var albumResp = &AlbumResp{}
albumResp.FromModel(&v)
resp.List = append(resp.List, albumResp)
}
if resp.HasNext {
resp.List = resp.List[:len(resp.List)-1]
}
return resp, nil
}
type AlbumDetailReq struct {
ID string `uri:"id" form:"id"`
PageNumber int64 `json:"pageNumber" form:"pageNumber"`
PageSize int64 `json:"pageSize" form:"pageSize"`
}
type AlbumDetailResp struct {
AlbumResp
Videos []AlbumDetailVideoResp `json:"videos"`
}
type AlbumDetailVideoResp struct {
ID string `json:"id"`
Title string `json:"title"`
SeoSlug string `json:"seoSlug"`
Description string `json:"description"`
Cover string `json:"cover"`
Url string `json:"url"`
IsHot bool `json:"isHot"`
Tags []VideoTagResp `json:"tags"`
WatchCount int64 `json:"watchCount"`
LikeCount int64 `json:"likeCount"`
CommentCount int64 `json:"commentCount"`
CollectCount int64 `json:"collectCount"`
}
func AlbumDetail(req *AlbumDetailReq) (resp AlbumDetailResp, err error) {
if req.ID == "" {
err = stderr.ErrParamError
return
}
// 兼容 id 与 seoSlug24 位 hex 按 _id 查,否则按 seoSlug 查
filter := bson.M{}
if objID, e := primitive.ObjectIDFromHex(req.ID); e == nil {
filter["_id"] = objID
} else {
filter["seoSlug"] = req.ID
}
albumMod := &officialWebsitemod.Album{}
err = albumMod.FindOne(filter)
if err != nil {
return
}
resp.FromModel(albumMod)
// 组装获取专辑下视频列表
filter = bson.M{"albumId": albumMod.ID}
var skip, limit = transPageAndPageNumber(req.PageSize, req.PageNumber)
var option = options.Find().SetSort(bson.D{{Key: "createdAt", Value: -1}}).SetSkip(skip).SetLimit(limit + 1)
videoMod := &officialWebsitemod.Video{}
var videos []officialWebsitemod.Video
videos, err = videoMod.FindMany(filter, option)
if err != nil {
return
}
for _, video := range videos {
var videoResp = AlbumDetailVideoResp{
ID: video.ID.Hex(),
Title: video.Title,
SeoSlug: video.SeoSlug,
Description: video.Description,
Cover: video.Cover,
Url: video.Url,
IsHot: video.IsHot,
WatchCount: video.WatchCount,
LikeCount: video.LikeCount,
CommentCount: video.CommentCount,
CollectCount: video.CollectCount,
}
for _, tag := range video.Tags {
videoResp.Tags = append(videoResp.Tags, VideoTagResp{
ID: tag.ID.Hex(),
Name: tag.Name,
})
}
resp.Videos = append(resp.Videos, videoResp)
}
return
}
+225
View File
@@ -0,0 +1,225 @@
package officialWebsiteser
import (
"91porn-server/common/stderr"
"91porn-server/models/v/officialWebsitemod"
"91porn-server/models/v/sourcemod"
"go.mongodb.org/mongo-driver/bson/primitive"
)
type GetBasicDataResp struct {
Title string `json:"title"`
Description string `json:"description"`
//域名信息
SourceList []*sourcemod.SourceRes `json:"sourceList"`
//接口域名
Domain []string `json:"domain"`
Banner []Banner `json:"banner"`
BannersDescription string `json:"bannersDescription" bson:"bannersDescription"`
BannersDuration int `json:"bannersDuration" bson:"bannersDuration"`
HeroBanner []BasicDataHeroBanner `json:"heroBanner"`
Masterpiece []BasicDataMasterpiece `json:"masterpiece"`
Business []BasicDataBusiness `json:"business"`
AboutUs BasicDataAboutUs `json:"aboutUs"`
FAQ []BasicDataFAQ `json:"faq"`
HomePageCMS []BasicDataCMSData `json:"homePageCMS"`
RecruitCMS []BasicDataCMSData `json:"recruitCMS"`
Tags []officialWebsitemod.Tag `json:"tags"`
}
type Banner struct {
Name string `json:"name"`
Description string `json:"description"`
Image string `json:"image"`
PhoneImage string `json:"phoneImage"`
Thumbnail string `json:"thumbnail"`
URL string `json:"url"`
}
type BasicDataHeroBanner struct {
HeroID string `json:"heroId"`
Name string `json:"name"`
Description string `json:"description"`
Image string `json:"image"`
URL string `json:"url"`
Duration int `json:"duration"`
}
type BasicDataMasterpiece struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Cover string `json:"cover"`
Type string `json:"type"`
}
type BasicDataBusiness struct {
Name string `json:"name"`
EnglishName string `json:"englishName"`
Description string `json:"description"`
Cover string `json:"cover"`
Detail []BasicDataBusinessDetail `json:"detail"`
}
type BasicDataBusinessDetail struct {
Cover string `json:"cover"`
Description string `json:"description"`
}
type BasicDataAboutUs struct {
Description string `json:"description"`
Companies []BasicDataCompanyInfo `json:"companies"`
Values string `json:"values"`
ValuesImg string `json:"valuesImg"`
}
type BasicDataCompanyInfo struct {
Name string `json:"name"`
Address string `json:"address"`
Description string `json:"description"`
Contact []BasicDataContactInfo `json:"contact"`
}
type BasicDataContactInfo struct {
Type string `json:"type"`
Value string `json:"value"`
}
type SourceResp struct {
ID primitive.ObjectID `json:"id,omitempty" bson:"_id,omitempty"`
IsActive bool `json:"isActive,omitempty" bson:"isActive,omitempty"`
Type string `json:"type,omitempty" bson:"type,omitempty"`
Domain DomainResp `json:"domain,omitempty" bson:"domain,omitempty"`
}
type DomainResp struct {
Weight int `json:"weight,omitempty" bson:"weight,omitempty"`
Url string `json:"url,omitempty" bson:"url,omitempty"`
Desc string `json:"desc,omitempty" bson:"desc,omitempty"`
Status int `json:"status,omitempty" bson:"status,omitempty"`
}
type BasicDataFAQ struct {
Question string `json:"question"`
Answer string `json:"answer"`
}
type BasicDataCMSData struct {
Description string `json:"description"`
Value string `json:"value"`
}
func GetBasicData() (data GetBasicDataResp, err error) {
basicDataMod := &officialWebsitemod.BasicData{}
err = basicDataMod.FindOne()
if err != nil {
return
}
if basicDataMod.ID == primitive.NilObjectID {
err = stderr.OfficialWebsiteBasicDataNotExist
return
}
data = GetBasicDataResp{
Title: basicDataMod.Title,
Description: basicDataMod.Description,
Banner: make([]Banner, 0),
BannersDescription: basicDataMod.BannersDescription,
BannersDuration: basicDataMod.BannersDuration,
HeroBanner: make([]BasicDataHeroBanner, 0),
Masterpiece: make([]BasicDataMasterpiece, 0),
Business: make([]BasicDataBusiness, 0),
AboutUs: BasicDataAboutUs{},
FAQ: make([]BasicDataFAQ, 0),
HomePageCMS: make([]BasicDataCMSData, 0),
RecruitCMS: make([]BasicDataCMSData, 0),
}
for _, v := range basicDataMod.Banner {
data.Banner = append(data.Banner, Banner{
Name: v.Name,
Description: v.Description,
Image: v.Image,
PhoneImage: v.PhoneImage,
Thumbnail: v.Thumbnail,
URL: v.URL,
})
}
for _, v := range basicDataMod.HeroBanner {
data.HeroBanner = append(data.HeroBanner, BasicDataHeroBanner{
HeroID: v.HeroID.Hex(),
Name: v.Name,
Description: v.Description,
Image: v.Image,
URL: v.URL,
Duration: v.Duration,
})
}
for _, v := range basicDataMod.Masterpiece {
data.Masterpiece = append(data.Masterpiece, BasicDataMasterpiece{
ID: v.ID.Hex(),
Name: v.Name,
Description: v.Description,
Cover: v.Cover,
Type: v.Type,
})
}
for _, v := range basicDataMod.Business {
data.Business = append(data.Business, BasicDataBusiness{
Name: v.Name,
EnglishName: v.EnglishName,
Description: v.Description,
Cover: v.Cover,
Detail: make([]BasicDataBusinessDetail, 0, len(v.Detail)),
})
for _, d := range v.Detail {
data.Business[len(data.Business)-1].Detail = append(data.Business[len(data.Business)-1].Detail, BasicDataBusinessDetail{
Cover: d.Cover,
Description: d.Description,
})
}
}
data.AboutUs = BasicDataAboutUs{
Description: basicDataMod.AboutUs.Description,
Values: basicDataMod.AboutUs.Values,
ValuesImg: basicDataMod.AboutUs.ValuesImg,
}
for _, v := range basicDataMod.AboutUs.Companies {
data.AboutUs.Companies = append(data.AboutUs.Companies, BasicDataCompanyInfo{
Name: v.Name,
Address: v.Address,
Description: v.Description,
Contact: make([]BasicDataContactInfo, 0),
})
for _, c := range v.Contact {
data.AboutUs.Companies[len(data.AboutUs.Companies)-1].Contact = append(data.AboutUs.Companies[len(data.AboutUs.Companies)-1].Contact, BasicDataContactInfo{
Type: c.Type,
Value: c.Value,
})
}
}
for _, v := range basicDataMod.FAQ {
data.FAQ = append(data.FAQ, BasicDataFAQ{
Question: v.Question,
Answer: v.Answer,
})
}
for _, v := range basicDataMod.HomePageCMS {
data.HomePageCMS = append(data.HomePageCMS, BasicDataCMSData{
Description: v.Description,
Value: v.Value,
})
}
for _, v := range basicDataMod.RecruitCMS {
data.RecruitCMS = append(data.RecruitCMS, BasicDataCMSData{
Description: v.Description,
Value: v.Value,
})
}
data.Tags = basicDataMod.Tags
// 域名信息(Domain/SourceList)改由 controller 实时获取,不进基础数据大缓存
return data, err
}
@@ -0,0 +1,66 @@
package officialWebsiteser
import "91porn-server/models/v/officialWebsitemod"
type BusinessListReq struct{}
type BusinessListResp struct {
Total int64 `json:"total"`
ADPlacement []BusinessInfo `json:"adPlacement"`
ContentProduction []BusinessInfo `json:"contentProduction"`
SubRevenue []BusinessInfo `json:"subRevenue"`
}
type BusinessInfo struct {
Title string `json:"title"`
Description string `json:"description"`
Type string `json:"type"` // 业务类型,如"adPlacement", "contentProduction", "subRevenue"
ServiceOverview string `json:"serviceOverview"`
CollaborationProcess string `json:"collaborationProcess"`
CaseStudies string `json:"caseStudies"`
}
func BusinessList(req *BusinessListReq) (resp BusinessListResp, err error) {
data, err := (&officialWebsitemod.BusinessData{}).FindMany(nil)
if err != nil {
return
}
resp = BusinessListResp{
Total: int64(len(data)),
ADPlacement: make([]BusinessInfo, 0),
ContentProduction: make([]BusinessInfo, 0),
SubRevenue: make([]BusinessInfo, 0),
}
for _, v := range data {
switch v.Type {
case "adPlacement":
resp.ADPlacement = append(resp.ADPlacement, BusinessInfo{
Title: v.Title,
Description: v.Description,
Type: v.Type,
ServiceOverview: v.ServiceOverview,
CollaborationProcess: v.CollaborationProcess,
CaseStudies: v.CaseStudies,
})
case "contentProduction":
resp.ContentProduction = append(resp.ContentProduction, BusinessInfo{
Title: v.Title,
Description: v.Description,
Type: v.Type,
ServiceOverview: v.ServiceOverview,
CollaborationProcess: v.CollaborationProcess,
CaseStudies: v.CaseStudies,
})
case "subRevenue":
resp.SubRevenue = append(resp.SubRevenue, BusinessInfo{
Title: v.Title,
Description: v.Description,
Type: v.Type,
ServiceOverview: v.ServiceOverview,
CollaborationProcess: v.CollaborationProcess,
CaseStudies: v.CaseStudies,
})
}
}
return resp, nil
}
+13
View File
@@ -0,0 +1,13 @@
package officialWebsiteser
func transPageAndPageNumber(pageSize, pageNumber int64) (skip int64, limit int64) {
if pageNumber <= 0 {
pageNumber = 1
}
if pageSize <= 0 {
pageSize = 20
}
skip = (pageNumber - 1) * pageSize
limit = pageSize
return skip, limit
}
+314
View File
@@ -0,0 +1,314 @@
package officialWebsiteser
import (
"91porn-server/common"
"91porn-server/models/v/officialWebsitemod"
"sync"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo/options"
)
type HeroListReq struct {
SortType int `json:"sortType" form:"sortType"` // 1: 最多粉丝,2: 最新加入,3:后管排序
PageNumber int64 `json:"pageNumber" form:"pageNumber"`
PageSize int64 `json:"pageSize" form:"pageSize"`
}
type HeroListResp struct {
HasNext bool `json:"hasNext"`
List []*HeroResp `json:"list"`
}
type HeroResp struct {
ID string `json:"id"`
Name string `json:"name"`
SeoSlug string `json:"seoSlug"`
Avatar string `json:"avatar"`
FansCount int64 `json:"fansCount"`
Cover string `json:"cover"`
}
func HeroList(req *HeroListReq) (resp HeroListResp, err error) {
var sort = bson.M{}
switch req.SortType {
case 2:
sort["createdAt"] = -1
case 3:
sort["sort"] = -1
default:
sort["fansCount"] = -1
}
// 分页查询时,查询一条多的数据来判断是否有下一页数据
var skip, limit = transPageAndPageNumber(req.PageSize, req.PageNumber)
var ops = options.Find().SetSort(sort).SetSkip(skip).SetLimit(limit + 1)
data, err := (&officialWebsitemod.Hero{}).FindMany(bson.M{"isActive": true}, ops)
if err != nil {
return
}
resp = HeroListResp{
HasNext: len(data) > int(limit),
List: make([]*HeroResp, 0),
}
for _, v := range data {
hero := &HeroResp{
ID: v.ID.Hex(),
Name: v.Name,
SeoSlug: v.SeoSlug,
Avatar: v.Avatar,
FansCount: v.FansCount,
Cover: v.Cover,
}
resp.List = append(resp.List, hero)
}
// 如果HasNext为true,说明还有下一页数,去除多查询的一条数据
if resp.HasNext {
resp.List = resp.List[:len(resp.List)-1]
}
return
}
type HeroDetailReq struct {
ID string `uri:"id" binding:"required"`
}
type HeroDetailResp struct {
ID string `json:"id"`
Name string `json:"name"`
SeoSlug string `json:"seoSlug"`
Avatar string `json:"avatar"`
Height int64 `json:"height"`
Bust int64 `json:"bust"`
Waist int64 `json:"waist"`
Hip int64 `json:"hip"`
Description string `json:"description"`
FansCount int64 `json:"fansCount"`
Cover string `json:"cover"`
Partners []HeroDetailPartner `json:"partners"`
Albums []HeroDetailAlbum `json:"albums"`
Videos []HeroDetailVideo `json:"videos"`
Photograph []Photograph `json:"photograph"`
}
type HeroDetailAlbum struct {
ID string `json:"id"`
Title string `json:"title"`
SeoSlug string `json:"seoSlug"`
Description string `json:"description"`
Cover string `json:"cover"`
Tags []HeroDetailTag `json:"tags"`
IsHot bool `json:"isHot"`
}
type HeroDetailVideo struct {
ID string `json:"id"`
Title string `json:"title"`
SeoSlug string `json:"seoSlug"`
Description string `json:"description"`
Cover string `json:"cover"`
Url string `json:"url"`
Tags []HeroDetailTag `json:"tags"`
IsHot bool `json:"isHot"`
}
type HeroDetailPartner struct {
ID string `json:"id"`
Name string `json:"name"`
Url string `json:"url"`
Logo string `json:"logo"`
}
type Photograph struct {
ID string `json:"id" bson:"_id,omitempty"`
Name string `json:"name" bson:"name"`
Description string `json:"description" bson:"description"`
Cover string `json:"cover" bson:"cover"`
Photos []string `json:"photos" bson:"photos"`
}
type HeroDetailTag struct {
ID string `json:"id"`
Name string `json:"name"`
}
func HeroDetail(req *HeroDetailReq) (resp *HeroDetailResp, err error) {
filter := bson.M{"isActive": true}
if id, e := primitive.ObjectIDFromHex(req.ID); e == nil {
filter["_id"] = id
} else {
filter["seoSlug"] = req.ID
}
hero := &officialWebsitemod.Hero{}
err = hero.FindOne(filter)
if err != nil {
return nil, err
}
resp = &HeroDetailResp{
ID: hero.ID.Hex(),
Name: hero.Name,
SeoSlug: hero.SeoSlug,
Avatar: hero.Avatar,
Height: hero.Height,
Bust: hero.Bust,
Waist: hero.Waist,
Hip: hero.Hip,
Description: hero.Description,
FansCount: hero.FansCount,
Cover: hero.Cover,
Partners: make([]HeroDetailPartner, 0),
Albums: make([]HeroDetailAlbum, 0),
Videos: make([]HeroDetailVideo, 0),
}
wg := sync.WaitGroup{}
wg.Add(4)
// 查询合作伙伴
common.Go(func() {
defer wg.Done()
resp.Partners, err = getHeroDetailPartners(hero.Partners)
if err != nil {
return
}
})
// 查询专辑
common.Go(func() {
defer wg.Done()
resp.Albums, err = getHeroDetailAlbums(hero.ID)
if err != nil {
return
}
})
// 查询视频
common.Go(func() {
defer wg.Done()
resp.Videos, err = getHeroDetailVideos(hero.ID)
if err != nil {
return
}
})
common.Go(func() {
defer wg.Done()
resp.Photograph, err = getHeroDetailPhotograph(hero.ID)
})
wg.Wait()
return
}
func getHeroDetailAlbums(heroID primitive.ObjectID) (albums []HeroDetailAlbum, err error) {
var albumMod = &officialWebsitemod.Album{}
var filters = bson.M{"heroID": heroID}
albumsData, err := albumMod.FindMany(filters, options.Find().SetSort(bson.D{{Key: "isHot", Value: -1}, {Key: "createdAt", Value: -1}}).SetLimit(10))
if err != nil {
return nil, err
}
albums = make([]HeroDetailAlbum, 0)
for _, v := range albumsData {
tags := make([]HeroDetailTag, 0)
for _, t := range v.Tags {
tags = append(tags, HeroDetailTag{
ID: t.ID.Hex(),
Name: t.Name,
})
}
albums = append(albums, HeroDetailAlbum{
ID: v.ID.Hex(),
Title: v.Title,
SeoSlug: v.SeoSlug,
Description: v.Description,
Cover: v.Cover,
IsHot: v.IsHot,
Tags: tags,
})
}
return
}
func getHeroDetailVideos(heroID primitive.ObjectID) (videos []HeroDetailVideo, err error) {
var videoMod = &officialWebsitemod.Video{}
var filters = bson.M{"heroID": heroID}
videosData, err := videoMod.FindMany(filters, options.Find().SetSort(bson.D{{Key: "isHot", Value: -1}, {Key: "createdAt", Value: -1}}).SetLimit(10))
if err != nil {
return nil, err
}
videos = make([]HeroDetailVideo, 0)
for _, v := range videosData {
tags := make([]HeroDetailTag, 0)
for _, t := range v.Tags {
tags = append(tags, HeroDetailTag{
ID: t.ID.Hex(),
Name: t.Name,
})
}
videos = append(videos, HeroDetailVideo{
ID: v.ID.Hex(),
Title: v.Title,
SeoSlug: v.SeoSlug,
Description: v.Description,
Cover: v.Cover,
Url: v.Url,
IsHot: v.IsHot,
Tags: tags,
})
}
return
}
func getHeroDetailPartners(partnerIds []primitive.ObjectID) (partners []HeroDetailPartner, err error) {
var partnerMod = &officialWebsitemod.Partner{}
var filters = bson.M{"_id": bson.M{"$in": partnerIds}, "isActive": true}
partnersData, err := partnerMod.FindMany(filters)
if err != nil {
return nil, err
}
partners = make([]HeroDetailPartner, 0)
for i := range partnerIds { // 保持合作伙伴的顺序和Hero中的一致,由后管控制
for _, v := range partnersData {
if v.ID == partnerIds[i] {
partners = append(partners, HeroDetailPartner{
ID: v.ID.Hex(),
Name: v.Name,
Url: v.Url,
Logo: v.Logo,
})
}
}
}
return
}
func getHeroDetailPhotograph(heroID primitive.ObjectID) (photograph []Photograph, err error) {
var photographMod = &officialWebsitemod.Photograph{}
var filters = bson.M{"heroId": heroID, "isActive": true}
photographData, err := photographMod.FindMany(filters, options.Find().SetSort(bson.D{{Key: "createdAt", Value: -1}}).SetLimit(10))
if err != nil {
return
}
photograph = make([]Photograph, 0)
for _, v := range photographData {
ph := Photograph{
ID: v.ID.Hex(),
Name: v.Name,
Description: v.Description,
Cover: v.Cover,
Photos: v.Photos,
}
photograph = append(photograph, ph)
}
return
}
+47
View File
@@ -0,0 +1,47 @@
package officialWebsiteser
import (
"91porn-server/models/v/officialWebsitemod"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo/options"
)
type JobListReq struct {
}
type JobListResp struct {
Total int64 `json:"total"`
List []JobInfo `json:"list"`
}
type JobInfo struct {
Title string `json:"title"`
Description string `json:"description"`
Requirements string `json:"requirements"`
Benefits string `json:"benefits"`
JDUrl string `json:"jdUrl"`
}
func JobList(req *JobListReq) (resp JobListResp, err error) {
var filter = bson.M{"isActive": true}
var jobMod = &officialWebsitemod.Job{}
jobs, err := jobMod.FindMany(filter, options.Find().SetSort(bson.D{{Key: "isHot", Value: -1}, {Key: "sort", Value: -1}, {Key: "createdAt", Value: -1}}))
if err != nil {
return
}
resp = JobListResp{
Total: int64(len(jobs)),
List: make([]JobInfo, len(jobs)),
}
for i, job := range jobs {
resp.List[i] = JobInfo{
Title: job.Title,
Description: job.Description,
Requirements: job.Requirements,
Benefits: job.Benefits,
JDUrl: job.JDUrl,
}
}
return resp, nil
}
+163
View File
@@ -0,0 +1,163 @@
package officialWebsiteser
import (
"91porn-server/models/v/officialWebsitemod"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo/options"
)
type NewsListReq struct {
PageNumber int64 `form:"PageNumber"`
PageSize int64 `form:"pageSize"`
}
type NewsListResp struct {
HasNext bool `json:"hasNext"`
List []*NewsResp `json:"list"`
}
type NewsResp struct {
ID string `json:"id"`
Title string `json:"title"`
SeoSlug string `json:"seoSlug"`
Description string `json:"description"`
Cover string `json:"cover"`
Url string `json:"url"`
Tags []NewsTagResp `json:"tags"`
CreatedAt time.Time `json:"createdAt,omitempty" bson:"createdAt,omitempty"`
}
type NewsTagResp struct {
ID string `json:"id,omitempty" bson:"_id,omitempty"`
Name string `json:"name,omitempty" bson:"name,omitempty"`
Type string `json:"type,omitempty" bson:"type,omitempty"`
IsHot bool `json:"isHot,omitempty" bson:"isHot,omitempty"`
}
func NewsList(req *NewsListReq) (resp *NewsListResp, err error) {
var filter = bson.M{"isActive": true}
var newsMod = &officialWebsitemod.News{}
var skip, limit = transPageAndPageNumber(req.PageSize, req.PageNumber)
data, err := newsMod.FindMany(filter, options.Find().SetSort(bson.D{{Key: "isHot", Value: -1}, {Key: "sort", Value: -1}, {Key: "createdAt", Value: -1}}).SetSkip(skip).SetLimit(limit+1))
if err != nil {
return nil, err
}
resp = &NewsListResp{
HasNext: len(data) > int(limit),
List: make([]*NewsResp, 0),
}
for _, v := range data {
newsResp := &NewsResp{
ID: v.ID.Hex(),
Title: v.Title,
SeoSlug: v.SeoSlug,
Description: v.Description,
Cover: v.Cover,
Url: v.Url,
CreatedAt: v.CreatedAt,
}
for _, tag := range v.Tags {
newsResp.Tags = append(newsResp.Tags, NewsTagResp{
ID: tag.ID.Hex(),
Name: tag.Name,
Type: tag.Type,
IsHot: tag.IsHot,
})
}
resp.List = append(resp.List, newsResp)
}
if resp.HasNext {
resp.List = resp.List[:len(resp.List)-1]
}
return
}
type NewsDetailReq struct {
ID string `uri:"id" binding:"required"`
RelatedPageNumber int64 `form:"RelatedPageNumber"`
RelatedPageSize int64 `form:"RelatedPageSize"`
}
type NewsDetailResp struct {
ID string `json:"id"`
Title string `json:"title"`
SeoSlug string `json:"seoSlug"`
Description string `json:"description"`
Cover string `json:"cover"`
Url string `json:"url"`
Tags []NewsTagResp `json:"tags"`
Detail string `json:"detail"`
Related []*NewsResp `json:"related"`
CreatedAt time.Time `json:"createdAt"`
}
func NewsDetail(req *NewsDetailReq) (resp NewsDetailResp, err error) {
// 兼容 id 与 seoSlug24 位 hex 按 _id 查,否则按 seoSlug 查
var filter = bson.M{"isActive": true}
if id, e := primitive.ObjectIDFromHex(req.ID); e == nil {
filter["_id"] = id
} else {
filter["seoSlug"] = req.ID
}
var newsMod = &officialWebsitemod.News{}
err = newsMod.FindOne(filter)
if err != nil {
return
}
resp = NewsDetailResp{
ID: newsMod.ID.Hex(),
Title: newsMod.Title,
SeoSlug: newsMod.SeoSlug,
Description: newsMod.Description,
Cover: newsMod.Cover,
Url: newsMod.Url,
Detail: newsMod.Detail,
CreatedAt: newsMod.CreatedAt,
}
var tagIDs []primitive.ObjectID
for _, tag := range newsMod.Tags {
resp.Tags = append(resp.Tags, NewsTagResp{
ID: tag.ID.Hex(),
Name: tag.Name,
Type: tag.Type,
IsHot: tag.IsHot,
})
tagIDs = append(tagIDs, tag.ID)
}
if len(resp.Tags) > 0 {
// 组装 Related,根据tagIDs搜索,并按照排序
filter = bson.M{"tags._id": bson.M{"$in": tagIDs}, "isActive": true}
} else {
filter = bson.M{"isActive": true}
}
skip, limit := transPageAndPageNumber(req.RelatedPageSize, req.RelatedPageNumber)
data, err := newsMod.FindMany(filter, options.Find().SetSort(bson.D{{Key: "isHot", Value: -1}, {Key: "sort", Value: -1}, {Key: "createdAt", Value: -1}}).SetSkip(skip).SetLimit(limit))
if err != nil {
return
}
for _, v := range data {
newsResp := &NewsResp{
ID: v.ID.Hex(),
Title: v.Title,
SeoSlug: v.SeoSlug,
Description: v.Description,
Cover: v.Cover,
Url: v.Url,
CreatedAt: v.CreatedAt,
}
for _, tag := range v.Tags {
newsResp.Tags = append(newsResp.Tags, NewsTagResp{
ID: tag.ID.Hex(),
Name: tag.Name,
Type: tag.Type,
IsHot: tag.IsHot,
})
}
resp.Related = append(resp.Related, newsResp)
}
return
}
+37
View File
@@ -0,0 +1,37 @@
package officialWebsiteser
import "91porn-server/models/v/officialWebsitemod"
type PartnerListReq struct{}
type PartnerListResp struct {
Total int64 `json:"total"`
List []PartnerResp `json:"list"`
}
type PartnerResp struct {
Name string `json:"name"`
Description string `json:"description"`
Logo string `json:"logo"`
Url string `json:"url"`
}
func PartnerList(req *PartnerListReq) (resp PartnerListResp, err error) {
data, err := (&officialWebsitemod.Partner{}).FindMany(nil)
if err != nil {
return
}
resp = PartnerListResp{
Total: int64(len(data)),
List: make([]PartnerResp, 0),
}
for _, v := range data {
resp.List = append(resp.List, PartnerResp{
Name: v.Name,
Description: v.Description,
Logo: v.Logo,
Url: v.Url,
})
}
return resp, nil
}
+97
View File
@@ -0,0 +1,97 @@
package officialWebsiteser
import (
"91porn-server/models/v/officialWebsitemod"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)
type RecruitFormReq struct {
Name string `json:"name" form:"name" binding:"required"`
Sex int `json:"sex" form:"sex"`
Age int `json:"age" form:"age"`
Country string `json:"country" form:"country"`
Address string `json:"address" form:"address"`
Contact []ContactInfoReq `json:"contact" form:"contact" binding:"required,dive"`
Description string `json:"description" form:"description"`
}
type ContactInfoReq struct {
Type string `json:"type" form:"type"`
Value string `json:"value" form:"value"`
}
type RecruitFormResp struct {
Message string `json:"message"`
}
func RecruitForm(req *RecruitFormReq) (resp RecruitFormResp, err error) {
if filter, ok := buildRecruitContactFilter(req.Contact); ok {
var exist = &officialWebsitemod.RecruitForm{}
err = exist.FindOne(filter)
if err != nil {
return
}
if exist.ID != primitive.NilObjectID {
resp = RecruitFormResp{
Message: "您已提交过了,我们会尽快联系您",
}
return resp, nil
}
}
form := &officialWebsitemod.RecruitForm{
Name: req.Name,
Sex: req.Sex,
Age: req.Age,
Country: req.Country,
Address: req.Address,
Description: req.Description,
}
for _, v := range req.Contact {
form.Contact = append(form.Contact, officialWebsitemod.ContactInfo{
Type: v.Type,
Value: v.Value,
})
}
err = form.Create()
if err != nil {
return
}
resp = RecruitFormResp{
Message: "提交成功",
}
return resp, nil
}
func buildRecruitContactFilter(contacts []ContactInfoReq) (officialWebsitemod.M, bool) {
if len(contacts) == 0 {
return nil, false
}
orConditions := make([]officialWebsitemod.M, 0, len(contacts))
for _, c := range contacts {
if c.Type == "" || c.Value == "" {
continue
}
orConditions = append(orConditions, officialWebsitemod.M{
"contact": bson.M{
"$elemMatch": bson.M{
"type": c.Type,
"value": c.Value,
},
},
})
}
if len(orConditions) == 0 {
return nil, false
}
if len(orConditions) == 1 {
return orConditions[0], true
}
return officialWebsitemod.M{"$or": orConditions}, true
}
+48
View File
@@ -0,0 +1,48 @@
package officialWebsiteser
import (
"91porn-server/models/v/officialWebsitemod"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo/options"
)
type TagListReq struct {
Type string `json:"type" form:"type" binding:"required,oneof=video hero album all"`
}
type TagListResp struct {
List []*TagResp `json:"list"`
}
type TagResp struct {
ID string `json:"id"`
Name string `json:"name"`
}
func TagList(req *TagListReq) (resp TagListResp, err error) {
var filter = bson.M{}
switch req.Type {
case "":
filter = bson.M{}
case "all":
filter = bson.M{}
default:
filter = bson.M{"type": req.Type}
}
filter["isActive"] = true
data, err := (&officialWebsitemod.Tag{}).FindMany(filter, options.Find().SetSort(bson.D{{Key: "isHot", Value: -1}, {Key: "sort", Value: -1}, {Key: "createdAt", Value: -1}}))
if err != nil {
return
}
resp = TagListResp{
List: make([]*TagResp, 0),
}
for _, v := range data {
resp.List = append(resp.List, &TagResp{
ID: v.ID.Hex(),
Name: v.Name,
})
}
return resp, nil
}
+227
View File
@@ -0,0 +1,227 @@
package officialWebsiteser
import (
"91porn-server/common"
"91porn-server/common/stderr"
"91porn-server/models/v/officialWebsitemod"
"91porn-server/models/v/vidmod"
"sync"
"time"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo/options"
)
type VideoListReq struct {
Type int64 `json:"type" form:"type"` // 1: 全量,2:专辑ID3:演员ID, 4: TagID
ID string `json:"id" form:"id"` // 专辑ID或者演员ID,根据Type决定
Sort int64 `json:"sort" form:"sort"` // 1:热度,2:创建时间,3: 播放量,4:点赞量,5:评论量,6:收藏量
PageNumber int64 `json:"pageNumber" form:"pageNumber"`
PageSize int64 `json:"pageSize" form:"pageSize"`
}
type VideoListResp struct {
HasNext bool `json:"hasNext"`
List []*VideoResp `json:"list"`
}
type VideoResp struct {
ID string `json:"id"`
Title string `json:"title"`
SeoSlug string `json:"seoSlug"`
Cover string `json:"cover"`
IsHot bool `json:"isHot"`
Tags []VideoTagResp `json:"tags"`
}
type VideoTagResp struct {
ID string `json:"id"`
Name string `json:"name"`
}
func VideoList(req *VideoListReq) (resp VideoListResp, err error) {
var sort interface{}
switch req.Sort {
case 2:
sort = bson.D{{Key: "createdAt", Value: -1}}
case 3:
sort = bson.D{{Key: "watchCount", Value: -1}}
case 4:
sort = bson.D{{Key: "likeCount", Value: -1}}
case 5:
sort = bson.D{{Key: "commentCount", Value: -1}}
case 6:
sort = bson.D{{Key: "collectCount", Value: -1}}
default:
sort = bson.D{{Key: "isHot", Value: -1}, {Key: "createdAt", Value: -1}}
}
var filter = bson.M{}
objID, err := primitive.ObjectIDFromHex(req.ID)
if err != nil && req.Type != 1 {
err = stderr.ErrParamError
return
}
switch req.Type {
case 2:
filter["albumId"] = objID
case 3:
filter["heroId"] = objID
case 4:
filter["tags._id"] = objID
}
filter["isActive"] = true
var skip, limit = transPageAndPageNumber(req.PageSize, req.PageNumber)
var ops = options.Find().SetSort(sort).SetSkip(skip).SetLimit(limit + 1)
videosData, err := (&officialWebsitemod.Video{}).FindMany(filter, ops)
if err != nil {
return
}
resp = VideoListResp{
HasNext: len(videosData) > int(limit),
List: make([]*VideoResp, 0),
}
for _, v := range videosData {
var videoResp = &VideoResp{
ID: v.ID.Hex(),
Title: v.Title,
SeoSlug: v.SeoSlug,
Cover: v.Cover,
IsHot: v.IsHot,
Tags: make([]VideoTagResp, 0),
}
for _, tag := range v.Tags {
videoResp.Tags = append(videoResp.Tags, VideoTagResp{
ID: tag.ID.Hex(),
Name: tag.Name,
})
}
resp.List = append(resp.List, videoResp)
}
if resp.HasNext {
resp.List = resp.List[:len(resp.List)-1]
}
return
}
type VideoDetailReq struct {
ID string `uri:"id" binding:"required"`
}
type VideoDetailResp struct {
ID string `json:"id"`
Title string `json:"title"`
SeoSlug string `json:"seoSlug"`
Description string `json:"description"`
Cover string `json:"cover"`
Url string `json:"url"`
PlayTime uint `json:"playTime"` // 视频播放时长(秒)
IsHot bool `json:"isHot"`
Tags []VideoTagResp `json:"tags"`
WatchCount int64 `json:"watchCount"`
LikeCount int64 `json:"likeCount"`
CommentCount int64 `json:"commentCount"`
CollectCount int64 `json:"collectCount"`
RelatedVideos []VideoResp `json:"relatedVideos"`
CreatedAt time.Time `json:"createdAt"`
}
func VideoDetail(req *VideoDetailReq) (resp VideoDetailResp, err error) {
// 兼容 id 与 seoSlug24 位 hex 按 _id 查,否则按 seoSlug 查
filter := bson.M{"isActive": true}
if id, e := primitive.ObjectIDFromHex(req.ID); e == nil {
filter["_id"] = id
} else {
filter["seoSlug"] = req.ID
}
video := &officialWebsitemod.Video{}
err = video.FindOne(filter)
if err != nil {
return
}
if video.ID == primitive.NilObjectID {
err = stderr.OfficialWebsiteVideoNotExist
return
}
resp = VideoDetailResp{
ID: video.ID.Hex(),
Title: video.Title,
SeoSlug: video.SeoSlug,
Description: video.Description,
Cover: video.Cover,
Url: video.Url,
IsHot: video.IsHot,
Tags: make([]VideoTagResp, 0),
WatchCount: video.WatchCount,
LikeCount: video.LikeCount,
CommentCount: video.CommentCount,
CollectCount: video.CollectCount,
CreatedAt: video.CreatedAt,
}
// 播放时长:官网视频复用了视频库(vidmod)的视频 ID,按 ID 反查视频库获取
if vid, e := vidmod.GetVideoByID(video.ID); e == nil && vid != nil {
resp.PlayTime = vid.PlayTime
}
for _, tag := range video.Tags {
resp.Tags = append(resp.Tags, VideoTagResp{
ID: tag.ID.Hex(),
Name: tag.Name,
})
}
var tagsID = make([]primitive.ObjectID, 0)
for _, tag := range video.Tags {
tagsID = append(tagsID, tag.ID)
}
var videoTags []officialWebsitemod.Video
var videoNormal []officialWebsitemod.Video
var wg = &sync.WaitGroup{}
wg.Add(2)
common.Go(func() {
defer wg.Done()
if len(tagsID) == 0 {
return
}
filterTags := bson.M{"tags.id": bson.M{"$in": tagsID}, "isActive": true}
videoTags, _ = (&officialWebsitemod.Video{}).FindMany(filterTags,
options.Find().SetSort(bson.D{{Key: "isHot", Value: -1}, {Key: "createdAt", Value: -1}}).SetLimit(10))
})
common.Go(func() {
defer wg.Done()
filterNormal := bson.M{"isActive": true}
videoNormal, _ = (&officialWebsitemod.Video{}).FindMany(filterNormal,
options.Find().SetSort(bson.D{{Key: "isHot", Value: -1}, {Key: "createdAt", Value: -1}}).SetLimit(10))
})
wg.Wait()
var relatedVideosData []officialWebsitemod.Video
if len(videoTags) > 0 {
relatedVideosData = videoTags
} else {
relatedVideosData = videoNormal
}
resp.RelatedVideos = make([]VideoResp, 0)
for _, v := range relatedVideosData {
var videoResp = VideoResp{
ID: v.ID.Hex(),
Title: v.Title,
SeoSlug: v.SeoSlug,
Cover: v.Cover,
IsHot: v.IsHot,
Tags: make([]VideoTagResp, 0),
}
for _, tag := range v.Tags {
videoResp.Tags = append(videoResp.Tags, VideoTagResp{
ID: tag.ID.Hex(),
Name: tag.Name,
})
}
resp.RelatedVideos = append(resp.RelatedVideos, videoResp)
}
return
}