提交 a355b167823a66be2e5e1515b62cad3e73a0c1f6

作者 yongkangw
0 个父辈

wps-oa插件

Signed-off-by: yongkangw <yongkangw@chinadci.com>
  1 +BROWSER=none
  2 +
  3 +PUBLIC_URL='.'
\ No newline at end of file
... ...
  1 +{
  2 + "name": "wps-oa",
  3 + "addonType": "wps",
  4 + "version": "1.0.0",
  5 + "private": true,
  6 + "dependencies": {
  7 + "axios": "^0.19.2",
  8 + "http-server": "^0.12.3",
  9 + "immutable": "^4.0.0-rc.12",
  10 + "react": "^16.13.1",
  11 + "react-dom": "^16.13.1",
  12 + "react-redux": "^7.2.0",
  13 + "react-router-dom": "^5.2.0",
  14 + "react-scripts": "3.4.1",
  15 + "redux": "^4.0.5"
  16 + },
  17 + "scripts": {
  18 + "start": "set PORT=3889 && react-scripts start",
  19 + "build": "react-scripts build",
  20 + "test": "react-scripts test",
  21 + "eject": "react-scripts eject"
  22 + },
  23 + "eslintConfig": {
  24 + "extends": "react-app",
  25 + "globals": {
  26 + "wps": "readonly"
  27 + }
  28 + },
  29 + "browserslist": {
  30 + "production": [
  31 + ">0.2%",
  32 + "not dead",
  33 + "not op_mini all"
  34 + ],
  35 + "development": [
  36 + "last 1 chrome version",
  37 + "last 1 firefox version",
  38 + "last 1 safari version"
  39 + ]
  40 + },
  41 + "devDependencies": {
  42 + "wps-jsapi": "latest"
  43 + }
  44 +}
\ No newline at end of file
... ...
  1 +http://127.0.0.1:3889/.debugTemp/systemdemo.html
\ No newline at end of file
... ...
  1 +var projInfo = {"name":"wps-oa","type":"wps"}
\ No newline at end of file
... ...
  1 +<!DOCTYPE html>
  2 +<html>
  3 +<meta http-equiv="X-UA-Compatible" content="IE=edge chrome=1">
  4 +
  5 +<head>
  6 + <meta charset="utf-8">
  7 + <meta http-equiv="X-UA-Compatible" content="IE=8">
  8 + <title>业务系统模拟页面</title>
  9 + <script type="text/javascript" src="./wpsjsrpcsdk.js"></script>
  10 + <script type="text/javascript" src="./project.js"></script>
  11 +</head>
  12 +
  13 +<body>
  14 + <div class="divTitle">XXX业务系统-前端模拟页面</div>
  15 + <div>
  16 + <div class="partItem">单进程模式:</div>
  17 + <div class="divItem">
  18 + <li><a href="#" onclick="openOfficeFile('http://我是文件的服务端地址')">打开业务系统文件</a></li>
  19 + </div>
  20 + <div class="divItem">
  21 + <li><a href="#" onclick="onDivClick('getDocumentName', false)">获取wps当前打开的文件的文件名</a></li>
  22 + </div>
  23 + <div class="divItem">
  24 + <li><a href="#" onclick="onDivClick('newDocument', true)">新建一个文件</a></li>
  25 + </div>
  26 + <div class="divItem">请点击wps加载项“给业务系统发通知”按钮,体验加载项主动发送消息</div>
  27 + <div class="divItem">消息内容:<span style="font-weight: bolder;color: red;" id="webnotifyspan"></span></div>
  28 + </div>
  29 +
  30 + <div id='tishi'>
  31 + <p style="text-align: center;">正在打开文件</p>
  32 + <p>
  33 + <progress id="openFile" value="0" max="100">
  34 + <p style="text-align: center;">当前进度<span id="openfilespan" style="color:crimson;">0</span>%</p>
  35 + </progress>
  36 + </p>
  37 + </div>
  38 +
  39 + <div>
  40 + <div class="partItem">多进程模式:</div>
  41 + <li><a href="#" onclick="openFileInSilentMode()">新建客户端:静默打开文件</a>
  42 + </li>
  43 + <div id="rootClients"></div>
  44 + </div>
  45 +
  46 + <div class="divNote">
  47 + <hr>
  48 + <p>
  49 + 更详细的与B/S业务系统集成的能力相关的示例,请参考:
  50 + <span style="font-weight: bolder;color: slateblue;"><a
  51 + href="https://code.aliyun.com/zouyingfeng/wps/blob/master/README.md" target="_blank">
  52 + https://code.aliyun.com/zouyingfeng/wps/blob/master/README.md
  53 + </a></span>
  54 + </p>
  55 + <p>
  56 + 和我们一起构建WPS开发者社区,可以来<a href="https://zhuanlan.zhihu.com/c_1256350603921915904"
  57 + target="_blank">「WPS二次开发」</a>转转,留下您的评论。
  58 + </p>
  59 + </div>
  60 +</body>
  61 +<script>
  62 + //实际的开发中,业务系统与wps加载项的交互代码如下:
  63 + var callbackFunc = function (result) {
  64 + if (result.status == 0) {
  65 + //下面这行代码用来注册从wps加载项返回的消息的接收函数
  66 + WpsInvoke.RegWebNotify(projInfo.type, projInfo.name, function (messageText) {
  67 + var span = document.getElementById("webnotifyspan")
  68 + span.innerHTML = messageText
  69 + })
  70 + alert(result.response)
  71 + }
  72 + else
  73 + alert(result.message)
  74 + }
  75 +
  76 + function openOfficeFile(param) {
  77 + var invokeParam = {
  78 + flag: "openOfficeFile",
  79 + filepath: param
  80 + } //根据需求任意定义
  81 + WpsInvoke.InvokeAsHttp(
  82 + projInfo.type,
  83 + projInfo.name, //wps加载项的名字,在实际项目中写上对应的名字
  84 + "openOfficeFileFromSystemDemo", //要调用的在wps加载项中的函数名
  85 + JSON.stringify(invokeParam), //调用的在wps加载项中的函数要传递的数据,是一个json对象,根据业务系统需求任意定义
  86 + callbackFunc) //回调函数,wps加载项中InvokeFromSystemDemo这个函数的返回值作为这个函数的参数
  87 + }
  88 +
  89 + function onDivClick(param, showToFront) {
  90 + var invokeParam = {
  91 + 按需求定义: "安需求给值",
  92 + Index: param,
  93 + AppType: projInfo.type,
  94 + 自定义: {
  95 + xxx定义: "xxx值"
  96 + }
  97 + } //根据需求任意定义
  98 + WpsInvoke.InvokeAsHttp(
  99 + projInfo.type,
  100 + projInfo.name, //wps加载项的名字,在实际项目中写上对应的名字
  101 + "InvokeFromSystemDemo", //要调用的在wps加载项中的函数名
  102 + JSON.stringify(invokeParam), //调用的在wps加载项中的函数要传递的数据,是一个json对象,根据业务系统需求任意定义
  103 + callbackFunc, //回调函数,wps加载项中InvokeFromSystemDemo这个函数的返回值作为这个函数的参数
  104 + showToFront) //设置wps是否显示到最前面来
  105 + }
  106 +
  107 + //WebNotifyUseTimeout()
  108 + var clientCount = 0;
  109 + var dialogProgress; //打开文件进度计数
  110 + var interval; //window.setInterval对象
  111 + function openFileInSilentMode() {
  112 + var dlg = document.getElementById("tishi");
  113 + dlg.style.display = 'block';
  114 + dialogProgress = 0
  115 + interval = setInterval(updateProgress, 100)
  116 + document.body.style.pointerEvents = "none"
  117 +
  118 + var houzui = ".xlsx";
  119 + if (projInfo.type == "wps")
  120 + houzui = ".docx"
  121 + else if (projInfo.type == "wpp")
  122 + houzui = ".pptx"
  123 + var url = location.protocol + "//" + location.host + "/.debugTemp/" + projInfo.type + "Demo" + houzui;
  124 + var wpsClient = new WpsClient(projInfo.type);
  125 + var eleId = "clientId" + (++clientCount);
  126 + var WebNotifycount = 0;
  127 + wpsClient.onMessage = function (messageText) {
  128 + ++WebNotifycount;
  129 + var spanDiv = document.getElementById("webnotifyCount" + eleId);
  130 + spanDiv.innerText = "(次数:" + WebNotifycount + "):";
  131 + var span = document.getElementById("webnotifyspan" + eleId);
  132 + span.innerHTML = messageText;
  133 + }
  134 + //先静默启动客户端,在回调函数里面实现打开大文件
  135 + wpsClient.StartWpsInSilentMode(projInfo.name, function () {
  136 + var invokeParam = {
  137 + 按需求定义: "安需求给值",
  138 + Index: 'OpenFile',
  139 + AppType: projInfo.type,
  140 + filepath: url, //要打开的文件路径
  141 + 自定义: {
  142 + xxx定义: "xxx值"
  143 + }
  144 + } //根据需求任意定义
  145 + wpsClient.InvokeAsHttp(
  146 + projInfo.name, //wps加载项的名字,在实际项目中写上对应的名字
  147 + "InvokeFromSystemDemo", //要调用的在wps加载项中的函数名
  148 + JSON.stringify(invokeParam), //调用的在wps加载项中的函数要传递的数据,是一个json对象,根据业务系统需求任意定义
  149 + openFileCallbackFunc, //回调函数,wps加载项中InvokeFromSystemDemo这个函数的返回值作为这个函数的参数
  150 + false) //设置wps是否显示到最前面来
  151 + });
  152 +
  153 + //打开文件成功后的交互代码
  154 + function openFileCallbackFunc(result) {
  155 + clearInterval(interval);
  156 + //console.log(JSON.stringify(result))
  157 + if (result.status !== 0) {
  158 + setProgress(0)
  159 + var dlg = document.getElementById("tishi");
  160 + dlg.style.display = 'none';
  161 + document.body.style.pointerEvents = "auto"
  162 + alert(result.message)
  163 + return;
  164 + }
  165 + setProgress(100);
  166 + wpsClient.ShowToFront(projInfo.name, function () {
  167 + setProgress(0)
  168 + var dlg = document.getElementById("tishi");
  169 + dlg.style.display = 'none';
  170 + document.body.style.pointerEvents = "auto"
  171 + });
  172 +
  173 + var rootElement = document.getElementById("rootClients");
  174 + var ele = document.createElement("div");
  175 + ele.className = "addonItem";
  176 + ele.id = eleId;
  177 + ele.client = wpsClient;
  178 + ele.innerHTML =
  179 + '<div class="clientItem">客户端' + clientCount + '\n' +
  180 + '<div class="divItem"><li><a href="#" onclick="onClientGetFileName(' + "'" + ele.id + "'" + ',' + "'getDocumentName'" + ', false' + ')">获取wps当前打开的文件的文件名</a></li></div>\n' +
  181 + '<div class="divItem"><li><a href="#" onclick="onClientGetFileName(' + "'" + ele.id + "'" + ',' + "'newDocument'" + ', true' + ')">新建一个文件</a></li></div>\n' +
  182 + '<div class="divItem">加载项主动发送的消息内容<span id="webnotifyCount' + ele.id + '"></span><span style="font-weight: bolder;color: red;" id="webnotifyspan' + ele.id + '"></span></div>'
  183 + '</div>';
  184 + rootElement.appendChild(ele);
  185 + }
  186 + }
  187 +
  188 + function onClientGetFileName(clientId, param, showToFront) {
  189 + var invokeParam = {
  190 + 按需求定义: "安需求给值",
  191 + Index: param,
  192 + AppType: projInfo.type,
  193 + 自定义: {
  194 + xxx定义: "xxx值"
  195 + }
  196 + } //根据需求任意定义
  197 + var ele = document.getElementById(clientId);
  198 + ele.client.InvokeAsHttp(
  199 + projInfo.name, //wps加载项的名字,在实际项目中写上对应的名字
  200 + "InvokeFromSystemDemo", //要调用的在wps加载项中的函数名
  201 + JSON.stringify(invokeParam), //调用的在wps加载项中的函数要传递的数据,是一个json对象,根据业务系统需求任意定义
  202 + clientCallbackFunc, //回调函数,wps加载项中InvokeFromSystemDemo这个函数的返回值作为这个函数的参数
  203 + showToFront) //设置wps是否显示到最前面来
  204 +
  205 + function clientCallbackFunc(result) {
  206 + if (result.status !== 0)
  207 + alert(result.message)
  208 + else {
  209 + if (result.response == "Failed to send message to WPS.") {
  210 + ele.client.IsClientRunning(function (status) {
  211 + if (status.response == "Client is running.")
  212 + alert("任务发送失败,WPS 正在执行其他任务,请前往WPS完成当前任务")
  213 + else
  214 + alert("WPS 客户端被关闭了!")
  215 + })
  216 + } else {
  217 + alert(result.response)
  218 + }
  219 + }
  220 + }
  221 + }
  222 +
  223 + function updateProgress() {
  224 + setProgress(++dialogProgress);
  225 + }
  226 + function setProgress(newValue) {
  227 + if (newValue < 90 || newValue == 100) {
  228 + var progress = document.getElementById('openFile');
  229 + progress.value = newValue;
  230 + var span = document.getElementById("openfilespan")
  231 + span.innerHTML = newValue;
  232 + }
  233 + }
  234 +</script>
  235 +<style>
  236 + .divTitle {
  237 + margin-top: 30px;
  238 + margin-bottom: 20px;
  239 + font-size: 40px;
  240 + font-weight: bolder;
  241 + text-align: center;
  242 + }
  243 +
  244 + .divItem {
  245 + margin: 5px;
  246 + }
  247 +
  248 + .divNote {
  249 + margin-top: 60px;
  250 + }
  251 +
  252 + #rootClients {
  253 + padding-left: 20px;
  254 + font-size: 15px;
  255 + }
  256 +
  257 + .clientItem {
  258 + margin: 5px;
  259 + }
  260 +
  261 + .partItem {
  262 + font-size: 20px;
  263 + margin: 5px;
  264 + padding-top: 20px;
  265 + }
  266 +
  267 + #tishi {
  268 + position: absolute;
  269 + left: 600px;
  270 + min-height: 150px;
  271 + border: 1px solid black;
  272 + padding: 10px 12px;
  273 + display: none;
  274 + background: #fff;
  275 +
  276 + }
  277 +</style>
  278 +
  279 +</html>
\ No newline at end of file
... ...
  1 +D:\JsProjects\wps-oa
\ No newline at end of file
... ...
不能预览此文件类型
  1 +(function (global, factory) {
  2 +
  3 + "use strict";
  4 +
  5 + if (typeof module === "object" && typeof module.exports === "object") {
  6 + module.exports = factory(global, true);
  7 + } else {
  8 + factory(global);
  9 + }
  10 +
  11 +})(typeof window !== "undefined" ? window : this, function (window, noGlobal) {
  12 +
  13 + "use strict";
  14 +
  15 + var bFinished = true;
  16 +
  17 + function getHttpObj() {
  18 + var httpobj = null;
  19 + if (IEVersion() < 10) {
  20 + try {
  21 + httpobj = new XDomainRequest();
  22 + } catch (e1) {
  23 + httpobj = new createXHR();
  24 + }
  25 + } else {
  26 + httpobj = new createXHR();
  27 + }
  28 + return httpobj;
  29 + }
  30 + //兼容IE低版本的创建xmlhttprequest对象的方法
  31 + function createXHR() {
  32 + if (typeof XMLHttpRequest != 'undefined') { //兼容高版本浏览器
  33 + return new XMLHttpRequest();
  34 + } else if (typeof ActiveXObject != 'undefined') { //IE6 采用 ActiveXObject, 兼容IE6
  35 + var versions = [ //由于MSXML库有3个版本,因此都要考虑
  36 + 'MSXML2.XMLHttp.6.0',
  37 + 'MSXML2.XMLHttp.3.0',
  38 + 'MSXML2.XMLHttp'
  39 + ];
  40 +
  41 + for (var i = 0; i < versions.length; i++) {
  42 + try {
  43 + return new ActiveXObject(versions[i]);
  44 + } catch (e) {
  45 + //跳过
  46 + }
  47 + }
  48 + } else {
  49 + throw new Error('您的浏览器不支持XHR对象');
  50 + }
  51 + }
  52 +
  53 + function startWps(options) {
  54 + if (!bFinished && !options.concurrent) {
  55 + if (options.callback)
  56 + options.callback({
  57 + status: 1,
  58 + message: "上一次请求没有完成"
  59 + });
  60 + return;
  61 + }
  62 + bFinished = false;
  63 +
  64 + function startWpsInnder(tryCount) {
  65 + if (tryCount <= 0) {
  66 + if (bFinished)
  67 + return;
  68 + bFinished = true;
  69 + if (options.callback)
  70 + options.callback({
  71 + status: 2,
  72 + message: "请允许浏览器打开WPS Office"
  73 + });
  74 + return;
  75 + }
  76 + var xmlReq = getHttpObj();
  77 + //WPS客户端提供的接收参数的本地服务,HTTP服务端口为58890,HTTPS服务端口为58891
  78 + //这俩配置,取一即可,不可同时启用
  79 + xmlReq.open('POST', options.url);
  80 + xmlReq.onload = function (res) {
  81 + bFinished = true;
  82 + if (options.callback) {
  83 + options.callback({
  84 + status: 0,
  85 + response: IEVersion() < 10 ? xmlReq.responseText : res.target.response
  86 + });
  87 + }
  88 + }
  89 + xmlReq.ontimeout = xmlReq.onerror = function (res) {
  90 + xmlReq.bTimeout = true;
  91 + if (tryCount == options.tryCount && options.bPop) { //打开wps并传参
  92 + window.location.href = "ksoWPSCloudSvr://start=RelayHttpServer" //是否启动wps弹框
  93 + }
  94 + setTimeout(function () {
  95 + startWpsInnder(tryCount - 1)
  96 + }, 1000);
  97 + }
  98 + if (IEVersion() < 10) {
  99 + xmlReq.onreadystatechange = function () {
  100 + if (xmlReq.readyState != 4)
  101 + return;
  102 + if (xmlReq.bTimeout) {
  103 + return;
  104 + }
  105 + if (xmlReq.status === 200)
  106 + xmlReq.onload();
  107 + else
  108 + xmlReq.onerror();
  109 + }
  110 + }
  111 + xmlReq.timeout = options.timeout;
  112 + xmlReq.send(options.sendData)
  113 + }
  114 + startWpsInnder(options.tryCount);
  115 + return;
  116 + }
  117 +
  118 + var fromCharCode = String.fromCharCode;
  119 + // encoder stuff
  120 + var cb_utob = function (c) {
  121 + if (c.length < 2) {
  122 + var cc = c.charCodeAt(0);
  123 + return cc < 0x80 ? c :
  124 + cc < 0x800 ? (fromCharCode(0xc0 | (cc >>> 6)) +
  125 + fromCharCode(0x80 | (cc & 0x3f))) :
  126 + (fromCharCode(0xe0 | ((cc >>> 12) & 0x0f)) +
  127 + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) +
  128 + fromCharCode(0x80 | (cc & 0x3f)));
  129 + } else {
  130 + var cc = 0x10000 +
  131 + (c.charCodeAt(0) - 0xD800) * 0x400 +
  132 + (c.charCodeAt(1) - 0xDC00);
  133 + return (fromCharCode(0xf0 | ((cc >>> 18) & 0x07)) +
  134 + fromCharCode(0x80 | ((cc >>> 12) & 0x3f)) +
  135 + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) +
  136 + fromCharCode(0x80 | (cc & 0x3f)));
  137 + }
  138 + };
  139 + var re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g;
  140 + var utob = function (u) {
  141 + return u.replace(re_utob, cb_utob);
  142 + };
  143 + var _encode = function (u) {
  144 + var isUint8Array = Object.prototype.toString.call(u) === '[object Uint8Array]';
  145 + if (isUint8Array)
  146 + return u.toString('base64')
  147 + else
  148 + return btoa(utob(String(u)));
  149 + }
  150 +
  151 + if (typeof window.btoa !== 'function') window.btoa = func_btoa;
  152 +
  153 + function func_btoa(input) {
  154 + var str = String(input);
  155 + var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
  156 + for (
  157 + // initialize result and counter
  158 + var block, charCode, idx = 0, map = chars, output = '';
  159 + // if the next str index does not exist:
  160 + // change the mapping table to "="
  161 + // check if d has no fractional digits
  162 + str.charAt(idx | 0) || (map = '=', idx % 1);
  163 + // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8
  164 + output += map.charAt(63 & block >> 8 - idx % 1 * 8)
  165 + ) {
  166 + charCode = str.charCodeAt(idx += 3 / 4);
  167 + if (charCode > 0xFF) {
  168 + throw new InvalidCharacterError("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");
  169 + }
  170 + block = block << 8 | charCode;
  171 + }
  172 + return output;
  173 + }
  174 +
  175 + var encode = function (u, urisafe) {
  176 + return !urisafe ?
  177 + _encode(u) :
  178 + _encode(String(u)).replace(/[+\/]/g, function (m0) {
  179 + return m0 == '+' ? '-' : '_';
  180 + }).replace(/=/g, '');
  181 + };
  182 +
  183 + function IEVersion() {
  184 + var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串
  185 + var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1; //判断是否IE<11浏览器
  186 + var isEdge = userAgent.indexOf("Edge") > -1 && !isIE; //判断是否IE的Edge浏览器
  187 + var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf("rv:11.0") > -1;
  188 + if (isIE) {
  189 + var reIE = new RegExp("MSIE (\\d+\\.\\d+);");
  190 + reIE.test(userAgent);
  191 + var fIEVersion = parseFloat(RegExp["$1"]);
  192 + if (fIEVersion == 7) {
  193 + return 7;
  194 + } else if (fIEVersion == 8) {
  195 + return 8;
  196 + } else if (fIEVersion == 9) {
  197 + return 9;
  198 + } else if (fIEVersion == 10) {
  199 + return 10;
  200 + } else {
  201 + return 6; //IE版本<=7
  202 + }
  203 + } else if (isEdge) {
  204 + return 20; //edge
  205 + } else if (isIE11) {
  206 + return 11; //IE11
  207 + } else {
  208 + return 30; //不是ie浏览器
  209 + }
  210 + }
  211 +
  212 + function WpsStart(options) {
  213 + var startInfo = {
  214 + "name": options.name,
  215 + "function": options.func,
  216 + "info": options.param.param,
  217 + "jsPluginsXml": options.param.jsPluginsXml
  218 + };
  219 + var strData = JSON.stringify(startInfo);
  220 + if (IEVersion() < 10) {
  221 + try {
  222 + eval("strData = '" + JSON.stringify(startInfo) + "';");
  223 + } catch (err) {
  224 +
  225 + }
  226 + }
  227 +
  228 + var baseData = encode(strData);
  229 + var url = options.urlBase + "/" + options.clientType + "/runParams";
  230 + var data = "ksowebstartup" + options.clientType + "://" + baseData;
  231 + startWps({
  232 + url: url,
  233 + sendData: data,
  234 + callback: options.callback,
  235 + tryCount: options.tryCount,
  236 + bPop: options.bPop,
  237 + timeout: 5000,
  238 + concurrent: false,
  239 + client: options.wpsclient
  240 + });
  241 + }
  242 +
  243 + function WpsStartWrap(options) {
  244 + WpsStart({
  245 + clientType: options.clientType,
  246 + name: options.name,
  247 + func: options.func,
  248 + param: options.param,
  249 + urlBase: options.urlBase,
  250 + callback: options.callback,
  251 + tryCount: 4,
  252 + bPop: true,
  253 + wpsclient: options.wpsclient,
  254 + })
  255 + }
  256 +
  257 + /**
  258 + * 支持浏览器触发,WPS有返回值的启动
  259 + *
  260 + * @param {*} clientType 组件类型
  261 + * @param {*} name WPS加载项名称
  262 + * @param {*} func WPS加载项入口方法
  263 + * @param {*} param 参数:包括WPS加载项内部定义的方法,参数等
  264 + * @param {*} callback 回调函数
  265 + * @param {*} tryCount 重试次数
  266 + * @param {*} bPop 是否弹出浏览器提示对话框
  267 + */
  268 + var exId = 0;
  269 + function WpsStartWrapExInner(options) {
  270 + var infocontent = options.param.param;
  271 + if (!options.wpsclient) {
  272 + infocontent = JSON.stringify(options.param.param);
  273 + var rspUrl = options.urlBase + "/transferEcho/runParams";
  274 + var time = new Date();
  275 + var cmdId = "js" + time.getTime() + "_" + exId;
  276 + var funcEx = "var res = " + options.func;
  277 + var cbCode = "var xhr = new XMLHttpRequest();xhr.open('POST', '" + rspUrl + "');xhr.send(JSON.stringify({id: '" + cmdId + "', response: res}));" //res 为func执行返回值
  278 + var infoEx = infocontent + ");" + cbCode + "void(0";
  279 + options.func = funcEx;
  280 + infocontent = infoEx;
  281 + }
  282 + var startInfo = {
  283 + "name": options.name,
  284 + "function": options.func,
  285 + "info": infocontent,
  286 + "showToFront": options.param.showToFront,
  287 + "jsPluginsXml": options.param.jsPluginsXml,
  288 + };
  289 +
  290 + var strData = JSON.stringify(startInfo);
  291 + if (IEVersion() < 10) {
  292 + try {
  293 + eval("strData = '" + JSON.stringify(startInfo) + "';");
  294 + } catch (err) {
  295 +
  296 + }
  297 + }
  298 +
  299 + var baseData = encode(strData);
  300 + var wrapper;
  301 +
  302 + if (!options.wpsclient) {
  303 + var url = options.urlBase + "/transfer/runParams";
  304 + var data = "ksowebstartup" + options.clientType + "://" + baseData;
  305 + wrapper = {
  306 + id: cmdId,
  307 + app: options.clientType,
  308 + data: data
  309 + };
  310 + }
  311 + else {
  312 + var url = options.urlBase + "/transferEx/runParams";
  313 + wrapper = {
  314 + id: options.wpsclient.clientId,
  315 + app: options.clientType,
  316 + data: baseData,
  317 + mode: options.wpsclient.silentMode ? "true" : "false"
  318 + };
  319 + }
  320 + wrapper = JSON.stringify(wrapper);
  321 + startWps({
  322 + url: url,
  323 + sendData: wrapper,
  324 + callback: options.callback,
  325 + tryCount: options.tryCount,
  326 + bPop: options.bPop,
  327 + timeout: 0,
  328 + concurrent: options.concurrent,
  329 + client: options.wpsclient
  330 + });
  331 + }
  332 +
  333 + var serverVersion = "wait"
  334 + var cloudSvrStart = true;
  335 + function WpsStartWrapVersionInner(options) {
  336 + if (serverVersion == "wait") {
  337 + if (cloudSvrStart == false) {
  338 + window.location.href = "ksoWPSCloudSvr://start=RelayHttpServer" //是否启动wps弹框
  339 + }
  340 + startWps({
  341 + url: options.urlBase + '/version',
  342 + data: "",
  343 + callback: function (res) {
  344 + if (res.status !== 0) {
  345 + options.callback(res)
  346 + return;
  347 + }
  348 + serverVersion = res.response;
  349 + cloudSvrStart = true;
  350 + options.tryCount = 1
  351 + options.bPop = false
  352 + if (serverVersion === "") {
  353 + WpsStart(options)
  354 + } else if (serverVersion < "1.0.1" && options.wpsclient) {
  355 + if (options.callback) {
  356 + options.callback({
  357 + status: 4,
  358 + message: "当前客户端不支持,请升级客户端"
  359 + })
  360 + }
  361 + } else {
  362 + WpsStartWrapExInner(options);
  363 + }
  364 + },
  365 + tryCount: 4,
  366 + bPop: true,
  367 + timeout: 5000,
  368 + concurrent: options.concurrent
  369 + });
  370 + } else {
  371 + if (serverVersion === "") {
  372 + WpsStartWrap(options)
  373 + } else if (serverVersion < "1.0.1" && options.wpsclient) {
  374 + if (options.callback) {
  375 + options.callback({
  376 + status: 4,
  377 + message: "当前客户端不支持,请升级客户端"
  378 + })
  379 + }
  380 + } else {
  381 + options.tryCount = 1
  382 + options.bPop = true
  383 + WpsStartWrapExInner(options);
  384 + }
  385 + }
  386 + }
  387 +
  388 + var HeartBeatCode =
  389 + "function getHttpObj() {\n"
  390 ++" var httpobj = null;\n"
  391 ++" if (IEVersion() < 10) {\n"
  392 ++" try {\n"
  393 ++" httpobj = new XDomainRequest();\n"
  394 ++" } catch (e1) {\n"
  395 ++" httpobj = new createXHR();\n"
  396 ++" }\n"
  397 ++" } else {\n"
  398 ++" httpobj = new createXHR();\n"
  399 ++" }\n"
  400 ++" return httpobj;\n"
  401 ++" }\n"
  402 ++" \n"
  403 ++" function createXHR() {\n"
  404 ++" if (typeof XMLHttpRequest != 'undefined') {\n"
  405 ++" return new XMLHttpRequest();\n"
  406 ++" } else if (typeof ActiveXObject != 'undefined') {\n"
  407 ++" var versions = [\n"
  408 ++" 'MSXML2.XMLHttp.6.0',\n"
  409 ++" 'MSXML2.XMLHttp.3.0',\n"
  410 ++" 'MSXML2.XMLHttp'\n"
  411 ++" ];\n"
  412 ++" \n"
  413 ++" for (var i = 0; i < versions.length; i++) {\n"
  414 ++" try {\n"
  415 ++" return new ActiveXObject(versions[i]);\n"
  416 ++" } catch (e) {\n"
  417 ++" \n"
  418 ++" }\n"
  419 ++" }\n"
  420 ++" } else {\n"
  421 ++" throw new Error('您的浏览器不支持XHR对象');\n"
  422 ++" }\n"
  423 ++" }\n"
  424 ++" \n"
  425 ++" function IEVersion() {\n"
  426 ++" var userAgent = navigator.userAgent; \n"
  427 ++" var isIE = userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1;\n"
  428 ++" var isEdge = userAgent.indexOf('Edge') > -1 && !isIE; \n"
  429 ++" var isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf('rv:11.0') > -1;\n"
  430 ++" if (isIE) {\n"
  431 ++" var reIE = new RegExp('MSIE (\\d+\\.\\d+);');\n"
  432 ++" reIE.test(userAgent);\n"
  433 ++" var fIEVersion = parseFloat(RegExp['$1']);\n"
  434 ++" if (fIEVersion == 7) {\n"
  435 ++" return 7;\n"
  436 ++" } else if (fIEVersion == 8) {\n"
  437 ++" return 8;\n"
  438 ++" } else if (fIEVersion == 9) {\n"
  439 ++" return 9;\n"
  440 ++" } else if (fIEVersion == 10) {\n"
  441 ++" return 10;\n"
  442 ++" } else {\n"
  443 ++" return 6; \n"
  444 ++" }\n"
  445 ++" } else if (isEdge) {\n"
  446 ++" return 20; \n"
  447 ++" } else if (isIE11) {\n"
  448 ++" return 11; \n"
  449 ++" } else {\n"
  450 ++" return 30; \n"
  451 ++" }\n"
  452 ++" }\n"
  453 ++" var heartBeatStart = false;\n"
  454 ++" function checkLastRegTime() {\n"
  455 ++" var now = new Date().valueOf();\n"
  456 ++" var TimeGap = now - LastRegTime;\n"
  457 ++" if (TimeGap > 5000 && !heartBeatStart) {\n"
  458 ++" HeartBeat();\n"
  459 ++" heartBeatStart = true;\n"
  460 ++" }\n"
  461 ++" }\n"
  462 ++" \n"
  463 ++" function HeartBeat() {\n"
  464 ++" var heartBeatItem = function () {\n"
  465 ++" var xhr = getHttpObj();\n"
  466 ++" xhr.onload = function (e) {\n"
  467 ++" self.setTimeout(heartBeatItem, 5000);\n"
  468 ++" }\n"
  469 ++" xhr.onerror = function (e) {\n"
  470 ++" self.setTimeout(heartBeatItem, 5000);\n"
  471 ++" }\n"
  472 ++" xhr.ontimeout = function (e) {\n"
  473 ++" self.setTimeout(heartBeatItem, 5000);\n"
  474 ++" }\n"
  475 ++" xhr.open('POST', 'http://127.0.0.1:58890/askwebnotify', true);\n"
  476 ++" xhr.timeout = 2000;\n"
  477 ++" xhr.send(JSON.stringify(paramStr));\n"
  478 ++" }\n"
  479 ++" heartBeatItem();\n"
  480 ++" }\n"
  481 ++" \n"
  482 ++" var paramStr;\n"
  483 ++" var startCheck = false;\n"
  484 ++" self.addEventListener('message', function (event) {\n"
  485 ++" var data = event.data;\n"
  486 ++" paramStr = data.param\n"
  487 ++" paramStr.heartBeat = true\n"
  488 ++" LastRegTime = data.LastRegTime;\n"
  489 ++" if (!startCheck) {\n"
  490 ++" startCheck = true;\n"
  491 ++" self.setInterval(checkLastRegTime, 5000)\n"
  492 ++" }\n"
  493 ++" }, false);\n"
  494 +
  495 + function codeToBlob(code) {
  496 + var blob = new Blob([code], { type: 'text/javascript' }); // 生成js文件对象
  497 + var objectURL = window.URL.createObjectURL(blob); // 生成js文件的url
  498 + return objectURL;
  499 + }
  500 +
  501 + var RegWebNotifyMap = { wps: {}, wpp: {}, et: {} }
  502 + var bWebNotifyUseTimeout = true
  503 + function WebNotifyUseTimeout(value) {
  504 + bWebNotifyUseTimeout = value ? true : false
  505 + }
  506 + var g_businessId = Number(Math.random().toString().substr(3, 5) + Date.parse(new Date())).toString(36);
  507 + var HeartBeatWorker
  508 + if (window.Worker) {
  509 + try {
  510 + HeartBeatWorker = new Worker(codeToBlob(HeartBeatCode));
  511 + } catch (error) {
  512 + //
  513 + }
  514 + }
  515 + var g_LastRegTime;
  516 + /**
  517 + * 注册一个前端页面接收WPS传来消息的方法
  518 + * @param {*} clientType wps | et | wpp
  519 + * @param {*} name WPS加载项的名称
  520 + * @param {*} callback 回调函数
  521 + */
  522 + function RegWebNotify(clientType, name, callback, wpsclient) {
  523 + if (clientType != "wps" && clientType != "wpp" && clientType != "et")
  524 + return;
  525 + var paramStr = {}
  526 + if (wpsclient) {
  527 + if (wpsclient.notifyRegsitered == true) {
  528 + return
  529 + }
  530 + wpsclient.notifyRegsitered = true;
  531 + paramStr = {
  532 + clientId: wpsclient.clientId,
  533 + name: name,
  534 + type: clientType
  535 + }
  536 + if (HeartBeatWorker)
  537 + paramStr.businessId = g_businessId
  538 + }
  539 + else {
  540 + if (typeof callback != 'function')
  541 + return
  542 + if (RegWebNotifyMap[clientType][name]) {
  543 + RegWebNotifyMap[clientType][name] = callback;
  544 + return
  545 + }
  546 + var RegWebNotifyID = new Date().valueOf() + ''
  547 + paramStr = {
  548 + id: RegWebNotifyID,
  549 + name: name,
  550 + type: clientType
  551 + }
  552 + if (HeartBeatWorker)
  553 + paramStr.businessId = g_businessId
  554 + RegWebNotifyMap[clientType][name] = callback
  555 + }
  556 +
  557 + var askItem = function () {
  558 + var xhr = getHttpObj()
  559 + xhr.onload = function (e) {
  560 + if (xhr.responseText == "WPSInnerMessage_quit") {
  561 + RegWebNotifyMap[clientType][name] = undefined;
  562 + return;
  563 + }
  564 + try {
  565 + var resText = JSON.parse(xhr.responseText);
  566 + if(typeof resText == 'object'){
  567 + paramStr.messageId = resText.msgId;
  568 + }
  569 + if (wpsclient) {
  570 + wpsclient.OnRegWebNotify(resText.data)
  571 + } else {
  572 + var func = RegWebNotifyMap[clientType][name]
  573 + func(resText.data)
  574 + }
  575 + }
  576 + catch (e) {
  577 + if (wpsclient) {
  578 + wpsclient.OnRegWebNotify(xhr.responseText)
  579 + } else {
  580 + var func = RegWebNotifyMap[clientType][name]
  581 + func(xhr.responseText)
  582 + }
  583 + }
  584 + window.setTimeout(askItem, 300)
  585 + }
  586 + xhr.onerror = function (e) {
  587 + if (bWebNotifyUseTimeout)
  588 + window.setTimeout(askItem, 1000)
  589 + else
  590 + window.setTimeout(askItem, 10000)
  591 + }
  592 + xhr.ontimeout = function (e) {
  593 + if (bWebNotifyUseTimeout)
  594 + window.setTimeout(askItem, 300)
  595 + else
  596 + window.setTimeout(askItem, 10000)
  597 + }
  598 + if (IEVersion() < 10) {
  599 + xhr.onreadystatechange = function () {
  600 + if (xhr.readyState != 4)
  601 + return;
  602 + if (xhr.bTimeout) {
  603 + return;
  604 + }
  605 + if (xhr.status === 200)
  606 + xhr.onload();
  607 + else
  608 + xhr.onerror();
  609 + }
  610 + }
  611 + xhr.open('POST', GetUrlBase() + '/askwebnotify', true)
  612 + if (bWebNotifyUseTimeout)
  613 + xhr.timeout = 2000;
  614 + if (HeartBeatWorker){
  615 + g_LastRegTime = new Date().valueOf();
  616 + var param = {
  617 + param : {
  618 + name: projInfo.name,
  619 + type: projInfo.type,
  620 + businessId: g_businessId
  621 + },
  622 + LastRegTime: g_LastRegTime
  623 + }
  624 + HeartBeatWorker.postMessage(param)
  625 + }
  626 + xhr.send(JSON.stringify(paramStr));
  627 + }
  628 + window.setTimeout(askItem, 2000)
  629 + }
  630 +
  631 + function GetUrlBase() {
  632 + if (location.protocol == "http:")
  633 + return "http://127.0.0.1:58890"
  634 + return "https://127.0.0.1:58891"
  635 + }
  636 +
  637 + function WpsStartWrapVersion(clientType, name, func, param, callback, showToFront, jsPluginsXml) {
  638 + var paramEx = {
  639 + jsPluginsXml: jsPluginsXml ? jsPluginsXml : "",
  640 + showToFront: typeof (showToFront) == 'boolean' ? showToFront : true,
  641 + param: (typeof (param) == 'object' ? param : JSON.parse(param))
  642 + }
  643 + var options = {
  644 + clientType: clientType,
  645 + name: name,
  646 + func: func,
  647 + param: paramEx,
  648 + urlBase: GetUrlBase(),
  649 + callback: callback,
  650 + wpsclient: undefined,
  651 + concurrent: true
  652 + }
  653 + WpsStartWrapVersionInner(options);
  654 + }
  655 +
  656 + //从外部浏览器远程调用 WPS 加载项中的方法
  657 + var WpsInvoke = {
  658 + InvokeAsHttp: WpsStartWrapVersion,
  659 + InvokeAsHttps: WpsStartWrapVersion,
  660 + RegWebNotify: RegWebNotify,
  661 + ClientType: {
  662 + wps: "wps",
  663 + et: "et",
  664 + wpp: "wpp"
  665 + },
  666 + CreateXHR: getHttpObj,
  667 + IsClientRunning: IsClientRunning
  668 + }
  669 +
  670 + window.wpsclients = [];
  671 + /**
  672 + * @constructor WpsClient wps客户端
  673 + * @param {string} clientType 必传参数,加载项类型,有效值为"wps","wpp","et";分别表示文字,演示,电子表格
  674 + */
  675 + function WpsClient(clientType) {
  676 + /**
  677 + * 设置RegWebNotify的回调函数,加载项给业务端发消息通过该函数
  678 + * @memberof WpsClient
  679 + * @member onMessage
  680 + */
  681 + this.onMessage;
  682 +
  683 + /**
  684 + * 设置加载项路径
  685 + * @memberof WpsClient
  686 + * @member jsPluginsXml
  687 + */
  688 + this.jsPluginsXml;
  689 +
  690 + /**
  691 + * 内部成员,外部无需调用
  692 + */
  693 + this.notifyRegsitered = false;
  694 + this.clientId = "";
  695 + this.concurrent = false;
  696 + this.clientType = clientType;
  697 + this.firstRequest = true;
  698 +
  699 + /**
  700 + * 内部函数,外部无需调用
  701 + * @param {*} options
  702 + */
  703 + this.initWpsClient = function (options) {
  704 + options.clientType = this.clientType
  705 + options.wpsclient = this
  706 + options.concurrent = this.firstRequest ? true : this.concurrent
  707 + this.firstRequest = false;
  708 + WpsStartWrapVersionInner(options)
  709 + }
  710 +
  711 + /**
  712 + * 以http启动
  713 + * @param {string} name 加载项名称
  714 + * @param {string} func 要调用的加载项中的函数行
  715 + * @param {string} param 在加载项中执行函数func要传递的数据
  716 + * @param {function({int, string})} callback 回调函数,status = 0 表示成功,失败请查看message信息
  717 + * @param {bool} showToFront 设置wps是否显示到前面来
  718 + * @return {string} "Failed to send message to WPS." 发送消息失败,客户端已关闭;
  719 + * "WPS Addon is not response." 加载项阻塞,函数执行失败
  720 + */
  721 + this.InvokeAsHttp = function (name, func, param, callback, showToFront) {
  722 + function clientCallback(res) {
  723 + //this不是WpsClient
  724 + if (res.status !== 0 || serverVersion < "1.0.1") {
  725 + if (callback) callback(res);
  726 + return;
  727 + }
  728 + var resObject = JSON.parse(res.response);
  729 + if (this.client.clientId == "") {
  730 + this.client.clientId = resObject.clientId;
  731 + }
  732 + this.client.concurrent = true;
  733 + if (typeof resObject.data == "object")
  734 + res.response = JSON.stringify(resObject.data);
  735 + else
  736 + res.response = resObject.data;
  737 + if (IEVersion() < 10)
  738 + eval(" res.response = '" + res.response + "';");
  739 + if (callback)
  740 + callback(res);
  741 + this.client.RegWebNotify(name);
  742 + }
  743 + var paramEx = {
  744 + jsPluginsXml: this.jsPluginsXml ? this.jsPluginsXml : "",
  745 + showToFront: typeof (showToFront) == 'boolean' ? showToFront : true,
  746 + param: (typeof (param) == 'object' ? param : JSON.parse(param))
  747 + }
  748 + this.initWpsClient({
  749 + name: name,
  750 + func: func,
  751 + param: paramEx,
  752 + urlBase: GetUrlBase(),
  753 + callback: clientCallback
  754 + })
  755 + }
  756 +
  757 + /**
  758 + * 以https启动
  759 + * @param {string} name 加载项名称
  760 + * @param {string} func 要调用的加载项中的函数行
  761 + * @param {string} param 在加载项中执行函数func要传递的数据
  762 + * @param {function({int, string})} callback 回调函数,status = 0 表示成功,失败请查看message信息
  763 + * @param {bool} showToFront 设置wps是否显示到前面来
  764 + */
  765 + this.InvokeAsHttps = function (name, func, param, callback, showToFront) {
  766 + var paramEx = {
  767 + jsPluginsXml: this.jsPluginsXml ? this.jsPluginsXml : "",
  768 + showToFront: typeof (showToFront) == 'boolean' ? showToFront : true,
  769 + param: (typeof (param) == 'object' ? param : JSON.parse(param))
  770 + }
  771 + this.initWpsClient({
  772 + name: name,
  773 + func: func,
  774 + param: paramEx,
  775 + urlBase: GetUrlBase(),
  776 + callback: callback
  777 + })
  778 + }
  779 +
  780 + /**
  781 + * 内部函数,外部无需调用
  782 + * @param {*} name
  783 + */
  784 + this.RegWebNotify = function (name) {
  785 + RegWebNotify(this.clientType, name, null, this);
  786 + }
  787 +
  788 + this.OnRegWebNotify = function (message) {
  789 + if (this.onMessage)
  790 + this.onMessage(message)
  791 + }
  792 +
  793 + /**
  794 + * 以静默模式启动客户端
  795 + * @param {string} name 必传参数,加载项名称
  796 + * @param {function({int, string})} [callback] 回调函数,status = 0 表示成功,失败请查看message信息
  797 + */
  798 + this.StartWpsInSilentMode = function (name, callback) {
  799 + function initCallback(res) {
  800 + //this不是WpsClient
  801 + if (res.status !== 0 || serverVersion < "1.0.1") {
  802 + if (callback) callback(res);
  803 + return;
  804 + }
  805 + if (this.client.clientId == "") {
  806 + this.client.clientId = JSON.parse(res.response).clientId;
  807 + window.wpsclients[window.wpsclients.length] = { name: name, client: this.client };
  808 + }
  809 + res.response = JSON.stringify(JSON.parse(res.response).data);
  810 + this.client.concurrent = true;
  811 + if (callback) {
  812 + callback(res);
  813 + }
  814 + this.client.RegWebNotify(name);
  815 + }
  816 + var paramEx = {
  817 + jsPluginsXml: this.jsPluginsXml,
  818 + showToFront: false,
  819 + param: { status: "InitInSilentMode" }
  820 + }
  821 + this.silentMode = true;
  822 + this.initWpsClient({
  823 + name: name,
  824 + func: "",
  825 + param: paramEx,
  826 + urlBase: GetUrlBase(),
  827 + callback: initCallback
  828 + })
  829 + }
  830 +
  831 + /**
  832 + * 显示客户端到最前面
  833 + * @param {string} name 必传参数,加载项名称
  834 + * @param {function({int, string})} [callback] 回调函数
  835 + */
  836 + this.ShowToFront = function (name, callback) {
  837 + if (serverVersion < "1.0.1") {
  838 + if (callback) {
  839 + callback({
  840 + status: 4,
  841 + message: "当前客户端不支持,请升级客户端"
  842 + });
  843 + return;
  844 + }
  845 + return;
  846 + }
  847 + if (this.clientId == "") {
  848 + if (callback) callback({
  849 + status: 3,
  850 + message: "没有静默启动客户端"
  851 + });
  852 + return;
  853 + }
  854 + var paramEx = {
  855 + jsPluginsXml: "",
  856 + showToFront: true,
  857 + param: { status: "ShowToFront" }
  858 + }
  859 + this.initWpsClient({
  860 + name: name,
  861 + func: "",
  862 + param: paramEx,
  863 + urlBase: GetUrlBase(),
  864 + callback: callback
  865 + })
  866 + }
  867 +
  868 + /**
  869 + * 关闭未显示出来的静默启动客户端
  870 + * @param {string} name 必传参数,加载项名称
  871 + * @param {function({int, string})} [callback] 回调函数
  872 + */
  873 + this.CloseSilentClient = function (name, callback) {
  874 + if (serverVersion < "1.0.1") {
  875 + if (callback) {
  876 + callback({
  877 + status: 4,
  878 + message: "当前客户端不支持,请升级客户端"
  879 + });
  880 + return;
  881 + }
  882 + return;
  883 + }
  884 + if (this.clientId == "") {
  885 + if (callback) callback({
  886 + status: 3,
  887 + message: "没有静默启动客户端"
  888 + });
  889 + return;
  890 + }
  891 + var paramEx = {
  892 + jsPluginsXml: "",
  893 + showToFront: false,
  894 + param: undefined
  895 + }
  896 + var func;
  897 + if (this.clientType == "wps")
  898 + func = "wps.WpsApplication().Quit"
  899 + else if (this.clientType == "et")
  900 + func = "wps.EtApplication().Quit"
  901 + else if (this.clientType == "wpp")
  902 + func = "wps.WppApplication().Quit"
  903 +
  904 + function closeSilentClient(res) {
  905 + if (res.status == 0)
  906 + this.client.clientId = ""
  907 + if (callback) callback(res);
  908 + return;
  909 + }
  910 + this.initWpsClient({
  911 + name: name,
  912 + func: func,
  913 + param: paramEx,
  914 + urlBase: GetUrlBase(),
  915 + callback: closeSilentClient
  916 + })
  917 + }
  918 +
  919 + /**
  920 + * 当前客户端是否在运行,使用WpsClient.IsClientRunning()进行调用
  921 + * @param {function({int, string})} [callback] 回调函数,"Client is running." 客户端正在运行
  922 + * "Client is not running." 客户端没有运行
  923 + */
  924 + this.IsClientRunning = function (callback) {
  925 + if (serverVersion < "1.0.1") {
  926 + if (callback) {
  927 + callback({
  928 + status: 4,
  929 + message: "当前客户端不支持,请升级客户端"
  930 + });
  931 + return;
  932 + }
  933 + return;
  934 + }
  935 + IsClientRunning(this.clientType, callback, this)
  936 + }
  937 + }
  938 +
  939 + function InitSdk() {
  940 + var url = GetUrlBase() + "/version";
  941 + startWps({
  942 + url: url,
  943 + data: "",
  944 + callback: function (res) {
  945 + if (res.status !== 0) {
  946 + cloudSvrStart = false;
  947 + return;
  948 + }
  949 + if (serverVersion == "wait") {
  950 + serverVersion = res.response;
  951 + cloudSvrStart = true;
  952 + }
  953 + },
  954 + tryCount: 1,
  955 + bPop: false,
  956 + timeout: 5000
  957 + });
  958 + }
  959 + InitSdk();
  960 +
  961 + if (typeof noGlobal === "undefined") {
  962 + window.WpsInvoke = WpsInvoke;
  963 + window.WpsClient = WpsClient;
  964 + window.WebNotifyUseTimeout = WebNotifyUseTimeout;
  965 + }
  966 +
  967 + /**
  968 + * 当前客户端是否在运行,使用WpsInvoke.IsClientRunning()进行调用
  969 + * @param {string} clientType 加载项类型
  970 + * @param {function} [callback] 回调函数,"Client is running." 客户端正在运行
  971 + * "Client is not running." 客户端没有运行
  972 + */
  973 + function IsClientRunning(clientType, callback, wpsclient) {
  974 + var url = GetUrlBase() + "/isRunning";
  975 + var wrapper = {
  976 + id: wpsclient == undefined ? undefined : wpsclient.clientId,
  977 + app: clientType
  978 + }
  979 + wrapper = JSON.stringify(wrapper);
  980 + startWps({
  981 + url: url,
  982 + sendData: wrapper,
  983 + callback: callback,
  984 + tryCount: 1,
  985 + bPop: false,
  986 + timeout: 2000,
  987 + concurrent: true,
  988 + client: wpsclient
  989 + });
  990 + }
  991 +
  992 + function WpsAddonGetAllConfig(callBack) {
  993 + var baseData;
  994 + startWps({
  995 + url: GetUrlBase() + "/publishlist",
  996 + type: "GET",
  997 + sendData: baseData,
  998 + callback: callBack,
  999 + tryCount: 3,
  1000 + bPop: true,
  1001 + timeout: 5000,
  1002 + concurrent: true
  1003 + });
  1004 + }
  1005 +
  1006 + function WpsAddonVerifyStatus(element, callBack) {
  1007 + var xmlReq = getHttpObj();
  1008 + var offline = element.online === "false";
  1009 + var url = offline ? element.url : element.url + "ribbon.xml";
  1010 + xmlReq.open("POST", GetUrlBase() + "/redirect/runParams");
  1011 + xmlReq.onload = function (res) {
  1012 + if (offline && !res.target.response.startsWith("7z")) {
  1013 + callBack({ status: 1, msg: "不是有效的7z格式" + url });
  1014 + } else if (!offline && !res.target.response.startsWith("<customUI")) {
  1015 + callBack({ status: 1, msg: "不是有效的ribbon.xml, " + url })
  1016 + } else {
  1017 + callBack({ status: 0, msg: "OK" })
  1018 + }
  1019 + }
  1020 + xmlReq.onerror = function (res) {
  1021 + xmlReq.bTimeout = true;
  1022 + callBack({ status: 2, msg: "网页路径不可访问,如果是跨域问题,不影响使用" + url })
  1023 + }
  1024 + xmlReq.ontimeout = function (res) {
  1025 + xmlReq.bTimeout = true;
  1026 + callBack({ status: 3, msg: "访问超时" + url })
  1027 + }
  1028 + if (IEVersion() < 10) {
  1029 + xmlReq.onreadystatechange = function () {
  1030 + if (xmlReq.readyState != 4)
  1031 + return;
  1032 + if (xmlReq.bTimeout) {
  1033 + return;
  1034 + }
  1035 + if (xmlReq.status === 200)
  1036 + xmlReq.onload();
  1037 + else
  1038 + xmlReq.onerror();
  1039 + }
  1040 + }
  1041 + xmlReq.timeout = 5000;
  1042 + var data = {
  1043 + method: "get",
  1044 + url: url,
  1045 + data: ""
  1046 + }
  1047 + var sendData = FormatSendData(data)
  1048 + xmlReq.send(sendData);
  1049 + }
  1050 +
  1051 + function WpsAddonHandleEx(element, cmd, callBack) {
  1052 + var data = FormatData(element, cmd);
  1053 + startWps({
  1054 + url: GetUrlBase() + "/deployaddons/runParams",
  1055 + type: "POST",
  1056 + sendData: data,
  1057 + callback: callBack,
  1058 + tryCount: 3,
  1059 + bPop: true,
  1060 + timeout: 5000,
  1061 + concurrent: true
  1062 + });
  1063 + }
  1064 +
  1065 + function WpsAddonEnable(element, callBack) {
  1066 + WpsAddonHandleEx(element, "enable", callBack)
  1067 + }
  1068 +
  1069 + function WpsAddonDisable(element, callBack) {
  1070 + WpsAddonHandleEx(element, "disable", callBack)
  1071 + }
  1072 +
  1073 + function FormatData(element, cmd) {
  1074 + var data = {
  1075 + "cmd": cmd, //"enable", 启用, "disable", 禁用, "disableall", 禁用所有
  1076 + "name": element.name,
  1077 + "url": element.url,
  1078 + "addonType": element.addonType,
  1079 + "online": element.online,
  1080 + "version": element.version
  1081 + }
  1082 + return FormatSendData(data);
  1083 + }
  1084 +
  1085 + function FormatSendData(data) {
  1086 + var strData = JSON.stringify(data);
  1087 + if (IEVersion() < 10)
  1088 + eval("strData = '" + JSON.stringify(strData) + "';");
  1089 + return encode(strData);
  1090 + }
  1091 + //管理 WPS 加载项
  1092 + var WpsAddonMgr = {
  1093 + getAllConfig: WpsAddonGetAllConfig,
  1094 + verifyStatus: WpsAddonVerifyStatus,
  1095 + enable: WpsAddonEnable,
  1096 + disable: WpsAddonDisable,
  1097 + }
  1098 +
  1099 + if (typeof noGlobal === "undefined") {
  1100 + window.WpsAddonMgr = WpsAddonMgr;
  1101 + }
  1102 +
  1103 + return { WpsInvoke: WpsInvoke, WpsAddonMgr: WpsAddonMgr, version: "1.0.15" };
  1104 +});
\ No newline at end of file
... ...
不能预览此文件类型
  1 +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><style type="text/css">.skinbaseDark,.skinbaseLight,.skinthemeDark{fill-rule:evenodd;}.skinbaseDark,.skinbaseLight{opacity:0.8;}.skinbaseLight{fill:#838383;}.skinthemeDark{fill:#5789d9;}</style></defs><title>编辑文字</title><path class="skinbaseDark" d="M21,23H2a2,2,0,0,1-2-2V2A2,2,0,0,1,2,0H21a2,2,0,0,1,2,2V21A2,2,0,0,1,21,23ZM22,2a1,1,0,0,0-1-1H2A1,1,0,0,0,1,2V21a1,1,0,0,0,1,1H21a1,1,0,0,0,1-1Z"/><path class="skinbaseLight" d="M21.5,12h-3a.5.5,0,1,1,0-1h3a.5.5,0,1,1,0,1Zm-10,10a.50005.50005,0,0,1-.5-.5v-3a.5.5,0,1,1,1,0v3A.50005.50005,0,0,1,11.5,22Zm0-19a.50005.50005,0,0,1-.5-.5v-1a.5.5,0,1,1,1,0v1A.50005.50005,0,0,1,11.5,3Zm-7,9h-3a.5.5,0,1,1,0-1h3a.5.5,0,1,1,0,1Z"/><path class="skinthemeDark" d="M17.9993,18.9997H16.9367L15.27,14H7.7281L6.0617,18.9997H4.9991L8.9988,6.9993h0a2.92165,2.92165,0,0,1,2.5-2,2.75159,2.75159,0,0,1,2.5,2h0ZM12.9363,6.9993a1.2901,1.2901,0,0,0-1.4375-.9375,1.39754,1.39754,0,0,0-1.4375.9375h0L8.0613,13h6.8753L12.9362,6.9993h.0001Z"/></svg>
\ No newline at end of file
... ...
  1 +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><defs><style type="text/css">.skinbaseDark,.skinthemeDark{fill-rule:evenodd;}.skinbaseDark{opacity:0.8;}.skinthemeDark{fill:#5789d9;}</style></defs><title>艺术字大小</title><path class="skinbaseDark" d="M17.9993,18.9997H16.9367L15.27,14H7.7281L6.0617,18.9997H4.9991L8.9988,6.9993h0a2.92165,2.92165,0,0,1,2.5-2,2.75159,2.75159,0,0,1,2.5,2h0ZM12.9363,6.9993a1.2901,1.2901,0,0,0-1.4375-.9375,1.39754,1.39754,0,0,0-1.4375.9375h0L8.0613,13h6.8753L12.9362,6.9993h.0001Z"/><path class="skinthemeDark" d="M23,21v1a1,1,0,0,1-1,1H21a1,1,0,0,1-1-1H3a1,1,0,0,1-1,1H1a1,1,0,0,1-1-1V21a1,1,0,0,1,1-1V4A1,1,0,0,1,0,3V2A1,1,0,0,1,1,1H2A1,1,0,0,1,3,2H20a1,1,0,0,1,1-1h1a1,1,0,0,1,1,1V3a1,1,0,0,1-1,1V20A1,1,0,0,1,23,21ZM1,21.6a.4.4,0,0,0,.4.4h.2a.4.4,0,0,0,.4-.4v-.2a.4.4,0,0,0-.4-.4H1.4a.4.4,0,0,0-.4.4ZM2,2.4A.4.4,0,0,0,1.6,2H1.4a.4.4,0,0,0-.4.4v.2a.4.4,0,0,0,.4.4h.2A.4.4,0,0,0,2,2.6ZM20,3H3A1,1,0,0,1,2,4V20a1,1,0,0,1,1,1H20a1,1,0,0,1,1-1V4A1,1,0,0,1,20,3Zm2-.6a.4.4,0,0,0-.4-.4h-.2a.4.4,0,0,0-.4.4v.2a.4.4,0,0,0,.4.4h.2a.4.4,0,0,0,.4-.4ZM21.6,21h-.2a.4.4,0,0,0-.4.4v.2a.4.4,0,0,0,.4.4h.2a.4.4,0,0,0,.4-.4v-.2A.4.4,0,0,0,21.6,21Z"/></svg>
\ No newline at end of file
... ...
  1 +<?xml version="1.0" encoding="utf-8"?>
  2 +<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
  3 +<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
  4 + viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
  5 +<style type="text/css">
  6 + .skinbaseDark{opacity:0.8;enable-background:new ;}
  7 + .skinthemeDark{fill:#5789D9;}
  8 +</style>
  9 +<path class="skinbaseDark" d="M13,23h-1.4c-0.1,0-0.2,0-0.3-0.1c-0.7-0.2-0.9-0.6-1.3-0.9l-5-5H1.6C0.7,17,0,16.3,0,15.4V8.6
  10 + C0,7.7,0.7,7,1.6,7H5l5-5c0.4-0.4,0.6-0.8,1.3-0.9C11.4,1,11.5,1,11.6,1H12l0,0l0,0h1c0.6,0,1,0.5,1,1v20C14,22.5,13.6,23,13,23z
  11 + M13,2.4C13,2.2,12.8,2,12.6,2H12c-0.5,0-0.9,0.2-1.1,0.4c0.1-0.1,0,0,0,0C10.8,2.6,7.3,6,5.3,8H1.6C1.3,8,1,8.3,1,8.6v6.8
  12 + C1,15.7,1.3,16,1.6,16h3.7c2,2,5.5,5.5,5.7,5.7c0.2,0.2,0.6,0.3,1,0.3h0.6c0.2,0,0.4-0.2,0.4-0.4V2.4z M10,2C10,2,9.9,2.1,10,2
  13 + C9.9,2,10,2,10,2z"/>
  14 +<path class="skinthemeDark" d="M18.5,20.9c-0.1,0.1-0.2,0.1-0.4,0.1c-0.3,0-0.5-0.2-0.5-0.5c0-0.2,0.1-0.4,0.3-0.5l0,0
  15 + c3-1.5,5.1-4.5,5.1-8.1s-2.1-6.6-5.1-8.1l0,0c-0.2-0.1-0.3-0.3-0.3-0.5c0-0.3,0.2-0.5,0.5-0.5c0.1,0,0.3,0.1,0.4,0.2
  16 + c3.3,1.6,5.5,5,5.5,8.9S21.8,19.3,18.5,20.9z M19,12c0,1.7-0.9,3.2-2.2,4.1c-0.1,0.1-0.2,0.2-0.4,0.2c-0.3,0-0.5-0.2-0.5-0.5
  17 + c0-0.2,0.1-0.4,0.3-0.5v0c1.1-0.7,1.8-1.9,1.8-3.3c0-1.4-0.7-2.6-1.8-3.3v0c-0.2-0.1-0.3-0.3-0.3-0.5c0-0.3,0.2-0.5,0.5-0.5
  18 + c0.2,0,0.3,0.1,0.4,0.2C18.1,8.8,19,10.3,19,12z"/>
  19 +</svg>
... ...
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<svg width="21px" height="20px" viewBox="0 0 21 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  3 + <!-- Generator: Sketch 51.2 (57519) - http://www.bohemiancoding.com/sketch -->
  4 + <title>从模版新建</title>
  5 + <desc>Created with Sketch.</desc>
  6 + <defs></defs>
  7 + <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
  8 + <g id="Artboard" transform="translate(-31.000000, -26.000000)">
  9 + <g id="从模版新建" transform="translate(29.000000, 24.000000)">
  10 + <g id="Group" stroke-width="1">
  11 + <g id="新增节" transform="translate(2.000000, 2.000000)">
  12 + <path d="M19.9587402,10 L18.9587402,10 L18.9587402,2 C18.9587402,1.44771525 18.511025,1 17.9587402,1 L6.0300293,1 C5.47774455,1 5.0300293,1.44771525 5.0300293,2 L5.0300293,18 C5.0300293,18.5522847 5.47774455,19 6.0300293,19 L9.95874023,19 L9.95874023,20 L6.0300293,20 C4.9254598,20 4.0300293,19.1045695 4.0300293,18 L4.0300293,2 C4.0300293,0.8954305 4.9254598,2.02906125e-16 6.0300293,0 L17.9587402,0 C19.0633097,-2.02906125e-16 19.9587402,0.8954305 19.9587402,2 L19.9587402,10 Z" id="Combined-Shape" fill="#404040" fill-rule="nonzero"></path>
  13 + <path d="M6,1 L4,1 C3.44771525,1 3,1.44771525 3,2 L3,18 C3,18.5522847 3.44771525,19 4,19 L6,19 L6,20 L4,20 C2.8954305,20 2,19.1045695 2,18 L2,2 C2,0.8954305 2.8954305,2.02906125e-16 4,0 L6,0 L6,1 Z" id="Combined-Shape-Copy-2" fill="#404040" fill-rule="nonzero"></path>
  14 + <path d="M4,1 L2,1 C1.44771525,1 1,1.44771525 1,2 L1,18 C1,18.5522847 1.44771525,19 2,19 L4,19 L4,20 L2,20 C0.8954305,20 1.03797111e-16,19.1045695 0,18 L0,2 C-1.10284431e-16,0.8954305 0.8954305,2.02906125e-16 2,0 L4,0 L4,1 Z" id="Combined-Shape-Copy-3" fill="#404040" fill-rule="nonzero"></path>
  15 + <path d="M17,15 L20.5,15 C20.7761424,15 21,15.2238576 21,15.5 C21,15.7761424 20.7761424,16 20.5,16 L17,16 L17,19.5 C17,19.7761424 16.7761424,20 16.5,20 C16.2238576,20 16,19.7761424 16,19.5 L16,16 L12.5,16 C12.2238576,16 12,15.7761424 12,15.5 C12,15.2238576 12.2238576,15 12.5,15 L16,15 L16,11.5 C16,11.2238576 16.2238576,11 16.5,11 C16.7761424,11 17,11.2238576 17,11.5 L17,15 Z" id="Combined-Shape" fill="#5789D9"></path>
  16 + </g>
  17 + </g>
  18 + <rect id="Rectangle-15" fill="#404040" x="9" y="6" width="10" height="1"></rect>
  19 + </g>
  20 + </g>
  21 + </g>
  22 +</svg>
\ No newline at end of file
... ...
  1 +<!DOCTYPE html>
  2 +<html lang="en">
  3 + <head>
  4 + <meta charset="utf-8" />
  5 + <title>WPSJS</title>
  6 + </head>
  7 + <body>
  8 + <noscript>You need to enable JavaScript to run this app.</noscript>
  9 + <div id="root"></div>
  10 + <!--
  11 + This HTML file is a template.
  12 + If you open it directly in the browser, you will see an empty page.
  13 +
  14 + You can add webfonts, meta tags, or analytics to this file.
  15 + The build step will place the bundled scripts into the <body> tag.
  16 +
  17 + To begin the development, run `npm start` or `yarn start`.
  18 + To create a production bundle, use `npm run build` or `yarn build`.
  19 + -->
  20 + </body>
  21 +</html>
... ...
  1 +<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" onLoad="ribbon.OnAddinLoad">
  2 + <ribbon startFromScratch="false">
  3 + <tabs>
  4 + <tab id="SystemAddin" label="系统插件" insertBeforeMso="TabHome">
  5 + <group id="btnDemoGroup" label="group1">
  6 + <!-- <button id="btnShowMsg" label="弹出消息框" onAction="ribbon.OnAction" getEnabled="ribbon.OnGetEnabled" getImage="ribbon.GetImage" visible="true" size="large"/>
  7 + <button id="btnIsEnbable" getLabel="ribbon.OnGetLabel" onAction="ribbon.OnAction" enabled="true" getImage="ribbon.GetImage" visible="true" size="large"/>
  8 + <button id="btnShowDialog" label="弹对话框网页" onAction="ribbon.OnAction" getEnabled="ribbon.OnGetEnabled" getImage="ribbon.GetImage" getVisible="ribbon.OnGetVisible" size="large"/>
  9 + <button id="btnShowTaskPane" label="弹任务窗格网页" onAction="ribbon.OnAction" getEnabled="ribbon.OnGetEnabled" getImage="ribbon.GetImage" getVisible="ribbon.OnGetVisible" size="large"/>
  10 + <button id="btnApiEvent" getLabel="ribbon.OnGetLabel" onAction="ribbon.OnAction" getEnabled="ribbon.OnGetEnabled" getImage="ribbon.GetImage" getVisible="ribbon.OnGetVisible" size="large"/>
  11 + <button id="btnWebNotify" label="给业务系统发通知" onAction="ribbon.OnAction" enabled="true" getImage="ribbon.GetImage" getVisible="ribbon.OnGetVisible" size="large"/>
  12 + <button id="btnOpenWebFile" label="打开远程文件" onAction="ribbon.OnAction" enabled="true" getImage="ribbon.GetImage" getVisible="ribbon.OnGetVisible" size="large"/> -->
  13 + <button id="btnSaveToServer" label="保存到OA" onAction="ribbon.OnAction" enabled="true" getImage="ribbon.GetImage" size="large"/>
  14 + <button id="btnInsertRedHeader" label="套红头" onAction="ribbon.OnAction" enabled="true" getImage="ribbon.GetImage" size="large"/>
  15 + </group>
  16 + </tab>
  17 + </tabs>
  18 + </ribbon>
  19 + <commands>
  20 + <!-- idMso支持getEnabled和onAction,不支持visible属性和事件-->
  21 + <!-- 文档复制和剪切控制-->
  22 + <!-- <command idMso="Copy" getEnabled="OnGetEnabled" />
  23 + <command idMso="Cut" getEnabled="OnGetEnabled" /> --> -->
  24 + <!-- 文档保存和另存控制-->
  25 + <command idMso="FileSave" enabled="true" onAction="ribbon.OnAction"/>
  26 + <!-- <command idMso="SaveAll" getEnabled="OnGetEnabled" />
  27 + <command idMso="FileSaveAsMenu" getEnabled="OnGetEnabled" onAction="OnAction"/>
  28 + <command idMso="FileSaveAs" getEnabled="OnGetEnabled" onAction="OnAction"/>
  29 + <command idMso="FileSaveAsPicture" getEnabled="OnGetEnabled" />
  30 + <command idMso="SaveAsPicture" getEnabled="OnGetEnabled" />
  31 + <command idMso="FileMenuSendMail" getEnabled="OnGetEnabled" />
  32 + <!-- 输出PDF控制-->
  33 + <command idMso="SaveAsPDF" getEnabled="OnGetEnabled"/>
  34 + <command idMso="FileSaveAsPDF" getEnabled="OnGetEnabled"/>
  35 + <command idMso="ExportToPDF" getEnabled="OnGetEnabled"/>
  36 + <command idMso="FileSaveAsPdfOrXps" getEnabled="OnGetEnabled"/>
  37 + <!-- 输出OFD控制-->
  38 + <command idMso="SaveAsOfd" getEnabled="OnGetEnabled"/>
  39 + <command idMso="FileSaveAsOfd" getEnabled="OnGetEnabled"/>
  40 + <!--文档打印控制-->
  41 + <command idMso="FilePrint" getEnabled="OnGetEnabled"/>
  42 + <command idMso="FilePrintMenu" getEnabled="OnGetEnabled"/>
  43 + <command idMso="FilePrintPreview" getEnabled="OnGetEnabled"/>
  44 + <!--文档修订控制-->
  45 + <command idMso="ReviewTrackChangesMenu" getEnabled="OnGetEnabled"/>
  46 + <command idMso="ReviewRejectChangeMenu" getEnabled="OnGetEnabled"/>
  47 + <command idMso="ReviewAcceptChangeMenu" getEnabled="OnGetEnabled"/>
  48 + <!--文档新建控制-->
  49 + <command idMso="FileNewMenu" getEnabled="OnGetEnabled" onAction="OnAction"/>
  50 + <command idMso="FileNew" getEnabled="OnGetEnabled" onAction="OnAction"/>
  51 + <command idMso="WindowNew" getEnabled="OnGetEnabled" onAction="OnAction"/>
  52 + <command idMso="FileNewBlankDocument" getEnabled="OnGetEnabled" onAction="OnAction"/>
  53 + </commands>
  54 +</customUI>
\ No newline at end of file
... ...
  1 +// -------------------------- 通用常量
  2 +import {constStrEnum,EnumDocLandMode} from "./enum"
  3 +var wps = window.wps||window
  4 +
  5 +
  6 +//OA门户网站用接口,配置默认服务器接口
  7 +var OA_DOOR = {
  8 + templateDataUrl: undefined, //正文模板列表接口
  9 + templateBaseURL: undefined, //指定正文模板基础接口
  10 + redHeadsPath: undefined, //默认红头模板列表获取路径
  11 + getRedHeadPath: undefined, //默认获取红头文件路径
  12 + bookmarkPath: undefined, //书签列表接口
  13 + redHeadsPath: undefined, //默认红头模板列表获取路径
  14 +}
  15 +
  16 +// -------------------------- 通用方法 ---------------------------
  17 +//去除字符串左边空格
  18 +String.prototype.ltrim = function () {
  19 + return this.replace(/(^\s*)/g, "");
  20 +}
  21 +
  22 +//去除字符串右边空格
  23 +String.prototype.rtrim = function () {
  24 + return this.replace(/(\s*$)/g, "");
  25 +}
  26 +
  27 +//扩展js string endwith,startwith方法
  28 +String.prototype.endWith = function (str) {
  29 + if (str == null || str == "" || this.length == 0 || str.length > this.length)
  30 + return false;
  31 + if (this.substring(this.length - str.length) == str)
  32 + return true;
  33 + else
  34 + return false;
  35 +}
  36 +
  37 +String.prototype.startWith = function (str) {
  38 + if (str == null || str == "" || this.length == 0 || str.length > this.length)
  39 + return false;
  40 + if (this.substr(0, str.length) == str)
  41 + return true;
  42 + else
  43 + return false;
  44 +}
  45 +
  46 +//UTF-16转UTF-8
  47 +function utf16ToUtf8(s) {
  48 + if (!s) {
  49 + return;
  50 + }
  51 + var i, code, ret = [],
  52 + len = s.length;
  53 + for (i = 0; i < len; i++) {
  54 + code = s.charCodeAt(i);
  55 + if (code > 0x0 && code <= 0x7f) {
  56 + //单字节
  57 + //UTF-16 0000 - 007F
  58 + //UTF-8 0xxxxxxx
  59 + ret.push(s.charAt(i));
  60 + } else if (code >= 0x80 && code <= 0x7ff) {
  61 + //双字节
  62 + //UTF-16 0080 - 07FF
  63 + //UTF-8 110xxxxx 10xxxxxx
  64 + ret.push(
  65 + //110xxxxx
  66 + String.fromCharCode(0xc0 | ((code >> 6) & 0x1f)),
  67 + //10xxxxxx
  68 + String.fromCharCode(0x80 | (code & 0x3f))
  69 + );
  70 + } else if (code >= 0x800 && code <= 0xffff) {
  71 + //三字节
  72 + //UTF-16 0800 - FFFF
  73 + //UTF-8 1110xxxx 10xxxxxx 10xxxxxx
  74 + ret.push(
  75 + //1110xxxx
  76 + String.fromCharCode(0xe0 | ((code >> 12) & 0xf)),
  77 + //10xxxxxx
  78 + String.fromCharCode(0x80 | ((code >> 6) & 0x3f)),
  79 + //10xxxxxx
  80 + String.fromCharCode(0x80 | (code & 0x3f))
  81 + );
  82 + }
  83 + }
  84 +
  85 + return ret.join('');
  86 +
  87 +}
  88 +var Base64 = {
  89 + _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
  90 + encode: function(e) {
  91 + var t = "";
  92 + var n, r, i, s, o, u, a;
  93 + var f = 0;
  94 + e = Base64._utf8_encode(e);
  95 + while (f < e.length) {
  96 + n = e.charCodeAt(f++);
  97 + r = e.charCodeAt(f++);
  98 + i = e.charCodeAt(f++);
  99 + s = n >> 2;
  100 + o = (n & 3) << 4 | r >> 4;
  101 + u = (r & 15) << 2 | i >> 6;
  102 + a = i & 63;
  103 + if (isNaN(r)) {
  104 + u = a = 64
  105 + } else if (isNaN(i)) {
  106 + a = 64
  107 + }
  108 + t = t + this._keyStr.charAt(s) + this._keyStr.charAt(o) + this._keyStr.charAt(u) + this._keyStr.charAt(a)
  109 + }
  110 + return t
  111 + },
  112 + decode: function(e) {
  113 + var t = "";
  114 + var n, r, i;
  115 + var s, o, u, a;
  116 + var f = 0;
  117 + e = e.replace(/[^A-Za-z0-9+/=]/g, "");
  118 + while (f < e.length) {
  119 + s = this._keyStr.indexOf(e.charAt(f++));
  120 + o = this._keyStr.indexOf(e.charAt(f++));
  121 + u = this._keyStr.indexOf(e.charAt(f++));
  122 + a = this._keyStr.indexOf(e.charAt(f++));
  123 + n = s << 2 | o >> 4;
  124 + r = (o & 15) << 4 | u >> 2;
  125 + i = (u & 3) << 6 | a;
  126 + t = t + String.fromCharCode(n);
  127 + if (u != 64) {
  128 + t = t + String.fromCharCode(r)
  129 + }
  130 + if (a != 64) {
  131 + t = t + String.fromCharCode(i)
  132 + }
  133 + }
  134 + t = Base64._utf8_decode(t);
  135 + return t
  136 + },
  137 + _utf8_encode: function(e) {
  138 + e = e.replace(/rn/g, "n");
  139 + var t = "";
  140 + for (var n = 0; n < e.length; n++) {
  141 + var r = e.charCodeAt(n);
  142 + if (r < 128) {
  143 + t += String.fromCharCode(r)
  144 + } else if (r > 127 && r < 2048) {
  145 + t += String.fromCharCode(r >> 6 | 192);
  146 + t += String.fromCharCode(r & 63 | 128)
  147 + } else {
  148 + t += String.fromCharCode(r >> 12 | 224);
  149 + t += String.fromCharCode(r >> 6 & 63 | 128);
  150 + t += String.fromCharCode(r & 63 | 128)
  151 + }
  152 + }
  153 + return t
  154 + },
  155 + _utf8_decode: function(e) {
  156 + var t = "";
  157 + var n = 0;
  158 + let c1,c2,c3;
  159 + var r = c1 = c2 = 0;
  160 + while (n < e.length) {
  161 + r = e.charCodeAt(n);
  162 + if (r < 128) {
  163 + t += String.fromCharCode(r);
  164 + n++
  165 + } else if (r > 191 && r < 224) {
  166 + c2 = e.charCodeAt(n + 1);
  167 + t += String.fromCharCode((r & 31) << 6 | c2 & 63);
  168 + n += 2
  169 + } else {
  170 + c2 = e.charCodeAt(n + 1);
  171 + c3 = e.charCodeAt(n + 2);
  172 + t += String.fromCharCode((r & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
  173 + n += 3
  174 + }
  175 + }
  176 + return t
  177 + }
  178 +}
  179 +//UTF-8转UTF-16
  180 +function utf8ToUtf16(s) {
  181 + if (!s) {
  182 + return;
  183 + }
  184 +
  185 + var i, codes, bytes, ret = [],
  186 + len = s.length;
  187 + for (i = 0; i < len; i++) {
  188 + codes = [];
  189 + codes.push(s.charCodeAt(i));
  190 + if (((codes[0] >> 7) & 0xff) == 0x0) {
  191 + //单字节 0xxxxxxx
  192 + ret.push(s.charAt(i));
  193 + } else if (((codes[0] >> 5) & 0xff) == 0x6) {
  194 + //双字节 110xxxxx 10xxxxxx
  195 + codes.push(s.charCodeAt(++i));
  196 + bytes = [];
  197 + bytes.push(codes[0] & 0x1f);
  198 + bytes.push(codes[1] & 0x3f);
  199 + ret.push(String.fromCharCode((bytes[0] << 6) | bytes[1]));
  200 + } else if (((codes[0] >> 4) & 0xff) == 0xe) {
  201 + //三字节 1110xxxx 10xxxxxx 10xxxxxx
  202 + codes.push(s.charCodeAt(++i));
  203 + codes.push(s.charCodeAt(++i));
  204 + bytes = [];
  205 + bytes.push((codes[0] << 4) | ((codes[1] >> 2) & 0xf));
  206 + bytes.push(((codes[1] & 0x3) << 6) | (codes[2] & 0x3f));
  207 + ret.push(String.fromCharCode((bytes[0] << 8) | bytes[1]));
  208 + }
  209 + }
  210 + return ret.join('');
  211 +
  212 +}
  213 +
  214 +function currentTime() {
  215 + var now = new Date();
  216 +
  217 + var year = now.getFullYear(); //年
  218 + var month = now.getMonth() + 1; //月
  219 + var day = now.getDate(); //日
  220 +
  221 + var hh = now.getHours(); //时
  222 + var mm = now.getMinutes(); //分
  223 +
  224 + var clock = year + "年";
  225 +
  226 + if (month < 10)
  227 + clock += "0";
  228 +
  229 + clock += month + "月";
  230 +
  231 + if (day < 10)
  232 + clock += "0";
  233 +
  234 + clock += day + "日";
  235 +
  236 + if (hh < 10)
  237 + clock += "0";
  238 +
  239 + clock += hh + ":";
  240 + if (mm < 10) clock += '0';
  241 + clock += mm;
  242 + return (clock);
  243 +}
  244 +
  245 +/**
  246 + * 获取文件路径
  247 + * @param {*} html 文件全称
  248 + */
  249 +function getHtmlURL(html) {
  250 + //弹出辅助窗格框
  251 + var GetUrlPath = ()=> {
  252 + var e = document.location.toString();
  253 + return -1 != (e = decodeURI(e)).indexOf("/") && (e = e.substring(0, e.lastIndexOf("/"))), e
  254 + }
  255 +
  256 + var url = GetUrlPath();
  257 +
  258 + if (url.length != 0) {
  259 + url = url.concat("/" + html);
  260 + } else {
  261 + url = url.concat("./" + html);
  262 + }
  263 + return url;
  264 +}
  265 +
  266 +/**
  267 + * wps内弹出web页面
  268 + * @param {*} html 文件名
  269 + * @param {*} title 窗口标题
  270 + * @param {*} hight 窗口高
  271 + * @param {*} width 窗口宽
  272 + */
  273 +export function OnShowDialog(html, title, height, width, bModal) {
  274 + var l_ActiveDoc = wps.WpsApplication().ActiveDocument;
  275 + if (!l_ActiveDoc) {
  276 + alert("WPS当前没有可操作文档!")
  277 + return;
  278 + }
  279 + if (typeof bModal == "undefined" || bModal == null) {
  280 + bModal = true;
  281 + }
  282 + width *= window.devicePixelRatio;
  283 + height *= window.devicePixelRatio;
  284 + var url = getHtmlURL(html);
  285 + wps.ShowDialog(url, title, height, width, bModal);
  286 +}
  287 +
  288 +/**
  289 + * 解析返回response的参数
  290 + * @param {*} resp
  291 + * @return {*} body
  292 + */
  293 +function handleResultBody(resp) {
  294 + var result = "";
  295 + if (resp.Body) {
  296 + // 解析返回response的参数
  297 + }
  298 + return result;
  299 +}
  300 +
  301 +
  302 +/**
  303 + * 判断WPS中的文件个数是否为0,若为0则关闭WPS函数
  304 + * @param {*} name
  305 + */
  306 +function closeWpsIfNoDocument() {
  307 + var wpsApp = wps.WpsApplication();
  308 + var docs = wpsApp.Documents;
  309 + if (!docs || docs.Count == 0) {
  310 + wps.ApiEvent.Cancel = true;
  311 + //根据业务可以选择是否退出进程 wpsApp.Quit();
  312 + }
  313 +}
  314 +
  315 +export function activeTab() {
  316 + //启动WPS程序后,默认显示的工具栏选项卡为ribbon.xml中某一tab
  317 + if (wps.ribbonUI)
  318 + wps.ribbonUI.ActivateTab('wpsAddinTab');
  319 +}
  320 +
  321 +// function showOATab() {
  322 +// wps.PluginStorage.setItem("ShowOATabDocActive", pCheckIfOADoc()); //根据文件是否为OA文件来显示OA菜单
  323 +// wps.ribbonUI.Invalidate(); // 刷新Ribbon自定义按钮的状态
  324 +// }
  325 +
  326 +function getDemoTemplatePath() {
  327 + var url = document.location.toString();
  328 + url = decodeURI(url);
  329 + if (url.indexOf("/") != -1) {
  330 + url = url.substring(0, url.lastIndexOf("/"));
  331 + }
  332 + if (url.length !== 0)
  333 + url = url.concat("/template/红头文件.docx");
  334 +
  335 + if (url.startsWith("file:///"))
  336 + url = url.substr("file:///".length);
  337 + return url;
  338 +}
  339 +
  340 +function getDemoSealPath() {
  341 + var url = document.location.toString();
  342 + url = decodeURI(url);
  343 + if (url.indexOf("/") != -1) {
  344 + url = url.substring(0, url.lastIndexOf("/"));
  345 + }
  346 + if (url.length !== 0)
  347 + url = url.concat("/template/OA模板:公章.png");
  348 +
  349 + if (url.startsWith("file:///"))
  350 + url = url.substr("file:///".length);
  351 + return url;
  352 +}
  353 +
  354 +function pGetParamName(data, attr) {
  355 + var start = data.indexOf(attr);
  356 + data = data.substring(start + attr.length);
  357 + return data;
  358 +}
  359 +/**
  360 + * 从requst中获取文件名(确保请求中有filename这个参数)
  361 + * @param {*} request
  362 + * @param {*} url
  363 + */
  364 +function pGetFileName(request, url) {
  365 + var disposition = request.getResponseHeader("Content-Disposition");
  366 + var filename = "";
  367 + if (disposition) {
  368 + var matchs = pGetParamName(disposition, "filename=");
  369 + if (matchs) {
  370 + filename = decodeURIComponent(matchs);
  371 + } else {
  372 + filename = "petro" + Date.getTime();
  373 + }
  374 + } else {
  375 + var filename = url.substring(url.lastIndexOf("/") + 1);
  376 + }
  377 + return filename;
  378 +}
  379 +
  380 +function StringToUint8Array(string) {
  381 + var binLen, buffer, chars, i, _i;
  382 + binLen = string.length;
  383 + buffer = new ArrayBuffer(binLen);
  384 + chars = new Uint8Array(buffer);
  385 + for (var i = 0; i < binLen; ++i) {
  386 + chars[i] = String.prototype.charCodeAt.call(string, i);
  387 + }
  388 + return buffer;
  389 +}
  390 +/**
  391 + * WPS下载文件到本地打开(业务系统可根据实际情况进行修改)
  392 + * @param {*} url 文件流的下载路径
  393 + * @param {*} callback 下载后的回调
  394 + */
  395 +export function DownloadFile(url,fileName, callback) {
  396 + var xhr = new XMLHttpRequest();
  397 + xhr.onreadystatechange = function () {
  398 + if (this.readyState == 4 && this.status == 200) {
  399 + //需要业务系统的服务端在传递文件流时,确保请求中的参数有filename
  400 + // var fileName = pGetFileName(xhr, url)
  401 + //落地打开模式下,WPS会将文件下载到本地的临时目录,在关闭后会进行清理
  402 + var path = wps.Env.GetTempPath() + "/" + fileName
  403 + var reader = new FileReader();
  404 + reader.onload = function () {
  405 + wps.FileSystem.writeAsBinaryString(path, reader.result);
  406 + callback(path);
  407 + };
  408 + reader.readAsBinaryString(xhr.response);
  409 + }
  410 + }
  411 + xhr.open('GET', url);
  412 + xhr.responseType = 'blob';
  413 + xhr.send();
  414 +}
  415 +/**
  416 + * WPS上传文件到服务端(业务系统可根据实际情况进行修改,为了兼容中文,服务端约定用UTF-8编码格式)
  417 + * @param {*} strFileName 上传到服务端的文件名称(包含文件后缀)
  418 + * @param {*} strPath 上传文件的文件路径(文件在操作系统的绝对路径)
  419 + * @param {*} uploadPath 上传文件的服务端地址
  420 + * @param {*} strFieldName 业务调用方自定义的一些内容可通过此字段传递,默认赋值'file'
  421 + * @param {*} OnSuccess 上传成功后的回调
  422 + * @param {*} OnFail 上传失败后的回调
  423 + */
  424 +export function UploadFile(strFileName, strPath, uploadPath, strFieldName, params ,OnSuccess, OnFail) {
  425 + var xhr = new XMLHttpRequest();
  426 + xhr.open('POST', uploadPath);
  427 +
  428 + var fileData = wps.FileSystem.readAsBinaryString(strPath);
  429 +
  430 + var data = new window.FakeFormData();
  431 +
  432 +
  433 + if (strFieldName == "" || typeof strFieldName == "undefined"){//如果业务方没定义,默认设置为'file'
  434 + strFieldName = 'stream';
  435 + }
  436 +
  437 +
  438 +
  439 + if(params != null && typeof params == "object"){
  440 + const {nid,pid,token,tokenIdKey} = params;
  441 + if(nid != null){
  442 + data.append("nid",nid);
  443 + data.append("reUploadNid",nid);
  444 + data.append("isReUpload",true);
  445 + }
  446 +
  447 + if(pid != null){
  448 + data.append("pid",pid)
  449 + };
  450 +
  451 + if(token != null) {
  452 + data.append("token",token);
  453 + if(tokenIdKey != null)
  454 + data.append(tokenIdKey,token)
  455 + else
  456 + data.append("DCI_TOKEN_ID",token);
  457 + }
  458 +
  459 + }
  460 +
  461 + data.append("stream", {
  462 + name: strFileName, //主要是考虑中文名的情况,服务端约定用utf-8来解码。
  463 + type: "application/octet-stream",
  464 + getAsBinary: function () {
  465 + return fileData;
  466 + }
  467 + });
  468 +
  469 + xhr.onreadystatechange = function () {
  470 + if (xhr.readyState == 4) {
  471 + if (xhr.status == 200)
  472 + OnSuccess(xhr.response)
  473 + else
  474 + OnFail(xhr.response);
  475 + }
  476 + };
  477 + xhr.setRequestHeader("Cache-Control", "no-cache");
  478 + xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
  479 + xhr.setRequestHeader("Accept", "*/*")
  480 + xhr.setRequestHeader("Access-Control-Allow-Origin", "*")
  481 + xhr.setRequestHeader("Access-Control-Allow-Credentials", "true")
  482 + // xhr.setRequestHeader("Accept-Encoding","gzip, deflate, br")
  483 + if (data.fake) {
  484 + xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + data.boundary);
  485 + var arr = StringToUint8Array(data.toString());
  486 + xhr.send(arr);
  487 + } else {
  488 + xhr.send(data);
  489 + }
  490 +}
  491 +
  492 +// /**
  493 +// * 打开WPS后通知到业务系统,可根据需求扩展
  494 +// * @param {*} p_Url 业务方接受请求的地址
  495 +// */
  496 +// function NotifyToServer(p_Url) {
  497 +// $.ajax({
  498 +// url: p_Url, // URL + '/wps/wpsCanOpen',
  499 +// async: true,
  500 +// method: "post",
  501 +// dataType: 'json'
  502 +// });
  503 +// }
  504 +
  505 +// /**
  506 +// * 更新编辑状态
  507 +// * @param {*} p_Url 要传入OA端,通知业务系统,当前文档所处的编辑状态的URL地址路径
  508 +// * @param {*} p_OpenUrl 当前文档从业务系统打开时的入口URL,这个URL包含业务系统开发者需要传入的ID等参数
  509 +// * @param {*} docId 文档id
  510 +// * @param {*} state 0-正在编辑中 1-文件保存 2-文件关闭 状态可根据需要进行自定义扩展
  511 +// */
  512 +// function UpdateEditState(p_Url, p_OpenUrl, docId, state) {
  513 +// var formData = {
  514 +// "openUrl": p_OpenUrl,
  515 +// "docId": docId,
  516 +// "state": state
  517 +// };
  518 +// $.ajax({
  519 +// url: p_Url, //URL + '/document/stateMonitor',
  520 +// async: false,
  521 +// data: formData,
  522 +// method: "post",
  523 +// dataType: 'json',
  524 +// success: function (response) {
  525 +// if (response == "success") {
  526 +// console.log(response);
  527 +// }
  528 +// },
  529 +// error: function (response) {
  530 +// console.log(response);
  531 +// }
  532 +// });
  533 +// }
  534 +
  535 +// /**
  536 +// * 作用:判断文档关闭后,如果系统已经没有打开的文档了,则设置回初始用户名
  537 +// */
  538 +// function pSetWPSAppUserName() {
  539 +// //文档全部关闭的情况下,把WPS初始启动的用户名设置回去
  540 +// if (wps.WpsApplication().Documents.Count == 1) {
  541 +// var l_strUserName = wps.PluginStorage.getItem(constStrEnum.WPSInitUserName);
  542 +// wps.WpsApplication().UserName = l_strUserName;
  543 +// }
  544 +// }
  545 +
  546 +/**
  547 + * 设置文档参数的属性值
  548 + * @param {*} Doc
  549 + * @param {*} Key
  550 + * @param {*} Value
  551 + */
  552 +function SetDocParamsValue(Doc, Key, Value) {
  553 + if (!Doc || !Key) {
  554 + return;
  555 + }
  556 +
  557 + var l_Params = wps.PluginStorage.getItem(Doc.DocID);
  558 + if (!l_Params) {
  559 + return;
  560 + }
  561 +
  562 + var l_objParams = JSON.parse(l_Params);
  563 + if (!(typeof(l_objParams) == "undefined")) {
  564 + l_objParams[Key] = Value;
  565 + }
  566 +
  567 + //把属性值整体再写回原来的文档ID中
  568 + wps.PluginStorage.setItem(Doc.DocID, JSON.stringify(l_objParams));
  569 +}
  570 +
  571 +export function GetDocParamsValue(Doc, Key) {
  572 + if (!Doc) {
  573 + return "";
  574 + }
  575 +
  576 + var l_Params = wps.PluginStorage.getItem(Doc.DocID);
  577 + if (!l_Params) {
  578 + return "";
  579 + }
  580 +
  581 + var l_objParams = JSON.parse(l_Params);
  582 + if (typeof(l_objParams) == "undefined") {
  583 + return "";
  584 + }
  585 +
  586 + var l_rtnValue = l_objParams[Key];
  587 + if (typeof(l_rtnValue) == "undefined" || l_rtnValue == null) {
  588 + return "";
  589 + }
  590 + return l_rtnValue;
  591 +}
  592 +
  593 +function pIsOnlineOADoc(doc) {
  594 + var l_LandMode = GetDocParamsValue(doc, constStrEnum.OADocLandMode); //获取文档落地模式
  595 + if (l_LandMode == "") { //用户本地打开的文档
  596 + return false;
  597 + }
  598 + return l_LandMode == EnumDocLandMode.DLM_OnlineDoc;
  599 +}
  600 +
  601 +export function OnUploadToServerSuccess (info){
  602 + if(info == undefined || info.length == 0) {
  603 + alert("请求处理失败!请检查是否允许跨域!")
  604 + }
  605 + if(info != null){
  606 + if(typeof info === "string"){
  607 + info = JSON.parse(info);
  608 + }
  609 + if(typeof info === "object"){
  610 + if(info.code == 0 && info.success){
  611 + alert(info.message || "上传成功!");
  612 + return;
  613 + }
  614 + }
  615 + }
  616 + alert(info && info.message || info || "上传失败!");
  617 +}
  618 +
  619 +export function OnUploadToServerFail (info){
  620 + if(info == undefined || info.length == 0) {
  621 + alert("请求处理失败!请检查是否允许跨域!")
  622 + }
  623 + if( typeof info === "string"){
  624 + info = JSON.parse(info);
  625 + }
  626 + alert(info && info.message || info || "上传失败!");
  627 +}
  628 +
  629 +
  630 +function pInsertRInedHead(doc, strFile, bookmark) {
  631 + var bookMarks = doc.Bookmarks;
  632 + if (bookMarks.Item("quanwen")) { // 当前文档存在"quanwen"书签时候表示已经套过红头
  633 + alert("当前文档已套过红头,请勿重复操作!");
  634 + return;
  635 + }
  636 +
  637 + var wpsApp = wps.WpsApplication();
  638 + var activeDoc = wpsApp.ActiveDocument;
  639 + var selection = wpsApp.ActiveWindow.Selection;
  640 + // 准备以非批注的模式插入红头文件(剪切/粘贴等操作会留有痕迹,故先关闭修订)
  641 + activeDoc.TrackRevisions = false;
  642 + selection.WholeStory(); //选取全文
  643 + bookMarks.Add("quanwen", selection.Range)
  644 + selection.Cut();
  645 + selection.InsertFile(strFile);
  646 + if (bookMarks.Exists(bookmark)) {
  647 + var bookmark1 = bookMarks.Item(bookmark);
  648 + bookmark1.Range.Select(); //获取指定书签位置
  649 + var s = activeDoc.ActiveWindow.Selection;
  650 + s.Paste();
  651 + } else {
  652 + alert("套红头失败,您选择的红头模板没有对应书签:" + bookmark);
  653 + }
  654 +
  655 + // 轮询插入书签
  656 + var elements = GetDocParamsValue(doc, constStrEnum.redFileElement);
  657 + if (elements != "") {
  658 + for (var key in elements) {
  659 + console.log(key + "----" + elements[key])
  660 + if (bookMarks.Exists(key)) {
  661 + // 直接插入
  662 + var eleBookmark = bookMarks.Item(key);
  663 + eleBookmark.Range.Text = elements[key];
  664 + }
  665 + }
  666 + }
  667 +
  668 + // 恢复修订模式(根据传入参数决定)
  669 + var l_revisionCtrl = GetDocParamsValue(activeDoc, constStrEnum.revisionCtrl);
  670 + activeDoc.TrackRevisions = l_revisionCtrl == "" ? false : l_revisionCtrl.bOpenRevision;
  671 + //取消WPS关闭时的提示信息
  672 + wps.WpsApplication().DisplayAlerts = wps.Enum&&wps.Enum.wdAlertsNone||0;
  673 +}
  674 +/**
  675 + * 从OA-web端点击套红头
  676 + * doc : 需要存在以下属性
  677 + * 'insertFileUrl':'',获取红头模板接口
  678 + * 'bkInsertFile':'' ,正文书签
  679 + */
  680 +export function InsertRedHeadDoc(doc) { //插入红头
  681 + if (!doc) {
  682 + alert('文档不存在!');
  683 + return;
  684 + }
  685 +
  686 + var bookmark = GetDocParamsValue(doc, constStrEnum.bkInsertFile);
  687 + var strFile = GetDocParamsValue(doc, constStrEnum.insertFileUrl);
  688 + if (strFile == "") {
  689 + alert("未获取到系统传入的红头模板URL路径,不能正常套红");
  690 + return;
  691 + }
  692 + if (bookmark == "") {
  693 + alert("套红头失败,您选择的红头模板没有正文书签!");
  694 + return;
  695 + }
  696 +
  697 + pInsertRInedHead(doc, strFile, bookmark)
  698 +}
... ...
  1 +export const GETDOCNAME = "getDocName";
  2 +export const CREATETASKPANE = "createTaskpane";
  3 +export const NEWDOC = "newDoc";
  4 +export const ADDSTRING = "addString";
  5 +export const CLOSEDOC = "closeDoc";
  6 +export const SETDEMOSPAN = "setDemoSpan";
  7 +export const OPENWEB = "openWeb";
  8 +
  9 +export function getDocName(data) {
  10 + return { type: GETDOCNAME, data }
  11 +}
  12 +
  13 +export function createTaskpane(data) {
  14 + return { type: CREATETASKPANE, data }
  15 +}
  16 +
  17 +export function newDoc(data) {
  18 + return { type: NEWDOC, data }
  19 +}
  20 +
  21 +export function addString(data) {
  22 + return { type: ADDSTRING, data }
  23 +}
  24 +
  25 +export function closeDoc(data) {
  26 + return { type: CLOSEDOC, data }
  27 +}
  28 +
  29 +export function setDemoSpan(data) {
  30 + return { type: SETDEMOSPAN, data }
  31 +}
  32 +
  33 +export function openWeb(data) {
  34 + return { type: OPENWEB, data }
  35 +}
\ No newline at end of file
... ...
  1 +/**
  2 + * WPS常用的API枚举值,具体参与API文档
  3 + */
  4 +export const WPS_Enum = {
  5 + wdDoNotSaveChanges: 0,
  6 + wdFormatPDF: 17,
  7 + wdFormatOpenDocumentText: 23,
  8 + wdFieldFormTextInput: 70,
  9 + wdAlertsNone: 0,
  10 + wdDialogFilePageSetup: 178,
  11 + wdDialogFilePrint: 88,
  12 + wdRelativeHorizontalPositionPage: 1,
  13 + wdGoToPage: 1,
  14 + wdPropertyPages: 14,
  15 + wdRDIComments: 1,
  16 + wdDialogInsertDateTime: 165,
  17 + msoCTPDockPositionLeft: 0,
  18 + msoCTPDockPositionRight: 2,
  19 + /**
  20 + * 将形状嵌入到文字中。
  21 + */
  22 + wdWrapInline: 7,
  23 + /**
  24 + * 将形状放在文字前面。 请参阅 wdWrapFront。
  25 + */
  26 + wdWrapNone: 3,
  27 + /**
  28 + * 使文字环绕形状。 行在形状的另一侧延续。
  29 + */
  30 + wdWrapSquare: 0,
  31 + /**
  32 + * 使文字环绕形状。
  33 + */
  34 + wdWrapThrough: 2,
  35 + /**
  36 + * 使文字紧密地环绕形状。
  37 + */
  38 + wdWrapTight: 1,
  39 + /**
  40 + * 将文字放在形状的上方和下方。
  41 + */
  42 + wdWrapTopBottom: 4,
  43 + /**
  44 + * 将形状放在文字后面。
  45 + */
  46 + wdWrapBehind: 5,
  47 + /**
  48 + * 将形状放在文字前面。
  49 + */
  50 + wdWrapFront: 6
  51 +}
  52 +
  53 +/**
  54 + * WPS加载项自定义的枚举值
  55 + */
  56 + export const constStrEnum = {
  57 + AllowOADocReOpen: "AllowOADocReOpen",
  58 + AutoSaveToServerTime: "AutoSaveToServerTime",
  59 + bkInsertFile: "bkInsertFile",
  60 + buttonGroups: "buttonGroups",
  61 + CanSaveAs: "CanSaveAs",
  62 + copyUrl: "copyUrl",
  63 + DefaultUploadFieldName: "DefaultUploadFieldName",
  64 + disableBtns: "disableBtns",
  65 + insertFileUrl: "insertFileUrl",
  66 + IsInCurrOADocOpen: "IsInCurrOADocOpen",
  67 + IsInCurrOADocSaveAs: "IsInCurrOADocSaveAs",
  68 + isOA: "isOA",
  69 + notifyUrl: "notifyUrl",
  70 + OADocCanSaveAs: "OADocCanSaveAs",
  71 + OADocLandMode: "OADocLandMode",
  72 + OADocUserSave: "OADocUserSave",
  73 + openType: "openType",
  74 + picPath: "picPath",
  75 + picHeight: "picHeight",
  76 + picWidth: "picWidth",
  77 + redFileElement: "redFileElement",
  78 + revisionCtrl: "revisionCtrl",
  79 + ShowOATabDocActive: "ShowOATabDocActive",
  80 + SourcePath: "SourcePath",
  81 + /**
  82 + * 保存文档到业务系统服务端时,另存一份其他格式到服务端,其他格式支持:.pdf .ofd .uot .uof
  83 + */
  84 + suffix: "suffix",
  85 + templateDataUrl: "templateDataUrl",
  86 + TempTimerID: "TempTimerID",
  87 + /**
  88 + * 文档上传到业务系统的保存地址:服务端接收文件流的地址
  89 + */
  90 + uploadPath: "uploadPath",
  91 + /**
  92 + * 文档上传到服务端后的名称
  93 + */
  94 + uploadFieldName: "uploadFieldName",
  95 + /**
  96 + * 文档上传时的名称,默认取当前活动文档的名称
  97 + */
  98 + uploadFileName: "uploadFileName",
  99 + uploadAppendPath: "uploadAppendPath",
  100 + /**
  101 + * 标志位: 1 在保存到业务系统时再保存一份suffix格式的文档, 需要和suffix参数配合使用
  102 + */
  103 + uploadWithAppendPath: "uploadWithAppendPath",
  104 + userName: "userName",
  105 + WPSInitUserName: "WPSInitUserName",
  106 + taskpaneid: "taskpaneid",
  107 + /**
  108 + * 是否弹出上传前确认和成功后的确认信息:true|弹出,false|不弹出
  109 + */
  110 + Save2OAShowConfirm: "Save2OAShowConfirm",
  111 + /**
  112 + * 修订状态标志位
  113 + */
  114 + RevisionEnableFlag: "RevisionEnableFlag"
  115 +}
  116 +
  117 +export const EnumOAFlag = {
  118 + DocFromOA: 1,
  119 + DocFromNoOA: 0
  120 +}
  121 +
  122 +//记录是否用户点击OA文件的保存按钮
  123 +export const EnumDocSaveFlag = {
  124 + OADocSave: 1,
  125 + NoneOADocSave: 0
  126 +}
  127 +
  128 +//标识文档的落地模式 本地文档落地 0 ,不落地 1
  129 +export const EnumDocLandMode = {
  130 + DLM_LocalDoc: 0,
  131 + DLM_OnlineDoc: 1
  132 +}
\ No newline at end of file
... ...
  1 +/*
  2 + * @Descripttion:
  3 + * @version:
  4 + * @Author: 魏永康
  5 + * @Date: 2021-04-21 18:59:57
  6 + * @LastEditors: sueRimn
  7 + * @LastEditTime: 2021-04-21 19:17:11
  8 + */
  9 +/**
  10 + * Emulate FormData for some browsers
  11 + * MIT License
  12 + * (c) 2010 François de Metz
  13 + */
  14 +(function(w) {
  15 + if (w.FakeFormData)
  16 + return;
  17 + function FormData() {
  18 + this.fake = true;
  19 + this.boundary = "------WebKitFormBoundary" + Math.random();
  20 + this._fields = [];
  21 + }
  22 + FormData.prototype.append = function(key, value) {
  23 + this._fields.push([key, value]);
  24 + }
  25 + FormData.prototype.toString = function() {
  26 + var boundary = this.boundary;
  27 + var body = "";
  28 + this._fields.forEach(function(field) {
  29 + body += "--" + boundary + "\r\n";
  30 + // file upload
  31 + if (field[1].name) {
  32 + var file = field[1];
  33 + body += "Content-Disposition: form-data; name=\""+ field[0] +"\"; filename=\""+ file.name +"\"\r\n";
  34 + body += "Content-Type: "+ file.type +"\r\n\r\n";
  35 + body += file.getAsBinary() + "\r\n";
  36 + } else {
  37 + body += "Content-Disposition: form-data; name=\""+ field[0] +"\";\r\n\r\n";
  38 + body += field[1] + "\r\n";
  39 + }
  40 + });
  41 + body += "--" + boundary +"--";
  42 + return body;
  43 + }
  44 + w.FakeFormData = FormData;
  45 +})(window);
\ No newline at end of file
... ...
  1 +export const getUserInfo = data => {
  2 + return {
  3 + type: 'GET_USER_INFO',
  4 + data
  5 + }
  6 +}
\ No newline at end of file
... ...
  1 +/*
  2 + * @Descripttion:
  3 + * @version:
  4 + * @Author: 魏永康
  5 + * @Date: 2021-04-20 16:18:53
  6 + * @LastEditors: sueRimn
  7 + * @LastEditTime: 2021-04-25 15:09:17
  8 + */
  9 +
  10 +import {GetDocParamsValue,UploadFile,OnUploadToServerSuccess,OnUploadToServerFail,OnShowDialog,InsertRedHeadDoc,DownloadFile} from "./common.js"
  11 +import {constStrEnum,EnumDocSaveFlag} from "./enum.js"
  12 +
  13 +var wps = window.wps||window
  14 +
  15 +
  16 +// 初始化
  17 + function initWpsAddin() {
  18 + if(wps.FileSystem.Exists(wps.Env.GetTempPath())){
  19 + wps.FileSystem.Remove(wps.Env.GetTempPath());
  20 + wps.FileSystem.Mkdir(wps.Env.GetTempPath())
  21 + }
  22 +}
  23 +
  24 +// 保存
  25 +function OnSaveToServer() {
  26 + // console.log('SaveToServer');
  27 + var doc = wps.WpsApplication().ActiveDocument;
  28 + if (!doc) {
  29 + alert("空文档不能保存!");
  30 + return;
  31 + }
  32 +
  33 + var param = wps.PluginStorage.getItem(doc.DocID);
  34 +
  35 + if(typeof param == "string") param = JSON.parse(param);
  36 +
  37 + if(param == null || param.OADocLandMode === 0 ) {
  38 + wps.WpsApplication().CommandBars.ExecuteMso("SaveAll");
  39 + return;
  40 + }
  41 +
  42 +
  43 +
  44 +
  45 + let {tokenIdKey,nid,token,openUrl,writeUrl,fullName} = param;
  46 + if(tokenIdKey == null ||nid == null || token == null || openUrl == null || writeUrl == null || fullName == null){
  47 + alert("取参数失败,请确定此文档是OA文档,tokenIdKey,nid,token,openUrl,writeUrl,fullName 参数取值不可为空!")
  48 + }
  49 +
  50 +
  51 + // //非OA文档,不能上传到OA
  52 + // if (pCheckIfOADoc() == false) {
  53 + // alert("非系统打开的文档,不能直接上传到系统!");
  54 + // return;
  55 + // }
  56 +
  57 + // //如果是OA打开的文档,并且设置了保护的文档,则不能再上传到OA服务器
  58 + // if (pISOADocReadOnly(doc)) {
  59 + // wps.alert("系统设置了保护的文档,不能再提交到系统后台。");
  60 + // return;
  61 + // }
  62 +
  63 + /**
  64 + * 参数定义:OAAsist.UploadFile(name, path, url, field, "OnSuccess", "OnFail")
  65 + * 上传一个文件到远程服务器。
  66 + * name:为上传后的文件名称;
  67 + * path:是文件绝对路径;
  68 + * url:为上传地址;
  69 + * field:为请求中name的值;
  70 + * 最后两个参数为回调函数名称;
  71 + */
  72 +
  73 +
  74 + var l_showConfirm = wps.PluginStorage.getItem(constStrEnum.Save2OAShowConfirm)
  75 + if (l_showConfirm) {
  76 + if (!wps.confirm("先保存文档,并开始上传到系统后台,请确认?")) {
  77 + return;
  78 + }
  79 + }
  80 +
  81 + var l_FieldName = GetDocParamsValue(doc, constStrEnum.uploadFieldName); //上载到后台的业务方自定义的字段名称
  82 + if (l_FieldName == "") {
  83 + l_FieldName = wps.PluginStorage.getItem(constStrEnum.DefaultUploadFieldName); // 默认为‘file’
  84 + }
  85 +
  86 + var l_UploadName = GetDocParamsValue(doc, constStrEnum.uploadFileName); //设置OA传入的文件名称参数
  87 + if (l_UploadName == "") {
  88 + l_UploadName = doc.Name; //默认文件名称就是当前文件编辑名称
  89 + }
  90 +
  91 + var docPath = doc.FullName; // 文件所在路径
  92 +
  93 + // if (pIsOnlineOADoc(doc) == false) {
  94 + //对于本地磁盘文件上传OA,先用Save方法保存后,再上传
  95 + //设置用户保存按钮标志,避免出现禁止OA文件保存的干扰信息
  96 + wps.PluginStorage.setItem(constStrEnum.OADocUserSave, EnumDocSaveFlag.OADocSave);
  97 + doc.Save(); //执行一次保存方法
  98 + //设置用户保存按钮标志
  99 + wps.PluginStorage.setItem(constStrEnum.OADocUserSave, EnumDocSaveFlag.NoneOADocSave);
  100 + //落地文档,调用UploadFile方法上传到OA后台
  101 + try {
  102 + //调用OA助手的上传方法
  103 + UploadFile(fullName, docPath, writeUrl, null,param, OnUploadToServerSuccess, OnUploadToServerFail);
  104 + } catch (err) {
  105 + alert("上传文件失败!请检查系统上传参数及网络环境!");
  106 + }
  107 + // } else {
  108 + // // 不落地的文档,调用 Document 对象的不落地上传方法
  109 + // wps.PluginStorage.setItem(constStrEnum.OADocUserSave, EnumDocSaveFlag.OADocSave);
  110 + // try {
  111 + // //调用不落地上传方法
  112 + // doc.SaveAsUrl(l_UploadName, l_uploadPath, l_FieldName, "OnUploadToServerSuccess", "OnUploadToServerFail");
  113 + // } catch (err) {
  114 + // alert("上传文件失败!请检查系统上传参数及网络环境,重新上传。");
  115 + // }
  116 + // wps.PluginStorage.setItem(constStrEnum.OADocUserSave, EnumDocSaveFlag.NoneOADocSave);
  117 + // }
  118 +
  119 + // //获取OA传入的 转其他格式上传属性
  120 + // var l_suffix = GetDocParamsValue(doc, constStrEnum.suffix);
  121 + // if (l_suffix == "") {
  122 + // console.log("上传需转换的文件后缀名错误,无法进行转换上传!");
  123 + // return;
  124 + // }
  125 +
  126 + //判断是否同时上传PDF等格式到OA后台
  127 + var l_uploadWithAppendPath = GetDocParamsValue(doc, constStrEnum.uploadWithAppendPath); //标识是否同时上传suffix格式的文档
  128 + if (l_uploadWithAppendPath == "1") {
  129 + //调用转pdf格式函数,强制关闭转换修订痕迹,不弹出用户确认的对话框
  130 + // pDoChangeToOtherDocFormat(doc, l_suffix, false, false);
  131 + }
  132 + return;
  133 +}
  134 +
  135 +export function OnInsertRedHeaderClick() {
  136 + var l_Doc = wps.WpsApplication().ActiveDocument;
  137 + if (!l_Doc) {
  138 + return;
  139 + }
  140 + var l_insertFileUrl = GetDocParamsValue(l_Doc, constStrEnum.insertFileUrl); //插入文件的位置
  141 + var l_BkFile = GetDocParamsValue(l_Doc, constStrEnum.bkInsertFile);
  142 + if (l_BkFile == "" || l_insertFileUrl == "") {
  143 + var height = 250;
  144 + var width = 400;
  145 + OnShowDialog("redhead.html", "OA助手", width, height);
  146 + return;
  147 + }
  148 + InsertRedHeadDoc(l_Doc);
  149 +}
  150 +
  151 +
  152 +function openWebFile(param){
  153 + if(param == null) {
  154 + return {code:-1,msg:"参数错误!"}
  155 + }
  156 +
  157 + let {tokenIdKey,nid,token,openUrl,writeUrl,fullName} = param;
  158 +
  159 + if(tokenIdKey == null ||nid == null || token == null || openUrl == null || writeUrl == null || fullName == null){
  160 + return {code:-1,msg:"参数错误!tokenIdKey,nid,token,openUrl,writeUrl,fullName 不可为空"}
  161 + }
  162 +
  163 + let url = `${openUrl}?nid=${nid}&token=${token}`;
  164 +
  165 + DownloadFile(
  166 + url,
  167 + fullName,
  168 + (path) => {
  169 + let doc = wps
  170 + .WpsApplication()
  171 + .Documents.Open(path, false, false, false, "");
  172 +
  173 + if (!doc) return;
  174 + var l_Param = wps.PluginStorage.getItem(doc.DocID);
  175 + if(l_Param == null) {
  176 + l_Param = param;
  177 + }else if(typeof l_Param == "string"){
  178 + l_Param = JSON.parse(l_Param);
  179 + }
  180 + //增加属性,或设置
  181 + l_Param.OADocLandMode = 0; //设置OA文档的落地标志
  182 +
  183 + //将OA文档落地模式标志存入系统变量对象保存
  184 +
  185 + wps.PluginStorage.setItem(doc.DocID,JSON.stringify(param) );
  186 + // 把WPS对象置前
  187 + wps.WpsApplication().WindowState = 1;
  188 + wps.WpsApplication().Activate();
  189 + }
  190 + );
  191 +}
  192 +
  193 +export function onWebEvent(param){
  194 + if(param == undefined || param.eventType == undefined){
  195 + return {code:-1,msg:"无此类型!"}
  196 + }
  197 +
  198 + let eventType = param.eventType;
  199 +
  200 + switch (eventType){
  201 + case "openOfficeEidt":
  202 + return openWebFile(param);
  203 + break;
  204 +
  205 + default:
  206 + return {code:-1,msg:`无此类型【${eventType}】`}
  207 +
  208 + }
  209 +
  210 +}
  211 +
  212 +export default {onWebEvent,openWebFile,OnSaveToServer,initWpsAddin}
\ No newline at end of file
... ...
  1 +export const DOCKLEFT = "dockLeft";
  2 +export const DOCKRIGHT = "dockRight";
  3 +export const HIDETASKPANE = "hideTaskPane";
  4 +export const ADDSTRING = "addString";
  5 +export const GETDOCNAME = "getDocName";
  6 +export const SETDEMOSPAN = "setDemoSpan";
  7 +export const OPENWEB = "openWeb";
  8 +
  9 +
  10 +export function dockLeft(data) {
  11 + return { type: DOCKLEFT, data }
  12 +}
  13 +
  14 +export function dockRight(data) {
  15 + return { type: DOCKRIGHT, data }
  16 +}
  17 +
  18 +export function hideTaskPane(data) {
  19 + return { type: HIDETASKPANE, data }
  20 +}
  21 +
  22 +export function addString(data) {
  23 + return { type: ADDSTRING, data }
  24 +}
  25 +
  26 +export function getDocName(data) {
  27 + return { type: GETDOCNAME, data }
  28 +}
  29 +
  30 +export function setDemoSpan(data) {
  31 + return { type: SETDEMOSPAN, data }
  32 +}
  33 +
  34 +export function openWeb(data) {
  35 + return { type: OPENWEB, data }
  36 +}
\ No newline at end of file
... ...
  1 +import React, { Component } from 'react';
  2 +import ribbon from './ribbon';
  3 +
  4 +
  5 +class App extends Component {
  6 + constructor(props) {
  7 + super(props)
  8 + this.state = {
  9 + }
  10 + console.log("init ribbon")
  11 + window.ribbon = ribbon;
  12 + }
  13 +
  14 + render() {
  15 + return (
  16 + <div>
  17 + this is index.html
  18 + </div>
  19 + )
  20 + }
  21 +}
  22 +
  23 +export default App;
... ...
  1 +button {
  2 + margin: 4px;
  3 +}
  4 +
  5 +.global{
  6 + font-size: 15px;
  7 + min-height: 95%;
  8 +}
  9 +
  10 +.divItem {
  11 + margin-left: 5px;
  12 + margin-bottom: 18px;
  13 + font-size: 15px;
  14 + word-wrap: break-word;
  15 +}
  16 +
  17 +.debug {
  18 + font-weight: bolder;
  19 +}
  20 +
  21 +.docs {
  22 + font-weight: bolder;
  23 + color: slateblue;
  24 +}
\ No newline at end of file
... ...
  1 +import React, { Component } from 'react';
  2 +import { connect } from 'react-redux';
  3 +import { getDocName, createTaskpane, newDoc, addString, closeDoc, setDemoSpan, openWeb } from '../actions/dialog';
  4 +import './dialog.css';
  5 +import axios from 'axios'
  6 +
  7 +
  8 +class Dialog extends Component {
  9 + constructor(props) {
  10 + super(props);
  11 + this.state = {
  12 + };
  13 + }
  14 +
  15 + componentDidMount() {
  16 + axios.get('/.debugTemp/NotifyDemoUrl').then((res) => {
  17 + const { setDemoSpan } = this.props;
  18 + setDemoSpan(res.data);
  19 + });
  20 + }
  21 +
  22 + onDocNameClick = () => {
  23 + const { getDocName } = this.props;
  24 + getDocName();
  25 + }
  26 +
  27 + onCreateTaskpane = () => {
  28 + const { createTaskpane } = this.props;
  29 + createTaskpane();
  30 + }
  31 +
  32 + onCreateDoc = () => {
  33 + const { newDoc } = this.props;
  34 + newDoc();
  35 + }
  36 +
  37 + onAddString = () => {
  38 + const { addString } = this.props;
  39 + addString();
  40 + }
  41 +
  42 + onCloseDoc = () => {
  43 + const { closeDoc } = this.props;
  44 + closeDoc();
  45 + }
  46 +
  47 + onOpenWeb = () => {
  48 + const { openWeb } = this.props;
  49 + openWeb();
  50 + }
  51 +
  52 + render() {
  53 + const { docName, demoSpan } = this.props;
  54 +
  55 + return (
  56 + <div>
  57 + <div className="divItem">
  58 + 这是一个网页,按<span className="debug">"F12"</span>可以打开调试器
  59 + </div>
  60 + <div className="divItem">
  61 + 这个示例展示了wps加载项的相关基础能力,与B/S业务系统的交互,请用浏览器打开:
  62 + <span className="docs" onClick={this.onOpenWeb}>{demoSpan}</span>
  63 + </div>
  64 + <div className="divItem">开发文档: <span className="docs">https://open.wps.cn/docs/office</span></div>
  65 + <div>
  66 + <button onClick={this.onDocNameClick}>取文件名</button>
  67 + <button onClick={this.onCreateTaskpane}>创建任务窗格</button>
  68 + <button onClick={this.onCreateDoc}>新建文件</button>
  69 + <button onClick={this.onAddString}>文档开头添加字符串</button>
  70 + <button onClick={this.onCloseDoc}>关闭文件</button>
  71 + </div>
  72 + <hr />
  73 + <div>文档文件名为:<span>{docName}</span></div>
  74 + </div>
  75 + )
  76 + }
  77 +}
  78 +
  79 +const mapStateToProps = state => {
  80 + return {
  81 + docName: state.dialog.get('docName'),
  82 + demoSpan: state.dialog.get('demoSpan'),
  83 + }
  84 +}
  85 +
  86 +export default connect(mapStateToProps, {
  87 + getDocName,
  88 + createTaskpane,
  89 + newDoc,
  90 + addString,
  91 + closeDoc,
  92 + setDemoSpan,
  93 + openWeb
  94 +})(Dialog);
... ...
  1 +import Util from "../js/util.js";
  2 +import SystemDemo from "../js/systemdemo.js";
  3 +import {
  4 + DownloadFile
  5 +} from "../actions/common.js";
  6 +
  7 +import SystemAddin,{onWebEvent} from "../actions/systemAddin.js";
  8 +/* global wps:false */
  9 +var WebNotifycount = 0;
  10 +
  11 +var ribbon = {
  12 + //这个函数在整个wps加载项中是第一个执行的
  13 + OnAddinLoad: function (ribbonUI) {
  14 + if (typeof wps.ribbonUI != "object") {
  15 + wps.ribbonUI = ribbonUI;
  16 + }
  17 +
  18 + if (typeof wps.Enum != "object") {
  19 + // 如果没有内置枚举值
  20 + wps.Enum = Util.WPS_Enum;
  21 + }
  22 +
  23 + //这几个导出函数是给外部业务系统调用的
  24 + window.openOfficeFileFromSystemDemo =
  25 + SystemDemo.openOfficeFileFromSystemDemo;
  26 + window.InvokeFromSystemDemo = SystemDemo.InvokeFromSystemDemo;
  27 +
  28 + window.onWebEvent = onWebEvent;
  29 +
  30 + wps.PluginStorage.setItem("EnableFlag", false); //往PluginStorage中设置一个标记,用于控制两个按钮的置灰
  31 + wps.PluginStorage.setItem("ApiEventFlag", false); //往PluginStorage中设置一个标记,用于控制ApiEvent的按钮label
  32 + wps.ribbonUI.ActivateTab('SystemAddin'); // 切换tab
  33 + SystemAddin.initWpsAddin();
  34 +
  35 + return true;
  36 + },
  37 +
  38 + OnAction: function (control) {
  39 + const eleId = control.Id;
  40 + switch (eleId) {
  41 + case "btnShowMsg": {
  42 + const doc = wps.WpsApplication().ActiveDocument;
  43 + if (!doc) {
  44 + alert("当前没有打开任何文档");
  45 + return;
  46 + }
  47 + alert(doc.Name);
  48 + }
  49 + break;
  50 + case "btnIsEnbable": {
  51 + let bFlag = wps.PluginStorage.getItem("EnableFlag");
  52 + wps.PluginStorage.setItem("EnableFlag", !bFlag);
  53 +
  54 + //通知wps刷新以下几个按饰的状态
  55 + wps.ribbonUI.InvalidateControl("btnIsEnbable");
  56 + wps.ribbonUI.InvalidateControl("btnShowDialog");
  57 + wps.ribbonUI.InvalidateControl("btnShowTaskPane");
  58 + //wps.ribbonUI.Invalidate(); 这行代码打开则是刷新所有的按钮状态
  59 + break;
  60 + }
  61 + case "btnShowDialog":
  62 + wps.ShowDialog(
  63 + Util.GetUrlPath() + "dialog",
  64 + "这是一个对话框网页",
  65 + 400 * window.devicePixelRatio,
  66 + 400 * window.devicePixelRatio,
  67 + false
  68 + );
  69 + break;
  70 + case "btnShowTaskPane": {
  71 + let tsId = wps.PluginStorage.getItem("taskpane_id");
  72 + if (!tsId) {
  73 + let tskpane = wps.CreateTaskPane(Util.GetUrlPath() + "taskpane");
  74 + let id = tskpane.ID;
  75 + wps.PluginStorage.setItem("taskpane_id", id);
  76 + tskpane.Visible = true;
  77 + } else {
  78 + let tskpane = wps.GetTaskPane(tsId);
  79 + tskpane.Visible = !tskpane.Visible;
  80 + }
  81 + }
  82 + break;
  83 + case "btnApiEvent": {
  84 + let bFlag = wps.PluginStorage.getItem("ApiEventFlag");
  85 + let bRegister = bFlag ? false : true;
  86 + wps.PluginStorage.setItem("ApiEventFlag", bRegister);
  87 + if (bRegister) {
  88 + wps.ApiEvent.AddApiEventListener(
  89 + "DocumentNew",
  90 + "ribbon.OnNewDocumentApiEvent"
  91 + );
  92 + } else {
  93 + wps.ApiEvent.RemoveApiEventListener(
  94 + "DocumentNew",
  95 + "ribbon.OnNewDocumentApiEvent"
  96 + );
  97 + }
  98 +
  99 + wps.ribbonUI.InvalidateControl("btnApiEvent");
  100 + }
  101 + break;
  102 + case "btnWebNotify": {
  103 + let currentTime = new Date();
  104 + let timeStr =
  105 + currentTime.getHours() +
  106 + ":" +
  107 + currentTime.getMinutes() +
  108 + ":" +
  109 + currentTime.getSeconds();
  110 + wps.OAAssist.WebNotify(
  111 + "这行内容由wps加载项主动送达给业务系统,可以任意自定义, 比如时间值:" +
  112 + timeStr +
  113 + ",次数:" +
  114 + ++WebNotifycount,
  115 + true
  116 + );
  117 + }
  118 + break;
  119 + case "btnOpenWebFile": {
  120 + DownloadFile(
  121 + "https://apps.chinadci.com/api/attach/stream/open.do?nid=uMLA3veiVV92b8mUGSW&token=3e299484-5286-4bc5-a538-0ab1bdeecfbc",
  122 + "收 入 证 明 .docx",
  123 + (path) => {
  124 + let doc = wps
  125 + .WpsApplication()
  126 + .Documents.Open(path, false, false, false, "");
  127 +
  128 + if (!doc) return;
  129 + var l_Param = wps.PluginStorage.getItem(doc.DocID);
  130 + var l_objParam = JSON.parse(l_Param);
  131 + //增加属性,或设置
  132 + l_objParam.OADocLandMode = 0; //设置OA文档的落地标志
  133 +
  134 + var l_p = JSON.stringify(l_objParam);
  135 + //将OA文档落地模式标志存入系统变量对象保存
  136 +
  137 + wps.PluginStorage.setItem(doc.DocID, l_p);
  138 + // 把WPS对象置前
  139 + wps.WpsApplication().WindowState = 1;
  140 + wps.WpsApplication().Activate();
  141 + }
  142 + );
  143 + }
  144 + break;
  145 + case "btnSaveToServer":
  146 + {
  147 + SystemAddin.OnSaveToServer()
  148 + }
  149 + break;
  150 + case "btnInsertRedHeader":
  151 + {
  152 +
  153 + }
  154 + break;
  155 + default:
  156 + case "FileSave":
  157 + {
  158 + let doc = wps.WpsApplication().ActiveDocument;
  159 + if (!doc) {
  160 + alert("空文档不能保存!");
  161 + return;
  162 + }
  163 +
  164 + let param = wps.PluginStorage.getItem(doc.DocID);
  165 +
  166 + if(param != null){
  167 + param = JSON.parse(param);
  168 + if(param.OADocLandMode == 0){
  169 + SystemAddin.OnSaveToServer();
  170 + return;
  171 + }
  172 + }
  173 +
  174 + }
  175 + break;
  176 + }
  177 + return true;
  178 + },
  179 +
  180 + GetImage: function (control) {
  181 + const eleId = control.Id;
  182 + switch (eleId) {
  183 + case "btnShowMsg":
  184 + return "images/1.svg";
  185 + case "btnShowDialog":
  186 + return "images/2.svg";
  187 + case "btnShowTaskPane":
  188 + return "images/3.svg";
  189 + default:
  190 + }
  191 + return "images/newFromTemp.svg";
  192 + },
  193 +
  194 + OnGetEnabled: function (control) {
  195 + const eleId = control.Id;
  196 + switch (eleId) {
  197 + case "btnShowMsg":
  198 + return true;
  199 + case "btnShowDialog": {
  200 + let bFlag = wps.PluginStorage.getItem("EnableFlag");
  201 + return bFlag;
  202 + }
  203 + case "btnShowTaskPane": {
  204 + let bFlag = wps.PluginStorage.getItem("EnableFlag");
  205 + return bFlag;
  206 + }
  207 + default:
  208 + break;
  209 + }
  210 + return true;
  211 + },
  212 +
  213 + OnGetVisible: function (control) {
  214 + const eleId = control.Id;
  215 + console.log(eleId);
  216 + return true;
  217 + },
  218 +
  219 + OnGetLabel: function (control) {
  220 + const eleId = control.Id;
  221 + switch (eleId) {
  222 + case "btnIsEnbable": {
  223 + let bFlag = wps.PluginStorage.getItem("EnableFlag");
  224 + return bFlag ? "按钮Disable" : "按钮Enable";
  225 + }
  226 + case "btnApiEvent": {
  227 + let bFlag = wps.PluginStorage.getItem("ApiEventFlag");
  228 + return bFlag ? "清除新建文件事件" : "注册新建文件事件";
  229 + }
  230 + default:
  231 + break;
  232 + }
  233 + return "";
  234 + },
  235 +
  236 + OnNewDocumentApiEvent: function (doc) {
  237 + alert("新建文件事件响应,取文件名: " + doc.Name);
  238 + },
  239 +};
  240 +
  241 +export default ribbon;
\ No newline at end of file
... ...
  1 +import React, { Component } from 'react';
  2 +import { connect } from 'react-redux';
  3 +import { dockLeft, dockRight, hideTaskPane, addString, getDocName, setDemoSpan, openWeb } from '../actions/taskpane';
  4 +import './dialog.css';
  5 +import axios from 'axios';
  6 +
  7 +
  8 +class Taskpane extends Component {
  9 +
  10 + componentDidMount() {
  11 + axios.get('/.debugTemp/NotifyDemoUrl').then((res) => {
  12 + const { setDemoSpan } = this.props;
  13 + setDemoSpan(res.data);
  14 + });
  15 + }
  16 +
  17 + onDockLeft = () => {
  18 + const { dockLeft } = this.props;
  19 + dockLeft();
  20 + }
  21 +
  22 + onDockRight = () => {
  23 + const { dockRight } = this.props;
  24 + dockRight();
  25 + }
  26 + onHideTaskPane = () => {
  27 + const { hideTaskPane } = this.props;
  28 + hideTaskPane();
  29 + }
  30 + onAddString = () => {
  31 + const { addString } = this.props;
  32 + addString();
  33 + }
  34 + onGetDocName = () => {
  35 + const { getDocName } = this.props;
  36 + getDocName();
  37 + }
  38 + onOpenWeb = () => {
  39 + const { openWeb } = this.props;
  40 + openWeb();
  41 + }
  42 +
  43 + render() {
  44 + const { docName, demoSpan } = this.props;
  45 +
  46 + return (
  47 + <div className="global">
  48 + <div className="divItem">
  49 + 这是一个网页,按<span className="debug">"F12"</span>可以打开调试器
  50 + </div>
  51 + <div className="divItem">
  52 + 这个示例展示了wps加载项的相关基础能力,与B/S业务系统的交互,请用浏览器打开:
  53 + <span className="docs" onClick={this.onOpenWeb}>{demoSpan}</span>
  54 + </div>
  55 + <div className="divItem">开发文档: <span className="docs">https://open.wps.cn/docs/office</span></div>
  56 + <hr />
  57 + <div className="divItem">
  58 + <button onClick={this.onDockLeft}>停靠左边</button>
  59 + <button onClick={this.onDockRight}>停靠右边</button>
  60 + <button onClick={this.onHideTaskPane}>隐藏TaskPane</button>
  61 + <button onClick={this.onAddString} > 文档开头添加字符串</button >
  62 + <button onClick={this.onGetDocName} > 取文件名</button >
  63 + </div >
  64 + <hr />
  65 + <div className="divItem">文档文件名为:<span>{docName}</span></div>
  66 + </div>
  67 + )
  68 + }
  69 +}
  70 +
  71 +const mapStateToProps = state => {
  72 + return {
  73 + docName: state.dialog.get('docName'),
  74 + demoSpan: state.dialog.get('demoSpan'),
  75 + }
  76 +}
  77 +
  78 +export default connect(mapStateToProps, {
  79 + dockLeft,
  80 + dockRight,
  81 + hideTaskPane,
  82 + addString,
  83 + getDocName,
  84 + setDemoSpan,
  85 + openWeb
  86 +})(Taskpane);
... ...
  1 +/*
  2 + * @Descripttion:
  3 + * @version:
  4 + * @Author: 魏永康
  5 + * @Date: 2021-04-20 14:53:58
  6 + * @LastEditors: sueRimn
  7 + * @LastEditTime: 2021-04-21 19:00:39
  8 + */
  9 +import React from 'react';
  10 +import ReactDOM from 'react-dom';
  11 +import { HashRouter, Route, Switch } from 'react-router-dom';
  12 +import "./actions/formdata.js";
  13 +import App from './components/app';
  14 +import Dialog from './components/dialog';
  15 +import TaskPane from './components/taskpane';
  16 +import { Provider } from 'react-redux';
  17 +import { createStore } from "redux";
  18 +import rootReducer from './reducers';
  19 +
  20 +const store = createStore(rootReducer, window.STATE_FROM_SERVER);
  21 +
  22 +ReactDOM.render((
  23 + <Provider store={store}>
  24 + <HashRouter>
  25 + <Switch>
  26 + <Route path="/" exact component={App} />
  27 + <Route path="/dialog" exact component={Dialog} />
  28 + <Route path="/taskpane" exact component={TaskPane} />
  29 + </Switch>
  30 + </HashRouter>
  31 + </Provider>
  32 +), document.getElementById("root")
  33 +);
... ...
  1 +
  2 +/* global wps:false */
  3 +
  4 +function openOfficeFileFromSystemDemo(param){
  5 + let jsonObj = (typeof(param)=='string' ? JSON.parse(param) : param)
  6 + alert("从业务系统传过来的参数为:" + JSON.stringify(jsonObj))
  7 + return {wps加载项项返回: jsonObj.filepath + ", 这个地址给的不正确"}
  8 +}
  9 +
  10 +function InvokeFromSystemDemo(param){
  11 + let jsonObj = (typeof(param)=='string' ? JSON.parse(param) : param)
  12 + let handleInfo = jsonObj.Index
  13 + switch (handleInfo){
  14 + case "getDocumentName":{
  15 + let docName = ""
  16 + if (wps.WpsApplication().ActiveDocument){
  17 + docName = wps.WpsApplication().ActiveDocument.Name
  18 + }
  19 +
  20 + return {当前打开的文件名为:docName}
  21 + }
  22 +
  23 + case "newDocument":{
  24 + let newDocName=""
  25 + let doc = wps.WpsApplication().Documents.Add()
  26 + newDocName = doc.Name
  27 +
  28 + return {操作结果:"新建文档成功,文档名为:" + newDocName}
  29 + }
  30 +
  31 + case "OpenFile":{
  32 + let filePath = jsonObj.filepath
  33 + wps.WpsApplication().Documents.OpenFromUrl(filePath)
  34 + return {操作结果:"打开文件成功"}
  35 + }
  36 + default:
  37 + }
  38 +
  39 + return {其它xxx:""}
  40 +}
  41 +
  42 +export default{
  43 + openOfficeFileFromSystemDemo,
  44 + InvokeFromSystemDemo
  45 +}
\ No newline at end of file
... ...
  1 +//在后续的wps版本中,wps的所有枚举值都会通过wps.Enum对象来自动支持,现阶段先人工定义
  2 +var WPS_Enum = {
  3 + msoCTPDockPositionLeft: 0,
  4 + msoCTPDockPositionRight: 2
  5 +}
  6 +
  7 +function GetUrlPath() {
  8 + let e = document.location.toString()
  9 + e = decodeURI(e)
  10 + if (-1 !== e.indexOf("/"))
  11 + e = e.substring(0, e.lastIndexOf("/"))
  12 + return e
  13 +}
  14 +
  15 +export default {
  16 + WPS_Enum,
  17 + GetUrlPath
  18 +}
... ...
  1 +import { GETDOCNAME, CREATETASKPANE, NEWDOC, ADDSTRING, CLOSEDOC, SETDEMOSPAN, OPENWEB } from "../actions/dialog";
  2 +import * as Immutable from "immutable";
  3 +import Util from "../js/util.js"
  4 +
  5 +/* global wps:false */
  6 +
  7 +const defaultState = Immutable.Map({
  8 + docName: null,
  9 + demoSpan: "waiting..."
  10 +});
  11 +
  12 +export default function (state = defaultState, action) {
  13 + switch (action.type) {
  14 + case GETDOCNAME:
  15 + {
  16 + let docName = wps.WpsApplication().ActiveDocument.Name
  17 + let newState = state.set('docName', docName)
  18 + return newState
  19 + }
  20 + case NEWDOC:
  21 + {
  22 + wps.WpsApplication().Documents.Add()
  23 + break;
  24 + }
  25 + case CREATETASKPANE:
  26 + {
  27 + let tsId = wps.PluginStorage.getItem("taskpane_id")
  28 + if (!tsId){
  29 + let tskpane = wps.CreateTaskPane(Util.GetUrlPath() + "taskpane")
  30 + let id = tskpane.ID
  31 + wps.PluginStorage.setItem("taskpane_id", id)
  32 + tskpane.Visible = true
  33 + }else{
  34 + let tskpane = wps.GetTaskPane(tsId)
  35 + tskpane.Visible = true
  36 + }
  37 + break
  38 + }
  39 + case ADDSTRING:
  40 + {
  41 + let doc = wps.WpsApplication().ActiveDocument
  42 + if (doc){
  43 + doc.Range(0, 0).Text="Hello, wps加载项!"
  44 + //好像是wps的bug, 这两句话触发wps重绘
  45 + let rgSel = wps.WpsApplication().Selection.Range
  46 + if (rgSel)
  47 + rgSel.Select()
  48 + }
  49 + break;
  50 + }
  51 + case CLOSEDOC:
  52 + {
  53 + if (wps.WpsApplication().Documents.Count < 2)
  54 + {
  55 + alert("当前只有一个文档,别关了。")
  56 + break
  57 + }
  58 +
  59 + let doc = wps.WpsApplication().ActiveDocument
  60 + if (doc)
  61 + doc.Close()
  62 + break;
  63 + }
  64 + case SETDEMOSPAN:
  65 + {
  66 + let newState = state.set('demoSpan', action.data)
  67 + return newState
  68 + }
  69 + case OPENWEB:
  70 + {
  71 + let param = state.get('demoSpan')
  72 + wps.OAAssist.ShellExecute(param)
  73 + }
  74 + default:
  75 + }
  76 + return state;
  77 +}
\ No newline at end of file
... ...
  1 +import { combineReducers } from 'redux';
  2 +import dialog from './dialog';
  3 +import taskpane from './taskpane';
  4 +
  5 +const rootReducer = combineReducers({
  6 + dialog,
  7 + taskpane
  8 +});
  9 +
  10 +export default rootReducer;
\ No newline at end of file
... ...
  1 +import { DOCKLEFT, DOCKRIGHT, HIDETASKPANE, ADDSTRING, GETDOCNAME, SETDEMOSPAN, OPENWEB } from "../actions/taskpane";
  2 +import * as Immutable from "immutable";
  3 +import Util from "../js/util.js"
  4 +
  5 +/* global wps:false */
  6 +
  7 +const defaultState = Immutable.Map({
  8 + docName: null,
  9 + demoSpan: "waiting..."
  10 +});
  11 +
  12 +export default function (state = defaultState, action) {
  13 + switch (action.type) {
  14 + case DOCKLEFT:
  15 + {
  16 + let tsId = wps.PluginStorage.getItem("taskpane_id")
  17 + if (tsId){
  18 + let tskpane = wps.GetTaskPane(tsId)
  19 + let value;
  20 + if (wps.Enum)
  21 + value = wps.Enum.msoCTPDockPositionLeft;
  22 + else
  23 + value = Util.WPS_Enum.msoCTPDockPositionLeft
  24 + tskpane.DockPosition = value
  25 + }
  26 + break
  27 + }
  28 + case DOCKRIGHT:
  29 + {
  30 + let tsId = wps.PluginStorage.getItem("taskpane_id")
  31 + if (tsId){
  32 + let tskpane = wps.GetTaskPane(tsId)
  33 + let value;
  34 + if (wps.Enum)
  35 + value = wps.Enum.msoCTPDockPositionRight;
  36 + else
  37 + value = Util.WPS_Enum.msoCTPDockPositionRight
  38 + tskpane.DockPosition = value
  39 + }
  40 + break
  41 + }
  42 + case HIDETASKPANE:
  43 + {
  44 + let tsId = wps.PluginStorage.getItem("taskpane_id")
  45 + if (tsId){
  46 + let tskpane = wps.GetTaskPane(tsId)
  47 + tskpane.Visible = false
  48 + }
  49 + break
  50 + }
  51 + case ADDSTRING:
  52 + {
  53 + let doc = wps.WpsApplication().ActiveDocument
  54 + if (doc){
  55 + doc.Range(0, 0).Text="Hello, wps加载项!"
  56 + //好像是wps的bug, 这两句话触发wps重绘
  57 + let rgSel = wps.WpsApplication().Selection.Range
  58 + if (rgSel)
  59 + rgSel.Select()
  60 + }
  61 + break;
  62 + }
  63 + case GETDOCNAME:
  64 + {
  65 + let docName = wps.WpsApplication().ActiveDocument.Name
  66 + let newState = state.set('docName', docName)
  67 + return newState
  68 + }
  69 + case SETDEMOSPAN:
  70 + {
  71 + let newState = state.set('DemoSpan', action.data)
  72 + return newState
  73 + }
  74 + case OPENWEB:
  75 + {
  76 + let param = state.get('demoSpan')
  77 + wps.OAAssist.ShellExecute(param)
  78 + }
  79 + default:
  80 + }
  81 + return state;
  82 +}
\ No newline at end of file
... ...
注册登录 后发表评论