├── .DS_Store ├── asset ├── json.png └── mysql.png ├── src ├── .DS_Store ├── util │ └── regex.go ├── global │ └── postgresql.go ├── middleware │ └── usage_count.go ├── contoller │ ├── index.go │ ├── index_test.go │ └── controler.go ├── model │ ├── json_time.go │ ├── tools.go │ └── fund.go ├── service │ ├── placeholder.go │ └── ip.go ├── router │ └── router.go ├── conf │ └── config.go └── main.go ├── static ├── .DS_Store ├── favicon.ico ├── css │ ├── fonts │ │ ├── element-icons.ttf │ │ └── element-icons.woff │ └── sql2struct.css ├── webfonts │ ├── fa-solid-900.eot │ ├── fa-solid-900.ttf │ └── fa-solid-900.woff2 └── js │ ├── background.js │ ├── file_hash.worker.js │ ├── encrypt_rsa.js │ ├── placeholder.js │ ├── timestamp.js │ ├── websocket.js │ ├── morse.js │ ├── encrypt_aes.js │ ├── encrypt_des.js │ ├── regex.js │ ├── tinyimg.js │ ├── file_hash.js │ └── sql2struct.js ├── .gitignore ├── docker-compose.yaml ├── conf.yaml.default ├── tpl ├── test.html ├── morse.html ├── regex.html ├── websocket.html ├── index.html ├── base64.html ├── json2go.html ├── file_hash.html ├── union_code.html ├── ip.html ├── number.html ├── tinyimg.html ├── json.html ├── rsa.html ├── color.html ├── aside.html ├── aes.html ├── des.html ├── placeholder.html ├── url.html ├── xinpianchang.html ├── hash.html ├── unicode.html ├── image2base64.html ├── json2yaml.html ├── timestamp.html ├── mysqlgo.html ├── json2xml.html ├── pdf2img.html ├── qrcode.html └── fund.html ├── Dockerfile ├── .github └── workflows │ └── githubio.yml ├── LICENSE ├── go.mod ├── README_zh.md ├── README.md ├── sql ├── tools.mysql └── tools.sql ├── script └── build.go └── go.sum /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaArJun/devTools/HEAD/.DS_Store -------------------------------------------------------------------------------- /asset/json.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaArJun/devTools/HEAD/asset/json.png -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaArJun/devTools/HEAD/src/.DS_Store -------------------------------------------------------------------------------- /asset/mysql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaArJun/devTools/HEAD/asset/mysql.png -------------------------------------------------------------------------------- /static/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaArJun/devTools/HEAD/static/.DS_Store -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaArJun/devTools/HEAD/static/favicon.ico -------------------------------------------------------------------------------- /static/css/fonts/element-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaArJun/devTools/HEAD/static/css/fonts/element-icons.ttf -------------------------------------------------------------------------------- /static/webfonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaArJun/devTools/HEAD/static/webfonts/fa-solid-900.eot -------------------------------------------------------------------------------- /static/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaArJun/devTools/HEAD/static/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /static/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaArJun/devTools/HEAD/static/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | *.exe 3 | *.log 4 | build/ 5 | script/release.go 6 | conf.yaml 7 | main 8 | oktools* 9 | tpl/index.html -------------------------------------------------------------------------------- /static/css/fonts/element-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ChinaArJun/devTools/HEAD/static/css/fonts/element-icons.woff -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "2.2" 2 | services: 3 | oktools: 4 | image: tools:v1.0-master 5 | volumes: 6 | - "./oktools/:/app/" 7 | container_name: oktools 8 | ports: 9 | - "81:81" 10 | -------------------------------------------------------------------------------- /static/css/sql2struct.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 0px; 3 | margin: 0px; 4 | background-color: #fafaff; 5 | } 6 | 7 | a { 8 | text-decoration: none; 9 | } 10 | 11 | .el-header { 12 | padding: 0; 13 | } -------------------------------------------------------------------------------- /src/util/regex.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "regexp" 5 | ) 6 | 7 | // 校验是否是IPV4 8 | func CheckIPV4(ip string) bool { 9 | pattern := `(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})(\.(2(5[0-5]{1}|[0-4]\d{1})|[0-1]?\d{1,2})){3}` 10 | reg := regexp.MustCompile(pattern) 11 | return reg.MatchString(ip) 12 | } 13 | -------------------------------------------------------------------------------- /conf.yaml.default: -------------------------------------------------------------------------------- 1 | app: 2 | # mode: debug 3 | mode: release 4 | log-file: oktools.log 5 | 6 | http: 7 | port: 80 8 | ssl: 9 | enable: false 10 | crt: 11 | key: 12 | postgresdb: 13 | host: 127.0.0.1 14 | port: 5432 15 | username: 16 | password: 17 | dbname: devtools 18 | 19 | mysqldb: 20 | host: 127.0.01 21 | port: 3306 22 | username: root 23 | password: 24 | dbname: fund 25 | maxId: 10 26 | maxOpen: 100 27 | log: 1 28 | 29 | third-party: 30 | amap: 31 | key: 32 | serverchan: 33 | key: 34 | -------------------------------------------------------------------------------- /tpl/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 18 | 19 | 20 |
登录成功
21 | 22 | -------------------------------------------------------------------------------- /src/global/postgresql.go: -------------------------------------------------------------------------------- 1 | package global 2 | 3 | import ( 4 | _ "github.com/lib/pq" 5 | ) 6 | 7 | //var PSDB *sql.DB 8 | // 9 | //func init() { 10 | // dbConf := conf.Conf.Postgresdb 11 | // var err error 12 | // 13 | // PSDB, err = sql.Open("postgres", fmt.Sprintf( 14 | // "host=%s port=%s user=%s password=%s dbname=%s sslmode=disable", 15 | // dbConf.Host, dbConf.Port, dbConf.Username, dbConf.Password, dbConf.DbName)) 16 | // if err != nil { 17 | // log.Fatalln("Open SqlErr:", err) 18 | // } 19 | // log.Print("postgresdb connect success!") 20 | //} 21 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FROM golang:alpine 4 | #WORKDIR /app 5 | #RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build main.go 6 | 7 | FROM docker.io/jeanblanchard/alpine-glibc AS final 8 | 9 | WORKDIR /app 10 | COPY ./main /app/main 11 | #COPY ./conf.yaml /app/ 12 | COPY ./static /app/static 13 | COPY ./tpl /app/tpl 14 | 15 | # 清空缓存 16 | RUN rm -rf /var/cache/apk/* 17 | 18 | ENV LANG=en_US.UTF-8 \ 19 | LANGUAGE=en_US:en \ 20 | LC_ALL=en_US.UTF-8 \ 21 | USER_HOME_DIR="/root" 22 | 23 | ENTRYPOINT ["/app/main"] 24 | 25 | -------------------------------------------------------------------------------- /static/js/background.js: -------------------------------------------------------------------------------- 1 | chrome.browserAction.onClicked.addListener(function(activeTab) { 2 | var url = 'html/sql2struct.html'; 3 | chrome.tabs.create({ 4 | url: url 5 | }); 6 | }); 7 | 8 | chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) { 9 | if (message.act == 'setOptions') { 10 | localStorage.setItem('sql2struct_options', message.data) 11 | sendResponse('ok') 12 | } 13 | if (message.act = 'getOptions') { 14 | options = localStorage.getItem('sql2struct_options') 15 | sendResponse(options) 16 | } 17 | }) -------------------------------------------------------------------------------- /src/middleware/usage_count.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "time" 6 | ) 7 | 8 | var channel = make(chan string) 9 | 10 | const flushInterval = 5 * time.Minute 11 | 12 | func init() { 13 | timer := time.NewTicker(flushInterval) 14 | 15 | go func() { 16 | for { 17 | select { 18 | //case path := <-channel: 19 | // 使用次数 +1 20 | //model.ToolMap[path].UsageCount++ 21 | case <-timer.C: 22 | // 使用次数写入数据库 23 | //log.Print("使用次数写入数据库") 24 | //model.UpdateUsageCount() 25 | } 26 | } 27 | }() 28 | } 29 | 30 | func UsageCount(c *gin.Context) { 31 | channel <- c.Request.URL.Path 32 | } 33 | -------------------------------------------------------------------------------- /.github/workflows/githubio.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | # 在master分支发生push事件时触发。 3 | on: 4 | push: 5 | branches: 6 | - master 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: GoModules 13 | run: go env -w GO111MODULE=on 14 | - name: tidy 15 | run: go mod tidy 16 | - name: run main.go 17 | run: CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build src/main.go 18 | - name: BuildDockerImage 19 | run: docker build . --file Dockerfile --tag chinaarjun/devtools:${{ github.ref_name }} 20 | - name: Publish to Registry 21 | uses: elgohr/Publish-Docker-Github-Action@v4 22 | 23 | with: 24 | name: chinaarjun/devtools:${{ github.ref_name }} 25 | username: ${{ secrets.DOCKER_USERNAME }} 26 | password: ${{ secrets.DOCKER_PASSWORD }} 27 | snapshot: true -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 maomao1996 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/contoller/index.go: -------------------------------------------------------------------------------- 1 | package contoller 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | log "github.com/sirupsen/logrus" 6 | "net/http" 7 | "oktools/src/model" 8 | "time" 9 | ) 10 | 11 | func FundIndex(c *gin.Context) { 12 | c.HTML(http.StatusOK, "fund.html", gin.H{ 13 | "times": GetTimes(), 14 | "funds": GetFunds(c), 15 | }) 16 | } 17 | 18 | // 19 | //func FundIndex(c *gin.Context) { 20 | // c.HTML(http.StatusOK, "index.html", gin.H{ 21 | // //"tools": GetFunds(), 22 | // }) 23 | //} 24 | 25 | func GetTimes() []struct{ Time string } { 26 | var times []struct{ Time string } 27 | now := time.Now() 28 | for i := 0; i < 120; i++ { 29 | date := now.AddDate(0, 0, -i) 30 | formatDay := date.Format("2006-01-02") 31 | times = append(times, struct{ Time string }{Time: formatDay}) 32 | } 33 | return times 34 | } 35 | 36 | func GetFunds(c *gin.Context) []model.Fund { 37 | timeStr := c.Query("time") 38 | log.Print("GetFunds_Time", timeStr) 39 | searchMaps := make(map[string]string) 40 | searchMaps["enddate"] = timeStr 41 | searchMaps["order_by"] = "enddate desc" 42 | 43 | fund := model.GetFund() 44 | res, err := fund.List(searchMaps, 0, 100) 45 | if err != nil { 46 | return nil 47 | } 48 | 49 | return res 50 | } 51 | -------------------------------------------------------------------------------- /src/contoller/index_test.go: -------------------------------------------------------------------------------- 1 | package contoller 2 | 3 | import ( 4 | "fmt" 5 | "github.com/jinzhu/gorm" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | func TestSql(t *testing.T) { 11 | db, err := gorm.Open("mysql", "root:amo1994@(127.0.0.1:3306)/python_fund?charset=utf8mb4&parseTime=True&loc=Local") 12 | if err != nil { 13 | fmt.Println(err) 14 | } 15 | 16 | rows, err := db.DB().Query("select * from danjuan_fund") 17 | 18 | var items []interface{} 19 | for rows.Next() { 20 | var countMap struct { 21 | Id int64 `json:"id"` 22 | } 23 | db.ScanRows(rows, &countMap) 24 | items = append(items, countMap) 25 | } 26 | rows.Close() 27 | } 28 | 29 | func TestGetTimes(t *testing.T) { 30 | now := time.Now() 31 | date := now.AddDate(0, 0, -1) 32 | formatDay := date.Format("2006-01-02") 33 | curMonthFormat := now.Format("2006-01") 34 | 35 | year, month, _ := now.Date() 36 | thisMonthFirstDay := time.Date(year, month, 1, 1, 1, 1, 0, now.Location()) 37 | lastMonth := thisMonthFirstDay.AddDate(0, -1, 0) 38 | lastMonthFormat := lastMonth.Format("2006-01-02") 39 | 40 | lastday := thisMonthFirstDay.AddDate(0, 0, -1) 41 | fmt.Println(formatDay) 42 | fmt.Println(curMonthFormat) 43 | fmt.Println(lastMonthFormat) 44 | 45 | fmt.Println(lastday.Format("2006-01-02")) 46 | } 47 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module oktools 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/gin-gonic/gin v1.7.0 7 | github.com/go-sql-driver/mysql v1.5.0 8 | github.com/jinzhu/gorm v1.9.16 9 | github.com/lib/pq v1.1.1 10 | github.com/onrik/logrus v0.8.0 11 | github.com/sirupsen/logrus v1.7.0 12 | github.com/tdewolff/minify v2.3.6+incompatible 13 | gopkg.in/yaml.v2 v2.2.8 14 | ) 15 | 16 | require ( 17 | github.com/gin-contrib/sse v0.1.0 // indirect 18 | github.com/go-playground/locales v0.13.0 // indirect 19 | github.com/go-playground/universal-translator v0.17.0 // indirect 20 | github.com/go-playground/validator/v10 v10.4.1 // indirect 21 | github.com/golang/protobuf v1.3.3 // indirect 22 | github.com/jinzhu/inflection v1.0.0 // indirect 23 | github.com/json-iterator/go v1.1.9 // indirect 24 | github.com/leodido/go-urn v1.2.0 // indirect 25 | github.com/mattn/go-isatty v0.0.12 // indirect 26 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 27 | github.com/modern-go/reflect2 v1.0.1 // indirect 28 | github.com/tdewolff/parse v2.3.4+incompatible // indirect 29 | github.com/tdewolff/test v1.0.0 // indirect 30 | github.com/ugorji/go/codec v1.1.7 // indirect 31 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect 32 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd // indirect 33 | ) 34 | -------------------------------------------------------------------------------- /static/js/file_hash.worker.js: -------------------------------------------------------------------------------- 1 | importScripts('https://cdn.bootcss.com/crypto-js/3.1.9-1/crypto-js.min.js'); 2 | 3 | let algo; 4 | 5 | function createAlgo(name) { 6 | switch (name) { 7 | case 'MD5': 8 | algo = CryptoJS.algo.MD5.create(); 9 | break; 10 | case 'SHA-1': 11 | algo = CryptoJS.algo.SHA1.create(); 12 | break; 13 | case 'SHA-224': 14 | algo = CryptoJS.algo.SHA224.create(); 15 | break; 16 | case 'SHA-256': 17 | algo = CryptoJS.algo.SHA256.create(); 18 | break; 19 | case 'SHA-384': 20 | algo = CryptoJS.algo.SHA384.create(); 21 | break; 22 | case 'SHA-512': 23 | algo = CryptoJS.algo.SHA512.create(); 24 | break; 25 | } 26 | } 27 | 28 | addEventListener('message', function (e) { 29 | switch (e.data.type) { 30 | case 'algo': 31 | createAlgo(e.data.name); 32 | break; 33 | case 'chunk': 34 | algo.update(CryptoJS.enc.Latin1.parse(e.data.chunk)); 35 | postMessage({type: 'progress', value: e.data.offs * 100 / e.data.total}); 36 | break; 37 | case 'done': 38 | let hash = algo.finalize(); 39 | postMessage({type: 'result', value: hash.toString(CryptoJS.enc.Hex)}); 40 | self.close(); 41 | break; 42 | } 43 | }, false); 44 | 45 | -------------------------------------------------------------------------------- /tpl/morse.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 摩斯电码|摩斯密码 - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {{template "aside"}} 14 |
15 |
16 |

摩斯电码

17 | 19 |
20 | 24 | 28 | 29 |
30 | 31 |
32 |
33 | 34 | 35 | -------------------------------------------------------------------------------- /static/js/encrypt_rsa.js: -------------------------------------------------------------------------------- 1 | function generateKey(btn) { 2 | if (btn) { 3 | btn.stopPropatation = true; 4 | btn.cancelBubble = true; 5 | } 6 | 7 | let keySize = parseInt(document.getElementById('select_key_size').value); 8 | let crypt = new JSEncrypt({default_key_size: keySize}); 9 | if (btn) btn.innerText = '正在生成...'; 10 | 11 | new Promise(function (resolve) { 12 | setTimeout(function () { 13 | resolve([crypt.getPrivateKey(), crypt.getPublicKey()]); 14 | }, 50); 15 | }).then(function (e) { 16 | document.getElementById('area_private_key').value = e[0]; 17 | document.getElementById('area_public_key').value = e[1]; 18 | if (btn) btn.innerText = '生成密钥'; 19 | }); 20 | } 21 | 22 | function getCrypt() { 23 | let private_key = document.getElementById('area_private_key').value; 24 | let public_key = document.getElementById('area_public_key').value; 25 | if (private_key && public_key) { 26 | let crypt = new JSEncrypt(); 27 | crypt.setPrivateKey(private_key); 28 | return crypt 29 | } 30 | } 31 | 32 | function encrypt() { 33 | let cipher_text = ''; 34 | let original_text = document.getElementById('area_original_text').value; 35 | if (original_text) { 36 | cipher_text = getCrypt().encrypt(original_text) || '' 37 | } 38 | document.getElementById('area_cipher_text').value = cipher_text 39 | } 40 | 41 | function decrypt() { 42 | let original_text = ''; 43 | let cipher_text = document.getElementById('area_cipher_text').value; 44 | if (cipher_text) { 45 | original_text = getCrypt().decrypt(cipher_text) || '' 46 | } 47 | document.getElementById('area_original_text').value = original_text 48 | } 49 | 50 | generateKey(); -------------------------------------------------------------------------------- /tpl/regex.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 正则表达式 - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 11 | 12 | {{template "aside"}} 13 |
14 |
15 |

正则表达式

16 | 17 |
18 | 22 | 23 | 24 | 25 |
26 | 27 |
28 | 替换文本 29 | 30 | 31 |
32 | 33 |

常用正则表达式

34 |
35 |
36 |
37 | 38 | 39 | -------------------------------------------------------------------------------- /tpl/websocket.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | WebSocket测试 - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 18 | 19 | 20 | {{template "aside"}} 21 |
22 |
23 |

WebSocket测试

24 |
25 | 29 |
30 | 31 | 32 | 33 |
34 |
35 |
36 |
37 | 消息 38 | 39 | 40 |
41 |
42 |
43 | 44 | 45 | -------------------------------------------------------------------------------- /src/model/json_time.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "database/sql/driver" 5 | "fmt" 6 | "strconv" 7 | "time" 8 | ) 9 | 10 | const ( 11 | timeFormart = "2006-01-02 15:04:05" 12 | dateFormat = "2006-01-02" 13 | zone = "Asia/Shanghai" 14 | ) 15 | 16 | // JSONTime format json time field by myself 17 | type JSONTime struct { 18 | time.Time 19 | } 20 | 21 | // MarshalJSON on JSONTime format Time field with %Y-%m-%d %H:%M:%S 22 | func (t JSONTime) MarshalJSON() ([]byte, error) { 23 | if t.IsZero() { 24 | return []byte(`""`), nil 25 | } 26 | formatted := fmt.Sprintf("\"%s\"", t.Format(timeFormart)) 27 | return []byte(formatted), nil 28 | } 29 | 30 | // MarshalJSON on JSONTime format Time field with %Y-%m-%d %H:%M:%S 31 | func (t JSONTime) UnixStr() string { 32 | unix := t.Unix() 33 | if unix < 0 { 34 | return "0" 35 | } 36 | return strconv.FormatInt(unix, 10) 37 | } 38 | 39 | // UnmarshalJSON implements json unmarshal interface. 40 | func (t *JSONTime) UnmarshalJSON(data []byte) (err error) { 41 | if string(data) == `""` { 42 | return 43 | } 44 | now, err := time.ParseInLocation(`"`+timeFormart+`"`, string(data), time.Local) 45 | if err != nil { 46 | now, err = time.ParseInLocation(`"`+dateFormat+`"`, string(data), time.Local) 47 | } 48 | t.Time = time.Time(now) 49 | return 50 | } 51 | 52 | // Value insert timestamp into mysql need this function. 53 | func (t JSONTime) Value() (driver.Value, error) { 54 | var zeroTime time.Time 55 | if t.Time.UnixNano() == zeroTime.UnixNano() { 56 | return nil, nil 57 | } 58 | return t.Time, nil 59 | } 60 | 61 | // Scan valueof time.Time 62 | func (t *JSONTime) Scan(v interface{}) error { 63 | value, ok := v.(time.Time) 64 | if ok { 65 | *t = JSONTime{Time: value} 66 | return nil 67 | } 68 | return fmt.Errorf("can not convert %v to timestamp", v) 69 | } 70 | -------------------------------------------------------------------------------- /tpl/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 在线工具 - DevTools 6 | 7 | 11 | 15 | 16 | 17 | 18 |
19 |
20 | 21 | 31 |
32 |
33 |
34 | {{range .tools}}

{{.Title}}

36 |

https://tools.zhequtao.com{{.Path}}

{{end}} 38 |
39 | 42 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /tpl/base64.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Base64编码、Base64解码 - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {{template "aside"}} 14 |
15 |
16 |

Base64编码/解码

17 | 18 |
19 | 23 | 27 | 28 |
29 | 30 |
31 |
32 | 49 | 50 | -------------------------------------------------------------------------------- /static/js/placeholder.js: -------------------------------------------------------------------------------- 1 | const host = 'https://tools.zhequtao.com'; 2 | 3 | function preview(url) { 4 | document.getElementById('preview').setAttribute('href', url); 5 | document.getElementById('img_preview').setAttribute('src', url); 6 | document.getElementById('input_url').value = url; 7 | } 8 | 9 | function generate() { 10 | let path = host + '/ph/'; 11 | let width = parseInt(document.getElementById('input_width').value); 12 | if (width <= 0) { 13 | alert('宽必须大于0'); 14 | return 15 | } 16 | path += width; 17 | 18 | let height = parseInt(document.getElementById('input_height').value); 19 | if (height > 0) { 20 | path += 'x' + height; 21 | } 22 | 23 | let hasParam = false; 24 | let text = document.getElementById('input_text').value; 25 | if (text) { 26 | path += '?t=' + text; 27 | hasParam = true 28 | } 29 | 30 | let bgColor = document.getElementById('input_bg_color').value; 31 | if (bgColor) { 32 | if (!checkHexColor(bgColor)) { 33 | alert('背景颜色取值错误'); 34 | return; 35 | } 36 | path += hasParam ? '&bg=' + bgColor : '?bg=' + bgColor; 37 | hasParam = true 38 | } 39 | 40 | let fgColor = document.getElementById('input_fg_color').value; 41 | if (fgColor) { 42 | if (!checkHexColor(fgColor)) { 43 | alert('前景颜色取值错误'); 44 | return; 45 | } 46 | path += hasParam ? '&fg=' + fgColor : '?fg=' + fgColor 47 | } 48 | 49 | preview(path) 50 | } 51 | 52 | function checkHexColor(s) { 53 | let hexStr = s.toLowerCase(); 54 | let reg = /^([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/; 55 | return hexStr && reg.test(hexStr) 56 | } 57 | 58 | function copyUrl() { 59 | let input_url = document.getElementById('input_url'); 60 | let url = input_url.value; 61 | if (url) { 62 | input_url.select(); 63 | document.execCommand("copy"); 64 | alert("复制成功"); 65 | } 66 | } 67 | 68 | preview(host + '/ph/800x200'); -------------------------------------------------------------------------------- /src/service/placeholder.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gin-gonic/gin" 6 | "math" 7 | "net/http" 8 | "strconv" 9 | "strings" 10 | ) 11 | 12 | const ( 13 | defaultBackground = "CCC" 14 | defaultForeground = "FFF" 15 | ) 16 | 17 | func PlaceHolder(c *gin.Context) { 18 | var err error 19 | // 图片参数 20 | var bg string 21 | var fg string 22 | var text string 23 | var width int 24 | var height int 25 | var fontSize int 26 | 27 | // 确定尺寸 28 | size := c.Param("size") 29 | if size == "" { 30 | c.AbortWithStatus(http.StatusBadRequest) 31 | return 32 | } 33 | sizeArr := strings.Split(size, "x") 34 | l := len(sizeArr) 35 | if l == 1 { 36 | // 方形 37 | width, err = strconv.Atoi(sizeArr[0]) 38 | if err != nil { 39 | c.AbortWithStatus(http.StatusBadRequest) 40 | return 41 | } 42 | height = width 43 | } else if l == 2 { 44 | // 确定宽度 45 | width, err = strconv.Atoi(sizeArr[0]) 46 | if err != nil { 47 | c.AbortWithStatus(http.StatusBadRequest) 48 | return 49 | } 50 | // 确定高度 51 | height, err = strconv.Atoi(sizeArr[1]) 52 | if err != nil { 53 | c.AbortWithStatus(http.StatusBadRequest) 54 | return 55 | } 56 | } else { 57 | c.AbortWithStatus(http.StatusBadRequest) 58 | return 59 | } 60 | 61 | // 文字 62 | text = c.DefaultQuery("t", strconv.Itoa(width)+"x"+strconv.Itoa(height)) 63 | // 背景颜色 64 | bg = c.DefaultQuery("bg", defaultBackground) 65 | // 前景颜色 66 | fg = c.DefaultQuery("fg", defaultForeground) 67 | // 字体大小 68 | fontSize = int(math.Min(float64(width)/float64(len(text)), float64(height))) 69 | 70 | c.Header("Cache-Control", "max-age=3153600") 71 | c.Header("Content-Type", "image/svg+xml") 72 | 73 | // 生成SVG文本 74 | _, err = fmt.Fprintf(c.Writer, `%s`, 75 | width, height, width, height, bg, fontSize, fg, text) 76 | if err != nil { 77 | c.AbortWithStatus(http.StatusInternalServerError) 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | # devTools - golang程序员利器 2 | > 工具的初衷,最大化减少重复性劳动 3 | 4 | ## 效果预览 5 | > json转golang struct 6 | ![img](./asset/json.png) 7 | > mysql转golang struct 8 | ![img](./asset/mysql.png) 9 | 10 | 11 | ## 有哪些功能? 12 | ``` go 13 | r.GET("/base64", contoller.Base64, middleware.UsageCount) 14 | r.GET("/image2base64", contoller.Image2Base64, middleware.UsageCount) 15 | r.GET("/tinyimg", contoller.TinyImage, middleware.UsageCount) 16 | r.GET("/hash", contoller.Hash, middleware.UsageCount) 17 | r.GET("/file-hash", contoller.FileHash, middleware.UsageCount) 18 | r.GET("/ip", contoller.IPInfo, middleware.UsageCount) 19 | r.GET("/json", contoller.JSONView, middleware.UsageCount) 20 | r.GET("/number", contoller.Number, middleware.UsageCount) 21 | r.GET("/placeholder", contoller.Placeholder, middleware.UsageCount) 22 | r.GET("/qrcode", contoller.QRCode, middleware.UsageCount) 23 | r.GET("/regex", contoller.Regex, middleware.UsageCount) 24 | r.GET("/timestamp", contoller.Timestamp, middleware.UsageCount) 25 | r.GET("/color", contoller.Color, middleware.UsageCount) 26 | r.GET("/aes", contoller.AES, middleware.UsageCount) 27 | r.GET("/des", contoller.DES, middleware.UsageCount) 28 | r.GET("/rsa", contoller.RSA, middleware.UsageCount) 29 | r.GET("/morse", contoller.Morse, middleware.UsageCount) 30 | r.GET("/url", contoller.URL, middleware.UsageCount) 31 | r.GET("/unicode", contoller.Unicode, middleware.UsageCount) 32 | r.GET("/json2go", contoller.JSON2GO, middleware.UsageCount) 33 | r.GET("/json2xml", contoller.JSON2XML, middleware.UsageCount) 34 | r.GET("/json2yaml", contoller.JSON2YAML, middleware.UsageCount) 35 | r.GET("/pdf2img", contoller.PDF2IMG, middleware.UsageCount) 36 | ``` 37 | 38 | ## 打包 39 | > go build main.go 40 | > command-line-arguments 41 | > .\main.go:57:7: undefined: InitRouter 42 | 43 | 44 | > Windows下编译Mac, Linux平台的64位可执行程序: 45 | * $ SET CGO_ENABLED=0 SET GOOS=darwin3 SET GOARCH=amd64 go build main.go 46 | * $ SET CGO_ENABLED=0 SET GOOS=linux SET GOARCH=amd64 go build main.go 47 | * $ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build ./src/main.go 48 | 49 | ## 参考 50 | * [tools](https://github.com/wangyiwy/oktools) 51 | * [mysql](https://github.com) 52 | 53 | 54 | ## License 55 | 56 | [MIT](https://github.com/ChinaArJun/devTools/blob/master/LICENSE) -------------------------------------------------------------------------------- /tpl/json2go.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSON转Golang Struct - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 11 | 20 | 21 | 22 | {{template "aside"}} 23 |
24 |
25 |

JSON转Golang Struct

26 |
27 |
28 | 29 |

30 |             
31 |
32 |
33 | 34 | 35 | 36 | 37 |
38 |
39 |
40 | 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /tpl/file_hash.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 文件Hash计算 MD5、SHA1、SHA224、SHA-256、SHA384、SHA512计算 - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {{template "aside"}} 14 |
15 |
16 |

文件Hash计算

17 |
18 | 19 | 20 | 21 | 22 | 23 | 拖拽文件到这里或者点击选择文件 24 | 25 |
26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 |
34 |
35 |
    36 |
  • 可同时选择多个文件计算,
  • 37 |
  • 使用crypto-js 39 | 本地计算,文件不会被上传到服务器。 40 |
  • 41 |
42 |
43 | 44 | 45 |
46 |
47 |
48 | 49 | 50 | -------------------------------------------------------------------------------- /tpl/union_code.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IP地址查询 - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 11 | 12 | {{template "aside"}} 13 |
14 |
15 |

银行联行号信息查询

16 |
17 | 请输入关键词 18 | 19 | 20 |
21 |
22 |
23 |
24 | 65 | 66 | -------------------------------------------------------------------------------- /tpl/ip.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IP地址查询 - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 11 | 12 | {{template "aside"}} 13 |
14 |
15 |

IP地址查询

16 |
17 | IP或域名 18 | 19 | 20 |
21 |
22 |
23 |
24 | 65 | 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [English](./README.md) | [中文](./README_zh.md) 3 | 4 | # devTools - golang programmer's tool 5 | > The original intention of the tool is to minimize repetitive work 6 | 7 | ## Effect preview 8 | > json to golang struct 9 | ![img](./asset/json.png) 10 | > mysql to golang struct 11 | ![img](./asset/mysql.png) 12 | 13 | 14 | ## What functions are there? 15 | ``` go 16 | r.GET("/base64", contoller.Base64, middleware.UsageCount) 17 | r.GET("/image2base64", contoller.Image2Base64, middleware.UsageCount) 18 | r.GET("/tinyimg", contoller.TinyImage, middleware.UsageCount) 19 | r.GET("/hash", contoller.Hash, middleware.UsageCount) 20 | r.GET("/file-hash", contoller.FileHash, middleware.UsageCount) 21 | r.GET("/ip", contoller.IPInfo, middleware.UsageCount) 22 | r.GET("/json", contoller.JSONView, middleware.UsageCount) 23 | r.GET("/number", contoller.Number, middleware.UsageCount) 24 | r.GET("/placeholder", contoller.Placeholder, middleware.UsageCount) 25 | r.GET("/qrcode", contoller.QRCode, middleware.UsageCount) 26 | r.GET("/regex", contoller.Regex, middleware.UsageCount) 27 | r.GET("/timestamp", contoller.Timestamp, middleware.UsageCount) 28 | r.GET("/color", contoller.Color, middleware.UsageCount) 29 | r.GET("/aes", controller.AES, middleware.UsageCount) 30 | r.GET("/des", controller.DES, middleware.UsageCount) 31 | r.GET("/rsa", contoller.RSA, middleware.UsageCount) 32 | r.GET("/morse", contoller.Morse, middleware.UsageCount) 33 | r.GET("/url", contoller.URL, middleware.UsageCount) 34 | r.GET("/unicode", contoller.Unicode, middleware.UsageCount) 35 | r.GET("/json2go", contoller.JSON2GO, middleware.UsageCount) 36 | r.GET("/json2xml", contoller.JSON2XML, middleware.UsageCount) 37 | r.GET("/json2yaml", contoller.JSON2YAML, middleware.UsageCount) 38 | r.GET("/pdf2img", contoller.PDF2IMG, middleware.UsageCount) 39 | ``` 40 | 41 | ## Pack 42 | > go build main.go 43 | > command-line-arguments 44 | > .\main.go:57:7: undefined: InitRouter 45 | 46 | 47 | > Compile 64-bit executable programs for Mac and Linux platforms under Windows: 48 | * $ SET CGO_ENABLED=0 SET GOOS=darwin3 SET GOARCH=amd64 go build main.go 49 | * $ SET CGO_ENABLED=0 SET GOOS=linux SET GOARCH=amd64 go build main.go 50 | * $ CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build ./src/main.go 51 | 52 | ## refer to 53 | * [tools](https://github.com/wangyiwy/oktools) 54 | * [mysql](https://github.com) 55 | 56 | 57 | ## License 58 | 59 | [MIT](https://github.com/ChinaArJun/devTools/blob/master/LICENSE) -------------------------------------------------------------------------------- /src/router/router.go: -------------------------------------------------------------------------------- 1 | package router 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "net/http" 6 | "oktools/src/contoller" 7 | "oktools/src/middleware" 8 | "oktools/src/service" 9 | ) 10 | 11 | func InitRouter() *gin.Engine { 12 | r := gin.Default() 13 | 14 | r.Static("/static", "./static") 15 | r.LoadHTMLGlob("./tpl/*") 16 | 17 | r.GET("/favicon.ico", func(c *gin.Context) { 18 | c.Header("Cache-Control", "max-age=3153600") 19 | c.File("./static/favicon.ico") 20 | }) 21 | 22 | r.GET("/", contoller.Index) 23 | r.GET("/ping", contoller.Ping) 24 | r.GET("/uptime", contoller.Uptime) 25 | r.GET("/ph/:size", service.PlaceHolder) 26 | 27 | r.GET("/base64", contoller.Base64, middleware.UsageCount) 28 | r.GET("/image2base64", contoller.Image2Base64, middleware.UsageCount) 29 | r.GET("/tinyimg", contoller.TinyImage, middleware.UsageCount) 30 | r.GET("/hash", contoller.Hash, middleware.UsageCount) 31 | r.GET("/file-hash", contoller.FileHash, middleware.UsageCount) 32 | r.GET("/ip", contoller.IPInfo, middleware.UsageCount) 33 | r.GET("/json", contoller.JSONView, middleware.UsageCount) 34 | r.GET("/number", contoller.Number, middleware.UsageCount) 35 | r.GET("/placeholder", contoller.Placeholder, middleware.UsageCount) 36 | r.GET("/qrcode", contoller.QRCode, middleware.UsageCount) 37 | r.GET("/regex", contoller.Regex, middleware.UsageCount) 38 | r.GET("/timestamp", contoller.Timestamp, middleware.UsageCount) 39 | r.GET("/color", contoller.Color, middleware.UsageCount) 40 | r.GET("/aes", contoller.AES, middleware.UsageCount) 41 | r.GET("/des", contoller.DES, middleware.UsageCount) 42 | r.GET("/rsa", contoller.RSA, middleware.UsageCount) 43 | r.GET("/morse", contoller.Morse, middleware.UsageCount) 44 | r.GET("/url", contoller.URL, middleware.UsageCount) 45 | r.GET("/unicode", contoller.Unicode, middleware.UsageCount) 46 | r.GET("/union_code", contoller.UnionCode, middleware.UsageCount) 47 | r.GET("/mysqlgo", contoller.MYSQLGO, middleware.UsageCount) 48 | r.GET("/json2go", contoller.JSON2GO, middleware.UsageCount) 49 | r.GET("/json2xml", contoller.JSON2XML, middleware.UsageCount) 50 | r.GET("/json2yaml", contoller.JSON2YAML, middleware.UsageCount) 51 | r.GET("/pdf2img", contoller.PDF2IMG, middleware.UsageCount) 52 | r.GET("/fund", contoller.FundIndex, middleware.UsageCount) 53 | 54 | r.GET("/xinpianchang", contoller.Xinpianchang, middleware.UsageCount) 55 | r.GET("/websocket", func(c *gin.Context) { 56 | c.Redirect(http.StatusMovedPermanently, "/websocket") 57 | }) 58 | 59 | api := r.Group("/api") 60 | { 61 | api.GET("/ip/:query", service.IPInfo) 62 | } 63 | return r 64 | } 65 | -------------------------------------------------------------------------------- /tpl/number.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 进制转换 二、八、十、十六进制转换 - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 11 | 12 | {{template "aside"}} 13 |
14 |
15 |

进制转换

16 |
17 | 25 | 26 | 27 |
28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 |
2进制4进制8进制10进制16进制32进制
43 |
44 |
    45 |
  • 只支持整数之间的转换,
  • 46 |
  • JavaScript中的基本数据类Number是双精度浮点数,可以转换的数字取值范围在-2^53~2^53,即十进制的-9007199254740991~9007199254740991。 47 |
  • 48 |
49 |
50 |
51 |
52 | 66 | 67 | -------------------------------------------------------------------------------- /tpl/tinyimg.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 图片压缩 - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 18 | 19 | 20 | {{template "aside"}} 21 |
22 |
23 |

图片压缩

24 |
25 | 26 | 28 | 29 | 30 | 31 | 选择一张图片 32 | 33 | 34 |
35 |
36 |

37 |
38 | 48 |
49 | 50 | 51 |
52 |
53 |
54 |

55 |
56 | 使用JavaScript进行压缩,图片不会被上传到服务器。 57 |
58 |
59 |
60 | 61 | 62 | -------------------------------------------------------------------------------- /src/conf/config.go: -------------------------------------------------------------------------------- 1 | package conf 2 | 3 | import ( 4 | "gopkg.in/yaml.v2" 5 | "io/ioutil" 6 | "log" 7 | "os" 8 | ) 9 | 10 | type Config struct { 11 | App struct { 12 | Mode string `yaml:"mode"` 13 | LogFile string `yaml:"log-file"` 14 | } `yaml:"app"` 15 | Http struct { 16 | Port string `yaml:"port"` 17 | SSL struct { 18 | Enable bool `yaml:"enable"` 19 | Crt string `yaml:"crt"` 20 | Key string `yaml:"key"` 21 | } `yaml:"ssl"` 22 | } `yaml:"http"` 23 | Postgresdb struct { 24 | Host string `yaml:"host"` 25 | Port string `yaml:"port"` 26 | Username string `yaml:"username"` 27 | Password string `yaml:"password"` 28 | DbName string `yaml:"dbname"` 29 | } `yaml:"postgresdb"` 30 | Mysqldb struct { 31 | Host string `yaml:"host"` 32 | Port string `yaml:"port"` 33 | Username string `yaml:"username"` 34 | Password string `yaml:"password"` 35 | DbName string `yaml:"dbname"` 36 | MaxId string `yaml:"maxId"` 37 | MaxOpen string `yaml:"maxOpen"` 38 | Log string `yaml:"log"` 39 | } `yaml:"mysqldb"` 40 | ThirdParty struct { 41 | Amap struct { 42 | Key string `yaml:"key"` 43 | } `yaml:"amap"` 44 | ServerChan struct { 45 | Key string `yaml:"key"` 46 | } `yaml:"serverchan"` 47 | } `yaml:"third-party"` 48 | } 49 | 50 | // 51 | //type Config struct { 52 | // App struct { 53 | // Mode string `yaml:"mode"` 54 | // LogFile string `yaml:"log-file"` 55 | // } `yaml:"app"` 56 | // Http struct { 57 | // Port string `yaml:"port"` 58 | // SSL struct { 59 | // Enable bool `yaml:"enable"` 60 | // Crt string `yaml:"crt"` 61 | // Key string `yaml:"key"` 62 | // } `yaml:"ssl"` 63 | // } `yaml:"http"` 64 | // Database struct { 65 | // Host string `yaml:"host"` 66 | // Port string `yaml:"port"` 67 | // Username string `yaml:"username"` 68 | // Password string `yaml:"password"` 69 | // DbName string `yaml:"dbname"` 70 | // } `yaml:"database"` 71 | // ThirdParty struct { 72 | // Amap struct { 73 | // Key string `yaml:"key"` 74 | // } `yaml:"amap"` 75 | // ServerChan struct { 76 | // Key string `yaml:"key"` 77 | // } `yaml:"serverchan"` 78 | // } `yaml:"third-party"` 79 | //} 80 | 81 | var Conf = &Config{} 82 | 83 | func init() { 84 | var conf string 85 | if len(os.Args) == 2 { 86 | conf = os.Args[1] 87 | } 88 | if conf == "" { 89 | conf = "conf.yaml" 90 | } 91 | 92 | data, err := ioutil.ReadFile(conf) 93 | if err != nil { 94 | log.Fatalln(err) 95 | } 96 | 97 | err = yaml.UnmarshalStrict(data, &Conf) 98 | if err != nil { 99 | log.Fatalln(err) 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /static/js/timestamp.js: -------------------------------------------------------------------------------- 1 | const dateFormat = 'yyyy-MM-dd hh:mm:ss'; 2 | 3 | Date.prototype.format = function (fmt) { 4 | let o = { 5 | "M+": this.getMonth() + 1, 6 | "d+": this.getDate(), 7 | "h+": this.getHours(), 8 | "m+": this.getMinutes(), 9 | "s+": this.getSeconds(), 10 | "q+": Math.floor((this.getMonth() + 3) / 3), 11 | "s": this.getMilliseconds() 12 | }; 13 | if (/(y+)/.test(fmt)) { 14 | fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); 15 | } 16 | for (let k in o) { 17 | if (new RegExp("(" + k + ")").test(fmt)) { 18 | fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); 19 | } 20 | } 21 | return fmt; 22 | }; 23 | 24 | let date = new Date(); 25 | let time_now = document.getElementById('time_now'); 26 | time_now.value = Math.round(date / 1000).toString(); 27 | document.getElementById('input_time').value = Math.round(date / 1000); 28 | document.getElementById('input_date').value = date.format(dateFormat); 29 | 30 | function updateTime() { 31 | let unit = document.getElementById('select_now_unit').value; 32 | if (unit === 's') { 33 | time_now.value = Math.round(new Date() / 1000).toString(); 34 | } else if (unit === 'ms') { 35 | time_now.value = new Date().getTime().toString(); 36 | } 37 | } 38 | 39 | let handle = setInterval(updateTime, 1000); 40 | 41 | function startUpdate(e) { 42 | window.clearInterval(handle); 43 | handle = setInterval(updateTime, 1000); 44 | e.classList.add('primary') 45 | } 46 | 47 | function stopUpdate(e) { 48 | window.clearInterval(handle); 49 | e.parentElement.firstElementChild.classList.remove('primary') 50 | } 51 | 52 | function timeToDate() { 53 | let input = document.getElementById('input_time').value; 54 | let unit = document.getElementById('select_input_unit').value; 55 | let output_date = document.getElementById('output_date'); 56 | if (unit === 's') { 57 | output_date.value = new Date(input * 1000).format(dateFormat); 58 | } else if (unit === 'ms') { 59 | output_date.value = new Date(parseInt(input)).format(dateFormat); 60 | } 61 | } 62 | 63 | function dateToTime() { 64 | let input = document.getElementById('input_date').value.replace(/-/g, "/"); 65 | let unit = document.getElementById('select_output_unit').value; 66 | let output_time = document.getElementById('output_time'); 67 | if (unit === 's') { 68 | output_time.value = new Date(input).getTime() / 1000; 69 | } else if (unit === 'ms') { 70 | output_time.value = new Date(input).getTime(); 71 | } 72 | } -------------------------------------------------------------------------------- /tpl/json.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSON格式化 - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 11 | 12 | 29 | 30 | 31 | {{template "aside"}} 32 |
33 |
34 |

JSON格式化

35 |
36 |
37 |
38 |
39 | 42 | 45 | 46 |
47 |
48 |
49 |
50 |
51 |
52 | 53 | 73 | 74 | -------------------------------------------------------------------------------- /static/js/websocket.js: -------------------------------------------------------------------------------- 1 | const dateFormat = 'yyyy-MM-dd hh:mm:ss'; 2 | 3 | Date.prototype.format = function (fmt) { 4 | let o = { 5 | "M+": this.getMonth() + 1, 6 | "d+": this.getDate(), 7 | "h+": this.getHours(), 8 | "m+": this.getMinutes(), 9 | "s+": this.getSeconds(), 10 | "q+": Math.floor((this.getMonth() + 3) / 3), 11 | "s": this.getMilliseconds() 12 | }; 13 | if (/(y+)/.test(fmt)) { 14 | fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length)); 15 | } 16 | for (let k in o) { 17 | if (new RegExp("(" + k + ")").test(fmt)) { 18 | fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))); 19 | } 20 | } 21 | return fmt; 22 | }; 23 | 24 | let ws; 25 | const msg_list = document.getElementById('msg_list'); 26 | 27 | function addMsg(msg) { 28 | msg_list.innerHTML += msg; 29 | msg_list.scrollTop = msg_list.scrollHeight; 30 | } 31 | 32 | function cleanup() { 33 | msg_list.innerHTML = ''; 34 | } 35 | 36 | function send() { 37 | if (ws) { 38 | let input_msg = document.getElementById('input_msg'); 39 | let text = input_msg.value; 40 | if (text) { 41 | ws.send(text); 42 | input_msg.value = ''; 43 | addMsg(`

客户端:${new Date().format(dateFormat)}

${text}

`) 44 | } 45 | } 46 | } 47 | 48 | function connect(btn) { 49 | if (!"WebSocket" in window) { 50 | alert("您的浏览器不支持 WebSocket!"); 51 | } 52 | 53 | let server = document.getElementById('input_server').value; 54 | if (!server) { 55 | return 56 | } 57 | 58 | try { 59 | ws = new WebSocket(server); 60 | } catch (e) { 61 | addMsg(`

${e}

`); 62 | return; 63 | } 64 | 65 | ws.onopen = function () { 66 | btn.classList.add('primary'); 67 | addMsg(`

连接成功,可发送消息到服务端

`) 68 | }; 69 | ws.onmessage = function (e) { 70 | addMsg(`

服务端:${new Date().format(dateFormat)}

${e.data}

`) 71 | }; 72 | ws.onclose = function () { 73 | ws = null; 74 | btn.classList.remove('primary'); 75 | addMsg(`

连接已关闭

`) 76 | }; 77 | ws.onerror = function (e) { 78 | btn.classList.remove('primary'); 79 | addMsg(`

${e}

`) 80 | } 81 | } 82 | 83 | function disconnect() { 84 | if (ws) { 85 | ws.close(); 86 | ws = null 87 | } 88 | } 89 | 90 | document.getElementById('input_msg').addEventListener('keydown', function (event) { 91 | if (event.keyCode === 13) { 92 | send() 93 | } 94 | }); -------------------------------------------------------------------------------- /src/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gin-gonic/gin" 6 | "io/ioutil" 7 | "log" 8 | "net/http" 9 | _ "net/http/pprof" 10 | "net/url" 11 | "oktools/src/conf" 12 | "oktools/src/contoller" 13 | "oktools/src/middleware" 14 | "oktools/src/router" 15 | "os" 16 | "time" 17 | ) 18 | 19 | func main() { 20 | gin.SetMode(conf.Conf.App.Mode) 21 | 22 | if gin.Mode() == gin.ReleaseMode { 23 | // Release模式 24 | gin.DisableConsoleColor() 25 | 26 | logfile := conf.Conf.App.LogFile 27 | if logfile == "" { 28 | log.Fatalln("Please set the log file path!") 29 | } 30 | 31 | file, err := os.OpenFile(logfile, os.O_RDWR|os.O_CREATE|os.O_APPEND, os.ModePerm) 32 | if err != nil { 33 | file, err = os.Create(logfile) 34 | if file == nil { 35 | log.Fatalln(err) 36 | } 37 | } 38 | 39 | defer func() { 40 | err := file.Close() 41 | if err != nil { 42 | log.Fatalln(err) 43 | } 44 | }() 45 | 46 | gin.DefaultWriter = file 47 | log.SetOutput(file) 48 | } else { 49 | // Debug模式 50 | go func() { 51 | err := http.ListenAndServe(":6060", nil) 52 | if err != nil { 53 | log.Fatalln(err) 54 | } 55 | }() 56 | } 57 | 58 | r := router.InitRouter() 59 | 60 | var err error 61 | if gin.Mode() == gin.ReleaseMode { 62 | serverChan("DevTools server started") 63 | 64 | runNoTLS() 65 | err = r.RunTLS(":"+conf.Conf.Http.Port, conf.Conf.Http.SSL.Crt, conf.Conf.Http.SSL.Key) 66 | } else { 67 | err = r.Run(":" + conf.Conf.Http.Port) 68 | } 69 | 70 | if err != nil { 71 | if gin.Mode() == gin.ReleaseMode { 72 | serverChan("DevTools server stopped") 73 | } 74 | log.Fatalln("Something terrible happened:", err) 75 | } 76 | } 77 | 78 | func serverChan(msg string) { 79 | key := conf.Conf.ThirdParty.ServerChan.Key 80 | msg += time.Now().Format(" - 2006-01-02 15:04:05") 81 | 82 | resp, err := http.Get(fmt.Sprintf("https://sc.ftqq.com/%s.send?text=%s", key, url.QueryEscape(msg))) 83 | if err == nil { 84 | bytes, _ := ioutil.ReadAll(resp.Body) 85 | log.Println("ServerChan resp:", string(bytes)) 86 | } else { 87 | log.Println("ServerChan error:", err) 88 | } 89 | } 90 | 91 | func runNoTLS() { 92 | go func() { 93 | e := gin.Default() 94 | e.LoadHTMLFiles("./tpl/websocket.html", "./tpl/aside.html") 95 | 96 | e.GET("/*path", func(c *gin.Context) { 97 | uri := c.Request.RequestURI 98 | if "/websocket" == uri { 99 | contoller.WebSocket(c) 100 | middleware.UsageCount(c) 101 | } else { 102 | c.Redirect(http.StatusMovedPermanently, "/websocket"+uri) 103 | } 104 | }) 105 | 106 | err := e.Run(":" + conf.Conf.Http.Port) 107 | if err != nil { 108 | log.Fatalln("Something terrible happened:", err) 109 | } 110 | }() 111 | } 112 | -------------------------------------------------------------------------------- /tpl/rsa.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | RSA加密、RSA解密 - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {{template "aside"}} 14 |
15 |
16 |

RSA加密/解密

17 |
18 |
19 |

Private Key

20 | 21 |
22 |
23 |
24 | 30 | 31 |
32 |
33 |
34 |

Public Key

35 | 36 |
37 |
38 |
39 |
40 |

原文

41 | 42 |
43 |
44 |
45 | 49 | 53 |
54 |
55 |
56 |

密文

57 | 58 |
59 |
60 |
61 |
62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/service/ip.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "errors" 7 | "github.com/gin-gonic/gin" 8 | "io/ioutil" 9 | "log" 10 | "net" 11 | "net/http" 12 | "oktools/src/conf" 13 | "oktools/src/util" 14 | ) 15 | 16 | func IPInfo(c *gin.Context) { 17 | param := c.Param("query") 18 | if param == "" { 19 | c.AbortWithStatus(http.StatusBadRequest) 20 | return 21 | } 22 | 23 | var addrs [] string 24 | if util.CheckIPV4(param) { 25 | // 是IPV4 26 | addrs = append(addrs, param) 27 | } else { 28 | // 根据域名查询 29 | var err error 30 | addrs, err = net.LookupHost(param) 31 | if err != nil { 32 | c.AbortWithStatus(http.StatusBadRequest) 33 | log.Println(err) 34 | return 35 | } 36 | } 37 | 38 | buf, err := getByAmap(addrs) 39 | if err != nil { 40 | buf = getByTaobao(addrs) 41 | } 42 | 43 | c.Data(http.StatusOK, "application/json; charset=utf-8", buf.Bytes()) 44 | } 45 | 46 | func getByAmap(addrs [] string) (*bytes.Buffer, error) { 47 | var buf bytes.Buffer 48 | buf.WriteString("[") 49 | for k, v := range addrs { 50 | resp, err := http.Get("https://restapi.amap.com/v3/ip?key=" + conf.Conf.ThirdParty.Amap.Key + "&ip=" + v) 51 | if err != nil { 52 | log.Println(err) 53 | return nil, err 54 | } 55 | if http.StatusOK != resp.StatusCode { 56 | return nil, errors.New("Failed to get ip data from amap , StatusCode : " + resp.Status) 57 | } 58 | 59 | data := gin.H{} 60 | err = json.NewDecoder(resp.Body).Decode(&data) 61 | if err != nil { 62 | log.Println(err) 63 | return nil, err 64 | } 65 | 66 | if data["status"] != "1" { 67 | err = errors.New("Failed to get ip data from amap , info : " + data["info"].(string)) 68 | log.Println(err) 69 | return nil, err 70 | } 71 | 72 | data["ip"] = v 73 | data["status"] = nil 74 | data["info"] = nil 75 | data["infocode"] = nil 76 | 77 | b, err := json.Marshal(data) 78 | if err != nil { 79 | log.Println(err) 80 | return nil, err 81 | } 82 | 83 | if k > 0 { 84 | buf.WriteString(",") 85 | } 86 | buf.Write(b) 87 | } 88 | buf.WriteString("]") 89 | return &buf, nil 90 | } 91 | 92 | func getByTaobao(addrs [] string) *bytes.Buffer { 93 | var buf bytes.Buffer 94 | buf.WriteString("[") 95 | for k, v := range addrs { 96 | resp, err := http.Get("http://ip.taobao.com/service/getIpInfo.php?ip=" + v) 97 | if err != nil { 98 | log.Println(err) 99 | continue 100 | } 101 | 102 | if http.StatusOK != resp.StatusCode { 103 | log.Println("Failed to get ip data from taobao :", resp.Status) 104 | continue 105 | } 106 | 107 | data, err := ioutil.ReadAll(resp.Body) 108 | if err != nil { 109 | log.Println(err) 110 | continue 111 | } 112 | 113 | if k > 0 { 114 | buf.WriteString(",") 115 | } 116 | buf.Write(data) 117 | } 118 | buf.WriteString("]") 119 | return &buf 120 | } 121 | -------------------------------------------------------------------------------- /tpl/color.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 颜色值转换 RGB转HEX、RGB转HSL。RGB,RGBA,HEX,HSL互转 - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 26 | 27 | 28 | {{template "aside"}} 29 |
30 |
31 |

颜色值转换

32 |
33 | 颜色值 34 | 35 | 36 |
37 |
38 | 输入示例(大小写不敏感): 39 | #707B7C 40 | #AAF7DC6F 42 | rgb(72,201,176) 44 | rgba(241,148,138,0.5) 46 | hsl(204,70%,63%) 47 |
48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 |
预览格式转换结果
58 |

CSS颜色表

59 |
60 | HTML 和 CSS 颜色规范中定义了 147 中颜色名(17 种标准颜色加 130 种其他颜色)。下面的表格中列出了所有这些颜色,以及它们的十六进制值。 61 |
62 | 17 种标准色是 aqua, black, blue, fuchsia, gray, green, lime, maroon, navy, olive, orange, purple, red, 63 | silver, 64 | teal, white, yellow。 65 |
66 |
67 |
68 |
69 | 70 | 71 | -------------------------------------------------------------------------------- /tpl/aside.html: -------------------------------------------------------------------------------- 1 | {{define "aside"}} 2 | 55 | 71 | {{end}} -------------------------------------------------------------------------------- /tpl/aes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AES加密、AES解密 - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {{template "aside"}} 14 |
15 |
16 |

AES加密/解密

17 | 18 |
19 | 模式 20 | 27 | 填充 28 | 36 | 偏移量 37 | 38 | 密文编码 39 | 43 |
44 |
45 | 密钥 46 | 47 | 51 | 55 | 58 |
59 | 60 |
61 |
62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /tpl/des.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DES加密、DES解密 - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {{template "aside"}} 14 |
15 |
16 |

DES加密/解密

17 | 18 |
19 | 模式 20 | 27 | 填充 28 | 36 | 偏移量 37 | 38 | 密文编码 39 | 43 |
44 |
45 | 密钥 46 | 47 | 51 | 55 | 58 |
59 | 60 |
61 |
62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /tpl/placeholder.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SVG占位图 - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 11 | 12 | {{template "aside"}} 13 |
14 |
15 |

SVG占位图

16 |
17 | 18 |
19 |
20 |
21 |
22 | 27 |
28 |
29 | 34 |
35 |
36 | 40 |
41 |
42 | 46 |
47 |
48 | 52 |
53 |
54 |
55 | 56 | 57 |
58 | 59 |
60 |

使用方式

61 |
62 |
    63 |
  • https://tools.zhequtao.com/ph/[width]x[height]
  • 64 |
  • https://tools.zhequtao.com/ph/[width]x[height]?t=[文字]&bg=[背景颜色]&fg=[文字颜色]
  • 65 |
66 |
67 |
68 |
69 | 70 | 71 | -------------------------------------------------------------------------------- /sql/tools.mysql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat Premium Data Transfer 3 | 4 | Source Server : pgsql-localhost 5 | Source Server Type : PostgreSQL 6 | Source Server Version : 110002 7 | Source Host : localhost:5432 8 | Source Catalog : oktools 9 | Source Schema : oktools 10 | 11 | Target Server Type : PostgreSQL 12 | Target Server Version : 110002 13 | File Encoding : 65001 14 | 15 | Date: 24/09/2019 12:51:40 16 | */ 17 | 18 | 19 | -- ---------------------------- 20 | -- Table structure for toolshttps://item.m.jd.com/product/10024996935738.html?wxa_abtest=o&utm_source=iosapp&utm_medium=appshare&utm_campaign=t_335139774&utm_term=CopyURL&ad_od=share 21 | -- ---------------------------- 22 | use oktools; 23 | CREATE TABLE `tools` ( 24 | `path` varchar(255) NOT NULL DEFAULT '' COMMENT '' , 25 | `title` varchar(255) NOT NULL DEFAULT '' COMMENT '', 26 | `icon` varchar(255) NOT NULL DEFAULT '' COMMENT '', 27 | `category` int(64) NOT NULL DEFAULT 0, 28 | `usage_count` int(64) NOT NULL DEFAULT 0 29 | ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8 COMMENT='分类'; 30 | 31 | -- ---------------------------- 32 | -- Records of tools 33 | -- ---------------------------- 34 | INSERT INTO `tools` VALUES ('/json2yaml', 'JSON/YAML转换', '', 0, 0); 35 | INSERT INTO `tools` VALUES ('/json2go', 'JSON转Go Struct', '', 0, 0); 36 | INSERT INTO `tools` VALUES ('/unicode', 'Unicode编码转换', '', 0, 0); 37 | INSERT INTO `tools` VALUES ('/url', 'URL编码解码', '', 0, 0); 38 | INSERT INTO `tools` VALUES ('/hash', 'Hash计算', '', 0, 0); 39 | INSERT INTO `tools` VALUES ('/morse', '摩斯电码', '', 0, 0); 40 | INSERT INTO `tools` VALUES ('/number', '进制转换', '', 0, 0); 41 | INSERT INTO `tools` VALUES ('/websocket', 'WebSocket测试', '', 0, 0); 42 | INSERT INTO `tools` VALUES ('/timestamp', 'Unix时间戳', '', 0, 0); 43 | INSERT INTO `tools` VALUES ('/regex', '正则表达式测试', '', 0, 0); 44 | INSERT INTO `tools` VALUES ('/qrcode', '二维码制作', '', 0, 0); 45 | INSERT INTO `tools` VALUES ('/ip', 'IP地址信息', '', 0, 0); 46 | INSERT INTO `tools` VALUES ('/file-hash', '文件Hash计算', '', 0, 0); 47 | INSERT INTO `tools` VALUES ('/rsa', 'RSA加密解密', '', 0, 0); 48 | INSERT INTO `tools` VALUES ('/des', 'DES加密解密', '', 0, 0); 49 | INSERT INTO `tools` VALUES ('/aes', 'AES加密解密', '', 0, 0); 50 | INSERT INTO `tools` VALUES ('/color', '颜色值转换', '', 0, 0); 51 | INSERT INTO `tools` VALUES ('/image2base64', '图片Base64编码', '', 0, 0); 52 | INSERT INTO `tools` VALUES ('/base64', 'Base64编码解码', '', 0, 0); 53 | INSERT INTO `tools` VALUES ('/json', 'JSON格式化', '', 0, 0); 54 | INSERT INTO `tools` VALUES ('/placeholder', 'SVG占位图', '', 0, 0); 55 | INSERT INTO `tools` VALUES ('/tinyimg', '图片压缩', '', 0, 0); 56 | INSERT INTO `tools` VALUES ('/json2xml', 'JSON/XML转换', '', 0, 0); 57 | INSERT INTO `tools` VALUES ('/clocks', 'CSS时钟', '', 0, 0); 58 | INSERT INTO `tools` VALUES ('/pdf2img', 'PDF转图片', '', 0, 0); 59 | INSERT INTO `tools` VALUES ('/fund', '基金数据', '', 0, 0); 60 | -- ---------------------------- 61 | -- Primary Key structure for table tools 62 | -- ---------------------------- 63 | ALTER TABLE `tools` ADD CONSTRAINT "tools_pkey" PRIMARY KEY ("path"); 64 | -------------------------------------------------------------------------------- /tpl/url.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | URL编码、URL解码 - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {{template "aside"}} 14 |
15 |
16 |

URL编码/解码

17 | 18 |
19 | 23 | 27 | 28 |
29 |

encodeURI:

30 | 31 |

encodeURIComponent:

32 | 34 |
35 |
    36 |
  • encodeURI()是Javascript中用来对URL编码的函数。它着眼于对整个URL进行编码,因此除了常见的符号以外,对其他一些在网址中有特殊含义的符号"; / ? : @ & 37 | = + $ , #",也不进行编码。编码后,它输出符号的utf-8形式,并且在每个字节前加上%。 38 |
  • 39 |
  • encodeURIComponent()与encodeURI()的区别是,它用于对URL的组成部分进行个别编码,而不用于对整个URL进行编码。因此"; / ? : @ & = + $ 40 | , #",这些在encodeURI()中不被编码的符号,在encodeURIComponent()中统统会被编码。至于具体的编码方法,两者是一样。 41 |
  • 42 |
43 |
44 |
45 |
46 | 70 | 71 | -------------------------------------------------------------------------------- /static/js/morse.js: -------------------------------------------------------------------------------- 1 | const standard = { 2 | 'A': '01', 3 | 'B': '1000', 4 | 'C': '1010', 5 | 'D': '100', 6 | 'E': '0', 7 | 'F': '0010', 8 | 'G': '110', 9 | 'H': '0000', 10 | 'I': '00', 11 | 'J': '0111', 12 | 'K': '101', 13 | 'L': '0100', 14 | 'M': '11', 15 | 'N': '10', 16 | 'O': '111', 17 | 'P': '0110', 18 | 'Q': '1101', 19 | 'R': '010', 20 | 'S': '000', 21 | 'T': '1', 22 | 'U': '001', 23 | 'V': '0001', 24 | 'W': '011', 25 | 'X': '1001', 26 | 'Y': '1011', 27 | 'Z': '1100', 28 | '0': '11111', 29 | '1': '01111', 30 | '2': '00111', 31 | '3': '00011', 32 | '4': '00001', 33 | '5': '00000', 34 | '6': '10000', 35 | '7': '11000', 36 | '8': '11100', 37 | '9': '11110', 38 | '.': '010101', 39 | ',': '110011', 40 | '?': '001100', 41 | '\'': '011110', 42 | '!': '101011', 43 | '/': '10010', 44 | '(': '10110', 45 | ')': '101101', 46 | '&': '01000', 47 | ':': '111000', 48 | ';': '101010', 49 | '=': '10001', 50 | '+': '01010', 51 | '-': '100001', 52 | '_': '001101', 53 | '"': '010010', 54 | '$': '0001001', 55 | '@': '011010', 56 | }; 57 | const option = ['/', '.', '-']; 58 | let standardReverse = {}; 59 | for (let key in standard) { 60 | standardReverse[standard[key]] = key; 61 | } 62 | 63 | function unicodeHexMorse(ch) { 64 | let r = []; 65 | for (let i = 0; i < ch.length; i++) 66 | r[i] = ('00' + ch.charCodeAt(i).toString(16)).slice(-4); 67 | r = r.join(''); 68 | r = parseInt(r, 16).toString(2); 69 | return r; 70 | } 71 | 72 | function _encode(msg) { 73 | let morse = []; 74 | msg = msg.replace(/\s+/g, '').toLocaleUpperCase().split(''); 75 | let ch, r; 76 | for (let i = 0, l = msg.length; i < l; i++) { 77 | ch = msg[i]; 78 | r = standard[ch]; 79 | if (!r) r = unicodeHexMorse(ch); 80 | morse.push(r.replace(/0/g, option[1]).replace(/1/g, option[2])); 81 | } 82 | return morse.join(option[0]); 83 | } 84 | 85 | function morseHexUnicode(mor) { 86 | mor = parseInt(mor, 2); 87 | if (isNaN(mor)) return ''; 88 | return unescape('%u' + mor.toString(16)); 89 | } 90 | 91 | function _decode(morse) { 92 | let msg = []; 93 | morse = morse.split(option[0]); 94 | let mor, r; 95 | for (let i = 0, l = morse.length; i < l; i++) { 96 | mor = morse[i].replace(/\s+/g, '') 97 | .replace(new RegExp('\\' + option[1], 'g'), '0') 98 | .replace(new RegExp('\\' + option[2], 'g'), '1'); 99 | r = standardReverse[mor]; 100 | if (!r) r = morseHexUnicode(mor); 101 | msg.push(r); 102 | } 103 | return msg.join(''); 104 | } 105 | 106 | let area_input = document.getElementById('area_input'); 107 | let area_output = document.getElementById('area_output'); 108 | 109 | function encode() { 110 | area_output.value = _encode(area_input.value) 111 | } 112 | 113 | function decode() { 114 | area_input.value = _decode(area_output.value) 115 | } 116 | 117 | function cleanup() { 118 | area_input.value = ''; 119 | area_output.value = ''; 120 | } -------------------------------------------------------------------------------- /tpl/xinpianchang.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Unicode转中文、中文Unicode编码、ASCII转Unicode、Unicode转ASCII - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {{template "aside"}} 14 |
15 |
16 |

新片场下载链接获取

17 | 18 |
19 | 23 | 24 |
25 | 26 |
27 |
28 | 90 | 91 | -------------------------------------------------------------------------------- /static/js/encrypt_aes.js: -------------------------------------------------------------------------------- 1 | function encrypt() { 2 | let text = document.getElementById('area_text').value; 3 | if (text) { 4 | let key = CryptoJS.enc.Utf8.parse(document.getElementById('input_key').value); 5 | try { 6 | let encrypted = CryptoJS.AES.encrypt(text, key, buildConfig()); 7 | let encode = document.getElementById('select_output_encode').value; 8 | let cipherText = encrypted.toString(); 9 | if (encode === 'HEX') { 10 | cipherText = CryptoJS.enc.Hex.stringify(CryptoJS.enc.Base64.parse(cipherText)); 11 | } 12 | document.getElementById('area_cipher_text').value = cipherText; 13 | } catch (e) { 14 | alert(e) 15 | } 16 | } 17 | } 18 | 19 | function decrypt() { 20 | let text = document.getElementById('area_cipher_text').value; 21 | if (text) { 22 | let encode = document.getElementById('select_output_encode').value; 23 | let cipherText; 24 | if (encode === 'Base64') { 25 | cipherText = CryptoJS.enc.Base64.parse(text) 26 | } else if (encode === 'HEX') { 27 | cipherText = CryptoJS.enc.Hex.parse(text) 28 | } 29 | let key = CryptoJS.enc.Utf8.parse(document.getElementById('input_key').value); 30 | try { 31 | let decrypted = CryptoJS.AES.decrypt({ 32 | ciphertext: cipherText 33 | }, key, buildConfig()); 34 | document.getElementById('area_text').value = decrypted.toString(CryptoJS.enc.Utf8); 35 | } catch (e) { 36 | alert(e) 37 | } 38 | } 39 | } 40 | 41 | function buildConfig() { 42 | let mode = document.getElementById('select_mode').value; 43 | let pad = document.getElementById('select_pad').value; 44 | let conf = {}; 45 | switch (mode) { 46 | case 'CBC': 47 | conf.mode = CryptoJS.mode.CBC; 48 | break; 49 | case 'CFB': 50 | conf.mode = CryptoJS.mode.CFB; 51 | break; 52 | case 'CTR': 53 | conf.mode = CryptoJS.mode.CTR; 54 | break; 55 | case 'OFB': 56 | conf.mode = CryptoJS.mode.OFB; 57 | break; 58 | case 'ECB': 59 | conf.mode = CryptoJS.mode.ECB; 60 | break; 61 | } 62 | switch (pad) { 63 | case 'Pkcs7': 64 | conf.padding = CryptoJS.pad.Pkcs7; 65 | break; 66 | case 'Iso97971': 67 | conf.padding = CryptoJS.pad.Iso97971; 68 | break; 69 | case 'AnsiX923': 70 | conf.padding = CryptoJS.pad.AnsiX923; 71 | break; 72 | case 'Iso10126': 73 | conf.padding = CryptoJS.pad.Iso10126; 74 | break; 75 | case 'ZeroPadding': 76 | conf.padding = CryptoJS.pad.ZeroPadding; 77 | break; 78 | case 'NoPadding': 79 | conf.padding = CryptoJS.pad.NoPadding; 80 | break; 81 | } 82 | conf.iv = CryptoJS.enc.Utf8.parse(document.getElementById('input_iv').value); 83 | return conf 84 | } 85 | 86 | function cleanup() { 87 | document.getElementById('area_text').value = ''; 88 | document.getElementById('area_cipher_text').value = ''; 89 | document.getElementById('input_key').value = ''; 90 | document.getElementById('input_iv').value = ''; 91 | } -------------------------------------------------------------------------------- /static/js/encrypt_des.js: -------------------------------------------------------------------------------- 1 | function encrypt() { 2 | let text = document.getElementById('area_text').value; 3 | if (text) { 4 | let key = CryptoJS.enc.Utf8.parse(document.getElementById('input_key').value); 5 | try { 6 | let encrypted = CryptoJS.DES.encrypt(text, key, buildConfig()); 7 | let encode = document.getElementById('select_output_encode').value; 8 | let cipherText = encrypted.toString(); 9 | if (encode === 'HEX') { 10 | cipherText = CryptoJS.enc.Hex.stringify(CryptoJS.enc.Base64.parse(cipherText)); 11 | } 12 | document.getElementById('area_cipher_text').value = cipherText; 13 | } catch (e) { 14 | alert(e) 15 | } 16 | } 17 | } 18 | 19 | function decrypt() { 20 | let text = document.getElementById('area_cipher_text').value; 21 | if (text) { 22 | let encode = document.getElementById('select_output_encode').value; 23 | let cipherText; 24 | if (encode === 'Base64') { 25 | cipherText = CryptoJS.enc.Base64.parse(text) 26 | } else if (encode === 'HEX') { 27 | cipherText = CryptoJS.enc.Hex.parse(text) 28 | } 29 | let key = CryptoJS.enc.Utf8.parse(document.getElementById('input_key').value); 30 | try { 31 | let decrypted = CryptoJS.DES.decrypt({ 32 | ciphertext: cipherText 33 | }, key, buildConfig()); 34 | document.getElementById('area_text').value = decrypted.toString(CryptoJS.enc.Utf8); 35 | } catch (e) { 36 | alert(e) 37 | } 38 | } 39 | } 40 | 41 | function buildConfig() { 42 | let mode = document.getElementById('select_mode').value; 43 | let pad = document.getElementById('select_pad').value; 44 | let conf = {}; 45 | switch (mode) { 46 | case 'CBC': 47 | conf.mode = CryptoJS.mode.CBC; 48 | break; 49 | case 'CFB': 50 | conf.mode = CryptoJS.mode.CFB; 51 | break; 52 | case 'CTR': 53 | conf.mode = CryptoJS.mode.CTR; 54 | break; 55 | case 'OFB': 56 | conf.mode = CryptoJS.mode.OFB; 57 | break; 58 | case 'ECB': 59 | conf.mode = CryptoJS.mode.ECB; 60 | break; 61 | } 62 | switch (pad) { 63 | case 'Pkcs7': 64 | conf.padding = CryptoJS.pad.Pkcs7; 65 | break; 66 | case 'Iso97971': 67 | conf.padding = CryptoJS.pad.Iso97971; 68 | break; 69 | case 'AnsiX923': 70 | conf.padding = CryptoJS.pad.AnsiX923; 71 | break; 72 | case 'Iso10126': 73 | conf.padding = CryptoJS.pad.Iso10126; 74 | break; 75 | case 'ZeroPadding': 76 | conf.padding = CryptoJS.pad.ZeroPadding; 77 | break; 78 | case 'NoPadding': 79 | conf.padding = CryptoJS.pad.NoPadding; 80 | break; 81 | } 82 | conf.iv = CryptoJS.enc.Utf8.parse(document.getElementById('input_iv').value); 83 | return conf 84 | } 85 | 86 | function cleanup() { 87 | document.getElementById('area_text').value = ''; 88 | document.getElementById('area_cipher_text').value = ''; 89 | document.getElementById('input_key').value = ''; 90 | document.getElementById('input_iv').value = ''; 91 | } -------------------------------------------------------------------------------- /sql/tools.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat Premium Data Transfer 3 | 4 | Source Server : pgsql-localhost 5 | Source Server Type : PostgreSQL 6 | Source Server Version : 110002 7 | Source Host : localhost:5432 8 | Source Catalog : oktools 9 | Source Schema : public 10 | 11 | Target Server Type : PostgreSQL 12 | Target Server Version : 110002 13 | File Encoding : 65001 14 | 15 | Date: 24/09/2019 12:51:40 16 | */ 17 | 18 | 19 | -- ---------------------------- 20 | -- Table structure for toolshttps://item.m.jd.com/product/10024996935738.html?wxa_abtest=o&utm_source=iosapp&utm_medium=appshare&utm_campaign=t_335139774&utm_term=CopyURL&ad_od=share 21 | -- ---------------------------- 22 | DROP Thttps://item.m.jd.com/product/10023423161006.html?wxa_abtest=o&utm_source=iosapp&utm_medium=appshare&utm_campaign=t_335139774&utm_term=CopyURL&ad_od=shareABLE IF EXISTS "public"."tools"; 23 | CREATE TABLE "public"."tools" ( 24 | "path" varchar(255) COLLATE "pg_catalog"."default" NOT NULL, 25 | "title" varchar(255) COLLATE "pg_catalog"."default" NOT NULL, 26 | "icon" varchar(255) COLLATE "pg_catalog"."default", 27 | "category" int2 NOT NULL DEFAULT 0, 28 | "usage_count" int4 NOT NULL DEFAULT 0 29 | ) 30 | ; 31 | 32 | -- ---------------------------- 33 | -- Records of tools 34 | -- ---------------------------- 35 | INSERT INTO "public"."tools" VALUES ('/json2yaml', 'JSON/YAML转换', NULL, 0, 0); 36 | INSERT INTO "public"."tools" VALUES ('/json2go', 'JSON转Go Struct', NULL, 0, 0); 37 | INSERT INTO "public"."tools" VALUES ('/unicode', 'Unicode编码转换', NULL, 0, 0); 38 | INSERT INTO "public"."tools" VALUES ('/url', 'URL编码解码', NULL, 0, 0); 39 | INSERT INTO "public"."tools" VALUES ('/hash', 'Hash计算', NULL, 0, 0); 40 | INSERT INTO "public"."tools" VALUES ('/morse', '摩斯电码', NULL, 0, 0); 41 | INSERT INTO "public"."tools" VALUES ('/number', '进制转换', NULL, 0, 0); 42 | INSERT INTO "public"."tools" VALUES ('/websocket', 'WebSocket测试', NULL, 0, 0); 43 | INSERT INTO "public"."tools" VALUES ('/timestamp', 'Unix时间戳', NULL, 0, 0); 44 | INSERT INTO "public"."tools" VALUES ('/regex', '正则表达式测试', NULL, 0, 0); 45 | INSERT INTO "public"."tools" VALUES ('/qrcode', '二维码制作', NULL, 0, 0); 46 | INSERT INTO "public"."tools" VALUES ('/ip', 'IP地址信息', NULL, 0, 0); 47 | INSERT INTO "public"."tools" VALUES ('/file-hash', '文件Hash计算', NULL, 0, 0); 48 | INSERT INTO "public"."tools" VALUES ('/rsa', 'RSA加密解密', NULL, 0, 0); 49 | INSERT INTO "public"."tools" VALUES ('/des', 'DES加密解密', NULL, 0, 0); 50 | INSERT INTO "public"."tools" VALUES ('/aes', 'AES加密解密', NULL, 0, 0); 51 | INSERT INTO "public"."tools" VALUES ('/color', '颜色值转换', NULL, 0, 0); 52 | INSERT INTO "public"."tools" VALUES ('/image2base64', '图片Base64编码', '', 0, 0); 53 | INSERT INTO "public"."tools" VALUES ('/base64', 'Base64编码解码', NULL, 0, 0); 54 | INSERT INTO "public"."tools" VALUES ('/json', 'JSON格式化', NULL, 0, 0); 55 | INSERT INTO "public"."tools" VALUES ('/placeholder', 'SVG占位图', NULL, 0, 0); 56 | INSERT INTO "public"."tools" VALUES ('/tinyimg', '图片压缩', NULL, 0, 0); 57 | INSERT INTO "public"."tools" VALUES ('/json2xml', 'JSON/XML转换', NULL, 0, 0); 58 | INSERT INTO "public"."tools" VALUES ('/clocks', 'CSS时钟', NULL, 0, 0); 59 | INSERT INTO "public"."tools" VALUES ('/pdf2img', 'PDF转图片', NULL, 0, 0); 60 | INSERT INTO "public"."tools" VALUES ('/fund', '基金数据', NULL, 0, 0); 61 | -- ---------------------------- 62 | -- Primary Key structure for table tools 63 | -- ---------------------------- 64 | ALTER TABLE "public"."tools" ADD CONSTRAINT "tools_pkey" PRIMARY KEY ("path"); 65 | -------------------------------------------------------------------------------- /tpl/hash.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hash计算 MD5、SHA1、SHA224、SHA-256、SHA384、SHA512计算 - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 11 | 12 | {{template "aside"}} 13 |
14 |
15 |

Hash计算

16 | 17 |
18 | 32 | 33 | 34 |
35 | 36 |
37 |
38 | 39 | 91 | 92 | -------------------------------------------------------------------------------- /src/contoller/controler.go: -------------------------------------------------------------------------------- 1 | package contoller 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gin-gonic/gin" 6 | "net/http" 7 | "oktools/src/model" 8 | "time" 9 | ) 10 | 11 | const ( 12 | second = 1 13 | minute = 60 * second 14 | hour = 60 * minute 15 | day = 24 * hour 16 | ) 17 | 18 | var begin = time.Now() 19 | 20 | func Uptime(c *gin.Context) { 21 | diff := time.Now().Unix() - begin.Unix() 22 | days := diff / day 23 | hours := (diff - days*day) / hour 24 | minutes := (diff - days*day - hours*hour) / minute 25 | seconds := (diff - minutes*minute - days*day - hours*hour) / second 26 | 27 | c.String(http.StatusOK, 28 | fmt.Sprintf("The system launched in %s. already running for %d days, %d hours, %d minues, %d seconds.", 29 | begin.Format("2006-01-02 15:04:05"), days, hours, minutes, seconds), 30 | ) 31 | } 32 | 33 | func Ping(c *gin.Context) { 34 | c.JSON(http.StatusOK, gin.H{"msg": "pong"}) 35 | } 36 | 37 | func Index(c *gin.Context) { 38 | c.HTML(http.StatusOK, "index.html", gin.H{ 39 | "tools": model.GetTools(), 40 | }) 41 | } 42 | 43 | func Color(c *gin.Context) { 44 | c.HTML(http.StatusOK, "color.html", nil) 45 | } 46 | 47 | func Base64(c *gin.Context) { 48 | c.HTML(http.StatusOK, "base64.html", nil) 49 | } 50 | 51 | func Image2Base64(c *gin.Context) { 52 | c.HTML(http.StatusOK, "image2base64.html", nil) 53 | } 54 | 55 | func TinyImage(c *gin.Context) { 56 | c.HTML(http.StatusOK, "tinyimg.html", nil) 57 | } 58 | 59 | func Hash(c *gin.Context) { 60 | c.HTML(http.StatusOK, "hash.html", nil) 61 | } 62 | 63 | func FileHash(c *gin.Context) { 64 | c.HTML(http.StatusOK, "file_hash.html", nil) 65 | } 66 | 67 | func IPInfo(c *gin.Context) { 68 | c.HTML(http.StatusOK, "ip.html", gin.H{ 69 | "IP": c.ClientIP(), 70 | }) 71 | } 72 | 73 | func JSONView(c *gin.Context) { 74 | c.HTML(http.StatusOK, "json.html", nil) 75 | } 76 | 77 | func Number(c *gin.Context) { 78 | c.HTML(http.StatusOK, "number.html", nil) 79 | } 80 | 81 | func Placeholder(c *gin.Context) { 82 | c.HTML(http.StatusOK, "placeholder.html", nil) 83 | } 84 | 85 | func QRCode(c *gin.Context) { 86 | c.HTML(http.StatusOK, "qrcode.html", nil) 87 | } 88 | 89 | func Regex(c *gin.Context) { 90 | c.HTML(http.StatusOK, "regex.html", nil) 91 | } 92 | 93 | func Timestamp(c *gin.Context) { 94 | c.HTML(http.StatusOK, "timestamp.html", nil) 95 | } 96 | 97 | func WebSocket(c *gin.Context) { 98 | c.HTML(http.StatusOK, "websocket.html", nil) 99 | } 100 | 101 | func AES(c *gin.Context) { 102 | c.HTML(http.StatusOK, "aes.html", nil) 103 | } 104 | 105 | func DES(c *gin.Context) { 106 | c.HTML(http.StatusOK, "des.html", nil) 107 | } 108 | 109 | func RSA(c *gin.Context) { 110 | c.HTML(http.StatusOK, "rsa.html", nil) 111 | } 112 | 113 | func Morse(c *gin.Context) { 114 | c.HTML(http.StatusOK, "morse.html", nil) 115 | } 116 | 117 | func URL(c *gin.Context) { 118 | c.HTML(http.StatusOK, "url.html", nil) 119 | } 120 | 121 | func Unicode(c *gin.Context) { 122 | c.HTML(http.StatusOK, "unicode.html", nil) 123 | } 124 | 125 | func UnionCode(c *gin.Context) { 126 | c.HTML(http.StatusOK, "union_code.html", nil) 127 | } 128 | 129 | func MYSQLGO(c *gin.Context) { 130 | c.HTML(http.StatusOK, "mysqlgo.html", nil) 131 | } 132 | 133 | func JSON2GO(c *gin.Context) { 134 | c.HTML(http.StatusOK, "json2go.html", nil) 135 | } 136 | 137 | func JSON2XML(c *gin.Context) { 138 | c.HTML(http.StatusOK, "json2xml.html", nil) 139 | } 140 | 141 | func JSON2YAML(c *gin.Context) { 142 | c.HTML(http.StatusOK, "json2yaml.html", nil) 143 | } 144 | 145 | func PDF2IMG(c *gin.Context) { 146 | c.HTML(http.StatusOK, "pdf2img.html", nil) 147 | } 148 | 149 | func Clocks(c *gin.Context) { 150 | c.HTML(http.StatusOK, "clocks.html", nil) 151 | } 152 | 153 | func Xinpianchang(c *gin.Context) { 154 | 155 | c.HTML(http.StatusOK, "xinpianchang.html", nil) 156 | } 157 | -------------------------------------------------------------------------------- /tpl/unicode.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Unicode转中文、中文Unicode编码、ASCII转Unicode、Unicode转ASCII - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {{template "aside"}} 14 |
15 |
16 |

Unicode编码转换

17 | 18 |
19 | 23 | 27 | 31 | 35 | 36 |
37 | 38 |
39 |
40 | 102 | 103 | -------------------------------------------------------------------------------- /tpl/image2base64.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 图片转Base64编码 - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {{template "aside"}} 14 |
15 |
16 |

图片Base64编码

17 |
18 | 19 | 21 | 22 | 23 | 24 | 选择一张图片 25 | 26 | 27 |
28 |
30 |
31 | 35 | 38 |
39 | 40 |
41 |
42 | 100 | 101 | -------------------------------------------------------------------------------- /static/js/regex.js: -------------------------------------------------------------------------------- 1 | const patterns = [ 2 | { 3 | category: '一、数字', 4 | list: { 5 | '数字': '^[0-9]*$', 6 | 'n位的数字': '^\\d{n}$', 7 | '至少n位的数字': '^\\d{n,}$', 8 | 'm-n位的数字': '^\\d{m,n}$', 9 | '零和非零开头的数字': '^(0|[1-9][0-9]*)$', 10 | '非零开头的最多带两位小数的数字': '^([1-9][0-9]*)+(\\.[0-9]{1,2})?$', 11 | '带1-2位小数的正数或负数': '^(\\-)?\\d+(\\.\\d{1,2})$', 12 | '正数、负数、和小数': '^(\\-|\\+)?\\d+(\\.\\d+)?$', 13 | '有两位小数的正实数': '^[0-9]+(\\.[0-9]{2})?$', 14 | '非负整数': '^\\d+$ 或 ^[1-9]\\d*|0$', 15 | '非正整数': '^-[1-9]\\d*|0$', 16 | '浮点数': '^(-?\\d+)(\\.\\d+)?$', 17 | '正浮点数': '^[1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*$', 18 | '负浮点数': '^-([1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*)$', 19 | } 20 | }, { 21 | category: '二、字符', 22 | list: { 23 | '汉字': '^[\\u4e00-\\u9fa5]{0,}$', 24 | '大写英文': '^[A-Z]+$', 25 | '小写英文': '^[a-z]+$', 26 | '英文和数字': '^[A-Za-z0-9]+$', 27 | '英文、数字和下划线': '^\\w+$', 28 | '中文、英文、数字': '^[\\u4E00-\\u9FA5A-Za-z0-9]+$', 29 | '中文、英文、数字和下划线': '^[\\u4E00-\\u9FA5A-Za-z0-9_]+$', 30 | '双字节字符(包括汉字在内)': '[^\\x00-\\xff]', 31 | } 32 | }, { 33 | category: '三、特殊需求表达式', 34 | list: { 35 | 'Email': '^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$', 36 | '身份证号码': '^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$', 37 | '手机号码': '^1(3|4|5|6|7|8|9)\\d{9}$', 38 | '固定电话(XXX-XXXXXXX XXXX-XXXXXXXX)': '(\\(\\d{3,4}\\)|\\d{3,4}-|\\s)?\\d{8}', 39 | '域名': '^((http:\\/\\/)|(https:\\/\\/))?([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}(\\/)', 40 | 'IPv4': '((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))', 41 | 'HTML标签': '<(\\S*?)[^>]*>.*?|<.*? />', 42 | '日期': '^\\d{4}-\\d{1,2}-\\d{1,2}', 43 | '密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线)': '^[a-zA-Z]\\w{5,17}$', 44 | '密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在 8-10 之间)': '^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])[a-zA-Z0-9]{8,10}$', 45 | '密码(必须包含大小写字母和数字的组合,可以使用特殊字符,长度在8-10之间)': '^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$', 46 | } 47 | } 48 | ]; 49 | 50 | let tables = ''; 51 | for (let key in patterns) { 52 | let item = patterns[key]; 53 | tables += `

${item.category}

`; 54 | for (let name in item.list) { 55 | tables += ``; 56 | } 57 | tables += '
${name}${item.list[name]}
' 58 | } 59 | document.getElementById('tables').innerHTML = tables; 60 | 61 | function buildRegex() { 62 | let pattern = document.getElementById('input_pattern').value; 63 | if (!pattern) { 64 | return; 65 | } 66 | 67 | let op = ''; 68 | if (document.getElementById("cb_global_search").checked) { 69 | op = 'g'; 70 | } 71 | if (document.getElementById("cb_ignore_case").checked) { 72 | op += 'i'; 73 | } 74 | return new RegExp(pattern, op); 75 | } 76 | 77 | function match() { 78 | let text = document.getElementById('area_text').value; 79 | if (!text) { 80 | return 81 | } 82 | 83 | let regex = buildRegex(); 84 | if (!regex) { 85 | return; 86 | } 87 | 88 | let match = text.match(regex); 89 | if (match) { 90 | document.getElementById('area_matched').value = match.length + '处匹配:\n' + match.join(' '); 91 | } else { 92 | document.getElementById('area_matched').value = '没有匹配'; 93 | } 94 | } 95 | 96 | function replace() { 97 | let text = document.getElementById('area_text').value; 98 | if (!text) { 99 | return 100 | } 101 | 102 | let regex = buildRegex(); 103 | if (!regex) { 104 | return; 105 | } 106 | 107 | let value = document.getElementById('input_replace').value; 108 | document.getElementById('area_replacement').value = text.replace(regex, value) 109 | } -------------------------------------------------------------------------------- /tpl/json2yaml.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSON转YAML,YAML转JSON - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 11 | 12 | 21 | 22 | 23 | {{template "aside"}} 24 |
25 |
26 |

JSON转YAML,YAML转JSON

27 |
28 |
29 | 30 |

 31 |             
32 |
33 |
34 | 38 | 42 | 44 | 46 | 47 |
48 |
49 |
50 | 51 |

 52 |             
53 |
54 |
55 |
56 | 57 | 58 | 59 | 60 | 61 | 102 | 103 | -------------------------------------------------------------------------------- /static/js/tinyimg.js: -------------------------------------------------------------------------------- 1 | const input_img = document.querySelector('#img_input img'); 2 | const output_img = document.querySelector('#img_output img'); 3 | const output_width = document.getElementById('output_width'); 4 | const output_height = document.getElementById('output_height'); 5 | const select_quality = document.getElementById('select_quality'); 6 | const output_quality = document.getElementById('output_quality'); 7 | const output_info = document.getElementById('output_info'); 8 | let file; 9 | let blob; 10 | 11 | const options = ''; 12 | select_quality.innerHTML = options; 13 | 14 | function formatSize(size, len, units) { 15 | let unit; 16 | units = units || ['B', 'K', 'M', 'G', 'TB']; 17 | while ((unit = units.shift()) && size > 1024) { 18 | size = size / 1024; 19 | } 20 | return (unit === 'B' ? size : size.toFixed(len === undefined ? 2 : len)) + unit; 21 | } 22 | 23 | function preview(f) { 24 | if (!f) return; 25 | 26 | let reader = new FileReader(); 27 | reader.onload = function () { 28 | document.getElementById('file_name').innerHTML = f.name; 29 | input_img.src = this.result 30 | }; 31 | reader.readAsDataURL(f); 32 | file = f; 33 | output_info.innerText = ''; 34 | 35 | input_img.onload = () => { 36 | output_width.value = input_img.naturalWidth; 37 | output_height.value = input_img.naturalHeight; 38 | document.getElementById('file_name').innerHTML = f.name + `  [${formatSize(f.size)} - ${input_img.naturalWidth}x${input_img.naturalHeight}]`; 39 | } 40 | } 41 | 42 | function onChangeWidth() { 43 | let ratio = input_img.width / input_img.height; 44 | output_height.value = Math.round(output_width.value / ratio); 45 | } 46 | 47 | function onChangeHeight() { 48 | let ratio = input_img.width / input_img.height; 49 | output_width.value = Math.round(output_height.value * ratio); 50 | } 51 | 52 | function onInputQuality() { 53 | let quality = output_quality.value; 54 | if (quality) { 55 | quality = parseInt(quality); 56 | if (quality <= 0 || quality > 100) { 57 | alert('压缩质量在0-100之间'); 58 | return 59 | } 60 | select_quality.innerHTML = '' 61 | } else { 62 | select_quality.innerHTML = options 63 | } 64 | } 65 | 66 | function compress(btn) { 67 | btn.innerText = '压缩中...'; 68 | new Promise(function (resolve) { 69 | setTimeout(function () { 70 | resolve(_compress()) 71 | }, 50); 72 | }).then(function (e) { 73 | output_img.src = e[0]; 74 | blob = e[1]; 75 | output_info.innerText = formatSize(blob.size); 76 | btn.innerText = '压缩'; 77 | }); 78 | } 79 | 80 | function _compress() { 81 | let w = parseInt(output_width.value); 82 | let h = parseInt(output_height.value); 83 | let canvas = document.createElement('canvas'); 84 | let ctx = canvas.getContext('2d'); 85 | let anw = document.createAttribute("width"); 86 | anw.nodeValue = w; 87 | let anh = document.createAttribute("height"); 88 | anh.nodeValue = h; 89 | canvas.setAttributeNode(anw); 90 | canvas.setAttributeNode(anh); 91 | 92 | ctx.fillRect(0, 0, w, h); 93 | ctx.drawImage(input_img, 0, 0, w, h); 94 | 95 | let quality = output_quality.value; 96 | if (quality) { 97 | quality = parseInt(quality) / 100; 98 | } else { 99 | quality = parseFloat(select_quality.value) 100 | } 101 | 102 | const base64 = canvas.toDataURL('image/jpeg', quality); 103 | const bytes = window.atob(base64.split(',')[1]); 104 | const ab = new ArrayBuffer(bytes.length); 105 | const ia = new Uint8Array(ab); 106 | for (let i = 0; i < bytes.length; i++) { 107 | ia[i] = bytes.charCodeAt(i); 108 | } 109 | let blob = new Blob([ab], {type: 'image/jpeg'}); 110 | return [base64, blob] 111 | } 112 | 113 | function save() { 114 | let a = document.createElement('a'); 115 | let event = new MouseEvent('click'); 116 | a.download = file.name.split('.')[0] + '_' + Math.round(new Date() / 1000) + '.jpg'; 117 | a.href = URL.createObjectURL(blob); 118 | a.dispatchEvent(event) 119 | } -------------------------------------------------------------------------------- /tpl/timestamp.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Unix时间戳转换 - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 11 | 12 | {{template "aside"}} 13 |
14 |
15 |

Unix时间戳

16 |
17 |
18 | 当前时间 19 | 20 | 24 |
25 |
26 | 27 | 28 | 29 |
30 |
31 |
32 | Unix时间戳 33 | 34 | 38 | 39 | 40 |
41 |
42 |
43 | 北京时间 44 | 45 | 46 | 47 | 51 |
52 |

在编程语言中获取Unix时间戳:

53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 |
语言毫秒
JavaScriptMath.round(new Date() / 1000)new Date().getTime()
JavaSystem.currentTimeMillis() / 1000System.currentTimeMillis()
Pythonint(time.time())int(time.time() * 1000)
Gotime.Now().Unix()time.Now().UnixNano() / 1e6
PHPtime()(int)(microtime(true) * 1000)
RubyTime.now.to_i(Time.now.to_f * 1000).to_i
C#DateTimeOffset.UtcNow.ToUnixTimeSeconds()DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
SwiftNSDate().timeIntervalSince1970NSDate().timeIntervalSince1970 * 1000
Objective-C[[NSDate date] timeIntervalSince1970][[NSDate date] timeIntervalSince1970] * 1000
109 |
110 |
111 | 112 | 113 | -------------------------------------------------------------------------------- /script/build.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "archive/tar" 5 | "compress/gzip" 6 | "fmt" 7 | "github.com/tdewolff/minify" 8 | "github.com/tdewolff/minify/css" 9 | "github.com/tdewolff/minify/html" 10 | "github.com/tdewolff/minify/js" 11 | "io" 12 | "log" 13 | "os" 14 | "os/exec" 15 | "path/filepath" 16 | "regexp" 17 | "strings" 18 | ) 19 | 20 | const buildDir = "./build" 21 | const tempDir = buildDir + "/oktools" 22 | 23 | const srcTplDir = "./tpl" 24 | const dstTplDir = tempDir + "/tpl/" 25 | 26 | const srcCSSDir = "./static/css" 27 | const dstCSSDir = tempDir + "/static/css/" 28 | 29 | const srcJSDir = "./static/js" 30 | const dstJSDir = tempDir + "/static/js/" 31 | 32 | func main() { 33 | clean() 34 | buildGo() 35 | minifyStatic() 36 | copyFiles() 37 | packAll() 38 | } 39 | 40 | func clean() { 41 | err := os.RemoveAll(buildDir) 42 | if err != nil { 43 | fmt.Println(err) 44 | } 45 | } 46 | 47 | func buildGo() { 48 | err := os.Setenv("GOOS", "linux") 49 | err = os.Setenv("GOARCH", "amd64") 50 | checkError(err) 51 | 52 | cmd := exec.Command("go", "build", "-o", tempDir+"/oktools", "-i", "./src") 53 | cmd.Stderr = os.Stderr 54 | out, err := cmd.Output() 55 | checkError(err) 56 | fmt.Println(string(out)) 57 | } 58 | 59 | func minifyStatic() { 60 | m := minify.New() 61 | m.AddFunc("text/css", css.Minify) 62 | m.AddFunc("text/html", html.Minify) 63 | m.AddFuncRegexp(regexp.MustCompile("^(application|text)/(x-)?(java|ecma)script$"), js.Minify) 64 | 65 | minifyFiles(m, "text/html", srcTplDir, dstTplDir) 66 | minifyFiles(m, "text/css", srcCSSDir, dstCSSDir) 67 | minifyFiles(m, "application/javascript", srcJSDir, dstJSDir) 68 | } 69 | 70 | func copyFiles() { 71 | copyDir("./sql", tempDir+"/sql") 72 | copyFile("./static/favicon.ico", tempDir+"/static/favicon.ico") 73 | copyFile("./conf.yaml", tempDir+"/conf.yaml") 74 | } 75 | 76 | func minifyFiles(m *minify.M, mimeType, src, dst string) { 77 | err := os.MkdirAll(dst, os.ModePerm) 78 | checkError(err) 79 | 80 | err = filepath.Walk(src, func(path string, info os.FileInfo, err error) error { 81 | if info.IsDir() { 82 | return nil 83 | } 84 | 85 | file, err := os.Open(path) 86 | if err != nil { 87 | return err 88 | } 89 | 90 | dest, err := os.Create(dst + info.Name()) 91 | if err != nil { 92 | return err 93 | } 94 | defer dest.Close() 95 | 96 | if strings.HasSuffix(info.Name(), "min.css") || strings.HasSuffix(info.Name(), "min.js") { 97 | _, err = io.Copy(dest, file) 98 | return err 99 | } 100 | 101 | return m.Minify(mimeType, dest, file) 102 | }) 103 | checkError(err) 104 | } 105 | 106 | func copyDir(src string, dst string) { 107 | err := os.MkdirAll(dst, os.ModePerm) 108 | checkError(err) 109 | 110 | dir, _ := os.Open(src) 111 | defer dir.Close() 112 | objects, err := dir.Readdir(-1) 113 | 114 | for _, obj := range objects { 115 | srcFile := src + "/" + obj.Name() 116 | dstFile := dst + "/" + obj.Name() 117 | 118 | if obj.IsDir() { 119 | copyDir(srcFile, dstFile) 120 | } else { 121 | copyFile(srcFile, dstFile) 122 | } 123 | } 124 | } 125 | 126 | func copyFile(src string, dst string) { 127 | srcFile, err := os.Open(src) 128 | defer srcFile.Close() 129 | checkError(err) 130 | 131 | destFile, err := os.Create(dst) 132 | defer destFile.Close() 133 | checkError(err) 134 | 135 | _, err = io.Copy(destFile, srcFile) 136 | checkError(err) 137 | 138 | err = os.Chmod(dst, os.ModePerm) 139 | checkError(err) 140 | } 141 | 142 | func packAll() { 143 | dir, err := os.Open(tempDir) 144 | defer dir.Close() 145 | checkError(err) 146 | 147 | info, err := dir.Stat() 148 | checkError(err) 149 | 150 | d, err := os.Create(buildDir + "/" + info.Name() + ".tar.gz") 151 | defer d.Close() 152 | checkError(err) 153 | 154 | gw := gzip.NewWriter(d) 155 | defer gw.Close() 156 | 157 | tw := tar.NewWriter(gw) 158 | defer tw.Close() 159 | 160 | compress(dir, "", tw) 161 | } 162 | 163 | func compress(file *os.File, prefix string, tw *tar.Writer) { 164 | info, err := file.Stat() 165 | checkError(err) 166 | 167 | if info.IsDir() { 168 | prefix = prefix + "/" + info.Name() 169 | fileInfos, err := file.Readdir(-1) 170 | checkError(err) 171 | 172 | for _, fi := range fileInfos { 173 | f, err := os.Open(file.Name() + "/" + fi.Name()) 174 | checkError(err) 175 | 176 | compress(f, prefix, tw) 177 | f.Close() 178 | } 179 | } else { 180 | h, err := tar.FileInfoHeader(info, "") 181 | checkError(err) 182 | 183 | h.Name = prefix + "/" + h.Name 184 | h.Mode = int64(info.Mode().Perm()) 185 | err = tw.WriteHeader(h) 186 | checkError(err) 187 | 188 | _, err = io.Copy(tw, file) 189 | err = file.Close() 190 | checkError(err) 191 | } 192 | } 193 | 194 | func checkError(err error) { 195 | if err != nil { 196 | log.Fatalln(err) 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /tpl/mysqlgo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | sql2struct 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {{template "aside"}} 14 |
15 |
16 |
17 | 18 | 19 | 27 | SQL2Struct 28 | options 29 | Github 30 | 31 | 32 | 33 | 34 | 35 | 36 |
37 | 38 | 39 | 41 | 42 | 43 |
44 |
45 | 46 |
47 | 48 | 49 | 51 | 52 | 53 |
54 |
55 |
56 |
57 | 58 | 59 | 60 |
61 | 62 | 63 | 64 | 65 | 69 | 70 | 71 | 72 | 76 | 77 | 78 | 79 | 83 | 84 | 85 | 86 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 |
98 |
99 |
100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /tpl/json2xml.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSON转XML,XML转JSON - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 11 | 12 | 21 | 22 | 23 | {{template "aside"}} 24 |
25 |
26 |

JSON转XML,XML转JSON

27 |
28 |
29 | 30 |

 31 |             
32 |
33 |
34 | 38 | 42 | 44 | 45 | 46 |
47 |
48 |
49 | 50 |

 51 |             
52 |
53 |
54 |
55 | 56 | 57 | 58 | 59 | 60 | 130 | 131 | -------------------------------------------------------------------------------- /tpl/pdf2img.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PDF转图片|PDF转JPG - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {{template "aside"}} 14 |
15 |
16 |

PDF转图片

17 |
18 | 19 | 21 | 22 | 23 | 24 | 选择一个PDF文件 25 | 26 | 27 |
28 |
29 |
30 | 34 | 38 |
39 |
40 | 43 | 46 |
47 | 50 | 53 |
54 |

55 |
56 | 57 |
58 |
59 |
60 | 61 | 158 | 159 | -------------------------------------------------------------------------------- /tpl/qrcode.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 二维码制作 - 在线工具 - DevTools 6 | 7 | 8 | 9 | 10 | 34 | 35 | 36 | {{template "aside"}} 37 |
38 |
39 |

二维码制作

40 |
41 |
42 |
43 | 46 |

字数越多,越不易扫描

47 |
48 |
49 |
50 |
51 | 尺寸(px) 52 | 54 |
55 |
56 | 纠错等级 57 | 63 |
64 |
65 | 背景颜色 66 | 67 |
68 |
69 | 前景颜色 70 | 71 |
72 | 73 |
74 |
75 |
76 | 77 |
78 |
79 |
80 |

二维码原理

81 |

二维条码/二维码可以分为堆叠式/行排式二维条码和矩阵式二维条码。 82 | 堆叠式/行排式二维条码形态上是由多行短截的一维5条码堆叠而成; 83 | 矩阵式二维条码以矩阵的形式组成,在矩阵相应元素位置上用“点”表示二进制“1”, 84 | 用“空”表示二进制“0”,“点”和“空”的排列组成代码。

85 |

数据表示方法

86 |

深色模块表示二进制“1”,浅色模块表示二进制“0”。

87 |

纠错能力

88 |
    89 |
  • level L : 约可纠错7%的数据码字
  • 90 |
  • level M : 约可纠错15%的数据码字
  • 91 |
  • level Q : 约可纠错25%的数据码字
  • 92 |
  • level H : 约可纠错30%的数据码字
  • 93 |
94 |
95 |
96 |
97 | 98 | 151 | 152 | -------------------------------------------------------------------------------- /src/model/tools.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "fmt" 5 | "github.com/jinzhu/gorm" 6 | "log" 7 | . "oktools/src/global" 8 | "time" 9 | ) 10 | 11 | // 内存缓存有效期 12 | const toolsCacheAge = 24 * time.Hour 13 | 14 | type Tool struct { 15 | Path string `json:"path"` 16 | Title string `json:"title"` 17 | Icon *string `json:"icon"` 18 | Category int `json:"category,,omitempty"` 19 | UsageCount int `json:"usage_count,omitempty"` 20 | DB *gorm.DB `json:"-" gorm:"-"` // 数据库操作DB 21 | } 22 | 23 | type Cache struct { 24 | Data interface{} 25 | Expir time.Time 26 | } 27 | 28 | var ToolMap = make(map[string]Tool) 29 | 30 | // 全部工具内存缓存 31 | var toolsCache *Cache 32 | 33 | func GetTools() []Tool { 34 | now := time.Now() 35 | if toolsCache == nil || toolsCache.Expir.Before(now) { 36 | tools, err := loadTools() 37 | if err != nil { 38 | log.Println("Failed to load tools data :", err) 39 | return nil 40 | } 41 | 42 | toolsCache = &Cache{} 43 | toolsCache.Data = tools 44 | toolsCache.Expir = now.Add(toolsCacheAge) 45 | return tools 46 | } 47 | return toolsCache.Data.([]Tool) 48 | } 49 | 50 | func loadTools() ([]Tool, error) { 51 | //rows, err := global.PSDB.Query(`SELECT path,title,icon,usage_count,category FROM tools ORDER BY usage_count desc`) 52 | //if err != nil { 53 | // return nil, err 54 | //} 55 | //rows, err := 56 | 57 | ts := GetTool() 58 | tools, _ := ts.List(nil, 0, 0) 59 | //for rows.Next() { 60 | // tool := &Tool{} 61 | // err = rows.Scan(&tool.Path, &tool.Title, &tool.Icon, &tool.UsageCount, &tool.Category) 62 | // if err != nil { 63 | // return nil, err 64 | // } 65 | // tools = append(tools, tool) 66 | // ToolMap[tool.Path] = tool 67 | //} 68 | return tools, nil 69 | } 70 | 71 | func UpdateUsageCount() { 72 | //if len(ToolMap) == 0 { 73 | // log.Println("Tools map is empty , No need to update data!") 74 | // return 75 | //} 76 | // 77 | //var buf bytes.Buffer 78 | //buf.WriteString("UPDATE tools SET usage_count = CASE path ") 79 | //for k, v := range ToolMap { 80 | // buf.WriteString(" WHEN '") 81 | // buf.WriteString(k) 82 | // buf.WriteString("' THEN ") 83 | // buf.WriteString(strconv.Itoa(v.UsageCount)) 84 | //} 85 | //buf.WriteString(" END WHERE path IN(") 86 | // 87 | //for k := range ToolMap { 88 | // buf.WriteString("'") 89 | // buf.WriteString(k) 90 | // buf.WriteString("'") 91 | // buf.WriteString(",") 92 | //} 93 | //buf.WriteString("'')") 94 | // 95 | //sql := buf.String() 96 | //_, err := PSDB.Exec(sql) 97 | //if err != nil { 98 | // log.Println("Failed to update tools usage count data :", err) 99 | //} 100 | // 101 | //log.Println(sql) 102 | } 103 | 104 | func init() { 105 | _, err := loadTools() 106 | if err != nil { 107 | log.Fatalln("loadTools:", err) 108 | } 109 | } 110 | 111 | /** 112 | * 数据打码 113 | */ 114 | func (obj *Tool) Init() { 115 | if obj == nil { 116 | return 117 | } 118 | 119 | return 120 | } 121 | 122 | /** 123 | * 获取结构体,方便对结构体的数据进行初始化 124 | */ 125 | func GetTool() Tool { 126 | var obj Tool 127 | obj.DB = SqlDB.Conn 128 | fmt.Println(SqlDB.Database) 129 | return obj 130 | } 131 | 132 | // 设置User的表名为`profiles` 133 | func (obj Tool) TableName() string { 134 | return "tools" 135 | } 136 | 137 | // 获取数据库链接 138 | func (obj Tool) getDB() (db *gorm.DB) { 139 | db = obj.DB 140 | if db == nil { 141 | db = SqlDB.GetConn() 142 | } 143 | db = db.Table(obj.TableName()) 144 | db = db.Select(obj.FieldList()) 145 | return db 146 | } 147 | 148 | func (obj Tool) FieldList() (fieldList []string) { 149 | fieldList = SqlDB.GetFieldName(obj) 150 | return 151 | } 152 | 153 | // 传递过来的json数据初始化 154 | func (obj *Tool) Insert() (id int64, err error) { 155 | err = obj.getDB().Create(&obj).Error 156 | if err == nil { 157 | //id = obj.ID 158 | } 159 | return 160 | } 161 | 162 | // 更新部分, 可以清空 163 | func (obj *Tool) Update(id int64, updateData map[string]interface{}) (err error) { 164 | err = obj.Get(id) 165 | if err != nil { 166 | return 167 | } 168 | updateData = SqlDB.CleanChangeMap(updateData, obj) 169 | err = obj.getDB().Model(&obj).Updates(updateData).Error 170 | return 171 | } 172 | 173 | // 删除数据 174 | func (obj *Tool) Delete(id int64) (err error) { 175 | err = obj.Get(id) 176 | if err != nil { 177 | return 178 | } 179 | err = obj.getDB().Delete(&obj).Error 180 | return 181 | } 182 | 183 | // 获取一个 184 | func (obj *Tool) Get(id int64) (err error) { 185 | err = obj.getDB().First(&obj, id).Error 186 | if err == nil { 187 | obj.Init() 188 | } 189 | return 190 | } 191 | 192 | // 获取查询db 193 | func (obj *Tool) QueryDB(db *gorm.DB, searchKey map[string]string) (returnDB *gorm.DB) { 194 | 195 | // 查询扩展 196 | // 字段中如果字段 为 realname 197 | // 则默认支持以下查询 198 | // searchKey["realname"] 精确查询 "realname = ?", "%" + searchKey["realname_min"] + "%" 199 | // searchKey["realname_not"] 精确查询 "realname <> ?", "%" + searchKey["realname_min"] + "%" 200 | // searchKey["realname_like"] 模糊查询 "realname like ?", "%" + searchKey["realname_min"] + "%" 201 | // searchKey["realname_left_like"] 模糊左匹配查询 "realname like ?", searchKey["realname_min"] + "%" 202 | // searchKey["realname_min"] 查询 "realname >= ?" , searchKey["realname_min"] 203 | // searchKey["realname_max"] 查询 "realname <= ?" , searchKey["realname_min"] 204 | db = SqlDB.QueryDbInit(db, obj.FieldList(), searchKey) 205 | 206 | returnDB = db 207 | return 208 | } 209 | 210 | func (obj *Tool) QueryOneByCondition(searchKey map[string]string) (err error) { 211 | db := obj.getDB() 212 | db = obj.QueryDB(db, searchKey) 213 | err = db.First(&obj).Error 214 | 215 | if err == nil { 216 | obj.Init() 217 | } 218 | 219 | return 220 | } 221 | 222 | // 列表 223 | func (obj *Tool) List(searchKey map[string]string, page int64, pageSize int64) (results []Tool, err error) { 224 | db := obj.getDB() 225 | 226 | db = obj.QueryDB(db, searchKey) 227 | 228 | // 待调整成 229 | // select a.* from 表1 a, (select id from 表1 where 条件 limit 100000,20) b where a.id=b.id 230 | // 231 | 232 | // 分页 233 | if page > 0 && pageSize > 0 { 234 | if page <= 30 { 235 | //30页前直接获取 236 | db = db.Limit(pageSize).Offset((page - 1) * pageSize) 237 | } else { 238 | 239 | db = db.Select("id as b__id") 240 | db = db.Limit(pageSize).Offset((page - 1) * pageSize) 241 | 242 | db = obj.getDB(). 243 | Table(obj.TableName()). 244 | Joins("join (?) b on id = b__id", db.QueryExpr()) 245 | } 246 | } else { 247 | if pageSize > 0 { 248 | db = db.Limit(pageSize) 249 | } 250 | } 251 | 252 | // 查询数据 253 | err = db.Find(&results).Error 254 | 255 | if err == nil { 256 | for k, _ := range results { 257 | (&results[k]).Init() 258 | } 259 | } 260 | return 261 | } 262 | 263 | // 获取数量 264 | func (obj *Tool) Count(searchKey map[string]string) (totalSize int64, err error) { 265 | db := obj.getDB().Where("deleted_at is null") 266 | err = obj.QueryDB(db, searchKey).Count(&totalSize).Error 267 | 268 | return 269 | } 270 | -------------------------------------------------------------------------------- /tpl/fund.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSON格式化 - 在线工具 - OKTools 6 | 7 | 8 | 9 | 10 | 11 | 12 | 29 | 30 | 31 | 58 |
59 |
60 |

股票持仓数据

61 |
62 |
    63 | {{range .funds}} 64 |
  • 65 |

    基金名称: {{ .FundName}}

    66 |

    基金代码: {{ .FundCode}}

    67 |

    基金经理: {{ .Managers}}

    68 |

    更新日期: {{ .Enddate}}

    69 | 70 |
    71 | {{/* */}} 72 |
    73 | {{range .FundDataShow.Data.FundPosition.StockList}} 74 |
    75 |

    持仓名称:
    {{ .Name}}

    76 |

    股票代码:

    {{ .Code}}

    77 |

    持仓比例:

    %{{ .Percent}}

    78 |

    当前价格:

    {{ .CurrentPrice}}

    79 |

    股价变动:

    {{ .ChangePercentage}}

    80 | {{/*

    当前价格:{{ .CurrentPrice}}

    */}} 81 | {{/*

    股价变动: {{ .ChangePercentage}}

    */}} 82 |

    备注说明: {{ .XqSymbol}}

    83 | {{/* {{ .XqURL }}*/}} 84 |
    85 | {{end}} 86 |
    87 |
    88 | 89 |
    90 |
    91 |
  • {{end}} 92 | 93 |
94 | {{/*
    */}} 95 | {{/* {{range .funds}}*/}} 96 | {{/*
  • */}} 97 | {{/* */}}{{/*
  • */}} 98 | {{/*

    基金名称: {{ .FundName}}

    */}} 99 | {{/*

    基金代码: {{ .FundCode}}

    */}} 100 | {{/* {{range .FundDataShow.Data.FundPosition.StockList}}*/}} 101 | {{/*
  • */}} 102 | {{/*
    */}} 103 | {{/*

    持仓名称:{{ .Name}}

    */}} 104 | {{/*

    持仓代号:{{ .Code}}

    */}} 105 | {{/*

    持仓比例:{{ .Percent}}

    */}} 106 | {{/*

    当前价格:{{ .CurrentPrice}}

    */}} 107 | {{/*

    股价变动: {{ .ChangePercentage}}

    */}} 108 | {{/*

    股价变动: {{ .XqSymbol}}

    */}} 109 | {{/* 查看: {{ .XqURL}}*/}} 110 | {{/*
    */}} 111 | {{/*
  • {{end}}*/}} 112 | {{/* {{end}}*/}} 113 | {{/*
*/}} 114 |
115 |
116 |
117 | 118 | 134 | 154 | 155 | -------------------------------------------------------------------------------- /static/js/file_hash.js: -------------------------------------------------------------------------------- 1 | if ((typeof File !== 'undefined') && !File.prototype.slice) { 2 | if (File.prototype.webkitSlice) { 3 | File.prototype.slice = File.prototype.webkitSlice; 4 | } 5 | 6 | if (File.prototype.mozSlice) { 7 | File.prototype.slice = File.prototype.mozSlice; 8 | } 9 | } 10 | 11 | let web_crypto = window.crypto && window.crypto.subtle && window.crypto.subtle.digest; 12 | if (web_crypto) { 13 | document.getElementById('tips').innerHTML += 14 | '
  • SHA-1、SHA-256、SHA-384 和 SHA-512算法使用速度更快的(WebCryptoAPI),' + 16 | '需要使用更多的内存。Microsoft Edge浏览器不支持SHA-1算法。
  • '; 17 | } 18 | 19 | function isEdge() { 20 | return navigator.userAgent.indexOf("Edge") > -1 21 | } 22 | 23 | function onFileSelected(e) { 24 | e.stopPropagation(); 25 | e.preventDefault(); 26 | 27 | let table = [], max_crypto_file_size = 500 * 1024 * 1024; 28 | let files = e.dataTransfer ? e.dataTransfer.files : e.target.files; 29 | for (let i = 0; i < files.length; i++) { 30 | let file = files[i], crypto_algos = [], workers = []; 31 | 32 | table.push(`${file.name}(${file.type || 'n/a'}) - ${file.size}bytes`); 33 | let pb = ''; 34 | 35 | if (document.getElementById('cb_md5').checked) { 36 | let id = 'md5_' + i; 37 | table.push(`MD5`, pb); 38 | 39 | let worker = new Worker('/static/js/file_hash.worker.js'); 40 | worker.addEventListener('message', onWorkerEvent(id)); 41 | worker.postMessage({type: 'algo', name: 'MD5'}); 42 | workers.push(worker) 43 | } 44 | 45 | if (document.getElementById('cb_sha1').checked) { 46 | let id = 'sha1_' + i; 47 | table.push(`SHA1`, pb); 48 | 49 | if (!isEdge() && web_crypto && file.size < max_crypto_file_size) { 50 | crypto_algos.push({id: id, name: 'SHA-1'}); 51 | } else { 52 | let worker = new Worker('/static/js/file_hash.worker.js'); 53 | worker.addEventListener('message', onWorkerEvent(id)); 54 | worker.postMessage({type: 'algo', name: 'SHA-1'}); 55 | workers.push(worker) 56 | } 57 | } 58 | 59 | if (document.getElementById('cb_sha224').checked) { 60 | let id = 'sha224_' + i; 61 | table.push(`SHA224`, pb); 62 | 63 | let worker = new Worker('/static/js/file_hash.worker.js'); 64 | worker.addEventListener('message', onWorkerEvent(id)); 65 | worker.postMessage({type: 'algo', name: 'SHA-224'}); 66 | workers.push(worker) 67 | } 68 | 69 | if (document.getElementById('cb_sha256').checked) { 70 | let id = 'sha256_' + i; 71 | table.push(`SHA256`, pb); 72 | 73 | if (web_crypto && file.size < max_crypto_file_size) { 74 | crypto_algos.push({id: id, name: 'SHA-256'}); 75 | } else { 76 | let worker = new Worker('/static/js/file_hash.worker.js'); 77 | worker.addEventListener('message', onWorkerEvent(id)); 78 | worker.postMessage({type: 'algo', name: 'SHA-256'}); 79 | workers.push(worker) 80 | } 81 | } 82 | 83 | if (document.getElementById('cb_sha384').checked) { 84 | let id = 'sha384_' + i; 85 | table.push(`SHA384`, pb); 86 | 87 | if (web_crypto && file.size < max_crypto_file_size) { 88 | crypto_algos.push({id: id, name: 'SHA-384'}); 89 | } else { 90 | let worker = new Worker('/static/js/file_hash.worker.js'); 91 | worker.addEventListener('message', onWorkerEvent(id)); 92 | worker.postMessage({type: 'algo', name: 'SHA-384'}); 93 | workers.push(worker) 94 | } 95 | } 96 | 97 | if (document.getElementById('cb_sha512').checked) { 98 | let id = 'sha512_' + i; 99 | table.push(`SHA512`, pb); 100 | 101 | if (web_crypto && file.size < max_crypto_file_size) { 102 | crypto_algos.push({id: id, name: 'SHA-512'}); 103 | } else { 104 | let worker = new Worker('/static/js/file_hash.worker.js'); 105 | worker.addEventListener('message', onWorkerEvent(id)); 106 | worker.postMessage({type: 'algo', name: 'SHA-512'}); 107 | workers.push(worker) 108 | } 109 | } 110 | 111 | if (crypto_algos.length > 0) { 112 | calcByWebCrypto(file, crypto_algos) 113 | } 114 | if (workers.length > 0) { 115 | calcByCryptoJS(file, workers) 116 | } 117 | } 118 | 119 | document.getElementById('tbody_hash').innerHTML = table.join('') 120 | } 121 | 122 | function updateProgress(eid, progress) { 123 | let pb = document.querySelector('#' + eid + ' .progress'); 124 | pb.setAttribute('value', progress); 125 | } 126 | 127 | function calcByWebCrypto(file, algos) { 128 | let reader = new FileReader(); 129 | reader.onprogress = function (e) { 130 | for (let i = 0; i < algos.length; i++) { 131 | updateProgress(algos[i].id, e.loaded * 100 / e.total); 132 | } 133 | }; 134 | reader.onload = function (e) { 135 | for (let i = 0; i < algos.length; i++) { 136 | let algo = algos[i]; 137 | window.crypto.subtle.digest({name: algo.name}, e.target.result) 138 | .then(function (hash) { 139 | let hexString = '', hashResult = new Uint8Array(hash); 140 | for (let i = 0; i < hashResult.length; i++) { 141 | hexString += ("00" + hashResult[i].toString(16)).slice(-2); 142 | } 143 | document.getElementById(algo.id).innerText = hexString 144 | }).catch(e => console.error(e)); 145 | } 146 | }; 147 | reader.readAsArrayBuffer(file); 148 | } 149 | 150 | function readChunked(file, chunkCallback, endCallback) { 151 | let fileSize = file.size; 152 | let chunkSize = 4 * 1024 * 1024; 153 | let offset = 0; 154 | 155 | let reader = new FileReader(); 156 | reader.onload = function () { 157 | if (reader.error) { 158 | endCallback(reader.error || {}); 159 | return; 160 | } 161 | offset += reader.result.length; 162 | chunkCallback(reader.result, offset, fileSize); 163 | if (offset >= fileSize) { 164 | endCallback(null); 165 | return; 166 | } 167 | readNext(); 168 | }; 169 | 170 | reader.onerror = function (err) { 171 | endCallback(err || {}); 172 | }; 173 | 174 | function readNext() { 175 | let slice = file.slice(offset, offset + chunkSize); 176 | reader.readAsBinaryString(slice); 177 | } 178 | 179 | readNext(); 180 | } 181 | 182 | function onWorkerEvent(id) { 183 | return function (e) { 184 | if (e.data.type === 'progress') { 185 | updateProgress(id, e.data.value); 186 | } else if (e.data.type === 'result') { 187 | document.getElementById(id).innerText = e.data.value; 188 | } 189 | } 190 | } 191 | 192 | function calcByCryptoJS(file, workers) { 193 | readChunked(file, (chunk, offs, total) => { 194 | for (let i = 0; i < workers.length; i++) { 195 | workers[i].postMessage({type: 'chunk', chunk: chunk, offs: offs, total: total}); 196 | } 197 | }, err => { 198 | if (err) { 199 | alert(err) 200 | } else { 201 | for (let i = 0; i < workers.length; i++) { 202 | workers[i].postMessage({type: 'done'}); 203 | } 204 | } 205 | }); 206 | } 207 | 208 | document.getElementById('input_file').addEventListener('change', onFileSelected, false); 209 | document.getElementById('drop_zone').addEventListener('drop', onFileSelected, false); 210 | document.getElementById('drop_zone').addEventListener('dragover', function (e) { 211 | e.stopPropagation(); 212 | e.preventDefault(); 213 | }, false); 214 | -------------------------------------------------------------------------------- /static/js/sql2struct.js: -------------------------------------------------------------------------------- 1 | new Vue({ 2 | el: '#app', 3 | data() { 4 | return { 5 | cache: null, 6 | sqlContent: '', 7 | structContent: '', 8 | activeIndex: '1', 9 | typeMap: getTypeMap(), 10 | typeMapStr: '', 11 | useGorm: true, 12 | useSqlx: true, 13 | useJson: true, 14 | useForm: true, 15 | dialogFormVisible: false 16 | } 17 | }, 18 | created() { 19 | var message = { 20 | act: 'getOptions' 21 | } 22 | var that = this 23 | // 获取缓存数据 24 | chrome.runtime.sendMessage(message, function(res) { 25 | if (!res) { // 不存在缓存数据 26 | // 初始配置数据 27 | var data = { 28 | useGorm: that.useGorm, 29 | useSqlx: that.useSqlx, 30 | useJson: that.useJson, 31 | useForm: that.useForm, 32 | typeMap: that.typeMap 33 | } 34 | that.setCache(data) 35 | for (var k in that.typeMap) { 36 | that.typeMapStr += k + ': ' + that.typeMap[k] + '\n' 37 | } 38 | return 39 | } 40 | var obj = JSON.parse(res) 41 | if (obj.useGorm != undefined) { 42 | that.useGorm = obj.useGorm 43 | } 44 | if (obj.useSqlx != undefined) { 45 | that.useSqlx = obj.useSqlx 46 | } 47 | if (obj.useJson != undefined) { 48 | that.useJson = obj.useJson 49 | } 50 | if (obj.useForm != undefined) { 51 | that.useForm = obj.useForm 52 | } 53 | if (obj.typeMap != undefined) { 54 | that.typeMap = obj.typeMap 55 | for (var k in obj.typeMap) { 56 | that.typeMapStr += k + ': ' + obj.typeMap[k] + '\n' 57 | } 58 | } 59 | }) 60 | }, 61 | watch: { 62 | sqlContent(val) { 63 | if (!val) { 64 | this.structContent = '' 65 | return 66 | } 67 | var res = val.match(/\`[\w_]+\`\s+[\w_\(\)]+(\s+|\,)/g) 68 | if (!res) { 69 | this.structContent = 'invalid sql' 70 | return 71 | } 72 | var types = this.typeMap 73 | var structResult = 'type ' 74 | for (var i = 0, len = res.length; i < len; i++) { 75 | var field = res[i].match(/\`(.+)\`\s+(tinyint|smallint|int|mediumint|bigint|float|double|decimal|varchar|char|text|mediumtext|longtext|datetime|time|date|enum|set|blob)?/) 76 | if (i == 0) { // 第一个字段为数据表名称 77 | if (field && field[1] != undefined && field[2] == undefined) { 78 | var tbName = titleCase(field[1]) 79 | structResult += tbName + ' struct {' 80 | continue 81 | } else { 82 | return 83 | } 84 | } else { // 数据表字段 85 | if (field && field[1] != undefined && field[2] != undefined) { 86 | if (types[field[2]] != undefined) { 87 | var fieldName = titleCase(field[1]) 88 | var fieldType = types[field[2]] 89 | var fieldJsonName = field[1].toLowerCase() 90 | if (fieldName.toLowerCase() == 'id') { 91 | fieldName = 'ID' 92 | } 93 | structResult += '\n\t' + fieldName + ' ' + fieldType + ' ' 94 | structArr = [] 95 | if (this.useGorm) { 96 | structArr.push('gorm:"column:'+ fieldJsonName +'"') 97 | } 98 | if (this.useSqlx) { 99 | structArr.push('db:"column:'+ fieldJsonName +'"') 100 | } 101 | if (this.useJson) { 102 | structArr.push('json:"' + fieldJsonName + '"') 103 | } 104 | if (this.useForm) { 105 | structArr.push('form:"' + fieldJsonName + '"') 106 | } 107 | if (structArr.length > 0) { 108 | structResult += '`'+structArr.join(' ')+'`' 109 | } 110 | } else { 111 | continue 112 | } 113 | } else { 114 | continue 115 | } 116 | } 117 | } 118 | structResult += '\n}' 119 | this.structContent = structResult 120 | }, 121 | typeMapStr(val) { 122 | var typeArr = val.split('\n') 123 | var typeMap = {} 124 | for (var i = 0, len = typeArr.length; i < len; i++) { 125 | var itemArr = typeArr[i].split(/\:\s+/) 126 | if (itemArr[0] != undefined && itemArr[1] != undefined) { 127 | typeMap[itemArr[0]] = itemArr[1] 128 | } 129 | } 130 | this.typeMap = typeMap 131 | var data = { 132 | useGorm: this.useGorm, 133 | useSqlx: this.useSqlx, 134 | useJson: this.useJson, 135 | useForm: this.useForm, 136 | typeMap: this.typeMap 137 | } 138 | this.setCache(data) 139 | }, 140 | useGorm(val) { 141 | this.useGorm = val 142 | var data = { 143 | useGorm: this.useGorm, 144 | useSqlx: this.useSqlx, 145 | useJson: this.useJson, 146 | useForm: this.useForm, 147 | typeMap: this.typeMap 148 | } 149 | this.setCache(data) 150 | }, 151 | useSqlx(val) { 152 | this.useSqlx = val 153 | var data = { 154 | useGorm: this.useGorm, 155 | useSqlx: this.useSqlx, 156 | useJson: this.useJson, 157 | useForm: this.useForm, 158 | typeMap: this.typeMap 159 | } 160 | this.setCache(data) 161 | }, 162 | useJson(val) { 163 | this.useJson = val 164 | var data = { 165 | useGorm: this.useGorm, 166 | useSqlx: this.useSqlx, 167 | useJson: this.useJson, 168 | useForm: this.useForm, 169 | typeMap: this.typeMap 170 | } 171 | this.setCache(data) 172 | }, 173 | useForm(val) { 174 | this.useForm = val 175 | var data = { 176 | useGorm: this.useGorm, 177 | useSqlx: this.useSqlx, 178 | useJson: this.useJson, 179 | useForm: this.useForm, 180 | typeMap: this.typeMap 181 | } 182 | this.setCache(data) 183 | } 184 | }, 185 | methods: { 186 | handleSelect(key, keyPath) { 187 | 188 | }, 189 | setCache(data) { 190 | var message = { 191 | act: 'setOptions', 192 | data: JSON.stringify(data) 193 | } 194 | chrome.runtime.sendMessage(message, function(res) { 195 | //console.log(res) 196 | }) 197 | } 198 | } 199 | }) 200 | 201 | // 首字母大写 202 | function titleCase(str) { 203 | 204 | var array = str.toLowerCase().split("_"); 205 | for (var i = 0; i < array.length; i++){ 206 | array[i] = array[i][0].toUpperCase() + array[i].substring(1, array[i].length); 207 | } 208 | var string = array.join(""); 209 | 210 | return string; 211 | } 212 | 213 | // 类型映射 214 | function getTypeMap() { 215 | return { 216 | 'tinyint': 'int64', 217 | 'smallint': 'int64', 218 | 'int': 'int64', 219 | 'mediumint': 'int64', 220 | 'bigint': 'int64', 221 | 'float': 'float64', 222 | 'double': 'float64', 223 | 'decimal': 'float64', 224 | 'char': 'string', 225 | 'varchar': 'string', 226 | 'text': 'string', 227 | 'mediumtext': 'string', 228 | 'longtext': 'string', 229 | 'time': 'time.Time', 230 | 'date': 'time.Time', 231 | 'datetime': 'time.Time', 232 | 'timestramp': 'int64', 233 | 'enum': 'string', 234 | 'set': 'string', 235 | 'blob': 'string' 236 | } 237 | } -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= 2 | github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= 3 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 5 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM= 7 | github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= 8 | github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= 9 | github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= 10 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 11 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 12 | github.com/gin-gonic/gin v1.7.0 h1:jGB9xAJQ12AIGNB4HguylppmDK1Am9ppF7XnGXXJuoU= 13 | github.com/gin-gonic/gin v1.7.0/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= 14 | github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A= 15 | github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= 16 | github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= 17 | github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= 18 | github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= 19 | github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= 20 | github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= 21 | github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= 22 | github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs= 23 | github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 24 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= 25 | github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= 26 | github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= 27 | github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 28 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 29 | github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o= 30 | github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs= 31 | github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= 32 | github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= 33 | github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= 34 | github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= 35 | github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= 36 | github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 37 | github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= 38 | github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= 39 | github.com/lib/pq v1.1.1 h1:sJZmqHoEaY7f+NPP8pgLB/WxulyR3fewgCM2qaSlBb4= 40 | github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 41 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 42 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 43 | github.com/mattn/go-sqlite3 v1.14.0 h1:mLyGNKR8+Vv9CAU7PphKa2hkEqxxhn8i32J6FPj1/QA= 44 | github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus= 45 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 46 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 47 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 48 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 49 | github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= 50 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 51 | github.com/onrik/logrus v0.8.0 h1:lM37gnPr1doWCR1lgeV01Ti8zlDdsPWhEP2OEE1phZk= 52 | github.com/onrik/logrus v0.8.0/go.mod h1:qfe9NeZVAJfIxviw3cYkZo3kvBtLoPRJriAO8zl7qTk= 53 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 54 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 55 | github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= 56 | github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 57 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 58 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 59 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 60 | github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 61 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 62 | github.com/tdewolff/minify v2.3.6+incompatible h1:2hw5/9ZvxhWLvBUnHE06gElGYz+Jv9R4Eys0XUzItYo= 63 | github.com/tdewolff/minify v2.3.6+incompatible/go.mod h1:9Ov578KJUmAWpS6NeZwRZyT56Uf6o3Mcz9CEsg8USYs= 64 | github.com/tdewolff/parse v2.3.4+incompatible h1:x05/cnGwIMf4ceLuDMBOdQ1qGniMoxpP46ghf0Qzh38= 65 | github.com/tdewolff/parse v2.3.4+incompatible/go.mod h1:8oBwCsVmUkgHO8M5iCzSIDtpzXOT0WXX9cWhz+bIzJQ= 66 | github.com/tdewolff/test v1.0.0 h1:jOwzqCXr5ePXEPGJaq2ivoR6HOCi+D5TPfpoyg8yvmU= 67 | github.com/tdewolff/test v1.0.0/go.mod h1:DiQUlutnqlEvdvhSn2LPGy4TFwRauAaYDsL+683RNX4= 68 | github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= 69 | github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= 70 | github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= 71 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 72 | golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 73 | golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 74 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= 75 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 76 | golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 77 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 78 | golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 79 | golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= 80 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 81 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 82 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 83 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 84 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= 85 | golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 86 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 87 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 88 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 89 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 90 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 91 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 92 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 93 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 94 | -------------------------------------------------------------------------------- /src/model/fund.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/jinzhu/gorm" 7 | . "oktools/src/global" 8 | "time" 9 | ) 10 | 11 | type FundDataGenerated struct { 12 | Data FundData `json:"data"` 13 | ResultCode int `json:"result_code"` 14 | } 15 | type StockList struct { 16 | Name string `json:"name"` 17 | Code string `json:"code"` 18 | Percent float64 `json:"percent"` 19 | CurrentPrice float64 `json:"current_price"` 20 | ChangePercentage float64 `json:"change_percentage"` 21 | XqSymbol string `json:"xq_symbol"` 22 | XqURL string `json:"xq_url"` 23 | Amarket bool `json:"amarket"` 24 | } 25 | type FundPosition struct { 26 | StockPercent float64 `json:"stock_percent"` 27 | CashPercent float64 `json:"cash_percent"` 28 | OtherPercent float64 `json:"other_percent"` 29 | AssetTot float64 `json:"asset_tot"` 30 | AssetVal float64 `json:"asset_val"` 31 | SourceMark string `json:"source_mark"` 32 | Source string `json:"source"` 33 | Enddate string `json:"enddate"` 34 | StockList []StockList `json:"stock_list"` 35 | BondList []interface{} `json:"bond_list"` 36 | } 37 | type DeclareRateTable struct { 38 | Name string `json:"name"` 39 | Value string `json:"value"` 40 | } 41 | type WithdrawRateTable struct { 42 | Name string `json:"name"` 43 | Value string `json:"value"` 44 | } 45 | type OtherRateTable struct { 46 | Name string `json:"name"` 47 | Value string `json:"value"` 48 | } 49 | type FundRates struct { 50 | FdCode string `json:"fd_code"` 51 | SubscribeRate string `json:"subscribe_rate"` 52 | DeclareRate string `json:"declare_rate"` 53 | WithdrawRate string `json:"withdraw_rate"` 54 | Discount string `json:"discount"` 55 | SubscribeDiscount string `json:"subscribe_discount"` 56 | DeclareDiscount string `json:"declare_discount"` 57 | DeclareRateTable []DeclareRateTable `json:"declare_rate_table"` 58 | WithdrawRateTable []WithdrawRateTable `json:"withdraw_rate_table"` 59 | OtherRateTable []OtherRateTable `json:"other_rate_table"` 60 | } 61 | type AchievementList struct { 62 | FundCode string `json:"fund_code"` 63 | Fundsname string `json:"fundsname"` 64 | PostDate string `json:"post_date"` 65 | CpRate float64 `json:"cp_rate"` 66 | ResiDate string `json:"resi_date,omitempty"` 67 | } 68 | type ManagerList struct { 69 | Name string `json:"name"` 70 | Resume string `json:"resume"` 71 | College string `json:"college"` 72 | AchievementList []AchievementList `json:"achievement_list"` 73 | } 74 | type FundDateConf struct { 75 | FdCode string `json:"fd_code"` 76 | BuyConfirmDate int `json:"buy_confirm_date"` 77 | BuyQueryDate int `json:"buy_query_date"` 78 | SaleConfirmDate int `json:"sale_confirm_date"` 79 | SaleQueryDate int `json:"sale_query_date"` 80 | AllBuyDays int `json:"all_buy_days"` 81 | AllSaleDays int `json:"all_sale_days"` 82 | } 83 | type FundData struct { 84 | FundCompany string `json:"fund_company"` 85 | FundPosition FundPosition `json:"fund_position"` 86 | FundRates FundRates `json:"fund_rates"` 87 | ManagerList []ManagerList `json:"manager_list"` 88 | FundDateConf FundDateConf `json:"fund_date_conf"` 89 | } 90 | type Fund struct { 91 | /* 92 | `id` int(11) NOT NULL AUTO_INCREMENT, 93 | `fund_name` varchar(64) DEFAULT '' COMMENT '基金名称', 94 | `fund_code` varchar(16) NOT NULL DEFAULT '' COMMENT '基金代码', 95 | `managers` varchar(32) NOT NULL DEFAULT '' COMMENT '管理人', 96 | `enddate` varchar(32) NOT NULL DEFAULT '' COMMENT '季报日期', 97 | `type` varchar(32) NOT NULL DEFAULT '' COMMENT '基金类型', 98 | `detail_json` text NOT NULL COMMENT '蛋卷基金详细信息 json', 99 | `created_at` timestamp NULL DEFAULT NULL COMMENT '创建时间', 100 | `updated_at` timestamp NULL DEFAULT NULL COMMENT '更新时间', 101 | `deleted_at` timestamp NULL DEFAULT NULL COMMENT '删除时间', 102 | */ 103 | 104 | FundName string `json:"fund_name"` 105 | FundCode string `json:"fund_code"` 106 | Managers string `json:"managers"` 107 | Enddate string `json:"enddate"` 108 | Type string `json:"type"` 109 | DetailJson string `json:"detail_json"` 110 | 111 | ID int64 `json:"id" gorm:"primary_key"` 112 | CreatedAt JSONTime `json:"created_at" gorm:"column:created_at"` //创建日期 113 | UpdatedAt time.Time `json:"-" gorm:"column:updated_at"` 114 | DeletedAt *time.Time `json:"-" gorm:"column:deleted_at" sql:"index"` 115 | 116 | DB *gorm.DB `json:"-" gorm:"-"` // 数据库操作DB 117 | 118 | FundDataShow FundDataGenerated `json:"fund_data_show" gorm:"-"` 119 | } 120 | 121 | /** 122 | * 数据打码 123 | */ 124 | func (obj *Fund) Init() { 125 | if obj == nil { 126 | return 127 | } 128 | err := json.Unmarshal([]byte(obj.DetailJson), &obj.FundDataShow) 129 | if err != nil { 130 | fmt.Println(err.Error()) 131 | } 132 | 133 | return 134 | } 135 | 136 | /** 137 | * 获取结构体,方便对结构体的数据进行初始化 138 | */ 139 | func GetFund() Fund { 140 | var obj Fund 141 | obj.DB = SqlDB.Conn 142 | fmt.Println(SqlDB.Database) 143 | return obj 144 | } 145 | 146 | // 设置User的表名为`profiles` 147 | func (obj Fund) TableName() string { 148 | return "danjuan_fund" 149 | } 150 | 151 | // 获取数据库链接 152 | func (obj Fund) getDB() (db *gorm.DB) { 153 | db = obj.DB 154 | if db == nil { 155 | db = SqlDB.GetConn() 156 | } 157 | db = db.Table(obj.TableName()) 158 | db = db.Select(obj.FieldList()) 159 | return db 160 | } 161 | 162 | func (obj Fund) FieldList() (fieldList []string) { 163 | fieldList = SqlDB.GetFieldName(obj) 164 | return 165 | } 166 | 167 | //传递过来的json数据初始化 168 | func (obj *Fund) Insert() (id int64, err error) { 169 | err = obj.getDB().Create(&obj).Error 170 | if err == nil { 171 | id = obj.ID 172 | } 173 | return 174 | } 175 | 176 | // 更新部分, 可以清空 177 | func (obj *Fund) Update(id int64, updateData map[string]interface{}) (err error) { 178 | err = obj.Get(id) 179 | if err != nil { 180 | return 181 | } 182 | updateData = SqlDB.CleanChangeMap(updateData, obj) 183 | err = obj.getDB().Model(&obj).Updates(updateData).Error 184 | return 185 | } 186 | 187 | //删除数据 188 | func (obj *Fund) Delete(id int64) (err error) { 189 | err = obj.Get(id) 190 | if err != nil { 191 | return 192 | } 193 | err = obj.getDB().Delete(&obj).Error 194 | return 195 | } 196 | 197 | func (obj *Fund) GetCompanyByBankCardNum(company_id int64, bankNum string) (err error) { 198 | searchMap := make(map[string]string) 199 | searchMap["bd_num"] = bankNum 200 | 201 | err = obj.QueryOneByCondition(searchMap) 202 | return 203 | } 204 | 205 | //获取一个 206 | func (obj *Fund) Get(id int64) (err error) { 207 | err = obj.getDB().First(&obj, id).Error 208 | if err == nil { 209 | obj.Init() 210 | } 211 | return 212 | } 213 | 214 | //获取查询db 215 | func (obj *Fund) QueryDB(db *gorm.DB, searchKey map[string]string) (returnDB *gorm.DB) { 216 | 217 | // 查询扩展 218 | // 字段中如果字段 为 realname 219 | // 则默认支持以下查询 220 | // searchKey["realname"] 精确查询 "realname = ?", "%" + searchKey["realname_min"] + "%" 221 | // searchKey["realname_not"] 精确查询 "realname <> ?", "%" + searchKey["realname_min"] + "%" 222 | // searchKey["realname_like"] 模糊查询 "realname like ?", "%" + searchKey["realname_min"] + "%" 223 | // searchKey["realname_left_like"] 模糊左匹配查询 "realname like ?", searchKey["realname_min"] + "%" 224 | // searchKey["realname_min"] 查询 "realname >= ?" , searchKey["realname_min"] 225 | // searchKey["realname_max"] 查询 "realname <= ?" , searchKey["realname_min"] 226 | db = SqlDB.QueryDbInit(db, obj.FieldList(), searchKey) 227 | 228 | returnDB = db 229 | return 230 | } 231 | 232 | func (obj *Fund) QueryOneByCondition(searchKey map[string]string) (err error) { 233 | db := obj.getDB() 234 | db = obj.QueryDB(db, searchKey) 235 | err = db.First(&obj).Error 236 | 237 | if err == nil { 238 | obj.Init() 239 | } 240 | 241 | return 242 | } 243 | 244 | //列表 245 | func (obj *Fund) List(searchKey map[string]string, page int64, pageSize int64) (results []Fund, err error) { 246 | db := obj.getDB() 247 | 248 | db = obj.QueryDB(db, searchKey) 249 | 250 | // 待调整成 251 | // select a.* from 表1 a, (select id from 表1 where 条件 limit 100000,20) b where a.id=b.id 252 | // 253 | 254 | // 分页 255 | if page > 0 && pageSize > 0 { 256 | if page <= 30 { 257 | //30页前直接获取 258 | db = db.Limit(pageSize).Offset((page - 1) * pageSize) 259 | } else { 260 | 261 | db = db.Select("id as b__id") 262 | db = db.Limit(pageSize).Offset((page - 1) * pageSize) 263 | 264 | db = obj.getDB(). 265 | Table(obj.TableName()). 266 | Joins("join (?) b on id = b__id", db.QueryExpr()) 267 | } 268 | } else { 269 | if pageSize > 0 { 270 | db = db.Limit(pageSize) 271 | } 272 | } 273 | 274 | // 查询数据 275 | err = db.Find(&results).Error 276 | 277 | if err == nil { 278 | for k, _ := range results { 279 | (&results[k]).Init() 280 | } 281 | } 282 | return 283 | } 284 | 285 | //获取数量 286 | func (obj *Fund) Count(searchKey map[string]string) (totalSize int64, err error) { 287 | db := obj.getDB().Where("deleted_at is null") 288 | err = obj.QueryDB(db, searchKey).Count(&totalSize).Error 289 | 290 | return 291 | } 292 | --------------------------------------------------------------------------------