package services

import (
	"encoding/json"
	"errors"
	"eta/eta_api/models"
	"eta/eta_api/models/company"
	"eta/eta_api/models/report"
	"eta/eta_api/models/system"
	"eta/eta_api/services/alarm_msg"
	"eta/eta_api/services/public_api"
	"eta/eta_api/utils"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"html"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"
)

func GetReportContentSub(content string) (contentSub string, err error) {
	content = html.UnescapeString(content)
	doc, err := goquery.NewDocumentFromReader(strings.NewReader(content))
	if err != nil {
		fmt.Println("create doc err:", err.Error())
		return
	}
	n := 0
	doc.Find("p").Each(func(i int, s *goquery.Selection) {
		if n >= 5 {
			return
		}
		n++
		phtml, err := s.Html()
		if err != nil {
			fmt.Println("get html err", err.Error())
			return
		}
		if s.Text() != "" || strings.Contains(phtml, "src") {
			contentSub = contentSub + "<p>" + phtml + "</p>"
		}
	})
	return
}

// UpdateChaptersVideo 更新章节音频
func UpdateChaptersVideo(ids []int) (err error) {
	defer func() {
		if err != nil {
			utils.FileLog.Error("UpdateChaptersVideo, chapterIds:%v, Err:%s", ids, err.Error())
			go alarm_msg.SendAlarmMsg(fmt.Sprintf("更新章节音频失败, 章节ID: %v; Err: "+err.Error(), ids), 3)
		}
	}()
	if len(ids) <= 0 {
		return
	}

	chapterList, err := models.GetChapterListByChapterIds(ids)
	if err != nil {
		return
	}
	// 生成video
	nowTime := time.Now()
	updateCols := make([]string, 0)
	updateCols = append(updateCols, "VideoUrl", "VideoName", "VideoSize", "VideoPlaySeconds")
	for i := 0; i < len(chapterList); i++ {
		item := chapterList[i]
		// 忽略已有音频的章节
		if item.VideoUrl != "" && item.VideoName != "" && item.VideoSize != "" && item.VideoPlaySeconds != "" {
			continue
		}
		videoUrl, videoName, videoSize, videoPlaySeconds, e := CreateReportVideo(item.Title, html.UnescapeString(item.Content), nowTime.Format(utils.FormatDateTime))
		if e != nil {
			err = e
			return
		}
		item.VideoUrl = videoUrl
		item.VideoName = videoName
		item.VideoSize = videoSize
		item.VideoPlaySeconds = fmt.Sprintf("%.2f", videoPlaySeconds)
		if e = item.UpdateChapter(updateCols); e != nil {
			err = e
		}
	}
	return
}

// PublishTodayDayReport 发布今日晨报
//func PublishTodayDayReport() (err error) {
//	nowTime := time.Now()
//	startTime := time.Date(nowTime.Year(), nowTime.Month(), nowTime.Day(), 0, 0, 0, 0, time.Local)
//	endTime := time.Date(nowTime.Year(), nowTime.Month(), nowTime.Day(), 23, 59, 59, 0, time.Local)
//	todayReport, err := models.GetUnPublishDayReport(startTime, endTime)
//	if err != nil {
//		if utils.IsErrNoRow(err) { //如果是找不到待发送的晨报,那么需要将err置空
//			err = nil
//		}
//		return
//	}
//	if todayReport != nil {
//		if _, tmpErr, _ := PublishChapterReport(todayReport, "", nil); tmpErr != nil {
//			err = tmpErr
//			return
//		}
//		// 定时发布的晨报自动推送客群
//		reportDetail, tmpErr := models.GetReportById(todayReport.Id)
//		if tmpErr != nil {
//			err = tmpErr
//			return
//		}
//		// 推送模板消息
//		if tmpErr = SendMiniProgramReportWxMsg(todayReport.Id); tmpErr != nil {
//			err = tmpErr
//			return
//		}
//		if tmpErr = models.ModifyReportThsMsgIsSend(reportDetail); tmpErr != nil {
//			err = tmpErr
//			return
//		}
//	}
//
//	return
//}

// UpdateReportEs 更新报告/章节Es
func UpdateReportEs(reportId int, publishState int) (err error) {
	if reportId <= 0 {
		return
	}
	reportInfo, err := models.GetReportByReportId(reportId)
	if err != nil {
		return
	}
	categories := ""
	if reportInfo.HasChapter == 1 {
		// 晨周报
		chapterList, tmpErr := models.GetPublishedChapterListByReportId(reportInfo.Id)
		if tmpErr != nil {
			return
		}
		if len(chapterList) > 0 {
			// 更新章节的es数据
			for _, chapterInfo := range chapterList {
				err = updateReportChapterEsByChapter(chapterInfo)
				if err != nil {
					return
				}
			}
		}
	} else {
		// 获取最小分类的id
		minClassifyId, _, tmpErr := getMinClassify(reportInfo)
		if tmpErr != nil {
			return
		}
		permissionList, tmpErr := models.GetChartPermissionNameFromMappingByKeyword("rddp", minClassifyId)
		if tmpErr != nil {
			return
		}
		categoryArr := make([]string, 0)
		for i := 0; i < len(permissionList); i++ {
			categoryArr = append(categoryArr, permissionList[i].PermissionName)
		}
		aliasArr, _ := addCategoryAliasToArr(categoryArr)
		categories = strings.Join(aliasArr, ",")
		//}
	}

	// 最小单位的分类id
	minClassifyId, minClassifyName, err := getMinClassify(reportInfo)
	if err != nil {
		return
	}

	// 新增报告ES
	esReport := &models.ElasticReportDetail{
		ReportId:           reportInfo.Id,
		ReportChapterId:    0,
		Title:              reportInfo.Title,
		Abstract:           reportInfo.Abstract,
		BodyContent:        utils.TrimHtml(html.UnescapeString(reportInfo.Content)),
		PublishTime:        reportInfo.PublishTime.Format(utils.FormatDateTime),
		PublishState:       publishState,
		Author:             reportInfo.Author,
		ClassifyIdFirst:    reportInfo.ClassifyIdFirst,
		ClassifyNameFirst:  reportInfo.ClassifyNameFirst,
		ClassifyIdSecond:   reportInfo.ClassifyIdSecond,
		ClassifyNameSecond: reportInfo.ClassifyNameSecond,
		ClassifyId:         minClassifyId,
		ClassifyName:       minClassifyName,
		Categories:         categories,
		StageStr:           strconv.Itoa(reportInfo.Stage),
	}
	docId := fmt.Sprintf("%d-%d", reportInfo.Id, 0)
	if err = EsAddOrEditReport(utils.EsReportIndexName, docId, esReport); err != nil {
		return
	}

	return
}

// addCategoryAliasToArr 品种别名
func addCategoryAliasToArr(categoryArr []string) (aliasArr []string, err error) {
	aliasArr = categoryArr
	if len(categoryArr) > 0 {
		for i := 0; i < len(categoryArr); i++ {
			if strings.Contains(categoryArr[i], "沥青") {
				aliasArr = append(aliasArr, "BU")
			}
			if strings.Contains(categoryArr[i], "MEG") {
				aliasArr = append(aliasArr, "EG", "乙二醇")
			}
			if strings.Contains(categoryArr[i], "聚酯") {
				aliasArr = append(aliasArr, "长丝", "短纤", "瓶片")
			}
			if strings.Contains(categoryArr[i], "纯苯+苯乙烯") {
				aliasArr = append(aliasArr, "EB")
			}
			if strings.Contains(categoryArr[i], "聚乙烯") {
				aliasArr = append(aliasArr, "PP", "PE")
			}
			if strings.Contains(categoryArr[i], "玻璃纯碱") {
				aliasArr = append(aliasArr, "玻璃", "纯碱", "FG", "SA")
			}
			if strings.Contains(categoryArr[i], "甲醇") {
				aliasArr = append(aliasArr, "甲醇", "MA")
			}
			if strings.Contains(categoryArr[i], "橡胶") {
				aliasArr = append(aliasArr, "橡胶", "RU")
			}
		}
	}
	return
}

// UpdateReportChapterEs
// @Description: 通过章节id更新报告章节ES
// @author: Roc
// @datetime 2024-06-20 13:16:22
// @param reportChapterId int
// @return err error
func UpdateReportChapterEs(reportChapterId int) (err error) {
	if reportChapterId <= 0 {
		return
	}
	chapterInfo, err := models.GetReportChapterInfoById(reportChapterId)
	if err != nil {
		return
	}

	err = updateReportChapterEsByChapter(chapterInfo)
	if err != nil {
		return
	}

	return
}

// updateReportChapterEsByChapter
// @Description: 通过章节详情更新报告章节ES
// @author: Roc
// @datetime 2024-06-20 13:16:11
// @param chapterInfo *models.ReportChapter
// @return err error
func updateReportChapterEsByChapter(chapterInfo *models.ReportChapter) (err error) {
	// 章节对应的品种
	obj := report.ReportChapterPermissionMapping{}
	permissionList, tmpErr := obj.GetPermissionItemListById(chapterInfo.ReportChapterId)
	if tmpErr != nil {
		return
	}
	categoryArr := make([]string, 0)
	if len(permissionList) > 0 {
		for ii := 0; ii < len(permissionList); ii++ {
			categoryArr = append(categoryArr, permissionList[ii].ChartPermissionName)
		}
	}
	aliasArr, _ := addCategoryAliasToArr(categoryArr)
	categories := strings.Join(aliasArr, ",")
	// 新增/编辑ES

	esChapter := &models.ElasticReportDetail{
		ReportId:           chapterInfo.ReportId,
		ReportChapterId:    chapterInfo.ReportChapterId,
		Title:              chapterInfo.Title,
		Abstract:           chapterInfo.Abstract,
		BodyContent:        utils.TrimHtml(html.UnescapeString(chapterInfo.Content)),
		PublishTime:        chapterInfo.PublishTime.Format(utils.FormatDateTime),
		PublishState:       chapterInfo.PublishState,
		Author:             chapterInfo.Author,
		ClassifyIdFirst:    chapterInfo.ClassifyIdFirst,
		ClassifyNameFirst:  chapterInfo.ClassifyNameFirst,
		ClassifyIdSecond:   0,
		ClassifyNameSecond: "",
		ClassifyId:         chapterInfo.ClassifyIdFirst,
		ClassifyName:       chapterInfo.ClassifyNameFirst,
		Categories:         categories,
		StageStr:           strconv.Itoa(chapterInfo.Stage),
	}
	chapterDocId := fmt.Sprintf("%d-%d", chapterInfo.ReportId, chapterInfo.ReportChapterId)
	if err = EsAddOrEditReport(utils.EsReportIndexName, chapterDocId, esChapter); err != nil {
		return
	}

	return
}

// 替换报告内容中的base64图片
func replaceReportBase64ToImg(content string) (newContent string, err error) {
	if content == "" {
		return
	}
	pattern := "data:([a-z]+\\/[a-z0-9-+.]+(;[a-z-]+=[a-z0-9-]+)?)?(;base64)?,([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?"
	re, _ := regexp.Compile(pattern)
	matcher := re.FindAllString(content, 999)
	if len(matcher) > 0 {
		for _, v := range matcher {
			imgUrl, tmpErr := reportBase64ToImg(v)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			content = strings.ReplaceAll(content, v, imgUrl)
		}
	}
	newContent = content
	return
}

// 转换base64图片为img并上传
func reportBase64ToImg(imageBase64 string) (resourceUrl string, err error) {
	if imageBase64 == "" {
		err = errors.New("图片为空")
		return
	}

	ext := ".png"
	uploadDir := "./static"
	randStr := utils.GetRandStringNoSpecialChar(28)
	fileName := randStr + ext
	fpath := uploadDir + "/" + fileName

	b, _ := regexp.MatchString(`^data:\s*image\/(\w+);base64,`, imageBase64)
	if !b {
		err = errors.New("图片格式不正确")
		return
	}
	re, _ := regexp.Compile(`^data:\s*image\/(\w+);base64,`)
	base64Str := re.ReplaceAllString(imageBase64, "")
	base64Str = strings.Replace(base64Str, " ", "", -1)

	err = utils.SaveBase64ToFile(base64Str, fpath)
	if err != nil {
		err = errors.New("图片保存失败" + err.Error())
		return
	}

	defer os.Remove(fpath)

	hzUploadDir := utils.RESOURCE_DIR + "images/"
	savePath := hzUploadDir + time.Now().Format("200601/20060102/")
	savePath += fileName

	//上传到阿里云 和 minio
	//if utils.ObjectStorageClient == "minio" {
	//	err = UploadFileToMinIo(fileName, fpath, savePath)
	//	if err != nil {
	//		err = errors.New("文件上传失败" + err.Error())
	//		return
	//	}
	//	resourceUrl = utils.MinIoImghost + savePath
	//} else {
	//	err = UploadFileToAliyun(fileName, fpath, savePath)
	//	if err != nil {
	//		err = errors.New("文件上传失败" + err.Error())
	//		return
	//	}
	//	resourceUrl = utils.Imghost + savePath
	//}
	ossClient := NewOssClient()
	if ossClient == nil {
		err = fmt.Errorf("初始化OSS服务失败")
		return
	}
	resourceUrl, err = ossClient.UploadFile(fileName, fpath, savePath)
	if err != nil {
		err = fmt.Errorf("文件上传失败, Err: %s", err.Error())
		return
	}

	item := new(models.Resource)
	item.ResourceUrl = resourceUrl
	item.ResourceType = 1
	item.CreateTime = time.Now()
	_, err = models.AddResource(item)
	if err != nil {
		err = errors.New("资源上传失败" + err.Error())
		return
	}

	return
}

//// UpdateReportVideo 更新报告及其章节音频
//func UpdateReportVideo(reportId int) (err error) {
//	defer func() {
//		if err != nil {
//			utils.FileLog.Error("UpdateReportVideo, reportId:%s, Err:%s", strconv.Itoa(reportId), err.Error())
//			go alarm_msg.SendAlarmMsg("更新报告音频失败, 报告ID: "+strconv.Itoa(reportId)+", Err: "+err.Error(), 3)
//			//go utils.SendEmail(utils.APPNAME+"【"+utils.RunMode+"】"+"失败提醒", "更新报告音频失败, 报告ID: " + reportIdStr + ", Err: "+err.Error(), utils.EmailSendToUsers)
//		}
//	}()
//	if reportId == 0 {
//		return
//	}
//	reportInfo, err := models.GetReportByReportId(reportId)
//	if err != nil {
//		return
//	}
//	if reportInfo.HasChapter == 1 {
//		// 更新章节音频
//		chapterList, tmpErr := models.GetPublishedChapterListByReportId(reportInfo.Id)
//		if tmpErr != nil {
//			err = tmpErr
//			return
//		}
//		chapterIdArr := make([]int, 0)
//		for i := 0; i < len(chapterList); i++ {
//			chapterIdArr = append(chapterIdArr, chapterList[i].ReportChapterId)
//		}
//		//go UpdateChaptersVideo(chapterIds)
//		err = UpdateChaptersVideo(chapterIdArr)
//	} else {
//		// 更新报告音频
//		if reportInfo.VideoUrl != "" {
//			return
//		}
//		nowTime := time.Now()
//		updateCols := make([]string, 0)
//		updateCols = append(updateCols, "VideoUrl", "VideoName", "VideoSize", "VideoPlaySeconds")
//		videoUrl, videoName, videoSize, videoPlaySeconds, tmpErr := CreateReportVideo(reportInfo.Title, html.UnescapeString(reportInfo.Content), nowTime.Format(utils.FormatDateTime))
//		reportInfo.VideoUrl = videoUrl
//		reportInfo.VideoName = videoName
//		reportInfo.VideoSize = videoSize
//		reportInfo.VideoPlaySeconds = fmt.Sprintf("%.2f", videoPlaySeconds)
//		tmpErr = reportInfo.UpdateReport(updateCols)
//		if tmpErr != nil {
//			err = tmpErr
//			return
//		}
//	}
//	return
//}
//
//func UpdateEmptyVideoReportVideo() (err error) {
//	list, err := models.GetSyncEmptyVideoReport()
//	if err != nil {
//		return
//	}
//	listLen := len(list)
//	if listLen <= 0 {
//		fmt.Println("无报告需要更新音频")
//		return
//	}
//	fmt.Println("Start 待更新报告音频数: ", listLen)
//	for i := 0; i < listLen; i++ {
//		if err = UpdateReportVideo(list[i].Id); err != nil {
//			fmt.Printf("更新音频失败")
//			fmt.Println(err.Error())
//			return
//		}
//	}
//	fmt.Println("End 报告音频更新完毕")
//	return
//}

// checkDayWeekChapterWrite 校验晨周报已写章节与本期应写章节
func checkDayWeekChapterWrite(chapters []*models.ReportChapter, reportType string) (publishReport bool, tips string, publishIdArr, unPublishIdArr []int, err error) {
	nowTime := time.Now().Local()
	updateTypeArr := make([]int, 0) // 需更新的章节类型IDs
	publishIdArr = make([]int, 0)   // 需发布的章节IDs
	unPublishIdArr = make([]int, 0) // 需取消发布/未发布的章节IDs
	// 校验章节内容
	if reportType == utils.REPORT_TYPE_DAY {
		// 晨报章节不能都为空
		isEmpty := true
		for i := 0; i < len(chapters); i++ {
			if chapters[i].Content != "" && chapters[i].Title != "" {
				isEmpty = false
				break
			}
		}
		if isEmpty {
			err = errors.New("报告章节内容均为空或标题为空,不可发布")
			return
		}
	} else {
		// 周报章节需至少有一篇已编辑且有标题
		editNum := 0
		for i := 0; i < len(chapters); i++ {
			if chapters[i].IsEdit == 1 && chapters[i].Title != "" {
				editNum += 1
			}
		}
		if editNum == 0 {
			err = errors.New("报告均未编辑或标题为空,不可发布")
			return
		}
	}
	// 章节类型列表
	types, e := models.GetReportChapterTypeListByResearchType(reportType)
	if e != nil {
		err = errors.New("获取章节类型列表失败")
		return
	}
	// 本期需更新的章节IDs
	typeLen := len(types)
	for i := 0; i < typeLen; i++ {
		if types[i].IsSet != 1 && types[i].Enabled != 0 {
			// 正常更新
			updateTypeArr = append(updateTypeArr, types[i].ReportChapterTypeId)
		} else {
			// 被设置为零值的也算作正常更新
			if types[i].PauseStartTime == utils.EmptyDateStr && types[i].PauseEndTime == utils.EmptyDateStr {
				updateTypeArr = append(updateTypeArr, types[i].ReportChapterTypeId)
				continue
			}
			// 暂停更新需校验时间
			startTime, _ := time.Parse(utils.FormatDate, types[i].PauseStartTime)
			endTime, _ := time.Parse(utils.FormatDate, types[i].PauseEndTime)
			if nowTime.Before(startTime) || nowTime.After(endTime.AddDate(0, 0, 1)) {
				updateTypeArr = append(updateTypeArr, types[i].ReportChapterTypeId)
			}
		}
	}
	// 校验本期需更新的章节是否都已编辑
	chapterLen := len(chapters)
	updateTypeLen := len(updateTypeArr)
	tipsArr := make([]string, 0)
	for i := 0; i < chapterLen; i++ {
		isWrite := false
		for ii := 0; ii < updateTypeLen; ii++ {
			// 本期应发布的章节
			if chapters[i].TypeId == updateTypeArr[ii] {
				// 标题或者内容为空的情况下, 记录tips提示信息且不发布该章节
				if chapters[i].Title == "" || chapters[i].Content == "" {
					tipsArr = append(tipsArr, chapters[i].TypeName)
					break
				}
				isWrite = true
				break
			}
		}
		if isWrite {
			publishIdArr = append(publishIdArr, chapters[i].ReportChapterId)
		} else {
			unPublishIdArr = append(unPublishIdArr, chapters[i].ReportChapterId)
		}
	}
	if len(tipsArr) > 0 {
		tips = "部分章节未发布:" + strings.Join(tipsArr, "、") + "未填写标题/内容"
	}
	// 周报需发布的章节与需更新的章节数相等则表示可发布整期, 晨报无限制
	if reportType == utils.REPORT_TYPE_DAY {
		publishReport = true
	} else {
		if len(publishIdArr) == updateTypeLen {
			publishReport = true
		}
	}
	return
}

// PcCreateAndUploadSunCode 生成太阳码并上传OSS
func PcCreateAndUploadSunCode(scene, page string) (imgUrl string, err error) {
	if page == "" {
		err = errors.New("page不能为空")
		return
	}

	// scene超过32位会生成失败,md5处理至32位
	sceneMD5 := "a=1"
	if scene != "" {
		sceneMD5 = utils.MD5(scene)
	}
	picByte, err := GetSunCode(page, sceneMD5)
	if err != nil {
		return
	}
	// 生成图片
	localPath := "./static/imgs"
	fileName := utils.GetRandStringNoSpecialChar(28) + ".png"
	fpath := fmt.Sprint(localPath, "/", fileName)
	f, err := os.Create(fpath)
	if err != nil {
		fmt.Println("11111")
		return
	}
	if _, err = f.Write(picByte); err != nil {
		return
	}
	defer func() {
		f.Close()
		os.Remove(fpath)
	}()
	// 上传OSS
	fileDir := "yb/suncode/"

	//上传到阿里云 和 minio
	//if utils.ObjectStorageClient == "minio" {
	//	imgUrl, err = UploadMinIoToDir(fileName, fpath, "", fileDir)
	//	if err != nil {
	//		return
	//	}
	//} else {
	//	imgUrl, err = UploadAliyunToDir(fileName, fpath, "", fileDir)
	//	if err != nil {
	//		return
	//	}
	//}
	savePath := fileDir + time.Now().Format("200601/20060102/") + fileName
	ossClient := NewOssClient()
	if ossClient == nil {
		err = fmt.Errorf("初始化OSS服务失败")
		return
	}
	imgUrl, err = ossClient.UploadFile(fileName, fpath, savePath)
	if err != nil {
		err = fmt.Errorf("文件上传失败, Err: %s", err.Error())
		return
	}

	if err != nil {
		return
	}
	// 记录参数
	if scene != "" {
		newSuncode := &models.YbPcSuncode{
			Scene:      scene,
			SceneMd5:   sceneMD5,
			CodePage:   page,
			SuncodeUrl: imgUrl,
			CreateTime: time.Now(),
		}
		err = models.AddYbPcSunCode(newSuncode)
	}
	// 记录参数md5
	if scene != "" {
		newPars := &models.YbSuncodePars{
			Scene:      scene,
			SceneKey:   sceneMD5,
			CreateTime: time.Now(),
		}
		err = models.AddYbSuncodePars(newPars)
	}
	return
}

// CreateNewReport 创建新报告
func CreateNewReport(req models.AddReq, adminInfo *system.Admin) (item *models.Report, errMsg string, err error) {
	contentSub := ""
	if req.Content != "" {
		e := utils.ContentXssCheck(req.Content)
		if e != nil {
			errMsg = "存在非法标签"
			err = errors.New("存在非法标签, Err: " + e.Error())
			return
		}
		contentClean, e := FilterReportContentBr(req.Content)
		if e != nil {
			errMsg = "内容去除前后空格失败"
			err = errors.New("内容去除前后空格失败, Err: " + e.Error())
			return
		}
		req.Content = contentClean

		sub, e := GetReportContentSub(req.Content)
		if e != nil {
			go alarm_msg.SendAlarmMsg("ContentSub 失败,Err:"+e.Error(), 3)
		}
		contentSub = sub
	}
	maxStage, e := models.GetReportStage(req.ClassifyIdFirst, req.ClassifyIdSecond, req.ClassifyIdThird)
	if e != nil {
		errMsg = "期数获取失败!"
		err = errors.New("期数获取失败,Err:" + e.Error())
		return
	}

	item = new(models.Report)
	item.AddType = req.AddType
	item.ClassifyIdFirst = req.ClassifyIdFirst
	item.ClassifyNameFirst = req.ClassifyNameFirst
	item.ClassifyIdSecond = req.ClassifyIdSecond
	item.ClassifyNameSecond = req.ClassifyNameSecond
	item.Title = req.Title
	item.Abstract = req.Abstract
	item.Author = req.Author
	item.Frequency = req.Frequency
	item.State = req.State
	item.Content = html.EscapeString(req.Content)
	item.Stage = maxStage + 1
	item.ContentSub = html.EscapeString(contentSub)
	item.CreateTime = req.CreateTime
	item.ModifyTime = time.Now()
	item.ReportVersion = req.ReportVersion
	item.AdminId = adminInfo.AdminId
	item.AdminRealName = adminInfo.RealName

	item.ClassifyIdThird = req.ClassifyIdThird
	item.ClassifyNameThird = req.ClassifyNameThird
	// 产品要求,如果是多人协作,那么就是章节类型的报告
	if req.CollaborateType == 2 {
		item.HasChapter = 1
		item.ChapterType = ""
	}
	item.LastModifyAdminId = adminInfo.AdminId
	item.LastModifyAdminName = adminInfo.RealName
	item.ContentModifyTime = time.Now()
	item.NeedSplice = 1
	item.ContentStruct = html.EscapeString(req.ContentStruct)
	item.HeadImg = req.HeadImg
	item.EndImg = req.EndImg
	item.CanvasColor = req.CanvasColor
	item.HeadResourceId = req.HeadResourceId
	item.EndResourceId = req.EndResourceId
	item.CollaborateType = req.CollaborateType
	item.ReportLayout = req.ReportLayout
	item.IsPublicPublish = req.IsPublicPublish
	item.ReportCreateTime = time.Now()

	reportDate := time.Now()
	t, _ := time.ParseInLocation(utils.FormatDate, req.CreateTime, time.Local)
	if !t.IsZero() {
		reportDate = t
	}
	err, errMsg = AddReportAndChapter(item, 0, req.GrantAdminIdList, reportDate)

	return
}

// FilterReportContentBr 过滤报告正文前后换行符
func FilterReportContentBr(content string) (res string, err error) {
	newContent := content
	//content = `<p style=\"font-size: 16px;\"><br></p><p style=\"font-size: 16px;\"><br></p><p style=\"font-size: 16px;\"><br></p><p style=\"font-size: 16px;\"><br></p><p style=\"font-size: 16px;\"><br></p><p style=\"font-size: 16px;\"><br></p><p style=\"font-size: 16px;\"><br></p><p style=\"font-size: 16px;\"><br></p><p style=\"font-size: 16px;\"><br></p><p style=\"font-size: 16px;\"><strong>四季度验证投产预期</strong></p><p style=\"font-size: 16px;\"><strong>&nbsp;</strong></p><p style=\"font-size: 16px;\"><strong>PTA:<strong><strong>近端短缺的格局出现缓解的迹象,表现在:PX进口回升;国内重整及常减压提负;PTA、PX投产在即</strong></strong><strong>。正套部分或全部止盈。</strong></strong></p><p style=\"font-size: 16px;\"><strong>&nbsp;</strong></p><p style=\"font-size: 16px;\"><strong>乙二醇:</strong><strong style=\"font-weight: 700; color: rgb(0, 0, 0); font-family: ;\">到港预报集中的情况下仍在去库,4200-4600区间震荡操作,节前没有明显方向,不建议在节前备货的时间段布局空单</strong><strong>。</strong></p><p style=\"font-size: 16px;\"><strong>&nbsp;</strong></p><p style=\"font-size: 16px;\"><strong>1、PX国内供应本周回落,PTA工厂负荷变动滞后于PX装置。</strong></p><p style=\"font-size: 16px;\">PX装置变动:</p><p style=\"font-size: 16px;\">海南炼化一期66万吨PX装置因故障停车检修,重启时间待跟踪,其二期100万吨PX装置预计在此装置重启后停车检修。</p><p style=\"font-size: 16px;\">天津石化一套100万吨重整已于20日重启中,其39万吨PX预计下周初出产品。</p><p style=\"font-size: 16px;\">韩国SK 位于仁川的130万吨PX装置按计划在23日停车检修,计划检修时长45天左右。</p><p style=\"font-size: 16px;\">截至周五,中国国内PX负荷小幅回落至73.4%(前值<span style=\"color: rgb(65, 65, 65); font-family: sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;\">76.8</span>%),亚洲PX负荷小幅回落至68.7%(<span style=\"color: rgb(65, 65, 65); font-family: sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;\">72</span>%)。</p><p style=\"font-size: 16px;\"><img src=\"https://hongze.oss-accelerate.aliyuncs.com/static/images/202209/20220925/4VcA2eUE1Sgkx0KQ0NjchM0ajIis.png\" class=\"fr-fic fr-dib fr-draggable\"></p><p style=\"font-size: 16px;\"><img src=\"https://hongze.oss-accelerate.aliyuncs.com/static/images/202209/20220925/vi3laEb3qejWISetD0SjGTwuAxUg.png\" class=\"fr-fic fr-dib fr-draggable\"></p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=760c86a78c35ab9286903e9ce52a6682\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe></p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=1e36d11158bf146313f3f65a65dbc5f3\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe></p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=7a69494b1a84520b2cdf1dccb3c78bda\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe></p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=0a2e374c0689d5fba4a9dc40474a33b0\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe></p><p style=\"font-size: 16px;\">PXN本周延续回落至380美金附近。</p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=ad1b869f60ab31060730e8bd58260d8c\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe></p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=d1c87cb3adff22aea0fc37dfb1870626\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe></p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=bac98256b0b86e92ed4084fbbd223f5b\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe></p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><span style=\"font-size: 16px; font-family: Arial, Helvetica, sans-serif;\">PX平衡表</span></p><p style=\"margin: 0px; padding: 0px; font-size: 16px; color: rgb(0, 0, 0); font-family: ;\">海关统计,国内8月PX进口总量在78.8万吨,环比增加17.3万吨,增幅28%;同比减少30.8万吨,降幅28.1%;8月PX出口量0.47万吨,环比下降5万吨。</p><p style=\"margin: 0px; padding: 0px; font-size: 16px; color: rgb(0, 0, 0); font-family: ;\"><span style=\"color: rgb(0, 0, 0); font-family: ;\">PX 8月进口量大幅回升至79万吨附近,其中8月从韩国进口的PX量达到33.65万吨。9月目前公布的1-20号从韩国进口PX的量已经接近8月全月的水平,即环比8月仍是大幅增加的情况:</span><span style=\"font-size: 16px;\">据悉,9月1-20日韩国PX出口总量在30.9万吨,其中出口至中国27.9万吨。</span></p><p style=\"margin: 0px; padding: 0px; font-size: 16px; color: rgb(0, 0, 0); font-family: ;\"><span style=\"font-size: 16px;\">预计9月进口量环比8月进一步增加。</span></p><p style=\"margin: 0px; padding: 0px; font-size: 16px; color: rgb(0, 0, 0); font-family: ;\"><span style=\"font-size: 16px;\"><img src=\"https://hongze.oss-accelerate.aliyuncs.com/static/images/202209/20220925/TD59rptBDNwJ7J2qpxd8HXi4X5cQ.png\" class=\"fr-fic fr-dib fr-draggable\"></span></p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><strong><span style=\"color: rgb(0, 0, 0); font-family: ;\">原油本周偏弱,欧美汽油利润本周均出现了明显回升。</span></strong></p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><strong><span style=\"color: rgb(0, 0, 0); font-family: ;\"><span style=\"color: rgb(34, 34, 34); font-family: system-ui, -apple-system, BlinkMacSystemFont, ;\">美国飓风将在下周登陆墨西哥湾,届时或将影响海上钻机的运行以及炼厂开工。</span>&nbsp;</span></strong></p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=ef172d65e20b986351ed50545f3d36d1\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe></p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=4930c0981fc33ab125e6ef346c9cbd5b\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe></p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=f0cae34883508273d482d4cf8c577410\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe></p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><strong>2、</strong><strong>乙烯连续跌价至900美金,PX投产压力临近PXN延续压缩。石脑油亏损本周延续修复。</strong></p><p style=\"font-size: 16px;\">PTA:按照PX11-12月上1054美金(石脑油672美金,Brent86.15美金)计算,醋酸3075元,目前含醋酸的原料成本在5670元附近。可以发现虽然Brent和PX环比上周都出现了明显的下跌,但石脑油相对上周环比上涨,石脑油亏损本周延续修复,目前石脑油-Brent价差回升至0以上。</p><p style=\"font-size: 16px;\">给到200-300的最低加工成本,PTA的估值在5870-5970元。周五日盘收盘后TA11合约5742,11月及之后的PTA合约均亏损。</p><p style=\"font-size: 16px;\">PTA基差再度回升至1000附近,周五小幅走弱至970。</p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=3e743a3907292d9ad2dce6033ae7d8a4\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe></p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><img src=\"https://hongze.oss-accelerate.aliyuncs.com/static/images/202209/20220925/Csak38HlAbt8XsbBsPeSWlaUKJiO.png\" class=\"fr-fic fr-dib fr-draggable\"></p><p style=\"font-size: 16px;\"><img src=\"https://hongze.oss-accelerate.aliyuncs.com/static/images/202209/20220925/LOPKDaDnRnbJauWqlvbhQ5VNxa03.png\" class=\"fr-fic fr-dib fr-draggable\"></p><p style=\"font-size: 16px;\"><img src=\"https://hongze.oss-accelerate.aliyuncs.com/static/images/202209/20220925/Ocdq2m3bMDqZnM8PTXVyj8XILt7Z.png\" class=\"fr-fic fr-dib fr-draggable\"></p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=268b3f7204aa21accb8d292154cf4e3c\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe></p><p style=\"font-size: 16px;\">乙二醇:静态来看,按照盘面(煤价按照900元),锚定石脑油672美金,乙烯900美金,甲醇2640元,北美乙烷价格38美分/加仑计算,乙二醇的综合成本仍在5050元附近。周五日盘收盘01合约按照综合成本亏损700元附近。</p><p style=\"font-size: 16px;\">国内外采乙烷制乙二醇目前扭亏为盈。</p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=f1e3ba1df230353571d00af2dfb7e92a\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe></p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=0d17c186dda211dab039f2ccd39a8d76\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe></p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=3a93cb16f02731bc5c74b560f9590456\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe></p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=e1a38d9058b719d8dd5bf746bc9739be\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe></p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><img src=\"https://hongze.oss-accelerate.aliyuncs.com/static/images/202209/20220925/drjYJ468Tpnr3Bno52CQZXRuayow.png\" class=\"fr-fic fr-dib fr-draggable\"></p><p style=\"font-size: 16px;\"><img src=\"https://hongze.oss-accelerate.aliyuncs.com/static/images/202209/20220925/bv4JvZN7OxhXFnx0xL0EW6yGFlX8.png\" class=\"fr-fic fr-dib fr-draggable\"></p><p style=\"font-size: 16px;\"><img src=\"https://hongze.oss-accelerate.aliyuncs.com/static/images/202209/20220918/54TYCFo1ulvOhbJpk9jQPJcnDyan.png\" class=\"fr-fic fr-dib fr-draggable\"></p><p style=\"font-size: 16px;\"><img src=\"https://hongze.oss-accelerate.aliyuncs.com/static/images/202209/20220925/fZayI9g8kS2ILeVu799dBnAdugNB.png\" class=\"fr-fic fr-dib fr-draggable\"></p><ol style=\"margin: 0px; padding: 0px; list-style: none; color: rgb(0, 0, 0); font-family: ;\"><li style=\"margin: 0px; padding: 0px; font-size: 16px;\"><strong>3、</strong><span style=\"font-size: 16px; color: rgb(0, 0, 0); font-family: ;\"><strong>需求端本周仍偏弱:继上周加弹负荷下滑后,本周织造负荷下滑。延续坯布库存回升同时原料库存下降,聚酯连续累库(瓶片低库存优势也明显减弱),两家大厂减产执行过程和节前备货中和,因此减产去库成效甚微</strong><strong>。</strong></span><span style=\"font-size: 16px;\">&nbsp;</span></li><li style=\"margin: 0px; padding: 0px; font-size: 16px;\"><span style=\"font-size: 18px !important; color: rgb(0, 0, 0); font-family: Tahoma, ;\">终端:江浙加弹综合开工微幅回升至77%(前值</span><span style=\"font-size: 16px; color: rgb(0, 0, 0); font-family: Tahoma, ;\">76</span><span style=\"font-size: 18px !important; color: rgb(0, 0, 0); font-family: Tahoma, ;\">%);江浙织机综合开工回落至69%(前值</span><span style=\"font-size: 16px; color: rgb(0, 0, 0); font-family: Tahoma, ;\">71</span><span style=\"font-size: 18px !important; color: rgb(0, 0, 0); font-family: Tahoma, ;\">%);</span><span style=\"font-size: 18px !important; color: rgb(0, 0, 0); font-family: Tahoma, ;\">江浙印染综合开工维持在77%</span><span style=\"font-size: 18px !important; color: rgb(0, 0, 0); font-family: Tahoma, ;\">&nbsp;。</span></li><li style=\"margin: 0px; padding: 0px; font-size: 16px;\"><span style=\"font-size: 18px !important; color: rgb(0, 0, 0); font-family: Tahoma, ;\">本周,涤丝仅周三稍有放量,整体涤丝销售氛围偏弱为主。终端在新订单氛围走弱和成本端偏弱氛围下,原料不再进一步跟进,消化前期备货为主,综合原料备货有所下降。截至目前,原料备货集中在10-15天,偏高备货至10月底。</span></li><li style=\"margin: 0px; padding: 0px; font-size: 16px;\"><span style=\"font-size: 18px !important; color: rgb(0, 0, 0); font-family: Tahoma, ;\">订单情况:近期的织造端新单氛围整体走弱明显,前期较好的圆机和经编工厂尤为明显,出货量也有所放缓,部分工厂生产前期订单为主。</span><br><span style=\"font-size: 18px !important; color: rgb(0, 0, 0); font-family: Tahoma, ;\">直接需求:</span>近期装置轮动检修与重启,长丝大厂陆续执行减产动作,但也有几套切片装置恢复,整体而言聚酯负荷仍以区间波动为主。截至本周五,初步核算聚酯负荷在83.9%(前值84.3%)。</li></ol><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=9c163c32bf7fca689c0067e285eb1a30\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe></p><p style=\"font-size: 16px;\">轻纺城成交量节前震荡回升但仍在偏低水平。</p><p style=\"font-size: 16px;\"><img src=\"https://hongze.oss-accelerate.aliyuncs.com/static/images/202209/20220925/sHBC03ZwLXP1jUK1mDdd0hUjEtQo.png\" class=\"fr-fic fr-dib fr-draggable\"></p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=5e2a381802d34c5cf33502d8a9649bd6\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe></p><p style=\"text-align: left; margin-top: 10px; font-size: 16px;\"><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=e47bcc409b9b7e9178805ac6c4a00bc1\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe><br></p><p style=\"font-size: 16px;\"><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=12be062cbc0c61819f99648cef6e2740\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe><br></p><p style=\"font-size: 16px;\"><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=fea70f6d5bf7f1899394be0619cc2da1\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe><br><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=8a50b210b7ebb4fbb890d8ad58a817f6\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe><br><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=800bf3710951ca96c2e5a3693c94a20d\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe><br><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=fd1bff8836af41d0c32d0ed168c8b748\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe><br><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=baf493ba32b3c39e070e24ac5546fd6b\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe></p><ul style=\"margin: 0px; padding: 0px; list-style: none; color: rgb(0, 0, 0); font-family: ;\"><li style=\"margin: 0px; padding: 0px; font-size: 16px;\"><strong>4、PTA行情沙盘推演<strong>2022.9.23:</strong><strong>PTA近端短缺的格局出现缓解的迹象,表现在:PX进口回升;国内重整及常减压提负;PTA、PX投产在即</strong></strong><strong>。正套部分或全部止盈。</strong></li></ul><p style=\"font-size: 16px;\"><img style=\"width: 100%;\" src=\"https://hzstatic.hzinsights.com/static/images/202209/20220922/d1HYjIFoBG9L2bGuWrXq7sBPpnT7.png\" class=\"fr-fic fr-dii fr-draggable\"><br></p><p style=\"font-size: 16px;\">PTA库存结构变化跟踪:本期PTA库存大幅去化17.9万吨附近(本周仓单集中注销,仓单库存大幅下降至0附近),聚酯成品折算PTA库存大幅累库9.3万吨,叠加PTA库存在聚酯成品库存累库的情况下去库8.6万吨。</p><p style=\"font-size: 16px;\"><img src=\"https://hongze.oss-accelerate.aliyuncs.com/static/images/202209/20220925/qYivQYoLkxJrmWGI5kNOy8i05q8P.png\" class=\"fr-fic fr-dib fr-draggable\"><img src=\"https://hongze.oss-accelerate.aliyuncs.com/static/images/202209/20220925/cvLkXlLwczkvzktkN4R2SKCoHFby.png\" class=\"fr-fic fr-dib fr-draggable\" style=\"width: 572px;\"></p><p style=\"font-size: 16px;\"><img src=\"https://hongze.oss-accelerate.aliyuncs.com/static/images/202209/20220925/EzRc4yuCqVcbdw2lb5FS2MCWvHd1.png\" class=\"fr-fic fr-dib fr-draggable\" style=\"width: 595px;\"></p><p style=\"font-size: 16px;\">PTA平衡表——按照Q4有500万吨新装置投产(东营威联化学250万吨及嘉通能源250万吨分别在11、12月计入产能基数)计算,按照9-10月聚酯月均负荷84%(下调1%)、87%(下调1%)预估,8-12月出口预计25万吨附近。8-10月目前预估均为去库格局。</p><p style=\"font-size: 16px;\">PX折算PTA与PTA合计9月去库幅度修正后大幅收窄。</p><p style=\"font-size: 16px;\"><img src=\"https://hongze.oss-accelerate.aliyuncs.com/static/images/202209/20220925/6VzQkr5nkbeqlCakRzTvZgl1PeFE.png\" class=\"fr-fic fr-dib fr-draggable\"></p><p style=\"margin: 0px; padding: 0px; font-size: 16px;\"><br></p><p style=\"margin: 0px; padding: 0px; font-size: 16px;\"><strong style=\"color: rgb(0, 0, 0); font-family: ;\">5、</strong><strong style=\"color: rgb(0, 0, 0); font-family: ;\">乙二醇行情沙盘推演2022.9.23:到港预报集中的情况下仍在去库,4200-4600区间震荡操作,节前没有明显方向,不建议在节前备货的时间段布局空单。</strong></p><p style=\"margin: 0px; padding: 0px; font-size: 16px;\"><strong style=\"color: rgb(0, 0, 0); font-family: ;\"><img style=\"width: 100%;\" src=\"https://hzstatic.hzinsights.com/static/images/202209/20220916/e5XTMMmx04X6wpKITZ2NgjUyz8sI.png\" class=\"fr-fic fr-dii fr-draggable\"></strong><br></p><p style=\"margin: 0px; padding: 0px; font-size: 16px;\">乙二醇国内供需:</p><ul style=\"margin: 0px; padding: 0px; list-style: none; color: rgb(0, 0, 0); font-family: ;\"><li style=\"margin: 0px; padding: 0px; font-size: 16px;\"><span style=\"color: rgb(0, 0, 0); font-family: Arial, Helvetica, sans-serif; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 28px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline !important;\">乙二醇负荷低位仍在下降:截至9月22日,中国大陆地区乙二醇整体开工负荷在43.98%(较上期下降2.44%),其中煤制乙二醇开工负荷在28.67%(较上期下降2.08%)。</span><span style=\"font-family: Arial, Helvetica, sans-serif;\">&nbsp;</span></li><li style=\"margin: 0px; padding: 0px; font-size: 16px;\"><span style=\"font-family: Arial, Helvetica, sans-serif;\">后续供应存增加预期:</span></li><li style=\"margin: 0px; padding: 0px; font-size: 16px;\"><span style=\"font-family: Arial, Helvetica, sans-serif;\">上周意外停车的大连大型装置预计本周末或下周初开车。</span></li><li style=\"margin: 0px; padding: 0px; font-size: 16px;\"><span style=\"font-family: Arial, Helvetica, sans-serif;\">内蒙古40万吨装置装置周内正常出料,负荷回升中。</span></li><li style=\"margin: 0px; padding: 0px; font-size: 16px;\"><span style=\"font-family: Arial, Helvetica, sans-serif;\">陕西30万吨装置将于近日重启,预计9月底前后出料;内蒙古26万吨装置计划本月底前后投料重启。</span></li><li style=\"margin: 0px; padding: 0px; font-size: 16px;\"><span style=\"font-family: Arial, Helvetica, sans-serif;\"><img src=\"https://hongze.oss-accelerate.aliyuncs.com/static/images/202209/20220925/Yy4lTK54zBA3ifN4DFdpAhE1TQ4w.png\" class=\"fr-fic fr-dib fr-draggable\"></span><img src=\"https://hongze.oss-accelerate.aliyuncs.com/static/images/202209/20220925/eXC4GZApxmJQLQSZZ15HV6J1nGdK.png\" class=\"fr-fic fr-dib fr-draggable\"></li></ul><p style=\"font-size: 16px;\">乙二醇到港预报与实际到港:</p><p style=\"font-size: 16px;\"><span style=\"font-size: 16px; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; font-family: Arial, Helvetica, sans-serif; text-indent: 32px; float: none; display: inline !important;\"><span style=\"color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 32px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline !important;\">隆众口径:截至9月29日,国内乙二醇华东总到港量预计在19.21万吨,较上一期增加3.45万吨,提升21.93个百分点。</span>&nbsp;</span></p><p style=\"font-size: 16px;\"><span style=\"font-size: 16px; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; font-family: Arial, Helvetica, sans-serif; text-indent: 32px; float: none; display: inline !important;\">港口发货节前回升。</span></p><p style=\"font-size: 16px;\"><br></p><p style=\"font-size: 16px;\"><img src=\"https://hongze.oss-accelerate.aliyuncs.com/static/images/202209/20220925/WXVwl3NV0U68hnEjeNX5RFPGowq3.png\" class=\"fr-fic fr-dib fr-draggable\"></p><p style=\"font-size: 16px;\"><img src=\"https://hongze.oss-accelerate.aliyuncs.com/static/images/202209/20220925/2FuGYgp5dpx6XbCNXLdSzdh4uzvp.png\" class=\"fr-fic fr-dib fr-draggable\"></p><p style=\"font-size: 16px;\">海外装置:</p><p style=\"font-size: 16px;\">印度IOC 32.5万吨装置将于近期停车技改,预计停车将持续至12月份。</p><p style=\"font-size: 16px;\">伊朗 Marun 44.5万吨装置目前处于停车状态,该装置此前货源供应印度市场为主。</p><p style=\"font-size: 16px;\">美国Sasol 28万吨装置计划于10月上旬停车检修,预计检修时长在一个月附近。</p><p style=\"font-size: 16px;\"><img src=\"https://hongze.oss-accelerate.aliyuncs.com/static/images/202209/20220925/CRzzaHscEcvhW8KXdajvLqABw11g.png\" class=\"fr-fic fr-dib fr-draggable\"></p><ul style=\"margin: 0px; padding: 0px; list-style: none; color: rgb(0, 0, 0); font-family: ;\"><li style=\"margin: 0px; padding: 0px; font-size: 16px;\">库存:</li><li style=\"margin: 0px; padding: 0px; font-size: 16px;\">隆众口径:<span style=\"font-size: 16px; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; font-family: Arial, Helvetica, sans-serif; text-indent: 32px; float: none; display: inline !important;\">截至9月22日,华东主港地区MEG港口库存总量81.6万吨,较上一统计周期减少3.64万吨,降低4.27%。受周末台风天气影响,主港本周到货延迟且整体出货尚可,本周港口库存延续去库走势。</span></li></ul><ul style=\"margin: 0px; padding: 0px; list-style: none;\"><li style=\"margin: 0px; padding: 0px; color: rgb(0, 0, 0); font-family: ;\">节前备货,聚酯工厂的乙二醇备货量本周小幅回升至84万吨附近。</li><li><br></li><li><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=c13c3e669ae5940893d1fd0e669754a5\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe></li><li><iframe src=\"https://chartlib.hzinsights.com/chartshow?code=0fac897a91cbfcdb67958ae9e5d039a7\" width=\"100%\" height=\"350\" style=\"border-width:0px; min-height:350px;\"></iframe></li><li style=\"margin: 0px; padding: 0px;\"><span style=\"font-size: 16px; font-family: Arial, Helvetica, sans-serif;\">乙二醇平衡表:</span></li><li style=\"margin: 0px; padding: 0px; font-size: 16px;\"><span style=\"color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; float: none; display: inline !important;\">2022年8月我国乙二醇当月进口量为598134.40吨,累计进口量为5189987.09吨,进口量环比升4.83%,进口量同比下跌23.97%,累计进口量比去年同期降9.28%。&nbsp;</span></li><li style=\"margin: 0px; padding: 0px; font-size: 16px;\"><span style=\"font-family: Arial, Helvetica, sans-serif;\">按照9-10月聚酯月均负荷84%、87%,8月进口量比预估略多,9月因受到台风影响到港持续延迟,压力预计在9月下旬至9月底显现,因此预计也只有55万吨附近,Q4进口预计仍有差别,10-12月目前预计进口60-65万吨(其中10月或偏多)。</span></li><li style=\"margin: 0px; padding: 0px; font-size: 16px; font-family: Arial, Helvetica, sans-serif;\">进口量调整后,8月去库收窄至16万吨偏下,9月目前预计去库14万吨附近,10月累库压力来自于到港集中及新装置开始贡献产量,11月累库压力来自于需求回落+新装置产量提升。</li><li style=\"margin: 0px; padding: 0px; font-size: 16px; font-family: Arial, Helvetica, sans-serif;\">11-12月警惕供应端的超预期缩量。</li><li style=\"margin: 0px; padding: 0px; font-size: 16px; font-family: Arial, Helvetica, sans-serif;\"><img src=\"https://hongze.oss-accelerate.aliyuncs.com/static/images/202209/20220925/VEW93DsD4vrzXuNUfTMCFiJSU8Y3.png\" class=\"fr-fic fr-dib fr-draggable\"></li></ul><p style=\"font-size: 16px;\"><br></p><p style=\"font-size: 16px;\"><br></p><p style=\"font-size: 16px;\"><br></p><p style=\"font-size: 16px;\"><br></p><p style=\"font-size: 16px;\"><br></p><p style=\"font-size: 16px;\"><br></p><p style=\"font-size: 16px;\"><br></p><p style=\"font-size: 16px;\"><br></p>`
	content = html.UnescapeString(content)
	if content == "" {
		return
	}
	// 过滤编辑器版权html
	content = strings.Replace(content, "<p data-f-id=\"pbf\" style=\"text-align: center; font-size: 14px; margin-top: 30px; opacity: 0.65; font-family: sans-serif;\">Powered by <a href=\"https://www.froala.com/wysiwyg-editor?pb=1\" title=\"Froala Editor\">Froala Editor</a></p>", "", -1)

	defer func() {
		if err != nil {
			go alarm_msg.SendAlarmMsg("过滤报告正文前后换行符及空格失败, ErrMsg: "+err.Error(), 3)
		}
	}()

	// 做一个配置,有问题的时候随时关闭
	configKey := "report_filter_br"
	conf, e := company.GetConfigDetailByCode(configKey)
	if e != nil {
		err = errors.New("获取报告过滤配置失败, Err: " + e.Error())
		return
	}
	if conf.ConfigValue != "1" {
		return content, nil
	}

	// 找出所有<p>标签, <p>标签的索引
	re := regexp.MustCompile(`(?is:<p(.*?)</p>)`)
	arr := re.FindAllString(content, -1)
	indexArr := re.FindAllIndex([]byte(content), -1)

	// 空<p>正则
	emptyRe := `<p[^>]*>(<br>|<br/>)+</p>`
	startIsBr := false
	countEmptyBr := 0 // 需要连续替换的空<p>总数
	lastBrRange := 0  // 最后一个空<p>右侧index, 用来判断是否为连续的空<p>

	// 注:以下逻辑只适用于去除前面的空行, 由于编辑器始终会在文章最后面跟上自己的html标签, 此处不再进行后面空行的去除=_=!
	for i := range arr {
		byteRange := indexArr[i]
		if len(byteRange) == 2 {
			// 内容开头不为<p>直接跳出遍历, 否则才进行空<p>的判断
			if i == 0 && byteRange[0] == 0 {
				startIsBr = true
			}
			if !startIsBr {
				break
			}
			if lastBrRange != 0 {
				// 说明不是连续的空<p>, 中间出现了其他标签, 那么结束遍历, 进行最终的文本替换
				if lastBrRange != byteRange[0] {
					break
				}
			}
			// 正则匹配为空<p>则计数, 记录该空<p>右侧index
			m, e := regexp.Match(emptyRe, []byte(arr[i]))
			if e != nil {
				err = e
				return
			}
			if m {
				countEmptyBr += 1
				lastBrRange = byteRange[1]
				continue
			}
			// 遍历到该<p>标签不为空了, 结束遍历
			break
		}
	}
	if countEmptyBr > 0 {
		reg, e := regexp.Compile(emptyRe)
		if e != nil {
			err = errors.New("正则解析失败, Err: " + e.Error())
			return
		}
		counted := 0 // 已替换数
		res = reg.ReplaceAllStringFunc(content, func(s string) string {
			counted += 1
			if counted <= countEmptyBr {
				return ""
			} else {
				return s
			}
		})
		if res == "" {
			res = newContent
		}
	} else {
		res = content
		if res == "" {
			res = newContent
		}
	}
	return
}

// GetEnglishReportOverview 获取英文研报overview部分
func GetEnglishReportOverview(content string) (res string, err error) {
	content = html.UnescapeString(content)
	doc, e := goquery.NewDocumentFromReader(strings.NewReader(content))
	if e != nil {
		err = errors.New("Create Doc Err: " + e.Error())
		return
	}

	target := "overview"
	label := "</strong>"
	start := -1
	end := -1
	doc.Find("p").Each(func(i int, s *goquery.Selection) {
		h, e := s.Html()
		if e != nil {
			err = errors.New("Get Html1 Err: " + e.Error())
			return
		}
		h = strings.ToLower(h)
		t := s.Text()
		t = strings.ToLower(t)

		if strings.Contains(h, label) && t != "" && strings.Contains(t, target) {
			start = i
		}
		if start != -1 && end == -1 && i > start && strings.Contains(h, label) {
			end = i
		}
	})

	if start != -1 && end != -1 {
		doc.Find("p").Each(func(i int, s *goquery.Selection) {
			if i > start && i < end {
				h, e := s.Html()
				if e != nil {
					err = errors.New("Get Html2 Err: " + e.Error())
					return
				}
				// 包含iframe则过滤掉
				if strings.Contains(h, "iframe") {
					return
				}
				res += `<p>` + h + `</p>`
			}
		})
	}
	return
}

// GetReportContentSubWithoutIframe 获取报告正文前几段,过滤iframe
func GetReportContentSubWithoutIframe(content string) (contentSub string, err error) {
	content = html.UnescapeString(content)
	doc, err := goquery.NewDocumentFromReader(strings.NewReader(content))
	if err != nil {
		fmt.Println("create doc err:", err.Error())
		return
	}
	label := "iframe"
	n := 0
	doc.Find("p").Each(func(i int, s *goquery.Selection) {
		if n >= 5 {
			return
		}
		n++
		h, err := s.Html()
		if err != nil {
			fmt.Println("get html err", err.Error())
			return
		}
		// 包含iframe则过滤掉
		if strings.Contains(h, label) {
			return
		}
		if s.Text() != "" || strings.Contains(h, "src") {
			contentSub = contentSub + "<p>" + h + "</p>"
		}
	})
	return
}

// UpdateReportEditMark 更新研报当前更新状态
// status 枚举值 1:编辑中, 2:只做查询,3:完成编辑
func UpdateReportEditMark(reportId, reportChapterId, nowUserId, status int, nowUserName, lang string) (ret models.MarkReportResp, err error) {
	//更新标记key
	key := fmt.Sprint(`crm:report:edit:`, reportId)
	//  章节id不为0则加上章节id
	if reportChapterId > 0 {
		key = fmt.Sprint(key, ":", reportChapterId)
	}
	ret.Status = 0
	ret.Msg = "无人编辑"

	opUserId, e := utils.Rc.RedisInt(key)
	var opUser models.MarkReportItem
	var classifyNameFirst string
	if e != nil {
		opUserInfoStr, tErr := utils.Rc.RedisString(key)
		if tErr == nil {
			tErr = json.Unmarshal([]byte(opUserInfoStr), &opUser)
			if tErr == nil {
				opUserId = opUser.AdminId
			}
		}
	}
	//判断是否是晨报或者周报,如果是则跳过
	var reportInfo *models.ReportDetail
	classifyNameFirst = opUser.ReportClassifyNameFirst
	if reportId > 0 && status != 2 && classifyNameFirst == "" {
		//查询报告ID信息
		reportInfo, err = models.GetReportById(reportId)
		if err != nil {
			err = fmt.Errorf("报告不存在")
			return
		}
		classifyNameFirst = reportInfo.ClassifyNameFirst
	}

	if opUserId > 0 && opUserId != nowUserId {
		editor := opUser.Editor
		if editor == "" {
			//查询账号的用户姓名
			otherInfo, e := system.GetSysAdminById(opUserId)
			if e != nil {
				err = fmt.Errorf("查询其他编辑者信息失败")
				return
			}
			editor = otherInfo.RealName
		}

		ret.Status = 1
		if lang == utils.EnLangVersion {
			ret.Msg = fmt.Sprintf("%s is currently editing the report", editor)
		} else {
			ret.Msg = fmt.Sprintf("当前%s正在编辑报告", editor)
		}
		ret.Editor = editor
		return
	}
	if status == 1 {
		nowUser := &models.MarkReportItem{AdminId: nowUserId, Editor: nowUserName, ReportClassifyNameFirst: classifyNameFirst}
		bt, e := json.Marshal(nowUser)
		if e != nil {
			err = fmt.Errorf("格式化编辑者信息失败")
			return
		}
		if opUserId > 0 {
			utils.Rc.Do("SETEX", key, int64(utils.ReportPptEditingWait), string(bt)) //3分钟缓存
		} else {
			utils.Rc.SetNX(key, string(bt), utils.ReportPptEditingWait*time.Second) //3分钟缓存
		}
	} else if status == 3 {
		//完成编辑,开始清除编辑缓存
		_ = utils.Rc.Delete(key)
	}
	return
}

// HandleVideoDecibel 处理报告中的音频文件
func HandleVideoDecibel(chapterInfo *models.ReportChapter) {
	public_api.HandleVideoDecibel(chapterInfo.ReportChapterId)

	return
}

// SaveReportLogs 记录报告日志
func SaveReportLogs(item *models.Report, chapters []*models.ReportChapter, adminId int, adminRealName string) {
	if item == nil && len(chapters) == 0 {
		return
	}
	var err error
	defer func() {
		if err != nil {
			tips := fmt.Sprintf("报告日志记录, SaveReportLogs error: %s", err.Error())
			go alarm_msg.SendAlarmMsg(tips, 2)
		}
	}()

	if item != nil {
		e := models.AddReportSaveLog(item.Id, item.AdminId, item.Content, item.ContentSub, item.ContentStruct, item.CanvasColor, item.AdminRealName, item.HeadResourceId, item.EndResourceId)
		if e != nil {
			err = fmt.Errorf("AddReportSaveLog: %s", e.Error())
			return
		}
	}
	if len(chapters) > 0 {
		e := models.MultiAddReportChaptersSaveLog(chapters, adminId, adminRealName)
		if e != nil {
			err = fmt.Errorf("MultiAddReportChaptersSaveLog: %s", e.Error())
			return
		}
	}
	return
}