feat: 首次提交,添加Web界面和Redis支持的数据管理系统

This commit is contained in:
2025-09-01 00:45:37 +08:00
parent 7abb872b2c
commit b9fbe07b70
30 changed files with 4970 additions and 0 deletions

4
.gitignore vendored
View File

@@ -25,3 +25,7 @@ go.work.sum
# env file
.env
/.idea
/tmp
/token.json
/config.toml

47
config/config.go Normal file
View File

@@ -0,0 +1,47 @@
package config
import (
"fmt"
"github.com/spf13/viper"
)
type Config struct {
Host string `mapstructure:"host"`
RunMode string `mapstructure:"run-mode"`
Redis Redis `mapstructure:"redis"`
}
type Redis struct {
Host string `mapstructure:"host"`
Password string `mapstructure:"password"`
DB int `mapstructure:"db"`
}
var APPConfig Config
func InitConfig() {
//设置默认值
defaultConf := Config{
Host: "0.0.0.0:8080",
RunMode: "release",
Redis: Redis{
Host: "localhost:6379",
Password: "",
DB: 0,
},
}
viper.SetDefault("redis", defaultConf)
//设置配置文件名和路径 ./config.toml
viper.AddConfigPath(".")
viper.SetConfigName("config")
viper.SetConfigType("toml")
viper.SafeWriteConfig() //安全写入默认配置
//读取配置文件
if err := viper.ReadInConfig(); err != nil {
fmt.Errorf("无法读取配置文件: %w", err)
}
//解析配置文件
if err := viper.Unmarshal(&APPConfig); err != nil {
fmt.Errorf("无法解析配置: %w", err)
}
}

View File

@@ -0,0 +1,62 @@
package controller
import (
"dypid/db"
"dypid/global"
"dypid/model"
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
)
func ReadDataHandler(c *gin.Context) {
lLen := global.RDB.LLen(global.RCtx, fmt.Sprintf("list:%s", c.Query("token")))
if lLen.Val() == 0 {
c.JSON(200, gin.H{"result": "数据库没有数据"})
return
}
retData := global.RDB.BLPop(global.RCtx, 0, fmt.Sprintf("list:%s", c.Query("token")))
newData := model.Data{}
err := json.Unmarshal([]byte(retData.Val()[1]), &newData)
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
c.JSON(200, gin.H{"result": newData})
}
func WriteDataHandler(c *gin.Context) {
data := model.Data{}
if err := c.BindQuery(&data); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
dedupObject, err := db.GetDedupObject(data.Token)
if err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
err = createBF(fmt.Sprintf("dedup:%s:%s", data.Token, dedupObject), 0.01, 100000000)
if err != nil && err.Error() != "ERR item exists" {
c.JSON(400, gin.H{"error": err.Error()})
return
}
exists := global.RDB.BFExists(global.RCtx, fmt.Sprintf("dedup:%s:%s", data.Token, dedupObject), c.Query(dedupObject))
if exists.Val() {
return
}
marshal, err := json.Marshal(data)
if err != nil {
return
}
global.RDB.LPush(global.RCtx, fmt.Sprintf("list:%s", data.Token), marshal)
global.RDB.BFAdd(global.RCtx, fmt.Sprintf("dedup:%s:%s", data.Token, dedupObject), c.Query(dedupObject))
c.JSON(200, gin.H{"result": "ok"})
}
func createBF(bloomFilter string, errorRate float64, capacity int64) error {
_, err := global.RDB.BFReserve(global.RCtx, bloomFilter, errorRate, capacity).Result()
return err
}

View File

@@ -0,0 +1,122 @@
package controller
import (
"dypid/db"
"dypid/global"
"net/http"
"github.com/gin-gonic/gin"
)
func ListTokenHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"result": db.ListToken()})
}
func CreateTokenHandler(c *gin.Context) {
if c.Query("token") == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "token不能为空"})
return
} else if c.Query("dedup_object") == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "dedup_object不能为空"})
return
}
err := db.CreateToken(c.Query("token"), c.Query("dedup_object"))
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"result": "ok"})
}
func UpdateTokenHandler(c *gin.Context) {
if c.Query("token") == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "token不能为空"})
return
} else if c.Query("dedup_object") == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "dedup_object不能为空"})
return
}
err := db.UpdateToken(c.Query("token"), c.Query("dedup_object"))
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"result": "ok"})
}
func DeleteTokenHandler(c *gin.Context) {
if c.Query("token") == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "token不能为空"})
return
}
err := db.DeleteToken(c.Query("token"))
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"result": "ok"})
}
func GetTokenInfoHandler(c *gin.Context) {
input := struct {
Token string `form:"token" binding:"required"`
}{}
if err := c.ShouldBindQuery(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Token不能为空"})
return
}
dedupObject, err := db.GetDedupObject(input.Token)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "获取去重对象失败 " + err.Error()})
return
}
output := struct {
Token string `json:"token"`
DedupObject string `json:"dedup_object"`
DedupItemsNumber int64 `json:"dedup_items_number"`
CacheListNumber int64 `json:"cache_list_number"`
}{}
output.Token = input.Token
output.DedupObject = dedupObject
output.DedupItemsNumber = global.RDB.BFCard(global.RCtx, "dedup:"+input.Token+":"+dedupObject).Val()
output.CacheListNumber = global.RDB.LLen(global.RCtx, "list:"+input.Token).Val()
c.JSON(http.StatusOK, gin.H{"result": output})
}
func DeleteTokenInfoHandler(c *gin.Context) {
//解析输入数据
input := struct {
Token string `form:"token" binding:"required"`
DedupBF bool `form:"dedup_bf"`
CacheList bool `form:"cache_list"`
}{}
if err := c.ShouldBindQuery(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Token不能为空"})
return
}
//检查token是否存在
_, err := db.GetDedupObject(input.Token)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "Token不存在" + err.Error()})
return
}
//删除去重对象
if input.DedupBF {
keys := global.RDB.Keys(global.RCtx, "dedup:"+input.Token+":*").Val()
global.RDB.Del(global.RCtx, keys...)
}
if input.CacheList {
global.RDB.Del(global.RCtx, "list:"+input.Token)
}
//输出信息
c.JSON(http.StatusOK, gin.H{"result": "ok"})
}

107
db/local.go Normal file
View File

@@ -0,0 +1,107 @@
package db
import (
"encoding/json"
"errors"
"fmt"
"os"
)
var localDB []Token
type Token struct {
Token string `json:"token"`
DedupObject string `json:"dedup_object"`
}
func InitLocalDB() {
start:
data, err := os.ReadFile("./token.json")
if os.IsNotExist(err) {
os.WriteFile("./token.json", []byte("[]"), 0644)
goto start
} else if err != nil {
fmt.Println(err)
}
err = json.Unmarshal(data, &localDB)
if err != nil {
fmt.Println(err)
}
}
func ListToken() []Token {
InitLocalDB()
return localDB
}
func CreateToken(token string, dedupObject string) error {
InitLocalDB()
for _, t := range localDB {
if t.Token == token {
return errors.New("token已经存在")
}
}
a := append(localDB, Token{token, dedupObject})
marshal, err := json.Marshal(a)
if err != nil {
return err
}
if err := os.WriteFile("./token.json", marshal, 0644); err != nil {
return err
}
InitLocalDB()
return nil
}
func UpdateToken(token string, dedupObject string) error {
InitLocalDB()
for i, t := range localDB {
if t.Token == token {
localDB[i].DedupObject = dedupObject
marshal, err := json.Marshal(localDB)
if err != nil {
return err
}
if err := os.WriteFile("./token.json", marshal, 0644); err != nil {
return err
}
return nil
}
}
InitLocalDB()
return errors.New("token not found")
}
func DeleteToken(token string) error {
InitLocalDB()
for i, t := range localDB {
if t.Token == token {
localDB = append(localDB[:i], localDB[i+1:]...)
marshal, err := json.Marshal(localDB)
if err != nil {
return err
}
if err := os.WriteFile("./token.json", marshal, 0644); err != nil {
return err
}
return nil
}
}
InitLocalDB()
return errors.New("token not found")
}
func GetDedupObject(token string) (dedupObject string, err error) {
for i, t := range localDB {
if t.Token == token {
return localDB[i].DedupObject, nil
}
}
return "", errors.New("未找到Token")
}

26
db/redis.go Normal file
View File

@@ -0,0 +1,26 @@
package db
import (
"dypid/config"
"dypid/global"
"fmt"
"github.com/redis/go-redis/v9"
)
// InitRedis 初始化Redis
func InitRedis() {
global.RDB = redis.NewClient(&redis.Options{
Addr: config.APPConfig.Redis.Host,
Password: config.APPConfig.Redis.Password,
DB: config.APPConfig.Redis.DB,
//PoolSize: 1000,
})
ping := global.RDB.Ping(global.RCtx)
if ping.Err() != nil {
fmt.Println("Redis初始化失败", ping.Err())
panic("Redis error")
} else {
fmt.Println("Redis初始化完成")
}
}

10
global/global.go Normal file
View File

@@ -0,0 +1,10 @@
package global
import (
"context"
"github.com/redis/go-redis/v9"
)
var RDB *redis.Client
var RCtx = context.Background()

57
go.mod Normal file
View File

@@ -0,0 +1,57 @@
module dypid
go 1.25
require (
github.com/labstack/echo/v4 v4.13.4
github.com/redis/go-redis/v9 v9.12.1
github.com/spf13/viper v1.20.1
)
require (
github.com/bytedance/sonic v1.13.3 // indirect
github.com/bytedance/sonic/loader v0.2.4 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cloudwego/base64x v0.1.5 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/fsnotify/fsnotify v1.8.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
github.com/gin-contrib/cors v1.7.6 // indirect
github.com/gin-contrib/sse v1.1.0 // indirect
github.com/gin-contrib/static v1.1.5 // indirect
github.com/gin-gonic/gin v1.10.1 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.26.0 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/goccy/go-json v0.10.5 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
github.com/labstack/gommon v0.4.2 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/sagikazarmark/locafero v0.7.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.12.0 // indirect
github.com/spf13/cast v1.7.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.3.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
golang.org/x/arch v0.18.0 // indirect
golang.org/x/crypto v0.39.0 // indirect
golang.org/x/net v0.41.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.26.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

180
go.sum Normal file
View File

@@ -0,0 +1,180 @@
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ=
github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
github.com/bytedance/sonic v1.13.3 h1:MS8gmaH16Gtirygw7jV91pDCN33NyMrPbN7qiYhEsF0=
github.com/bytedance/sonic v1.13.3/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY=
github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
github.com/gin-contrib/cors v1.7.6 h1:3gQ8GMzs1Ylpf70y8bMw4fVpycXIeX1ZemuSQIsnQQY=
github.com/gin-contrib/cors v1.7.6/go.mod h1:Ulcl+xN4jel9t1Ry8vqph23a60FwH9xVLd+3ykmTjOk=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E=
github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0=
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
github.com/gin-contrib/static v1.1.5 h1:bAPqT4KTZN+4uDY1b90eSrD1t8iNzod7Jj8njwmnzz4=
github.com/gin-contrib/static v1.1.5/go.mod h1:8JSEXwZHcQ0uCrLPcsvnAJ4g+ODxeupP8Zetl9fd8wM=
github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo/v4 v4.13.4 h1:oTZZW+T3s9gAu5L8vmzihV7/lkXGZuITzTQkTEhcXEA=
github.com/labstack/echo/v4 v4.13.4/go.mod h1:g63b33BZ5vZzcIUF8AtRH40DrTlXnx4UMC8rBdndmjQ=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/redis/go-redis/v9 v9.12.1 h1:k5iquqv27aBtnTm2tIkROUDp8JBXhXZIVu1InSgvovg=
github.com/redis/go-redis/v9 v9.12.1/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4=
github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA=
github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/arch v0.16.0 h1:foMtLTdyOmIniqWCHjY6+JxuC54XP1fDwx4N0ASyW+U=
golang.org/x/arch v0.16.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
golang.org/x/arch v0.18.0 h1:WN9poc33zL4AzGxqf8VtpKUnGvMi8O9lhNyBMF/85qc=
golang.org/x/arch v0.18.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

59
main.go Normal file
View File

@@ -0,0 +1,59 @@
package main
import (
"dypid/config"
"dypid/controller"
"dypid/db"
"embed"
"fmt"
"github.com/gin-contrib/cors"
"github.com/gin-contrib/static"
"github.com/gin-gonic/gin"
)
//go:embed web/dist/*
var webDir embed.FS
func main() {
config.InitConfig()
db.InitRedis()
db.InitLocalDB()
//初始化一个http服务对象
gin.SetMode(config.APPConfig.RunMode)
r := gin.Default()
//跨域设置
r.Use(cors.Default())
//静态文件目录
web, err := static.EmbedFolder(webDir, "web/dist")
if err != nil {
panic(err)
}
r.Use(static.Serve("/", web))
//API接口
g := r.Group("/api") //初始化路由组 /api/xxxx
{
g.GET("/token", controller.ListTokenHandler) //获取token列表
g.POST("/token", controller.CreateTokenHandler) //创建token
g.PUT("/token", controller.UpdateTokenHandler) //更新token
g.DELETE("/token", controller.DeleteTokenHandler) //删除token
g.GET("/token/info", controller.GetTokenInfoHandler) //获取token信息
g.DELETE("/token/info", controller.DeleteTokenInfoHandler) //删除token数据库
}
{
g.GET("/data", controller.ReadDataHandler) //获取数据
g.POST("/data", controller.WriteDataHandler) //写入数据
}
// 监听并在 0.0.0.0:8080 上启动服务
fmt.Printf("服务器正在%s运行\n", config.APPConfig.Host)
err = r.Run(config.APPConfig.Host)
if err != nil {
fmt.Println("服务启动失败:", err)
return
}
}
//atomic.AddInt64(&Same, 1)

16
model/data.go Normal file
View File

@@ -0,0 +1,16 @@
package model
type Data struct {
Token string `form:"token" json:"token"`
Uid string `form:"uid" json:"uid"`
Pid string `form:"pid" json:"pid"`
SecId string `form:"secid" json:"secId"`
Dyid string `form:"dyid" json:"dyid"`
Key string `form:"key" json:"key"`
CommentId string `form:"comment_id" json:"comment_id"`
Id1 string `form:"id1" json:"id1"`
Id2 string `form:"id2" json:"id2"`
Id3 string `form:"id3" json:"id3"`
Id4 string `form:"id4" json:"id4"`
Id5 string `form:"id5" json:"id5"`
}

1
web/.env.production Normal file
View File

@@ -0,0 +1 @@
VITE_API_BASE_URL=

30
web/.gitignore vendored Normal file
View File

@@ -0,0 +1,30 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.tsbuildinfo

33
web/README.md Normal file
View File

@@ -0,0 +1,33 @@
# web
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
## Type Support for `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.
## Customize configuration
See [Vite Configuration Reference](https://vite.dev/config/).
## Project Setup
```sh
npm install
```
### Compile and Hot-Reload for Development
```sh
npm run dev
```
### Type-Check, Compile and Minify for Production
```sh
npm run build
```

1
web/env.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
/// <reference types="vite/client" />

13
web/index.html Normal file
View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

3758
web/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

34
web/package.json Normal file
View File

@@ -0,0 +1,34 @@
{
"name": "web",
"version": "0.0.0",
"private": true,
"type": "module",
"engines": {
"node": "^20.19.0 || >=22.12.0"
},
"scripts": {
"dev": "vite",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --build"
},
"dependencies": {
"axios": "^1.11.0",
"element-plus": "^2.11.1",
"pinia": "^3.0.3",
"vue": "^3.5.18",
"vue-router": "^4.5.1"
},
"devDependencies": {
"@tsconfig/node22": "^22.0.2",
"@types/node": "^22.16.5",
"@vitejs/plugin-vue": "^6.0.1",
"@vue/tsconfig": "^0.7.0",
"npm-run-all2": "^8.0.4",
"typescript": "~5.8.0",
"vite": "^7.0.6",
"vite-plugin-vue-devtools": "^8.0.0",
"vue-tsc": "^3.0.4"
}
}

BIN
web/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

59
web/src/App.vue Normal file
View File

@@ -0,0 +1,59 @@
<script setup lang="ts">
import {ref, watch} from 'vue'
import {useRoute, useRouter} from "vue-router";
const router = useRouter()
const route = useRoute()
const activeIndex = ref(route.name?.toString() || "TokenList")
watch(route, (newRoute) => {
activeIndex.value = newRoute.name?.toString() || "TokenList"
})
const handleSelect = (key: string) => {
router.push({
name: key
})
}
</script>
<template>
<el-container>
<el-header>
<el-menu
:default-active="activeIndex"
class="el-menu-demo"
mode="horizontal"
@select="handleSelect"
>
<el-menu-item index="TokenList">Token列表</el-menu-item>
<el-menu-item index="TokenDetail">Token信息</el-menu-item>
</el-menu>
</el-header>
<el-container>
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</template>
<style>
html, body, #app {
height: 100%;
margin: 0;
padding: 0;
}
.el-container {
height: 100%;
}
.el-menu-demo {
line-height: 60px;
}
</style>

7
web/src/axios.ts Normal file
View File

@@ -0,0 +1,7 @@
import axios from 'axios';
const instance = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL,
});
export default instance;

15
web/src/main.ts Normal file
View File

@@ -0,0 +1,15 @@
import {createApp} from 'vue'
import {createPinia} from 'pinia'
import App from './App.vue'
import router from './router'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.use(ElementPlus)
app.mount('#app')

16
web/src/router/index.ts Normal file
View File

@@ -0,0 +1,16 @@
import {createRouter, createWebHistory} from 'vue-router'
import TokenListView from '@/views/TokenListView.vue'
import TokenDetailView from '@/views/TokenDetailView.vue'
const routes = [
{path: '/', name: "TokenList", component: TokenListView},
{path: '/token', name: "TokenDetail", component: TokenDetailView},
];
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes,
})
export default router

View File

@@ -0,0 +1,8 @@
import {ref, computed} from 'vue'
import {defineStore} from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const token = ref("")
return {token}
})

View File

@@ -0,0 +1,62 @@
<script setup lang="ts">
import {useCounterStore} from "@/stores/counter.ts";
import {ref} from 'vue'
import axios from "@/axios.ts";
const result = ref()
const getInfo = () => {
axios.get('/api/token/info', {
params: {
token: useCounterStore().token
}
}).then(res => {
if (res.status == 200) {
result.value = res.data.result
}
})
}
const deleteDedup = () => {
axios.delete('/api/token/info', {
params: {
token: useCounterStore().token,
dedup_bf: true
}
})
}
const deleteRedis = () => {
axios.delete('/api/token/info', {
params: {
token: useCounterStore().token,
cache_list: true
}
})
}
getInfo()
setInterval(getInfo, 5000)
</script>
<template>
<p>当前Token{{ useCounterStore().token }}</p>
<el-button type="danger" @click="deleteDedup">删除去重记录值</el-button>
<el-button type="danger" @click="deleteRedis">删除Redis数据</el-button>
<el-divider/>
<el-button type="primary" @click="getInfo">手动刷新</el-button>
<el-descriptions
:title="'Token信息 - ' + useCounterStore().token+'(每5秒刷新)'"
direction="vertical"
:column="4"
border
>
<el-descriptions-item label="去重对象">{{ result?.dedup_object }}</el-descriptions-item>
<el-descriptions-item label="去重记录值">{{ result?.dedup_items_number }}</el-descriptions-item>
<el-descriptions-item label="Redis中数据条数">{{ result?.cache_list_number }}</el-descriptions-item>
</el-descriptions>
</template>
<style scoped>
</style>

View File

@@ -0,0 +1,183 @@
<script setup lang="ts">
import {ref} from "vue";
import axios from "@/axios.ts";
import {ElMessage, ElMessageBox} from 'element-plus'
const tableData = ref([])
axios.get("/api/token").then(res => {
tableData.value = res.data.result
})
const input = ref('')
const value = ref('')
const options = [
{
value: 'token',
label: 'token',
},
{
value: 'uid',
label: 'uid',
},
{
value: 'pid',
label: 'pid',
},
{
value: 'secid',
label: 'secid',
},
{
value: 'dyid',
label: 'dyid',
},
{
value: 'key',
label: 'key',
},
{
value: 'comment_id',
label: 'comment_id',
}
]
const addToken = () => {
axios.post('/api/token', {}, {
params: {
token: input.value,
dedup_object: value.value
}
}).then(response => {
if (response.data.result == "ok") {
ElMessage({
message: '添加成功',
type: 'success',
})
axios.get('/api/token').then(res => {
tableData.value = res.data.result
})
}
}).catch(error => {
ElMessage.error(error.response?.data?.error)
})
}
import {useCounterStore} from "@/stores/counter.ts";
import {useRouter} from "vue-router";
const router = useRouter()
const viewDetails = (row: any) => {
useCounterStore().token = row.token
router.push({
name: "TokenDetail"
})
}
var rowOut: any
const dedupObjectVisible = ref(false)
const dialogDedupObjectVisible = (row: any) => {
rowOut = row
dedupObjectVisible.value = true
}
const updateDedupObject = () => {
dedupObjectVisible.value = false
axios.put('/api/token', {}, {
params: {
token: rowOut.token,
dedup_object: value.value
}
}).then(res => {
if (res.data.result == "ok") {
ElMessage({
message: '更改成功',
type: 'success',
})
axios.get('/api/token').then(res => {
tableData.value = res.data.result
})
}
}).catch(error => {
ElMessage.error(error.response?.data?.error)
})
}
const deleteToken = (row: any) => {
axios.delete('/api/token', {
params: {
token: row.token
}
}).then(res => {
if (res.data.result == "ok") {
ElMessage({
message: '删除成功',
type: 'success',
})
axios.get('/api/token').then(res => {
tableData.value = res.data.result
})
}
}).catch(error => {
ElMessage.error(error.response?.data?.error)
})
}
</script>
<template>
<!--添加Token-->
<el-input v-model="input" style="width: 200px" placeholder="请输入Token名称"/>
<el-select v-model="value" placeholder="选择去重对象" style="width: 200px">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-button type="primary" @click="addToken">添加Token</el-button>
<!--Token列表-->
<el-table :data="tableData" style="width: 100%">
<el-table-column prop="token" label="Token" width="180"/>
<el-table-column prop="dedup_object" label="去重对象" width="180"/>
<el-table-column label="操作">
<template #default="scope">
<el-button @click="viewDetails(scope.row)">查看详细</el-button>
<el-button @click="dialogDedupObjectVisible(scope.row)" type="primary">更改去重对象</el-button>
<el-popconfirm
width="180"
title="确认删除此Token吗"
confirm-button-text="确认"
cancel-button-text="取消"
@confirm="deleteToken(scope.row)"
>
<template #reference>
<el-button type="danger">删除此Token</el-button>
</template>
</el-popconfirm>
</template>
</el-table-column>
</el-table>
<el-dialog v-model="dedupObjectVisible" title="更改去重对象" width="400">
<el-select v-model="value" placeholder="选择去重对象" style="width: 200px">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<template #footer>
<el-button type="primary" @click="updateDedupObject">
确定
</el-button>
</template>
</el-dialog>
</template>
<style scoped>
</style>

12
web/tsconfig.app.json Normal file
View File

@@ -0,0 +1,12 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"paths": {
"@/*": ["./src/*"]
}
}
}

11
web/tsconfig.json Normal file
View File

@@ -0,0 +1,11 @@
{
"files": [],
"references": [
{
"path": "./tsconfig.node.json"
},
{
"path": "./tsconfig.app.json"
}
]
}

19
web/tsconfig.node.json Normal file
View File

@@ -0,0 +1,19 @@
{
"extends": "@tsconfig/node22/tsconfig.json",
"include": [
"vite.config.*",
"vitest.config.*",
"cypress.config.*",
"nightwatch.conf.*",
"playwright.config.*",
"eslint.config.*"
],
"compilerOptions": {
"noEmit": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"module": "ESNext",
"moduleResolution": "Bundler",
"types": ["node"]
}
}

18
web/vite.config.ts Normal file
View File

@@ -0,0 +1,18 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueDevTools from 'vite-plugin-vue-devtools'
// https://vite.dev/config/
export default defineConfig({
plugins: [
vue(),
vueDevTools(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
},
},
})