From c63283776710b7bb60335d10202ed04cad9c30da Mon Sep 17 00:00:00 2001 From: eson Date: Thu, 20 Aug 2020 19:29:22 +0800 Subject: [PATCH] add charts --- goserver/count_tag.go | 65 +++++++++++ goserver/main.go | 252 ++++++++++++++++++---------------------- goserver/main_test.go | 8 +- goserver/openrec.go | 7 ++ goserver/twitcasting.go | 9 ++ goserver/twitch.go | 8 ++ goserver/var_sql.go | 34 ++++++ package-lock.json | 34 ++++++ package.json | 2 + src/App.js | 19 ++- src/ContentTable.js | 21 ++++ src/Graph.js | 151 ++++++++++++++++++++++++ src/Table.js | 97 ++++++++-------- src/Table.less | 4 + 14 files changed, 517 insertions(+), 194 deletions(-) create mode 100644 goserver/count_tag.go create mode 100644 goserver/openrec.go create mode 100644 goserver/twitcasting.go create mode 100644 goserver/twitch.go create mode 100644 goserver/var_sql.go create mode 100644 src/ContentTable.js create mode 100644 src/Graph.js diff --git a/goserver/count_tag.go b/goserver/count_tag.go new file mode 100644 index 0000000..9b5d976 --- /dev/null +++ b/goserver/count_tag.go @@ -0,0 +1,65 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + "time" + + "github.com/gin-gonic/gin" +) + +var tagCounter = make(map[string]*tagcounter) + +type tagcounter struct { + Name string + LastTime time.Time + CountWord map[string]int +} + +func init() { + +} + +func CountTag(cxt *gin.Context) { + platform := cxt.Query("platform") + var cw *tagcounter + if cw, ok := tagCounter[platform]; ok { + if time.Now().Sub(cw.LastTime).Minutes() <= 10 { + cxt.JSON(200, cw.CountWord) + return + } + } + + sql := fmt.Sprintf(SqlTag, platform) + rows, err := StoreStreamer.Query(sql) + if err != nil { + cxt.Error(err) + return + } + + cw = &tagcounter{} + cw.CountWord = make(map[string]int) + cw.Name = platform + cw.LastTime = time.Now() + tagCounter[platform] = cw + + for rows.Next() { + var stag string + err = rows.Scan(&stag) + if err != nil { + log.Println(err) + } + var tag []string + json.Unmarshal([]byte(stag), &tag) + for _, t := range tag { + if _, ok := cw.CountWord[t]; ok { + cw.CountWord[t]++ + } else { + cw.CountWord[t] = 1 + } + } + } + cxt.JSON(200, cw.CountWord) + cw.LastTime = time.Now() +} diff --git a/goserver/main.go b/goserver/main.go index d95f1a9..8f6afd6 100644 --- a/goserver/main.go +++ b/goserver/main.go @@ -4,7 +4,6 @@ import ( "database/sql" "encoding/json" "fmt" - "log" "net/http" "strconv" "strings" @@ -15,33 +14,6 @@ import ( ) var StoreStreamer *sql.DB -var SqlQuery string = `SELECT -ie.uid, -ie.platform, -ie.user_id, -ie.user_name , -ie.live_url , -ie.tags , -cl.followers , -cl.views , -cl.gratuity , -cl.live_title, -cl.live_start_time , -cl.live_end_time , -cl.update_time -From -( -SELECT - * -FROM - intimate_extractor.streamer -WHERE - platform = "twitcasting" - AND operator = 0 - AND latest_log_uid is not NULL limit %s,%s) ie -JOIN intimate_extractor.collect_log cl -WHERE -ie.latest_log_uid = cl.log_uid; ` func init() { db, err := sql.Open("mysql", InitConfig.Database.ExtractorURI) @@ -51,121 +23,12 @@ func init() { StoreStreamer = db } -// ie.uid, -// ie.platform, -// ie.user_id, -// ie.user_name , -// ie.live_url , -// ie.tags , -// cl.followers , -// cl.views , -// cl.gratuity , -// cl.live_title, -// cl.live_start_time , -// cl.live_end_time , -// cl.update_time - -type ObjectTwistcasting struct { - Uid int64 - Platform string - UserId string - UserName string - LiveUrl string - Tags []string - Followers int64 - Views int64 - Gratuity int64 - LiveTitle string - LiveStartTime *time.Time - LiveEndTime *time.Time - UpdateTime *time.Time -} - type Result struct { Code int Error string Data interface{} } -func TwitcastingQuery(cxt *gin.Context) { - var err error - page, err := strconv.Atoi(cxt.Query("page")) - if err != nil { - cxt.Error(err) - } - psize, err := strconv.Atoi(cxt.Query("psize")) - if err != nil { - cxt.Error(err) - } - if psize > 100 { - cxt.Error(fmt.Errorf("page size <= 100")) - } - - start := (page - 1) * 200 - // end := start + 200 - - ssql := fmt.Sprintf(SqlQuery, strconv.Itoa(start), strconv.Itoa(psize)) - rows, err := StoreStreamer.Query(ssql) - if err != nil { - cxt.Error(err) - } - var ots []*ObjectTwistcasting - for rows.Next() { - ot := &ObjectTwistcasting{} - var lstm, letm, utm sql.NullTime - var tags string - err = rows.Scan( - &ot.Uid, - &ot.Platform, - &ot.UserId, - &ot.UserName, - &ot.LiveUrl, - &tags, - &ot.Followers, - &ot.Views, - &ot.Gratuity, - &ot.LiveTitle, - &lstm, - &letm, - &utm, - ) - if err != nil { - cxt.Error(err) - return - } - if !lstm.Valid { - ot.LiveStartTime = nil - } else { - ot.LiveStartTime = &lstm.Time - } - if !letm.Valid { - ot.LiveEndTime = nil - } else { - ot.LiveEndTime = &letm.Time - } - if !utm.Valid { - ot.UpdateTime = nil - } else { - ot.UpdateTime = &utm.Time - } - - if err = json.Unmarshal([]byte(tags), &ot.Tags); err != nil { - log.Println(tags) - } - - ots = append(ots, ot) - } - - r := &Result{Code: 200} - r.Data = ots - log.Println(len(ots)) - if retdata, err := json.Marshal(r); err != nil { - cxt.Error(err) - } else { - cxt.JSON(r.Code, string(retdata)) - } -} - func Cors() gin.HandlerFunc { return func(c *gin.Context) { method := c.Request.Method //请求方法 @@ -202,10 +65,125 @@ func Cors() gin.HandlerFunc { } } +type ObjectQuery struct { + Uid int64 + Platform string + UserId string + UserName string + LiveUrl string + Tags []string + Followers int64 + Views int64 + Gratuity int64 + LiveTitle string + LiveStartTime *time.Time + LiveEndTime *time.Time + UpdateTime *time.Time +} + +func Query(cxt *gin.Context, platform string) { + var err error + page, err := strconv.Atoi(cxt.Query("page")) + if err != nil { + cxt.Error(err) + return + } + psize, err := strconv.Atoi(cxt.Query("psize")) + if err != nil { + cxt.Error(err) + return + } + if psize > 100 { + cxt.Error(fmt.Errorf("page size <= 100")) + return + } + + start := (page - 1) * psize + // end := start + 200 + + ssql := fmt.Sprintf(SqlQuery, platform, strconv.Itoa(start), strconv.Itoa(psize)) + rows, err := StoreStreamer.Query(ssql) + if err != nil { + cxt.Error(err) + return + } + var ots []*ObjectQuery + for rows.Next() { + ot := &ObjectQuery{} + var view, gratuity sql.NullInt64 + var lstm, letm, utm sql.NullTime + var tags, livetitle sql.NullString + err = rows.Scan( + &ot.Uid, + &ot.Platform, + &ot.UserId, + &ot.UserName, + &ot.LiveUrl, + &tags, + &ot.Followers, + &view, + &gratuity, + &livetitle, + &lstm, + &letm, + &utm, + ) + if err != nil { + cxt.Error(err) + return + } + if !lstm.Valid { + ot.LiveStartTime = nil + } else { + ot.LiveStartTime = &lstm.Time + } + if !letm.Valid { + ot.LiveEndTime = nil + } else { + ot.LiveEndTime = &letm.Time + } + if !utm.Valid { + ot.UpdateTime = nil + } else { + ot.UpdateTime = &utm.Time + } + + if livetitle.Valid { + ot.LiveTitle = livetitle.String + } + + if view.Valid { + ot.Views = view.Int64 + } + + if gratuity.Valid { + ot.Gratuity = gratuity.Int64 + } + + if err = json.Unmarshal([]byte(tags.String), &ot.Tags); err != nil { + // log.Println(tags) + } + + ots = append(ots, ot) + } + + r := &Result{Code: 200} + r.Data = ots + // log.Println(len(ots)) + if retdata, err := json.Marshal(r); err != nil { + cxt.Error(err) + } else { + cxt.JSON(r.Code, string(retdata)) + } +} + func main() { engine := gin.New() //r := gin.Default() //使用默认中间件 engine.Use(gin.Logger()) engine.Use(Cors()) engine.GET("twitcasting/query", TwitcastingQuery) + engine.GET("openrec/query", OpenrecQuery) + engine.GET("twitch/query", TwitchQuery) + engine.GET("tag/count", CountTag) engine.Run(":5500") } diff --git a/goserver/main_test.go b/goserver/main_test.go index ef64976..9b4ed43 100644 --- a/goserver/main_test.go +++ b/goserver/main_test.go @@ -1,7 +1,13 @@ package main -import "testing" +import ( + "testing" +) func TestMain(t *testing.T) { main() } + +func TestCountTag(t *testing.T) { + +} diff --git a/goserver/openrec.go b/goserver/openrec.go new file mode 100644 index 0000000..322186d --- /dev/null +++ b/goserver/openrec.go @@ -0,0 +1,7 @@ +package main + +import "github.com/gin-gonic/gin" + +func OpenrecQuery(cxt *gin.Context) { + Query(cxt, "openrec") +} diff --git a/goserver/twitcasting.go b/goserver/twitcasting.go new file mode 100644 index 0000000..881cd3d --- /dev/null +++ b/goserver/twitcasting.go @@ -0,0 +1,9 @@ +package main + +import ( + "github.com/gin-gonic/gin" +) + +func TwitcastingQuery(cxt *gin.Context) { + Query(cxt, "twitcasting") +} diff --git a/goserver/twitch.go b/goserver/twitch.go new file mode 100644 index 0000000..b91a6d2 --- /dev/null +++ b/goserver/twitch.go @@ -0,0 +1,8 @@ +package main + +import "github.com/gin-gonic/gin" + +// TwitchQuery +func TwitchQuery(cxt *gin.Context) { + Query(cxt, "twitch") +} diff --git a/goserver/var_sql.go b/goserver/var_sql.go new file mode 100644 index 0000000..64f5c23 --- /dev/null +++ b/goserver/var_sql.go @@ -0,0 +1,34 @@ +package main + +// SqlTag 获取 tag +var SqlTag string = `SELECT tags FROM intimate_extractor.streamer +WHERE platform = "%s" AND tags IS NOT NULL` + +//SqlQuery 获取 网站数据 +var SqlQuery string = `SELECT +ie.uid, +ie.platform, +ie.user_id, +ie.user_name , +ie.live_url , +ie.tags , +cl.followers , +cl.views , +cl.gratuity , +cl.live_title, +cl.live_start_time , +cl.live_end_time , +cl.update_time +From +( +SELECT + * +FROM + intimate_extractor.streamer +WHERE + platform = "%s" + AND operator = 0 + AND latest_log_uid is not NULL limit %s,%s) ie +JOIN intimate_extractor.collect_log cl +WHERE +ie.latest_log_uid = cl.log_uid; ` diff --git a/package-lock.json b/package-lock.json index e9e5006..e613e88 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5066,6 +5066,30 @@ "safer-buffer": "^2.1.0" } }, + "echarts": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-4.8.0.tgz", + "integrity": "sha512-YwShpug8fWngj/RlgxDaYrLBoD+LsZUArrusjNPHpAF+is+gGe38xx4W848AwWMGoi745t3OXM52JedNrv+F6g==", + "requires": { + "zrender": "4.3.1" + } + }, + "echarts-for-react": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/echarts-for-react/-/echarts-for-react-2.0.16.tgz", + "integrity": "sha512-VmHCktay2qKt/+wpL/C7thbvIa7dYBEey0/U4Zaqo+qeA4wx+uiCd5NeCsPIhD/0Pv+2qqNswqiNiUCtcgccOw==", + "requires": { + "fast-deep-equal": "^2.0.1", + "size-sensor": "^1.0.0" + }, + "dependencies": { + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + } + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -14024,6 +14048,11 @@ "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" }, + "size-sensor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/size-sensor/-/size-sensor-1.0.1.tgz", + "integrity": "sha512-QTy7MnuugCFXIedXRpUSk9gUnyNiaxIdxGfUjr8xxXOqIB3QvBUYP9+b51oCg2C4dnhaeNk/h57TxjbvoJrJUA==" + }, "slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", @@ -16392,6 +16421,11 @@ "camelcase": "^5.0.0", "decamelize": "^1.2.0" } + }, + "zrender": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-4.3.1.tgz", + "integrity": "sha512-CeH2TpJeCdG0TAGYoPSAcFX2ogdug1K7LIn9UO/q9HWqQ54gWhrMAlDP9AwWYMUDhrPe4VeazQ4DW3msD96nUQ==" } } } diff --git a/package.json b/package.json index e78aa47..5459a1c 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,8 @@ "@testing-library/user-event": "^11.1.0", "antd": "^4.5.4", "craco-less": "^1.17.0", + "echarts": "^4.8.0", + "echarts-for-react": "^2.0.16", "react": "^16.13.1", "react-dom": "^16.13.1", "react-scripts": "^3.4.3", diff --git a/src/App.js b/src/App.js index 25d5c6c..9e89ba7 100644 --- a/src/App.js +++ b/src/App.js @@ -5,9 +5,12 @@ import Icon, { import { Button, Layout, Menu } from 'antd'; import 'antd/dist/antd.css'; import React from 'react'; +import ReactDom from 'react-dom'; import './App.less'; import DataTable from './Table'; +import ContentTable from './ContentTable'; import DataTableTest from './TableTest'; +import CountCharts from './Graph'; const { Header, Content, Footer, Sider } = Layout; @@ -38,10 +41,15 @@ class App extends React.Component { - } > - 数据展示 + } onClick={(e)=>{ this.refs.ctable.changePlatform( e.key) ; }} > + openrec + + } onClick={(e)=>{ this.refs.ctable.changePlatform( e.key) ; }} > + twitcasting + + } onClick={(e)=>{ this.refs.ctable.changePlatform( e.key) ; }} > + twitch @@ -53,9 +61,8 @@ class App extends React.Component { -
- -
+ {/* */} +