|
|
@@ -0,0 +1,433 @@
|
|
|
+package controllers
|
|
|
+
|
|
|
+import (
|
|
|
+ "context"
|
|
|
+ "encoding/json"
|
|
|
+ "errors"
|
|
|
+ "fwh-toolbox-server/database"
|
|
|
+ "fwh-toolbox-server/ext/api/fwh_pro"
|
|
|
+ "time"
|
|
|
+
|
|
|
+ "go.mongodb.org/mongo-driver/bson"
|
|
|
+ "go.mongodb.org/mongo-driver/mongo"
|
|
|
+ "go.mongodb.org/mongo-driver/mongo/options"
|
|
|
+)
|
|
|
+
|
|
|
+type StateConfig struct {
|
|
|
+ Enable bool `bson:"enable" json:"enable"`
|
|
|
+}
|
|
|
+
|
|
|
+type SocConfig struct {
|
|
|
+ Enable bool `bson:"enable" json:"enable"`
|
|
|
+}
|
|
|
+
|
|
|
+type APowerConfig struct {
|
|
|
+ Enable bool `bson:"enable" json:"enable"`
|
|
|
+}
|
|
|
+
|
|
|
+type AlarmConfig struct {
|
|
|
+ Enable bool `bson:"enable" json:"enable"`
|
|
|
+}
|
|
|
+
|
|
|
+type VersionConfig struct {
|
|
|
+ Enable bool `bson:"enable" json:"enable"`
|
|
|
+}
|
|
|
+
|
|
|
+type TariffsConfig struct {
|
|
|
+ Enable bool `bson:"enable" json:"enable"`
|
|
|
+}
|
|
|
+
|
|
|
+type OthersConfig struct {
|
|
|
+ Enable bool `bson:"enable" json:"enable"`
|
|
|
+}
|
|
|
+
|
|
|
+type MonitorPageConfig struct {
|
|
|
+ State StateConfig `bson:"state" json:"state"`
|
|
|
+ Soc SocConfig `bson:"soc" json:"soc"`
|
|
|
+ APower APowerConfig `bson:"aPower" json:"aPower"`
|
|
|
+ Alarm AlarmConfig `bson:"alarm" json:"alarm"`
|
|
|
+ Version VersionConfig `bson:"version" json:"version"`
|
|
|
+ Tariffs TariffsConfig `bson:"tariffs" json:"tariffs"`
|
|
|
+ Others OthersConfig `bson:"others" json:"others"`
|
|
|
+}
|
|
|
+
|
|
|
+type SitesMonitorConfig struct {
|
|
|
+ Name string `bson:"name" json:"name"`
|
|
|
+ Description string `bson:"description" json:"description"`
|
|
|
+ SiteList []string `bson:"siteList" json:"siteList"`
|
|
|
+ PageConfig *MonitorPageConfig `bson:"pageConfig,omitempty" json:"pageConfig,omitempty"`
|
|
|
+}
|
|
|
+
|
|
|
+type SiteInfoPara struct {
|
|
|
+ SiteList []string `json:"siteList"`
|
|
|
+ PageSize uint `json:"pageSize"`
|
|
|
+ PageNum uint `json:"pageNum"`
|
|
|
+}
|
|
|
+
|
|
|
+type SiteInfo struct {
|
|
|
+ Id string `json:"id"`
|
|
|
+ Name *string `json:"name"`
|
|
|
+ FhpSn string `json:"fhpSn"`
|
|
|
+ ActiveStatus int `json:"activeStatus"`
|
|
|
+ ActiveTime string `json:"activeTime"`
|
|
|
+ Country string `json:"country"`
|
|
|
+ Province string `json:"province"`
|
|
|
+ City string `json:"city"`
|
|
|
+ OnOffStatus int `json:"onOffStatus"`
|
|
|
+ RealSysHdVersion string `json:"realSysHdVersion"`
|
|
|
+ RunStatus int `json:"runStatus"`
|
|
|
+ Version string `json:"version"`
|
|
|
+}
|
|
|
+
|
|
|
+type SiteInfoResponse struct {
|
|
|
+ Code int `json:"code"`
|
|
|
+ Msg string `json:"msg"`
|
|
|
+ Result []SiteInfo `json:"result"`
|
|
|
+}
|
|
|
+
|
|
|
+type WorkModeInfo struct {
|
|
|
+ Id uint `json:"id"`
|
|
|
+ OldIndex uint `json:"oldIndex"`
|
|
|
+ Name string `json:"name"`
|
|
|
+ Soc float32 `json:"soc"`
|
|
|
+ MaxSoc float32 `json:"maxSoc"`
|
|
|
+ MinSoc float32 `json:"minSoc"`
|
|
|
+ DischargeDepthSoc *float32 `json:"dischargeDepthSoc"`
|
|
|
+ WorkMode uint `json:"workMode"`
|
|
|
+ EnergyIncentivesType uint `json:"energyIncentivesType"`
|
|
|
+ ElectricityType uint `json:"electricityType"`
|
|
|
+}
|
|
|
+
|
|
|
+type SiteModeInfo struct {
|
|
|
+ CurrendId uint `json:"currendId"`
|
|
|
+ List []WorkModeInfo `json:"list"`
|
|
|
+}
|
|
|
+
|
|
|
+type SiteModeInfoResponse struct {
|
|
|
+ Code int `json:"code"`
|
|
|
+ Msg string `json:"msg"`
|
|
|
+ Result SiteModeInfo `json:"result"`
|
|
|
+ Success bool `json:"success"`
|
|
|
+}
|
|
|
+
|
|
|
+type SitePowerFlow struct {
|
|
|
+ Index uint `json:"index"` // 非当天为0,当天为实时数量
|
|
|
+ DeviceTimeArray []string `json:"deviceTimeArray"` // 设备本地时间,格式 “2025-08-18 00:00:00”
|
|
|
+ PowerFhpArray []float32 `json:"powerFhpArray"`
|
|
|
+ PowerGenArray []float32 `json:"powerGenArray"`
|
|
|
+ PowerLoadArray []float32 `json:"powerLoadArray"`
|
|
|
+ PowerSunArray []float32 `json:"powerSunArray"`
|
|
|
+ PowerUtiArray []float32 `json:"powerUtiArray"`
|
|
|
+ SocArray []float32 `json:"socArray"`
|
|
|
+ RunStatusArray []uint `json:"runStatusArray"` // 运行状态,0:待机;1:充电;2:放电;3:故障
|
|
|
+ KwhTotalArray []float32 `json:"kwhTotalArray"` // 总可用电量,应该是根据SOC推算出来的。
|
|
|
+}
|
|
|
+
|
|
|
+type SitePowerFlowResponse struct {
|
|
|
+ Code int `json:"code"`
|
|
|
+ Msg string `json:"msg"`
|
|
|
+ Result SitePowerFlow `json:"result"`
|
|
|
+}
|
|
|
+
|
|
|
+type SiteAlarmList struct {
|
|
|
+ Id uint `json:"id"`
|
|
|
+ GatewayId string `json:"gatewayId"`
|
|
|
+ AlarmEqSn string `json:"alarmEqSn"`
|
|
|
+ AlarmCode string `json:"alarmCode"`
|
|
|
+ CommonAlarmCode string `json:"commonAlarmCode"`
|
|
|
+ Level int `json:"level"`
|
|
|
+ Time string `json:"time"`
|
|
|
+ LogName string `json:"logName"`
|
|
|
+ CommonLogName string `json:"commonLogName"`
|
|
|
+ LogNameEn string `json:"logNameEn"`
|
|
|
+ CommonLogNameEn string `json:"commonLogNameEn"`
|
|
|
+}
|
|
|
+
|
|
|
+type SiteAlarmListResponse struct {
|
|
|
+ Code int `json:"code"`
|
|
|
+ Message string `json:"message"`
|
|
|
+ Result []SiteAlarmList `json:"result"`
|
|
|
+ Success bool `json:"success"`
|
|
|
+ Total uint `json:"total"`
|
|
|
+}
|
|
|
+
|
|
|
+type Progress string // 'pending' | 'running' | 'error' | 'complete'
|
|
|
+
|
|
|
+type SiteAnalysisInfo struct {
|
|
|
+ Id uint64 `bson:"id" json:"id"`
|
|
|
+ Sn string `bson:"sn" json:"sn"`
|
|
|
+ Description string `bson:"description" json:"description"`
|
|
|
+ Item []string `bson:"item" json:"item"`
|
|
|
+ Progress Progress `bson:"progress" json:"progress"`
|
|
|
+}
|
|
|
+
|
|
|
+// 从数据库获取站点分析列表
|
|
|
+func GetSiteAnalysisList() ([]SiteAnalysisInfo, error) {
|
|
|
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
|
+ defer cancel()
|
|
|
+
|
|
|
+ collection := database.GetCollection("SiteMonitorConfig")
|
|
|
+ cursor, err := collection.Find(ctx, bson.M{}) // 空条件,查全部
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ defer cursor.Close(ctx)
|
|
|
+
|
|
|
+ var configList []SitesMonitorConfig
|
|
|
+ for cursor.Next(ctx) {
|
|
|
+ var cfg SitesMonitorConfig
|
|
|
+ if err := cursor.Decode(&cfg); err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ configList = append(configList, cfg)
|
|
|
+ }
|
|
|
+
|
|
|
+ return configList, nil
|
|
|
+}
|
|
|
+
|
|
|
+// 从数据库获取站点监控配置列表
|
|
|
+func GetSiteMonitorConfig() ([]SitesMonitorConfig, error) {
|
|
|
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
|
+ defer cancel()
|
|
|
+
|
|
|
+ collection := database.GetCollection("SiteMonitorConfig")
|
|
|
+ cursor, err := collection.Find(ctx, bson.M{}) // 空条件,查全部
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ defer cursor.Close(ctx)
|
|
|
+
|
|
|
+ var configList []SitesMonitorConfig
|
|
|
+ for cursor.Next(ctx) {
|
|
|
+ var cfg SitesMonitorConfig
|
|
|
+ if err := cursor.Decode(&cfg); err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ configList = append(configList, cfg)
|
|
|
+ }
|
|
|
+
|
|
|
+ return configList, nil
|
|
|
+}
|
|
|
+
|
|
|
+// 从数据库获取监控名列表
|
|
|
+func GetSiteMonitorNameList() ([]string, error) {
|
|
|
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
|
+ defer cancel()
|
|
|
+
|
|
|
+ collection := database.GetCollection("SiteMonitorConfig")
|
|
|
+ cursor, err := collection.Find(
|
|
|
+ ctx,
|
|
|
+ bson.M{}, // 空条件,查全部
|
|
|
+ options.Find().SetProjection(bson.M{
|
|
|
+ "name": 1, // 只要 name 字段
|
|
|
+ "_id": 0, // 不要 _id 字段(默认会返回)
|
|
|
+ }),
|
|
|
+ )
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ defer cursor.Close(ctx)
|
|
|
+
|
|
|
+ var nameList []string
|
|
|
+ for cursor.Next(ctx) {
|
|
|
+ var result struct {
|
|
|
+ Name string `bson:"name"`
|
|
|
+ }
|
|
|
+ if err := cursor.Decode(&result); err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ nameList = append(nameList, result.Name)
|
|
|
+ }
|
|
|
+
|
|
|
+ return nameList, nil
|
|
|
+}
|
|
|
+
|
|
|
+// 从数据库获取一条站点监控配置
|
|
|
+func GetOneSiteMonitorConfig(name string) ([]SitesMonitorConfig, error) {
|
|
|
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
|
+ defer cancel()
|
|
|
+
|
|
|
+ collection := database.GetCollection("SiteMonitorConfig")
|
|
|
+ var cfg SitesMonitorConfig
|
|
|
+ err := collection.FindOne(ctx, bson.M{"name": name}).Decode(&cfg)
|
|
|
+ if err == mongo.ErrNoDocuments {
|
|
|
+ return []SitesMonitorConfig{}, nil
|
|
|
+ } else if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ var configList []SitesMonitorConfig
|
|
|
+ configList = append(configList, cfg)
|
|
|
+
|
|
|
+ return configList, nil
|
|
|
+}
|
|
|
+
|
|
|
+// 插入一条站点监控配置到数据库
|
|
|
+func InsertSiteMonitorConfig(config SitesMonitorConfig) error {
|
|
|
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
|
+ defer cancel()
|
|
|
+
|
|
|
+ collection := database.GetCollection("SiteMonitorConfig")
|
|
|
+
|
|
|
+ // _, err := collection.InsertOne(ctx, config)
|
|
|
+ filter := bson.M{"name": config.Name} // 按用户名匹配
|
|
|
+ update := bson.M{
|
|
|
+ "$set": config, // 如果存在就更新所有字段
|
|
|
+ }
|
|
|
+
|
|
|
+ opts := options.Update().SetUpsert(true)
|
|
|
+
|
|
|
+ _, err := collection.UpdateOne(ctx, filter, update, opts)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// 更新一条站点监控配置到数据库
|
|
|
+func UpdateSiteMonitorConfig(name string, config SitesMonitorConfig) error {
|
|
|
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
|
+ defer cancel()
|
|
|
+
|
|
|
+ collection := database.GetCollection("SiteMonitorConfig")
|
|
|
+
|
|
|
+ // _, err := collection.InsertOne(ctx, config)
|
|
|
+ filter := bson.M{"name": name} // 按用户名匹配
|
|
|
+ update := bson.M{
|
|
|
+ "$set": config, // 如果存在就更新所有字段
|
|
|
+ }
|
|
|
+
|
|
|
+ opts := options.Update().SetUpsert(true)
|
|
|
+
|
|
|
+ _, err := collection.UpdateOne(ctx, filter, update, opts)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// 删除一条站点监控配置
|
|
|
+func DeleteSiteMonitorConfig(name string) error {
|
|
|
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
|
+ defer cancel()
|
|
|
+
|
|
|
+ filter := bson.M{"name": name} // 删除条件
|
|
|
+ collection := database.GetCollection("SiteMonitorConfig")
|
|
|
+ _, err := collection.DeleteOne(ctx, filter)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// 更新一条站点监控页面配置到数据库
|
|
|
+func UpdateSiteMonitorPageConfig(name string, config MonitorPageConfig) error {
|
|
|
+ ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
|
+ defer cancel()
|
|
|
+
|
|
|
+ collection := database.GetCollection("SiteMonitorConfig")
|
|
|
+
|
|
|
+ // _, err := collection.InsertOne(ctx, config)
|
|
|
+ filter := bson.M{"name": name} // 按用户名匹配
|
|
|
+ update := bson.M{
|
|
|
+ "$set": bson.M{
|
|
|
+ "pageConfig": config, // 更新页面配置字段
|
|
|
+ },
|
|
|
+ }
|
|
|
+
|
|
|
+ opts := options.Update().SetUpsert(true)
|
|
|
+
|
|
|
+ _, err := collection.UpdateOne(ctx, filter, update, opts)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// 从fwh_pro获取站点信息表
|
|
|
+func QuerySiteInfoList(para SiteInfoPara) (SiteInfoResponse, error) {
|
|
|
+ resByte, err := fwh_pro.QuerySiteInfoList(para.SiteList, para.PageSize, para.PageNum)
|
|
|
+ if err != nil {
|
|
|
+ return SiteInfoResponse{}, err
|
|
|
+ }
|
|
|
+ var siteInfoRes SiteInfoResponse
|
|
|
+ // 反序列化(unmarshal)
|
|
|
+ jsonErr := json.Unmarshal(resByte, &siteInfoRes)
|
|
|
+ if jsonErr != nil {
|
|
|
+ return SiteInfoResponse{}, jsonErr
|
|
|
+ }
|
|
|
+
|
|
|
+ if siteInfoRes.Code == 401 {
|
|
|
+ // TODO 尝试重新登录
|
|
|
+ return SiteInfoResponse{}, errors.New("certification expired")
|
|
|
+ }
|
|
|
+
|
|
|
+ return siteInfoRes, nil
|
|
|
+}
|
|
|
+
|
|
|
+// 从fwh_pro获取站点工作模式信息
|
|
|
+func QuerySiteModeInfo(site string) (SiteModeInfoResponse, error) {
|
|
|
+ resByte, err := fwh_pro.QuerySiteModeInfo(site)
|
|
|
+ if err != nil {
|
|
|
+ return SiteModeInfoResponse{}, err
|
|
|
+ }
|
|
|
+ var siteModeInfoRes SiteModeInfoResponse
|
|
|
+ // 反序列化(unmarshal)
|
|
|
+ jsonErr := json.Unmarshal(resByte, &siteModeInfoRes)
|
|
|
+ if jsonErr != nil {
|
|
|
+ return SiteModeInfoResponse{}, jsonErr
|
|
|
+ }
|
|
|
+
|
|
|
+ if siteModeInfoRes.Code == 401 {
|
|
|
+ // TODO 尝试重新登录
|
|
|
+ return SiteModeInfoResponse{}, errors.New("certification expired")
|
|
|
+ }
|
|
|
+
|
|
|
+ return siteModeInfoRes, nil
|
|
|
+}
|
|
|
+
|
|
|
+// 从fwh_pro获取站点功率流
|
|
|
+func QuerySitePowerFlow(site string, day time.Time) (SitePowerFlowResponse, error) {
|
|
|
+ resByte, err := fwh_pro.QuerySitePowerFlow(site, day)
|
|
|
+ if err != nil {
|
|
|
+ return SitePowerFlowResponse{}, err
|
|
|
+ }
|
|
|
+ var sitePowerFlowRes SitePowerFlowResponse
|
|
|
+ // 反序列化(unmarshal)
|
|
|
+ jsonErr := json.Unmarshal(resByte, &sitePowerFlowRes)
|
|
|
+ if jsonErr != nil {
|
|
|
+ return SitePowerFlowResponse{}, jsonErr
|
|
|
+ }
|
|
|
+
|
|
|
+ if sitePowerFlowRes.Code == 401 {
|
|
|
+ // TODO 尝试重新登录
|
|
|
+ return SitePowerFlowResponse{}, errors.New("certification expired")
|
|
|
+ }
|
|
|
+
|
|
|
+ return sitePowerFlowRes, nil
|
|
|
+}
|
|
|
+
|
|
|
+// 从fwh_pro获取站点告警列表
|
|
|
+func QuerySiteAlarmList(site string) (SiteAlarmListResponse, error) {
|
|
|
+ resByte, err := fwh_pro.QuerySiteAlarmList(site)
|
|
|
+ if err != nil {
|
|
|
+ return SiteAlarmListResponse{}, err
|
|
|
+ }
|
|
|
+ var siteAlarmListRes SiteAlarmListResponse
|
|
|
+ // 反序列化(unmarshal)
|
|
|
+ jsonErr := json.Unmarshal(resByte, &siteAlarmListRes)
|
|
|
+ if jsonErr != nil {
|
|
|
+ return SiteAlarmListResponse{}, jsonErr
|
|
|
+ }
|
|
|
+
|
|
|
+ if siteAlarmListRes.Code == 401 {
|
|
|
+ // TODO 尝试重新登录
|
|
|
+ return SiteAlarmListResponse{}, errors.New("certification expired")
|
|
|
+ }
|
|
|
+
|
|
|
+ return siteAlarmListRes, nil
|
|
|
+}
|