package api import ( "encoding/json" "errors" "fmt" "io/ioutil" "math" "net/http" "strconv" "strings" "time" "tmr-watch/http/handle/restful" "tmr-watch/pkg/app" "tmr-watch/pkg/e" "tmr-watch/pkg/logging" "github.com/Anderson-Lu/gofasion/gofasion" "github.com/Knetic/govaluate" "github.com/gin-gonic/gin" "github.com/xormplus/xorm" ) //配方评估相关 type Nur struct { Avgmonthage float64 //月龄 Bw float64 //体重 Dayw float64 //日增重 Fetal float64 //胎次 Avgdim float64 //平均泌乳天数 Dayspre float64 //怀孕天数 Product float64 //产奶量 Fat float64 //乳脂率 Pro float64 //乳蛋白率 Lactose float64 //乳糖率 Source string //来源 Tem float64 //温度 Cowsum float64 //牛头数 Cowclass string //牲畜类别 Cowclassid string //牲畜类别id Bigcowclass string //牲畜大类 } //栏舍配方中的配方评估 func GETNurJudge(c *gin.Context) { appG := app.Gin{C: c} dataByte, _ := ioutil.ReadAll(c.Request.Body) fsion := gofasion.NewFasion(string(dataByte)) nurstr := fsion.Get("parammaps").Json() parammaps := make(map[string]interface{}) nur := Nur{} _ = json.Unmarshal([]byte(nurstr), &nur) //需要json 的类型相同 _ = json.Unmarshal([]byte(nurstr), ¶mmaps) //需要json 的类型相同 tx := restful.Engine.NewSession() err := tx.Begin() defer func() { switch { case err != nil: fmt.Println("__error:", err) if tx != nil { tx.Rollback() } default: if tx != nil { err = tx.Commit() } } if tx != nil { tx.Close() } }() //获取 tb_formula_d 表中对应牲畜类别及营养价值的公式 formulas, _ := tx.SQL("select * from tb_formula_d where cowclass = ? "+ "and if (?='',''='', nutrition=? ) ORDER BY nutrition", nur.Bigcowclass, nur.Source, nur.Source).Query().List() // 根据公式和栏舍生产性能的指标计算出奶牛需要 resnur, err := CalNUR(formulas, &nur) if err != nil { logging.Error("GETNurJudge err: ", err) msg := geterrmsg(err.Error()) appG.Response(http.StatusOK, e.ERROR, msg) } // 计算出配方提供、tmr料、采食量 resf, err := FeedproviderV2(parammaps, tx) reslist := make([]map[string]interface{}, 21) // 将数据转成前端需要的格式 if len(resf) > 1 { for key, _ := range resf[0] { //println(key) str, sort := switchname(key) res := make(map[string]interface{}, 0) res["standard"] = str res["cowneed"] = resnur[key] // 奶牛需要 res["ftpro"] = resf[0][key] // 配方提供 res["hprov"] = resf[1][key] // tmr料 res["sprov"] = resf[2][key] //采食量 reslist[sort] = res } } if err != nil { logging.Error("GETNurJudge err: ", err) msg := geterrmsg(err.Error()) appG.Response(http.StatusOK, e.ERROR, msg) } else { appG.Response(http.StatusOK, e.SUCCESS, reslist) } } //报表配方评估 func GETNurJudgeRport(c *gin.Context) { appG := app.Gin{C: c} dataByte, _ := ioutil.ReadAll(c.Request.Body) fsion := gofasion.NewFasion(string(dataByte)) nurstr := fsion.Get("parammaps").Json() parammaps := make(map[string]interface{}) _ = json.Unmarshal([]byte(nurstr), ¶mmaps) tx := restful.Engine.NewSession() err := tx.Begin() defer func() { switch { case err != nil: fmt.Println("__error:", err) if tx != nil { tx.Rollback() } default: if tx != nil { err = tx.Commit() } } if tx != nil { tx.Close() } }() //CulNurReportCow("getbmdetaillist",parammaps,tx) res, err := CulNurReportFT(parammaps, tx) if err != nil { logging.Error("GETNurJudgeRport err: ", err) //appG.Response(http.StatusOK, e.ERROR, err.Error()) msg := geterrmsg(err.Error()) appG.Response(http.StatusOK, e.ERROR, msg) } else { appG.Response(http.StatusOK, e.SUCCESS, res) } } //奶牛需要 func CulNurReportCow(sqlname string, parammaps map[string]interface{}, tx *xorm.Session) (map[string]interface{}, error) { var nur Nur sql, p := restful.GetSqlByNameDBT(sqlname, tx) s_params := make([]interface{}, 0) paramslist := strings.Split(p, ",") if len(paramslist) > 0 && p != "" { for _, value := range paramslist { s_params = append(s_params, parammaps[strings.Trim(value, " ")]) } } res, err := tx.SQL(sql, s_params...).Query().List() if len(res) > 0 { resstr, _ := json.Marshal(res[0]) err = json.Unmarshal(resstr, &nur) if err != nil { return nil, err } } formulas, _ := tx.SQL("select * from tb_formula_d where cowclass = ? and if (?='',''='', nutrition=? ) ORDER BY nutrition", nur.Bigcowclass, nur.Source, nur.Source).Query().List() resnur, err := CalNUR(formulas, &nur) if err != nil { return nil, err } return resnur, err } func CulNurReportFT(parammaps map[string]interface{}, tx *xorm.Session) (res []map[string]interface{}, err error) { // 获取该配方日期范围内的所有栏舍 //barids, err := tx.SQL("SELECT trim(fp.barid) barid,fp.ccount,DATE_FORMAT(fp.date, '%Y-%m-%d')date,fp.barname FROM feedpdate fp WHERE fp.pastureid = ? AND fp.date BETWEEN ? AND ? AND fp.`ftid` = ? GROUP BY fp.`barid` order by fp.barid", // parammaps["pastureid"], parammaps["startTime"], parammaps["stopTime"], parammaps["ftid"]).Query().List() barids, err := tx.SQL(` SELECT TRIM(fp.barid) barid,IFNULL((SELECT bm.cowsum FROM barmilk bm WHERE pastureid = fp.pastureid AND barid = fp.barid AND productdate <= ? ORDER BY productdate LIMIT 1),fp.ccount) ccount,DATE_FORMAT(fp.date, '%Y-%m-%d')date, fp.barname FROM feedpdate fp WHERE fp.pastureid = ? AND fp.date BETWEEN ? AND ? AND fp.ftid = ? GROUP BY fp.barid ORDER BY fp.barid`, parammaps["stopTime"], parammaps["pastureid"], parammaps["startTime"], parammaps["stopTime"], parammaps["ftid"]).Query().List() if err != nil { return nil, err } bartem := "" // 获取日期,以及日期范围校验 dates := make([]string, 0) startTime, err := time.Parse("2006-01-02", parammaps["startTime"].(string)) if err != nil { return nil, err } stopTime, err := time.Parse("2006-01-02", parammaps["stopTime"].(string)) if err != nil { return nil, err } if stopTime.Sub(startTime) > 31*24*time.Hour { return nil, errors.New("日期范围过大") } for stopTime.Sub(startTime) >= 0 { dates = append(dates, startTime.Format("2006-01-02")) startTime = startTime.Add(24 * time.Hour) } parammaps["date"] = parammaps["stopTime"] for key, value := range barids { // 遍历栏舍 if key == 0 { bartem = value["barid"].(string) parammaps["barid"] = value["barid"] } if bartem != value["barid"].(string) || key == len(barids)-1 || key == 0 { parammaps["barid"] = value["barid"] barres, err := FeedproviderV3(parammaps, dates, tx) if err != nil { return nil, err } // resnur, err := CulNurReportCow("getbmdetaillist", parammaps, tx) if err != nil { return nil, err } restem := make(map[string]interface{}, 0) for k, _ := range barres[0] { //println("wwwwwww",k) restem["barid"] = value["barid"].(string) restem["barname"] = value["barname"].(string) restem["ccount"] = value["ccount"].(int64) restem[k+"-nur"] = resnur[k] restem[k+"-FT"] = barres[0][k] restem[k+"-H"] = barres[1][k] restem[k+"-S"] = barres[2][k] } res = append(res, restem) if err != nil { return nil, err } bartem = value["barid"].(string) dates = make([]string, 0) parammaps["barid"] = value["barid"] } dates = append(dates, value["date"].(string)) } return res, err } //排序 func switchname(str string) (string, int) { tstr := "" sort := 0 switch str { case "dry": tstr = "干物质(kg)" sort = 0 case "nm": tstr = "产奶净能(MJ)" sort = 1 case "nuint": tstr = "奶牛能量单位(NND)" sort = 2 case "cp": tstr = "粗蛋白(g)" sort = 3 case "ca": tstr = " 钙(g)" sort = 4 case "p": tstr = "磷(g)" sort = 5 case "nmd": tstr = "产奶净能(MCal/DM)" sort = 6 case "cpd": tstr = "粗蛋白(%DM)" sort = 7 case "fat": tstr = "脂肪" sort = 8 case "starch": tstr = "淀粉" sort = 9 case "ndf": tstr = "NDF(%DM)" sort = 10 case "cndf": tstr = "粗料中的NDF(%DM)" sort = 11 case "adf": tstr = "ADF(%DM)" sort = 12 case "cad": tstr = " 钙(%DM)" sort = 13 case "pd": tstr = "磷(%DM)" sort = 14 case "trans35f": tstr = "(3.5)饲料转化效率(kg/DM)" sort = 15 case "trans4f": tstr = "(4.0)饲料转化效率(kg/DM)" sort = 16 case "jcrate": tstr = "精粗比" sort = 17 case "uprice": tstr = "日粮成本(元)" sort = 18 case "upriced": tstr = "干物质成本(元/公斤)" sort = 19 case "kprice": tstr = "公斤奶成本(元) " sort = 20 default: tstr = str sort = 21 } return tstr, sort } // 计算出配方提供、tmr料、采食量 func FeedproviderV2(parammaps map[string]interface{}, tx *xorm.Session) ([]map[string]float64, error) { startTime, err := time.Parse("2006-01-02", parammaps["startTime"].(string)) if err != nil { return nil, err } stopTime, err := time.Parse("2006-01-02", parammaps["stopTime"].(string)) if err != nil { return nil, err } if stopTime.Sub(startTime) > 31*24*time.Hour { return nil, errors.New("日期范围过大") } dates := make([]string, 0) for stopTime.Sub(startTime) >= 0 { dates = append(dates, startTime.Format("2006-01-02")) startTime = startTime.Add(24 * time.Hour) } resall, err := FeedproviderV3(parammaps, dates, tx) return resall, err } func FeedproviderV3(parammaps map[string]interface{}, dates []string, tx *xorm.Session) ([]map[string]float64, error) { res := make(map[string]float64, 0) resH := make(map[string]float64, 0) resS := make(map[string]float64, 0) i := 0 for _, date := range dates { i++ //println(date) parammaps["date"] = date restem, err := Feedprovider(parammaps, tx) if err != nil { return nil, err } restemSH, err := SHprovider(parammaps, tx) if err != nil { return nil, err } var h, s float64 if len(restemSH) > 1 { switch restemSH[0]["actualweightminus"].(type) { case string: h, _ = strconv.ParseFloat(restemSH[0]["actualweightminus"].(string), 64) } switch restemSH[1]["actualweightminus"].(type) { case string: s, _ = strconv.ParseFloat(restemSH[1]["actualweightminus"].(string), 64) } } if len(restem) > 0 { b, _ := strconv.ParseFloat(restem[0]["jcrate"].(string), 64) res["jcrate"] = res["jcrate"] + b resH["jcrate"] = resH["jcrate"] + h*b resS["jcrate"] = resS["jcrate"] + s*b b, _ = strconv.ParseFloat(restem[0]["cpd"].(string), 64) res["cpd"] = res["cpd"] + b resH["cpd"] = resH["cpd"] + h*b resS["cpd"] = resS["cpd"] + s*b b, _ = strconv.ParseFloat(restem[0]["adf"].(string), 64) res["adf"] = res["adf"] + b resH["adf"] = resH["adf"] + h*b resS["adf"] = resS["adf"] + s*b b, _ = strconv.ParseFloat(restem[0]["ca"].(string), 64) res["ca"] = res["ca"] + b resH["ca"] = resH["ca"] + h*b resS["ca"] = resS["ca"] + s*b b, _ = strconv.ParseFloat(restem[0]["cad"].(string), 64) res["cad"] = res["cad"] + b resH["cad"] = resH["cad"] + h*b resS["cad"] = resS["cad"] + s*b //b,_ =strconv.ParseFloat(restem[0]["cdry"].(string),64) //res["cdry"] = res["cdry"]+b // //resH["cdry"] = resH["cdry"]+ h*b //resS["cdry"] = resS["cdry"]+ s*b b, _ = strconv.ParseFloat(restem[0]["cndf"].(string), 64) res["cndf"] = res["cndf"] + b resH["cndf"] = resH["cndf"] + h*b resS["cndf"] = resS["cndf"] + s*b b, _ = strconv.ParseFloat(restem[0]["cp"].(string), 64) res["cp"] = res["cp"] + b resH["cp"] = resH["cp"] + h*b resS["cp"] = resS["cp"] + s*b b, _ = strconv.ParseFloat(restem[0]["dry"].(string), 64) res["dry"] = res["dry"] + b resH["dry"] = resH["dry"] + h*b resS["dry"] = resS["dry"] + s*b b, _ = strconv.ParseFloat(restem[0]["fat"].(string), 64) res["fat"] = res["fat"] + b resH["fat"] = resH["fat"] + h*b resS["fat"] = resS["fat"] + s*b b, _ = strconv.ParseFloat(restem[0]["kprice"].(string), 64) res["kprice"] = res["kprice"] + b resH["kprice"] = resH["kprice"] + h*b resS["kprice"] = resS["kprice"] + s*b b, _ = strconv.ParseFloat(restem[0]["nm"].(string), 64) res["nm"] = res["nm"] + b resH["nm"] = resH["nm"] + h*b resS["nm"] = resS["nm"] + s*b b, _ = strconv.ParseFloat(restem[0]["ndf"].(string), 64) res["ndf"] = res["ndf"] + b resH["ndf"] = resH["ndf"] + h*b resS["ndf"] = resS["ndf"] + s*b b, _ = strconv.ParseFloat(restem[0]["nm"].(string), 64) res["nm"] = res["nm"] + b resH["nm"] = resH["nm"] + h*b resS["nm"] = resS["nm"] + s*b b, _ = strconv.ParseFloat(restem[0]["nmd"].(string), 64) res["nmd"] = res["nmd"] + b resH["nmd"] = resH["nmd"] + h*b resS["nmd"] = resS["nmd"] + s*b b, _ = strconv.ParseFloat(restem[0]["nuint"].(string), 64) res["nuint"] = res["nuint"] + b resH["nuint"] = resH["nuint"] + h*b resS["nuint"] = resS["nuint"] + s*b b, _ = strconv.ParseFloat(restem[0]["p"].(string), 64) res["p"] = res["p"] + b resH["p"] = resH["p"] + h*b resS["p"] = resS["p"] + s*b b, _ = strconv.ParseFloat(restem[0]["pd"].(string), 64) res["pd"] = res["pd"] + b resH["pd"] = resH["pd"] + h*b resS["pd"] = resS["pd"] + s*b b, _ = strconv.ParseFloat(restem[0]["starch"].(string), 64) res["starch"] = res["starch"] + b resH["starch"] = resH["starch"] + h*b resS["starch"] = resS["starch"] + s*b b, _ = strconv.ParseFloat(restem[0]["trans4f"].(string), 64) res["trans4f"] = res["trans4f"] + b resH["trans4f"] = resH["trans4f"] + h*b resS["trans4f"] = resS["trans4f"] + s*b b, _ = strconv.ParseFloat(restem[0]["trans35f"].(string), 64) res["trans35f"] = res["trans35f"] + b resH["trans35f"] = resH["trans35f"] + h*b resS["trans35f"] = resS["trans35f"] + s*b b, _ = strconv.ParseFloat(restem[0]["uprice"].(string), 64) res["uprice"] = res["uprice"] + b resH["uprice"] = resH["uprice"] + h*b resS["uprice"] = resS["uprice"] + s*b b, _ = strconv.ParseFloat(restem[0]["upriced"].(string), 64) res["upriced"] = res["upriced"] + b resH["upriced"] = resH["upriced"] + h*b resS["upriced"] = resS["upriced"] + s*b } } for key, _ := range res { resf, _ := strconv.ParseFloat(fmt.Sprintf("%.3f", res[key]/float64(i)), 64) resHf, _ := strconv.ParseFloat(fmt.Sprintf("%.3f", resH[key]/float64(i)), 64) resSf, _ := strconv.ParseFloat(fmt.Sprintf("%.3f", resS[key]/float64(i)), 64) res[key] = resf resH[key] = resHf resS[key] = resSf } resAll := make([]map[string]float64, 0) resAll = append(resAll, res, resH, resS) return resAll, nil } func Feedprovider(parammaps map[string]interface{}, tx *xorm.Session) ([]map[string]interface{}, error) { sql, p := restful.GetSqlByNameDBT(parammaps["name"].(string), tx) s_params := make([]interface{}, 0) paramslist := strings.Split(p, ",") if len(paramslist) > 0 && p != "" { for _, value := range paramslist { s_params = append(s_params, parammaps[strings.Trim(value, " ")]) } } res, err := tx.SQL(sql, s_params...).Query().List() return res, err } func SHprovider(parammaps map[string]interface{}, tx *xorm.Session) ([]map[string]interface{}, error) { sql, p := restful.GetSqlByNameDBT(parammaps["name1"].(string), tx) //println(parammaps["name1"].(string),sql) s_params := make([]interface{}, 0) paramslist := strings.Split(p, ",") if len(paramslist) > 0 && p != "" { for _, value := range paramslist { s_params = append(s_params, parammaps[strings.Trim(value, " ")]) } } res, err := tx.SQL(sql, s_params...).Query().List() return res, err } //根据公式和栏舍生产性能的指标计算出奶牛需要 func CalNUR(formulas []map[string]interface{}, nur *Nur) (map[string]interface{}, error) { resmap := make(map[string]float64) resmapstr := make(map[string]string) resAll := make(map[string]interface{}) for _, formula := range formulas { if formula["type"].(int64) == 0 { resmapstr[formula["note"].(string)] = formula["formula"].(string) continue } res, err := PraseFormula(formula["formula"].(string), nur) if err != nil { logging.Error("PraseFormula err", err.Error(), formula["nutrition"].(string)) //println("PraseFormula err", err.Error(), formula["nutrition"].(string)) } switch res.(type) { case string: resmapstr[formula["note"].(string)] = res.(string) case float64, int, float32, int64, int32, int16, int8: var rest float64 switch res.(type) { case float64: rest = res.(float64) case int: rest = float64(res.(int)) case int64: rest = float64(res.(int64)) case int32: rest = float64(res.(int32)) case int16: rest = float64(res.(int16)) case int8: rest = float64(res.(int8)) } switch formula["nutrition"].(string) { case "ADF %DM": resmap["adf"] = resmap["adf"] + rest case "NDF %DM": resmap["ndf"] = resmap["ndf"] + rest case "NFC %DM": resmap["nfc"] = resmap["nfc"] + rest //case "小肠可消化粗蛋白": // resmap["cprotedm"] = resmap["cprotedm"] + rest case "干物质": resmap["dry"] = resmap["dry"] + rest case "淀粉": resmap["starch"] = resmap["starch"] + rest case "磷": resmap["p"] = resmap["p"] + rest case "粗料中的NDF %DM": resmap["cndf"] = resmap["cndf"] + rest case "粗料比例": resmap["jcrate"] = resmap["jcrate"] + rest case "粗蛋白": resmap["cp"] = resmap["cp"] + rest case "能量": resmap["nm"] = resmap["nm"] + rest case "脂肪": resmap["fat"] = resmap["fat"] + rest case "钙": resmap["ca"] = resmap["ca"] + rest case "饲料转化效率,标准乳/干物质": resmap["trans4f"] = resmap["trans4f"] + rest case "饲料转化效率,标准乳/干物质3.5": resmap["trans35f"] = resmap["trans35f"] + rest } default: fmt.Printf("===============%T \n", res) } } if resmap["dry"] == 0 { //粗蛋白%dm = 粗蛋白/干物质 resmap["cpd"] = 0 resmap["cad"] = 0 resmap["pd"] = 0 resmap["nuint"] = 0 resmap["nmd"] = 0 } else { resmap["cpd"] = resmap["cp"] / resmap["dry"] / 10 resmap["cad"] = resmap["ca"] / resmap["dry"] / 10 resmap["pd"] = resmap["p"] / resmap["dry"] / 10 resmap["nuint"] = resmap["nm"] / 3.138 resmap["nmd"] = resmap["nm"] * 0.2389 / resmap["dry"] } for key, value := range resmap { va, _ := strconv.ParseFloat(fmt.Sprintf("%.3f", value), 64) resAll[key] = va } for key, value := range resmapstr { //println(key, value) resAll[key] = value } resAll["uprice"] = "" resAll["upriced"] = "" resAll["kprice"] = "" return resAll, nil } //解析计算公式 func PraseFormula(formula string, nur *Nur) (interface{}, error) { str := formula str = strings.ReplaceAll(str, "日增重", strconv.FormatFloat(nur.Dayw, 'f', -1, 64)) //str = strings.ReplaceAll(str, "体重", nur.Bw) str = strings.ReplaceAll(str, "怀孕天数", strconv.FormatFloat(nur.Dayspre, 'f', -1, 64)) str = strings.ReplaceAll(str, "产量", strconv.FormatFloat(nur.Product, 'f', -1, 64)) str = strings.ReplaceAll(str, "乳脂率", strconv.FormatFloat(nur.Fat, 'f', -1, 64)) str = strings.ReplaceAll(str, "乳蛋白率", strconv.FormatFloat(nur.Pro, 'f', -1, 64)) str = strings.ReplaceAll(str, "乳糖率", strconv.FormatFloat(nur.Lactose, 'f', -1, 64)) str = strings.ReplaceAll(str, "标准乳", strconv.FormatFloat(0.35*nur.Product+15*nur.Fat/100*nur.Product, 'f', -1, 64)) // 3.5乳脂率 //str = strings.ReplaceAll(str, "标准乳", strconv.FormatFloat(0.35*nur.Product+18.57*nur.Fat/100*nur.Product, 'f', -1, 64)) //println("标准乳--",strconv.FormatFloat(0.4*nur.Product+15*nur.Fat/100*nur.Product, 'f', -1, 64)) str = strings.ReplaceAll(str, "泌乳天数", strconv.FormatFloat(nur.Avgdim, 'f', -1, 64)) str = strings.ReplaceAll(str, "月龄", strconv.FormatFloat(nur.Avgmonthage, 'f', -1, 64)) str = strings.ReplaceAll(str, "温度", strconv.FormatFloat(nur.Tem, 'f', -1, 64)) str = strings.ReplaceAll(str, "胎次", strconv.FormatFloat(nur.Fetal, 'f', -1, 64)) str = strings.ReplaceAll(str, "体重", strconv.FormatFloat(nur.Bw, 'f', -1, 64)) str = strings.ReplaceAll(str, "Math.pow", "Mathpow") str = strings.ReplaceAll(str, "Math.round", "Mathround") str = strings.ReplaceAll(str, "Math.log", "Mathlog") str = strings.ReplaceAll(str, "Math.exp", "Mathexp") //str := "(体重>200?4.2/0.55*Math.pow(体重,0.75):3.5/0.55*Math.pow(体重,0.75))" functions := map[string]govaluate.ExpressionFunction{ "strlen": func(args ...interface{}) (interface{}, error) { length := len(args[0].(string)) return (float64)(length), nil }, "Mathpow": func(args ...interface{}) (interface{}, error) { c := math.Pow(args[0].(float64), args[1].(float64)) return (float64)(c), nil }, "Mathround": func(args ...interface{}) (interface{}, error) { c := math.Round(args[0].(float64)) return (float64)(c), nil }, "Mathlog": func(args ...interface{}) (interface{}, error) { c := math.Log(args[0].(float64)) return (float64)(c), nil }, "Mathexp": func(args ...interface{}) (interface{}, error) { c := math.Exp(args[0].(float64)) return (float64)(c), nil }, } expression, err := govaluate.NewEvaluableExpressionWithFunctions(str, functions) if err != nil { return 0, err } //fmt.Printf("== %+v\n", str) result, err := expression.Evaluate(nil) //fmt.Printf("== %+v\n", result) if err != nil || result == nil { return 0, err } return result, err }