Compare commits

...

3 Commits

Author SHA1 Message Date
sk 0cc66a8b28 statistics文件下载 2024-12-26 08:26:00 +08:00
sk 82887c39c1 update excel 2024-12-26 08:25:12 +08:00
sk 6d1fe0c89b add 数据统计到mysql 2024-12-25 13:57:19 +08:00
11 changed files with 483 additions and 106 deletions

Binary file not shown.

View File

@ -7154,6 +7154,78 @@
"Compound": { "Compound": {
"71002": 10 "71002": 10
} }
},
{
"Id": 40005,
"Name": "金币赛门票",
"ShowLocation": [
1,
1,
0
],
"Classify": [
1,
1,
0
],
"Type": 4,
"Effect0": [
0,
0,
0,
0,
0,
0
],
"Effect": [
0,
0,
0,
0,
0,
0
],
"SaleGold": 100000,
"Composition": 1,
"CompositionMax": 1,
"Location": "0",
"Describe": "作用:用于报名特殊钻石赛事;\n产出途径存钱罐"
},
{
"Id": 40006,
"Name": "钻石赛门票",
"ShowLocation": [
1,
1,
0
],
"Classify": [
1,
1,
0
],
"Type": 4,
"Effect0": [
0,
0,
0,
0,
0,
0
],
"Effect": [
0,
0,
0,
0,
0,
0
],
"SaleGold": 100000,
"Composition": 1,
"CompositionMax": 1,
"Location": "0",
"Describe": "作用:用于报名特殊钻石赛事;\n产出途径存钱罐"
} }
] ]
} }

Binary file not shown.

Binary file not shown.

13
go.mod
View File

@ -19,6 +19,7 @@ require (
github.com/jinzhu/now v1.1.5 github.com/jinzhu/now v1.1.5
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
github.com/mojocn/base64Captcha v1.3.6 github.com/mojocn/base64Captcha v1.3.6
github.com/mozillazg/go-pinyin v0.20.0
github.com/spf13/cast v1.7.0 github.com/spf13/cast v1.7.0
github.com/spf13/viper v1.19.0 github.com/spf13/viper v1.19.0
github.com/tealeg/xlsx v1.0.5 github.com/tealeg/xlsx v1.0.5
@ -91,7 +92,7 @@ require (
github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/xtaci/kcp-go v5.4.20+incompatible // indirect github.com/xtaci/kcp-go v5.4.20+incompatible // indirect
github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d // indirect github.com/xuri/efp v0.0.0-20241211021726-c4e992084aa6 // indirect
github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 // indirect github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
go.etcd.io/etcd/api/v3 v3.5.16 // indirect go.etcd.io/etcd/api/v3 v3.5.16 // indirect
@ -102,12 +103,12 @@ require (
go.uber.org/automaxprocs v1.6.0 // indirect go.uber.org/automaxprocs v1.6.0 // indirect
go.uber.org/multierr v1.9.0 // indirect go.uber.org/multierr v1.9.0 // indirect
go.uber.org/zap v1.24.0 // indirect go.uber.org/zap v1.24.0 // indirect
golang.org/x/crypto v0.28.0 // indirect golang.org/x/crypto v0.31.0 // indirect
golang.org/x/image v0.18.0 // indirect golang.org/x/image v0.18.0 // indirect
golang.org/x/net v0.30.0 // indirect golang.org/x/net v0.33.0 // indirect
golang.org/x/sync v0.8.0 // indirect golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.26.0 // indirect golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.19.0 // indirect golang.org/x/text v0.21.0 // indirect
golang.org/x/time v0.7.0 // indirect golang.org/x/time v0.7.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect

13
go.sum
View File

@ -226,6 +226,8 @@ github.com/mojocn/base64Captcha v1.3.6 h1:gZEKu1nsKpttuIAQgWHO+4Mhhls8cAKyiV2Ew0
github.com/mojocn/base64Captcha v1.3.6/go.mod h1:i5CtHvm+oMbj1UzEPXaA8IH/xHFZ3DGY3Wh3dBpZ28E= github.com/mojocn/base64Captcha v1.3.6/go.mod h1:i5CtHvm+oMbj1UzEPXaA8IH/xHFZ3DGY3Wh3dBpZ28E=
github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/mozillazg/go-pinyin v0.20.0 h1:BtR3DsxpApHfKReaPO1fCqF4pThRwH9uwvXzm+GnMFQ=
github.com/mozillazg/go-pinyin v0.20.0/go.mod h1:iR4EnMMRXkfpFVV5FMi4FNB6wGq9NV6uDWbUuPhP4Yc=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
@ -386,6 +388,8 @@ github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37/go.mod h1:HpMP7DB2
github.com/xuri/efp v0.0.0-20200605144744-ba689101faaf/go.mod h1:uBiSUepVYMhGTfDeBKKasV4GpgBlzJ46gXUBAqV8qLk= github.com/xuri/efp v0.0.0-20200605144744-ba689101faaf/go.mod h1:uBiSUepVYMhGTfDeBKKasV4GpgBlzJ46gXUBAqV8qLk=
github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d h1:llb0neMWDQe87IzJLS4Ci7psK/lVsjIS2otl+1WyRyY= github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d h1:llb0neMWDQe87IzJLS4Ci7psK/lVsjIS2otl+1WyRyY=
github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
github.com/xuri/efp v0.0.0-20241211021726-c4e992084aa6 h1:8m6DWBG+dlFNbx5ynvrE7NgI+Y7OlZVMVTpayoW+rCc=
github.com/xuri/efp v0.0.0-20241211021726-c4e992084aa6/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
github.com/xuri/excelize/v2 v2.9.0 h1:1tgOaEq92IOEumR1/JfYS/eR0KHOCsRv/rYXXh6YJQE= github.com/xuri/excelize/v2 v2.9.0 h1:1tgOaEq92IOEumR1/JfYS/eR0KHOCsRv/rYXXh6YJQE=
github.com/xuri/excelize/v2 v2.9.0/go.mod h1:uqey4QBZ9gdMeWApPLdhm9x+9o2lq4iVmjiLfBS5hdE= github.com/xuri/excelize/v2 v2.9.0/go.mod h1:uqey4QBZ9gdMeWApPLdhm9x+9o2lq4iVmjiLfBS5hdE=
github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 h1:hPVCafDV85blFTabnqKgNhDCkJX25eik94Si9cTER4A= github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 h1:hPVCafDV85blFTabnqKgNhDCkJX25eik94Si9cTER4A=
@ -439,6 +443,8 @@ golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY= golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY=
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8=
@ -475,6 +481,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -487,6 +495,7 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -516,6 +525,8 @@ 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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
@ -528,6 +539,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=

View File

@ -1,13 +1,16 @@
StartTime: "2024-12-19T00:00:00+08:00" StartTime: "2024-12-25T00:00:00+08:00"
EndTime: "2024-12-20T00:00:00+08:00" EndTime: "2024-12-26T00:00:00+08:00"
IsDatabaseMode: true
ListenPort: 8888
Switch: # 1: open, 0: close Switch: # 1: open, 0: close
- 0 # 新用户游戏破产率 - 1 # 新用户游戏破产率
- 0 # 新用户平均游戏时长 - 1 # 新用户平均游戏时长
- 1 # 用户平均游戏时长 - 1 # 用户平均游戏时长
- 0 # 新用户平均局数 - 1 # 新用户平均局数
- 0 # 平均倍数 - 1 # 平均倍数
- 0 # 活跃破产率 - 1 # 活跃破产率
- 0 # 控输赢胜率 - 0 # 控输赢胜率
- 0 # 机器人胜率 - 0 # 机器人胜率
- 0 # 人均获得金币 - 0 # 人均获得金币

View File

@ -2,7 +2,14 @@ package main
import ( import (
"fmt" "fmt"
"golang.org/x/exp/maps"
"strings"
"github.com/mozillazg/go-pinyin"
"github.com/xuri/excelize/v2" "github.com/xuri/excelize/v2"
"gorm.io/gorm"
"mongo.games.com/goserver/core/logger"
"mongo.games.com/goserver/core/mysqlx"
) )
type ExcelData struct { type ExcelData struct {
@ -10,6 +17,10 @@ type ExcelData struct {
Head []string Head []string
Index int Index int
IndexCell int IndexCell int
TableName string
TableHead []string
DataName string
} }
func (e *ExcelData) SetHead(head []string) *ExcelData { func (e *ExcelData) SetHead(head []string) *ExcelData {
@ -59,13 +70,26 @@ func NewExcelMgr() *ExcelMgr {
} }
} }
func (e *ExcelMgr) Register(id int, head []string) *ExcelData { func (e *ExcelMgr) Register(id int, head []string, filename string) *ExcelData {
e.List[id] = &ExcelData{ e.List[id] = &ExcelData{
File: excelize.NewFile(), File: excelize.NewFile(),
Head: head, Head: head,
Index: 0, Index: 0,
} }
name := ChineseToPinYin([]string{filename})
if len(name) == 0 {
return nil
}
tableName := fmt.Sprintf("task_%s", name[0])
e.List[id].TableName = tableName
for _, v := range head {
cl := ChineseToPinYin([]string{v})[0]
e.List[id].TableHead = append(e.List[id].TableHead, cl)
}
e.List[id].DataName = filename
e.List[id].NewSheet("Sheet1") e.List[id].NewSheet("Sheet1")
if len(head) > 0 { if len(head) > 0 {
@ -79,10 +103,180 @@ func (e *ExcelMgr) Get(id int) *ExcelData {
return e.List[id] return e.List[id]
} }
func (e *ExcelMgr) Save(id int, fileName string) error { func (e *ExcelMgr) Save(id int, startTime, endTime string) error {
d := e.List[id] d := e.List[id]
if d == nil { if d == nil {
return nil return nil
} }
return d.SaveAs(fileName)
filename := fmt.Sprintf("%s_%s_%s.xlsx", d.DataName, startTime, endTime)
if VP.GetBool("IsDatabaseMode") {
rows, err := d.GetRows("Sheet1")
if err != nil {
return err
}
db, err := mysqlx.GetDatabase("1")
if err != nil {
logger.Logger.Errorf("GetDatabase error: %v", err)
return err
}
files := make(map[string]string)
index := make(map[string]string)
for _, v := range d.Head {
cl := ChineseToPinYin([]string{v})[0]
d.TableHead = append(d.TableHead, cl)
files[cl] = v
if strings.Contains(v, "*") {
index[cl] = "INDEX"
}
}
createSQL := buildCreateTableSQLWithIndices(d.TableName, d.DataName, files, index)
if err = db.Exec(createSQL).Error; err != nil {
logger.Logger.Errorf("createTable error: %v", err)
return err
}
if err = insertData(db.DB, d.TableName, maps.Keys(files), rows); err != nil {
logger.Logger.Errorf("insertData error: %v", err)
return err
}
return nil
}
return d.SaveAs(filename)
}
func (e *ExcelMgr) Pull(id int, startTime, endTime string) (*excelize.File, string, error) {
d := e.List[id]
if d == nil {
return nil, "", nil
}
db, err := mysqlx.GetDatabase("1")
if err != nil {
logger.Logger.Errorf("GetDatabase error: %v", err)
return nil, "", err
}
rows, err := db.Table(d.TableName).Where("ri_qi between ? and ?", startTime, endTime).Select(d.TableHead).Rows()
if err != nil {
logger.Logger.Errorf("Pull error: %v", err)
return nil, "", err
}
defer rows.Close()
f := excelize.NewFile()
f.NewSheet("Sheet1")
f.SetSheetRow("Sheet1", "A1", &d.Head)
index := 2
for rows.Next() {
data := make([]interface{}, len(d.TableHead))
scanArgs := make([]interface{}, len(d.TableHead))
for i := range data {
scanArgs[i] = &data[i]
}
err = rows.Scan(scanArgs...)
if err != nil {
logger.Logger.Errorf("Pull error: %v", err)
return nil, "", err
}
f.SetSheetRow("Sheet1", "A"+fmt.Sprintf("%d", index), &data)
index++
}
return f, fmt.Sprintf("%s_%s_%s", d.DataName, startTime, endTime), nil
}
// 构建创建表的 SQL 语句,支持中文描述和索引
func buildCreateTableSQLWithIndices(tableName string, comment string, fields map[string]string, indices map[string]string) string {
var columns []string
var indexDefs []string
// 遍历字段定义
for field, comment := range fields {
column := fmt.Sprintf("`%s` VARCHAR(255) COMMENT '%s'", field, comment)
columns = append(columns, column)
// 根据索引类型添加索引定义
if indexType, ok := indices[field]; ok {
switch strings.ToUpper(indexType) {
case "PRIMARY":
indexDefs = append(indexDefs, fmt.Sprintf("PRIMARY KEY (`%s`)", field))
case "UNIQUE":
indexDefs = append(indexDefs, fmt.Sprintf("UNIQUE KEY `idx_%s` (`%s`)", field, field))
case "INDEX":
indexDefs = append(indexDefs, fmt.Sprintf("KEY `idx_%s` (`%s`)", field, field))
}
}
}
// 拼接字段和索引部分
allDefs := append(columns, indexDefs...)
ret := fmt.Sprintf("CREATE TABLE IF NOT EXISTS `%s` (\n%s\n) COMMENT='%s';",
tableName,
strings.Join(allDefs, ",\n"), comment)
logger.Logger.Tracef("createTableSQL: %s", ret)
// 拼接最终的 SQL
return ret
}
func insertData(db *gorm.DB, tableName string, header []string, rows [][]string) error {
placeholders := strings.Repeat("?,", len(header))
placeholders = placeholders[:len(placeholders)-1] // 移除多余的逗号
insertSQL := fmt.Sprintf("INSERT INTO `%s` (%s) VALUES (%s)", tableName, "`"+strings.Join(header, "`,`")+"`", placeholders)
for _, row := range rows {
// 确保每行数据长度和表头一致
if len(row) < len(header) {
for len(row) < len(header) {
row = append(row, "") // 填充缺失列
}
}
err := db.Exec(insertSQL, interfaceSlice(row)...).Error
if err != nil {
return err
}
}
return nil
}
func interfaceSlice(slice []string) []interface{} {
result := make([]interface{}, len(slice))
for i, v := range slice {
result[i] = v
}
return result
}
var args = pinyin.NewArgs()
func init() {
args.Style = pinyin.Normal
}
func joinPinyin(py [][]string) string {
var result []string
for _, word := range py {
if len(word) > 0 {
result = append(result, word[0]) // 每个字的拼音取第一个候选
}
}
return strings.Join(result, "_")
}
func ChineseToPinYin(param []string) []string {
var ret []string
for _, v := range param {
ret = append(ret, joinPinyin(pinyin.Pinyin(v, args)))
}
return ret
} }

View File

@ -0,0 +1,51 @@
package main
import (
"net/http"
"strconv"
)
/*
下载
GET http://127.0.0.1:8888/statistics/task?data_type=0&start_time=2024-12-26&end_time=2024-12-26
请求参数
data_type 数据类型
0新用户游戏破产率
1新用户平均游戏时长
2用户平均游戏时长
3新用户平均局数
4平均倍数
5活跃破产率
start_time 开始时间
end_time 结束时间
*/
// Download 下载
func Download(w http.ResponseWriter, r *http.Request) {
// 请求参数
// data_type 数据类型
// start_time 开始时间
// end_time 结束时间
// Request parameters
dataType, err := strconv.Atoi(r.URL.Query().Get("data_type"))
if err != nil {
http.Error(w, "Invalid data_type", http.StatusBadRequest)
return
}
startTime := r.URL.Query().Get("start_time")
endTime := r.URL.Query().Get("end_time")
f, name, err := ExcelMgrSingle.Pull(dataType, startTime, endTime)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
defer f.Close()
w.Header().Set("Content-Type", "application/octet-stream;charset=UTF-8")
w.Header().Set("Content-Disposition", "attachment; filename=\""+name+".xlsx\"")
f.Write(w)
}

View File

@ -2,6 +2,10 @@ package main
import ( import (
"fmt" "fmt"
"mongo.games.com/goserver/core/utils"
"net/http"
"os"
"os/signal"
"sort" "sort"
"time" "time"
@ -11,6 +15,7 @@ import (
"mongo.games.com/goserver/core/mysqlx" "mongo.games.com/goserver/core/mysqlx"
"mongo.games.com/goserver/core/viperx" "mongo.games.com/goserver/core/viperx"
"mongo.games.com/game/common"
"mongo.games.com/game/statistics/task/gamefree" "mongo.games.com/game/statistics/task/gamefree"
"mongo.games.com/game/statistics/task/task" "mongo.games.com/game/statistics/task/task"
) )
@ -30,12 +35,93 @@ const (
) )
var VP *viper.Viper var VP *viper.Viper
var ExcelMgrSingle *ExcelMgr
func run() {
if VP.GetBool("IsDatabaseMode") {
VP.Set("StartTime", common.HMSToTime(0, 0, 0).Format(time.RFC3339))
VP.Set("EndTime", common.HMSToTime(0, 0, 0).AddDate(0, 0, 1).Format(time.RFC3339))
}
startTime, err := time.Parse(time.RFC3339, VP.GetString("StartTime"))
if err != nil {
panic(fmt.Sprintf("time.Parse err: %v", err))
return
}
endTime, err := time.Parse(time.RFC3339, VP.GetString("EndTime"))
if err != nil {
panic(fmt.Sprintf("time.Parse err: %v", err))
return
}
switchArr := VP.GetIntSlice("Switch")
for {
if startTime.Unix() >= endTime.Unix() {
break
}
startTimeStr := startTime.Format(time.RFC3339)
et := startTime.AddDate(0, 0, 1)
endTimeStr := et.Format(time.RFC3339)
logger.Logger.Infof("startTime: %v endTime: %v", startTimeStr, endTimeStr)
if switchArr[ExcelTypeNewPlayerBankrupt] == 1 {
// 新用户游戏破产率
ExcelMgrSingle.GenNewPlayerBankruptRateExcel("1", startTimeStr, endTimeStr)
}
if switchArr[ExcelTypeGameTimeAvg] == 1 {
// 新用户平均游戏时长
ExcelMgrSingle.GenNewPlayerGameTimeAvgExcel("1", startTimeStr, endTimeStr)
}
if switchArr[ExcelTypeGameTimeAllAvg] == 1 {
// 用户平均游戏时长
ExcelMgrSingle.GenPlayerGameTimeAvgExcel("1", startTimeStr, endTimeStr)
}
if switchArr[ExcelTypeGameCountAvg] == 1 {
// 新用户平均局数
ExcelMgrSingle.GenGameCountExcel("1", startTimeStr, endTimeStr)
}
if switchArr[ExcelTypeGameRate] == 1 {
// 平均倍数
ExcelMgrSingle.GenGameRateExcel("1", startTimeStr, endTimeStr)
}
if switchArr[ExcelTypeActiveRate] == 1 {
// 活跃破产率
ExcelMgrSingle.GenActiveBankruptRateExcel("1", startTimeStr, endTimeStr)
}
if switchArr[ExcelTypeCtrlWinRate] == 1 {
// 控赢胜率
ExcelMgrSingle.GenCtrlWinRateExcel("1", startTimeStr, endTimeStr)
}
if switchArr[ExcelTypeRobotWinRate] == 1 {
// 机器人胜率
ExcelMgrSingle.GenRobotWinRateExcel("1", startTimeStr, endTimeStr)
}
if switchArr[ExcelTypeCoinAvg] == 1 {
// 人均获得金币
ExcelMgrSingle.GenCoinAvgExcel("1", startTimeStr, endTimeStr)
}
if switchArr[ExcelTypeBankruptOffline] == 1 {
// 破产后离线
ExcelMgrSingle.GenBankruptOfflineExcel("1", startTimeStr, endTimeStr)
}
if switchArr[ExcelTypeOfflineCoin] == 1 {
// 离线金币
ExcelMgrSingle.GenOfflineCoinExcel("1", startTimeStr, endTimeStr)
}
startTime = et
}
ExcelMgrSingle.SaveAll(VP.GetString("StartTime")[:10], endTime.AddDate(0, 0, -1).Format(time.DateOnly))
}
func main() { func main() {
defer func() { defer func() {
logger.Logger.Flush() logger.Logger.Flush()
logger.Logger.Close() logger.Logger.Close()
}() }()
VP = viperx.GetViper("config.yaml") VP = viperx.GetViper("config.yaml")
// mongo // mongo
vp := viperx.GetViper("mongo.yaml") vp := viperx.GetViper("mongo.yaml")
@ -58,127 +144,84 @@ func main() {
mysqlx.Init(myConf) mysqlx.Init(myConf)
defer mysqlx.Close() defer mysqlx.Close()
startTime, err := time.Parse(time.RFC3339, VP.GetString("StartTime"))
if err != nil {
panic(fmt.Sprintf("time.Parse err: %v", err))
return
}
endTime, err := time.Parse(time.RFC3339, VP.GetString("EndTime"))
if err != nil {
panic(fmt.Sprintf("time.Parse err: %v", err))
return
}
mgr := NewExcelMgr() mgr := NewExcelMgr()
mgr.Register(ExcelTypeNewPlayerBankrupt, []string{"日期", "场次id", "破产人数", "参与人数", "破产率"}) ExcelMgrSingle = mgr
mgr.Register(ExcelTypeGameTimeAvg, []string{"日期", "场次id", "参与人数", "平均游戏时长"}) mgr.Register(ExcelTypeNewPlayerBankrupt, []string{"日期", "场次id", "破产人数", "参与人数", "破产率"}, "新用户破产率")
mgr.Register(ExcelTypeGameTimeAllAvg, []string{"日期", "场次id", "参与人数", "平均游戏时长"}) mgr.Register(ExcelTypeGameTimeAvg, []string{"日期", "场次id", "参与人数", "平均游戏时长"}, "新用户平均游戏时长")
mgr.Register(ExcelTypeGameCountAvg, []string{"日期", "场次id", "参与人数", "平均局数"}) mgr.Register(ExcelTypeGameTimeAllAvg, []string{"日期", "场次id", "参与人数", "平均游戏时长"}, "用户平均游戏时长")
mgr.Register(ExcelTypeGameRate, []string{"日期", "场次id", "总局数", "平均倍数", "有炸弹分局数", "炸弹分平均倍数", "2留在手里的局数"}) mgr.Register(ExcelTypeGameCountAvg, []string{"日期", "场次id", "参与人数", "平均局数"}, "新用户平均局数")
mgr.Register(ExcelTypeActiveRate, []string{"日期", "场次id", "破产人数", "参与人数", "破产率"}) mgr.Register(ExcelTypeGameRate, []string{"日期", "场次id", "总局数", "平均倍数", "有炸弹分局数", "炸弹分平均倍数", "2留在手里的局数"}, "平均倍数")
mgr.Register(ExcelTypeCtrlWinRate, []string{"日期", "场次id", "总局数", "平均倍数", "有炸弹分局数", "炸弹分平均倍数", "2留在手里的局数"}) mgr.Register(ExcelTypeActiveRate, []string{"日期", "场次id", "破产人数", "参与人数", "破产率"}, "活跃破产率")
mgr.Register(ExcelTypeCtrlWinRate*10, []string{"日期", "场次id", "总局数", "平均倍数", "有炸弹分局数", "炸弹分平均倍数", "2留在手里的局数"}) mgr.Register(ExcelTypeCtrlWinRate, []string{"日期", "场次id", "总局数", "平均倍数", "有炸弹分局数", "炸弹分平均倍数", "2留在手里的局数"}, "控赢胜率")
mgr.Register(ExcelTypeRobotWinRate, []string{"日期", "场次id", "总局数", "平均倍数", "有炸弹分局数", "炸弹分平均倍数", "2留在手里的局数"}) mgr.Register(ExcelTypeCtrlWinRate*10, []string{"日期", "场次id", "总局数", "平均倍数", "有炸弹分局数", "炸弹分平均倍数", "2留在手里的局数"}, "控数胜率")
mgr.Register(ExcelTypeCoinAvg, []string{"日期", "场次id", "参与人数", "人均获得金币"}) mgr.Register(ExcelTypeRobotWinRate, []string{"日期", "场次id", "总局数", "平均倍数", "有炸弹分局数", "炸弹分平均倍数", "2留在手里的局数"}, "机器人输率")
mgr.Register(ExcelTypeBankruptOffline, []string{"日期", "场次id", "破产人数", "参与人数", "破产率"}) mgr.Register(ExcelTypeCoinAvg, []string{"日期", "场次id", "参与人数", "人均获得金币"}, "人均获得金币")
mgr.Register(ExcelTypeOfflineCoin, []string{"日期", "场次id", "破产人数", "参与人数", "破产率"}) mgr.Register(ExcelTypeBankruptOffline, []string{"日期", "场次id", "破产人数", "参与人数", "破产率"}, "破产后离线")
switchArr := VP.GetIntSlice("Switch") mgr.Register(ExcelTypeOfflineCoin, []string{"日期", "场次id", "破产人数", "参与人数", "破产率"}, "离线金币")
for { if VP.GetBool("IsDatabaseMode") {
if startTime.Unix() >= endTime.Unix() { // 每天凌晨执行一次 run方法
break var f func()
f = func() {
nextTime := common.HMSToTime(0, 0, 0).AddDate(0, 0, 1)
time.AfterFunc(nextTime.Sub(time.Now())+time.Second*10, func() {
go utils.RepeatUntilPanicless(run)
f()
})
} }
startTimeStr := startTime.Format(time.RFC3339) f()
et := startTime.AddDate(0, 0, 1) //run()
endTimeStr := et.Format(time.RFC3339)
logger.Logger.Infof("startTime: %v endTime: %v", startTimeStr, endTimeStr)
if switchArr[ExcelTypeNewPlayerBankrupt] == 1 { listenPort := VP.GetString("ListenPort")
// 新用户游戏破产率 http.HandleFunc("/statistics/task", Download)
mgr.GenNewPlayerBankruptRateExcel("1", startTimeStr, endTimeStr) go http.ListenAndServe(fmt.Sprintf(":%v", listenPort), nil)
}
if switchArr[ExcelTypeGameTimeAvg] == 1 {
// 新用户平均游戏时长
mgr.GenNewPlayerGameTimeAvgExcel("1", startTimeStr, endTimeStr)
}
if switchArr[ExcelTypeGameTimeAllAvg] == 1 {
// 用户平均游戏时长
mgr.GenPlayerGameTimeAvgExcel("1", startTimeStr, endTimeStr)
}
if switchArr[ExcelTypeGameCountAvg] == 1 {
// 新用户平均局数
mgr.GenGameCountExcel("1", startTimeStr, endTimeStr)
}
if switchArr[ExcelTypeGameRate] == 1 {
// 平均倍数
mgr.GenGameRateExcel("1", startTimeStr, endTimeStr)
}
if switchArr[ExcelTypeActiveRate] == 1 {
// 活跃破产率
mgr.GenActiveBankruptRateExcel("1", startTimeStr, endTimeStr)
}
if switchArr[ExcelTypeCtrlWinRate] == 1 {
// 控赢胜率
mgr.GenCtrlWinRateExcel("1", startTimeStr, endTimeStr)
}
if switchArr[ExcelTypeRobotWinRate] == 1 {
// 机器人胜率
mgr.GenRobotWinRateExcel("1", startTimeStr, endTimeStr)
}
if switchArr[ExcelTypeCoinAvg] == 1 {
// 人均获得金币
mgr.GenCoinAvgExcel("1", startTimeStr, endTimeStr)
}
if switchArr[ExcelTypeBankruptOffline] == 1 {
// 破产后离线
mgr.GenBankruptOfflineExcel("1", startTimeStr, endTimeStr)
}
if switchArr[ExcelTypeOfflineCoin] == 1 {
// 离线金币
mgr.GenOfflineCoinExcel("1", startTimeStr, endTimeStr)
}
startTime = et logger.Logger.Infof("start server 0.0.0.0:%v", listenPort)
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, os.Kill)
sig := <-c
logger.Logger.Infof("closing down (signal: %v)", sig)
} else {
run()
} }
mgr.SaveAll(VP.GetString("StartTime")[:10], endTime.AddDate(0, 0, -1).Format(time.DateOnly))
} }
func (e *ExcelMgr) SaveAll(startTime, endTime string) { func (e *ExcelMgr) SaveAll(startTime, endTime string) {
switchArr := VP.GetIntSlice("Switch") switchArr := VP.GetIntSlice("Switch")
if switchArr[ExcelTypeNewPlayerBankrupt] == 1 { if switchArr[ExcelTypeNewPlayerBankrupt] == 1 {
e.Save(ExcelTypeNewPlayerBankrupt, fmt.Sprintf("新用户破产率_%s_%s.xlsx", startTime, endTime)) e.Save(ExcelTypeNewPlayerBankrupt, startTime, endTime)
} }
if switchArr[ExcelTypeGameTimeAvg] == 1 { if switchArr[ExcelTypeGameTimeAvg] == 1 {
e.Save(ExcelTypeGameTimeAvg, fmt.Sprintf("新用户平均游戏时长_%s_%s.xlsx", startTime, endTime)) e.Save(ExcelTypeGameTimeAvg, startTime, endTime)
} }
if switchArr[ExcelTypeGameTimeAllAvg] == 1 { if switchArr[ExcelTypeGameTimeAllAvg] == 1 {
e.Save(ExcelTypeGameTimeAllAvg, fmt.Sprintf("用户平均游戏时长_%s_%s.xlsx", startTime, endTime)) e.Save(ExcelTypeGameTimeAllAvg, startTime, endTime)
} }
if switchArr[ExcelTypeGameCountAvg] == 1 { if switchArr[ExcelTypeGameCountAvg] == 1 {
e.Save(ExcelTypeGameCountAvg, fmt.Sprintf("新用户平均局数_%s_%s.xlsx", startTime, endTime)) e.Save(ExcelTypeGameCountAvg, startTime, endTime)
} }
if switchArr[ExcelTypeGameRate] == 1 { if switchArr[ExcelTypeGameRate] == 1 {
e.Save(ExcelTypeGameRate, fmt.Sprintf("平均倍数_%s_%s.xlsx", startTime, endTime)) e.Save(ExcelTypeGameRate, startTime, endTime)
} }
if switchArr[ExcelTypeActiveRate] == 1 { if switchArr[ExcelTypeActiveRate] == 1 {
e.Save(ExcelTypeActiveRate, fmt.Sprintf("活跃破产率_%s_%s.xlsx", startTime, endTime)) e.Save(ExcelTypeActiveRate, startTime, endTime)
} }
if switchArr[ExcelTypeCtrlWinRate] == 1 { if switchArr[ExcelTypeCtrlWinRate] == 1 {
e.Save(ExcelTypeCtrlWinRate, fmt.Sprintf("控赢胜率_%s_%s.xlsx", startTime, endTime)) e.Save(ExcelTypeCtrlWinRate, startTime, endTime)
e.Save(ExcelTypeCtrlWinRate*10, fmt.Sprintf("控输胜率_%s_%s.xlsx", startTime, endTime)) e.Save(ExcelTypeCtrlWinRate*10, startTime, endTime)
} }
if switchArr[ExcelTypeRobotWinRate] == 1 { if switchArr[ExcelTypeRobotWinRate] == 1 {
e.Save(ExcelTypeRobotWinRate, fmt.Sprintf("机器人输率_%s_%s.xlsx", startTime, endTime)) e.Save(ExcelTypeRobotWinRate, startTime, endTime)
} }
if switchArr[ExcelTypeCoinAvg] == 1 { if switchArr[ExcelTypeCoinAvg] == 1 {
e.Save(ExcelTypeCoinAvg, fmt.Sprintf("人均获得金币_%s_%s.xlsx", startTime, endTime)) e.Save(ExcelTypeCoinAvg, startTime, endTime)
} }
if switchArr[ExcelTypeBankruptOffline] == 1 { if switchArr[ExcelTypeBankruptOffline] == 1 {
e.Save(ExcelTypeBankruptOffline, fmt.Sprintf("破产后离线_%s_%s.xlsx", startTime, endTime)) e.Save(ExcelTypeBankruptOffline, startTime, endTime)
} }
if switchArr[ExcelTypeOfflineCoin] == 1 { if switchArr[ExcelTypeOfflineCoin] == 1 {
e.Save(ExcelTypeOfflineCoin, fmt.Sprintf("离线金币_%s_%s.xlsx", startTime, endTime)) e.Save(ExcelTypeOfflineCoin, startTime, endTime)
} }
} }

Binary file not shown.