/**
 * 打开服务器上的文件
 * @param {*} fileUrl 文件url路径
 */
function OpenFile(params) {
	var l_strFileUrl = params.fileName //来自OA网页端的OA文件下载路径
	var doc
	var l_IsOnlineDoc = false //默认打开的是不落地文档
	if (!l_strFileUrl) return

	//判断是否打印
	//下载文档之前，判断是否已下载该文件
	if (
		pCheckIsExistOpenOADoc(l_strFileUrl) == true &&
		params.action !== 'printdocument'
	) {
		//如果找到相同OA地址文档，则给予提示
		//根据OA助手对是否允许再次打开相同文件的判断处理
		var l_AllowOADocReOpen = false
		l_AllowOADocReOpen = wps.PluginStorage.getItem(
			constStrEnum.AllowOADocReOpen
		)
		if (l_AllowOADocReOpen == false) {
			ShowMessage(
				'已打开相同的OA文件，请关闭之前的文件，再次打开',
				'warning',
				5
			)
			return null
		} else {
			//处理重复打开相同OA 文件的方法
			ShowConfirm('当前环境已打开该文件，是否重新再打开一份？', 'info', {
				btns: [
					{
						key: 'ok',
						text: '确定',
						primary: true,
						callback: function () {
							wps.WpsApplication().Documents.OpenFromUrl(l_strFileUrl, '', '')
							//重复打开的文档采用不落地的方式打开
							// 不落地方式打开文档判断落地比较多，V1版本先暂时关闭
							l_IsOnlineDoc = true
							doc = wps.WpsApplication().ActiveDocument
							pOpenFile(doc, params, l_IsOnlineDoc)
						},
					},
					{ key: 'cancel', text: '取消' },
				],
			})
		}
	} else {
		//如果当前没有打开文档，则另存为本地文件，再打开
		let fileName = GetFileNameByParams(params)
		if (params.action == 'taoda' && !!params.oldDocName)
			fileName = params.oldDocName
		DownloadFile(
			l_strFileUrl,
			fileName,
			params.action == 'printdocument' //打印文档操作保存随机路径
		)
			.then((path) => {
				if (path == '') {
					ShowMessage(
						'从服务端下载路径:' + l_strFileUrl + '\n' + '获取文件下载失败!',
						'error'
					)
					return null
				}

				doc = pDoOpenOADocProcess(params, path)
				pOpenFile(doc, params, l_IsOnlineDoc)
			})
			.catch((msg) => {
				ShowMessage(`下载文件[${fileName}]失败!${msg}`, 'error', 5)
				OAWebNotice(fileName)
			})
	}
}

/**
 * 作用：文档打开后执行的动作集合
 * @param {*} doc 文档对象
 * @param {*} params 前端传递的参数集合
 * @param {*} isOnlineDoc 在线打开/落地打开
 */
function pOpenFile(doc, params, isOnlineDoc) {
	var l_IsOnlineDoc = isOnlineDoc

	//设置当前文档为 本地磁盘落地模式
	if (l_IsOnlineDoc == true) {
		DoSetOADocLandMode(doc, EnumDocLandMode.DLM_OnlineDoc)
	} else {
		DoSetOADocLandMode(doc, EnumDocLandMode.DLM_LocalDoc)
	}

	var forceupload = false
	var action = params.action

	if (!!params.fileparam.WaterMark) {
		SetDocParamsValue(doc, constStrEnum.WaterMark, true)
		var args = [doc, params.fileparam.WaterMark]
		if (
			params.fileparam.WaterMarkParam &&
			params.fileparam.WaterMarkParam.length > 0
		) {
			var arr = params.fileparam.WaterMarkParam.split('|').filter(Boolean)
			if (arr.length == 4) args = args.concat(arr)
			else loginfo('水印参数错误,默认忽略')
		}
		WaterMark && WaterMark.SetWaterMark.apply(this, args)
		//doc.Save()
	}

	if (action != null) {
		switch (action) {
			case 'qinggao':
				clearRevDoc(doc) //清稿业务
				forceupload = true
				break
			case 'taoda':
				pInsertRInedHead(
					doc,
					wps.PluginStorage.getItem('ModelUrl'),
					wps.PluginStorage.getItem('ContentFieldName'),
					params
				)
				forceupload = true
				break
			case 'updateregion':
				UpdateRegion(doc, params)
				forceupload = true
				break
			case 'printdocument':
				UpdateRegion(doc, params)
				wps.OAAssist.WebNotify(doc.Name)
				break
			case 'gaizhang':
				pInsertYinzhang(
					doc,
					wps.PluginStorage.getItem('ModelUrl'),
					wps.PluginStorage.getItem('ContentFieldName')
				)
				forceupload = true
				break
			case 'convertpdf':
				OnDoChangeToOtherDocFormat('.pdf')
				break
			case 'convertofd':
				OnDoChangeToOtherDocFormat('.ofd')
				break
			case 'saveAs':
				if (getBoolean(params.fileparam.AutoAcceptRevisions, false)) {
					clearRevDoc(doc)
				}
				break
		}
	}

	var l_ProtectType = -1
	if (!!params.openType && params.openType.hasOwnProperty('protectType'))
		l_ProtectType = params.openType.protectType
	var l_bOpenRevision = false //初始化关闭修订模式
	var l_bShowRevision = getBoolean(params.fileparam.UseMark, true) //是否显示修订记录

	if (l_ProtectType == 0) {
		l_bOpenRevision = true
	}

	if (params.openType && params.openType.protectType > -1)
		SetOADocProtect(doc, params.openType.protectType, constStrEnum.docPassWord)

	var l_revisionmMode = getNumber(params.fileparam.MarkupMode, 1)
	//设置文档修订状态
	DoOADocOpenRevision(doc, l_bOpenRevision, l_bShowRevision, l_revisionmMode)

	//doc.Save()
	if (forceupload) {
		SetDocParamsValue(doc, constStrEnum.OriginalRsid, -1)
	}
	doc.Saved = true // 手动设定标志位
	if (
		!(l_ProtectType >= 2 || Heart.ACTIONS_WITHOUT_HEART.indexOf(action) != -1)
	) {
		//可编辑和非打印模式下才设置心跳
		//设定心跳值
		Heart.OpendOADocument(doc)
	}

	if (action == 'saveAs') {
		SaveAsAndClose(doc, params)
		return doc
	}

	if (params.fileparam.IsMaximization == false) {
		//静默模式
		doc.Close()
		return doc
	}

	// 触发切换窗口事件
	OnWindowActivate()

	loginfo('文档加载完成')
	setTimeout(function () {
		toggleBeforeOAfterLoading()

		//小文件二次调用，以保证loading窗口消失
		setTimeout(function () {
			toggleBeforeOAfterLoading()
		}, 1000)
	}, 200)
	return doc
}

/**
 * 书签填充
 * @param {wps.document} doc
 * @param {Object} params
 */
function UpdateRegion(doc, params) {
	// var elements = wps.PluginStorage.getItem("values");
	var tempvalues = params.values
	let Bookmarks = doc.Bookmarks
	if (typeof tempvalues === 'string') {
		var arrelements = tempvalues.split('|')
		for (var i = 0; i < arrelements.length; i++) {
			if (arrelements[i] != '') {
				var bookmark = Bookmarks.Item(arrelements[i].split('=')[0])
				if (bookmark) {
					var content = arrelements[i].split('=')[1]
					replaceBookmarkContent(doc, bookmark, content)
				}
			}
		}
	}
	if (tempvalues != null && typeof tempvalues === 'object') {
		// var tempvalues = params.values;
		for (let key in tempvalues) {
			if (
				typeof tempvalues[key] == 'string' ||
				typeof tempvalues[key] == 'number'
			) {
				var content = tempvalues[key]
				var bookmark = Bookmarks.Item(key)
				if (bookmark) {
					if (content.length > 50 && Base64.isBase64(content)) {
						repalceImg(doc, content, bookmark)
					} else replaceBookmarkContent(doc, bookmark, content)
				}
				var documentfield = wps
					.WpsApplication()
					.ActiveDocument.DocumentFields.Item(key)
				if (documentfield) {
					documentfield.Value = content
				}
			}
		}
		for (let key in tempvalues) {
			if (typeof tempvalues[key] != 'string') {
				if (doc.Bookmarks.Exists(key)) {
					var bookmark = Bookmarks.Item(key)
					bookmark.Select()
					doc.Application.Selection.Copy()
					//string value = base64Decode(item.Value.Value);
					var valuecount = tempvalues[key].length
					if (valuecount < 1) {
						bookmark.Range.Text = ''
					} else {
						for (let va in tempvalues[key]) {
							valuecount = valuecount - 1
							for (let vava in tempvalues[key][va]) {
								bookmark.Select()
								doc.Application.Selection.Find.ClearFormatting()
								doc.Application.Selection.Find.Text = '${' + vava + '}'
								doc.Application.Selection.Find.Forward = true
								doc.Application.Selection.Find.Wrap = 1
								doc.Application.Selection.Find.Execute()
								if (doc.Application.Selection.Find.Found == true) {
									var markvalue = String(tempvalues[key][va][vava])
									if (
										markvalue.indexOf('data:') != -1 &&
										markvalue.indexOf('base64') != -1
									) {
										// doc.Application.Selection.TypeText(' ')
										//doc.Application.Selection.AddPictureBase64(tempvalues[key][va][vava]);
										doc.Shapes.AddBase64Picture(markvalue)
									} else if (
										markvalue.length > 50 &&
										Base64.isBase64(markvalue)
									) {
										addBasePictureToBookMark(doc, markvalue, bookmark)
									} else if (markvalue.indexOf('&inserturl&') > -1) {
										var link = markvalue.replace('&inserturl&', '').split('|')
										doc.Hyperlinks.Add(
											doc.Application.Selection.Range,
											link[1],
											null,
											link[1],
											link[0]
										)
									} else {
										doc.Application.Selection.TypeText(
											getEmptyBookmarkText(markvalue)
										)
									}
								}
							}
							if (valuecount > 0) {
								bookmark.Delete()
								doc.Application.Selection.EndKey(5)
								doc.Application.Selection.TypeParagraph()
								doc.Application.Selection.ParagraphFormat.Alignment = 0
								doc.Application.Selection.PasteAndFormat(16)
							}
						}
					}
				}
			}
		}
	}
}

/**
 * 获取空标签内容
 * @param {string} txt
 * @returns
 */
function getEmptyBookmarkText(txt) {
	if (typeof txt == 'number') return String(txt)
	if (!!txt) return txt
	return ' '
}

function getContentLength(txt) {
	return txt.replace(/\r\n/gi, '\n').length
}

function replaceBookmarkContent(doc, bookmark, content) {
	var start = bookmark.Range.Start
	var end = bookmark.Range.End
	var label = '',
		link = ''
	if (typeof content == 'string' && content.indexOf('&inserturl&') > -1) {
		var tmp = content.replace('&inserturl&', '').split('|')
		label = getEmptyBookmarkText(tmp[0])
		link = tmp[1]
	} else {
		label = getEmptyBookmarkText(content)
	}

	bookmark.Range.InsertBefore(label)
	var contentLength = getContentLength(label)
	if (bookmark.Empty) {
		wps.Application.Selection.SetRange(start, start + contentLength)
		var range = wps.Application.Selection.Range

		var name = bookmark.Name
		bookmark.Delete()
		doc.Bookmarks.Add(name, range)
		if (!!link) doc.Hyperlinks.Add(range, link)
		return range
	} else {
		wps.Application.Selection.SetRange(
			start + contentLength,
			end + contentLength
		)
		wps.Application.Selection.Delete()
		if (!!link) doc.Hyperlinks.Add(bookmark.Range, link)
		return bookmark.Range
	}
}

function checkBs() {
	var bs = wps.ActiveDocument.Bookmarks.Count
	for (var i = 1; i <= bs; i++) {
		wps.ActiveDocument.Bookmarks.Item(i).Select()
		var b = wps.ActiveDocument.Bookmarks.Item(i)
		var txt = b.Range.Text.replace(/\r\n/, '↵').replace(/\t/, '→')
		console.log(
			`${b.Name.padStart(20, ' ')}:${b.Range.Start}-${b.Range.End}:${txt}`
		)
		b.Select()
		if (wps.Application.Selection.Bookmarks.Count > 1) {
			var ibs = wps.Application.Selection.Bookmarks
			console.log('覆盖标签' + ibs.Count)
			for (var j = 1; j <= ibs.Count; j++) {
				console.log(ibs.Item(j).Name)
			}
		}
	}
}

/**
 * 添加印章
 * @param {wps.document} doc
 * @param {string} strFile 印章文件路径
 * @param {string} postion 文件名字
 */
function pInsertYinzhang(doc, strFile, postion) {
	let Bookmarks = doc.Bookmarks
	var bookmark = Bookmarks.Item(postion)
	if (bookmark) {
		bookmark.Range.InsertFile(strFile)
	} else {
		doc.Application.Selection.EndKey(6)
		doc.Application.Selection.InsertFile(strFile)
	}
	wps.FileSystem.Remove(strFile) //删除临时文件
}

/**
 * 打开服务端的文档（不落地）
 * @param {*} fileUrl 文件url路径
 */
function OpenOnLineFile(OAParams) {
	//OA参数如果为空的话退出
	if (!OAParams) return

	//获取在线文档URL
	var l_OAFileUrl = OAParams.fileName
	var l_doc
	if (l_OAFileUrl) {
		//下载文档不落地（16版WPS的925后支持）
		wps
			.WpsApplication()
			.Documents.OpenFromUrl(
				l_OAFileUrl,
				'OnOpenOnLineDocSuccess',
				'OnOpenOnLineDocDownFail'
			)
		l_doc = wps.WpsApplication().ActiveDocument
	}
	//执行文档打开后的方法
	pOpenFile(l_doc, OAParams, true)
	return l_doc
}

/**
 * 打开在线文档成功后触发事件
 * @param {*} resp
 */
function OnOpenOnLineDocSuccess(resp) {}

/**
 *  打开在线不落地文档出现失败时，给予错误提示
 */
function OnOpenOnLineDocDownFail() {
	ShowMessage('打开在线不落地文档失败！请尝试重新打开。', 'error', 5, true)
	return
}

/**
 * 参数：
 * doc : 当前OA文档的Document对象
 * DocLandMode ： 落地模式设置
 */
function DoSetOADocLandMode(doc, DocLandMode) {
	if (!doc) return
	// var l_Param = wps.PluginStorage.getItem(doc.DocID);
	// var l_objParam = JSON.parse(l_Param);
	// //增加属性，或设置
	// l_objParam.OADocLandMode = DocLandMode; //设置OA文档的落地标志

	// var l_p = JSON.stringify(l_objParam);
	// //将OA文档落地模式标志存入系统变量对象保存

	// wps.PluginStorage.setItem(doc.DocID, l_p);

	SetDocParamsValue(doc, 'OADocLandMode', DocLandMode)
}

/**
 * 作用：打开文档处理的各种过程，包含：打开带密码的文档，保护方式打开文档，修订方式打开文档等种种情况
 * params	Object	OA Web端传来的请求JSON字符串，具体参数说明看下面数据
 * TempLocalFile : 字符串 先把文档从OA系统下载并保存在Temp临时目录，这个参数指已经下载下来的本地文档地址
 * ----------------------以下是OA参数的一些具体规范名称
 * docId	String	文档ID
 * uploadPath	String	保存文档接口
 * fileName	String	获取服务器文档接口（不传即为新建空文档）
 * suffix	String	".pdf|.uot"，可传多个，用“|”分割，保存时会按照所传的值转成对应的格式文档并上传
 * userName	String	用于更改显示修改人的用户名
 * strBookmarkDataPath	string	书签列表 (可不传，可以在OA助手config.js中配置)
 * templatePath	string	模板列表 (可不传，可以在OA助手config.js中配置)
 * buttonGroups	string	自定义按钮组 （可不传，不传显示所有按钮）
 * revisionCtrl	String	痕迹控制 ，不传正常打开
 *      bOpenRevision	String	true(打开)false(关闭)修订
 *      bShowRevision	String	true(显示)/false(关闭)痕迹
 * openType	String	文档打开方式 ，不传正常打开
 *      protectType	String	文档保护类型，-1：不启用保护模式，0：只允许对现有内容进行修订，1：只允许添加批注，2：只允许修改窗体域，3：只读
 *      password	String密码
 */
function pDoOpenOADocProcess(params, TempLocalFile) {
	// var l_ProtectType = -1; //默认文档保护类型 -1 为不启用保护
	var l_ProtectPassword = '' //默认文档密码为空

	var l_strDocPassword = '' //打开文档密码参数
	// var l_bOpenRevision = false; //初始化关闭修订模式
	// var l_bShowRevision = false; //初始化不显示修订气泡样式

	for (var _key in params) {
		var key = (_key || '').toUpperCase()
		switch (
			key.toUpperCase() //
		) {
			case 'userName'.toUpperCase(): //修改当前文档用户名
				wps.WpsApplication().Options.UseLocalUserInfo = true
				wps.WpsApplication().UserName = params[key]
				break
			case 'openType'.toUpperCase():
				// l_ProtectType = params[key].protectType; //获取OA传来的文档保护类型
				l_ProtectPassword = constStrEnum.docPassWord //获取OA传来的保护模式下的文档密码
				break
			case 'revisionCtrl'.toUpperCase(): //限制修订状态
				l_bOpenRevision = params[_key].bOpenRevision
				l_bShowRevision = params[_key].bShowRevision
				break
			case 'buttonGroups'.toUpperCase(): //按钮组合
				break
			case 'docPassword'.toUpperCase(): //传入打开文件的密码
				l_strDocPassword = params[_key].docPassword
				break
		}
	}

	var l_Doc
	// Open方法的参数说明如下
	//Function Open(FileName, [ConfirmConversions], [ReadOnly], [AddToRecentFiles],
	//  [PasswordDocument], [PasswordTemplate], [Revert], [WritePasswordDocument],
	//  [WritePasswordTemplate], [Format], [Encoding], [Visible],
	//  [OpenAndRepair], [DocumentDirection], [NoEncodingDialog], [XMLTransform]) As Document
	loginfo('Document.Open')
	l_Doc = wps
		.WpsApplication()
		.Documents.Open(TempLocalFile, false, false, false, l_strDocPassword)
	loginfo('Document.Open完成')

	//设置文档修订状态

	l_Doc.Unprotect(constStrEnum.docPassWord)
	l_Doc.TrackRevisions = false

	//打开文档的方法中统一处理参数存储到doc中
	var Persist = getBoolean(params.fileparam.AllowSaveAs, true)
	var RevisionsMode = getNumber(params.fileparam.MarkupMode, 1)
	var ps = Object.assign(
		{
			isOA: EnumOAFlag.DocFromOA,
			SourcePath: l_Doc.FullName,
			TempLocalFile,
			Persist,
			RevisionsMode,
		},
		params
	)
	ps[constStrEnum.OriginalRsid] = l_Doc.CurrentRsid
	SetDocParamsValues(l_Doc, ps)
	return l_Doc
}

/**
 * protectType: '', 文档保护模式(   -1：不启用保护模式，
 *                                  0：只允许对现有内容进行修订，
 *                                  1：只允许添加批注，
 *                                  2：只允许修改窗体域，
 *                                  3：只读)
 * @param {*} protectType
 * @param {*} doc
 */
function SetOADocProtect(doc, protectType, ProtectPassword) {
	if (!doc) return //校验文档是否存在
	if ([0, 1, 2, 3].indexOf(protectType) !== -1) {
		// 保护文档如果之前有被保护，再次保护会出问题，需要先解除保护
		doc.Unprotect()
		// ** 方法参数
		// ** Protect(Type As WdProtectionType, [NoReset], [Password], [UseIRM], [EnforceStyleLock])
		doc.Protect(protectType, false, ProtectPassword, false)
		// doc.Save()
	}
	return
}

/**
 * 打开/关闭修订
 * @param {*} doc :传入文档对象
 * @param {*} bOpenRevision :  布尔值，是否允许打开修订模式，true:打开/false:关闭
 * @param {*} bOpenRevision ： 布尔值，是否显示修订痕迹状态
 * 返回值：无
 */
function DoOADocOpenRevision(
	doc,
	bOpenRevision,
	bShowRevision,
	l_revisionmMode
) {
	if (!doc) return

	doc.TrackRevisions = bOpenRevision //如果标记对指定文档的修改，则该属性值为True
	wps
		.WpsApplication()
		.CommandBars.ExecuteMso('KsoEx_RevisionCommentModify_Disable') //去掉修改痕迹信息框中的接受修订和拒绝修订勾叉，使其不可用
	var l_v = doc.ActiveWindow.View
	l_v.ShowRevisionsAndComments = bShowRevision //如果为True，则 WPS 显示使用“修订”功能对文档所作的修订和批注
	l_v.RevisionsBalloonShowConnectingLines = bShowRevision //如果为 True，则 WPS 显示从文本到修订和批注气球之间的连接线
	l_v.RevisionsMode = l_revisionmMode //2为不支持气泡显示。
	return
}

/**
 *   描述：如何处理再次打开相同的OA文件
 *   返回值：打开的Document对象
 */
function pReOpenOADoc(OADocURL) {
	if (wps.confirm('当前环境已打开该文件，是否重新再打开一份？')) {
		//如果用户选择再次打开，则用在线方式打开
		wps.WpsApplication().Documents.OpenFromUrl(OADocURL, '', '')
	}
}

/**
 * 功能说明：判断是否已存在来自OA的已打开的文档
 * @param {字符串} FileURL
 */
function pCheckIsExistOpenOADoc(FileURL) {
	var l_DocCount = wps.WpsApplication().Documents.Count
	if (l_DocCount <= 0) return false

	//轮询检查当前已打开的WPS文档中，是否存在OA相同的文件
	if (l_DocCount >= 1) {
		for (var l_index = 1; l_index <= l_DocCount; l_index++) {
			var l_objDoc = wps.WpsApplication().Documents.Item(l_index)

			var l_strParam = wps.PluginStorage.getItem(GetUniqueId(l_objDoc))
			if (l_strParam == null) continue
			var l_objParam = JSON.parse(l_strParam)
			if (l_objParam.fileName == FileURL) {
				return true
			}
		}
		return false
	}
}

/**
 * 作用：
 * @param {*} suffix  ：文档后缀明：.pdf 或 .uot 或 .uof
 * @param {*} doc
 * @param {*} uploadPath
 * @param {}    FieldName ： 上传到服务器端的字段名称，可由OA传入的参数设置
 *
 * 返回值：是否执行了上传操作，布尔值
 */
function handleFileAndUpload(suffix, doc, uploadPath, FieldName) {
	var l_strChangeFileName = '' // 转换格式后的文件名称
	var l_strPath = '' // 转换格式后的文件路径
	var l_FieldName = FieldName

	if (!doc) {
		return false
	}
	if (!l_FieldName) {
		l_FieldName = 'file' //默认情况下，设置为 file 字段名称
	}

	var l_DocSourcePath = doc.FullName //保留当前文档明，在SaveAs使用后再保存回原来的文件明

	//Sub ExportAsFixedFormat(OutputFileName As String, ExportFormat As WdExportFormat,
	//                       [OpenAfterExport As Boolean = False],
	//                       [OptimizeFor As WdExportOptimizeFor = wdExportOptimizeForPrint],
	//                       [Range As WdExportRange = wdExportAllDocument], [From As Long = 1],
	//                       [To As Long = 1], [Item As WdExportItem = wdExportDocumentContent],
	//                       [IncludeDocProps As Boolean = False], [KeepIRM As Boolean = True],
	//                       [CreateBookmarks As WdExportCreateBookmarks = wdExportCreateNoBookmarks],
	//                       [DocStructureTags As Boolean = True], [BitmapMissingFonts As Boolean = True],
	//                       [UseISO19005_1 As Boolean = False], [FixedFormatExtClassPtr])

	//          Const wdExportFormatPDF = 17 (&H11)
	//          Const wdExportFormatXPS = 18 (&H12)
	//

	//处理水印 隐藏，上传后再显示在回调里面
	// WaterMark.Hidden(doc);
	// doc.Save();

	//根据传入的 后缀文件名称进行不同的转换文档操作
	switch (suffix.toLocaleLowerCase()) {
		case '.pdf':
			l_strPath = pGetValidDocTempPath(doc) + '.pdf' //获取有效输出路径
			wps.FileSystem.Remove(l_strPath) //先删除之前可能存在的临时文件
			doc.ExportAsFixedFormat(l_strPath, wps.Enum.wdFormatPDF, true) //文档另存为PDF格式
			l_strChangeFileName = doc.Name.split('.')[0] + '.pdf'
			UploadFile(
				l_strChangeFileName,
				l_strPath,
				uploadPath,
				l_FieldName,
				doc,
				OnChangeSuffixUploadSuccess,
				OnChangeSuffixUploadFail
			)
			break
		case '.uof':
			l_strPath = pGetValidDocTempPath(doc) + suffix
			wps.FileSystem.Remove(l_strPath) //先删除之前可能存在的临时文件
			doc.ExportAsFixedFormat(
				l_strPath,
				wps.Enum.wdFormatOpenDocumentText,
				true
			) //转换文件格式
			doc.SaveAs2(l_strPath)
			l_strChangeFileName = doc.Name.split('.')[0] + suffix
			UploadFile(
				l_strChangeFileName,
				l_strPath,
				uploadPath,
				l_FieldName,
				doc,
				OnChangeSuffixUploadSuccess,
				OnChangeSuffixUploadFail
			)
			doc.SaveAs2(l_DocSourcePath) //保存回原来的文档内容
			break
		case '.uot':
			l_strPath = pGetValidDocTempPath(doc) + suffix
			wps.FileSystem.Remove(l_strPath) //先删除之前可能存在的临时文件
			doc.ExportAsFixedFormat(
				l_strPath,
				wps.Enum.wdFormatOpenDocumentText,
				true
			)
			doc.SaveAs2(l_strPath)
			l_strChangeFileName = doc.Name.split('.')[0] + suffix
			UploadFile(
				l_strChangeFileName,
				l_strPath,
				uploadPath,
				l_FieldName,
				doc,
				OnChangeSuffixUploadSuccess,
				OnChangeSuffixUploadFail
			)
			doc.SaveAs2(l_DocSourcePath) //保存回原来的文档内容
			break
		case '.ofd':
			l_strPath = pGetValidDocTempPath(doc) + suffix
			wps.FileSystem.Remove(l_strPath) //先删除之前可能存在的临时文件
			doc.ExportAsFixedFormat(
				l_strPath,
				wps.Enum.wdFormatOpenDocumentText,
				true
			)
			doc.SaveAs2(l_strPath)
			l_strChangeFileName = doc.Name.split('.')[0] + suffix
			UploadFile(
				l_strChangeFileName,
				l_strPath,
				uploadPath,
				l_FieldName,
				doc,
				OnChangeSuffixUploadSuccess,
				OnChangeSuffixUploadFail
			)
			doc.SaveAs2(l_DocSourcePath) //保存回原来的文档内容
			break
		default:
			l_strPath = pGetValidDocTempPath(doc) + suffix
			wps.FileSystem.Remove(l_strPath) //先删除之前可能存在的临时文件
			doc.SaveAs2(l_strPath)
			l_strChangeFileName = doc.Name.split('.')[0] + suffix
			UploadFile(
				l_strChangeFileName,
				l_strPath,
				uploadPath,
				l_FieldName,
				doc,
				OnChangeSuffixUploadSuccess,
				OnChangeSuffixUploadFail
			)
			doc.SaveAs2(l_DocSourcePath) //保存回原来的文档内容
			break
	}

	wps.FileSystem.Remove(l_strPath) //上载完成后，删除临时文件
	//wps.OAAssist.WebNotify("fnRefreshFileList");
	return true
}

/**
 * 作用：获取一个有效的临时文档路径，用于保存转换格式后的文档
 * @param {*} doc
 */
function pGetValidDocTempPath(doc) {
	if (!doc) {
		return
	}
	if (doc.Path == '') {
		//对于不落地文档，文档路径为空
		return wps.Env.GetTempPath()
	} else {
		return doc.FullName.split('.')[0]
	}
}

/**
 * 作用：转格式保存上传成功后，触发这个事件的回调
 * @param {} response
 */
function OnChangeSuffixUploadSuccess(response) {
	// WaterMark.Show();
	l_result = handleResultBody(response)
	ShowMessage('文件转格式保存成功！', 'success')
}

/**
 * 作用：转格式保存失败，触发失败事件回调
 * @param {*} response
 */
function OnChangeSuffixUploadFail(doc, response) {
	// WaterMark.Show();
	OnUploadFileFail(doc, response, false)
}

/**
 * 解析返回response的参数
 * @param {*} resp
 * @return {*} body
 */
function handleResultBody(resp) {
	var l_result = ''
	if (resp.Body) {
		//解析返回response的参数
	}
	return l_result
}

/**
 * 把OA文件的当前编辑内容，自动提交到OA后台
 * 当前没有使用
 */
function pAutoUploadToServer(p_Doc) {
	if (!p_Doc) {
		return
	}

	/**
	 * 参数定义：OAAsist.UploadFile(name, path, url, field,  "OnSuccess", "OnFail")
	 * 上传一个文件到远程服务器。
	 * name：为上传后的文件名称；
	 * path：是文件绝对路径；
	 * url：为上传地址；
	 * field：为请求中name的值；
	 * 最后两个参数为回调函数名称；
	 */

	var l_uploadPath = GetDocParamsValue(p_Doc, constStrEnum.uploadPath) // 文件上载路径
	if (l_uploadPath == '') {
		//wps.alert("系统未传入文件上载路径，不能执行上传操作！");
		return
	}

	var l_FieldName = GetDocParamsValue(p_Doc, constStrEnum.uploadFieldName) //上载到后台的字段名称
	if (l_FieldName == '') {
		l_FieldName = wps.PluginStorage.getItem(constStrEnum.DefaultUploadFieldName) // 默认为‘file’
	}

	var l_UploadName = GetDocParamsValue(p_Doc, constStrEnum.uploadFileName) //设置OA传入的文件名称参数
	if (l_UploadName == '') {
		l_UploadName = p_Doc.Name //默认文件名称就是当前文件编辑名称
	}

	var l_DocPath = p_Doc.FullName // 文件所在路径

	if (pIsOnlineOADoc(p_Doc) == false) {
		console.log('落地文档自动保存')
		//对于本地磁盘文件上传OA，先用Save方法保存后，在上传
		//设置用户保存按钮标志，避免出现禁止OA文件保存的干扰信息
		wps.PluginStorage.setItem(
			constStrEnum.OADocUserSave,
			EnumDocSaveFlag.OADocSave
		)
		p_Doc.Save() //执行一次保存方法
		//设置用户保存按钮标志
		wps.PluginStorage.setItem(
			constStrEnum.OADocUserSave,
			EnumDocSaveFlag.NoneOADocSave
		)
		//落地文档，调用UploadFile方法上传到OA后台
		try {
			//调用OA助手的上传方法
			UploadFile(
				l_UploadName,
				l_DocPath,
				l_uploadPath,
				l_FieldName,
				p_Doc,
				OnAutoUploadSuccess,
				OnAutoUploadFail
			)
		} catch (err) {
			ShowMessage(
				'上传文件失败！请检查系统上传参数及网络环境！',
				'error',
				5,
				true
			)
		}
	} else {
		console.log('不落地文档自动保存')
		// 不落地的文档，调用 Document 对象的不落地上传方法
		wps.PluginStorage.setItem(
			constStrEnum.OADocUserSave,
			EnumDocSaveFlag.OADocSave
		)
		try {
			//调用不落地上传方法
			p_Doc.SaveAsUrl(
				l_UploadName,
				l_uploadPath,
				l_FieldName,
				'OnAutoUploadSuccess',
				'OnAutoUploadFail'
			)
		} catch (err) {}
		wps.PluginStorage.setItem(
			constStrEnum.OADocUserSave,
			EnumDocSaveFlag.NoneOADocSave
		)
	}
}

/**
 * 作用：自动上传到OA后台成功后出发事件
 */
function OnAutoUploadSuccess(resp) {
	return
}

/**
 * 作用：自动上传到OA后台成功后出发事件
 */
function OnAutoUploadFail(resp) {
	ShowMessage(resp, 'error', 5, true)
	return
}

/**
 * 实现一个定时器
 */
function OpenTimerRun(funcCallBack) {
	var l_mCount = 0 //设置一个计时器，按每分钟执行一次; 10分钟后重复执行
	var l_timeID = 0 //用于保存计时器ID值

	// 对间隔时间做处理
	var l_AutoSaveToServerTime = wps.PluginStorage.getItem(
		constStrEnum.AutoSaveToServerTime
	)
	if (l_AutoSaveToServerTime == 0) {
		// 设置为0则不启动定时器
		l_timeID = wps.PluginStorage.getItem(constStrEnum.TempTimerID)
		clearInterval(l_timeID)
		return
	} else if (l_AutoSaveToServerTime < 3) {
		l_AutoSaveToServerTime = 3
	}

	l_timeID = setInterval(function () {
		l_mCount = l_mCount + 1
		if (l_mCount > l_AutoSaveToServerTime) {
			//l_AutoSaveToServerTime 值由系统配置时设定，见pInitParameters()函数
			l_mCount = 0
			funcCallBack() //每隔l_AutoSaveToServerTime 分钟（例如10分钟）执行一次回调函数
		}
	}, 60000) //60000 每隔1分钟，执行一次操作(1000*60)

	wps.PluginStorage.setItem(constStrEnum.TempTimerID, l_timeID) //保存计时器ID值
}

/**
 * 套红头
 *  doc ：套红头的文档
 *  strFile ：获取红头模板接口
 *  bookmark ：,正文书签
 */
function pInsertRInedHead(doc, strFile, bookmark, params) {
	var bookMarks = doc.Bookmarks

	var wpsApp = wps.WpsApplication()
	var zhengwen = wpsApp.Documents.Add(strFile, false, 4, false)
	if (getBoolean(params.fileparam.AutoAcceptRevisions, false)) {
		clearRevDoc(zhengwen)
	}

	zhengwen.Range().Copy()
	if (bookMarks.Exists(bookmark)) {
		var bookmark1 = bookMarks.Item(bookmark)
		bookmark1.Range.Select() //获取指定书签位置
		var s = doc.ActiveWindow.Selection
		if (!!params.fileparam.ContentNeedFormate) s.PasteAndFormat(20)
		else s.PasteAndFormat(16)
	} else {
		ShowMessage(
			'套红头失败，您选择的红头模板没有对应书签：' + bookmark,
			'error',
			5,
			true
		)
	}
	zhengwen.Close(0)
	wps.FileSystem.Remove(strFile) //删除本地临时文件

	// var elements = wps.PluginStorage.getItem("values");
	var tempvalues = params.values
	let Bookmarks = doc.Bookmarks
	if (typeof tempvalues === 'string') {
		var arrelements = tempvalues.split('|')
		for (var i = 0; i < arrelements.length; i++) {
			if (arrelements[i] != '') {
				var bookmark = Bookmarks.Item(arrelements[i].split('=')[0])
				if (bookmark) {
					var content = arrelements[i].split('=')[1]
					replaceBookmarkContent(doc, bookmark, content)
				}
			}
		}
	}
	if (tempvalues !== null && typeof tempvalues === 'object') {
		// var tempvalues = params.values;
		for (let key in tempvalues) {
			if (
				typeof tempvalues[key] == 'string' ||
				typeof tempvalues[key] == 'number'
			) {
				var content = tempvalues[key]
				var bookmark = Bookmarks.Item(key)
				if (bookmark) {
					if (content.length > 50 && Base64.isBase64(content)) {
						repalceImg(doc, content, bookmark)
					} else replaceBookmarkContent(doc, bookmark, content)
				}
				var documentfield = wps
					.WpsApplication()
					.ActiveDocument.DocumentFields.Item(key)
				if (documentfield) {
					documentfield.Value = content
				}
			}
		}
		for (let key in tempvalues) {
			if (typeof tempvalues[key] != 'string') {
				if (doc.Bookmarks.Exists(key)) {
					var bookmark = Bookmarks.Item(key)
					bookmark.Select()
					doc.Application.Selection.Copy()
					//string value = base64Decode(item.Value.Value);
					var valuecount = tempvalues[key].length
					if (valuecount < 1) {
						bookmark.Range.Text = ''
					} else {
						for (let va in tempvalues[key]) {
							valuecount = valuecount - 1
							for (let vava in tempvalues[key][va]) {
								bookmark.Select()
								doc.Application.Selection.Find.ClearFormatting()
								doc.Application.Selection.Find.Text = '${' + vava + '}'
								doc.Application.Selection.Find.Forward = true
								doc.Application.Selection.Find.Wrap = 1
								doc.Application.Selection.Find.Execute()
								if (doc.Application.Selection.Find.Found == true) {
									var markvalue = String(tempvalues[key][va][vava])
									if (
										markvalue.indexOf('data:') != -1 &&
										markvalue.indexOf('base64') != -1
									) {
										doc.Application.Selection.TypeText(' ')
										//doc.Application.Selection.AddPictureBase64(tempvalues[key][va][vava]);
										doc.Application.ActiveDocument.Shapes.AddBase64Picture(
											markvalue
										)
									} else if (
										markvalue.length > 50 &&
										Base64.isBase64(markvalue)
									) {
										addBasePictureToBookMark(doc, markvalue, bookmark)
									} else if (markvalue.indexOf('&inserturl&') > -1) {
										var link = markvalue.replace('&inserturl&', '').split('|')
										doc.Hyperlinks.Add(
											bookmark.Range,
											link[1],
											null,
											link[1],
											link[0]
										)
									} else {
										doc.Application.Selection.TypeText(
											getEmptyBookmarkText(markvalue)
										)
									}
								}
							}
							if (valuecount > 0) {
								bookmark.Delete()
								doc.Application.Selection.EndKey(5)
								doc.Application.Selection.TypeParagraph()
								doc.Application.Selection.ParagraphFormat.Alignment = 0
								doc.Application.Selection.PasteAndFormat(16)
							}
						}
					}
				}
			}
		}
	}
}

/**
 * 将文件保存到服务器的逻辑
 * @param {wps.document} doc
 * @returns
 */
function UploadFileToServer(doc) {
	if (!Heart.IsOASystemOnline()) {
		ShowConfirm('检测到审批单已经关闭，无法上传，是否另存本文档？', 'warning', {
			btns: [
				{
					key: 'close',
					text: '否',
					close: true,
					callback: function () {
						Heart.CloseOADocument(doc)
						doc.Close(WdSaveOptions.wdDoNotSaveChange)
					},
				},
				{
					key: 'saveas',
					text: '是',
					primary: true,
					close: true,
					callback: function () {
						var dialog = wps.WpsApplication().FileDialog(2)
						dialog.InitialFileName = doc.FullName
						if (dialog.Show() == -1) {
							dialog.Execute()
							SetDocParamsValue(doc, 'Persist', true)
							Heart.CloseOADocument(doc)
							doc.Close()
						}
					},
				},
			],
		})
		return
	}

	loginfo('显现loading')
	ShowLoading('上传中，请稍后...', GetUniqueId(doc))
	// 水印不保留在文档中
	// WaterMark.ClearWaterMark(doc);
	// doc.Save();
	// 设定异步让loading显示出来
	setTimeout(() => {
		OnBtnSaveToServer(doc)
	}, 100)
}

/**
 * 上传失败回调
 * @param {document} doc
 * @param {response} rps
 * @param {boolean} savetmp 是否保存临时文件
 */
function OnUploadFileFail(doc, rps, savetmp = true) {
	//同步操作会把wps卡死
	setTimeout(() => {
		CloseLoading(GetUniqueId(doc))
		if (rps.startsWith('lockError')) {
			if (savetmp) {
				var gs = doc.Name.match(/^(?<name>.*)\.(?<ext>\w+)$/).groups
				var sourcename = doc.FullName
				var bkname =
					wps.Env.GetHomePath() +
					GetDirSpacer() +
					gs.name +
					'_锁异常临时备份' +
					'.' +
					gs.ext
				var data = wps.FileSystem.readAsBinaryString(sourcename)
				wps.FileSystem.writeAsBinaryString(bkname, data)
			}
			var failMsg = rps.split(',')
			var name = decodeURIComponent(failMsg[1]) || '未知'
			var msg = `文件已被 ${name} 编辑，无法继续提交，请确认是否关闭？`
			ShowConfirm(msg, 'error', {
				title: '提交失败',
				btns: [
					{
						key: 'close',
						text: '确认',
						primary: true,
						callback: function () {
							Heart.CloseOADocument(doc)
							doc.Close()
						},
					},
					{
						key: 'cancel',
						text: '取消',
						callback: function () {
							SetDocParamsValue(doc, 'LockError', {
								callback: 'AfterLockError',
								msg,
							})
						},
					},
				],
			})
		} else {
			ShowMessage('上传文件失败！请联系管理员', 'error')
		}
		logerr('上传失败：' + rps)
	}, 1000)
}

/**
 * 作用：执行清稿操作
 * 业务功能：清除所有修订痕迹和批注
 */
function clearRevDoc(idoc) {
	var doc = idoc || wps.WpsApplication().ActiveDocument
	if (!doc) {
		ShowMessage('尚未打开文档，请先打开文档再进行清稿操作！', 'error')
		return
	}

	//执行清稿操作前，给用户提示
	//if (!wps.confirm("清稿操作将接受所有的修订内容，关闭修订显示。请确认执行清稿操作？")) {
	// return;
	//}

	//接受所有修订
	if (doc.ProtectionType != WdProtectionType.wdNoProtection) {
		doc.Unprotect(constStrEnum.docPassWord)
	}

	doc.Protect(-1, false, constStrEnum.docPassWord, false)
	if (doc.Revisions.Count >= 1) {
		doc.AcceptAllRevisions()
	}
	//去除所有批注
	if (doc.Comments.Count >= 1) {
		doc.RemoveDocumentInformation(wps.Enum.wdRDIComments)
	}

	//删除所有ink墨迹对象
	pDeleteAllInkObj(doc)

	doc.TrackRevisions = false //关闭修订模式

	return
}

/**
 * 作用：删除当前文档的所有墨迹对象
 * @param {*} p_Doc
 */
function pDeleteAllInkObj(p_Doc) {
	var l_Count = 0
	var l_IsInkObjExist = true
	while (l_IsInkObjExist == true && l_Count < 20) {
		l_IsInkObjExist = pDeleteInkObj(p_Doc)
		l_Count++
	}
	return
}

/**
 * 删除墨迹对象
 */
function pDeleteInkObj(p_Doc) {
	var l_IsInkObjExist = false
	if (p_Doc) {
		for (var l_Index = 1; l_Index <= p_Doc.Shapes.Count; l_Index++) {
			var l_Item = p_Doc.Shapes.Item(l_Index)
			if (l_Item.Type == 23) {
				l_Item.Delete()
				//只要有一次找到Ink类型，就标识一下
				if (l_IsInkObjExist == false) {
					l_IsInkObjExist = true
				}
			}
		}
	}
	return l_IsInkObjExist
}

function SaveAsAndClose(doc, params) {
	var dialog = wps.WpsApplication().FileDialog(2)
	dialog.InitialFileName = doc.FullName
	if (dialog.Show() == -1) {
		dialog.Execute()
		SetDocParamsValue(doc, 'Persist', true)
		doc.Close()
	} else {
		doc.Close()
	}
}

function clearWaterMark(doc, params) {
	if (
		params[constStrEnum.WaterMark] &&
		!!!params.fileparam[constStrEnum.NeedSaveMark]
	) {
		//清理水印不留痕迹
		if (doc.ProtectionType > -1) {
			var sourceProtectedType = doc.ProtectionType
			doc.Unprotect(constStrEnum.docPassWord)
			//水印不保留在文档中
			WaterMark && WaterMark.ClearWaterMark(doc)

			// doc.Revisions.Item(doc.Revisions.Count).Accept()
			doc.Protect(sourceProtectedType, false, constStrEnum.docPassWord, false)
		} else {
			WaterMark && WaterMark.ClearWaterMark(doc)
		}

		doc.Save()
	}
}

function repalceImg(doc, data, bookmark) {
	var start = bookmark.Range.Start
	let name = bookmark.Name

	doc.Shapes.AddBase64Picture('data:image;base64,' + data).Select()
	wps.Application.Selection.Cut()
	bookmark.Range.Paste()

	if (!doc.Bookmarks.Exists(name)) {
		wps.Application.Selection.SetRange(start, start + 1)
		var range = wps.Application.Selection.Range
		doc.Bookmarks.Add(name, range)
	}
}

function addBasePictureToBookMark(doc, data, bookmark) {
	doc.Shapes.AddBase64Picture('data:image;base64,' + data).Select()
	wps.Application.Selection.Cut()
	bookmark.Range.Paste()
}

function toggleBeforeOAfterLoading(txt, show = false, ifTitle = false) {
	CloseLoading(constStrEnum.BeforeAfterLoadingID)
	show && ShowLoading(txt, constStrEnum.BeforeAfterLoadingID, false, ifTitle)
}
