Ver Fonte

区间分析保存指标

xyxie há 7 meses atrás
pai
commit
a7dc2f0a23

+ 153 - 116
controllers/data_manage/range_analysis/chart_info.go

@@ -1241,7 +1241,7 @@ func (this *RangeChartChartInfoController) Refresh() {
 // @Success Ret=200 返回指标id
 // @router /edb/save [post]
 func (this *RangeChartChartInfoController) MultipleGraphConfigSaveEdb() {
-	/*br := new(models.BaseResponse).Init()
+	br := new(models.BaseResponse).Init()
 	defer func() {
 		this.Data["json"] = br
 		this.ServeJSON()
@@ -1273,7 +1273,7 @@ func (this *RangeChartChartInfoController) MultipleGraphConfigSaveEdb() {
 	}()
 	edbInfoIds := make([]int, 0)
 	for _, v := range req.EdbInfoList {
-		edbInfoIds = append(edbInfoIds, v.EdbInfoId)
+		edbInfoIds = append(edbInfoIds, v.FromEdbInfoId)
 	}
 	mappingList, err := data_manage.GetChartEdbMappingListByEdbInfoIdList(edbInfoIds)
 	if err != nil {
@@ -1287,32 +1287,40 @@ func (this *RangeChartChartInfoController) MultipleGraphConfigSaveEdb() {
 	}
 
 	for _, v := range req.EdbInfoList {
-		if _, ok := edbInfoMap[v.EdbInfoId]; !ok {
+		if _, ok := edbInfoMap[v.FromEdbInfoId]; !ok {
 			br.Msg = "指标信息不存在"
-			br.ErrMsg = "指标信息不存在,EdbInfoId:" + strconv.Itoa(v.EdbInfoId)
+			br.ErrMsg = "指标信息不存在,EdbInfoId:" + strconv.Itoa(v.FromEdbInfoId)
 			br.IsSendEmail = false
 			return
 		}
 	}
-
+	// 区间计算图表配置校验
+	var extraConfig string
+	extraConfigByte, err := json.Marshal(req.ExtraConfig)
+	if err != nil {
+		br.Msg = "配置信息错误"
+		br.ErrMsg = "配置信息错误, Err: " + err.Error()
+		return
+	}
+	extraConfig = string(extraConfigByte)
 	// todo 校验配置合法性
-	multipleGraphConfigEdbMappingList, err := data_manage.GetMultipleGraphConfigEdbMappingListByIdAndSource(req.MultipleGraphConfigId, 10)
+	multipleGraphConfigEdbMappingList, err := data_manage.GetMultipleGraphConfigEdbMappingListByIdAndSource(req.MultipleGraphConfigId, utils.CHART_SOURCE_RANGE_ANALYSIS)
 	if err != nil {
 		br.Msg = `保存失败`
 		br.ErrMsg = "查询配置与图表的关联关系失败,ERR:" + err.Error()
 		return
 	}
-	var edbInfoId int
-	addEdbInfoIds := make([]int, 0)
-	updateEdbInfoIds := make([]int, 0)
-	deleteEdbInfoIds := make([]int, 0)
-	if len(multipleGraphConfigEdbMappingList) == 0 {
+	deleteEdbInfoIds := make([]int, 0) // 需要解除绑定的指标ID
+	fromEdbMap := make(map[int]int)
+	configMapping := make(map[int]*data_manage.MultipleGraphConfigEdbMapping, 0)
+	if len(multipleGraphConfigEdbMappingList) == 0 || req.IsSaveAs {
 		// 需要新增的指标
 	} else {
 		// 需要更新的指标
 		// 查询原先所有指标的来源指标,进一步筛选出需要新增,或者更新 或者删除的指标
 		oldEdbInfoIds := make([]int, 0)
 		for _, v := range multipleGraphConfigEdbMappingList {
+			configMapping[v.EdbInfoId] = v
 			oldEdbInfoIds = append(oldEdbInfoIds, v.EdbInfoId)
 		}
 
@@ -1324,140 +1332,170 @@ func (this *RangeChartChartInfoController) MultipleGraphConfigSaveEdb() {
 		}
 
 		// 说明指标还在,没有被删除
-		oldFromEdbInfoIds := make([]int, 0)
 		for _, v := range oldEdbCalculateMappingList {
+			fromEdbMap[v.FromEdbInfoId] = v.EdbInfoId
 			if !utils.InArrayByInt(edbInfoIds, v.FromEdbInfoId) {
 				deleteEdbInfoIds = append(deleteEdbInfoIds, v.EdbInfoId)
 			}
-			oldFromEdbInfoIds = append(oldFromEdbInfoIds, v.FromEdbInfoId)
 		}
 	}
-
-	// 关联指标
-	edbInfoIdArr := []data_manage.EdbInfoFromTag{
-		{
-			EdbInfoId: edbInfoMappingA.EdbInfoId,
-			FromTag:   "A",
-			MoveValue: 0,
-		}, {
-			EdbInfoId: edbInfoMappingB.EdbInfoId,
-			FromTag:   "B",
-			MoveValue: 0,
-		},
-	}
-
-	calculateFormula := request.EdbCalculateFormula{
-		BaseCalculateValue: correlationConf.CalculateValue,
-		BaseCalculateUnit:  correlationConf.CalculateUnit,
-		LeadValue:          rollingCorrelation.LeadValue,
-		LeadUnit:           rollingCorrelation.LeadUnit,
-		CalculateValue:     rollingCorrelation.CalculateValue,
-		CalculateUnit:      rollingCorrelation.CalculateUnit,
-	}
-	calculateFormulaByte, err := json.Marshal(calculateFormula)
-	if err != nil {
-		br.Msg = "参数解析异常!"
-		br.ErrMsg = "参数解析失败,Err:" + err.Error()
-		return
+	resp := data_manage.BatchEdbInfoCalculateBatchSaveResp{
+		Fail:    make([]data_manage.BatchEdbInfoCalculateBatchSaveFailResp, 0),
+		Success: make([]data_manage.BatchEdbInfoCalculateBatchSaveSuccessResp, 0),
 	}
+	// 普通指标批量新增\批量编辑
+	var saveReq data_manage.BatchEdbInfoCalculateBatchSaveReq
+	calculateEdbList := make([]data_manage.BatchEdbInfoCalculateBatchSaveSuccessResp, 0)
+	reqEdbList := make([]*data_manage.CalculateEdbInfoItem, 0)
+	for _, v := range req.EdbInfoList {
+		if edbInfoId, ok := fromEdbMap[v.EdbInfoId]; ok {
+			v.EdbInfoId = edbInfoId
+		}
+		v.CalculateId = strconv.Itoa(v.FromEdbInfoId)
+		v.EdbName = strings.Trim(v.EdbName, " ")
+		if v.EdbName == "" {
+			resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
+				CalculateId: v.CalculateId,
+				Msg:         "指标名称不能为空",
+			})
+			continue
+		}
 
-	var respItem *data.AddPredictEdbDataResponse
-	if edbInfoId <= 0 || req.IsSaveAs {
-		req2 := &data_manage.EdbInfoCalculateBatchSaveReqByEdbLib{
-			AdminId:      sysUser.AdminId,
-			AdminName:    sysUser.RealName,
-			EdbName:      req.EdbName,
-			Frequency:    req.Frequency,
-			Unit:         req.Unit,
-			ClassifyId:   req.ClassifyId,
-			Formula:      string(calculateFormulaByte),
-			Source:       utils.DATA_SOURCE_CALCULATE_CORRELATION,
-			EdbInfoIdArr: edbInfoIdArr,
-			Calendar:     `公历`,
+		if v.Frequency == "" {
+			resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
+				CalculateId: v.CalculateId,
+				Msg:         "频率不能为空",
+			})
+			continue
 		}
 
-		// 调用指标库去添加
-		reqJson, err := json.Marshal(req2)
-		if err != nil {
-			br.Msg = "参数解析异常!"
-			br.ErrMsg = "参数解析失败,Err:" + err.Error()
-			return
+		if v.Unit == "" {
+			resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
+				CalculateId: v.CalculateId,
+				Msg:         "单位不能为空",
+			})
+			continue
 		}
-		respItem, err = data.BatchSaveEdbCalculateData(string(reqJson), this.Lang)
-		if err != nil {
-			br.Msg = "新增失败"
-			br.ErrMsg = "新增失败,Err:" + err.Error()
-			return
+
+		if v.ClassifyId <= 0 {
+			resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
+				CalculateId: v.CalculateId,
+				Msg:         "请选择分类",
+			})
+			continue
 		}
-	} else {
-		req2 := &data_manage.EdbInfoCalculateBatchEditReqByEdbLib{
-			EdbInfoId:    edbInfoId,
-			EdbName:      req.EdbName,
-			Frequency:    req.Frequency,
-			Unit:         req.Unit,
-			ClassifyId:   req.ClassifyId,
-			Formula:      string(calculateFormulaByte),
-			Source:       utils.DATA_SOURCE_CALCULATE_CORRELATION,
-			EdbInfoIdArr: edbInfoIdArr,
-			Calendar:     `公历`,
+
+		//加入缓存机制,避免创建同一个名称的指标 start
+		redisKey := fmt.Sprint("edb_info:calculate:batch:save:", utils.DATA_SOURCE_CALCULATE_RANGEANLYSIS, ":", v.EdbName)
+		//加入缓存机制,避免创建同一个名称的指标 start
+		if req.EdbInfoType == 1 {
+			redisKey = fmt.Sprint("predict_edb_info:calculate:batch:save:", sysUser.AdminId, ":", utils.DATA_SOURCE_CALCULATE_RANGEANLYSIS, ":", v.CalculateId)
 		}
+		isExist := utils.Rc.IsExist(redisKey)
+		if isExist {
+			resp.Fail = append(resp.Fail, data_manage.BatchEdbInfoCalculateBatchSaveFailResp{
+				CalculateId: strconv.Itoa(v.FromEdbInfoId),
+				Msg:         "指标正在处理,请勿重复提交",
+			})
+			continue
+		} else {
+		}
+		reqEdbList = append(reqEdbList, v)
+	}
 
+	if req.EdbInfoType == 0 { //普通指标
+		if len(reqEdbList) <= 0 {
+			br.Msg = "新增失败!"
+			if len(resp.Fail) > 0 {
+				br.ErrMsg = resp.Fail[0].Msg
+			} else {
+				br.Msg = "请选择指标"
+			}
+			return
+		}
+		saveReq.Source = utils.DATA_SOURCE_CALCULATE_RANGEANLYSIS
+		saveReq.CalculateFormula = extraConfig
+		saveReq.AdminId = sysUser.AdminId
+		saveReq.AdminName = sysUser.RealName
+		saveReq.EdbList = reqEdbList
 		// 调用指标库去更新
-		reqJson, err := json.Marshal(req2)
+		reqJson, err := json.Marshal(saveReq)
 		if err != nil {
 			br.Msg = "参数解析异常!"
 			br.ErrMsg = "参数解析失败,Err:" + err.Error()
 			return
 		}
-		respItem, err = data.BatchEditEdbCalculateData(string(reqJson), this.Lang)
+		respItem, err := data.BatchSaveEdbCalculateMultiData(string(reqJson), this.Lang)
 		if err != nil {
-			br.Msg = "编辑失败"
-			br.ErrMsg = "编辑失败,Err:" + err.Error()
+			br.Msg = "新增失败!"
+			br.ErrMsg = "新增失败,Err:" + err.Error()
 			return
 		}
-	}
-	if respItem == nil {
-		br.Msg = "保存失败"
-		br.ErrMsg = "保存失败"
-		return
-	}
-	if respItem.Ret != 200 {
-		br.Msg = respItem.Msg
-		br.ErrMsg = respItem.ErrMsg
-		return
+		if respItem.Ret != 200 {
+			br.Msg = respItem.Msg
+			br.ErrMsg = respItem.ErrMsg
+			return
+		}
+		calculateEdbList = respItem.Data.Success
+	} else if req.EdbInfoType == 1 {
+		// 预测指标
+		for _, v := range req.EdbInfoList {
+			predictReq := new(data_manage.PredictEdbInfoCalculateBatchSaveReq)
+			predictReq.EdbInfoId = v.EdbInfoId
+			predictReq.CalculateFormula = extraConfig
+			predictReq.EdbName = v.EdbName
+			predictReq.Frequency = v.Frequency
+			predictReq.Unit = v.Unit
+			predictReq.ClassifyId = v.ClassifyId
+			predictReq.FromEdbInfoId = v.FromEdbInfoId
+			predictReq.AdminId = sysUser.AdminId
+			predictReq.AdminName = sysUser.RealName
+			//todo 新增预测指标的区间计算指标
+		}
 	}
 
-	resp := respItem.Data
-
-	//添加es
-	data.AddOrEditEdbInfoToEs(resp.EdbInfoId)
+	// 批量删除
+	if len(deleteEdbInfoIds) > 0 {
+		err = data_manage.DeleteMultipleGraphConfigEdbMappingByEdbIds(req.MultipleGraphConfigId, utils.CHART_SOURCE_RANGE_ANALYSIS, deleteEdbInfoIds)
+		if err != nil {
+			br.Msg = "更新失败!"
+			br.ErrMsg = "删除失败,Err:" + err.Error()
+			return
+		}
+	}
 
 	// 如果不是另存为的话,那么需要建立配置与指标的关系
 	if !req.IsSaveAs {
 		// 如果指标没有建立关联关系,那么就需要添加关系
-		if isAdd {
-			multipleGraphConfigEdbMapping = &data_manage.MultipleGraphConfigEdbMapping{
-				//Id:                    0,
-				MultipleGraphConfigId: req.MultipleGraphConfigId,
-				EdbInfoId:             resp.EdbInfoId,
-				Source:                req.Source,
-				ModifyTime:            time.Now(),
-				CreateTime:            time.Now(),
-			}
-			err = data_manage.AddMultipleGraphConfigEdbMapping(multipleGraphConfigEdbMapping)
-			if err != nil {
-				br.Msg = "保存失败"
-				br.ErrMsg = "保存配置与指标的关联关系失败,ERR:" + err.Error()
-				return
+		configEdbMappingList := make([]*data_manage.MultipleGraphConfigEdbMapping, 0)
+		for _, v := range calculateEdbList {
+			item, ok := configMapping[v.EdbInfoId]
+			if !ok {
+				multipleGraphConfigEdbMapping := &data_manage.MultipleGraphConfigEdbMapping{
+					//Id:                    0,
+					MultipleGraphConfigId: req.MultipleGraphConfigId,
+					EdbInfoId:             v.EdbInfoId,
+					Source:                utils.CHART_SOURCE_RANGE_ANALYSIS,
+					ModifyTime:            time.Now(),
+					CreateTime:            time.Now(),
+				}
+				configEdbMappingList = append(configEdbMappingList, multipleGraphConfigEdbMapping)
+			} else {
+				item.ModifyTime = time.Now()
+				err = item.Update([]string{"ModifyTime"})
+				if err != nil {
+					br.Msg = "保存失败"
+					br.ErrMsg = "保存配置与指标的关联关系失败,ERR:" + err.Error()
+					return
+				}
 			}
-		} else if multipleGraphConfigEdbMapping != nil {
-			multipleGraphConfigEdbMapping.EdbInfoId = resp.EdbInfoId
-			multipleGraphConfigEdbMapping.ModifyTime = time.Now()
-			err = multipleGraphConfigEdbMapping.Update([]string{"EdbInfoId", "ModifyTime"})
-			if err != nil {
-				br.Msg = "保存失败"
-				br.ErrMsg = "保存配置与指标的关联关系失败,ERR:" + err.Error()
-				return
+			if len(configEdbMappingList) > 0 {
+				err = data_manage.AddMultipleGraphConfigEdbMappingList(configEdbMappingList)
+				if err != nil {
+					br.Msg = "保存失败"
+					br.ErrMsg = "保存配置与指标的关联关系失败,ERR:" + err.Error()
+					return
+				}
 			}
 		}
 	}
@@ -1467,5 +1505,4 @@ func (this *RangeChartChartInfoController) MultipleGraphConfigSaveEdb() {
 	br.Msg = "保存成功"
 	br.Data = resp
 	br.IsAddLog = true
-	*/
 }

+ 4 - 2
models/data_manage/chart_info_range_analysis.go

@@ -90,7 +90,8 @@ func (a ChartRangeAnalysisManualDateConfList) Less(i, j int) bool {
 
 type ChartRangeAnalysisDataResp struct { //图表详情返回值
 	*ChartRangeAnalysisExtraConf
-	SeriesId int `description:"指标系列ID"`
+	SeriesId              int `description:"指标系列ID"`
+	MultipleGraphConfigId int `description:"配置ID"`
 }
 
 type ChartRangeAnalysisDateDataItem struct {
@@ -286,8 +287,9 @@ func EditRangeChartInfoAndMapping(req *EditChartInfoReq, edbInfoIdStr, lang stri
 
 // SaveChartRangeAnalysisEdbReq 指标保存请求
 type SaveChartRangeAnalysisEdbReq struct {
-	EdbInfoList           []*EdbInfoBase `description:"指标列表"`
+	EdbInfoList           []*CalculateEdbInfoItem `description:"指标列表"`
 	ExtraConfig           ChartRangeAnalysisExtraConf
 	MultipleGraphConfigId int  `description:"配置id"`
 	IsSaveAs              bool `description:"是否另存为,true的话,就是另存为,不会建立与配置的关系"`
+	EdbInfoType           int  `description:"指标类型"`
 }

+ 15 - 0
models/data_manage/multiple_graph_config_edb_mapping.go

@@ -1,6 +1,7 @@
 package data_manage
 
 import (
+	"eta/eta_api/utils"
 	"github.com/beego/beego/v2/client/orm"
 	"time"
 )
@@ -59,3 +60,17 @@ func GetMultipleGraphConfigEdbMappingListByIdAndSource(configId, source int) (it
 
 	return
 }
+
+// AddMultipleGraphConfigEdbMappingList 新增多图配置
+func AddMultipleGraphConfigEdbMappingList(items []*MultipleGraphConfigEdbMapping) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	_, err = o.InsertMulti(len(items), items)
+	return
+}
+
+func DeleteMultipleGraphConfigEdbMappingByEdbIds(configId, source int, edbIds []int) (err error) {
+	o := orm.NewOrmUsingDB("data")
+	sql := `DELETE FROM multiple_graph_config_edb_mapping WHERE multiple_graph_config_id = ? AND source = ? AND edb_id IN (` + utils.GetOrmInReplace(len(edbIds)) + `) `
+	_, err = o.Raw(sql, configId, source, edbIds).Exec()
+	return
+}

+ 9 - 0
routers/commentsRouter.go

@@ -1915,6 +1915,15 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/range_analysis:RangeChartChartInfoController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/range_analysis:RangeChartChartInfoController"],
+        beego.ControllerComments{
+            Method: "MultipleGraphConfigSaveEdb",
+            Router: `/edb/save`,
+            AllowHTTPMethods: []string{"post"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/range_analysis:RangeChartClassifyController"] = append(beego.GlobalControllerRouter["eta/eta_api/controllers/data_manage/range_analysis:RangeChartClassifyController"],
         beego.ControllerComments{
             Method: "AddChartClassify",

+ 48 - 7
services/data/range_analysis/chart_info.go

@@ -302,6 +302,15 @@ func GetChartDataByEdbInfoList(chartInfoId int, dateType, startYear int, startDa
 		}
 	}
 	dataResp = data_manage.ChartRangeAnalysisDataResp{ChartRangeAnalysisExtraConf: req}
+	// 查询配置关联关系
+	if chartInfoId > 0 {
+		multipleGraphConfigChartMapping, e := data_manage.GetMultipleGraphConfigChartMappingByChartId(chartInfoId)
+		if e != nil && e.Error() != utils.ErrNoRow() {
+			err = fmt.Errorf("获取配置与图表的关联关系失败,ERR:" + e.Error())
+			return
+		}
+		dataResp.MultipleGraphConfigId = multipleGraphConfigChartMapping.MultipleGraphConfigId
+	}
 	edbList, err = GetChartEdbInfoFormat(chartInfoId, edbInfoMappingList)
 	if err != nil {
 		err = fmt.Errorf("获取区间计算图表, 完善指标信息失败, Err:" + err.Error())
@@ -407,6 +416,16 @@ func GetChartDataByEdbInfoListBySeries(chartInfoId int, dateType, startYear int,
 		}
 	}
 	dataResp = data_manage.ChartRangeAnalysisDataResp{ChartRangeAnalysisExtraConf: req, SeriesId: seriesMappingItem.FactorEdbSeriesId}
+	// 查询配置关联关系
+	if chartInfoId > 0 {
+		multipleGraphConfigChartMapping, e := data_manage.GetMultipleGraphConfigChartMappingByChartId(chartInfoId)
+		if e != nil && e.Error() != utils.ErrNoRow() {
+			err = fmt.Errorf("获取配置与图表的关联关系失败,ERR:" + e.Error())
+			return
+		}
+		dataResp.MultipleGraphConfigId = multipleGraphConfigChartMapping.MultipleGraphConfigId
+	}
+
 	edbList, err = GetChartEdbInfoFormat(chartInfoId, edbInfoMappingList)
 	if err != nil {
 		err = fmt.Errorf("获取区间计算图表, 完善指标信息失败, Err:" + err.Error())
@@ -478,12 +497,7 @@ func getChartDataByEdbInfo(edbInfoMapping *data_manage.ChartEdbInfoMapping, req
 			endDateTime, _ = time.ParseInLocation(utils.FormatDate, endDate, time.Local)
 		} else {
 			endConf := req.AutoDateConf.EndDateConf
-			endDate := ""
-			if endConf.BaseDateType == 0 { //
-				endDate = edbEndDate
-			} else if endConf.BaseDateType == 2 {
-				endDate = "2020-01-01"
-			}
+			endDate := edbEndDate
 			if endConf.MoveForward > 0 {
 				endDate = GetEdbDateByMoveForward(endConf.MoveForward, dataList)
 			}
@@ -916,7 +930,34 @@ func AddChartInfo(req data_manage.AddChartInfoReq, source int, sysUser *system.A
 		}
 		//todo 如果保存失败是否要删除
 	}
-
+	//添加配置信息
+	multipleGraphConfig := &data_manage.MultipleGraphConfig{
+		//MultipleGraphConfigId: 0,
+		SysUserId:       sysUser.AdminId,
+		SysUserRealName: sysUser.RealName,
+		ModifyTime:      time.Now(),
+		CreateTime:      time.Now(),
+	}
+	err = data_manage.AddMultipleGraphConfig(multipleGraphConfig)
+	if err != nil {
+		errMsg = "操作失败"
+		err = errors.New("新增区间计算图表配置失败, Err: " + err.Error())
+		return
+	}
+	multipleGraphConfigChartMapping := &data_manage.MultipleGraphConfigChartMapping{
+		//Id:                    0,
+		MultipleGraphConfigId: multipleGraphConfig.MultipleGraphConfigId,
+		ChartInfoId:           chartInfo.ChartInfoId,
+		Source:                utils.CHART_SOURCE_RANGE_ANALYSIS,
+		ModifyTime:            time.Now(),
+		CreateTime:            time.Now(),
+	}
+	err = data_manage.AddMultipleGraphConfigChartMapping(multipleGraphConfigChartMapping)
+	if err != nil {
+		errMsg = "操作失败"
+		err = errors.New("新增区间计算图表和配置关联关系失败, Err: " + err.Error())
+		return
+	}
 	// 添加指标引用记录
 	_ = data.SaveChartEdbInfoRelation(edbInfoIdArr, chartInfo)
 	//添加es数据

+ 1 - 0
utils/constants.go

@@ -173,6 +173,7 @@ const (
 	DATA_SOURCE_BLOOMBERG                            = 83       // bloomberg彭博数据
 	DATA_SOURCE_BUSINESS                             = 84       // 来源于自有数据
 	DATA_SOURCE_SCI99                                = 85       // 卓创资讯 -> 85
+	DATA_SOURCE_CALCULATE_RANGEANLYSIS               = 87       //区间计算->87
 )
 
 // 数据刷新频率