API分页
This commit is contained in:
626
api/image.go
Normal file
626
api/image.go
Normal file
@@ -0,0 +1,626 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.satori.love/gameui/webp/models"
|
||||
"github.com/doug-martin/goqu/v9"
|
||||
"github.com/graphql-go/graphql"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"github.com/zhenghaoz/gorse/client"
|
||||
)
|
||||
|
||||
type Image struct {
|
||||
ID int `json:"id" db:"id" gorm:"primaryKey"`
|
||||
Width int `json:"width" db:"width"`
|
||||
Height int `json:"height" db:"height"`
|
||||
Content string `json:"content" db:"content"`
|
||||
Remark string `json:"remark" db:"remark"`
|
||||
Description string `json:"description" db:"description"`
|
||||
Tags string `json:"tags" db:"tags"`
|
||||
Rank string `json:"rank" db:"rank"`
|
||||
CommentNum int `json:"comment_num" db:"comment_num"`
|
||||
PraiseCount int `json:"praise_count" gorm:"column:praise"`
|
||||
CollectCount int `json:"collect_count" db:"collect_count"`
|
||||
ArticleID int `json:"article_id" db:"article_id"`
|
||||
UserID int `json:"user_id" db:"user_id"`
|
||||
CreateTime time.Time `json:"create_time" db:"create_time"`
|
||||
UpdateTime time.Time `json:"update_time" db:"update_time"`
|
||||
Text TextList `json:"text" db:"text" gorm:"type:json"`
|
||||
User User `json:"user" gorm:"foreignKey:UserID"`
|
||||
Article Article `json:"article" gorm:"foreignKey:ArticleID"`
|
||||
Activity bool `json:"activity"`
|
||||
}
|
||||
|
||||
func (Image) TableName() string {
|
||||
return "web_images"
|
||||
}
|
||||
|
||||
type TextList []struct {
|
||||
Text string `json:"text"`
|
||||
Confidence float64 `json:"confidence"`
|
||||
Coordinate [][]float64 `json:"coordinate"`
|
||||
}
|
||||
|
||||
func (a *TextList) Scan(value interface{}) error {
|
||||
// 如果数据库中的值为NULL,则返回nil
|
||||
if value == nil || len(value.([]byte)) == 0 {
|
||||
*a = TextList{}
|
||||
return nil
|
||||
}
|
||||
return json.Unmarshal(value.([]byte), a)
|
||||
}
|
||||
|
||||
func (a TextList) Value() (driver.Value, error) {
|
||||
return json.Marshal(a)
|
||||
}
|
||||
|
||||
// 图像的可选字段
|
||||
var imageType = graphql.NewObject(graphql.ObjectConfig{
|
||||
Name: "Image",
|
||||
Description: "图像",
|
||||
Fields: graphql.Fields{
|
||||
"id": &graphql.Field{Type: graphql.Int, Description: "图像ID"},
|
||||
"width": &graphql.Field{Type: graphql.Int, Description: "图像宽度"},
|
||||
"height": &graphql.Field{Type: graphql.Int, Description: "图像高度"},
|
||||
"content": &graphql.Field{Type: graphql.String, Description: "图像内容"},
|
||||
"remark": &graphql.Field{Type: graphql.String, Description: "图像备注"},
|
||||
"description": &graphql.Field{Type: graphql.String, Description: "图像描述"},
|
||||
"tags": &graphql.Field{Type: graphql.String, Description: "图像标签"},
|
||||
"rank": &graphql.Field{Type: graphql.String, Description: "图像等级"},
|
||||
"comment_num": &graphql.Field{Type: graphql.Int, Description: "评论数"},
|
||||
"article_category_top_id": &graphql.Field{Type: graphql.Int, Description: "文章分类顶级ID"},
|
||||
"praise_count": &graphql.Field{Type: graphql.Int, Description: "点赞数"},
|
||||
"collect_count": &graphql.Field{Type: graphql.Int, Description: "收藏数"},
|
||||
"create_time": &graphql.Field{Type: graphql.DateTime, Description: "图像创建时间"},
|
||||
"update_time": &graphql.Field{Type: graphql.DateTime, Description: "图像更新时间"},
|
||||
"activity": &graphql.Field{Type: graphql.Boolean, Description: "图像活动"},
|
||||
"article": &graphql.Field{Type: articleType, Description: "图像所属文章"},
|
||||
"praise": &graphql.Field{Type: graphql.Boolean, Description: "当前用户是否点赞", Resolve: func(p graphql.ResolveParams) (interface{}, error) {
|
||||
var user_id = p.Context.Value("user_id").(int)
|
||||
if user_id != 0 {
|
||||
var praise int64
|
||||
if err := db.Table("web_praise").Where("user_id = ?", user_id).Where("praise_id = ?", p.Source.(Image).ID).Where("type = ?", 4).Count(&praise); err != nil {
|
||||
return false, nil
|
||||
}
|
||||
if praise > 0 {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}},
|
||||
"collect": &graphql.Field{Type: graphql.Boolean, Description: "当前用户是否收藏", Resolve: func(p graphql.ResolveParams) (interface{}, error) {
|
||||
var user_id = p.Context.Value("user_id").(int)
|
||||
if user_id != 0 {
|
||||
var collect int64
|
||||
if err := db.Table("web_collect").Where("user_id = ?", user_id).Where("image_id = ?", p.Source.(Image).ID).Count(&collect); err != nil {
|
||||
return false, nil
|
||||
}
|
||||
if collect > 0 {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}},
|
||||
"collect_id": &graphql.Field{Type: graphql.Int, Description: "当前用户收藏ID", Resolve: func(p graphql.ResolveParams) (interface{}, error) {
|
||||
var user_id = p.Context.Value("user_id").(int)
|
||||
if user_id != 0 {
|
||||
var collect_id int
|
||||
if err := db.Table("web_collect").Where("user_id = ?", user_id).Where("image_id = ?", p.Source.(Image).ID).First(&collect_id); err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
return collect_id, nil
|
||||
}
|
||||
return nil, nil
|
||||
}},
|
||||
"text": &graphql.Field{
|
||||
Type: graphql.NewList(graphql.NewObject(graphql.ObjectConfig{
|
||||
Name: "Text",
|
||||
Description: "图像中的文字提取",
|
||||
Fields: graphql.Fields{
|
||||
"text": &graphql.Field{Type: graphql.String, Description: "文字内容"},
|
||||
"confidence": &graphql.Field{Type: graphql.Float, Description: "置信度"},
|
||||
"coordinate": &graphql.Field{Type: &graphql.List{OfType: graphql.NewList(graphql.Float)}, Description: "文字坐标"},
|
||||
},
|
||||
})),
|
||||
Description: "图像中的文字",
|
||||
Args: graphql.FieldConfigArgument{
|
||||
"text": &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选含有指定文字的列"},
|
||||
},
|
||||
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
|
||||
if p.Args["text"] != nil {
|
||||
var texts TextList
|
||||
for _, text := range p.Source.(Image).Text {
|
||||
if strings.Contains(text.Text, p.Args["text"].(string)) {
|
||||
texts = append(texts, text)
|
||||
}
|
||||
}
|
||||
return texts, nil
|
||||
}
|
||||
return p.Source.(Image).Text, nil
|
||||
},
|
||||
},
|
||||
//"user": &graphql.Field{Type: userType, Description: "图像所属用户"},
|
||||
},
|
||||
})
|
||||
|
||||
//image.AddFieldConfig("user", &graphql.Field{Type: userType, Description: "图像所属用户"})
|
||||
//image.AddFieldConfig("similars", &graphql.Field{Type: graphql.NewList(image), Description: "相似的图像", Resolve: func(p graphql.ResolveParams) (interface{}, error) {
|
||||
// return []Image{}, nil
|
||||
//}})
|
||||
|
||||
var ImageItem = &graphql.Field{
|
||||
Name: "image",
|
||||
Description: "单张图片",
|
||||
Type: imageType,
|
||||
Args: graphql.FieldConfigArgument{
|
||||
"id": &graphql.ArgumentConfig{Type: graphql.Int, Description: "根据ID获取图片"},
|
||||
},
|
||||
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
|
||||
img := Image{ID: p.Args["id"].(int)}
|
||||
query := db.Limit(1)
|
||||
for index, item := range LoadItem(p.Info.FieldASTs[0].SelectionSet.Selections) {
|
||||
fmt.Println(index, item)
|
||||
query = query.Preload(item)
|
||||
}
|
||||
if err := query.First(&img).Error; err != nil {
|
||||
log.Println("获取图片失败", err)
|
||||
return nil, err
|
||||
}
|
||||
return img, nil
|
||||
},
|
||||
}
|
||||
|
||||
var ImageItems = &graphql.Field{
|
||||
Name: "images",
|
||||
Description: "图像列表",
|
||||
Type: graphql.NewObject(graphql.ObjectConfig{
|
||||
Name: "ImageConnection",
|
||||
Description: "条件筛选图像列表",
|
||||
Fields: graphql.Fields{
|
||||
"list": &graphql.Field{Type: graphql.NewList(imageType), Description: "图像列表"},
|
||||
"total": &graphql.Field{Type: graphql.Int, Description: "图像总数"},
|
||||
},
|
||||
}),
|
||||
Args: graphql.FieldConfigArgument{
|
||||
"activity": &graphql.ArgumentConfig{Type: graphql.Boolean, Description: "按是否活动筛选图像"},
|
||||
"style": &graphql.ArgumentConfig{Type: graphql.String, Description: "按游戏风格筛选图像"},
|
||||
"device": &graphql.ArgumentConfig{Type: graphql.String, Description: "按游戏平台筛选图像"},
|
||||
"orientation": &graphql.ArgumentConfig{Type: graphql.String, Description: "按游戏版式筛选图像"},
|
||||
"era": &graphql.ArgumentConfig{Type: graphql.String, Description: "按游戏年份筛选图像"},
|
||||
"category_id": &graphql.ArgumentConfig{Type: graphql.String, Description: "按游戏类型筛选图像(支持多选)"},
|
||||
"tags": &graphql.ArgumentConfig{Type: graphql.String, Description: "按游戏标签筛选图像(支持多选)"},
|
||||
"images_desc": &graphql.ArgumentConfig{Type: graphql.String, Description: "按游戏归类筛选图像(支持多选)"},
|
||||
"article_tags": &graphql.ArgumentConfig{Type: graphql.String, Description: "按文章标签筛选图像(支持多选)"},
|
||||
"color": &graphql.ArgumentConfig{Type: graphql.String, Description: "按主色调筛选图像, 使用十六进制颜色代码(#FF1414)"},
|
||||
"explorer_id": &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选图像中指定收藏夹的"},
|
||||
"collect_id": &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选图像中指定收藏夹的"},
|
||||
"collect": &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选图像中指定用户收藏过的"},
|
||||
"praise": &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选图像中指定用户点赞过的"},
|
||||
"follower": &graphql.ArgumentConfig{Type: graphql.Int, Description: "获取指定ID用户的关注列表发布的图像"},
|
||||
"interest": &graphql.ArgumentConfig{Type: graphql.Int, Description: "获取指定ID用户的兴趣推荐图像"},
|
||||
"similar": &graphql.ArgumentConfig{Type: graphql.Int, Description: "获取与指定ID图像相似的图像"},
|
||||
"id": &graphql.ArgumentConfig{Type: graphql.Int, Description: "获取指定ID的图像"},
|
||||
"width": &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选图像中指定宽度的"},
|
||||
"height": &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选图像中指定高度的"},
|
||||
"comment_num": &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选图像中评论数等于指定值的"},
|
||||
"praise_count": &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选图像中点赞数等于指定值的"},
|
||||
"collect_count": &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选图像中收藏数等于指定值的"},
|
||||
"article_id": &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选图像中属于指定文章ID的"},
|
||||
"user_id": &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选图像中属于指定用户ID的"},
|
||||
"sort": &graphql.ArgumentConfig{Type: graphql.String, Description: "排序方法", DefaultValue: "id"},
|
||||
"content": &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选图像中含有指定内容的"},
|
||||
"remark": &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选图像中含有指定备注的"},
|
||||
"description": &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选图像中含有指定描述的"},
|
||||
"rank": &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选图像中含有指定排名的"},
|
||||
"text": &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选图像中含有指定文字的"},
|
||||
"create_time": &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选图像中创建时间等于指定值的"},
|
||||
"update_time": &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选图像中更新时间等于指定值的"},
|
||||
"first": &graphql.ArgumentConfig{Type: graphql.Int, Description: "翻页参数(傳回清單中的前n個元素)"},
|
||||
"last": &graphql.ArgumentConfig{Type: graphql.Int, Description: "翻页参数(傳回清單中的最後n個元素)"},
|
||||
"after": &graphql.ArgumentConfig{Type: graphql.Int, Description: "翻页参数(傳回清單中指定遊標之後的元素)"},
|
||||
"before": &graphql.ArgumentConfig{Type: graphql.Int, Description: "翻页参数(傳回清單中指定遊標之前的元素)"},
|
||||
"order": &graphql.ArgumentConfig{Type: orderType, Description: "排序方向", DefaultValue: "ASC"},
|
||||
},
|
||||
Resolve: func(p graphql.ResolveParams) (interface{}, error) {
|
||||
// 定义参数结构体
|
||||
var args struct {
|
||||
First int
|
||||
Last int
|
||||
After int
|
||||
Before int
|
||||
Text string
|
||||
Interest int
|
||||
Similar int
|
||||
Sort string
|
||||
Order string
|
||||
}
|
||||
mapstructure.Decode(p.Args, &args)
|
||||
|
||||
var total int
|
||||
var images []Image
|
||||
var query = goqu.Dialect("mysql").From("web_images")
|
||||
|
||||
// 参数映射
|
||||
var argFormat = []string{"id", "width", "height", "content", "remark", "description", "rank", "comment_num", "praise_count", "collect_count", "article_id", "user_id"}
|
||||
|
||||
// 筛选条件
|
||||
for _, format := range argFormat {
|
||||
if p.Args[format] != nil {
|
||||
fmt.Println(format, p.Args[format])
|
||||
query = query.Where(goqu.Ex{fmt.Sprintf("web_images.%s", format): p.Args[format]})
|
||||
}
|
||||
}
|
||||
|
||||
// 筛选:提取文字
|
||||
if p.Args["text"] != nil {
|
||||
resp, err := models.ZincSearch(map[string]interface{}{
|
||||
"query": map[string]interface{}{
|
||||
"bool": map[string]interface{}{
|
||||
"must": []map[string]interface{}{
|
||||
{
|
||||
"match_phrase": map[string]string{"text": args.Text},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"_source": false,
|
||||
"sort": []string{"_score"},
|
||||
"size": 200000,
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println("ZincSearch 获取图像列表失败", err)
|
||||
return nil, err
|
||||
}
|
||||
var item []int
|
||||
for _, hit := range resp.Hits.Hits {
|
||||
num, _ := strconv.Atoi(hit.ID)
|
||||
item = append(item, num)
|
||||
}
|
||||
if len(item) == 0 {
|
||||
return map[string]interface{}{"list": []Image{}, "total": 0}, nil
|
||||
}
|
||||
query = query.Where(goqu.Ex{"web_images.id": goqu.Op{"in": item}})
|
||||
total = len(item)
|
||||
}
|
||||
|
||||
// 筛选:相似图像
|
||||
if p.Args["similar"] != nil {
|
||||
var item []int
|
||||
for _, id := range models.GetSimilarImagesIdList(p.Args["similar"].(int), 200) {
|
||||
item = append(item, int(id))
|
||||
}
|
||||
|
||||
if len(item) == 0 {
|
||||
return map[string]interface{}{"list": []Image{}, "total": 0}, nil
|
||||
}
|
||||
|
||||
query = query.Where(goqu.Ex{"web_images.id": goqu.Op{"in": item}}).Select("web_images.id", goqu.L(
|
||||
fmt.Sprintf("ROW_NUMBER() OVER(ORDER BY FIELD(%s, %s))", "web_images.id", regexp.MustCompile(`[\[\]]`).ReplaceAllString(strings.Join(strings.Fields(fmt.Sprint(item)), ", "), "")),
|
||||
).As("row_num"))
|
||||
total = len(item)
|
||||
|
||||
// 收集阅读行为
|
||||
if p.Context.Value("user_id") != nil && p.Args["after"] == nil {
|
||||
ctx := context.Background()
|
||||
user_id := p.Context.Value("user_id").(int)
|
||||
|
||||
feedbacks := []client.Feedback{{
|
||||
FeedbackType: "read",
|
||||
UserId: fmt.Sprintf("%s", user_id),
|
||||
ItemId: fmt.Sprintf("%s", p.Args["Similar"]),
|
||||
Timestamp: time.Now().Format("2006-01-02 15:04:05"),
|
||||
}}
|
||||
|
||||
if _, err := gorse.InsertFeedback(ctx, feedbacks); err != nil {
|
||||
fmt.Println("写入阅读记录失败", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 筛选:兴趣推荐
|
||||
if p.Args["interest"] != nil {
|
||||
fmt.Println("interest:", p.Args["interest"])
|
||||
user_id := p.Args["interest"].(int)
|
||||
fmt.Println("interest1:", user_id)
|
||||
list, err := GetRecommend(user_id, []string{})
|
||||
fmt.Println("interest2:", list, err)
|
||||
if err != nil {
|
||||
fmt.Println("GetRecommend 获取兴趣推荐失败", err)
|
||||
return map[string]interface{}{"list": []Image{}, "total": 0}, nil
|
||||
}
|
||||
if len(list) == 0 {
|
||||
return map[string]interface{}{"list": []Image{}, "total": 0}, nil
|
||||
}
|
||||
fmt.Println("Interest:", user_id, list)
|
||||
query = query.Where(goqu.Ex{"web_images.id": goqu.Op{"in": list}}).Select("web_images.id", goqu.L(
|
||||
fmt.Sprintf("ROW_NUMBER() OVER(ORDER BY FIELD(%s, %s))", "web_images.id", regexp.MustCompile(`[\[\]]`).ReplaceAllString(strings.Join(strings.Fields(fmt.Sprint(list)), ", "), "")),
|
||||
).As("row_num"))
|
||||
total = len(list)
|
||||
}
|
||||
|
||||
// 筛选:时间段
|
||||
applyTimeCondition := func(name string, str string) {
|
||||
parts := strings.Split(str, "-")
|
||||
query = query.Where(goqu.Ex{fmt.Sprintf("YEAR(%s)", name): parts[0]})
|
||||
|
||||
if len(parts) > 1 {
|
||||
query = query.Where(goqu.Ex{fmt.Sprintf("MONTH(%s)", name): parts[1]})
|
||||
}
|
||||
if len(parts) > 2 {
|
||||
query = query.Where(goqu.Ex{fmt.Sprintf("DAY(%s)", name): parts[2]})
|
||||
}
|
||||
}
|
||||
|
||||
// 数据库中筛选:创建时间段
|
||||
if p.Args["create_time"] != nil {
|
||||
applyTimeCondition("create_time", p.Args["create_time"].(string))
|
||||
}
|
||||
|
||||
// 数据库中筛选:更新时间段
|
||||
if p.Args["update_time"] != nil {
|
||||
applyTimeCondition("update_time", p.Args["update_time"].(string))
|
||||
}
|
||||
|
||||
// 数据库中筛选:按是否活动
|
||||
if activity, ok := p.Args["activity"].(bool); ok {
|
||||
query = query.Where(goqu.Ex{"web_images.activity": map[bool]string{true: "1", false: "0"}[activity]})
|
||||
}
|
||||
|
||||
// 数据库中筛选:按游戏标签
|
||||
if p.Args["tags"] != nil {
|
||||
tags := strings.Split(strings.ReplaceAll(p.Args["tags"].(string), " ", ""), ",")
|
||||
for _, tag := range tags {
|
||||
query = query.Where(goqu.L("MATCH(web_images.tags) AGAINST (? IN NATURAL LANGUAGE MODE)", tag))
|
||||
}
|
||||
}
|
||||
|
||||
// 数据库中筛选:按游戏分类
|
||||
if p.Args["images_desc"] != nil {
|
||||
tags := strings.Split(strings.ReplaceAll(p.Args["images_desc"].(string), " ", ""), ",")
|
||||
for _, tag := range tags {
|
||||
query = query.Where(goqu.L("MATCH(web_images.images_desc) AGAINST (? IN NATURAL LANGUAGE MODE)", tag))
|
||||
}
|
||||
}
|
||||
|
||||
// 数据库中筛选:喜欢的截图
|
||||
if p.Args["praise"] != nil {
|
||||
query = query.Join(goqu.T("web_praise"), goqu.On(
|
||||
goqu.I("web_images.id").Eq(goqu.I("web_praise.praise_id")),
|
||||
goqu.I("web_praise.user_id").Eq(p.Args["praise"]),
|
||||
goqu.I("web_praise.type").Eq(4),
|
||||
))
|
||||
}
|
||||
|
||||
var collect_params []goqu.Expression = []goqu.Expression{
|
||||
goqu.I("web_images.id").Eq(goqu.I("web_collect.image_id")),
|
||||
}
|
||||
|
||||
// 数据库中筛选:用户收藏的截图
|
||||
if p.Args["collect"] != nil {
|
||||
collect_params = append(collect_params, goqu.I("web_collect.user_id").Eq(p.Args["collect"]))
|
||||
}
|
||||
|
||||
// 数据库中筛选:收藏夹中的截图
|
||||
if p.Args["collect_id"] != nil {
|
||||
collect_params = append(collect_params, goqu.I("web_collect.collect_id").Eq(p.Args["collect_id"]))
|
||||
}
|
||||
|
||||
// 数据库中筛选:收藏夹中的截图
|
||||
if p.Args["explorer_id"] != nil {
|
||||
collect_params = append(collect_params, goqu.I("web_collect.explorer_id").Eq(p.Args["explorer_id"]))
|
||||
}
|
||||
|
||||
if len(collect_params) > 1 {
|
||||
query = query.Join(goqu.T("web_collect"), goqu.On(collect_params...))
|
||||
}
|
||||
|
||||
var conditions []goqu.Expression = []goqu.Expression{
|
||||
goqu.I("web_images.article_id").Eq(goqu.I("web_article.id")),
|
||||
}
|
||||
|
||||
// 按游戏风格筛选图像
|
||||
if p.Args["style"] != nil {
|
||||
conditions = append(conditions, goqu.I("web_article.style").Eq(p.Args["style"]))
|
||||
}
|
||||
|
||||
// 按游戏平台筛选图像
|
||||
if p.Args["device"] != nil {
|
||||
conditions = append(conditions, goqu.I("web_article.device").Eq(p.Args["device"]))
|
||||
}
|
||||
|
||||
// 按游戏版式筛选图像
|
||||
if p.Args["orientation"] != nil {
|
||||
conditions = append(conditions, goqu.I("web_article.orientation").Eq(p.Args["orientation"]))
|
||||
}
|
||||
|
||||
// 按游戏年份筛选图像
|
||||
if p.Args["era"] != nil {
|
||||
conditions = append(conditions, goqu.I("web_article.era").Eq(p.Args["era"]))
|
||||
}
|
||||
|
||||
// 按游戏类型筛选图像(逗号分割且去除空格)
|
||||
if p.Args["category_id"] != nil {
|
||||
category_ids := strings.Split(strings.ReplaceAll(p.Args["category_id"].(string), " ", ""), ",")
|
||||
conditions = append(conditions, goqu.I("web_article.category_id").In(category_ids))
|
||||
}
|
||||
|
||||
// 按游戏标签筛选图像
|
||||
if p.Args["article_tags"] != nil {
|
||||
tags := strings.Split(strings.ReplaceAll(p.Args["article_tags"].(string), " ", ""), ", ")
|
||||
for _, tag := range tags {
|
||||
conditions = append(conditions, goqu.L("MATCH(web_article.tags) AGAINST (? IN NATURAL LANGUAGE MODE)", tag))
|
||||
}
|
||||
}
|
||||
|
||||
if len(conditions) > 1 {
|
||||
query = query.Join(goqu.T("web_article"), goqu.On(conditions...))
|
||||
}
|
||||
|
||||
// 数据库中筛选:按关注列表
|
||||
if p.Args["follower"] != nil {
|
||||
query = query.Join(goqu.T("web_fans"), goqu.On(
|
||||
goqu.I("web_images.user_id").Eq(goqu.I("web_fans.blogger_id")),
|
||||
goqu.I("web_fans.follower_id").Eq(p.Args["follower"]),
|
||||
))
|
||||
}
|
||||
|
||||
// 数据库中筛选: 按图像主色调颜色筛选
|
||||
if p.Args["color"] != nil {
|
||||
// hexToRGB 将十六进制颜色转换为 RGB
|
||||
hexToRGB := func(hex string) (int, int, int, error) {
|
||||
// 去掉 # 号
|
||||
if strings.HasPrefix(hex, "#") {
|
||||
hex = hex[1:]
|
||||
}
|
||||
// 检查是否是有效的十六进制颜色
|
||||
if len(hex) != 6 {
|
||||
return 0, 0, 0, fmt.Errorf("invalid hex color")
|
||||
}
|
||||
// 解析红色、绿色、蓝色通道的十六进制值
|
||||
r, err := strconv.ParseInt(hex[:2], 16, 0)
|
||||
if err != nil {
|
||||
return 0, 0, 0, err
|
||||
}
|
||||
g, err := strconv.ParseInt(hex[2:4], 16, 0)
|
||||
if err != nil {
|
||||
return 0, 0, 0, err
|
||||
}
|
||||
b, err := strconv.ParseInt(hex[4:], 16, 0)
|
||||
if err != nil {
|
||||
return 0, 0, 0, err
|
||||
}
|
||||
return int(r), int(g), int(b), nil
|
||||
}
|
||||
// 逗号分割且去除空格
|
||||
colors := strings.Split(strings.ReplaceAll(p.Args["color"].(string), " ", ""), ",")
|
||||
for index, color := range colors {
|
||||
|
||||
var precision int = 10
|
||||
if strings.Contains(color, ":") {
|
||||
re := regexp.MustCompile(`^#([0-9a-fA-F]{6}):(\d+)$`)
|
||||
matches := re.FindStringSubmatch(color)
|
||||
num, err := strconv.Atoi(matches[2])
|
||||
if err != nil {
|
||||
fmt.Println("数字精度转换失败:", err)
|
||||
return nil, err
|
||||
}
|
||||
color = "#" + matches[1]
|
||||
precision = num
|
||||
}
|
||||
|
||||
r, g, b, err := hexToRGB(color)
|
||||
if err != nil {
|
||||
fmt.Println("hexToRGB", index, err)
|
||||
return nil, err
|
||||
}
|
||||
fmt.Println(color, r, g, b, precision)
|
||||
query = query.Where(goqu.Or(
|
||||
goqu.And(
|
||||
goqu.L(fmt.Sprintf("web_images.color_%d_r", 0)).Gt(r-precision),
|
||||
goqu.L(fmt.Sprintf("web_images.color_%d_r", 0)).Lt(r+precision),
|
||||
goqu.L(fmt.Sprintf("web_images.color_%d_g", 0)).Gt(g-precision),
|
||||
goqu.L(fmt.Sprintf("web_images.color_%d_g", 0)).Lt(g+precision),
|
||||
goqu.L(fmt.Sprintf("web_images.color_%d_b", 0)).Gt(b-precision),
|
||||
goqu.L(fmt.Sprintf("web_images.color_%d_b", 0)).Lt(b+precision),
|
||||
),
|
||||
goqu.And(
|
||||
goqu.L(fmt.Sprintf("web_images.color_%d_r", 1)).Gt(r-precision),
|
||||
goqu.L(fmt.Sprintf("web_images.color_%d_r", 1)).Lt(r+precision),
|
||||
goqu.L(fmt.Sprintf("web_images.color_%d_g", 1)).Gt(g-precision),
|
||||
goqu.L(fmt.Sprintf("web_images.color_%d_g", 1)).Lt(g+precision),
|
||||
goqu.L(fmt.Sprintf("web_images.color_%d_b", 1)).Gt(b-precision),
|
||||
goqu.L(fmt.Sprintf("web_images.color_%d_b", 1)).Lt(b+precision),
|
||||
),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有外部排序则使用指定排序(正则sort只能是字母数字下划线)
|
||||
if p.Args["similar"] == nil && p.Args["interest"] == nil && p.Args["praise"] == nil {
|
||||
// 如果查询了 total 字段
|
||||
if existField(p.Info.FieldASTs[0].SelectionSet.Selections, "total") {
|
||||
sql, _, _ := query.ToSQL()
|
||||
sql = strings.Replace(sql, "SELECT *", "SELECT COUNT(*)", 1)
|
||||
if err := db.Raw(sql).Scan(&total).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
query = query.Select("web_images.id", goqu.L(fmt.Sprintf(
|
||||
"ROW_NUMBER() OVER(ORDER BY web_images.%s %s)",
|
||||
regexp.MustCompile(`[^a-zA-Z0-9_]`).ReplaceAllString(p.Args["sort"].(string), ""),
|
||||
p.Args["order"].(string),
|
||||
)).As("row_num"))
|
||||
}
|
||||
|
||||
// 图像按点赞顺序排序 p.Args["sort"].(string) == "praise_time"
|
||||
if p.Args["praise"] != nil {
|
||||
query = query.Select("web_images.id", goqu.L(
|
||||
fmt.Sprintf("ROW_NUMBER() OVER(ORDER BY web_praise.%s %s)", "id", p.Args["order"].(string)),
|
||||
).As("row_num"))
|
||||
}
|
||||
|
||||
// 取所有数据的前N条
|
||||
sql, _, _ := query.Where(goqu.Ex{"article_category_top_id": 22}).ToSQL()
|
||||
|
||||
// 遊標截取篩選結果集的前N条
|
||||
var cursor string
|
||||
if p.Args["after"] != nil {
|
||||
cursor = fmt.Sprintf(`WHERE row_num > (SELECT row_num FROM RankedArticles WHERE RankedArticles.id = %d)`, p.Args["after"].(int))
|
||||
}
|
||||
|
||||
var limit int = 10
|
||||
if args.First != 0 {
|
||||
limit = args.First
|
||||
} else if args.Last != 0 {
|
||||
limit = args.Last
|
||||
}
|
||||
|
||||
sql = fmt.Sprintf(`
|
||||
WITH RankedArticles AS (%s)
|
||||
SELECT web_images.* FROM web_images INNER JOIN(
|
||||
SELECT id, row_num FROM RankedArticles %s
|
||||
) AS LimitedRanked ON LimitedRanked.id = web_images.id
|
||||
ORDER BY LimitedRanked.row_num ASC LIMIT %d
|
||||
`, sql, cursor, limit)
|
||||
fmt.Println(sql)
|
||||
|
||||
if err := db.Raw(sql).Scan(&images).Error; err != nil {
|
||||
fmt.Println("获取图像列表失败", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var ids []int
|
||||
for _, item := range images {
|
||||
ids = append(ids, item.ID)
|
||||
}
|
||||
|
||||
var find = db.Where("web_images.id IN ?", ids).Select("*", "CASE WHEN activity = '1' THEN TRUE ELSE FALSE END")
|
||||
for _, item := range LoadItem(p.Info.FieldASTs[0].SelectionSet.Selections) {
|
||||
find = find.Preload(item)
|
||||
}
|
||||
|
||||
if len(ids) == 0 {
|
||||
return map[string]interface{}{"list": []Image{}, "total": 0}, nil
|
||||
}
|
||||
|
||||
orderClause := fmt.Sprintf("FIELD(id, %s)", regexp.MustCompile(`[\[\]]`).ReplaceAllString(strings.Join(strings.Fields(fmt.Sprint(ids)), ","), ""))
|
||||
if err := find.Order(orderClause).Find(&images).Error; err != nil {
|
||||
fmt.Println("获取图像列表失败", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"list": images,
|
||||
"total": total,
|
||||
}, nil
|
||||
},
|
||||
}
|
Reference in New Issue
Block a user