|
@@ -7,6 +7,7 @@ import (
|
|
|
"github.com/beego/beego/v2/client/orm"
|
|
|
"github.com/shopspring/decimal"
|
|
|
"github.com/yidane/formula"
|
|
|
+ "regexp"
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
"time"
|
|
@@ -22,6 +23,7 @@ type EdbInfoCalculateSaveReq struct {
|
|
|
Unit string `description:"单位"`
|
|
|
ClassifyId int `description:"分类id"`
|
|
|
CalculateFormula string `description:"计算公式"`
|
|
|
+ EmptyType int `description:"空值处理类型(0查找前后35天,1不计算,2前值填充,3后值填充,4等于0)"`
|
|
|
EdbInfoIdArr []EdbInfoFromTag
|
|
|
}
|
|
|
|
|
@@ -172,6 +174,7 @@ func AddCalculateInfo(req EdbInfoCalculateSaveReq, calculateMappingList []*EdbIn
|
|
|
LatestDate: "",
|
|
|
LatestValue: 0,
|
|
|
ChartImage: "",
|
|
|
+ EmptyType: req.EmptyType,
|
|
|
}
|
|
|
lastId, err := to.Insert(edbInfo)
|
|
|
if err != nil {
|
|
@@ -194,7 +197,7 @@ func AddCalculateInfo(req EdbInfoCalculateSaveReq, calculateMappingList []*EdbIn
|
|
|
}
|
|
|
|
|
|
//计算数据
|
|
|
- err = refreshAllCalculate(to, edbInfoList, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.EdbCode, edbInfo.CalculateFormula, "", "", edbInfoIdBytes)
|
|
|
+ err = refreshAllCalculate(to, edbInfoList, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.EdbCode, edbInfo.CalculateFormula, "", "", edbInfoIdBytes, edbInfo.EmptyType)
|
|
|
|
|
|
return
|
|
|
}
|
|
@@ -223,7 +226,8 @@ func EditCalculateInfo(edbInfo *EdbInfo, req EdbInfoCalculateSaveReq, formulaMap
|
|
|
edbInfo.ClassifyId = req.ClassifyId
|
|
|
edbInfo.CalculateFormula = req.CalculateFormula
|
|
|
edbInfo.ModifyTime = time.Now()
|
|
|
- _, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "CalculateFormula", "ModifyTime")
|
|
|
+ edbInfo.EmptyType = req.EmptyType
|
|
|
+ _, err = to.Update(edbInfo, "EdbName", "EdbNameSource", "Frequency", "Unit", "ClassifyId", "CalculateFormula", "ModifyTime", "EmptyType")
|
|
|
if err != nil {
|
|
|
return
|
|
|
}
|
|
@@ -293,7 +297,7 @@ func EditCalculateInfo(edbInfo *EdbInfo, req EdbInfoCalculateSaveReq, formulaMap
|
|
|
}
|
|
|
|
|
|
//计算数据
|
|
|
- err = refreshAllCalculate(to, edbInfoList, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.EdbCode, edbInfo.CalculateFormula, "", "", edbInfoIdBytes)
|
|
|
+ err = refreshAllCalculate(to, edbInfoList, edbInfo.EdbInfoId, edbInfo.Source, edbInfo.EdbCode, edbInfo.CalculateFormula, "", "", edbInfoIdBytes, edbInfo.EmptyType)
|
|
|
|
|
|
}
|
|
|
|
|
@@ -337,7 +341,7 @@ func DeleteCalculateEdbInfo(edbInfoId int) (err error) {
|
|
|
}
|
|
|
|
|
|
// RefreshAllCalculate 刷新全部数据
|
|
|
-func RefreshAllCalculate(edbInfoIdArr []*EdbInfo, edbInfoId, source int, edbCode, formulaStr, startDate, endDate string, edbInfoIdBytes []string) (err error) {
|
|
|
+func RefreshAllCalculate(edbInfoIdArr []*EdbInfo, edbInfoId, source int, edbCode, formulaStr, startDate, endDate string, edbInfoIdBytes []string, emptyType int) (err error) {
|
|
|
o := orm.NewOrm()
|
|
|
to, err := o.Begin()
|
|
|
if err != nil {
|
|
@@ -354,13 +358,13 @@ func RefreshAllCalculate(edbInfoIdArr []*EdbInfo, edbInfoId, source int, edbCode
|
|
|
fmt.Println(startDate, endDate)
|
|
|
|
|
|
//计算数据
|
|
|
- err = refreshAllCalculate(to, edbInfoIdArr, edbInfoId, source, edbCode, formulaStr, startDate, endDate, edbInfoIdBytes)
|
|
|
+ err = refreshAllCalculate(to, edbInfoIdArr, edbInfoId, source, edbCode, formulaStr, startDate, endDate, edbInfoIdBytes, emptyType)
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
// refreshAllCalculate 刷新全部数据
|
|
|
-func refreshAllCalculate(to orm.TxOrmer, edbInfoIdArr []*EdbInfo, edbInfoId, source int, edbCode, formulaStr, startDate, endDate string, edbInfoIdBytes []string) (err error) {
|
|
|
+func refreshAllCalculate(to orm.TxOrmer, edbInfoIdArr []*EdbInfo, edbInfoId, source int, edbCode, formulaStr, startDate, endDate string, edbInfoIdBytes []string, emptyType int) (err error) {
|
|
|
realSaveDataMap := make(map[string]map[int]float64)
|
|
|
saveDataMap := make(map[string]map[int]float64)
|
|
|
|
|
@@ -431,9 +435,12 @@ func refreshAllCalculate(to orm.TxOrmer, edbInfoIdArr []*EdbInfo, edbInfoId, sou
|
|
|
}
|
|
|
|
|
|
//数据处理,将日期内不全的数据做补全
|
|
|
- handleDateSaveDataMap(dateList, maxStartDate, minLatestDate, realSaveDataMap, saveDataMap, edbInfoIdArr)
|
|
|
+ handleDateSaveDataMap(dateList, maxStartDate, minLatestDate, realSaveDataMap, saveDataMap, edbInfoIdArr, emptyType)
|
|
|
|
|
|
- formulaMap := utils.CheckFormula(formulaStr)
|
|
|
+ formulaDateSlice, formulaDateMap, err := utils.CheckFormulaJson(formulaStr, maxStartDate.Format(utils.FormatDate))
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
addSql := ` INSERT INTO edb_data_calculate(edb_info_id,edb_code,data_time,value,create_time,modify_time,data_timestamp) values `
|
|
|
var isAdd bool
|
|
|
|
|
@@ -456,7 +463,28 @@ func refreshAllCalculate(to orm.TxOrmer, edbInfoIdArr []*EdbInfo, edbInfoId, sou
|
|
|
edbInfoIdStr := strconv.Itoa(edbInfoId)
|
|
|
existDataMap := make(map[string]string)
|
|
|
for sk, sv := range saveDataMap {
|
|
|
+ // 当空值处理类型选择了不计算时,只要有一个指标在某个日期没有值(即空值),则计算指标在该日期没有值
|
|
|
+ if emptyType == 1 {
|
|
|
+ if len(sv) != len(edbInfoIdArr) {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ }
|
|
|
//fmt.Println(sk, sv)
|
|
|
+ // 根据时间范围,选择对应的公式
|
|
|
+ formulaMap := make(map[string]string)
|
|
|
+ formulaStr = ""
|
|
|
+ for _, fv := range formulaDateSlice {
|
|
|
+ if sk >= fv {
|
|
|
+ if f, ok := formulaDateMap[fv]; ok {
|
|
|
+ formulaStr = f
|
|
|
+ formulaMap = utils.CheckFormula(formulaStr)
|
|
|
+ }
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if formulaStr == "" {
|
|
|
+ continue
|
|
|
+ }
|
|
|
formulaStr = strings.ToUpper(formulaStr)
|
|
|
formulaFormStr := ReplaceFormula(edbInfoIdArr, sv, formulaMap, formulaStr, edbInfoIdBytes)
|
|
|
//计算公式异常,那么就移除该指标
|
|
@@ -575,9 +603,13 @@ func ReplaceFormula(edbInfoIdArr []*EdbInfo, valArr map[int]float64, formulaMap
|
|
|
}
|
|
|
|
|
|
func GetFormulaReplace(index, edbInfoId int, formulaStr string, edbInfoIdBytes []string, formulaMap map[string]string, valArr map[int]float64) (formulaResult string, isReplace bool) {
|
|
|
+ // todo 获取原本的值
|
|
|
+ valArrMax := make(map[int]float64)
|
|
|
+
|
|
|
formulaResult = formulaStr
|
|
|
dKey := edbInfoIdBytes[index]
|
|
|
if _, ok := formulaMap[dKey]; ok { //公式中存在
|
|
|
+ // todo 判断公式中存在max、min,如果存在,则值从valArrMax中获取,其余的值从valArr中获取
|
|
|
if val, valOk := valArr[edbInfoId]; valOk { //值存在
|
|
|
dvStr := fmt.Sprintf("%v", val)
|
|
|
formulaResult = strings.Replace(formulaStr, dKey, dvStr, -1)
|
|
@@ -599,6 +631,8 @@ func GetFormulaMap() map[string]string {
|
|
|
funMap["MOD"] = "[@&]"
|
|
|
funMap["POW"] = "[@*]"
|
|
|
funMap["ROUND"] = "[@(]"
|
|
|
+ funMap["LN"] = "[@-]"
|
|
|
+ funMap["EXP"] = "[@+]"
|
|
|
return funMap
|
|
|
}
|
|
|
|
|
@@ -671,7 +705,22 @@ func CheckFormula2(edbInfoArr []*EdbInfo, formulaMap map[string]string, formulaS
|
|
|
}
|
|
|
|
|
|
// 处理整个数据
|
|
|
-func handleDateSaveDataMap(dateList []string, maxStartDate, minLatestDate time.Time, realSaveDataMap, saveDataMap map[string]map[int]float64, edbInfoIdArr []*EdbInfo) {
|
|
|
+func handleDateSaveDataMap(dateList []string, maxStartDate, minLatestDate time.Time, realSaveDataMap, saveDataMap map[string]map[int]float64, edbInfoIdArr []*EdbInfo, emptyType int) {
|
|
|
+ var startDate, endDate string
|
|
|
+ var startDateT, endDateT time.Time
|
|
|
+ if emptyType == 2 || emptyType == 3 {
|
|
|
+ for k, _ := range realSaveDataMap {
|
|
|
+ if k > endDate {
|
|
|
+ endDate = k
|
|
|
+ }
|
|
|
+ if k < startDate || startDate == "" {
|
|
|
+ startDate = k
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ startDateT, _ = time.ParseInLocation(utils.FormatDate, startDate, time.Local)
|
|
|
+ endDateT, _ = time.ParseInLocation(utils.FormatDate, endDate, time.Local)
|
|
|
+ }
|
|
|
for _, date := range dateList {
|
|
|
dateTime, _ := time.ParseInLocation(utils.FormatDate, date, time.Local)
|
|
|
// 如果当前日期早于数据的最大开始日期,那么不处理,进入下一个循环
|
|
@@ -688,6 +737,7 @@ func handleDateSaveDataMap(dateList []string, maxStartDate, minLatestDate time.T
|
|
|
tmpEdbInfoId := edbInfo.EdbInfoId // 当前指标id
|
|
|
// 如果该日期不存在该指标数据,那么需要找寻前后日期的数据,进行填补
|
|
|
if _, ok := tmpDataMap[tmpEdbInfoId]; !ok {
|
|
|
+
|
|
|
//day := 0
|
|
|
//switch edbInfo.Frequency {
|
|
|
//case "周度":
|
|
@@ -702,14 +752,24 @@ func handleDateSaveDataMap(dateList []string, maxStartDate, minLatestDate time.T
|
|
|
// day = 365
|
|
|
//}
|
|
|
// 需求池 255 指标运算文案修改,补数据遍历区间修改(2023-3-7 09:37:23修改)
|
|
|
- day := 35
|
|
|
- handleDateDataMap(realSaveDataMap, saveDataMap, date, tmpEdbInfoId, day)
|
|
|
+
|
|
|
+ switch emptyType {
|
|
|
+ case 0:
|
|
|
+ handleDateDataMap(realSaveDataMap, saveDataMap, date, tmpEdbInfoId, 35)
|
|
|
+ case 2:
|
|
|
+ handleDateDataMapBefore(realSaveDataMap, saveDataMap, date, tmpEdbInfoId, startDateT, endDateT)
|
|
|
+ case 3:
|
|
|
+ handleDateDataMapAfter(realSaveDataMap, saveDataMap, date, tmpEdbInfoId, startDateT, endDateT)
|
|
|
+ case 4:
|
|
|
+ handleDateDataMapZero(saveDataMap, date, tmpEdbInfoId)
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-// handleDateDataMap 处理单个日期的数据
|
|
|
+// handleDateDataMap 前后35天 处理单个日期的数据
|
|
|
func handleDateDataMap(realSaveDataMap, saveDataMap map[string]map[int]float64, date string, edbInfoId, day int) {
|
|
|
currDate, _ := time.ParseInLocation(utils.FormatDate, date, time.Local)
|
|
|
|
|
@@ -748,3 +808,113 @@ func handleDateDataMap(realSaveDataMap, saveDataMap map[string]map[int]float64,
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+// handleDateDataMapBefore 前值填充:空值优先以最近的前值填充,没有前值时,用后值填充
|
|
|
+func handleDateDataMapBefore(realSaveDataMap, saveDataMap map[string]map[int]float64, date string, edbInfoId int, startDateT, endDateT time.Time) {
|
|
|
+ currDate, _ := time.ParseInLocation(utils.FormatDate, date, time.Local)
|
|
|
+
|
|
|
+ // 后一天
|
|
|
+ nextDateDay := currDate
|
|
|
+
|
|
|
+ // 前一天
|
|
|
+ preDateDay := currDate
|
|
|
+
|
|
|
+ for i := 1; preDateDay.After(startDateT) || preDateDay == startDateT; i++ {
|
|
|
+ // 上个日期的数据
|
|
|
+ {
|
|
|
+ preDateDay = currDate.AddDate(0, 0, -i)
|
|
|
+ preDateDayStr := preDateDay.Format(utils.FormatDate)
|
|
|
+ if findDataMap, hasFindDataMap := realSaveDataMap[preDateDayStr]; hasFindDataMap { // 下一个日期有数据
|
|
|
+ if val, hasFindItem := findDataMap[edbInfoId]; hasFindItem {
|
|
|
+ fmt.Println(fmt.Sprintf("date:%s, 无值,取%s的值%.4f", date, preDateDayStr, val))
|
|
|
+ saveDataMap[date][edbInfoId] = val
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for i := 1; nextDateDay.Before(endDateT) || nextDateDay == endDateT; i++ {
|
|
|
+ // 下个日期的数据
|
|
|
+ {
|
|
|
+ nextDateDay = currDate.AddDate(0, 0, i)
|
|
|
+ nextDateDayStr := nextDateDay.Format(utils.FormatDate)
|
|
|
+ if findDataMap, hasFindDataMap := realSaveDataMap[nextDateDayStr]; hasFindDataMap { // 下一个日期有数据
|
|
|
+ if val, hasFindItem := findDataMap[edbInfoId]; hasFindItem {
|
|
|
+ fmt.Println(fmt.Sprintf("date:%s, 无值,取%s的值%.4f", date, nextDateDayStr, val))
|
|
|
+ saveDataMap[date][edbInfoId] = val
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// handleDateDataMapAfter 后值填充:空值优先以最近的后值填充,没有后值时,用前值填充
|
|
|
+func handleDateDataMapAfter(realSaveDataMap, saveDataMap map[string]map[int]float64, date string, edbInfoId int, startDateT, endDateT time.Time) {
|
|
|
+ currDate, _ := time.ParseInLocation(utils.FormatDate, date, time.Local)
|
|
|
+
|
|
|
+ // 后一天
|
|
|
+ nextDateDay := currDate
|
|
|
+
|
|
|
+ // 前一天
|
|
|
+ preDateDay := currDate
|
|
|
+
|
|
|
+ for i := 1; nextDateDay.Before(endDateT) || nextDateDay == endDateT; i++ {
|
|
|
+ // 下个日期的数据
|
|
|
+ {
|
|
|
+ nextDateDay = currDate.AddDate(0, 0, i)
|
|
|
+ nextDateDayStr := nextDateDay.Format(utils.FormatDate)
|
|
|
+ if findDataMap, hasFindDataMap := realSaveDataMap[nextDateDayStr]; hasFindDataMap { // 下一个日期有数据
|
|
|
+ if val, hasFindItem := findDataMap[edbInfoId]; hasFindItem {
|
|
|
+ fmt.Println(fmt.Sprintf("date:%s, 无值,取%s的值%.4f", date, nextDateDayStr, val))
|
|
|
+ saveDataMap[date][edbInfoId] = val
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for i := 1; preDateDay.After(startDateT) || preDateDay == startDateT; i++ {
|
|
|
+ // 上个日期的数据
|
|
|
+ {
|
|
|
+ preDateDay = currDate.AddDate(0, 0, -i)
|
|
|
+ preDateDayStr := preDateDay.Format(utils.FormatDate)
|
|
|
+ if findDataMap, hasFindDataMap := realSaveDataMap[preDateDayStr]; hasFindDataMap { // 下一个日期有数据
|
|
|
+ if val, hasFindItem := findDataMap[edbInfoId]; hasFindItem {
|
|
|
+ fmt.Println(fmt.Sprintf("date:%s, 无值,取%s的值%.4f", date, preDateDayStr, val))
|
|
|
+ saveDataMap[date][edbInfoId] = val
|
|
|
+ return
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// handleDateDataMapZero 等于0
|
|
|
+func handleDateDataMapZero(saveDataMap map[string]map[int]float64, date string, edbInfoId int) {
|
|
|
+ saveDataMap[date][edbInfoId] = 0
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+func GetMaxMinEdbInfo(formula string, formulaMap map[string]string) (edbInfoIdBytes []string) {
|
|
|
+ //formula := "A+min(A,B,max(A,C))"
|
|
|
+ // 定义正则表达式匹配max和min函数及其参数
|
|
|
+ regex := regexp.MustCompile(`MIN\((.*?)\)|MAX\((.*?)\)`)
|
|
|
+ matches := regex.FindAllStringSubmatch(formula, -1)
|
|
|
+
|
|
|
+ // 遍历匹配结果,输出max和min函数及其参数
|
|
|
+ for _, match := range matches {
|
|
|
+ if len(match) == 3 {
|
|
|
+ function := match[1] // min或max函数
|
|
|
+ parameter := match[2]
|
|
|
+ // todo 将max和min函数里的入参替换成小写
|
|
|
+ //lowercaseParameter := parameter // 参数保持不变
|
|
|
+ //lowercaseFormula = strings.ReplaceAll(lowercaseFormula, match[0], lowercaseFunction+lowercaseParameter) // 替换公式中的MAX/MIN函数及其参数为小写形式
|
|
|
+ fmt.Printf("Function: %s, Parameter: %s\n", function, parameter)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|