package excel import ( "encoding/json" "errors" "eta/eta_api/models/data_manage" "eta/eta_api/models/data_manage/excel" "eta/eta_api/models/data_manage/excel/request" "eta/eta_api/models/data_manage/excel/response" "eta/eta_api/models/system" "eta/eta_api/services/data" "eta/eta_api/services/data/data_manage_permission" "eta/eta_api/utils" "fmt" "sort" "time" ) // GetExcelDetailInfoByExcelInfoId 根据表格id获取表格详情 func GetExcelDetailInfoByExcelInfoId(excelInfoId, sysUserId int, lang string) (excelDetail response.ExcelInfoDetail, errMsg string, err error) { errMsg = `获取失败` //获取eta表格信息 excelInfo, err := excel.GetExcelInfoById(excelInfoId) if err != nil { err = errors.New("获取ETA表格信息失败,Err:" + err.Error()) if err.Error() == utils.ErrNoRow() { errMsg = "ETA表格被删除,请刷新页面" err = errors.New("ETA表格被删除,请刷新页面,Err:" + err.Error()) } return } return formatExcelInfo2Detail(excelInfo, sysUserId, lang) } // GetExcelDetailInfoByUnicode 根据表格编码获取表格详情 func GetExcelDetailInfoByUnicode(unicode string, sysUserId int, lang string) (excelDetail response.ExcelInfoDetail, errMsg string, err error) { errMsg = `获取失败` // 获取eta表格信息 excelInfo, err := excel.GetExcelInfoByUnicode(unicode) if err != nil { err = errors.New("获取ETA表格信息失败,Err:" + err.Error()) if err.Error() == utils.ErrNoRow() { errMsg = "ETA表格被删除,请刷新页面" err = errors.New("ETA表格被删除,请刷新页面,Err:" + err.Error()) } return } return formatExcelInfo2Detail(excelInfo, sysUserId, lang) } func formatExcelInfo2Detail(excelInfo *excel.ExcelInfo, sysUserId int, lang string) (excelDetail response.ExcelInfoDetail, errMsg string, err error) { // 数据权限 haveOperaAuth, err := data_manage_permission.CheckExcelPermissionByExcelInfoId(excelInfo.ExcelInfoId, excelInfo.ExcelClassifyId, excelInfo.IsJoinPermission, sysUserId) if err != nil { err = errors.New("获取表格权限信息失败,Err" + err.Error()) return } excelDetail = response.ExcelInfoDetail{ ExcelInfoId: excelInfo.ExcelInfoId, Source: excelInfo.Source, ExcelType: excelInfo.ExcelType, ExcelName: excelInfo.ExcelName, UniqueCode: excelInfo.UniqueCode, ExcelClassifyId: excelInfo.ExcelClassifyId, SysUserId: excelInfo.SysUserId, SysUserRealName: excelInfo.SysUserRealName, Content: excelInfo.Content, ExcelImage: excelInfo.ExcelImage, FileUrl: excelInfo.FileUrl, Sort: excelInfo.Sort, IsDelete: excelInfo.IsDelete, ModifyTime: excelInfo.ModifyTime, CreateTime: excelInfo.CreateTime, TableData: nil, HaveOperaAuth: haveOperaAuth, } // 无权限,不需要返回数据 if !haveOperaAuth { return } switch excelInfo.Source { case utils.TIME_TABLE: // 时间序列表格 var tableDataConfig TableDataConfig err = json.Unmarshal([]byte(excelDetail.Content), &tableDataConfig) if err != nil { err = errors.New("表格json转结构体失败,Err:" + err.Error()) return } result, tmpErr := GetDataByTableDataConfig(tableDataConfig) if tmpErr != nil { err = errors.New("获取最新的表格数据失败,Err:" + tmpErr.Error()) return } if len(result.EdbInfoIdList) > 0 { classifyIdList := make([]int, 0) for _, v := range result.Data { classifyIdList = append(classifyIdList, v.ClassifyId) } classifyMap := make(map[int]*data_manage.EdbClassify) classifyList, tmpErr := data_manage.GetEdbClassifyByIdList(classifyIdList) if tmpErr != nil { err = errors.New("获取分类列表失败,Err:" + tmpErr.Error()) return } for _, v := range classifyList { classifyMap[v.ClassifyId] = v } // 获取所有有权限的指标和分类 permissionEdbIdList, permissionClassifyIdList, tmpErr := data_manage_permission.GetUserEdbAndClassifyPermissionList(sysUserId, 0, 0) if err != nil { err = errors.New("获取所有有权限的指标和分类失败,Err:" + tmpErr.Error()) return } for i, v := range result.Data { if currClassify, ok := classifyMap[v.ClassifyId]; ok { result.Data[i].HaveOperaAuth = data_manage_permission.CheckEdbPermissionByPermissionIdList(v.IsJoinPermission, currClassify.IsJoinPermission, v.EdbInfoId, v.ClassifyId, permissionEdbIdList, permissionClassifyIdList) } } } excelDetail.TableData = result case utils.MIXED_TABLE: // 混合表格 var result request.MixedTableReq err = json.Unmarshal([]byte(excelDetail.Content), &result) if err != nil { err = errors.New("表格json转结构体失败,Err:" + err.Error()) return } newData, tmpErr, tmpErrMsg := GetMixedTableCellData(result, lang) if tmpErr != nil { errMsg = "获取失败" if tmpErrMsg != `` { errMsg = tmpErrMsg } err = errors.New("获取最新的数据失败,Err:" + tmpErr.Error()) return } result.Data = newData excelDetail.TableData = result } return } // GetExcelInfoOpButton 获取ETA表格的操作权限 func GetExcelInfoOpButton(sysUser *system.Admin, belongUserId, source int, haveOperaAuth bool) (button response.ExcelInfoDetailButton) { // 如果没有数据权限,那么直接返回 if !haveOperaAuth { return } //非管理员角色查看其他用户创建的表格,可刷新、另存为、下载表格; button.RefreshButton = true button.CopyButton = true button.DownloadButton = true // 1、本用户创建的表格,可编辑、刷新、另存为、下载、删除,删除需二次确认; // 2、管理员角色对所有表格有如上权限; // 3、在线excel所有人都能编辑 if sysUser.RoleTypeCode == utils.ROLE_TYPE_CODE_ADMIN || sysUser.RoleTypeCode == utils.ROLE_TYPE_CODE_FICC_ADMIN || sysUser.AdminId == belongUserId || source == utils.EXCEL_DEFAULT { button.OpButton = true button.DeleteButton = true } // 自定义分析 if source == utils.CUSTOM_ANALYSIS_TABLE { if sysUser.RoleTypeCode == utils.ROLE_TYPE_CODE_ADMIN || sysUser.RoleTypeCode == utils.ROLE_TYPE_CODE_FICC_ADMIN || sysUser.AdminId == belongUserId { button.OpEdbButton = true // 生成、查看指标按钮 button.RefreshEdbButton = true // 刷新指标按钮 } } return } // GetFirstEdbDataList 获取第一列的数据 func GetFirstEdbDataList(edbInfo *data_manage.EdbInfo, num int, manualDateList []string) (resultDataList []request.ManualDataReq, err error) { var dataList []*data_manage.EdbDataList switch edbInfo.EdbInfoType { case 0: dataList, err = data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfo.EdbInfoId, ``, ``) case 1: _, dataList, _, _, err, _ = data.GetPredictDataListByPredictEdbInfoId(edbInfo.EdbInfoId, ``, ``, false) default: err = errors.New(fmt.Sprint("获取失败,指标类型异常", edbInfo.EdbInfoType)) } if err != nil { return } // 获取需要的期数 lenData := len(dataList) if lenData <= 0 { return } tmpManualDateNum := 0 // 手工数据的期数 lenManualDate := len(manualDateList) if lenManualDate > 0 { sortDateList := manualDateList baseDateList := utils.StrArr{} baseDateList = append(baseDateList, sortDateList...) sort.Sort(baseDateList) sortDateList = append([]string{}, baseDateList...) lastData := dataList[lenData-1] lastDataDate, tmpErr := time.ParseInLocation(utils.FormatDate, lastData.DataTime, time.Local) if tmpErr != nil { err = tmpErr return } // 遍历倒序后的日期,然后匹配在实际数据之后日期的个数 for _, tmpDateStr := range sortDateList { tmpDate, tmpErr := time.ParseInLocation(utils.FormatDate, tmpDateStr, time.Local) if tmpErr != nil { err = tmpErr return } if tmpDate.After(lastDataDate) { tmpManualDateNum++ continue } break } } // 需要的期数减去手工数据的期数,这才是A列指标需要的数据 num = num - tmpManualDateNum if num > lenData { num = lenData } latestDateTime, _ := time.ParseInLocation(utils.FormatDate, edbInfo.LatestDate, time.Local) for i := 1; i <= num; i++ { dataTime, _ := time.ParseInLocation(utils.FormatDate, dataList[lenData-i].DataTime, time.Local) dataType := 1 // 如果是预测指标,且当前值的日期,晚于实际日期,那么是预测值 if edbInfo.EdbInfoType == 1 && dataTime.After(latestDateTime) { dataType = 5 } resultDataList = append(resultDataList, request.ManualDataReq{ DataType: dataType, DataTime: dataList[lenData-i].DataTime, ShowValue: fmt.Sprint(dataList[lenData-i].Value), Value: fmt.Sprint(dataList[lenData-i].Value), DataTimeType: 1, }) } return } // GetOtherEdbDataList 获取其他列的数据 func GetOtherEdbDataList(edbInfo *data_manage.EdbInfo, dateList []string) (resultDataList []request.ManualDataReq, err error) { lenDate := len(dateList) if lenDate <= 0 { return } sortDateList := dateList baseDateList := utils.StrArr{} baseDateList = append(baseDateList, sortDateList...) sort.Sort(baseDateList) sortDateList = append([]string{}, baseDateList...) endDateTime, err := time.ParseInLocation(utils.FormatDate, sortDateList[0], time.Local) if err != nil { return } firstDateTime, err := time.ParseInLocation(utils.FormatDate, sortDateList[lenDate-1], time.Local) if err != nil { return } var dataList []*data_manage.EdbDataList switch edbInfo.EdbInfoType { case 0: dataList, err = data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfo.EdbInfoId, ``, ``) case 1: _, dataList, _, _, err, _ = data.GetPredictDataListByPredictEdbInfoId(edbInfo.EdbInfoId, ``, ``, false) default: err = errors.New(fmt.Sprint("获取失败,指标类型异常", edbInfo.EdbInfoType)) } if err != nil { return } // 获取日期内的数据(包含开始日期前一个日期,以及 结束日期后一个日期,目的为了做空日期时的 插值法兼容) baseDataList := make([]*data_manage.EdbDataList, 0) var lastData *data_manage.EdbDataList var isInsert bool for _, data := range dataList { tmpDate := data.DataTime tmpDateTime, tmpErr := time.ParseInLocation(utils.FormatDate, tmpDate, time.Local) if tmpErr != nil { err = tmpErr return } if tmpDateTime.Before(firstDateTime) { lastData = data continue } // 如果是第一次写入数据 if !isInsert && lastData != nil { baseDataList = append(baseDataList, lastData) } if tmpDateTime.After(endDateTime) { baseDataList = append(baseDataList, data) break } baseDataList = append(baseDataList, data) isInsert = true } // 实际数据的日期map realValMap := make(map[string]string) for _, v := range baseDataList { realValMap[v.DataTime] = v.DataTime } // 插值法处理 handleDataMap := make(map[string]float64) err = data.HandleDataByLinearRegression(baseDataList, handleDataMap) if err != nil { return } latestDateTime, _ := time.ParseInLocation(utils.FormatDate, edbInfo.LatestDate, time.Local) // 对于不存在的数据做补充 for _, date := range sortDateList { dataType := 1 if _, ok := realValMap[date]; !ok { dataType = 2 } else { dataTime, _ := time.ParseInLocation(utils.FormatDate, date, time.Local) // 如果是预测指标,且当前值的日期,晚于实际日期,那么是预测值 if edbInfo.EdbInfoType == 1 && dataTime.After(latestDateTime) { dataType = 5 } } var value, showValue string if tmpVal, ok := handleDataMap[date]; ok { value = fmt.Sprint(tmpVal) showValue = value } else { dataType = 3 } resultDataList = append(resultDataList, request.ManualDataReq{ DataType: dataType, DataTime: date, ShowValue: showValue, Value: value, }) } return } // GetFirstHistoryEdbDataList 获取指标的历史的数据 func GetFirstHistoryEdbDataList(edbInfo *data_manage.EdbInfo, num int, endDate string) (resultDataList []request.ManualDataReq, err error) { endDateTime, err := time.ParseInLocation(utils.FormatDate, endDate, time.Local) if err != nil { return } var dataList []*data_manage.EdbDataList switch edbInfo.EdbInfoType { case 0: dataList, err = data_manage.GetEdbDataList(edbInfo.Source, edbInfo.SubSource, edbInfo.EdbInfoId, ``, endDate) case 1: _, dataList, _, _, err, _ = data.GetPredictDataListByPredictEdbInfoId(edbInfo.EdbInfoId, ``, endDate, true) default: err = errors.New(fmt.Sprint("获取失败,指标类型异常", edbInfo.EdbInfoType)) } if err != nil { return } // 获取需要的期数 lenData := len(dataList) if lenData <= 0 { return } lastData := dataList[lenData-1] lastDataDateTime, err := time.ParseInLocation(utils.FormatDate, lastData.DataTime, time.Local) if err != nil { return } if endDateTime.Equal(lastDataDateTime) || lastDataDateTime.After(endDateTime) { dataList = dataList[:lenData-1] lenData = len(dataList) } if num > lenData { num = lenData } latestDateTime, _ := time.ParseInLocation(utils.FormatDate, edbInfo.LatestDate, time.Local) for i := 1; i <= num; i++ { dataTime, _ := time.ParseInLocation(utils.FormatDate, dataList[lenData-i].DataTime, time.Local) dataType := 1 // 如果是预测指标,且当前值的日期,晚于实际日期,那么是预测值 if edbInfo.EdbInfoType == 1 && dataTime.After(latestDateTime) { dataType = 5 } resultDataList = append(resultDataList, request.ManualDataReq{ DataType: dataType, DataTime: dataList[lenData-i].DataTime, ShowValue: fmt.Sprint(dataList[lenData-i].Value), Value: fmt.Sprint(dataList[lenData-i].Value), }) } return } // GetEdbIdsFromExcelCodes 获取表格中的指标IDs func GetEdbIdsFromExcelCodes(excelCodes []string, sysUserId int, lang string) (edbIds []int, err error) { edbIds = make([]int, 0) edbIdExist := make(map[int]bool) for _, v := range excelCodes { // 表格详情 detail, msg, e := GetExcelDetailInfoByUnicode(v, sysUserId, lang) if e != nil { err = fmt.Errorf("GetExcelDetailInfoByExcelInfoId err: %s, errMsg: %s", e.Error(), msg) return } // 自定义表格 if detail.Source == utils.TIME_TABLE { jsonByte, e := json.Marshal(detail.TableData) if e != nil { err = fmt.Errorf("JSON格式化自定义表格数据失败, Err: %s", e.Error()) return } var tableData request.TableDataReq if e = json.Unmarshal(jsonByte, &tableData); e != nil { err = fmt.Errorf("解析自定义表格数据失败, Err: %s", e.Error()) return } for _, tv := range tableData.EdbInfoIdList { if edbIdExist[tv] { continue } edbIdExist[tv] = true edbIds = append(edbIds, tv) } } // 混合表格 if detail.Source == utils.MIXED_TABLE { jsonByte, e := json.Marshal(detail.TableData) if e != nil { err = fmt.Errorf("JSON格式化混合表格数据失败, Err: %s", e.Error()) return } var tableData request.MixedTableReq if e = json.Unmarshal(jsonByte, &tableData); e != nil { err = fmt.Errorf("解析混合表格数据失败, Err: %s", e.Error()) return } if len(tableData.Data) > 0 { for _, td := range tableData.Data { for _, tv := range td { if tv.EdbInfoId > 0 && !edbIdExist[tv.EdbInfoId] { edbIdExist[tv.EdbInfoId] = true edbIds = append(edbIds, tv.EdbInfoId) } } } } } } return } // GetExcelEdbBatchRefreshKey 获取批量刷新表格指标缓存key func GetExcelEdbBatchRefreshKey(source string, reportId, chapterId int) string { if source == `` { return `` } return fmt.Sprint("batch_refresh_excel_edb:", source, ":", reportId, ":", chapterId) } // ReplaceEdbInExcel 替换表格中的指标 func ReplaceEdbInExcel(oldEdbInfo, newEdbInfo *data_manage.EdbInfo) (err error) { //查询和指标相关的 表格 mappingList, err := excel.GetExcelEdbMappingByEdbInfoId(oldEdbInfo.EdbInfoId) if err != nil { err = fmt.Errorf("查询和指标相关的表格失败,错误:%s", err.Error()) return } updateList := make([]*excel.ExcelInfo, 0) // 循环列表,根据表格类型单独处理 for _, excelMapping := range mappingList { //查询和指标相关的混合表格 excelInfo, tmpErr := excel.GetExcelInfoById(excelMapping.ExcelInfoId) if tmpErr != nil { err = fmt.Errorf("查询和指标相关的混合表格失败,错误:%s", tmpErr.Error()) return } // 清除缓存 key := utils.HZ_CHART_LIB_EXCEL_TABLE_DETAIL + ":" + excelInfo.UniqueCode if utils.Re == nil { _ = utils.Rc.Delete(key) } // 根据表格类型,调用不同的处理函数 switch excelMapping.Source { case utils.TIME_TABLE: // 时间序列表格 // 替换余额表格中的指标 newExcelInfo, e := replaceEdbInTimeExcel(oldEdbInfo, newEdbInfo, excelInfo) if e != nil { err = fmt.Errorf("替换余额表格中的指标失败,错误:%s", e.Error()) return } updateList = append(updateList, newExcelInfo) case utils.MIXED_TABLE: // 替换余额表格中的指标 newExcelInfo, e := replaceEdbInBalanceExcel(oldEdbInfo, newEdbInfo, excelInfo) if e != nil { err = fmt.Errorf("替换余额表格中的指标失败,错误:%s", e.Error()) return } updateList = append(updateList, newExcelInfo) default: // 其他表格类型的处理逻辑 } } err = excel.ReplaceEdbInExcel(oldEdbInfo.EdbInfoId, newEdbInfo.EdbInfoId, updateList) if err != nil { err = fmt.Errorf("替换表格中的指标失败,错误:%s", err.Error()) return } //todo 是否需要刷新表格中的指标数据 return } func replaceEdbInBalanceExcel(oldEdbInfo, newEdbInfo *data_manage.EdbInfo, excelInfo *excel.ExcelInfo) (newExcelInfo *excel.ExcelInfo, err error) { newExcelInfo = excelInfo var mixedTableReq request.MixedTableReq err = json.Unmarshal([]byte(excelInfo.Content), &mixedTableReq) if err != nil { err = fmt.Errorf("表格json转结构体失败,Err:" + err.Error()) return } // 处理data configList := mixedTableReq.Data for ck, rowList := range configList { for rk, cell := range rowList { switch cell.DataType { case request.EdbDT: // 指标信息 if cell.EdbInfoId == oldEdbInfo.EdbInfoId { //更换成新指标ID configList[ck][rk].EdbInfoId = newEdbInfo.EdbInfoId } case request.InsertDataDT, request.PopInsertDataDT: // 插值、弹框插值 if cell.EdbInfoId == oldEdbInfo.EdbInfoId { //更换成新指标ID configList[ck][rk].EdbInfoId = newEdbInfo.EdbInfoId } case request.InsertEdbCalculateDataDT: // 插入指标计算公式生成的值 var config request.CalculateConf err = json.Unmarshal([]byte(cell.Value), &config) if err != nil { return } if cell.EdbInfoId == oldEdbInfo.EdbInfoId { //更换成新指标ID configList[ck][rk].EdbInfoId = newEdbInfo.EdbInfoId } if config.EdbInfoId == oldEdbInfo.EdbInfoId { config.EdbInfoId = newEdbInfo.EdbInfoId } var configStr []byte configStr, err = json.Marshal(config) if err != nil { return } configList[ck][rk].Value = string(configStr) case request.DateDT: // 日期类型 // 指标日期类型的单元格需要额外将指标id取出来 if cell.DataTimeType == request.EdbDateDT { var config request.EdbDateConf err = json.Unmarshal([]byte(cell.Value), &config) if err != nil { return } if config.EdbInfoId == oldEdbInfo.EdbInfoId { config.EdbInfoId = newEdbInfo.EdbInfoId var configStr []byte configStr, err = json.Marshal(config) if err != nil { return } configList[ck][rk].Value = string(configStr) } } } } } mixedTableReq.Data = configList var newContentByte []byte newContentByte, err = json.Marshal(mixedTableReq) if err != nil { return } // 生成的新内容替换原先的旧内容 excelInfo.Content = string(newContentByte) newExcelInfo = excelInfo return } func replaceEdbInTimeExcel(oldEdbInfo, newEdbInfo *data_manage.EdbInfo, excelInfo *excel.ExcelInfo) (newExcelInfo *excel.ExcelInfo, err error) { newExcelInfo = excelInfo var tableDataConfig TableDataConfig err = json.Unmarshal([]byte(excelInfo.Content), &tableDataConfig) if err != nil { err = errors.New("表格json转结构体失败,Err:" + err.Error()) return } if len(tableDataConfig.EdbInfoIdList) <= 0 { return } // 实际期数没有的情况下,直接返回吧 if tableDataConfig.Num <= 0 { return } // 先处理edbInfoList for k, id := range tableDataConfig.EdbInfoIdList { if id == oldEdbInfo.EdbInfoId { tableDataConfig.EdbInfoIdList[k] = newEdbInfo.EdbInfoId } } // 先处理tableEdbInfoList for k, tableEdbInfo := range tableDataConfig.TableEdbInfoList { if tableEdbInfo.EdbInfoId == oldEdbInfo.EdbInfoId { tableDataConfig.TableEdbInfoList[k].EdbInfoId = newEdbInfo.EdbInfoId } } var newContentByte []byte newContentByte, err = json.Marshal(tableDataConfig) if err != nil { return } // 生成的新内容替换原先的旧内容 excelInfo.Content = string(newContentByte) newExcelInfo = excelInfo return }