Browse Source

粮油商务网数据对接-数据爬取完毕

gmy 8 months ago
parent
commit
1ff39c3240
4 changed files with 791 additions and 122 deletions
  1. 174 109
      cmd/processor_business_logic.go
  2. 6 0
      cmd/processor_factory.go
  3. 489 7
      static/liangyou.json
  4. 122 6
      utils/date_util.go

+ 174 - 109
cmd/processor_business_logic.go

@@ -554,10 +554,10 @@ func (p *PurchaseShippingProcessor) Process(ctx context.Context, product string,
 	}
 
 	// 时间格式转换
-	/*format, err := utils.ConvertTimeFormat(dateText)
+	format, err := utils.ConvertTimeFormat(dateText)
 	if err != nil {
 		return []models.BaseFromLyData{}, err
-	}*/
+	}
 
 	// 处理提取的表格数据
 	var result []models.BaseFromLyData
@@ -599,6 +599,19 @@ func (p *PurchaseShippingProcessor) Process(ctx context.Context, product string,
 						return nil, err
 					}
 					yearMonth = row[0] + "-" + number
+					isSameMonth, err := utils.IsSameMonth(format, yearMonth)
+					if err != nil {
+						return nil, err
+					}
+					if isSameMonth {
+						yearMonth = format
+					} else {
+						lastDayOfMonth, err := utils.GetLastDayOfMonth(yearMonth)
+						if err != nil {
+							return nil, err
+						}
+						yearMonth = lastDayOfMonth
+					}
 
 					indexData, err := models.GetLyDataByIndexIdAndDataTime(indexId, yearMonth)
 					if err != nil {
@@ -1358,7 +1371,7 @@ func (p *ImportEstimateProcessor) Process(ctx context.Context, product string, r
 	}
 
 	// 拿到 行关键字和列关键字
-	/*var columnDates []string
+	var columnDates []string
 	rowVariety := keywords[1]
 
 	// 提取所有表格数据
@@ -1381,73 +1394,111 @@ func (p *ImportEstimateProcessor) Process(ctx context.Context, product string, r
 		return nil, err
 	}
 
+	monthsLastDay, err := utils.GetNextThreeMonthsLastDay(format)
+	if err != nil {
+		return nil, err
+	}
+
 	// 处理提取的表格数据
-	var result []models.BaseFromLyData*/
+	var result []models.BaseFromLyData
 
-	/*for _, data := range tableData {
+	for _, data := range tableData {
 		tableHeaders := data.Headers
 		tableRows := data.Rows
 
 		// 查找目标列
-		columnIdx := -1
-		for i, header := range tableHeaders {
-			if strings.Contains(header, columnName) {
-				columnIdx = i
-				break
+		for _, columnDate := range columnDates {
+
+			columnIdx := -1
+			for i, tableHeader := range tableHeaders {
+				if strings.Contains(tableHeader, columnDate) {
+					columnIdx = i
+					break
+				}
 			}
-		}
-		if columnIdx == -1 {
-			log.Printf("ImportEstimateProcessor Process() : Column '%s' not found in table", columnName)
-			continue
-		}
 
-		// 处理表格中的每一行
-		for rowIndex, row := range tableRows {
-			if len(row) >= len(tableHeaders) && strings.Contains(row[0], rowVariety) {
-				if columnIdx < len(row) {
-					// 指标名称
-					indexName := strings.Join(keywords[:len(keywords)-3], `:`)
-					// 指标编码
-					indexCode := utils.GenerateIndexCode(sourceName, indexName)
-					// 指标id获取
-					indexId, err := getIndexId(indexCode, indexName, classifyId, sourceName, keywords[len(keywords)-2], keywords[len(keywords)-1])
-					if err != nil {
-						logs.Error("ImportEstimateProcessor Process() : Failed to get index id: %v", err)
-						continue
-					}
+			if columnIdx == -1 {
+				log.Printf("ImportEstimateProcessor Process() : Column '%s' not found in table", columnDate)
+				continue
+			} else {
+				// 处理表格中的每一行
+				for _, row := range tableRows {
+					if len(row) >= len(tableHeaders) && strings.Contains(row[0], rowVariety) && isNumber(row[columnIdx]) {
+						if columnIdx < len(row) {
+							// 指标名称
+							indexName := strings.Join(keywords[:len(keywords)-2], `:`)
+							// 指标编码
+							indexCode := utils.GenerateIndexCode(sourceName, indexName)
+							// 指标id获取
+							indexId, err := getIndexId(indexCode, indexName, classifyId, sourceName, keywords[len(keywords)-2], keywords[len(keywords)-1])
+							if err != nil {
+								logs.Error("ImportEstimateProcessor Process() : Failed to get index id: %v", err)
+								continue
+							}
+							toNumber, err := utils.ConvertMonthToNumber(columnDate)
+							if err != nil {
+								logs.Error("ImportEstimateProcessor Process() : Failed to convert month to number: %v", err)
+								continue
+							}
+							slice, err := utils.GetElementInSlice(monthsLastDay, toNumber)
+							if err != nil {
+								logs.Error("ImportEstimateProcessor Process() : Failed to get element in slice: %v", err)
+								continue
+							}
 
-					indexData, err := models.GetLyDataByIndexIdAndDataTime(indexId, format)
-					if err != nil {
-						logs.Error("ImportEstimateProcessor Process() : Failed to get data by index id and date: %v", err)
-						continue
-					}
-					if len(indexData) > 0 {
-						logs.Info("ImportEstimateProcessor Process() : Data already exists for index %d and date %s", indexId, dateText)
-						continue
-					}
+							indexData, err := models.GetLyDataByIndexIdAndDataTime(indexId, slice)
+							if err != nil {
+								logs.Error("ImportEstimateProcessor Process() : Failed to get data by index id and date: %v", err)
+								continue
+							}
 
-					valueStr := row[columnIdx]
-					value, err := strconv.ParseFloat(valueStr, 64)
-					if err != nil {
-						return []models.BaseFromLyData{}, fmt.Errorf("failed to parse value '%s': %v", valueStr, err)
-					}
-					// 创建并添加到结果列表
-					baseFromLyData := models.BaseFromLyData{
-						DataTime:          format,
-						Value:             value,
-						BaseFromLyIndexId: indexId,
-						IndexCode:         indexCode,
+							valueStr := row[columnIdx]
+							value, err := strconv.ParseFloat(valueStr, 64)
+							if err != nil {
+								return []models.BaseFromLyData{}, fmt.Errorf("failed to parse value '%s': %v", valueStr, err)
+							}
+
+							if len(indexData) > 0 {
+								logs.Info("ImportEstimateProcessor Process() : Data already exists for index %d and date %s", indexId, dateText)
+								lyData := indexData[0]
+								time, err := utils.StringToTime(lyData.ModifyTime)
+								if err != nil {
+									return nil, err
+								}
+
+								timeZero, err := utils.StringToTimeZero(format)
+								if err != nil {
+									return nil, err
+								}
+
+								if lyData.Value != value && time.Before(timeZero) {
+									err := models.UpdateLyDataById(lyData.BaseFromLyDataId, value)
+									if err != nil {
+										return nil, err
+									}
+								}
+								continue
+							}
+
+							// 创建并添加到结果列表
+							baseFromLyData := models.BaseFromLyData{
+								DataTime:          slice,
+								Value:             value,
+								BaseFromLyIndexId: indexId,
+								IndexCode:         indexCode,
+							}
+							result = append(result, baseFromLyData)
+						} else {
+							log.Printf("ImportEstimateProcessor Process() : Column index out of range for row '%s', '%s'", rowVariety, columnDate)
+						}
+						break
 					}
-					result = append(result, baseFromLyData)
-				} else {
-					log.Printf("ImportEstimateProcessor Process() : Column index out of range for row '%s', '%s'", rowVariety, columnName)
 				}
-				break
 			}
 		}
-	}*/
+	}
 
-	return []models.BaseFromLyData{}, nil
+	return result, nil
 }
 
 // InternationalPriceProcessor
@@ -1677,12 +1728,12 @@ type ImportExportAnalysisProcessor struct{}
 func (p *ImportExportAnalysisProcessor) Process(ctx context.Context, product string, reportContent string, keywords []string, classifyId int) ([]models.BaseFromLyData, error) {
 	fmt.Println("Processing processing profit...")
 	// 解析关键字
-	if len(keywords) < 4 {
-		return []models.BaseFromLyData{}, fmt.Errorf("ProcessingProfitProcessor Process() : keywords must contain at least 4 elements")
+	if len(keywords) < 3 {
+		return []models.BaseFromLyData{}, fmt.Errorf("ProcessingProfitProcessor Process() : keywords must contain at least 3 elements")
 	}
 
 	// 拿到 行关键字和列关键字
-	var columnDate string
+	var columnDates []string
 	// 提取所有表格数据
 	tableData := getNoHeadTableData(reportContent)
 
@@ -1697,11 +1748,12 @@ func (p *ImportExportAnalysisProcessor) Process(ctx context.Context, product str
 	if err != nil {
 		return []models.BaseFromLyData{}, err
 	}
-	year, err := utils.GetCurrentYear(format)
+
+	// 2025年1月可能才出2024年12月的数据,所以往前取一年
+	columnDates, err = utils.GetCurrentYearAndLastYear(format)
 	if err != nil {
 		return nil, err
 	}
-	columnDate = year
 
 	// 处理提取的表格数据
 	var result []models.BaseFromLyData
@@ -1710,61 +1762,74 @@ func (p *ImportExportAnalysisProcessor) Process(ctx context.Context, product str
 		tableHeaders := data.Headers
 		tableRows := data.Rows
 
-		// 查找目标列
-		columnIdx := -1
-		for i, header := range tableHeaders {
-			if strings.Contains(header, columnDate) {
-				columnIdx = i
-				break
+		for _, columnDate := range columnDates {
+			// 查找目标列
+			columnIdx := -1
+			for i, header := range tableHeaders {
+				if strings.Contains(header, columnDate) {
+					columnIdx = i
+					break
+				}
 			}
-		}
-		if columnIdx == -1 {
-			log.Printf("ProcessingProfitProcessor Process() : Column '%s' not found in table", columnDate)
-			continue
-		}
 
-		// 处理表格中的每一行
-		for _, row := range tableRows {
-			if len(row) >= len(tableHeaders) {
-				if columnIdx < len(row) && isNumber(row[columnIdx]) {
-					// 指标名称
-					indexName := strings.Join(keywords[:len(keywords)-2], ":")
-					// 指标编码
-					indexCode := utils.GenerateIndexCode(sourceName, indexName)
-					// 指标id获取
-					indexId, err := getIndexId(indexCode, indexName, classifyId, sourceName, keywords[len(keywords)-2], keywords[len(keywords)-1])
-					if err != nil {
-						logs.Error("ProcessingProfitProcessor Process() : Failed to get index id: %v", err)
-						continue
-					}
+			if columnIdx == -1 {
+				log.Printf("ProcessingProfitProcessor Process() : Column '%s' not found in table", columnDate)
+				continue
+			}
 
-					indexData, err := models.GetLyDataByIndexIdAndDataTime(indexId, format)
-					if err != nil {
-						logs.Error("ProcessingProfitProcessor Process() : Failed to get data by index id and date: %v", err)
-						continue
-					}
-					if len(indexData) > 0 {
-						logs.Info("ProcessingProfitProcessor Process() : Data already exists for index %d and date %s", indexId, dateText)
-						continue
-					}
+			// 处理表格中的每一行
+			for _, row := range tableRows {
+				if len(row) >= len(tableHeaders) {
+					if columnIdx < len(row) && isNumber(row[columnIdx]) && isNumber(row[0]) {
+						// 指标名称
+						indexName := strings.Join(keywords[:len(keywords)-2], ":")
+						// 指标编码
+						indexCode := utils.GenerateIndexCode(sourceName, indexName)
+						// 指标id获取
+						indexId, err := getIndexId(indexCode, indexName, classifyId, sourceName, keywords[len(keywords)-2], keywords[len(keywords)-1])
+						if err != nil {
+							logs.Error("ProcessingProfitProcessor Process() : Failed to get index id: %v", err)
+							continue
+						}
+						atoi, err := strconv.Atoi(row[0])
+						if err != nil {
+							return nil, err
+						}
+						date := columnDate[:4] + "-" + fmt.Sprintf("%02d", atoi)
+						lastDayOfMonth, err := utils.GetLastDayOfMonth(date)
+						if err != nil {
+							return nil, err
+						}
 
-					valueStr := row[columnIdx]
-					value, err := strconv.ParseFloat(valueStr, 64)
-					if err != nil {
-						return []models.BaseFromLyData{}, fmt.Errorf("failed to parse value '%s': %v", valueStr, err)
-					}
-					// 创建并添加到结果列表
-					baseFromLyData := models.BaseFromLyData{
-						DataTime:          format,
-						Value:             value,
-						BaseFromLyIndexId: indexId,
-						IndexCode:         indexCode,
+						indexData, err := models.GetLyDataByIndexIdAndDataTime(indexId, lastDayOfMonth)
+						if err != nil {
+							logs.Error("ProcessingProfitProcessor Process() : Failed to get data by index id and date: %v", err)
+							continue
+						}
+						if len(indexData) > 0 {
+							logs.Info("ProcessingProfitProcessor Process() : Data already exists for index %d and date %s", indexId, dateText)
+							continue
+						}
+
+						valueStr := row[columnIdx]
+						value, err := strconv.ParseFloat(valueStr, 64)
+						if err != nil {
+							return []models.BaseFromLyData{}, fmt.Errorf("failed to parse value '%s': %v", valueStr, err)
+						}
+						// 创建并添加到结果列表
+						baseFromLyData := models.BaseFromLyData{
+							DataTime:          lastDayOfMonth,
+							Value:             value,
+							BaseFromLyIndexId: indexId,
+							IndexCode:         indexCode,
+						}
+						result = append(result, baseFromLyData)
+						continue
+					} else {
+						log.Printf("ProcessingProfitProcessor Process() : Column index out of range for row '%s'", columnDate)
 					}
-					result = append(result, baseFromLyData)
-				} else {
-					log.Printf("ProcessingProfitProcessor Process() : Column index out of range for row '%s'", columnDate)
+					break
 				}
-				break
 			}
 		}
 	}

+ 6 - 0
cmd/processor_factory.go

@@ -68,6 +68,8 @@ func GetProcessor(product string, category string) (ReportProcessor, error) {
 			return &ImportCostProcessor{}, nil
 		case "库存分析":
 			return &InventoryAnalysisProcessor{}, nil
+		case "进口预估":
+			return &ImportEstimateProcessor{}, nil
 		case "加拿大统计局":
 			return &CanadaStatisticsBureauProcessor{}, nil
 		case "进出口分析":
@@ -79,6 +81,8 @@ func GetProcessor(product string, category string) (ReportProcessor, error) {
 		switch category {
 		case "库存分析":
 			return &InventoryAnalysisProcessor{}, nil
+		case "进出口分析":
+			return &ImportExportAnalysisProcessor{}, nil
 		default:
 			return nil, fmt.Errorf("unknown category: %s", category)
 		}
@@ -86,6 +90,8 @@ func GetProcessor(product string, category string) (ReportProcessor, error) {
 		switch category {
 		case "库存分析":
 			return &InventoryAnalysisProcessor{}, nil
+		case "进口预估":
+			return &ImportEstimateProcessor{}, nil
 		case "每日成交":
 			return &DailyTransactionProcessor{}, nil
 		default:

+ 489 - 7
static/liangyou.json

@@ -1,14 +1,496 @@
 {
   "大豆": {
+    "进口成本": {
+      "国际大豆进口成本参考价": [
+        "美湾:国际大豆进口成本价:期货收盘:张家港:美分/蒲式耳:日度",
+        "美湾:国际大豆进口成本价:升贴水:张家港:美分/蒲式耳:日度",
+        "美湾:国际大豆进口成本价:FOB价:张家港:美元/吨:日度",
+        "美湾:国际大豆进口成本价:运费:张家港:美元/吨:日度",
+        "美湾:国际大豆进口成本价:CNF升贴水:张家港:美分/蒲式耳:日度",
+        "美湾:国际大豆进口成本价:CNF:张家港:美元/吨:日度",
+        "美湾:国际大豆进口成本价:进口成本:张家港:元/吨:日度",
+        "巴西:国际大豆进口成本价:期货收盘:张家港:美分/蒲式耳:日度",
+        "巴西:国际大豆进口成本价:升贴水:张家港:美分/蒲式耳:日度",
+        "巴西:国际大豆进口成本价:FOB价:张家港:美元/吨:日度",
+        "巴西:国际大豆进口成本价:运费:张家港:美元/吨:日度",
+        "巴西:国际大豆进口成本价:CNF升贴水:张家港:美分/蒲式耳:日度",
+        "巴西:国际大豆进口成本价:CNF:张家港:美元/吨:日度",
+        "巴西:国际大豆进口成本价:进口成本:张家港:元/吨:日度"
+      ]
+    },
+    "加工利润": {
+      "进口大豆盘面榨利及现货榨利表": [
+        "美湾:进口大豆盘面榨利:元/吨:日度",
+        "巴西:进口大豆盘面榨利:元/吨:日度",
+        "美湾:进口大豆现货榨利:元/吨:日度",
+        "巴西:进口大豆现货榨利:元/吨:日度"
+      ]
+    },
+    "船运费用": {
+      "国际谷物船运费报价及走势图": [
+        "巴西桑托斯:中国北方港口:超灵便型船:国际谷物船运费:当日价格:美元:日度",
+        "阿根廷:中国北方港口:巴拿马型船:国际谷物船运费:当日价格:美元:日度",
+        "美湾密西西比河:中国北方港口:巴拿马型船:国际谷物船运费:当日价格:美元:日度",
+        "美西塔科马:中国北方港口:巴拿马型船:国际谷物船运费:当日价格:美元:日度",
+        "美国北太平洋沿岸:中国:巴拿马型船:国际谷物船运费:当日价格:美元:日度",
+        "美国墨西哥湾:中国:巴拿马型船:国际谷物船运费:当日价格:美元:日度",
+        "巴西巴拉那瓜:中国:巴拿马型船:国际谷物船运费:当日价格:美元:日度",
+        "伊特科提亚拉港:中国:巴拿马型船:国际谷物船运费:当日价格:美元:日度",
+        "波罗的海巴拿马型指数(BPI):国际谷物船运费:当日价格:%:日度",
+        "波罗的海超灵便型指数(BSI):国际谷物船运费:当日价格:%:日度",
+        "波罗的海海岬型指数(BCI):国际谷物船运费:当日价格:%:日度",
+        "波罗的海干散货指数(BDI):国际谷物船运费:当日价格:%:日度",
+        "波罗的海灵便型指数(BHSI):国际谷物船运费:当日价格:%:日度"
+      ]
+    },
+    "供需平衡": {
+      "年度中国大豆市场供需报告": [
+        "中国大豆市场供需:期初库存:万吨:月度",
+        "中国大豆市场供需:种植面积:万吨:月度",
+        "中国大豆市场供需:国内产量:万吨:月度",
+        "中国大豆市场供需:进口量:万吨:月度",
+        "中国大豆市场供需:总供应量:万吨:月度",
+        "中国大豆市场供需:压榨用量:万吨:月度",
+        "中国大豆市场供需:其中:国产大豆:万吨:月度",
+        "中国大豆市场供需:进口大豆:万吨:月度",
+        "中国大豆市场供需:出口量:万吨:月度",
+        "中国大豆市场供需:食用量:万吨:月度",
+        "中国大豆市场供需:种用及其他:万吨:月度",
+        "中国大豆市场供需:总需求量:万吨:月度",
+        "中国大豆市场供需:期末库存:万吨:月度"
+      ]
+    },
     "采购装船": {
       "中国大豆采购进度周统计": [
-        "中国大豆计划采购量:计划采购量:万吨:周度",
-        "中国大豆已采购量:美国:已采购量美国:万吨:周度",
-        "中国大豆已采购量:巴西:已采购量巴西:万吨:周度",
-        "中国大豆已采购量:阿根廷/乌拉圭:已采购量阿根廷/乌拉圭:万吨:周度",
-        "中国大豆已采购量:小计:已采购量小计:万吨:周度",
-        "中国大豆未采购量:未采购量:万吨:周度",
-        "中国大豆采购进度:采购进度%:%:周度"
+        "中国大豆计划采购量:万吨:周度",
+        "中国大豆已采购量:美国:万吨:周度",
+        "中国大豆已采购量:巴西:万吨:周度",
+        "中国大豆已采购量:阿根廷/乌拉圭:万吨:周度",
+        "中国大豆已采购量:小计:万吨:周度",
+        "中国大豆未采购量:万吨:周度",
+        "中国大豆采购进度:%:周度"
+      ]
+    },
+    "加工报告": {
+      "国内大豆周度加工量调查": [
+        "国内大豆加工量:河南省:万吨:周度",
+        "国内大豆加工量:湖北省:万吨:周度",
+        "国内大豆加工量:湖南省:万吨:周度",
+        "国内大豆加工量:黑龙江:万吨:周度",
+        "国内大豆加工量:吉林省:万吨:周度",
+        "国内大豆加工量:辽宁省:万吨:周度",
+        "国内大豆加工量:内蒙古:万吨:周度",
+        "国内大豆加工量:河北省:万吨:周度",
+        "国内大豆加工量:天津市:万吨:周度",
+        "国内大豆加工量:江西省:万吨:周度",
+        "国内大豆加工量:山东省:万吨:周度",
+        "国内大豆加工量:安徽省:万吨:周度",
+        "国内大豆加工量:江苏省:万吨:周度",
+        "国内大豆加工量:上海市:万吨:周度",
+        "国内大豆加工量:浙江省:万吨:周度",
+        "国内大豆加工量:福建省:万吨:周度",
+        "国内大豆加工量:广东省:万吨:周度",
+        "国内大豆加工量:广西省:万吨:周度",
+        "国内大豆加工量:海南省:万吨:周度",
+        "国内大豆加工量:陕西省:万吨:周度",
+        "国内大豆加工量:四川省:万吨:周度",
+        "国内大豆加工量:重庆市:万吨:周度",
+        "国内大豆加工量:云南省:万吨:周度",
+        "国内大豆加工量:合计:万吨:周度",
+        "国内大豆加工量:其中:国产:万吨:周度",
+        "国内大豆加工量:进口:万吨:周度",
+        "国内大豆开机率:河南省:%:周度",
+        "国内大豆开机率:湖北省:%:周度",
+        "国内大豆开机率:湖南省:%:周度",
+        "国内大豆开机率:黑龙江:%:周度",
+        "国内大豆开机率:吉林省:%:周度",
+        "国内大豆开机率:辽宁省:%:周度",
+        "国内大豆开机率:内蒙古:%:周度",
+        "国内大豆开机率:河北省:%:周度",
+        "国内大豆开机率:天津市:%:周度",
+        "国内大豆开机率:山西省:%:周度",
+        "国内大豆开机率:山东省:%:周度",
+        "国内大豆开机率:安徽省:%:周度",
+        "国内大豆开机率:江苏省:%:周度",
+        "国内大豆开机率:上海市:%:周度",
+        "国内大豆开机率:浙江省:%:周度",
+        "国内大豆开机率:福建省:%:周度",
+        "国内大豆开机率:广东省:%:周度",
+        "国内大豆开机率:广西省:%:周度",
+        "国内大豆开机率:海南省:%:周度",
+        "国内大豆开机率:陕西省:%:周度",
+        "国内大豆开机率:四川省:%:周度",
+        "国内大豆开机率:重庆市:%:周度",
+        "国内大豆开机率:云南省:%:周度",
+        "国内大豆开机率:合计:%:周度",
+        "国内大豆开机率:其中:国产:%:周度",
+        "国内大豆开机率:进口:%:周度"
+      ]
+    },
+    "库存分析": {
+      "全国油厂进口大豆库存量统计周报": [
+        "全国油厂进口大豆库存量(万吨):东北地区:万吨:周度",
+        "全国油厂进口大豆库存量(万吨):华北地区:万吨:周度",
+        "全国油厂进口大豆库存量(万吨):华东地区:万吨:周度",
+        "全国油厂进口大豆库存量(万吨):华南地区:万吨:周度",
+        "全国油厂进口大豆库存量(万吨):西南地区:万吨:周度",
+        "全国油厂进口大豆库存量(万吨):其他地区:万吨:周度",
+        "全国油厂进口大豆库存量(万吨):全国统计:万吨:周度",
+        "全国油厂进口大豆库存量(万吨):其中:沿海库存:万吨:周度"
+      ]
+    }
+  },
+  "豆粕": {
+    "库存分析": {
+      "全国油厂豆粕库存与合同统计周报": [
+        "全国油厂豆粕库存量(万吨):东北地区:万吨:周度",
+        "全国油厂豆粕库存量(万吨):华北地区:万吨:周度",
+        "全国油厂豆粕库存量(万吨):华东地区:万吨:周度",
+        "全国油厂豆粕库存量(万吨):华中地区:万吨:周度",
+        "全国油厂豆粕库存量(万吨):华南地区:万吨:周度",
+        "全国油厂豆粕库存量(万吨):西南地区:万吨:周度",
+        "全国油厂豆粕库存量(万吨):西北地区:万吨:周度",
+        "全国油厂豆粕库存量(万吨):全国合计:万吨:周度",
+        "全国油厂豆粕库存量(万吨):其中:沿海库存:万吨:周度",
+        "全国油厂豆粕合同量(万吨):东北地区:万吨:周度",
+        "全国油厂豆粕合同量(万吨):华北地区:万吨:周度",
+        "全国油厂豆粕合同量(万吨):华东地区:万吨:周度",
+        "全国油厂豆粕合同量(万吨):华中地区:万吨:周度",
+        "全国油厂豆粕合同量(万吨):华南地区:万吨:周度",
+        "全国油厂豆粕合同量(万吨):西南地区:万吨:周度",
+        "全国油厂豆粕合同量(万吨):西北地区:万吨:周度",
+        "全国油厂豆粕合同量(万吨):全国合计:万吨:周度",
+        "全国油厂豆粕合同量(万吨):其中:沿海库存:万吨:周度"
+      ]
+    }
+  },
+  "大豆油": {
+    "库存分析": {
+      "全国油厂豆油库存与合同统计周报": [
+        "全国油厂豆油库存量(万吨):东北地区:万吨:周度",
+        "全国油厂豆油库存量(万吨):华北地区:万吨:周度",
+        "全国油厂豆油库存量(万吨):华东地区:万吨:周度",
+        "全国油厂豆油库存量(万吨):华中地区:万吨:周度",
+        "全国油厂豆油库存量(万吨):华南地区:万吨:周度",
+        "全国油厂豆油库存量(万吨):西南地区:万吨:周度",
+        "全国油厂豆油库存量(万吨):西北地区:万吨:周度",
+        "全国油厂豆油库存量(万吨):全国合计:万吨:周度",
+        "全国油厂豆油库存量(万吨):其中:沿海库存:万吨:周度",
+        "全国油厂豆油合同量(万吨):东北地区:万吨:周度",
+        "全国油厂豆油合同量(万吨):华北地区:万吨:周度",
+        "全国油厂豆油合同量(万吨):华东地区:万吨:周度",
+        "全国油厂豆油合同量(万吨):华中地区:万吨:周度",
+        "全国油厂豆油合同量(万吨):华南地区:万吨:周度",
+        "全国油厂豆油合同量(万吨):西南地区:万吨:周度",
+        "全国油厂豆油合同量(万吨):西北地区:万吨:周度",
+        "全国油厂豆油合同量(万吨):全国合计:万吨:周度",
+        "全国油厂豆油合同量(万吨):其中:沿海库存:万吨:周度"
+      ]
+    },
+    "价差套利": {
+      "豆棕油期现货价差统计": [
+        "棕榈油主力:大商所:期现货价差:元/吨:日度",
+        "豆油主力:大商所:期现货价差:元/吨:日度",
+        "24度棕榈油:进口液:期现货价差:元/吨:日度",
+        "一级豆油:进口压榨:期现货价差:元/吨:日度"
+      ]
+    },
+    "每日成交": {
+      "豆油成交量及价格统计": [
+        "豆油成交量:东北:吨:日度",
+        "豆油成交量:华北:吨:日度",
+        "豆油成交量:江苏:吨:日度",
+        "豆油成交量:浙江:吨:日度",
+        "豆油成交量:山东:吨:日度",
+        "豆油成交量:广东:吨:日度",
+        "豆油成交量:广西:吨:日度",
+        "豆油成交量:福建:吨:日度",
+        "豆油成交量:其他:吨:日度",
+        "豆油成交量:合计:吨:日度",
+        "豆油周度成交量:东北:吨:周度",
+        "豆油周度成交量:华北:吨:周度",
+        "豆油周度成交量:江苏:吨:周度",
+        "豆油周度成交量:浙江:吨:周度",
+        "豆油周度成交量:山东:吨:周度",
+        "豆油周度成交量:广东:吨:周度",
+        "豆油周度成交量:广西:吨:周度",
+        "豆油周度成交量:福建:吨:周度",
+        "豆油周度成交量:其他:吨:周度",
+        "豆油周度成交量:合计:吨:周度",
+        "主要集团:九三:豆油现货成交量:吨:周度",
+        "主要集团:中粮:豆油现货成交量:吨:周度",
+        "主要集团:中储粮:豆油现货成交量:吨:周度",
+        "豆油成交量:东北:1:吨:日度",
+        "豆油成交量:华北:1:吨:日度",
+        "豆油成交量:江苏:1:吨:日度",
+        "豆油成交量:浙江:1:吨:日度",
+        "豆油成交量:山东:1:吨:日度",
+        "豆油成交量:广东:1:吨:日度",
+        "豆油成交量:广西:1:吨:日度",
+        "豆油成交量:福建:1:吨:日度",
+        "豆油成交量:其他:1:吨:日度",
+        "豆油成交量:合计:1:吨:日度",
+        "豆油周度成交量:东北:1:吨:周度",
+        "豆油周度成交量:华北:1:吨:周度",
+        "豆油周度成交量:江苏:1:吨:周度",
+        "豆油周度成交量:浙江:1:吨:周度",
+        "豆油周度成交量:山东:1:吨:周度",
+        "豆油周度成交量:广东:1:吨:周度",
+        "豆油周度成交量:广西:1:吨:周度",
+        "豆油周度成交量:福建:1:吨:周度",
+        "豆油周度成交量:其他:1:吨:周度",
+        "豆油周度成交量:合计:1:吨:周度",
+        "主要集团:九三:豆油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:中粮:豆油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:中储粮:豆油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:达孚:豆油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:嘉吉:豆油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:金光:豆油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:邦基:豆油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:益海:豆油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:汇福:豆油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:渤海:豆油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:香驰:豆油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:中海:豆油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:其他:豆油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:总计:豆油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:九三:豆油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:中粮:豆油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:中储粮:豆油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:达孚:豆油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:嘉吉:豆油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:金光:豆油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:邦基:豆油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:益海:豆油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:汇福:豆油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:渤海:豆油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:香驰:豆油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:中海:豆油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:其他:豆油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:总计:豆油基差成交量:本周(吨)基差成交:吨:周度"
+      ]
+    }
+  },
+  "棕榈油": {
+    "国际价格": {
+      "国际棕榈油FOB报价及走势": [
+        "马来棕榈液油:FOB价格:美元/吨:日度",
+        "马来棕榈油:FOB价格:美元/吨:日度",
+        "马来棕榈硬脂:FOB价格:美元/吨:日度",
+        "印尼毛棕油:FOB价格:美元/吨:日度"
+      ]
+    },
+    "进口成本": {
+      "马来西亚棕榈油进口成本参考价": [
+        "棕榈液油(24度):运费:张家港:美元/吨:日度",
+        "棕榈液油(24度):CNF:张家港:美元/吨:日度",
+        "棕榈液油(24度):完税价:张家港:美元/吨:日度",
+        "棕榈液油(24度):进口成本:张家港:元/吨:日度"
+      ]
+    },
+    "库存分析": {
+      "全国棕榈油库存与合同统计周报": [
+        "棕榈油24度及以下库存:华北地区:万吨:周度",
+        "棕榈油24度及以下库存:华东地区:万吨:周度",
+        "棕榈油24度及以下库存:华南地区:万吨:周度",
+        "棕榈油24度及以下库存:其他地区:万吨:周度",
+        "棕榈油24度及以下库存:全国合计:万吨:周度",
+        "棕油总库存:华北地区:万吨:周度",
+        "棕油总库存:华东地区:万吨:周度",
+        "棕油总库存:华南地区:万吨:周度",
+        "棕油总库存:其他地区:万吨:周度",
+        "棕油总库存:全国合计:万吨:周度",
+        "棕榈油合同量:华北地区:万吨:周度",
+        "棕榈油合同量:华东地区:万吨:周度",
+        "棕榈油合同量:华南地区:万吨:周度",
+        "棕榈油合同量:其他地区:万吨:周度",
+        "棕榈油合同量:全国合计:万吨:周度"
+      ]
+    },
+    "每日成交": {
+      "棕榈油成交量及价格统计": [
+        "棕榈油成交量:华北:1:吨:日度",
+        "棕榈油成交量:山东:1:吨:日度",
+        "棕榈油成交量:江苏:1:吨:日度",
+        "棕榈油成交量:浙江:1:吨:日度",
+        "棕榈油成交量:福建:1:吨:日度",
+        "棕榈油成交量:广东:1:吨:日度",
+        "棕榈油成交量:广西:1:吨:日度",
+        "棕榈油成交量:其他:1:吨:日度",
+        "棕榈油成交量:合计:1:吨:日度",
+        "棕榈油周度成交量:华北:1:吨:日度",
+        "棕榈油周度成交量:山东:1:吨:日度",
+        "棕榈油周度成交量:江苏:1:吨:日度",
+        "棕榈油周度成交量:浙江:1:吨:日度",
+        "棕榈油周度成交量:福建:1:吨:日度",
+        "棕榈油周度成交量:广东:1:吨:日度",
+        "棕榈油周度成交量:广西:1:吨:日度",
+        "棕榈油周度成交量:其他:1:吨:日度",
+        "棕榈油周度成交量:合计:1:吨:日度",
+        "主要集团:中粮:豆油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:金光:豆油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:益海:豆油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:来宝:豆油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:合益荣:豆油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:其他:豆油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:总计:豆油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:中粮:豆油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:金光:豆油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:益海:豆油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:来宝:豆油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:合益荣:豆油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:其他:豆油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:总计:豆油基差成交量:本周(吨)基差成交:吨:周度"
+      ]
+    }
+  },
+  "油菜籽": {
+    "进口成本": {
+      "加拿大油菜籽理论进口成本": [
+        "加拿大油菜籽:期货收盘:广州港:美分/蒲式耳:日度",
+        "加拿大油菜籽:升贴水:广州港:美元/吨:日度",
+        "加拿大油菜籽:FOB价:广州港:美元/吨:日度",
+        "加拿大油菜籽:运费:广州港:美元/吨:日度",
+        "加拿大油菜籽:CNF升贴水:广州港:美元/吨:日度",
+        "加拿大油菜籽:CNF:广州港:美元/吨:日度",
+        "加拿大油菜籽:进口成本:广州港:元/吨:日度"
+      ]
+    },
+    "库存分析": {
+      "全国油厂进口油菜籽库存量统计周报": [
+        "全国油厂进口油菜籽库存量:广西地区:万吨:周度",
+        "全国油厂进口油菜籽库存量:广东地区:万吨:周度",
+        "全国油厂进口油菜籽库存量:福建地区:万吨:周度",
+        "全国油厂进口油菜籽库存量:江苏地区:万吨:周度",
+        "全国油厂进口油菜籽库存量:辽宁地区:万吨:周度",
+        "全国油厂进口油菜籽库存量:其它地区:万吨:周度",
+        "全国油厂进口油菜籽库存量:全国统计:万吨:周度"
+      ]
+    },
+    "进口预估": {
+      "进口油菜籽月度进口量预估": [
+        "进口油菜籽月度进口量预估:本年进口量:万吨:周度",
+        "进口油菜籽月度进口量预估:本年海关进口量:万吨:周度"
+      ]
+    },
+    "加拿大统计局": {
+      "加拿大双低油菜籽周度商业库存": [
+        "加拿大双低油菜籽:期初库存:万吨:周度",
+        "加拿大双低油菜籽:上市量:万吨:周度",
+        "加拿大双低油菜籽:出口量:万吨:周度",
+        "加拿大双低油菜籽:消费量:万吨:周度",
+        "加拿大双低油菜籽:期末库存:万吨:周度"
+      ]
+    },
+    "进出口分析": {
+      "油菜籽进口数量分析": [
+        "油菜籽进口量:万吨:月度"
+      ],
+      "油菜籽出口数量分析": [
+        "油菜籽出口量:吨:月度"
+      ]
+    }
+  },
+  "菜粕": {
+    "库存分析": {
+      "全国油厂进口压榨菜粕库存与合同统计周报": [
+        "全国油厂进口压榨菜粕库存量:广西地区:万吨:周度",
+        "全国油厂进口压榨菜粕库存量:广东地区:万吨:周度",
+        "全国油厂进口压榨菜粕库存量:福建地区:万吨:周度",
+        "全国油厂进口压榨菜粕库存量:江苏地区:万吨:周度",
+        "全国油厂进口压榨菜粕库存量:辽宁地区:万吨:周度",
+        "全国油厂进口压榨菜粕库存量:其他地区:万吨:周度",
+        "全国油厂进口压榨菜粕库存量:全国合计:万吨:周度",
+        "全国油厂进口压榨菜粕合同量:广西地区:万吨:周度",
+        "全国油厂进口压榨菜粕合同量:广东地区:万吨:周度",
+        "全国油厂进口压榨菜粕合同量:福建地区:万吨:周度",
+        "全国油厂进口压榨菜粕合同量:江苏地区:万吨:周度",
+        "全国油厂进口压榨菜粕合同量:辽宁地区:万吨:周度",
+        "全国油厂进口压榨菜粕合同量:其他地区:万吨:周度",
+        "全国油厂进口压榨菜粕合同量:全国合计:万吨:周度"
+
+      ]
+    },
+    "进出口分析": {
+      "菜粕出口数量分析": [
+        "菜粕出口数量:吨:月度"
+      ],
+      "菜粕进口数量分析": [
+        "菜粕进口数量:万吨:月度"
+      ]
+    }
+  },
+  "菜籽油": {
+    "库存分析": {
+      "全国油厂进口压榨菜油库存与合同统计周报": [
+        "全国油厂进口压榨菜油库存量:广西地区:万吨:周度",
+        "全国油厂进口压榨菜油库存量:广东地区:万吨:周度",
+        "全国油厂进口压榨菜油库存量:福建地区:万吨:周度",
+        "全国油厂进口压榨菜油库存量:江苏地区:万吨:周度",
+        "全国油厂进口压榨菜油库存量:辽宁地区:万吨:周度",
+        "全国油厂进口压榨菜油库存量:其他地区:万吨:周度",
+        "全国油厂进口压榨菜油库存量:全国合计:万吨:周度",
+        "全国油厂进口压榨菜油库存量:其中:非油企库存:万吨:周度",
+        "全国油厂进口压榨菜油库存量:油企库存:万吨:周度",
+        "全国油厂进口压榨菜油合同量:广西地区:万吨:周度",
+        "全国油厂进口压榨菜油合同量:广东地区:万吨:周度",
+        "全国油厂进口压榨菜油合同量:福建地区:万吨:周度",
+        "全国油厂进口压榨菜油合同量:江苏地区:万吨:周度",
+        "全国油厂进口压榨菜油合同量:辽宁地区:万吨:周度",
+        "全国油厂进口压榨菜油合同量:其他地区:万吨:周度",
+        "全国油厂进口压榨菜油合同量:全国合计:万吨:周度",
+        "全国油厂进口压榨菜油合同量:其中:非油企库存:万吨:周度",
+        "全国油厂进口压榨菜油合同量:油企库存:万吨:周度"
+      ]
+    },
+    "进口预估": {
+      "菜籽油月度进口量预估": [
+        "菜籽油月度进口量预估:本年进口量:万吨:周度",
+        "菜籽油月度进口量预估:本年海关进口量:万吨:周度"
+      ]
+    },
+    "每日成交": {
+      "菜籽油成交量及价格统计": [
+        "菜籽油成交量:东北:1:吨:日度",
+        "菜籽油成交量:华东:1:吨:日度",
+        "菜籽油成交量:福建:1:吨:日度",
+        "菜籽油成交量:广东:1:吨:日度",
+        "菜籽油成交量:广西:1:吨:日度",
+        "菜籽油成交量:其它:1:吨:日度",
+        "菜籽油成交量:合计:1:吨:日度",
+        "菜籽油成交量:华南合计:1:吨:日度",
+        "菜籽油成交量:沿海合计:1:吨:日度",
+        "菜籽油周度成交量:东北:1:吨:周度",
+        "菜籽油周度成交量:华东:1:吨:周度",
+        "菜籽油周度成交量:福建:1:吨:周度",
+        "菜籽油周度成交量:广东:1:吨:周度",
+        "菜籽油周度成交量:广西:1:吨:周度",
+        "菜籽油周度成交量:其它:1:吨:周度",
+        "菜籽油周度成交量:合计:1:吨:周度",
+        "菜籽油周度成交量:华南合计:1:吨:周度",
+        "菜籽油周度成交量:沿海合计:1:吨:周度",
+        "主要集团:营口嘉里:菜籽油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:富之源:菜籽油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:防城大海:菜籽油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:防城澳加:菜籽油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:成都中粮:菜籽油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:其它:菜籽油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:总计:菜籽油现货成交量:本周(吨)现货成交:吨:周度",
+        "主要集团:营口嘉里:菜籽油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:富之源:菜籽油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:防城大海:菜籽油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:防城澳加:菜籽油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:成都中粮:菜籽油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:其它:菜籽油基差成交量:本周(吨)基差成交:吨:周度",
+        "主要集团:总计:菜籽油基差成交量:本周(吨)基差成交:吨:周度"
+      ]
+    }
+  },
+  "葵花粕": {
+    "进口预估": {
+      "进口葵花粕月度进口量预估": [
+        "进口葵花粕月度进口量预估:本年进口量:万吨:周度",
+        "进口葵花粕月度进口量预估:本年海关进口量:万吨:周度"
       ]
     }
   }

+ 122 - 6
utils/date_util.go

@@ -128,6 +128,73 @@ func GetNextThreeMonthsNoYear(dateText string) ([]string, error) {
 	return result, nil
 }
 
+// GetNextThreeMonthsLastDay 取当前月的最后一天和后两个月的最后一天 时间格式为 2024-08-03 --> 2024-08-31, 2024-09-30, 2024-10-31
+func GetNextThreeMonthsLastDay(dateText string) ([]string, error) {
+	// 解析日期字符串为时间类型
+	date, err := time.Parse("2006-01-02", dateText)
+	if err != nil {
+		return nil, fmt.Errorf("日期解析错误: %v", err)
+	}
+
+	// 存储结果的切片
+	var result []string
+
+	// 获取本月及后两个月的最后一天
+	for i := 0; i < 3; i++ {
+		// 获取下个月的第一天
+		nextMonth := date.AddDate(0, 1, 0)
+
+		// 获取当前月的最后一天
+		lastDay := nextMonth.AddDate(0, 0, -nextMonth.Day())
+
+		// 添加到结果中
+		result = append(result, lastDay.Format("2006-01-02"))
+
+		// 将日期加一个月
+		date = date.AddDate(0, 1, 0)
+	}
+
+	return result, nil
+}
+
+// GetElementInSlice 获取切片中特定的元素,判断传入月份是否在当前切片月份匹配,如果匹配则返回切片中对应的元素 参数格式为 dateTexts month, [2024-08-31, 2024-09-30, 2024-10-31] 08 --> 2024-08-31, 07 --> nil
+func GetElementInSlice(dateTexts []string, month string) (string, error) {
+	for _, dateText := range dateTexts {
+		reportDate, err := time.Parse("2006-01-02", strings.TrimSpace(dateText))
+		if err != nil {
+			return "", fmt.Errorf("failed to parse report date: %v", err)
+		}
+
+		if strings.HasSuffix(reportDate.Format("2006-01"), month) {
+			return dateText, nil
+		}
+	}
+
+	return "", fmt.Errorf("未找到匹配的月份")
+}
+
+// StringToTime string 类型时间转换为 time 类型时间 dateText 格式为 2024-08-03 00:00:00 --> 2024-08-03 00:00:00
+func StringToTime(dateText string) (time.Time, error) {
+	// 解析日期
+	reportDate, err := time.Parse("2006-01-02 15:04:05", strings.TrimSpace(dateText))
+	if err != nil {
+		return time.Time{}, fmt.Errorf("failed to parse report date: %v", err)
+	}
+
+	return reportDate, nil
+}
+
+// StringToTimeZero string 类型时间转换为 time dateText 格式为 2024-08-03 --> 2024-08-03 00:00:00
+func StringToTimeZero(dateText string) (time.Time, error) {
+	// 解析日期
+	reportDate, err := time.Parse("2006-01-02", strings.TrimSpace(dateText))
+	if err != nil {
+		return time.Time{}, fmt.Errorf("failed to parse report date: %v", err)
+	}
+
+	return reportDate, nil
+}
+
 // GetWeekdaysInSameWeek 拿到传入时间本周当前工作日的时间列表,时间格式 dataText 格式为 2024-08-03 --> 8月3日
 func GetWeekdaysInSameWeek(dateStr string) ([]string, error) {
 	// 解析输入日期字符串
@@ -194,18 +261,23 @@ func ConvertTimeFormatToYearMonthDay(dateText string) (string, error) {
 	return fmt.Sprintf("%02d年%d月%d日", shortYear, reportDate.Month(), reportDate.Day()), nil
 }
 
-// GetCurrentYear 获取当前年份 转换时间格式 dateText 格式为 2024-08-03 --> 2024年
-func GetCurrentYear(dateText string) (string, error) {
+// GetCurrentYearAndLastYear 获取当前年份和前一年的年份 转换时间格式 dateText 格式为 2024-08-03 --> 2024年,2023年
+func GetCurrentYearAndLastYear(dateText string) ([]string, error) {
 	// 解析日期
 	reportDate, err := time.Parse("2006-01-02", strings.TrimSpace(dateText))
 	if err != nil {
-		return "", fmt.Errorf("failed to parse report date: %v", err)
+		return nil, fmt.Errorf("failed to parse report date: %v", err)
 	}
 
-	// 获取年份的后两位
-	shortYear := reportDate.Year() % 100
+	years := make([]string, 2)
+	year := reportDate.Year()
 
-	return fmt.Sprintf("%02d年", shortYear), nil
+	// 当前年份
+	years[0] = fmt.Sprintf("%d年", year)
+	// 前一年
+	years[1] = fmt.Sprintf("%d年", year-1)
+
+	return years, nil
 }
 
 // ConvertTimeFormatToYearMonth 转换时间格式 dateText 返回本月 和 后两月 格式为 2024-08-03 --> 2024年8月,2024-10-03 --> 2024年10月
@@ -262,6 +334,39 @@ func GetCurrentYearAndNextYear(dateText string) ([]string, error) {
 	return years, nil
 }
 
+// IsSameMonth 判断当前传入年月是否是同一月 2024-08-03, 2024-08 --> true, 2024-08-03, 2024-07 --> false
+func IsSameMonth(dateText1, dateText2 string) (bool, error) {
+	// 解析日期
+	date1, err := time.Parse("2006-01-02", strings.TrimSpace(dateText1))
+	if err != nil {
+		return false, fmt.Errorf("failed to parse date1: %v", err)
+	}
+
+	date2, err := time.Parse("2006-01", strings.TrimSpace(dateText2))
+	if err != nil {
+		return false, fmt.Errorf("failed to parse date2: %v", err)
+	}
+
+	return date1.Year() == date2.Year() && date1.Month() == date2.Month(), nil
+}
+
+// GetLastDayOfMonth 获取传入年月的最后一天 dateText 格式为 2024-08 --> 2024-08-31
+func GetLastDayOfMonth(dateText string) (string, error) {
+	// 解析日期
+	date, err := time.Parse("2006-01", strings.TrimSpace(dateText))
+	if err != nil {
+		return "", fmt.Errorf("failed to parse date: %v", err)
+	}
+
+	// 获取下个月的第一天
+	nextMonth := date.AddDate(0, 1, 0)
+
+	// 获取本月的最后一天
+	lastDay := nextMonth.AddDate(0, 0, -1)
+
+	return lastDay.Format("2006-01-02"), nil
+}
+
 // ConvertMonthToNumber 时间转换 格式 8月 --> 08
 func ConvertMonthToNumber(dateText string) (string, error) {
 	// 去掉字符串中的 "月"
@@ -276,6 +381,17 @@ func ConvertMonthToNumber(dateText string) (string, error) {
 	return fmt.Sprintf("%02d", month), nil
 }
 
+// 时间转换 格式 1 --> 01
+func ConvertMonthToNumber1(dateText string) (string, error) {
+	// 将月份转换为整数
+	month, err := strconv.Atoi(dateText)
+	if err != nil {
+		return "", fmt.Errorf("failed to parse month: %v", err)
+	}
+
+	return fmt.Sprintf("%02d", month), nil
+}
+
 // GetNextThreeMonths 获取传入时间的本月及后两月的年月 2024-08-03 --> 24年8月
 func GetNextThreeMonths(dateText string) ([]string, error) {
 	// 解析日期字符串为时间类型