Browse Source

feat:新增预测指标分段预测

Roc 2 years ago
parent
commit
5bbdf513ea
5 changed files with 739 additions and 33 deletions
  1. 1 0
      go.mod
  2. 2 21
      go.sum
  3. 13 2
      models/data_manage/predict_edb_conf.go
  4. 162 10
      services/data/predict_edb_info.go
  5. 561 0
      services/data/predict_edb_info_rule.go

+ 1 - 0
go.mod

@@ -9,6 +9,7 @@ require (
 	github.com/google/go-cmp v0.5.6 // indirect
 	github.com/nosixtools/solarlunar v0.0.0-20211112060703-1b6dea7b4a19
 	github.com/rdlucklib/rdluck_tools v1.0.2
+	github.com/shopspring/decimal v1.3.1
 	golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect
 	gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
 )

+ 2 - 21
go.sum

@@ -41,7 +41,6 @@ github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN
 github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
 github.com/beego/bee/v2 v2.0.2 h1:xWARyIqdnnbNMDBDUdb6Gvr9S/yGXC6Ni43kKdS1/eg=
 github.com/beego/bee/v2 v2.0.2/go.mod h1:rfZa899qLAF8SYBRvE7mWNPZTU7/qysOBhaCLmZrMX4=
-github.com/beego/beego/v2 v2.0.1 h1:07a7Z0Ok5vbqyqh+q53sDPl9LdhKh0ZDy3gbyGrhFnE=
 github.com/beego/beego/v2 v2.0.1/go.mod h1:8zyHi1FnWO1mZLwTn62aKRIZF/aIKvkCBB2JYs+eqQI=
 github.com/beego/beego/v2 v2.0.2 h1:Mx2MWMHJN1oFBHewHWyIhR25tXB9IPceIK8X7OuMdZM=
 github.com/beego/beego/v2 v2.0.2/go.mod h1:4pxstbxq+2qE8IUzFsVK8X9BsqfRjbp7ohbapTrTLho=
@@ -108,7 +107,6 @@ github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt
 github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
 github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI=
 github.com/elastic/go-elasticsearch/v6 v6.8.10/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI=
-github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
 github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
 github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
 github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
@@ -170,9 +168,7 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
 github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
 github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
 github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
 github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
@@ -186,7 +182,6 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
 github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
 github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -301,7 +296,6 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
 github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
 github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mitchellh/mapstructure v1.3.3 h1:SzB1nHZ2Xi+17FP0zVQBHIZqvwRN9408fJO8h+eeNA8=
 github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
 github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
@@ -368,7 +362,6 @@ github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod
 github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
 github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
 github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
-github.com/prometheus/client_golang v1.7.0 h1:wCi7urQOGBsYcQROHqpUUX4ct84xp40t9R9JX0FuA/U=
 github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
 github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
 github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ=
@@ -385,7 +378,6 @@ github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8
 github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
 github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
-github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc=
 github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
 github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
 github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
@@ -394,7 +386,6 @@ github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R
 github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
 github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
 github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
-github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8=
 github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
 github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
 github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
@@ -410,10 +401,11 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
-github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI+b2qND5gpH8YhURn0k8OCaeRnkINo=
 github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
 github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 h1:DAYUYH5869yV94zvCES9F51oYtN5oGlwjxJJz7ZCnik=
 github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
+github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
+github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
 github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s=
@@ -444,7 +436,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
@@ -499,7 +490,6 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc=
 golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
@@ -525,7 +515,6 @@ golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKG
 golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
 golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -550,7 +539,6 @@ golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLL
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
@@ -596,13 +584,11 @@ golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da h1:b3NXsE2LusjYGGjL5bxEVZZORm/YEFFrWFjR8eFrw/c=
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40 h1:JWgyZ1qgdTaF3N3oxC+MdTV7qvEEgHo3otj+HB5CM7Q=
@@ -611,7 +597,6 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
 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=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
@@ -649,7 +634,6 @@ golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtn
 golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
 golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58 h1:1Bs6RVeBFtLZ8Yi1Hk07DiOqzvwLD/4hln4iahvFlag=
 golang.org/x/tools v0.0.0-20201211185031-d93e913c1a58/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
@@ -702,10 +686,8 @@ google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQ
 google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
 google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
 google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
@@ -737,7 +719,6 @@ gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
 gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

+ 13 - 2
models/data_manage/predict_edb_conf.go

@@ -8,10 +8,13 @@ import (
 )
 
 type PredictEdbConf struct {
-	PredictEdbInfoId int       `orm:"column(predict_edb_info_id);pk" description:"预测指标id"`
+	ConfigId         int       `orm:"column(config_id);pk" description:"规则id"`
+	PredictEdbInfoId int       `orm:"column(predict_edb_info_id)" description:"预测指标id"`
 	SourceEdbInfoId  int       `description:"来源指标id"`
-	RuleType         int       `description:"预测规则,1:最新,2:固定值"`
+	RuleType         int       `description:"预测规则,1:最新,2:固定值,3:同比,4:同差,5:环比,6:环差,7:N期移动均值,8:N期段线性外推值"`
 	FixedValue       float64   `description:"固定值"`
+	Value            string    `description:"配置的值"`
+	EndDate          time.Time `description:"截止日期"`
 	ModifyTime       time.Time `description:"修改时间"`
 	CreateTime       time.Time `description:"添加时间"`
 }
@@ -125,3 +128,11 @@ func GetPredictEdbInfoAllCalculate(edbInfoIdList []int) (list []*EdbInfo, err er
 	_, err = o.Raw(sql, edbInfoIdList).QueryRows(&list)
 	return
 }
+
+// GetPredictEdbConfListById 根据预测指标id获取预测指标配置信息列表
+func GetPredictEdbConfListById(edbInfoId int) (items []*PredictEdbConf, err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := ` SELECT * FROM predict_edb_conf WHERE predict_edb_info_id=? ORDER BY config_id ASC`
+	_, err = o.Raw(sql, edbInfoId).QueryRows(&items)
+	return
+}

+ 162 - 10
services/data/predict_edb_info.go

@@ -2,9 +2,11 @@ package data
 
 import (
 	"errors"
+	"github.com/shopspring/decimal"
 	"hongze/hongze_chart_lib/models"
 	"hongze/hongze_chart_lib/models/data_manage"
 	"hongze/hongze_chart_lib/utils"
+	"strconv"
 	"time"
 )
 
@@ -103,11 +105,17 @@ func GetPredictDataListByPredictEdbInfo(edbInfo *data_manage.EdbInfo, startDate,
 		return GetPredictCalculateDataListByPredictEdbInfo(edbInfo, startDate, endDate)
 	}
 	// 查找该预测指标配置
-	predictEdbConf, err = data_manage.GetPredictEdbConfById(edbInfo.EdbInfoId)
+	predictEdbConfList, err := data_manage.GetPredictEdbConfListById(edbInfo.EdbInfoId)
 	if err != nil && err.Error() != utils.ErrNoRow() {
 		errMsg = "获取预测指标配置信息失败"
 		return
 	}
+	if len(predictEdbConfList) == 0 {
+		errMsg = "获取预测指标配置信息失败"
+		err = errors.New(errMsg)
+		return
+	}
+	predictEdbConf = predictEdbConfList[0]
 	if predictEdbConf == nil {
 		errMsg = "获取预测指标配置信息失败"
 		err = errors.New(errMsg)
@@ -124,11 +132,22 @@ func GetPredictDataListByPredictEdbInfo(edbInfo *data_manage.EdbInfo, startDate,
 		return
 	}
 
+	// 所有数据
+	allDataList := make([]*models.EdbDataList, 0)
 	//获取指标数据(实际已生成)
 	dataList, err = models.GetEdbDataList(sourceEdbInfoItem.Source, sourceEdbInfoItem.EdbInfoId, startDate, endDate)
 	if err != nil {
 		return
 	}
+	// 如果选择了日期,那么需要筛选所有的数据,用于未来指标的生成
+	if startDate != `` {
+		allDataList, err = models.GetEdbDataList(sourceEdbInfoItem.Source, sourceEdbInfoItem.EdbInfoId, "", "")
+		if err != nil {
+			return
+		}
+	} else {
+		allDataList = dataList
+	}
 
 	// 获取预测指标未来的数据
 	predictDataList := make([]*models.EdbDataList, 0)
@@ -143,22 +162,23 @@ func GetPredictDataListByPredictEdbInfo(edbInfo *data_manage.EdbInfo, startDate,
 			endDateStr = endDate
 		}
 	}
-	predictDataList, err = GetChartPredictEdbInfoDataList(*predictEdbConf, startDate, sourceEdbInfoItem.LatestDate, sourceEdbInfoItem.LatestValue, endDateStr, edbInfo.Frequency)
+	//predictDataList, err = GetChartPredictEdbInfoDataList(*predictEdbConf, startDate, sourceEdbInfoItem.LatestDate, sourceEdbInfoItem.LatestValue, endDateStr, edbInfo.Frequency)
+	var predictMinValue, predictMaxValue float64
+	predictDataList, predictMinValue, predictMaxValue, err = GetChartPredictEdbInfoDataListByConfList(predictEdbConfList, startDate, sourceEdbInfoItem.LatestDate, endDateStr, edbInfo.Frequency, allDataList)
+
 	if err != nil {
 		return
 	}
 	dataList = append(dataList, predictDataList...)
 	if len(predictDataList) > 0 {
-		tmpValue := predictDataList[0]
-
-		// 如果最大值 小于 预测值,那么将预测值作为最大值数据返回
-		if edbInfo.MaxValue < tmpValue.Value {
-			edbInfo.MaxValue = tmpValue.Value
+		// 如果最小值 大于 预测值,那么将预测值作为最小值数据返回
+		if edbInfo.MinValue > predictMinValue {
+			edbInfo.MinValue = predictMinValue
 		}
 
-		// 如果最小值 大于 预测值,那么将预测值作为最小值数据返回
-		if edbInfo.MinValue > tmpValue.Value {
-			edbInfo.MinValue = tmpValue.Value
+		// 如果最大值 小于 预测值,那么将预测值作为最大值数据返回
+		if edbInfo.MaxValue < predictMaxValue {
+			edbInfo.MaxValue = predictMaxValue
 		}
 	}
 	return
@@ -169,3 +189,135 @@ func GetPredictCalculateDataListByPredictEdbInfo(edbInfo *data_manage.EdbInfo, s
 	dataList, err = models.GetEdbDataList(edbInfo.Source, edbInfo.EdbInfoId, startDate, endDate)
 	return
 }
+
+// GetChartPredictEdbInfoDataListByConfList 获取图表的预测指标的未来数据
+func GetChartPredictEdbInfoDataListByConfList(predictEdbConfList []*data_manage.PredictEdbConf, filtrateStartDateStr, latestDateStr, endDateStr, frequency string, realPredictEdbInfoData []*models.EdbDataList) (predictEdbInfoData []*models.EdbDataList, minValue, maxValue float64, err error) {
+	endDate, err := time.ParseInLocation(utils.FormatDate, endDateStr, time.Local)
+	if err != nil {
+		return
+	}
+
+	latestDate, err := time.ParseInLocation(utils.FormatDate, latestDateStr, time.Local)
+	if err != nil {
+		return
+	}
+
+	// 开始预测数据的时间
+	startDate := latestDate
+
+	// 如果有筛选时间的话
+	if filtrateStartDateStr != `` {
+		filtrateStartDate, tmpErr := time.ParseInLocation(utils.FormatDate, filtrateStartDateStr, time.Local)
+		if tmpErr != nil {
+			err = tmpErr
+			return
+		}
+		//如果筛选时间晚于实际数据时间,那么就以筛选时间作为获取预测数据的时间
+		if filtrateStartDate.After(latestDate) {
+			startDate = filtrateStartDate.AddDate(0, 0, -1)
+		}
+	}
+
+	//var dateArr []string
+	// 对应日期的值
+	existMap := make(map[string]float64)
+	for _, v := range realPredictEdbInfoData {
+		//dateArr = append(dateArr, v.DataTime)
+		existMap[v.DataTime] = v.Value
+	}
+
+	predictEdbInfoData = make([]*models.EdbDataList, 0)
+	//dataValue := lastDataValue
+	//预测规则,1:最新,2:固定值,3:同比,4:同差,5:环比,6:环差,7:N期移动均值,8:N期段线性外推值
+
+	for _, predictEdbConf := range predictEdbConfList {
+		dataEndTime := endDate
+		if predictEdbConf.EndDate.Before(dataEndTime) {
+			dataEndTime = predictEdbConf.EndDate
+		}
+
+		var tmpMinValue, tmpMaxValue float64 // 当前预测结果中的最大/最小值
+
+		switch predictEdbConf.RuleType {
+		case 1: //1:最新
+			var lastDataValue float64 //最新值
+			tmpAllData := make([]*models.EdbDataList, 0)
+			tmpAllData = append(tmpAllData, realPredictEdbInfoData...)
+			tmpAllData = append(tmpAllData, predictEdbInfoData...)
+			lenTmpAllData := len(tmpAllData)
+			if lenTmpAllData > 0 {
+				lastDataValue = tmpAllData[lenTmpAllData-1].Value
+			}
+			predictEdbInfoData = GetChartPredictEdbInfoDataListByRule1(predictEdbConf.PredictEdbInfoId, lastDataValue, startDate, dataEndTime, frequency, predictEdbInfoData, existMap)
+			tmpMaxValue = lastDataValue
+			tmpMinValue = lastDataValue
+		case 2: //2:固定值
+			tmpValDecimal, tmpErr := decimal.NewFromString(predictEdbConf.Value)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			dataValue, _ := tmpValDecimal.Float64()
+			predictEdbInfoData = GetChartPredictEdbInfoDataListByRule1(predictEdbConf.PredictEdbInfoId, dataValue, startDate, dataEndTime, frequency, predictEdbInfoData, existMap)
+
+			tmpMaxValue = dataValue
+			tmpMinValue = dataValue
+		case 3: //3:同比
+			tmpValDecimal, tmpErr := decimal.NewFromString(predictEdbConf.Value)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			tbValue, _ := tmpValDecimal.Float64()
+			predictEdbInfoData, tmpMinValue, tmpMaxValue = GetChartPredictEdbInfoDataListByRuleTb(predictEdbConf.PredictEdbInfoId, tbValue, startDate, dataEndTime, frequency, predictEdbInfoData, existMap)
+		case 4: //4:同差
+			tmpValDecimal, tmpErr := decimal.NewFromString(predictEdbConf.Value)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			tcValue, _ := tmpValDecimal.Float64()
+			predictEdbInfoData, tmpMinValue, tmpMaxValue = GetChartPredictEdbInfoDataListByRuleTc(predictEdbConf.PredictEdbInfoId, tcValue, startDate, dataEndTime, frequency, predictEdbInfoData, existMap)
+		case 5: //5:环比
+			tmpValDecimal, tmpErr := decimal.NewFromString(predictEdbConf.Value)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			hbValue, _ := tmpValDecimal.Float64()
+			predictEdbInfoData, tmpMinValue, tmpMaxValue = GetChartPredictEdbInfoDataListByRuleHb(predictEdbConf.PredictEdbInfoId, hbValue, startDate, dataEndTime, frequency, predictEdbInfoData, existMap)
+		case 6: //6:环差
+			tmpValDecimal, tmpErr := decimal.NewFromString(predictEdbConf.Value)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			hcValue, _ := tmpValDecimal.Float64()
+			predictEdbInfoData, tmpMinValue, tmpMaxValue = GetChartPredictEdbInfoDataListByRuleHc(predictEdbConf.PredictEdbInfoId, hcValue, startDate, dataEndTime, frequency, predictEdbInfoData, existMap)
+		case 7: //7:N期移动均值
+			nValue, tmpErr := strconv.Atoi(predictEdbConf.Value)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			predictEdbInfoData, tmpMinValue, tmpMaxValue = GetChartPredictEdbInfoDataListByRuleNMoveMeanValue(predictEdbConf.PredictEdbInfoId, nValue, startDate, dataEndTime, frequency, realPredictEdbInfoData, predictEdbInfoData, existMap)
+		case 8: //8:N期段线性外推值
+			nValue, tmpErr := strconv.Atoi(predictEdbConf.Value)
+			if tmpErr != nil {
+				err = tmpErr
+				return
+			}
+			predictEdbInfoData, tmpMinValue, tmpMaxValue = GetChartPredictEdbInfoDataListByRuleNLinearRegression(predictEdbConf.PredictEdbInfoId, nValue, startDate, dataEndTime, frequency, realPredictEdbInfoData, predictEdbInfoData, existMap)
+		}
+		//startDate = dataEndTime.AddDate(0, 0, 1)
+		startDate = dataEndTime
+		if tmpMinValue < minValue {
+			minValue = tmpMinValue
+		}
+		if tmpMaxValue < maxValue {
+			maxValue = tmpMaxValue
+		}
+	}
+
+	return
+}

+ 561 - 0
services/data/predict_edb_info_rule.go

@@ -0,0 +1,561 @@
+package data
+
+import (
+	"github.com/shopspring/decimal"
+	"hongze/hongze_chart_lib/models"
+	"hongze/hongze_chart_lib/utils"
+	"time"
+)
+
+// GetChartPredictEdbInfoDataListByRule1 根据规则1获取预测数据
+func GetChartPredictEdbInfoDataListByRule1(edbInfoId int, dataValue float64, startDate, endDate time.Time, frequency string, predictEdbInfoData []*models.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*models.EdbDataList) {
+	newPredictEdbInfoData = predictEdbInfoData
+	//获取后面的预测数据
+	dayList := getPredictEdbDayList(startDate, endDate, frequency)
+	predictEdbInfoData = make([]*models.EdbDataList, 0)
+	for k, v := range dayList {
+		newPredictEdbInfoData = append(newPredictEdbInfoData, &models.EdbDataList{
+			EdbDataId:     edbInfoId + 10000000000 + k,
+			EdbInfoId:     edbInfoId,
+			DataTime:      v.Format(utils.FormatDate),
+			Value:         dataValue,
+			DataTimestamp: (v.UnixNano() / 1e6) + 1000, //前端需要让加1s,说是2022-09-01 00:00:00 这样的整点不合适
+		})
+		existMap[v.Format(utils.FormatDate)] = dataValue
+	}
+	return
+}
+
+//	GetChartPredictEdbInfoDataListByRuleTb 根据同比值规则获取预测数据
+//	2.1 同比: 在未来某一个时间段内,给定一个固定的同比增速a,用去年同期值X乘以同比增速(1+a),得到预测值Y=X(1+a)
+//	例: 今年1-3月值,100,100,120。给定同比增速a=0.1,则明年1-3月预测值为: 100*1.1=110,100*1.1=110,120*1.1=132。
+func GetChartPredictEdbInfoDataListByRuleTb(edbInfoId int, tbValue float64, startDate, endDate time.Time, frequency string, predictEdbInfoData []*models.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*models.EdbDataList, minValue, maxValue float64) {
+	newPredictEdbInfoData = predictEdbInfoData
+	index := len(predictEdbInfoData)
+	//获取后面的预测数据
+	dayList := getPredictEdbDayList(startDate, endDate, frequency)
+	predictEdbInfoData = make([]*models.EdbDataList, 0)
+	for k, currentDate := range dayList {
+
+		tmpData := &models.EdbDataList{
+			EdbDataId: edbInfoId + 10000000000 + index + k,
+			EdbInfoId: edbInfoId,
+			DataTime:  currentDate.Format(utils.FormatDate),
+			//Value:         dataValue,
+			DataTimestamp: (currentDate.UnixNano() / 1e6) + 1000, //前端需要让加1s,说是2022-09-01 00:00:00 这样的整点不合适
+		}
+
+		var val float64
+		var calculateStatus bool //计算结果
+		//currentItem := existMap[av]
+		//上一年的日期
+		preDate := currentDate.AddDate(-1, 0, 0)
+		preDateStr := preDate.Format(utils.FormatDate)
+		if preValue, ok := existMap[preDateStr]; ok { //上一年同期找到
+			val = TbzDiv(preValue, tbValue)
+			calculateStatus = true
+		} else {
+			switch frequency {
+			case "月度":
+				//向上和向下,各找一个月
+				nextDateDay := preDate
+				preDateDay := preDate
+				for i := 0; i <= 35; i++ {
+					nextDateDayStr := nextDateDay.Format(utils.FormatDate)
+					if preValue, ok := existMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
+						val = TbzDiv(preValue, tbValue)
+						calculateStatus = true
+						break
+					} else {
+						preDateDayStr := preDateDay.Format(utils.FormatDate)
+						if preValue, ok := existMap[preDateDayStr]; ok { //上一年同期->上一个月找到
+							val = TbzDiv(preValue, tbValue)
+							calculateStatus = true
+							break
+						}
+					}
+					nextDateDay = nextDateDay.AddDate(0, 0, 1)
+					preDateDay = preDateDay.AddDate(0, 0, -1)
+				}
+
+			case "季度", "年度":
+				if preValue, ok := existMap[preDateStr]; ok { //上一年同期->下一个月找到
+					val = TbzDiv(preValue, tbValue)
+					calculateStatus = true
+					break
+				}
+			default:
+				nextDateDay := preDate
+				preDateDay := preDate
+
+				for i := 0; i < 35; i++ {
+					nextDateDayStr := nextDateDay.Format(utils.FormatDate)
+					if preValue, ok := existMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
+						val = TbzDiv(preValue, tbValue)
+						calculateStatus = true
+						break
+					} else {
+						preDateDayStr := preDateDay.Format(utils.FormatDate)
+						if preValue, ok := existMap[preDateDayStr]; ok { //上一年同期->上一个月找到
+							val = TbzDiv(preValue, tbValue)
+							calculateStatus = true
+							break
+						} else {
+							//fmt.Println("pre not find:", preDateStr, "i:", i)
+						}
+					}
+					nextDateDay = nextDateDay.AddDate(0, 0, 1)
+					preDateDay = preDateDay.AddDate(0, 0, -1)
+				}
+			}
+		}
+
+		if calculateStatus {
+			tmpData.Value = val
+			newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData)
+
+			// 最大最小值
+			if val < minValue {
+				minValue = val
+			}
+			if val < maxValue {
+				maxValue = val
+			}
+		}
+	}
+	return
+}
+
+// TbzDiv 同比值计算
+// @params a float64 去年同期值
+// @params b float64 固定同比增速
+func TbzDiv(a, b float64) (result float64) {
+	if b != 0 {
+		// 去年同期值
+		af := decimal.NewFromFloat(a)
+
+		// 同比增速
+		bf := decimal.NewFromFloat(b)
+
+		// 默认1
+		cf := decimal.NewFromFloat(1)
+
+		// 总增速
+		val := bf.Add(cf)
+
+		// 计算
+		result, _ = val.Mul(af).RoundCeil(4).Float64()
+	} else {
+		result = 0
+	}
+	return
+}
+
+//	GetChartPredictEdbInfoDataListByRuleTc 根据同差值规则获取预测数据
+//	2.2 同差: 在未来某一个时间段内,给定一个固定的同比增加值a,用去年同期值X加上同比增加值A,得到预测值Y=X+a
+//	例: 今年1-3月值,100,100,120。给定同比增加值a=10,则明年1-3月预测值为: 100+10=110,100+10=110,120+10=130
+func GetChartPredictEdbInfoDataListByRuleTc(edbInfoId int, tcValue float64, startDate, endDate time.Time, frequency string, predictEdbInfoData []*models.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*models.EdbDataList, minValue, maxValue float64) {
+	newPredictEdbInfoData = predictEdbInfoData
+	index := len(predictEdbInfoData)
+	//获取后面的预测数据
+	dayList := getPredictEdbDayList(startDate, endDate, frequency)
+	predictEdbInfoData = make([]*models.EdbDataList, 0)
+	for k, currentDate := range dayList {
+
+		tmpData := &models.EdbDataList{
+			EdbDataId: edbInfoId + 10000000000 + index + k,
+			EdbInfoId: edbInfoId,
+			DataTime:  currentDate.Format(utils.FormatDate),
+			//Value:         dataValue,
+			DataTimestamp: (currentDate.UnixNano() / 1e6) + 1000, //前端需要让加1s,说是2022-09-01 00:00:00 这样的整点不合适
+		}
+
+		var val float64
+		var calculateStatus bool //计算结果
+		//currentItem := existMap[av]
+		//上一年的日期
+		preDate := currentDate.AddDate(-1, 0, 0)
+		preDateStr := preDate.Format(utils.FormatDate)
+		if preValue, ok := existMap[preDateStr]; ok { //上一年同期找到
+			val = TczDiv(preValue, tcValue)
+			calculateStatus = true
+		} else {
+			switch frequency {
+			case "月度":
+				//向上和向下,各找一个月
+				nextDateDay := preDate
+				preDateDay := preDate
+				for i := 0; i <= 35; i++ {
+					nextDateDayStr := nextDateDay.Format(utils.FormatDate)
+					if preValue, ok := existMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
+						val = TczDiv(preValue, tcValue)
+						calculateStatus = true
+						break
+					} else {
+						preDateDayStr := preDateDay.Format(utils.FormatDate)
+						if preValue, ok := existMap[preDateDayStr]; ok { //上一年同期->上一个月找到
+							val = TczDiv(preValue, tcValue)
+							calculateStatus = true
+							break
+						}
+					}
+					nextDateDay = nextDateDay.AddDate(0, 0, 1)
+					preDateDay = preDateDay.AddDate(0, 0, -1)
+				}
+
+			case "季度", "年度":
+				if preValue, ok := existMap[preDateStr]; ok { //上一年同期->下一个月找到
+					val = TczDiv(preValue, tcValue)
+					calculateStatus = true
+					break
+				}
+			default:
+				nextDateDay := preDate
+				preDateDay := preDate
+
+				for i := 0; i < 35; i++ {
+					nextDateDayStr := nextDateDay.Format(utils.FormatDate)
+					if preValue, ok := existMap[nextDateDayStr]; ok { //上一年同期->下一个月找到
+						val = TczDiv(preValue, tcValue)
+						calculateStatus = true
+						break
+					} else {
+						preDateDayStr := preDateDay.Format(utils.FormatDate)
+						if preValue, ok := existMap[preDateDayStr]; ok { //上一年同期->上一个月找到
+							val = TczDiv(preValue, tcValue)
+							calculateStatus = true
+							break
+						} else {
+							//fmt.Println("pre not find:", preDateStr, "i:", i)
+						}
+					}
+					nextDateDay = nextDateDay.AddDate(0, 0, 1)
+					preDateDay = preDateDay.AddDate(0, 0, -1)
+				}
+			}
+		}
+
+		if calculateStatus {
+			tmpData.Value = val
+			newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData)
+
+			// 最大最小值
+			if val < minValue {
+				minValue = val
+			}
+			if val < maxValue {
+				maxValue = val
+			}
+		}
+	}
+	return
+}
+
+// TczDiv 环差值计算
+// @params a float64 上一期值
+// @params b float64 固定的环比增加值
+func TczDiv(a, b float64) (result float64) {
+	if b != 0 {
+		// 上一期值
+		af := decimal.NewFromFloat(a)
+
+		// 固定的环比增加值
+		bf := decimal.NewFromFloat(b)
+
+		// 计算
+		result, _ = af.Add(bf).RoundCeil(4).Float64()
+	} else {
+		result = 0
+	}
+	return
+}
+
+//	GetChartPredictEdbInfoDataListByRuleHb 根据环比值规则获取预测数据
+//	环比:在未来某一个时间段内,给定一个固定的环比增速a,用上一期值X乘以环比增速(1+a),得到预测值Y=X(1+a)
+//	例: 最近1期值为100,给定环比增速a=0.2,则未来3期预测值为: 100*1.2=120,120*1.2=144,144*1.2=172.8
+func GetChartPredictEdbInfoDataListByRuleHb(edbInfoId int, hbValue float64, startDate, endDate time.Time, frequency string, predictEdbInfoData []*models.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*models.EdbDataList, minValue, maxValue float64) {
+	newPredictEdbInfoData = predictEdbInfoData
+	index := len(predictEdbInfoData)
+	//获取后面的预测数据
+	dayList := getPredictEdbDayList(startDate, endDate, frequency)
+	for k, currentDate := range dayList {
+		tmpK := index + k - 1 //上1期的值
+
+		// 环比值计算
+		val := HbzDiv(newPredictEdbInfoData[tmpK].Value, hbValue)
+
+		currentDateStr := currentDate.Format(utils.FormatDate)
+		newPredictEdbInfoData = append(newPredictEdbInfoData, &models.EdbDataList{
+			EdbDataId:     edbInfoId + 10000000000 + index + k,
+			EdbInfoId:     edbInfoId,
+			DataTime:      currentDateStr,
+			Value:         val,
+			DataTimestamp: (currentDate.UnixNano() / 1e6) + 1000, //前端需要让加1s,说是2022-09-01 00:00:00 这样的整点不合适
+		})
+		existMap[currentDateStr] = val
+
+		// 最大最小值
+		if val < minValue {
+			minValue = val
+		}
+		if val < maxValue {
+			maxValue = val
+		}
+	}
+	return
+}
+
+// HbzDiv 环比值计算
+// @params a float64 上一期值
+// @params b float64 固定的环比增速
+func HbzDiv(a, b float64) (result float64) {
+	if b != 0 {
+		// 上一期值
+		af := decimal.NewFromFloat(a)
+
+		// 固定的环比增速
+		bf := decimal.NewFromFloat(b)
+
+		// 默认1
+		cf := decimal.NewFromFloat(1)
+
+		// 总增速
+		val := bf.Add(cf)
+
+		// 计算
+		result, _ = val.Mul(af).RoundCeil(4).Float64()
+	} else {
+		result = 0
+	}
+	return
+}
+
+//	GetChartPredictEdbInfoDataListByRuleHc 根据环差值规则获取预测数据
+//	2.4 环差:在未来某一个时间段内,给定一个固定的环比增加值a,用上一期值X加上环比增加值a,得到预测值Y=X+a
+//	例: 最近1期值为100,给定环比增加值a=10,则未来3期预测值为: 100+10=110,110+10=120,120+10=130
+func GetChartPredictEdbInfoDataListByRuleHc(edbInfoId int, hcValue float64, startDate, endDate time.Time, frequency string, predictEdbInfoData []*models.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*models.EdbDataList, minValue, maxValue float64) {
+	newPredictEdbInfoData = predictEdbInfoData
+	index := len(predictEdbInfoData)
+	//获取后面的预测数据
+	dayList := getPredictEdbDayList(startDate, endDate, frequency)
+	for k, currentDate := range dayList {
+		tmpK := index + k - 1 //上1期的值
+
+		// 环差别值计算
+		val := HczDiv(newPredictEdbInfoData[tmpK].Value, hcValue)
+
+		currentDateStr := currentDate.Format(utils.FormatDate)
+		newPredictEdbInfoData = append(newPredictEdbInfoData, &models.EdbDataList{
+			EdbDataId:     edbInfoId + 10000000000 + index + k,
+			EdbInfoId:     edbInfoId,
+			DataTime:      currentDateStr,
+			Value:         val,
+			DataTimestamp: (currentDate.UnixNano() / 1e6) + 1000, //前端需要让加1s,说是2022-09-01 00:00:00 这样的整点不合适
+		})
+		existMap[currentDateStr] = val
+
+		// 最大最小值
+		if val < minValue {
+			minValue = val
+		}
+		if val < maxValue {
+			maxValue = val
+		}
+	}
+	return
+}
+
+// HczDiv 环差值计算
+// @params a float64 上一期值
+// @params b float64 固定的环比增加值
+func HczDiv(a, b float64) (result float64) {
+	if b != 0 {
+		// 上一期值
+		af := decimal.NewFromFloat(a)
+
+		// 固定的环比增加值
+		bf := decimal.NewFromFloat(b)
+
+		// 计算
+		result, _ = af.Add(bf).RoundCeil(4).Float64()
+	} else {
+		result = 0
+	}
+	return
+}
+
+//	GetChartPredictEdbInfoDataListByRuleNMoveMeanValue 根据N期移动均值规则获取预测数据
+//	2.5 N期移动均值:在未来某一个时间段内,下一期值等于过去N期值得平均值。
+//	例:最近3期值(N=3),为95,98,105则未来第1期值为 1/3*(95+98+105)=99.33, 未来第2期值为 1/3*(98+105+99.33)=100.78依次类推。
+func GetChartPredictEdbInfoDataListByRuleNMoveMeanValue(edbInfoId int, nValue int, startDate, endDate time.Time, frequency string, realPredictEdbInfoData, predictEdbInfoData []*models.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*models.EdbDataList, minValue, maxValue float64) {
+	allDataList := make([]*models.EdbDataList, 0)
+	allDataList = append(allDataList, realPredictEdbInfoData...)
+	allDataList = append(allDataList, predictEdbInfoData...)
+
+	newPredictEdbInfoData = predictEdbInfoData
+
+	lenAllData := len(allDataList)
+	if lenAllData < nValue || lenAllData <= 0 {
+		return
+	}
+	if nValue <= 0 {
+		return
+	}
+	// 分母
+	decimalN := decimal.NewFromInt(int64(nValue))
+
+	//获取后面的预测数据
+	dayList := getPredictEdbDayList(startDate, endDate, frequency)
+	for k, currentDate := range dayList {
+		tmpIndex := lenAllData + k - 1 //上1期的值
+
+		// 数据集合中的最后一个数据
+		tmpDecimalVal := decimal.NewFromFloat(allDataList[tmpIndex].Value)
+		for tmpK := 2; tmpK <= nValue; tmpK++ {
+			tmpIndex2 := tmpIndex - tmpK //上N期的值
+			tmpDecimalVal2 := decimal.NewFromFloat(allDataList[tmpIndex2].Value)
+			tmpDecimalVal = tmpDecimalVal.Add(tmpDecimalVal2)
+		}
+
+		// N期移动均值计算
+		val, _ := tmpDecimalVal.Div(decimalN).RoundCeil(4).Float64()
+
+		currentDateStr := currentDate.Format(utils.FormatDate)
+		tmpData := &models.EdbDataList{
+			EdbDataId:     edbInfoId + 10000000000 + lenAllData + k,
+			EdbInfoId:     edbInfoId,
+			DataTime:      currentDateStr,
+			Value:         val,
+			DataTimestamp: (currentDate.UnixNano() / 1e6) + 1000, //前端需要让加1s,说是2022-09-01 00:00:00 这样的整点不合适
+		}
+		newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData)
+		allDataList = append(allDataList, tmpData)
+		existMap[currentDateStr] = val
+
+		// 最大最小值
+		if val < minValue {
+			minValue = val
+		}
+		if val < maxValue {
+			maxValue = val
+		}
+	}
+	return
+}
+
+//	GetChartPredictEdbInfoDataListByRuleNLinearRegression 根据N期移动均值规则获取预测数据
+//	2.6N期段线性外推值:给出过去N期值所确定的线性回归方程(Y=aX+b)在未来一段时间内的推算值。回归方程虽然比较复杂,但各种编程语言应该都有现成的模块或函数,应该无需自己编写。
+//	例1:过去5期值(N=5)分别为:3,5,7,9,11(每两期值之间的时间间隔相等)。那么按照线性回归方程推算,未来三期的预测值是:13,15,17。
+//
+//	例2:过去6期值(N=6)分别为:3,3,5,7,9,11(每两期值之间的时间间隔相等)。那么按照线性回归方程推算,未来三期的预测值是:12.33,14.05,15.76。例1和例2的区别在于,多加了一期数据,导致回归方程发生改变,从而预测值不同。
+func GetChartPredictEdbInfoDataListByRuleNLinearRegression(edbInfoId int, nValue int, startDate, endDate time.Time, frequency string, realPredictEdbInfoData, predictEdbInfoData []*models.EdbDataList, existMap map[string]float64) (newPredictEdbInfoData []*models.EdbDataList, minValue, maxValue float64) {
+	//var errMsg string
+	//defer func() {
+	//	if errMsg != `` {
+	//		go alarm_msg.SendAlarmMsg("更新上海的token失败;ERR:"+err.Error(), 3)
+	//	}
+	//}()
+	allDataList := make([]*models.EdbDataList, 0)
+	allDataList = append(allDataList, realPredictEdbInfoData...)
+	allDataList = append(allDataList, predictEdbInfoData...)
+
+	newPredictEdbInfoData = predictEdbInfoData
+
+	lenAllData := len(allDataList)
+	if lenAllData < nValue || lenAllData <= 0 {
+		return
+	}
+
+	if nValue <= 0 {
+		return
+	}
+
+	//获取后面的预测数据
+	// 获取线性方程公式的a、b的值
+	coordinateData := make([]Coordinate, 0)
+	for tmpK := nValue; tmpK > 0; tmpK-- {
+		tmpIndex2 := lenAllData - tmpK //上N期的值
+		tmpCoordinate := Coordinate{
+			X: float64(nValue - tmpK + 1),
+			Y: allDataList[tmpIndex2].Value,
+		}
+		coordinateData = append(coordinateData, tmpCoordinate)
+	}
+	a, b := getLinearResult(coordinateData)
+	//fmt.Println("a:", a, ";======b:", b)
+
+	dayList := getPredictEdbDayList(startDate, endDate, frequency)
+	for k, currentDate := range dayList {
+		tmpK := nValue + k + 1
+
+		aDecimal := decimal.NewFromFloat(a)
+		xDecimal := decimal.NewFromInt(int64(tmpK))
+		bDecimal := decimal.NewFromFloat(b)
+
+		val, _ := aDecimal.Mul(xDecimal).Add(bDecimal).RoundCeil(4).Float64()
+
+		currentDateStr := currentDate.Format(utils.FormatDate)
+		tmpData := &models.EdbDataList{
+			EdbDataId:     edbInfoId + 10000000000 + lenAllData + k,
+			EdbInfoId:     edbInfoId,
+			DataTime:      currentDateStr,
+			Value:         val,
+			DataTimestamp: (currentDate.UnixNano() / 1e6) + 1000, //前端需要让加1s,说是2022-09-01 00:00:00 这样的整点不合适
+		}
+		newPredictEdbInfoData = append(newPredictEdbInfoData, tmpData)
+		allDataList = append(allDataList, tmpData)
+		existMap[currentDateStr] = val
+
+		// 最大最小值
+		if val < minValue {
+			minValue = val
+		}
+		if val < maxValue {
+			maxValue = val
+		}
+	}
+	return
+}
+
+// Series is a container for a series of data
+type Series []Coordinate
+
+// Coordinate holds the data in a series
+type Coordinate struct {
+	X, Y float64
+}
+
+func getLinearResult(s []Coordinate) (gradient, intercept float64) {
+	if len(s) == 0 {
+		return
+	}
+
+	// Placeholder for the math to be done
+	var sum [5]float64
+
+	// Loop over data keeping index in place
+	i := 0
+	for ; i < len(s); i++ {
+		sum[0] += s[i].X
+		sum[1] += s[i].Y
+		sum[2] += s[i].X * s[i].X
+		sum[3] += s[i].X * s[i].Y
+		sum[4] += s[i].Y * s[i].Y
+	}
+
+	// Find gradient and intercept
+	f := float64(i)
+	gradient = (f*sum[3] - sum[0]*sum[1]) / (f*sum[2] - sum[0]*sum[0])
+	intercept = (sum[1] / f) - (gradient * sum[0] / f)
+
+	//fmt.Println("gradient:", gradient, ";intercept:", intercept)
+	// Create the new regression series
+	//for j := 0; j < len(s); j++ {
+	//	regressions = append(regressions, Coordinate{
+	//		X: s[j].X,
+	//		Y: s[j].X*gradient + intercept,
+	//	})
+	//}
+
+	return
+}