# 数科套红技术说明文档

# 1.业务逻辑说明

# 1.1 快速发文正文套红

快速发文中正文套红代码逻辑如图所示:

1725866064548.png

# 1.2 待办正文套红

待办中正文套红逻辑如下图所示:

图标描述已自动生成

# 1.3 文单套红

文单套红代码逻辑如图所示:

1725866135602.png

# 2. 接口说明

# 2.1 使用方式

调用officeSDK.taohong(params,callback)方法进行套红,taohong方法是异步方法,如果需要确保套红完成后再做后续的逻辑,可采用一下两种方式: 方法1:

let result = await officeSDK.taohong(params);
if(result){
    // 后续处理逻辑
}

方法2:

officeSDK.taohong(params,function(err,result){
    if(!err){
        // err如果未false,表示套红成功,此处可以做后续处理
    }
})
// params:调用套红接口参数
// callback:回调函数,接收套红结果

备注:套红后是否打开文档是在各自插件对应的Adapter文件中控制,文件打开方式由params参数控制,可以在套红之前调用officeSDK.setOptions({})将参数设置进去,打开文件的时候会根据参数控制打开的方式

# 2.2 参数说明

# 1. 套红参数说明

参数 参数类型 是否必填 说明
allBookMark List 书签对象集合
templateType String 模板类型(edoc:正文,script:表单)
fileType String 文件类型(doc或者docx)
fileId String 文件ID
refreshBookMarkText Boolean 刷新数书签值,如果需要刷新书签,次参数传递true
templateUrl String 模板ID
extParam Map 扩展参数

# 2. 书签对象说明

参数 参数类型 是否必填 说明
bookmark String 书签名称
type String 书签类型(DOCUMENT \ IMAGE \TEXT)
text String 文本内容
imgInfo ImgInfo 图片对象,当type为IMAGE时,必填
fileInfo DocumentInfo 文件对象,当type为DOCUMENT时,必填

# 3. 图片对象说明

参数 参数类型 是否必填 说明
imgId String 图片ID
inputType String 图片类型(image、handwrite、barcode)
createDate String 创建时间
isSignatrue String 是否签章

# 4. 文件对象说明

参数 参数类型 是否必填 说明
fileId String 文件ID
fileType String 正文类型
originalFileId String 原正文ID
size Long 文件大小

# 5.扩展参数说明

参数 参数类型 是否必填 说明
useOriginContentTaohong String 是否原正文套红
originContentId String 原正文ID

# 3.套红功能

套红功能支持的插件为数科预览、金山文档中台、WPS加载项,在调用套红功能之前需要将当前插件切换为编辑模式,代码示例如下:

示例1:

await officeSDK.init({
    mode: OfficeSDK.ENUM_MODE_TYPE.EDIT
});

示例2:

await officeSDK.switchProvider({
    mode: OfficeSDK.ENUM_MODE_TYPE.EDIT
});

# 3.1 数科套红

# 1. 前端代码

同时存在多个可以套红的插件时会优先使用数科的套红功能,因此数科的前端套红方法被封装为OfficeSDK的一个工具方法:

OfficeSDK.utils = {
     taohong: function (params, callback) {
        .....
     }
}

PC代码位置:

apps-office-plugins-front\\desktop-front\\src\\office\\js\\OfficeSDK.js

移动端代码位置:

apps-office-plugins-front\\mplus-front\\src\\office\\js\\OfficeSDK.js

# 2. 后端代码

数科套红采用的是后端接口套红,接口信息如下:

请求方式:POST
请求地址:/rest/suWellTaoHong/taohong

接口入口如下:

@Path("/taohong")
@POST
@ApiOperation(name="套红",scenes = "PC端-套红")
public Response taohong(@RequestBody CommonTaoHongParam commonTaoHongParam){
    String configValue= OfficeConfigUtil.getConfigValue(OfficeConfigEnum.ONLINE_PREVIEW_TYPE);
    if(commonTaoHongParam == null){
        return this.fail("taoHongParams is null");
    }
    if(!("SUWELL").equals(configValue)){
        return this.fail("当前插件不支持套红");
    }
    try {
        DocumentInfo documentInfo = suWellTaoHongManager.taohong(commonTaoHongParam);
        return this.success(documentInfo);
    } catch (BusinessException e) {
        return this.fail(e.getMessage());
    }
}

# 3.2 文档通

由于文档同本身没有实现套红功能,套红逻辑采用的是数科的套红功能,因文档通的套红方法是通过调用OfficeSDK.utils.taohong(params,callback)方法进行套红的。

# 1. 前端代码

PC代码位置:apps-office-plugins-front\desktop-front\src\office\js\docWebOffice\wdtAdapter.js

DocWebOfficePlugin.prototype.taohong = function (params, callback) {
    var _self = this;
    return new Promise((resolve, reject) => {
        OfficeSDK.utils.taohong(params, async function (error, result) {
            if (error) {
                callback && callback(error, result);
                reject(error)
            } else {
                _self.openFile({ fileId: result.fileId }, function (error, result) {
                    callback && callback(error, result);
                    resolve(result)
                });
            }
        })
    })
}

移动端代码位置:

apps-office-plugins-front\mplus-front\src\webOffice\docWebOffice\wdtAdapter.js

DocWebOfficePlugin.prototype.taohong = function (params, callback) {
    var _self = this;
    return new Promise((resolve, reject) => {
        OfficeSDK.utils.taohong(params, function (error, result) {
            callback && callback(error,result);
            if (error) {
                reject(false)
            } else {
                resolve(result)
            }
        })
    })
}

# 3.金山文档中台

金山文档中台套红功能首先是调用后台套红接口进行套红,后台套红不支持的功能再经过前端进行套红。

备注:意见区域待图片使用前端套红

# 1. 前端代码

PC代码位置:

apps-office-plugins-front\desktop-front\src\office\js\kingSoftAdapter\kingSoftAdapter.js

KingSoftOfficePlugin.prototype.taohong = async function (params, callback) {
	var _self = this;
    return new Promise((resolve, reject) => {
		OfficeSDK.utils.taohong(params, async function (error, result) {
			if (error) {
				_self.webOfficeInstance.taohong(params, async (e, res) => {
					if (e) {
						callback && callback(e, res);
					} else {
						if (res) {
							// 后端套红成功,需要再执行前端套红
							// 服务端套红生成的文件需要比对是否替换fileId
							if (_self.params.fileId !== res.data.fileId) {
								_self.params.fileId = res.data.fileId;
							}
							// 服务端套红后需要刷新office,但是之前已经存在一个wps实例,会导致展示的内容为原wps内容而不是套红后的内容(这是wps本身缺陷),所以需保证wps实例为最新
							await _self.webOfficeInstance.wps.destroy();
							// 套红后需要是可以编辑状态
							_self.params.canEdit = true;
							_self.params.editType = "2,1";

							await _self.openFile();
							// 前端补套,由于服务端无法执行部分书签的套红(如:书签下同时包含图片和文字两种类型的值)
							// 如果是快速发文,不走前端套红的逻辑
							await _self.webOfficeInstance.frontTaohong(params.imgArray, params.allBookMark);
							var data = {
							  fileId: _self.params.fileId
							}
							callback && callback(null, data);
							resolve(data)
						} else {
							callback && callback(false, false);
							reject(false)
						}
					}
				});
			} else {
			  //刷新的时候调用强制刷新刷新内容
			  await _uploadWebofficeEditRefresh(result.fileId);
			  _self.openFile({fileId: result.fileId},function(error,result){
				callback && callback(error,result);
				resolve(result)
			  });
			}
		})
    })
}

PC端金山文档中台套红相关业务代码位置如下:

apps-office-plugins-front\desktop-front\src\office\js\kingSoftAdapter\kingSoftWebOffice.js通过KingSoftAdapter.js对业务代码进行调用。

移动端代码位置:

apps-office-plugins-front\mplus-front\src\webOffice\kingsoft\kingSoftAdapter.js

KingSoftOfficePlugin.prototype.taohong = async function (params, callback) {
	var _self = this;
	return new Promise((resolve, reject) => {
		OfficeSDK.utils.taohong(params, function (error, result) {
			if (error) {
				_self.webOfficeInstance.taohong(params, async (e, res) => {
					callback && callback(e, res);
					resolve(res)
				});
			}else{
				callback && callback(error, result);
				resolve(result)
			}
		})
	})
}

移动端金山文档中台套红相关业务代码位置如下:

apps-office-plugins-front\mplus-front\src\webOffice\kingSoftWebOffice.js通过KingSoftAdapter.js对业务代码进行调用。

# 2. 后台代码

金山文档中台后端套红代码接口信息如下:

请求方式:POST
请求地址:/rest/webOffice/format/taohong

金山文档中台代码位置:

apps-office-plugins\src\main\java\com\seeyon\ctp\rest\resources\WebOfficeFormatResource.java

代码入口如下:

@Path("/taohong")
@POST
@ApiOperation(name = "套红", scenes = "套红")
public Object taohong(@RequestBody TaoHongParams taoHongParams) throws BusinessException {
	// 获取模板
	if(taoHongParams == null){
		return this.fail("taoHongParams is null");
	}
	try {
		DocumentInfo info = formatControlManager.taohong(taoHongParams);
		return this.success(info);
	}catch (Exception e){
		log.error("后端套红出错",e);
		return this.fail(e.getMessage());
	}
}

# 4. WPS加载项

# 1. 前端代码

WPS加载项套红采用的是再客户端进行套红,目前暂时不支持移动端套红

PC代码位置:

apps-office-plugins-front\desktop-front\src\office\js\wpsAdapter\wpsAdapter.js

WpsAdapter.prototype.taohong = async function (params={}, callback){
	if(!await this.checkOpenState()){
		return false;
	}
	let allBM = {};
	params.allBookMark && params.allBookMark.forEach((item) => {
		if(item.type=='TEXT'){
			allBM[item.bookmark] = item.text;
		}else if(item.type === "IMAGE"){
			let imgInfo=item.imgInfo;
			if(typeof(imgInfo) !="undefined") {
				let imgValObj = {inputType: imgInfo.inputType};
				imgValObj["value"] = imgInfo.value;
				imgValObj["isSignatrue"] = "false";
				var imgVal = [["imgsign", imgValObj]];
				allBM[item.bookmark] = imgVal;
			}
		}else{
			if(item.bookmark.indexOf("FJ_正文")==0 || (params.extParam.category == "32" && item.type == "DOCUMENT")){
				let fileInfo=item.fileInfo;
				allBM[item.bookmark]={"FJContent":fileInfo.fileId,"fileName":fileInfo.fileName,"fileType":fileInfo.fileType};
			}else {
				allBM[item.bookmark] = item;
			}
		}
	});
	var wpsTaohongParam ={
		fileId:this.options.fileId,
		// 执行操作
		handleType: params.templateType=="edoc" ? HANDLE_TYPE.BodyInsertRed : HANDLE_TYPE.FormInsertRed,
		// 模版id
		templateUrl:params.templateUrl,
		redFileElement: allBM,
		//插入正文对应的元素
		bkInsertFile:'Content', //Content
		zhInsertFile:'正文', //正文
		editType: "1,0",
		istaohong:true
	}
	if (!WpsUtil.isEmptyObject(params.extParam)) {
		if (params.extParam["useOriginContentTaohong"] == true) {
			// 原正文套红
			wpsTaohongParam["useOriginContentTaohong"] = params.extParam["useOriginContentTaohong"];
			wpsTaohongParam["originContentId"] = params.extParam["originContentId"];
		} else {
			// 文单套红,可修改,但不能保存到oa,直接不清稿操作
			if(wpsTaohongParam.handleType==HANDLE_TYPE.FormInsertRed){
				wpsTaohongParam["wpsFileSaveToServer"] = params.extParam.wpsFileSaveToServer || '';
				wpsTaohongParam["isFromDocTaoHong"] = true;//是否来于文单套红
			}
		}
	}
	//信息报送-期刊套红
	try {
		if(params.extParam.category=="32") {
			wpsTaohongParam.category = "32";
			if (params.extParam.dataList && (params.extParam.dataList.length > 0|| Object.keys(params.extParam.dataList).length > 0)) {
				wpsTaohongParam.dataList = params.extParam.dataList;
			}
		}
	} catch(e) {}
	await this.active();
	await InsertRedHead(wpsTaohongParam);
	callback && callback(null,true);
	return true;
}
创建人:qingsg
修改人:het、liangyd