API分页
This commit is contained in:
		
							
								
								
									
										158
									
								
								api/article.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								api/article.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,158 @@
 | 
				
			|||||||
 | 
					package api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"log"
 | 
				
			||||||
 | 
						"regexp"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/doug-martin/goqu/v9"
 | 
				
			||||||
 | 
						"github.com/graphql-go/graphql"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Article struct {
 | 
				
			||||||
 | 
						ID          int       `json:"id"          db:"id" gorm:"primaryKey"`
 | 
				
			||||||
 | 
						Title       string    `json:"title"       db:"title"`
 | 
				
			||||||
 | 
						Orientation string    `json:"orientation" db:"orientation"`
 | 
				
			||||||
 | 
						Device      string    `json:"device"      db:"device"`
 | 
				
			||||||
 | 
						Era         string    `json:"era"         db:"era"`
 | 
				
			||||||
 | 
						Tags        string    `json:"tags"        db:"tags"`
 | 
				
			||||||
 | 
						UserId      int       `json:"user_id"     db:"user_id"`
 | 
				
			||||||
 | 
						User        User      `json:"user"        gorm:"foreignKey:UserId"`
 | 
				
			||||||
 | 
						CreateTime  time.Time `json:"create_time" db:"create_time"`
 | 
				
			||||||
 | 
						UpdateTime  time.Time `json:"update_time" db:"update_time"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (Article) TableName() string {
 | 
				
			||||||
 | 
						return "web_article"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var articleType = graphql.NewObject(graphql.ObjectConfig{
 | 
				
			||||||
 | 
						Name:        "Article",
 | 
				
			||||||
 | 
						Description: "文章",
 | 
				
			||||||
 | 
						Fields: graphql.Fields{
 | 
				
			||||||
 | 
							"id":          &graphql.Field{Type: graphql.Int, Description: "ID"},
 | 
				
			||||||
 | 
							"title":       &graphql.Field{Type: graphql.String, Description: "标题"},
 | 
				
			||||||
 | 
							"orientation": &graphql.Field{Type: graphql.String, Description: "方向"},
 | 
				
			||||||
 | 
							"device":      &graphql.Field{Type: graphql.String, Description: "设备"},
 | 
				
			||||||
 | 
							"era":         &graphql.Field{Type: graphql.String, Description: "游戏上线年份"},
 | 
				
			||||||
 | 
							"tags":        &graphql.Field{Type: graphql.String, Description: "标签"},
 | 
				
			||||||
 | 
							"user":        &graphql.Field{Type: userType, Description: "所属用户"},
 | 
				
			||||||
 | 
							"create_time": &graphql.Field{Type: graphql.DateTime, Description: "创建时间"},
 | 
				
			||||||
 | 
							"update_time": &graphql.Field{Type: graphql.DateTime, Description: "更新时间"},
 | 
				
			||||||
 | 
							"text_count": &graphql.Field{Type: graphql.Int, Description: "文字数量", Resolve: func(p graphql.ResolveParams) (interface{}, error) {
 | 
				
			||||||
 | 
								var count int64
 | 
				
			||||||
 | 
								err := db.Table("web_images").Where("article_id = ?", p.Source.(Article).ID).Where("text != ''").Count(&count).Error
 | 
				
			||||||
 | 
								return int(count), err
 | 
				
			||||||
 | 
							}},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var ArticleItem = &graphql.Field{
 | 
				
			||||||
 | 
						Name:        "article",
 | 
				
			||||||
 | 
						Description: "单篇文章",
 | 
				
			||||||
 | 
						Type:        articleType,
 | 
				
			||||||
 | 
						Args: graphql.FieldConfigArgument{
 | 
				
			||||||
 | 
							"id": &graphql.ArgumentConfig{Type: graphql.Int, Description: "根据ID获取文章"},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						Resolve: func(p graphql.ResolveParams) (interface{}, error) {
 | 
				
			||||||
 | 
							article := Article{ID: p.Args["id"].(int)}
 | 
				
			||||||
 | 
							if err := db.First(&article).Error; err != nil {
 | 
				
			||||||
 | 
								log.Println("获取文章失败", err)
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return article, nil
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var ArticleItems = &graphql.Field{
 | 
				
			||||||
 | 
						Name:        "articles",
 | 
				
			||||||
 | 
						Description: "文章列表",
 | 
				
			||||||
 | 
						Type: graphql.NewObject(graphql.ObjectConfig{
 | 
				
			||||||
 | 
							Name:        "ArticleConnection",
 | 
				
			||||||
 | 
							Description: "条件筛选文章列表",
 | 
				
			||||||
 | 
							Fields: graphql.Fields{
 | 
				
			||||||
 | 
								"list":  &graphql.Field{Type: graphql.NewList(articleType), Description: "文章列表"},
 | 
				
			||||||
 | 
								"total": &graphql.Field{Type: graphql.Int, Description: "文章总数"},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}),
 | 
				
			||||||
 | 
						Args: graphql.FieldConfigArgument{
 | 
				
			||||||
 | 
							"id":          &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选文章中指定ID的"},
 | 
				
			||||||
 | 
							"title":       &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选文章中含有指定标题的"},
 | 
				
			||||||
 | 
							"tags":        &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选文章中含有指定标签的"},
 | 
				
			||||||
 | 
							"create_time": &graphql.ArgumentConfig{Type: graphql.DateTime, Description: "筛选文章中创建时间等于指定值的"},
 | 
				
			||||||
 | 
							"update_time": &graphql.ArgumentConfig{Type: graphql.DateTime, Description: "筛选文章中更新时间等于指定值的"},
 | 
				
			||||||
 | 
							"sort":        &graphql.ArgumentConfig{Type: graphql.String, Description: "按指定字段排序游戏", DefaultValue: "id"},
 | 
				
			||||||
 | 
							"order":       &graphql.ArgumentConfig{Type: orderType, Description: "排序类型(升序或降序)", DefaultValue: "ASC"},
 | 
				
			||||||
 | 
							"first":       &graphql.ArgumentConfig{Type: graphql.Int, Description: "翻页参数(傳回清單中的前n個元素)"},
 | 
				
			||||||
 | 
							"last":        &graphql.ArgumentConfig{Type: graphql.Int, Description: "翻页参数(傳回清單中的最後n個元素)"},
 | 
				
			||||||
 | 
							"after":       &graphql.ArgumentConfig{Type: graphql.String, Description: "翻页参数(傳回清單中指定遊標之後的元素)"},
 | 
				
			||||||
 | 
							"before":      &graphql.ArgumentConfig{Type: graphql.String, Description: "翻页参数(傳回清單中指定遊標之前的元素)"},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						Resolve: func(p graphql.ResolveParams) (interface{}, error) {
 | 
				
			||||||
 | 
							var articles []Article
 | 
				
			||||||
 | 
							var total int
 | 
				
			||||||
 | 
							var err error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var query = goqu.Dialect("mysql").From("web_article")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 筛选条件
 | 
				
			||||||
 | 
							for _, format := range []string{"id", "style", "device", "orientation", "era", "category_id", "tags"} {
 | 
				
			||||||
 | 
								if p.Args[format] != nil {
 | 
				
			||||||
 | 
									query = query.Where(goqu.C(format).Eq(p.Args[format]))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 排序条件
 | 
				
			||||||
 | 
							if p.Args["sort"] != nil {
 | 
				
			||||||
 | 
								if p.Args["order"].(string) == "ASC" {
 | 
				
			||||||
 | 
									query = query.Order(goqu.C(p.Args["sort"].(string)).Asc())
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if p.Args["order"].(string) == "DESC" {
 | 
				
			||||||
 | 
									query = query.Order(goqu.C(p.Args["sort"].(string)).Desc())
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 如果没有外部排序则使用指定排序(正则sort只能是字母数字下划下)
 | 
				
			||||||
 | 
							if p.Args["text"] == nil && p.Args["similar"] == nil && p.Args["interest"] == nil {
 | 
				
			||||||
 | 
								sort := regexp.MustCompile(`[^a-zA-Z0-9_]`).ReplaceAllString(p.Args["sort"].(string), "")
 | 
				
			||||||
 | 
								query = query.Select("web_images.id", goqu.L(
 | 
				
			||||||
 | 
									fmt.Sprintf("ROW_NUMBER() OVER(ORDER BY web_images.%s %s)", sort, p.Args["order"]),
 | 
				
			||||||
 | 
								).As("row_num"))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 取所有数据的前N条
 | 
				
			||||||
 | 
							sql, _, _ := query.Where(goqu.Ex{"article_category_top_id": 9}).ToSQL()
 | 
				
			||||||
 | 
							fmt.Println(sql)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 遊標截取篩選結果集的前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 p.Args["first"] != nil {
 | 
				
			||||||
 | 
								limit = p.Args["first"].(int)
 | 
				
			||||||
 | 
							} else if p.Args["last"] != nil {
 | 
				
			||||||
 | 
								limit = p.Args["last"].(int)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							sql = fmt.Sprintf(`
 | 
				
			||||||
 | 
							WITH RankedArticles AS (%s)
 | 
				
			||||||
 | 
							SELECT * 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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err := db.Limit(limit).Where("category_top_id = 9").Find(&articles).Error; err != nil {
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return map[string]interface{}{
 | 
				
			||||||
 | 
								"list":  articles,
 | 
				
			||||||
 | 
								"total": total,
 | 
				
			||||||
 | 
							}, err
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										65
									
								
								api/collect.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								api/collect.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
				
			|||||||
 | 
					package api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/graphql-go/graphql"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Collect struct {
 | 
				
			||||||
 | 
						ID         int       `json:"id" gorm:"primaryKey"`
 | 
				
			||||||
 | 
						UserId     int       `json:"user_id"`
 | 
				
			||||||
 | 
						ArticleId  int       `json:"article_id"`
 | 
				
			||||||
 | 
						CreateTime time.Time `json:"create_time"`
 | 
				
			||||||
 | 
						UpdateTime time.Time `json:"update_time"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (Collect) TableName() string {
 | 
				
			||||||
 | 
						return "web_collect"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var CollectItems = &graphql.Field{
 | 
				
			||||||
 | 
						Name:        "collects",
 | 
				
			||||||
 | 
						Description: "收藏列表",
 | 
				
			||||||
 | 
						Type: graphql.NewObject(graphql.ObjectConfig{
 | 
				
			||||||
 | 
							Name:        "CollectConnection",
 | 
				
			||||||
 | 
							Description: "条件筛选收藏列表",
 | 
				
			||||||
 | 
							Fields: graphql.Fields{
 | 
				
			||||||
 | 
								"list": &graphql.Field{Type: graphql.NewList(graphql.NewObject(graphql.ObjectConfig{
 | 
				
			||||||
 | 
									Name:        "Collect",
 | 
				
			||||||
 | 
									Description: "收藏",
 | 
				
			||||||
 | 
									Fields: graphql.Fields{
 | 
				
			||||||
 | 
										"id":            &graphql.Field{Type: graphql.Int, Description: "收藏ID"},
 | 
				
			||||||
 | 
										"title":         &graphql.Field{Type: graphql.String, Description: "收藏标题"},
 | 
				
			||||||
 | 
										"type":          &graphql.Field{Type: graphql.Int, Description: "收藏类型"},
 | 
				
			||||||
 | 
										"create_time":   &graphql.Field{Type: graphql.DateTime, Description: "收藏创建时间"},
 | 
				
			||||||
 | 
										"update_time":   &graphql.Field{Type: graphql.DateTime, Description: "收藏更新时间"},
 | 
				
			||||||
 | 
										"praise_count":  &graphql.Field{Type: graphql.Int, Description: "点赞数"},
 | 
				
			||||||
 | 
										"collect_count": &graphql.Field{Type: graphql.Int, Description: "收藏数"},
 | 
				
			||||||
 | 
										"praise":        &graphql.Field{Type: graphql.Boolean, Description: "当前用户是否点赞"},
 | 
				
			||||||
 | 
										"collect":       &graphql.Field{Type: graphql.Boolean, Description: "当前用户是否收藏"},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								})), Description: "收藏列表"},
 | 
				
			||||||
 | 
								"total": &graphql.Field{Type: graphql.Int, Description: "收藏总数"},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}),
 | 
				
			||||||
 | 
						Args: graphql.FieldConfigArgument{
 | 
				
			||||||
 | 
							"id":          &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选收藏中指定ID的"},
 | 
				
			||||||
 | 
							"title":       &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选收藏中含有指定标题的"},
 | 
				
			||||||
 | 
							"type":        &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选收藏中含有指定类型的"},
 | 
				
			||||||
 | 
							"create_time": &graphql.ArgumentConfig{Type: graphql.DateTime, Description: "筛选收藏中创建时间等于指定值的"},
 | 
				
			||||||
 | 
							"update_time": &graphql.ArgumentConfig{Type: graphql.DateTime, Description: "筛选收藏中更新时间等于指定值的"},
 | 
				
			||||||
 | 
							"first":       &graphql.ArgumentConfig{Type: graphql.Int, Description: "翻页参数(傳回清單中的前n個元素)"},
 | 
				
			||||||
 | 
							"last":        &graphql.ArgumentConfig{Type: graphql.Int, Description: "翻页参数(傳回清單中的最後n個元素)"},
 | 
				
			||||||
 | 
							"after":       &graphql.ArgumentConfig{Type: graphql.String, Description: "翻页参数(傳回清單中指定遊標之後的元素)"},
 | 
				
			||||||
 | 
							"before":      &graphql.ArgumentConfig{Type: graphql.String, Description: "翻页参数(傳回清單中指定遊標之前的元素)"},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						Resolve: func(p graphql.ResolveParams) (interface{}, error) {
 | 
				
			||||||
 | 
							var collects []Collect
 | 
				
			||||||
 | 
							var total int
 | 
				
			||||||
 | 
							return map[string]interface{}{
 | 
				
			||||||
 | 
								"list":  collects,
 | 
				
			||||||
 | 
								"total": total,
 | 
				
			||||||
 | 
							}, nil
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										156
									
								
								api/game.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										156
									
								
								api/game.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,156 @@
 | 
				
			|||||||
 | 
					package api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"regexp"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/doug-martin/goqu/v9"
 | 
				
			||||||
 | 
						"github.com/graphql-go/graphql"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Game struct {
 | 
				
			||||||
 | 
						ID          int       `json:"id" gorm:"primaryKey"`
 | 
				
			||||||
 | 
						Title       string    `json:"title"`
 | 
				
			||||||
 | 
						Orientation string    `json:"orientation"`
 | 
				
			||||||
 | 
						Device      string    `json:"device"`
 | 
				
			||||||
 | 
						Era         string    `json:"era"`
 | 
				
			||||||
 | 
						Tags        string    `json:"tags"`
 | 
				
			||||||
 | 
						UserId      int       `json:"user_id"`
 | 
				
			||||||
 | 
						Content     string    `json:"content"`
 | 
				
			||||||
 | 
						Image       string    `json:"image"`
 | 
				
			||||||
 | 
						Images      string    `json:"images"`
 | 
				
			||||||
 | 
						User        User      `json:"user" gorm:"foreignKey:UserId"`
 | 
				
			||||||
 | 
						CreateTime  time.Time `json:"create_time"`
 | 
				
			||||||
 | 
						UpdateTime  time.Time `json:"update_time"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (Game) TableName() string {
 | 
				
			||||||
 | 
						return "web_article"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var gameType = graphql.NewObject(graphql.ObjectConfig{
 | 
				
			||||||
 | 
						Name:        "Game",
 | 
				
			||||||
 | 
						Description: "游戏",
 | 
				
			||||||
 | 
						Fields: graphql.Fields{
 | 
				
			||||||
 | 
							"id":            &graphql.Field{Type: graphql.Int, Description: "游戏ID"},
 | 
				
			||||||
 | 
							"title":         &graphql.Field{Type: graphql.String, Description: "游戏标题"},
 | 
				
			||||||
 | 
							"era":           &graphql.Field{Type: graphql.String, Description: "游戏上线年份"},
 | 
				
			||||||
 | 
							"create_time":   &graphql.Field{Type: graphql.DateTime, Description: "游戏创建时间"},
 | 
				
			||||||
 | 
							"update_time":   &graphql.Field{Type: graphql.DateTime, Description: "游戏更新时间"},
 | 
				
			||||||
 | 
							"praise_count":  &graphql.Field{Type: graphql.Int, Description: "点赞数"},
 | 
				
			||||||
 | 
							"collect_count": &graphql.Field{Type: graphql.Int, Description: "收藏数"},
 | 
				
			||||||
 | 
							"praise":        &graphql.Field{Type: graphql.Boolean, Description: "当前用户是否点赞"},
 | 
				
			||||||
 | 
							"collect":       &graphql.Field{Type: graphql.Boolean, Description: "当前用户是否收藏"},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var GameItems = &graphql.Field{
 | 
				
			||||||
 | 
						Name:        "games",
 | 
				
			||||||
 | 
						Description: "游戏列表",
 | 
				
			||||||
 | 
						Type: graphql.NewObject(graphql.ObjectConfig{
 | 
				
			||||||
 | 
							Name:        "GameConnection",
 | 
				
			||||||
 | 
							Description: "条件筛选游戏列表",
 | 
				
			||||||
 | 
							Fields: graphql.Fields{
 | 
				
			||||||
 | 
								"list":  &graphql.Field{Type: graphql.NewList(gameType), Description: "游戏列表"},
 | 
				
			||||||
 | 
								"total": &graphql.Field{Type: graphql.Int, Description: "游戏总数"},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}),
 | 
				
			||||||
 | 
						Args: graphql.FieldConfigArgument{
 | 
				
			||||||
 | 
							"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.Int, Description: "按分类ID筛选游戏"},
 | 
				
			||||||
 | 
							"tags":        &graphql.ArgumentConfig{Type: graphql.String, Description: "按标签筛选游戏"},
 | 
				
			||||||
 | 
							"user_id":     &graphql.ArgumentConfig{Type: graphql.Int, Description: "按用户ID筛选游戏"},
 | 
				
			||||||
 | 
							"id":          &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选游戏中指定ID的"},
 | 
				
			||||||
 | 
							"title":       &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选游戏中含有指定标题的"},
 | 
				
			||||||
 | 
							"rank":        &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选游戏中含有指定排名的"},
 | 
				
			||||||
 | 
							"create_time": &graphql.ArgumentConfig{Type: graphql.DateTime, Description: "按创建时间筛选游戏"},
 | 
				
			||||||
 | 
							"update_time": &graphql.ArgumentConfig{Type: graphql.DateTime, Description: "按修改时间筛选游戏"},
 | 
				
			||||||
 | 
							"sort":        &graphql.ArgumentConfig{Type: graphql.String, Description: "按指定字段排序游戏", DefaultValue: "id"},
 | 
				
			||||||
 | 
							"order":       &graphql.ArgumentConfig{Type: orderType, Description: "排序类型(升序或降序)", DefaultValue: "ASC"},
 | 
				
			||||||
 | 
							"first":       &graphql.ArgumentConfig{Type: graphql.Int, Description: "翻页参数(傳回清單中的前n個元素)"},
 | 
				
			||||||
 | 
							"last":        &graphql.ArgumentConfig{Type: graphql.Int, Description: "翻页参数(傳回清單中的最後n個元素)"},
 | 
				
			||||||
 | 
							"after":       &graphql.ArgumentConfig{Type: graphql.String, Description: "翻页参数(傳回清單中指定遊標之後的元素)"},
 | 
				
			||||||
 | 
							"before":      &graphql.ArgumentConfig{Type: graphql.String, Description: "翻页参数(傳回清單中指定遊標之前的元素)"},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						Resolve: func(p graphql.ResolveParams) (interface{}, error) {
 | 
				
			||||||
 | 
							var games []Game
 | 
				
			||||||
 | 
							var total int
 | 
				
			||||||
 | 
							var err error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var query = goqu.Dialect("mysql").From("web_article").Where(goqu.Ex{"category_top_id": 22})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 筛选条件
 | 
				
			||||||
 | 
							for _, format := range []string{"id", "title", "style", "device", "orientation", "era", "category_id", "tags"} {
 | 
				
			||||||
 | 
								if p.Args[format] != nil {
 | 
				
			||||||
 | 
									query = query.Where(goqu.C(format).Eq(p.Args[format]))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 如果查询了 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
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 如果没有外部排序则使用指定排序(正则sort只能是字母数字下划下)
 | 
				
			||||||
 | 
							if p.Args["text"] == nil && p.Args["similar"] == nil && p.Args["interest"] == nil {
 | 
				
			||||||
 | 
								sort := regexp.MustCompile(`[^a-zA-Z0-9_]`).ReplaceAllString(p.Args["sort"].(string), "")
 | 
				
			||||||
 | 
								query = query.Select("web_article.id", goqu.L(
 | 
				
			||||||
 | 
									fmt.Sprintf("ROW_NUMBER() OVER(ORDER BY web_article.%s %s)", sort, p.Args["order"]),
 | 
				
			||||||
 | 
								).As("row_num"))
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								// 排序条件
 | 
				
			||||||
 | 
								if p.Args["sort"] != nil {
 | 
				
			||||||
 | 
									if p.Args["order"].(string) == "ASC" {
 | 
				
			||||||
 | 
										query = query.Order(goqu.C(p.Args["sort"].(string)).Asc())
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									if p.Args["order"].(string) == "DESC" {
 | 
				
			||||||
 | 
										query = query.Order(goqu.C(p.Args["sort"].(string)).Desc())
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 取所有数据的前N条
 | 
				
			||||||
 | 
							sql, _, _ := query.ToSQL()
 | 
				
			||||||
 | 
							fmt.Println(sql)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 遊標截取篩選結果集的前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 p.Args["first"] != nil {
 | 
				
			||||||
 | 
								limit = p.Args["first"].(int)
 | 
				
			||||||
 | 
							} else if p.Args["last"] != nil {
 | 
				
			||||||
 | 
								limit = p.Args["last"].(int)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							sql = fmt.Sprintf(`
 | 
				
			||||||
 | 
							WITH RankedArticles AS (%s)
 | 
				
			||||||
 | 
							SELECT * FROM web_article INNER JOIN(
 | 
				
			||||||
 | 
								SELECT id, row_num FROM RankedArticles %s
 | 
				
			||||||
 | 
							) AS LimitedRanked ON LimitedRanked.id = web_article.id
 | 
				
			||||||
 | 
							ORDER BY LimitedRanked.row_num ASC LIMIT %d
 | 
				
			||||||
 | 
							`, sql, cursor, limit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err := db.Raw(sql).Scan(&games).Error; err != nil {
 | 
				
			||||||
 | 
								fmt.Println("获取游戏列表失败", err)
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return map[string]interface{}{
 | 
				
			||||||
 | 
								"list":  games,
 | 
				
			||||||
 | 
								"total": total,
 | 
				
			||||||
 | 
							}, err
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -12,7 +12,7 @@ import (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
var gorse *client.GorseClient
 | 
					var gorse *client.GorseClient
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func gorseInit(host string, port int) {
 | 
					func GorseInit(host string, port int) {
 | 
				
			||||||
	gorse = client.NewGorseClient(fmt.Sprintf("http://%s:%d", host, port), "")
 | 
						gorse = client.NewGorseClient(fmt.Sprintf("http://%s:%d", host, port), "")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1260
									
								
								api/graphql.go
									
									
									
									
									
								
							
							
						
						
									
										1260
									
								
								api/graphql.go
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										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
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										159
									
								
								api/struct.go
									
									
									
									
									
								
							
							
						
						
									
										159
									
								
								api/struct.go
									
									
									
									
									
								
							@@ -1,11 +1,9 @@
 | 
				
			|||||||
package api
 | 
					package api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"encoding/json"
 | 
					 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"time"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type IDS []int
 | 
					type IDS []int
 | 
				
			||||||
@@ -54,160 +52,3 @@ func (images *ImageList) ToAllUserID() (uniqueIds IDS) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return uniqueIds
 | 
						return uniqueIds
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
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)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type User struct {
 | 
					 | 
				
			||||||
	ID         int       `json:"id"          db:"id" gorm:"primaryKey"`
 | 
					 | 
				
			||||||
	UserName   string    `json:"user_name"   db:"user_name"`
 | 
					 | 
				
			||||||
	Avatar     string    `json:"avatar"      db:"avatar"`
 | 
					 | 
				
			||||||
	Rank       string    `json:"rank"        db:"rank"`
 | 
					 | 
				
			||||||
	Price      int       `json:"price"       db:"price"`
 | 
					 | 
				
			||||||
	CreateTime time.Time `json:"create_time" db:"create_time"`
 | 
					 | 
				
			||||||
	UpdateTime time.Time `json:"update_time" db:"update_time"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (User) TableName() string {
 | 
					 | 
				
			||||||
	return "web_member"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Work struct {
 | 
					 | 
				
			||||||
	ID          int       `json:"id" gorm:"primaryKey"`
 | 
					 | 
				
			||||||
	Title       string    `json:"title"`
 | 
					 | 
				
			||||||
	Orientation string    `json:"orientation"`
 | 
					 | 
				
			||||||
	Device      string    `json:"device"`
 | 
					 | 
				
			||||||
	Era         string    `json:"era"`
 | 
					 | 
				
			||||||
	Tags        string    `json:"tags"`
 | 
					 | 
				
			||||||
	UserId      int       `json:"user_id"`
 | 
					 | 
				
			||||||
	Content     string    `json:"content"`
 | 
					 | 
				
			||||||
	Image       string    `json:"image"`
 | 
					 | 
				
			||||||
	Images      string    `json:"images"`
 | 
					 | 
				
			||||||
	User        User      `json:"user" gorm:"foreignKey:UserId"`
 | 
					 | 
				
			||||||
	CreateTime  time.Time `json:"create_time"`
 | 
					 | 
				
			||||||
	UpdateTime  time.Time `json:"update_time"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (Work) TableName() string {
 | 
					 | 
				
			||||||
	return "web_article"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Game struct {
 | 
					 | 
				
			||||||
	ID          int       `json:"id" gorm:"primaryKey"`
 | 
					 | 
				
			||||||
	Title       string    `json:"title"`
 | 
					 | 
				
			||||||
	Orientation string    `json:"orientation"`
 | 
					 | 
				
			||||||
	Device      string    `json:"device"`
 | 
					 | 
				
			||||||
	Era         string    `json:"era"`
 | 
					 | 
				
			||||||
	Tags        string    `json:"tags"`
 | 
					 | 
				
			||||||
	UserId      int       `json:"user_id"`
 | 
					 | 
				
			||||||
	Content     string    `json:"content"`
 | 
					 | 
				
			||||||
	Image       string    `json:"image"`
 | 
					 | 
				
			||||||
	Images      string    `json:"images"`
 | 
					 | 
				
			||||||
	User        User      `json:"user" gorm:"foreignKey:UserId"`
 | 
					 | 
				
			||||||
	CreateTime  time.Time `json:"create_time"`
 | 
					 | 
				
			||||||
	UpdateTime  time.Time `json:"update_time"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (Game) TableName() string {
 | 
					 | 
				
			||||||
	return "web_article"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Article struct {
 | 
					 | 
				
			||||||
	ID          int       `json:"id"          db:"id" gorm:"primaryKey"`
 | 
					 | 
				
			||||||
	Title       string    `json:"title"       db:"title"`
 | 
					 | 
				
			||||||
	Orientation string    `json:"orientation" db:"orientation"`
 | 
					 | 
				
			||||||
	Device      string    `json:"device"      db:"device"`
 | 
					 | 
				
			||||||
	Era         string    `json:"era"         db:"era"`
 | 
					 | 
				
			||||||
	Tags        string    `json:"tags"        db:"tags"`
 | 
					 | 
				
			||||||
	UserId      int       `json:"user_id"     db:"user_id"`
 | 
					 | 
				
			||||||
	User        User      `json:"user"        gorm:"foreignKey:UserId"`
 | 
					 | 
				
			||||||
	CreateTime  time.Time `json:"create_time" db:"create_time"`
 | 
					 | 
				
			||||||
	UpdateTime  time.Time `json:"update_time" db:"update_time"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (Article) TableName() string {
 | 
					 | 
				
			||||||
	return "web_article"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Category struct {
 | 
					 | 
				
			||||||
	ID         int       `json:"id"`
 | 
					 | 
				
			||||||
	Title      string    `json:"title"`
 | 
					 | 
				
			||||||
	Keyword    string    `json:"keyword"`
 | 
					 | 
				
			||||||
	ParentID   int       `json:"parent_id"`
 | 
					 | 
				
			||||||
	Status     int       `json:"status"`
 | 
					 | 
				
			||||||
	Content    string    `json:"content"`
 | 
					 | 
				
			||||||
	Sort       int       `json:"sort"`
 | 
					 | 
				
			||||||
	Image      string    `json:"image"`
 | 
					 | 
				
			||||||
	ImageNum   int       `json:"image_num"`
 | 
					 | 
				
			||||||
	ArticleNum int       `json:"article_num"`
 | 
					 | 
				
			||||||
	CreateTime time.Time `json:"create_time"`
 | 
					 | 
				
			||||||
	UpdateTime time.Time `json:"update_time"`
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TableName 方法用于自定义表名
 | 
					 | 
				
			||||||
func (Category) TableName() string {
 | 
					 | 
				
			||||||
	return "web_article_category"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// 输入配置
 | 
					 | 
				
			||||||
type MysqlConfig struct {
 | 
					 | 
				
			||||||
	Host     string
 | 
					 | 
				
			||||||
	Port     int
 | 
					 | 
				
			||||||
	Database string
 | 
					 | 
				
			||||||
	UserName string
 | 
					 | 
				
			||||||
	Password string
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Oss struct {
 | 
					 | 
				
			||||||
	Local bool
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type GorseConfig struct {
 | 
					 | 
				
			||||||
	Host string
 | 
					 | 
				
			||||||
	Port int
 | 
					 | 
				
			||||||
	Open bool
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Config struct {
 | 
					 | 
				
			||||||
	Mysql MysqlConfig
 | 
					 | 
				
			||||||
	Gorse GorseConfig
 | 
					 | 
				
			||||||
	Oss
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										93
									
								
								api/user.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								api/user.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,93 @@
 | 
				
			|||||||
 | 
					package api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/graphql-go/graphql"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type User struct {
 | 
				
			||||||
 | 
						ID         int       `json:"id"          db:"id" gorm:"primaryKey"`
 | 
				
			||||||
 | 
						UserName   string    `json:"user_name"   db:"user_name"`
 | 
				
			||||||
 | 
						Avatar     string    `json:"avatar"      db:"avatar"`
 | 
				
			||||||
 | 
						Rank       string    `json:"rank"        db:"rank"`
 | 
				
			||||||
 | 
						Price      int       `json:"price"       db:"price"`
 | 
				
			||||||
 | 
						CreateTime time.Time `json:"create_time" db:"create_time"`
 | 
				
			||||||
 | 
						UpdateTime time.Time `json:"update_time" db:"update_time"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (User) TableName() string {
 | 
				
			||||||
 | 
						return "web_member"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var userType = graphql.NewObject(graphql.ObjectConfig{
 | 
				
			||||||
 | 
						Name:        "User",
 | 
				
			||||||
 | 
						Description: "用户信息",
 | 
				
			||||||
 | 
						Fields: graphql.Fields{
 | 
				
			||||||
 | 
							"id":          &graphql.Field{Type: graphql.Int, Description: "用户ID"},
 | 
				
			||||||
 | 
							"user_name":   &graphql.Field{Type: graphql.String, Description: "用户名"},
 | 
				
			||||||
 | 
							"avatar":      &graphql.Field{Type: graphql.String, Description: "用户头像"},
 | 
				
			||||||
 | 
							"rank":        &graphql.Field{Type: graphql.String, Description: "用户等级"},
 | 
				
			||||||
 | 
							"price":       &graphql.Field{Type: graphql.Int, Description: "用户金币"},
 | 
				
			||||||
 | 
							"create_time": &graphql.Field{Type: graphql.DateTime, Description: "用户创建时间"},
 | 
				
			||||||
 | 
							"update_time": &graphql.Field{Type: graphql.DateTime, Description: "用户更新时间"},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var UserItems = &graphql.Field{
 | 
				
			||||||
 | 
						Name:        "users",
 | 
				
			||||||
 | 
						Description: "用户列表",
 | 
				
			||||||
 | 
						Type: graphql.NewObject(graphql.ObjectConfig{
 | 
				
			||||||
 | 
							Name:        "UserConnection",
 | 
				
			||||||
 | 
							Description: "条件筛选用户列表",
 | 
				
			||||||
 | 
							Fields: graphql.Fields{
 | 
				
			||||||
 | 
								"list":  &graphql.Field{Type: graphql.NewList(userType), Description: "用户列表"},
 | 
				
			||||||
 | 
								"total": &graphql.Field{Type: graphql.Int, Description: "用户总数"},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}),
 | 
				
			||||||
 | 
						Args: graphql.FieldConfigArgument{
 | 
				
			||||||
 | 
							"id":          &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选用户中指定ID的"},
 | 
				
			||||||
 | 
							"user_name":   &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选用户中含有指定用户名的"},
 | 
				
			||||||
 | 
							"create_time": &graphql.ArgumentConfig{Type: graphql.DateTime, Description: "筛选用户中创建时间等于指定值的"},
 | 
				
			||||||
 | 
							"update_time": &graphql.ArgumentConfig{Type: graphql.DateTime, Description: "筛选用户中更新时间等于指定值的"},
 | 
				
			||||||
 | 
							"first":       &graphql.ArgumentConfig{Type: graphql.Int, Description: "翻页参数(傳回清單中的前n個元素)"},
 | 
				
			||||||
 | 
							"last":        &graphql.ArgumentConfig{Type: graphql.Int, Description: "翻页参数(傳回清單中的最後n個元素)"},
 | 
				
			||||||
 | 
							"after":       &graphql.ArgumentConfig{Type: graphql.String, Description: "翻页参数(傳回清單中指定遊標之後的元素)"},
 | 
				
			||||||
 | 
							"before":      &graphql.ArgumentConfig{Type: graphql.String, Description: "翻页参数(傳回清單中指定遊標之前的元素)"},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						Resolve: func(p graphql.ResolveParams) (interface{}, error) {
 | 
				
			||||||
 | 
							//var where []string
 | 
				
			||||||
 | 
							//if p.Args["id"] != nil {
 | 
				
			||||||
 | 
							//	where = append(where, fmt.Sprintf("id=%d", p.Args["id"]))
 | 
				
			||||||
 | 
							//}
 | 
				
			||||||
 | 
							//if p.Args["user_name"] != nil {
 | 
				
			||||||
 | 
							//	where = append(where, fmt.Sprintf("user_name='%s'", p.Args["user_name"]))
 | 
				
			||||||
 | 
							//}
 | 
				
			||||||
 | 
							//// 筛选条件
 | 
				
			||||||
 | 
							//where_str := strings.Join(where, " AND ")
 | 
				
			||||||
 | 
							//if where_str != "" {
 | 
				
			||||||
 | 
							//	where_str = "WHERE " + where_str
 | 
				
			||||||
 | 
							//}
 | 
				
			||||||
 | 
							//var query strings.Builder
 | 
				
			||||||
 | 
							var users []User
 | 
				
			||||||
 | 
							var total int
 | 
				
			||||||
 | 
							//fields := strings.Join(get_fields(p.Info.FieldASTs[0].SelectionSet.Selections), ",")
 | 
				
			||||||
 | 
							//query.WriteString(fmt.Sprintf("SELECT %s FROM web_member %s LIMIT %d OFFSET %d", fields, where_str, 10, 0))
 | 
				
			||||||
 | 
							//if err := connection.Select(&users, query.String()); err != nil {
 | 
				
			||||||
 | 
							//	fmt.Println("获取用户列表失败", err)
 | 
				
			||||||
 | 
							//	return nil, err
 | 
				
			||||||
 | 
							//}
 | 
				
			||||||
 | 
							//if len(users) > 0 {
 | 
				
			||||||
 | 
							//	query.Reset()
 | 
				
			||||||
 | 
							//	query.WriteString(fmt.Sprintf("SELECT COUNT(*) FROM web_member %s", where_str))
 | 
				
			||||||
 | 
							//	if err := connection.Get(&total, query.String()); err != nil {
 | 
				
			||||||
 | 
							//		fmt.Println("获取用户总数失败", err)
 | 
				
			||||||
 | 
							//		return nil, err
 | 
				
			||||||
 | 
							//	}
 | 
				
			||||||
 | 
							//}
 | 
				
			||||||
 | 
							return map[string]interface{}{
 | 
				
			||||||
 | 
								"list":  users,
 | 
				
			||||||
 | 
								"total": total,
 | 
				
			||||||
 | 
							}, nil
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										139
									
								
								api/work.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								api/work.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,139 @@
 | 
				
			|||||||
 | 
					package api
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
 | 
						"log"
 | 
				
			||||||
 | 
						"regexp"
 | 
				
			||||||
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/doug-martin/goqu/v9"
 | 
				
			||||||
 | 
						"github.com/graphql-go/graphql"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type Work struct {
 | 
				
			||||||
 | 
						ID          int       `json:"id" gorm:"primaryKey"`
 | 
				
			||||||
 | 
						Title       string    `json:"title"`
 | 
				
			||||||
 | 
						Orientation string    `json:"orientation"`
 | 
				
			||||||
 | 
						Device      string    `json:"device"`
 | 
				
			||||||
 | 
						Era         string    `json:"era"`
 | 
				
			||||||
 | 
						Tags        string    `json:"tags"`
 | 
				
			||||||
 | 
						UserId      int       `json:"user_id"`
 | 
				
			||||||
 | 
						Content     string    `json:"content"`
 | 
				
			||||||
 | 
						Image       string    `json:"image"`
 | 
				
			||||||
 | 
						Images      string    `json:"images"`
 | 
				
			||||||
 | 
						User        User      `json:"user" gorm:"foreignKey:UserId"`
 | 
				
			||||||
 | 
						CreateTime  time.Time `json:"create_time"`
 | 
				
			||||||
 | 
						UpdateTime  time.Time `json:"update_time"`
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (Work) TableName() string {
 | 
				
			||||||
 | 
						return "web_article"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var workType = graphql.NewObject(graphql.ObjectConfig{
 | 
				
			||||||
 | 
						Name:        "Work",
 | 
				
			||||||
 | 
						Description: "作品",
 | 
				
			||||||
 | 
						Fields: graphql.Fields{
 | 
				
			||||||
 | 
							"id":            &graphql.Field{Type: graphql.Int, Description: "作品ID"},
 | 
				
			||||||
 | 
							"title":         &graphql.Field{Type: graphql.String, Description: "作品标题"},
 | 
				
			||||||
 | 
							"create_time":   &graphql.Field{Type: graphql.DateTime, Description: "作品创建时间"},
 | 
				
			||||||
 | 
							"update_time":   &graphql.Field{Type: graphql.DateTime, Description: "作品更新时间"},
 | 
				
			||||||
 | 
							"praise_count":  &graphql.Field{Type: graphql.Int, Description: "点赞数"},
 | 
				
			||||||
 | 
							"collect_count": &graphql.Field{Type: graphql.Int, Description: "收藏数"},
 | 
				
			||||||
 | 
							"praise":        &graphql.Field{Type: graphql.Boolean, Description: "当前用户是否点赞"},
 | 
				
			||||||
 | 
							"collect":       &graphql.Field{Type: graphql.Boolean, Description: "当前用户是否收藏"},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var WorkItems = &graphql.Field{
 | 
				
			||||||
 | 
						Name:        "works",
 | 
				
			||||||
 | 
						Description: "作品列表",
 | 
				
			||||||
 | 
						Type: graphql.NewObject(graphql.ObjectConfig{
 | 
				
			||||||
 | 
							Name:        "WorkConnection",
 | 
				
			||||||
 | 
							Description: "条件筛选作品列表",
 | 
				
			||||||
 | 
							Fields: graphql.Fields{
 | 
				
			||||||
 | 
								"list": &graphql.Field{Type: graphql.NewList(workType), Description: "作品列表"},
 | 
				
			||||||
 | 
								//"total": &graphql.Field{Type: graphql.Int, Description: "作品总数"},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}),
 | 
				
			||||||
 | 
						Args: graphql.FieldConfigArgument{
 | 
				
			||||||
 | 
							"id":          &graphql.ArgumentConfig{Type: graphql.Int, Description: "筛选作品中指定ID的"},
 | 
				
			||||||
 | 
							"title":       &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选作品中含有指定标题的"},
 | 
				
			||||||
 | 
							"tags":        &graphql.ArgumentConfig{Type: graphql.String, Description: "筛选作品中含有指定标签的"},
 | 
				
			||||||
 | 
							"create_time": &graphql.ArgumentConfig{Type: graphql.DateTime, Description: "筛选作品中创建时间等于指定值的"},
 | 
				
			||||||
 | 
							"update_time": &graphql.ArgumentConfig{Type: graphql.DateTime, Description: "筛选作品中更新时间等于指定值的"},
 | 
				
			||||||
 | 
							"sort":        &graphql.ArgumentConfig{Type: graphql.String, Description: "按指定字段排序游戏", DefaultValue: "id"},
 | 
				
			||||||
 | 
							"order":       &graphql.ArgumentConfig{Type: orderType, Description: "排序类型(升序或降序)", DefaultValue: "ASC"},
 | 
				
			||||||
 | 
							"first":       &graphql.ArgumentConfig{Type: graphql.Int, Description: "翻页参数(傳回清單中的前n個元素)"},
 | 
				
			||||||
 | 
							"last":        &graphql.ArgumentConfig{Type: graphql.Int, Description: "翻页参数(傳回清單中的最後n個元素)"},
 | 
				
			||||||
 | 
							"after":       &graphql.ArgumentConfig{Type: graphql.String, Description: "翻页参数(傳回清單中指定遊標之後的元素)"},
 | 
				
			||||||
 | 
							"before":      &graphql.ArgumentConfig{Type: graphql.String, Description: "翻页参数(傳回清單中指定遊標之前的元素)"},
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						Resolve: func(p graphql.ResolveParams) (interface{}, error) {
 | 
				
			||||||
 | 
							var works []Work
 | 
				
			||||||
 | 
							var total int
 | 
				
			||||||
 | 
							var err error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							var query = goqu.Dialect("mysql").From("web_article")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 筛选条件
 | 
				
			||||||
 | 
							for _, format := range []string{"id", "tags"} {
 | 
				
			||||||
 | 
								if p.Args[format] != nil {
 | 
				
			||||||
 | 
									query = query.Where(goqu.C(format).Eq(p.Args[format]))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 排序条件
 | 
				
			||||||
 | 
							if p.Args["sort"] != nil {
 | 
				
			||||||
 | 
								if p.Args["order"].(string) == "ASC" {
 | 
				
			||||||
 | 
									query = query.Order(goqu.C(p.Args["sort"].(string)).Asc())
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if p.Args["order"].(string) == "DESC" {
 | 
				
			||||||
 | 
									query = query.Order(goqu.C(p.Args["sort"].(string)).Desc())
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 如果没有外部排序则使用指定排序(正则sort只能是字母数字下划下)
 | 
				
			||||||
 | 
							if p.Args["text"] == nil && p.Args["similar"] == nil && p.Args["interest"] == nil {
 | 
				
			||||||
 | 
								sort := regexp.MustCompile(`[^a-zA-Z0-9_]`).ReplaceAllString(p.Args["sort"].(string), "")
 | 
				
			||||||
 | 
								query = query.Select("web_images.id", goqu.L(
 | 
				
			||||||
 | 
									fmt.Sprintf("ROW_NUMBER() OVER(ORDER BY web_images.%s %s)", sort, p.Args["order"]),
 | 
				
			||||||
 | 
								).As("row_num"))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 取所有数据的前N条
 | 
				
			||||||
 | 
							sql, _, _ := query.Where(goqu.Ex{"article_category_top_id": 1}).ToSQL()
 | 
				
			||||||
 | 
							fmt.Println(sql)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// 遊標截取篩選結果集的前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 p.Args["first"] != nil {
 | 
				
			||||||
 | 
								limit = p.Args["first"].(int)
 | 
				
			||||||
 | 
							} else if p.Args["last"] != nil {
 | 
				
			||||||
 | 
								limit = p.Args["last"].(int)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							sql = fmt.Sprintf(`
 | 
				
			||||||
 | 
							WITH RankedArticles AS (%s)
 | 
				
			||||||
 | 
							SELECT * 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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if err := db.Limit(limit).Where("category_top_id = 1").Find(&works).Error; err != nil {
 | 
				
			||||||
 | 
								log.Println("获取作品列表失败", err)
 | 
				
			||||||
 | 
								return nil, err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return map[string]interface{}{
 | 
				
			||||||
 | 
								"list":  works,
 | 
				
			||||||
 | 
								"total": total,
 | 
				
			||||||
 | 
							}, err
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										61
									
								
								bin/main.go
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								bin/main.go
									
									
									
									
									
								
							@@ -19,6 +19,7 @@ import (
 | 
				
			|||||||
	"git.satori.love/gameui/webp/api"
 | 
						"git.satori.love/gameui/webp/api"
 | 
				
			||||||
	"git.satori.love/gameui/webp/models"
 | 
						"git.satori.love/gameui/webp/models"
 | 
				
			||||||
	_ "github.com/go-sql-driver/mysql"
 | 
						_ "github.com/go-sql-driver/mysql"
 | 
				
			||||||
 | 
						"github.com/graphql-go/graphql"
 | 
				
			||||||
	"github.com/graphql-go/handler"
 | 
						"github.com/graphql-go/handler"
 | 
				
			||||||
	"github.com/milvus-io/milvus-sdk-go/v2/entity"
 | 
						"github.com/milvus-io/milvus-sdk-go/v2/entity"
 | 
				
			||||||
	"github.com/spf13/viper"
 | 
						"github.com/spf13/viper"
 | 
				
			||||||
@@ -229,6 +230,7 @@ func main() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	models.InitConfig(config)
 | 
						models.InitConfig(config)
 | 
				
			||||||
	models.ZincInit()
 | 
						models.ZincInit()
 | 
				
			||||||
 | 
						api.InitDefault(config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mysqlConnection.Init()
 | 
						mysqlConnection.Init()
 | 
				
			||||||
	milvusConnection.Init()
 | 
						milvusConnection.Init()
 | 
				
			||||||
@@ -238,33 +240,35 @@ func main() {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// graphql Schema
 | 
					 | 
				
			||||||
	schema, err := api.NewSchema(api.Config{
 | 
					 | 
				
			||||||
		Mysql: api.MysqlConfig{
 | 
					 | 
				
			||||||
			Host:     config.GetString("mysql.host"),
 | 
					 | 
				
			||||||
			Port:     config.GetInt("mysql.port"),
 | 
					 | 
				
			||||||
			Database: config.GetString("mysql.database"),
 | 
					 | 
				
			||||||
			UserName: config.GetString("mysql.user"),
 | 
					 | 
				
			||||||
			Password: config.GetString("mysql.password"),
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		Oss: api.Oss{
 | 
					 | 
				
			||||||
			Local: config.GetBool("oss.local"),
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		Gorse: api.GorseConfig{
 | 
					 | 
				
			||||||
			Host: config.GetString("gorse.host"),
 | 
					 | 
				
			||||||
			Port: config.GetInt("gorse.port"),
 | 
					 | 
				
			||||||
			Open: config.GetBool("gorse.open"),
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
	})
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		log.Fatalf("failed to create new schema, error: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
 | 
						http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
		defer LogComponent(time.Now().UnixNano(), r) // 最后打印日志
 | 
							defer LogComponent(time.Now().UnixNano(), r) // 最后打印日志
 | 
				
			||||||
		w.Write([]byte("Hello World!"))
 | 
							w.Write([]byte("Hello World!"))
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if config.GetBool("oss.local") {
 | 
				
			||||||
 | 
							fmt.Println("开启图像色调计算")
 | 
				
			||||||
 | 
							go api.CheckColorNullRows(0)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if config.GetBool("gorse.open") {
 | 
				
			||||||
 | 
							fmt.Println("开启用户偏好收集")
 | 
				
			||||||
 | 
							api.GorseInit(config.GetString("gorse.host"), config.GetInt("gorse.port"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						schema, err := graphql.NewSchema(graphql.SchemaConfig{Query: graphql.NewObject(graphql.ObjectConfig{Name: "RootQuery", Fields: graphql.Fields{
 | 
				
			||||||
 | 
							"users":    api.UserItems,
 | 
				
			||||||
 | 
							"collects": api.CollectItems,
 | 
				
			||||||
 | 
							"games":    api.GameItems,
 | 
				
			||||||
 | 
							"works":    api.WorkItems,
 | 
				
			||||||
 | 
							"articles": api.ArticleItems,
 | 
				
			||||||
 | 
							"article":  api.ArticleItem,
 | 
				
			||||||
 | 
							"images":   api.ImageItems,
 | 
				
			||||||
 | 
							"image":    api.ImageItem,
 | 
				
			||||||
 | 
						}})})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Fatalf("failed to create new schema, error: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	http.Handle("/api", LogRequest(handler.New(&handler.Config{
 | 
						http.Handle("/api", LogRequest(handler.New(&handler.Config{
 | 
				
			||||||
		Schema:     &schema,
 | 
							Schema:     &schema,
 | 
				
			||||||
		Playground: true,
 | 
							Playground: true,
 | 
				
			||||||
@@ -275,19 +279,6 @@ func main() {
 | 
				
			|||||||
	http.HandleFunc("/api/images", func(w http.ResponseWriter, r *http.Request) {
 | 
						http.HandleFunc("/api/images", func(w http.ResponseWriter, r *http.Request) {
 | 
				
			||||||
		defer LogComponent(time.Now().UnixNano(), r) // 最后打印日志
 | 
							defer LogComponent(time.Now().UnixNano(), r) // 最后打印日志
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// 私域: (自己的图片, 自己的文章, 自己的精选集, 点赞收藏精选集)
 | 
					 | 
				
			||||||
		// 条件查询(模糊搜索, 时间区间, 作者, 标签, 分类, 精选集, 状态, 置顶, 模糊权重)(权重规则:权重指数)
 | 
					 | 
				
			||||||
		// 条件筛选(交集, 并集, 差集, 子集)
 | 
					 | 
				
			||||||
		// 文字搜索支持翻页
 | 
					 | 
				
			||||||
		// 文字搜索支持与按颜色筛选混合
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// TODO 查找含有指定文字的图像
 | 
					 | 
				
			||||||
		// TODO 查找含有指定标签的图像
 | 
					 | 
				
			||||||
		// TODO 查找含有指定特征的图像
 | 
					 | 
				
			||||||
		// TODO 查找含有指定颜色的图像(倒排索引)
 | 
					 | 
				
			||||||
		// TODO 查找含有指定分类的图像
 | 
					 | 
				
			||||||
		// 1,000,000
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// 获取查询条件(忽略空值)
 | 
							// 获取查询条件(忽略空值)
 | 
				
			||||||
		QueryConditions := func(key string) (list []string) {
 | 
							QueryConditions := func(key string) (list []string) {
 | 
				
			||||||
			for _, item := range strings.Split(r.URL.Query().Get(key), ",") {
 | 
								for _, item := range strings.Split(r.URL.Query().Get(key), ",") {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user