fix: 添加bbxt工具包和数据处理功能
This commit is contained in:
parent
a9a05c19e9
commit
0d8ef7056c
19
go.mod
19
go.mod
|
|
@ -25,11 +25,13 @@ require (
|
|||
github.com/gofiber/websocket/v2 v2.2.1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/google/wire v0.7.0
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/ollama/ollama v0.12.7
|
||||
github.com/redis/go-redis/v9 v9.16.0
|
||||
github.com/spf13/viper v1.17.0
|
||||
github.com/tmc/langchaingo v0.1.13
|
||||
golang.org/x/sync v0.15.0
|
||||
github.com/xuri/excelize/v2 v2.10.0
|
||||
golang.org/x/sync v0.17.0
|
||||
google.golang.org/grpc v1.64.0
|
||||
gorm.io/driver/mysql v1.6.0
|
||||
gorm.io/gorm v1.31.0
|
||||
|
|
@ -69,7 +71,6 @@ require (
|
|||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
|
|
@ -86,6 +87,8 @@ require (
|
|||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pkoukk/tiktoken-go v0.1.6 // indirect
|
||||
github.com/richardlehane/mscfb v1.0.4 // indirect
|
||||
github.com/richardlehane/msoleps v1.0.4 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.3.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
|
|
@ -96,23 +99,25 @@ require (
|
|||
github.com/spf13/afero v1.10.0 // indirect
|
||||
github.com/spf13/cast v1.5.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/stretchr/testify v1.11.1 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/tiendc/go-deepcopy v1.7.1 // indirect
|
||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.51.0 // indirect
|
||||
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
|
||||
github.com/xuri/efp v0.0.1 // indirect
|
||||
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 // indirect
|
||||
github.com/yargevad/filepathx v1.0.0 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
golang.org/x/arch v0.11.0 // indirect
|
||||
golang.org/x/crypto v0.39.0 // indirect
|
||||
golang.org/x/crypto v0.43.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect
|
||||
golang.org/x/net v0.38.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/text v0.26.0 // indirect
|
||||
golang.org/x/net v0.46.0 // indirect
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect
|
||||
google.golang.org/protobuf v1.34.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
|
|
|
|||
39
go.sum
39
go.sum
|
|
@ -368,6 +368,11 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH
|
|||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/redis/go-redis/v9 v9.16.0 h1:OotgqgLSRCmzfqChbQyG1PHC3tLNR89DG4jdOERSEP4=
|
||||
github.com/redis/go-redis/v9 v9.16.0/go.mod h1:u410H11HMLoB+TP67dz8rL9s6QW2j76l0//kSOd3370=
|
||||
github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM=
|
||||
github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk=
|
||||
github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
|
||||
github.com/richardlehane/msoleps v1.0.4 h1:WuESlvhX3gH2IHcd8UqyCuFY5yiq/GR/yqaSM/9/g00=
|
||||
github.com/richardlehane/msoleps v1.0.4/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
|
|
@ -423,6 +428,8 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
|
|||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/tiendc/go-deepcopy v1.7.1 h1:LnubftI6nYaaMOcaz0LphzwraqN8jiWTwm416sitff4=
|
||||
github.com/tiendc/go-deepcopy v1.7.1/go.mod h1:4bKjNC2r7boYOkD2IOuZpYjmlDdzjbpTRyCx+goBCJQ=
|
||||
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
|
||||
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||
|
|
@ -440,6 +447,12 @@ github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/
|
|||
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
|
||||
github.com/x-cray/logrus-prefixed-formatter v0.5.2 h1:00txxvfBM9muc0jiLIEAkAcIMJzfthRT6usrui8uGmg=
|
||||
github.com/x-cray/logrus-prefixed-formatter v0.5.2/go.mod h1:2duySbKsL6M18s5GU7VPsoEPHyzalCE06qoARUCeBBE=
|
||||
github.com/xuri/efp v0.0.1 h1:fws5Rv3myXyYni8uwj2qKjVaRP30PdjeYe2Y6FDsCL8=
|
||||
github.com/xuri/efp v0.0.1/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
|
||||
github.com/xuri/excelize/v2 v2.10.0 h1:8aKsP7JD39iKLc6dH5Tw3dgV3sPRh8uRVXu/fMstfW4=
|
||||
github.com/xuri/excelize/v2 v2.10.0/go.mod h1:SC5TzhQkaOsTWpANfm+7bJCldzcnU/jrhqkTi/iBHBU=
|
||||
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 h1:+C0TIdyyYmzadGaL/HBLbf3WdLgC29pgyhTjAT/0nuE=
|
||||
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
|
||||
github.com/yargevad/filepathx v1.0.0 h1:SYcT+N3tYGi+NvazubCNlvgIPbzAk7i7y2dwg3I5FYc=
|
||||
github.com/yargevad/filepathx v1.0.0/go.mod h1:BprfX/gpYNJHJfc35GjRRpVcwWXS89gGulUIU5tK3tA=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
|
|
@ -479,8 +492,8 @@ golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf
|
|||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
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/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
|
|
@ -495,6 +508,8 @@ golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrC
|
|||
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
|
||||
golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
|
|
@ -561,8 +576,8 @@ golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
|||
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
|
||||
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
|
@ -584,8 +599,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
||||
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
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-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
|
@ -640,8 +655,8 @@ golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
|
|
@ -650,8 +665,8 @@ golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
|
|||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
|
||||
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
|
||||
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
||||
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
|
@ -664,8 +679,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
|
||||
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/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.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
|
|
|
|||
|
|
@ -6,8 +6,14 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
)
|
||||
|
||||
func JsonStringIgonErr(data interface{}) string {
|
||||
|
|
@ -165,3 +171,190 @@ func SafeReplace(template string, replaceTag string, replacements ...string) (st
|
|||
|
||||
return template, nil
|
||||
}
|
||||
|
||||
func StructToMapUsingJsoniter(obj interface{}) (map[string]string, error) {
|
||||
var json = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
|
||||
// 转换为JSON
|
||||
jsonBytes, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 解析为map[string]interface{}
|
||||
var tempMap map[string]interface{}
|
||||
err = json.Unmarshal(jsonBytes, &tempMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 转换为map[string]string
|
||||
result := make(map[string]string)
|
||||
for k, v := range tempMap {
|
||||
result[k] = fmt.Sprintf("%v", v)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func GetModuleDir() (string, error) {
|
||||
dir, err := os.Getwd()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for {
|
||||
modPath := filepath.Join(dir, "go.mod")
|
||||
if _, err := os.Stat(modPath); err == nil {
|
||||
return dir, nil // 找到 go.mod
|
||||
}
|
||||
|
||||
// 向上查找父目录
|
||||
parent := filepath.Dir(dir)
|
||||
if parent == dir {
|
||||
break // 到达根目录,未找到
|
||||
}
|
||||
dir = parent
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("go.mod not found in current directory or parents")
|
||||
}
|
||||
|
||||
// GetCacheDir 用于获取缓存目录路径
|
||||
// 如果缓存目录不存在,则会自动创建
|
||||
// 返回值:
|
||||
// - string: 缓存目录的路径
|
||||
// - error: 如果获取模块目录失败或创建缓存目录失败,则返回错误信息
|
||||
func GetCacheDir() (string, error) {
|
||||
// 获取模块目录
|
||||
modDir, err := GetModuleDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// 拼接缓存目录路径
|
||||
path := fmt.Sprintf("%s/cache", modDir)
|
||||
// 创建目录(包括所有必要的父目录),权限设置为0755
|
||||
err = os.MkdirAll(path, 0755)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("创建目录失败: %w", err)
|
||||
}
|
||||
// 返回成功创建的缓存目录路径
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func GetTmplDir() (string, error) {
|
||||
modDir, err := GetModuleDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
path := fmt.Sprintf("%s/tmpl", modDir)
|
||||
err = os.MkdirAll(path, 0755)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("创建目录失败: %w", err)
|
||||
}
|
||||
return path, nil
|
||||
}
|
||||
|
||||
// 通用结构体转 Query 参数
|
||||
func StructToQuery(obj interface{}) (url.Values, error) {
|
||||
values := url.Values{}
|
||||
v := reflect.ValueOf(obj)
|
||||
t := reflect.TypeOf(obj)
|
||||
|
||||
// 如果是指针,获取指向的值
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
t = t.Elem()
|
||||
}
|
||||
|
||||
// 确保是结构体
|
||||
if v.Kind() != reflect.Struct {
|
||||
return values, fmt.Errorf("expected struct, got %v", v.Kind())
|
||||
}
|
||||
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
field := v.Field(i)
|
||||
fieldType := t.Field(i)
|
||||
|
||||
// 跳过零值字段(omitempty)
|
||||
tag := fieldType.Tag.Get("json")
|
||||
if strings.Contains(tag, "omitempty") && field.IsZero() {
|
||||
continue
|
||||
}
|
||||
|
||||
// 获取字段名
|
||||
fieldName := getFieldName(fieldType)
|
||||
if fieldName == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
// 处理不同类型的字段
|
||||
addFieldToValues(values, fieldName, field)
|
||||
}
|
||||
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func getFieldName(field reflect.StructField) string {
|
||||
tag := field.Tag.Get("json")
|
||||
if tag != "" {
|
||||
parts := strings.Split(tag, ",")
|
||||
if parts[0] != "-" && parts[0] != "" {
|
||||
return parts[0]
|
||||
}
|
||||
if parts[0] == "-" {
|
||||
return "" // 跳过该字段
|
||||
}
|
||||
}
|
||||
return field.Name
|
||||
}
|
||||
|
||||
func addFieldToValues(values url.Values, name string, field reflect.Value) {
|
||||
if !field.IsValid() || field.IsZero() {
|
||||
return
|
||||
}
|
||||
|
||||
switch field.Kind() {
|
||||
case reflect.String:
|
||||
values.Add(name, field.String())
|
||||
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
values.Add(name, strconv.FormatInt(field.Int(), 10))
|
||||
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
values.Add(name, strconv.FormatUint(field.Uint(), 10))
|
||||
|
||||
case reflect.Float32, reflect.Float64:
|
||||
values.Add(name, strconv.FormatFloat(field.Float(), 'f', -1, 64))
|
||||
|
||||
case reflect.Bool:
|
||||
values.Add(name, strconv.FormatBool(field.Bool()))
|
||||
|
||||
case reflect.Slice:
|
||||
// 处理切片,特别是 []string
|
||||
if field.Type().Elem().Kind() == reflect.String {
|
||||
for i := 0; i < field.Len(); i++ {
|
||||
item := field.Index(i).String()
|
||||
// 特殊处理 ct 字段
|
||||
if name == "ct" {
|
||||
formatted := strings.Replace(item, " ", "+", 1)
|
||||
if i == 1 && field.Len() >= 2 {
|
||||
formatted = formatted + ".999"
|
||||
}
|
||||
values.Add("ct[]", formatted)
|
||||
} else {
|
||||
values.Add(fmt.Sprintf("%s[]", name), item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case reflect.Struct:
|
||||
// 处理 time.Time
|
||||
if t, ok := field.Interface().(time.Time); ok {
|
||||
values.Add(name, t.Format("2006-01-02+15:04:05"))
|
||||
}
|
||||
|
||||
default:
|
||||
values.Add(name, fmt.Sprintf("%v", field.Interface()))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,210 @@
|
|||
package bbxt
|
||||
|
||||
import (
|
||||
"ai_scheduler/internal/pkg"
|
||||
"ai_scheduler/internal/pkg/l_request"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type StatisOursProductLossSumReq struct {
|
||||
ResellerId int `json:"reseller_id,omitempty"`
|
||||
Ct []string `json:"ct,omitempty"`
|
||||
}
|
||||
|
||||
type StatisOursProductLossSumRes struct {
|
||||
List []*StatisOursProductLossSumResponse `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
|
||||
}
|
||||
|
||||
type StatisOursProductLossSumResponse struct {
|
||||
OursProductId int32 `json:"oursProductId,omitempty"`
|
||||
OursProductName string `json:"oursProductName,omitempty"`
|
||||
ResellerName string `json:"resellerName,omitempty"`
|
||||
ResellerId int32 `json:"resellerId,omitempty"`
|
||||
Loss float64 `json:"loss,omitempty"`
|
||||
}
|
||||
|
||||
const Base = "https://reportapi.1688sup.com/api"
|
||||
|
||||
// StatisOursProductLossSumApi 负利润分析
|
||||
func StatisOursProductLossSumApi(param *StatisOursProductLossSumReq) (*StatisOursProductLossSumRes, error) {
|
||||
url := "/dataanalytics/statisOursProductLossSum"
|
||||
var res StatisOursProductLossSumRes
|
||||
if err := request(url, param, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
type GetProfitRankingSumRequest struct {
|
||||
Ct []string `protobuf:"bytes,1,rep,name=ct,proto3" json:"ct,omitempty"`
|
||||
Page int32 `protobuf:"varint,3,opt,name=page,proto3" json:"page,omitempty"`
|
||||
Limit int32 `protobuf:"varint,4,opt,name=limit,proto3" json:"limit,omitempty"`
|
||||
ResellerIds []int32 `protobuf:"varint,5,rep,packed,name=reseller_ids,json=resellerIds,proto3" json:"reseller_ids,omitempty"`
|
||||
}
|
||||
|
||||
type GetProfitRankingSumResponse struct {
|
||||
List []*ProfitRankingSumResponse `protobuf:"bytes,1,rep,name=list,proto3" json:"list,omitempty"`
|
||||
DataCount int32 `protobuf:"varint,2,opt,name=data_count,json=dataCount,proto3" json:"data_count,omitempty"`
|
||||
}
|
||||
|
||||
type ProfitRankingSumResponse struct {
|
||||
// 分销商ID
|
||||
ResellerId string `protobuf:"bytes,1,opt,name=reseller_id,json=resellerId,proto3" json:"reseller_id,omitempty"`
|
||||
// 分销商名称
|
||||
ResellerName string `protobuf:"bytes,2,opt,name=reseller_name,json=resellerName,proto3" json:"reseller_name,omitempty"`
|
||||
// 当前利润
|
||||
CurrentProfit float64 `protobuf:"fixed64,3,opt,name=current_profit,json=currentProfit,proto3" json:"current_profit,omitempty"`
|
||||
// 昨日同比利润
|
||||
HistoryOneProfit float64 `protobuf:"fixed64,4,opt,name=history_one_profit,json=historyOneProfit,proto3" json:"history_one_profit,omitempty"`
|
||||
// 上周同比利润
|
||||
HistoryTwoProfit float64 `protobuf:"fixed64,5,opt,name=history_two_profit,json=historyTwoProfit,proto3" json:"history_two_profit,omitempty"`
|
||||
// 昨日同比利润差值
|
||||
HistoryOneDiff float64 `protobuf:"fixed64,6,opt,name=history_one_diff,json=historyOneDiff,proto3" json:"history_one_diff,omitempty"`
|
||||
// 上周同比利润差值
|
||||
HistoryTwoDiff float64 `protobuf:"fixed64,7,opt,name=history_two_diff,json=historyTwoDiff,proto3" json:"history_two_diff,omitempty"`
|
||||
}
|
||||
|
||||
// GetProfitRankingSumApi 利润同比分销商排行榜
|
||||
func GetProfitRankingSumApi(param *GetProfitRankingSumRequest) (*GetProfitRankingSumResponse, error) {
|
||||
url := "/dataanalytics/profitRankingSum"
|
||||
var res GetProfitRankingSumResponse
|
||||
if err := request(url, param, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
type GetStatisOfficialProductSumRequest struct {
|
||||
Ct []string `protobuf:"bytes,1,rep,name=ct,proto3" json:"ct,omitempty"`
|
||||
DownwardValue int32 `protobuf:"varint,4,opt,name=downward_value,json=downwardValue,proto3" json:"downward_value,omitempty"`
|
||||
Page int32 `protobuf:"varint,5,opt,name=page,proto3" json:"page,omitempty"`
|
||||
Limit int32 `protobuf:"varint,6,opt,name=limit,proto3" json:"limit,omitempty"`
|
||||
OfficialProductId []int32 `protobuf:"varint,7,rep,packed,name=official_product_id,json=officialProductId,proto3" json:"official_product_id,omitempty"`
|
||||
}
|
||||
|
||||
type GetStatisOfficialProductSumResponse struct {
|
||||
OfficialProductSum []*GetStatisOfficialProductSum `protobuf:"bytes,1,rep,name=official_product_sum,json=officialProductSum,proto3" json:"official_product_sum,omitempty"`
|
||||
DataCount int32 `protobuf:"varint,2,opt,name=data_count,json=dataCount,proto3" json:"data_count,omitempty"`
|
||||
}
|
||||
|
||||
type GetStatisOfficialProductSum struct {
|
||||
OfficialProductId int32 `protobuf:"varint,1,opt,name=official_product_id,json=officialProductId,proto3" json:"official_product_id,omitempty"`
|
||||
OfficialProductName string `protobuf:"bytes,2,opt,name=official_product_name,json=officialProductName,proto3" json:"official_product_name,omitempty"`
|
||||
CurrentNum int32 `protobuf:"varint,3,opt,name=current_num,json=currentNum,proto3" json:"current_num,omitempty"`
|
||||
HistoryOneNum int32 `protobuf:"varint,4,opt,name=history_one_num,json=historyOneNum,proto3" json:"history_one_num,omitempty"`
|
||||
HistoryTwoNum int32 `protobuf:"varint,5,opt,name=history_two_num,json=historyTwoNum,proto3" json:"history_two_num,omitempty"`
|
||||
HistoryOneDiff int32 `protobuf:"varint,6,opt,name=history_one_diff,json=historyOneDiff,proto3" json:"history_one_diff,omitempty"`
|
||||
HistoryTwoDiff int32 `protobuf:"varint,7,opt,name=history_two_diff,json=historyTwoDiff,proto3" json:"history_two_diff,omitempty"`
|
||||
}
|
||||
|
||||
// GetStatisOfficialProductSumApi 销量同比分析
|
||||
func GetStatisOfficialProductSumApi(param *GetStatisOfficialProductSumRequest) (*GetStatisOfficialProductSumResponse, error) {
|
||||
url := "/dataanalytics/statisOfficialProduct"
|
||||
var res GetStatisOfficialProductSumResponse
|
||||
if err := request(url, param, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
type GetStatisOfficialProductSumDeclineResponse struct {
|
||||
OfficialProductSumDecline []*GetStatisOfficialProductSumDecline `protobuf:"bytes,1,rep,name=official_product_sum_decline,json=officialProductSumDecline,proto3" json:"official_product_sum_decline,omitempty"`
|
||||
DataCount int32 `protobuf:"varint,2,opt,name=data_count,json=dataCount,proto3" json:"data_count,omitempty"`
|
||||
}
|
||||
|
||||
type GetStatisOfficialProductSumDecline struct {
|
||||
ResellerId int32 `protobuf:"varint,1,opt,name=reseller_id,json=resellerId,proto3" json:"reseller_id,omitempty"`
|
||||
OfficialProductId int32 `protobuf:"varint,2,opt,name=official_product_id,json=officialProductId,proto3" json:"official_product_id,omitempty"`
|
||||
OfficialProductName string `protobuf:"bytes,3,opt,name=official_product_name,json=officialProductName,proto3" json:"official_product_name,omitempty"`
|
||||
ResellerName string `protobuf:"bytes,4,opt,name=reseller_name,json=resellerName,proto3" json:"reseller_name,omitempty"`
|
||||
CurrentNum int32 `protobuf:"varint,5,opt,name=current_num,json=currentNum,proto3" json:"current_num,omitempty"`
|
||||
HistoryOneNum int32 `protobuf:"varint,6,opt,name=history_one_num,json=historyOneNum,proto3" json:"history_one_num,omitempty"`
|
||||
HistoryTwoNum int32 `protobuf:"varint,7,opt,name=history_two_num,json=historyTwoNum,proto3" json:"history_two_num,omitempty"`
|
||||
HistoryOneDiff int32 `protobuf:"varint,8,opt,name=history_one_diff,json=historyOneDiff,proto3" json:"history_one_diff,omitempty"`
|
||||
HistoryTwoDiff int32 `protobuf:"varint,9,opt,name=history_two_diff,json=historyTwoDiff,proto3" json:"history_two_diff,omitempty"`
|
||||
}
|
||||
|
||||
// GetStatisOfficialProductSumDeclineApi 销量同比分析
|
||||
func GetStatisOfficialProductSumDeclineApi(param *GetStatisOfficialProductSumRequest) (*GetStatisOfficialProductSumDeclineResponse, error) {
|
||||
url := "/dataanalytics/statisOfficialProductDecline"
|
||||
var res GetStatisOfficialProductSumDeclineResponse
|
||||
if err := request(url, param, &res); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &res, nil
|
||||
}
|
||||
|
||||
type resCode struct {
|
||||
Code int `json:"code"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
Error string `json:"error"`
|
||||
}
|
||||
|
||||
func request(url string, reqData interface{}, resData interface{}) error {
|
||||
|
||||
reqParam, err := pkg.StructToQuery(reqData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req := &l_request.Request{
|
||||
Url: Base + url + "?" + customEncode(reqParam),
|
||||
Method: http.MethodGet,
|
||||
}
|
||||
res, err := req.Send()
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("request failed, status code: %d,resion: %s", res.StatusCode, res.Reason)
|
||||
}
|
||||
var code resCode
|
||||
if err = json.Unmarshal(res.Content, &code); err != nil {
|
||||
return fmt.Errorf("返回结构异常:%s", string(res.Content))
|
||||
}
|
||||
if code.Code != 200 {
|
||||
return fmt.Errorf("返回状态异常:%s", string(code.Error))
|
||||
}
|
||||
if err = json.Unmarshal(code.Data, resData); err != nil {
|
||||
return fmt.Errorf("返回数据异常:%s", string(res.Content))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func formatCtToQueryString(ct []string) string {
|
||||
if len(ct) != 2 {
|
||||
return ""
|
||||
}
|
||||
|
||||
values := url.Values{}
|
||||
|
||||
// 第一个时间(开始时间)
|
||||
startTime, err := time.Parse("2006-01-02 15:04:05", ct[0])
|
||||
if err == nil {
|
||||
// 保持原样
|
||||
values.Add("ct[]", startTime.Format("2006-01-02+15:04:05"))
|
||||
}
|
||||
|
||||
// 第二个时间(结束时间)
|
||||
endTime, err := time.Parse("2006-01-02 15:04:05", ct[1])
|
||||
if err == nil {
|
||||
// 添加毫秒
|
||||
endTimeWithMs := endTime.Add(999 * time.Millisecond)
|
||||
values.Add("ct[]", endTimeWithMs.Format("2006-01-02+15:04:05.000"))
|
||||
}
|
||||
|
||||
return values.Encode()
|
||||
}
|
||||
|
||||
func customEncode(params url.Values) string {
|
||||
encoded := params.Encode()
|
||||
|
||||
// 解码我们想要保留的字符
|
||||
encoded = strings.ReplaceAll(encoded, "%5B", "[") // 恢复 [
|
||||
encoded = strings.ReplaceAll(encoded, "%5D", "]") // 恢复 ]
|
||||
encoded = strings.ReplaceAll(encoded, "%2B", "+") // 恢复 +
|
||||
|
||||
return encoded
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
package bbxt
|
||||
|
||||
import (
|
||||
"ai_scheduler/internal/pkg"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/xuri/excelize/v2"
|
||||
)
|
||||
|
||||
type BbxtTools struct {
|
||||
cacheDir string
|
||||
excelTempDir string
|
||||
ct []string
|
||||
}
|
||||
|
||||
func NewBbxtTools() (*BbxtTools, error) {
|
||||
cache, err := pkg.GetCacheDir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tempDir, err := pkg.GetTmplDir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
now := time.Now()
|
||||
return &BbxtTools{
|
||||
cacheDir: cache,
|
||||
excelTempDir: fmt.Sprintf("%s/excel_temp", tempDir),
|
||||
ct: []string{
|
||||
time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()).Format("2006-01-02 15:04:05"),
|
||||
time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 0, now.Location()).Format("2006-01-02 15:04:05"),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (b *BbxtTools) DailyReport() (err error) {
|
||||
err = b.StatisOursProductLossSumTotal()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// OursProductLossSum 负利润分析
|
||||
func (b *BbxtTools) StatisOursProductLossSumTotal() (err error) {
|
||||
data, err := StatisOursProductLossSumApi(&StatisOursProductLossSumReq{
|
||||
Ct: b.ct,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var (
|
||||
total [][]string
|
||||
gt [][]string
|
||||
)
|
||||
|
||||
for _, v := range data.List {
|
||||
if v.Loss <= -100 {
|
||||
total = append(total, []string{
|
||||
v.OursProductName,
|
||||
fmt.Sprintf("%.2f", v.Loss),
|
||||
})
|
||||
}
|
||||
if v.Loss <= -500 {
|
||||
gt = append(gt, []string{
|
||||
v.OursProductName,
|
||||
fmt.Sprintf("%.2f", v.Loss),
|
||||
})
|
||||
}
|
||||
}
|
||||
//总量生成excel
|
||||
if len(total) > 0 {
|
||||
filePath := b.cacheDir + "/kshj_total" + fmt.Sprintf("%d", time.Now().Unix()) + ".xlsx"
|
||||
err = b.SimpleFillExcel(b.excelTempDir+"/"+"kshj_total.xlsx", filePath, total)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// 最简单的通用函数
|
||||
func (b *BbxtTools) SimpleFillExcel(templatePath, outputPath string, dataSlice interface{}) error {
|
||||
// 1. 打开模板
|
||||
f, err := excelize.OpenFile(templatePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
sheet := f.GetSheetName(0)
|
||||
|
||||
// 2. 反射获取切片数据
|
||||
v := reflect.ValueOf(dataSlice)
|
||||
if v.Kind() != reflect.Slice {
|
||||
return fmt.Errorf("dataSlice must be a slice")
|
||||
}
|
||||
|
||||
// 3. 从第2行开始填充
|
||||
row := 2
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
item := v.Index(i).Interface()
|
||||
currentRow := row + i
|
||||
|
||||
// 4. 将item转换为一行数据
|
||||
var rowData []interface{}
|
||||
|
||||
// 如果是切片
|
||||
if reflect.TypeOf(item).Kind() == reflect.Slice {
|
||||
itemV := reflect.ValueOf(item)
|
||||
for j := 0; j < itemV.Len(); j++ {
|
||||
rowData = append(rowData, itemV.Index(j).Interface())
|
||||
}
|
||||
} else if reflect.TypeOf(item).Kind() == reflect.Struct {
|
||||
itemV := reflect.ValueOf(item)
|
||||
for j := 0; j < itemV.NumField(); j++ {
|
||||
if itemV.Field(j).CanInterface() {
|
||||
rowData = append(rowData, itemV.Field(j).Interface())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rowData = []interface{}{item}
|
||||
}
|
||||
|
||||
// 5. 填充到Excel
|
||||
for col, value := range rowData {
|
||||
cell := fmt.Sprintf("%c%d", 'A'+col, currentRow)
|
||||
f.SetCellValue(sheet, cell, value)
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 保存
|
||||
return f.SaveAs(outputPath)
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package bbxt
|
||||
|
||||
import "testing"
|
||||
|
||||
func Test_StatisOursProductLossSumApiTotal(t *testing.T) {
|
||||
o, err := NewBbxtTools()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
err = o.StatisOursProductLossSumTotal()
|
||||
|
||||
t.Log(err)
|
||||
|
||||
}
|
||||
Binary file not shown.
Loading…
Reference in New Issue