import pako from 'pako' import {showloading, hideloading} from '../assets/config/loading'; import {luckysheetrefreshgrid, jfrefreshgrid_rhcw} from '../global/refresh'; import editor from '../global/editor' import {sheetHTML, luckyColor} from './constant'; import sheetmanage from './sheetmanage'; import menuButton from './menuButton'; import {createFilterOptions} from './filter'; import luckysheetFreezen from './freezen'; import luckysheetPostil from './postil'; import imageCtrl from './imageCtrl'; import dataVerificationCtrl from './dataVerificationCtrl'; import hyperlinkCtrl from './hyperlinkCtrl'; import {getObjType, replaceHtml, getByteLen} from '../utils/util'; import {getSheetIndex} from '../methods/get'; import Store from '../store'; import {collaborativeEditBox} from './select' import locale from '../locale/locale'; import dayjs from "dayjs"; import json from '../global/json'; import luckysheetConfigsetting from './luckysheetConfigsetting'; import {customImageUpdate} from './imageUpdateCtrl'; import method from '../global/method'; import {getOnlineUser} from "./extFunction"; import { delayMessage } from '../assets/config/loading.js'; const server = { gridKey: null, loadUrl: null, updateUrl: null, updateImageUrl: null, title: null, loadSheetUrl: null, retryTimer: null, // 文档配置相关操作 docConfigApi:{ // 用户登录配置 loginConfig:{ // 开启登录校验 enable: false, // 提交表单,#{x} 替换内容 formData: { username: '#{username}', password: '#{password}', }, // 返回结果,tokenkey,将获取的值存储在缓存中 tokenKey: 'access_token', // 登录地址 loginUrl: '', // 获取用户信息 getUserDetail: '' }, // 获取在线用户 getOnlineUser:'', // 详情查询地址 documentDetailUrl:'', // 修改文档标题 updateDocNameUrl:'', // 详情查询地址 documentHistoryUrl: '', }, // 展示分享按钮 showShareFlag:true, allowUpdate: false, //共享编辑模式 historyParam: function (data, sheetIndex, range) { let _this = this; let r1 = range.row[0], r2 = range.row[1]; let c1 = range.column[0], c2 = range.column[1]; if (r1 == r2 && c1 == c2) { //单个单元格更新 let v = data[r1][c1]; _this.saveParam("v", sheetIndex, v, {"r": r1, "c": c1}); } else { //范围单元格更新 let rowlen = r2 - r1 + 1; let collen = c2 - c1 + 1; let timeR = Math.floor(1000 / collen); let n = Math.ceil(rowlen / timeR); //分批次更新,一次最多1000个单元格 for (let i = 0; i < n; i++) { let str = r1 + timeR * i; let edr; if (i == n - 1) { edr = r2; } else { edr = r1 + timeR * (i + 1) - 1; } let v = []; for (let r = str; r <= edr; r++) { let v_row = []; for (let c = c1; c <= c2; c++) { if (data[r] == null) { v_row.push(null); } else { v_row.push(data[r][c]); } } v.push(v_row); } _this.saveParam("rv", sheetIndex, v, {"range": {"row": [str, edr], "column": [c1, c2]}}); if (i == n - 1) { _this.saveParam("rv_end", sheetIndex, null); } } } }, saveParam: function (type, index, value, params) { let _this = this; if (!_this.allowUpdate) { return; } if (value == undefined) { value = null; } let d = {}; d.t = type; d.i = index; d.v = value; //切换sheet页不发后台,TODO:改为发后台+后台不广播 if (type === 'shs') { return; } if (type == "rv") { //单元格批量更新 d.range = params.range; } else if (type == "v" || type == "fu" || type == "fm") { d.r = params.r; d.c = params.c; } else if (type == "fc") { d.op = params.op; d.pos = params.pos; } else if (type == "drc" || type == "arc" || type == "h" || type == "wh") { d.rc = params.rc; } else if (type == "c") { d.cid = params.cid; d.op = params.op; } else if (type == "f") { d.op = params.op; d.pos = params.pos; } else if (type == "s") { } else if (type == "sh") { d.op = params.op; if (params.cur != null) { d.cur = params.cur; } } else if (type == "cg") { d.k = params.k; } else if (type == "all") { d.k = params.k; // d.s = params.s; } // TODO 配置自定义方式同步图片 const customImageUpdateMethodConfig = luckysheetConfigsetting.imageUpdateMethodConfig if (JSON.stringify(customImageUpdateMethodConfig) !== "{}") { if ("images" != d.k) { let msg = pako.gzip(encodeURIComponent(JSON.stringify(d)), {to: "string"}); if (_this.websocket != null) { _this.websocket.send(msg); } } else { customImageUpdate(customImageUpdateMethodConfig.method, customImageUpdateMethodConfig.url, d) .then((data) => { console.log(data); }) .catch((err) => { console.log(err); }); } } else { let msg = pako.gzip(encodeURIComponent(JSON.stringify(d)), {to: "string"}); if (_this.websocket != null) { _this.websocket.send(msg); } } }, websocket: null, wxErrorCount: 0, openWebSocket: function () { let _this = this; if ('WebSocket' in window) { let split = '?'; if (_this.updateUrl.indexOf('?') > -1) { split = '&'; } let wxUrl = _this.updateUrl + split + "t=111&g=" + encodeURIComponent(_this.gridKey);; _this.websocket = new WebSocket(wxUrl); //连接建立时触发 _this.websocket.onopen = function () { console.info(locale().websocket.success); hideloading(); _this.wxErrorCount = 0; //防止websocket长时间不发送消息导致断连 _this.retryTimer = setInterval(function () { _this.websocket.send("rub"); }, 60000); getOnlineUser(); } //客户端接收服务端数据时触发 _this.websocket.onmessage = function (result) { Store.result = result let data = new Function("return " + result.data)(); method.createHookFunction('cooperativeMessage', data) console.info(data); let type = data.type; let {message, id} = data; // 用户退出时,关闭协同编辑时其提示框 if (message === '用户退出') { $("#luckysheet-multipleRange-show-" + id).hide(); Store.cooperativeEdit.changeCollaborationSize = Store.cooperativeEdit.changeCollaborationSize.filter(value => { return value.id != id }) Store.cooperativeEdit.checkoutData = Store.cooperativeEdit.checkoutData.filter(value => { return value.id != id }) } delayMessage(data); if (type == 0 || type == 999) { // 用户退出或者登录 刷新在线用户 getOnlineUser(); } if (type == 1) { //send 成功或失败 if(data.data && data.data.v){ const oldIndex = data.data.v.index; const sheetToUpdate = Store.luckysheetfile.filter((sheet) => sheet.index === oldIndex)[0]; if (sheetToUpdate !== null) { setTimeout(() => { const index = data.data.i; sheetToUpdate.index = index; Store.currentSheetIndex = index; $(`#luckysheet-sheets-item${oldIndex}`).attr('data-index', index); $(`#luckysheet-sheets-item${oldIndex}`).prop('id', `luckysheet-sheets-item${index}`); $(`#luckysheet-datavisual-selection-set-${oldIndex}`).prop('id', `luckysheet-datavisual-selection-set-${index}`); }, 1); } } } else if (type == 2) { //更新数据 let item = JSON.parse(data.data); _this.wsUpdateMsg(item); let chang_data = JSON.parse(data.data) if (chang_data.k == 'columnlen') { collaborativeEditBox(chang_data.v, null) } else if (chang_data.k == 'rowlen') { collaborativeEditBox(null, chang_data.v) } } else if (type == 3) { //多人操作不同选区("t": "mv")(用不同颜色显示其他人所操作的选区) let id = data.id; let username = data.username; let item = JSON.parse(data.data); let type = item.t, index = item.i, value = item.v; if (Store.cooperativeEdit.changeCollaborationSize.length === 0) { Store.cooperativeEdit.changeCollaborationSize.push({id: id, v: item.v[0], i: index}) } let flag = Store.cooperativeEdit.changeCollaborationSize.some(value1 => { return value1.id == id }) if (flag) { Store.cooperativeEdit.changeCollaborationSize.forEach(val => { if (val.id == id) { val.v = item.v[0] || item.range[0] val.i = index } }) } else { Store.cooperativeEdit.changeCollaborationSize.push({id: id, v: item.v[0], i: index}) } if (getObjType(value) != "array" && getObjType(value) !== "object") { value = JSON.parse(value); } let r = 0 let c = 0 if (index == Store.currentSheetIndex) {//发送消息者在当前页面 if (getObjType(value) === "object" && value.op === 'enterEdit') { r = value.range[value.range.length - 1].row[0]; c = value.range[value.range.length - 1].column[0]; _this.multipleRangeShow(id, username, r, c, value.op); } else { r = value[value.length - 1].row[0]; c = value[value.length - 1].column[0]; _this.multipleRangeShow(id, username, r, c); } } else { if (getObjType(value) === "object" && value.op === 'enterEdit') { r = value.range[value.range.length - 1].row[0]; c = value.range[value.range.length - 1].column[0]; } else { r = value[value.length - 1].row[0]; c = value[value.length - 1].column[0]; } } if (Store.cooperativeEdit.checkoutData.length === 0) { if (value.op) { Store.cooperativeEdit.checkoutData.push({id, username, r, c, op: value.op, index}) } else { Store.cooperativeEdit.checkoutData.push({id, username, r, c, index}) } } let checkoutFlag = Store.cooperativeEdit.checkoutData.some(item => { return item.id == id }) if (checkoutFlag) { Store.cooperativeEdit.checkoutData.forEach(item => { if (item.id == id) { item.username = username item.r = r item.c = c item.index = index if (value.op === 'enterEdit') { item.op = value.op } } }) } else { if (value.op === 'enterEdit') { Store.cooperativeEdit.checkoutData.push({id, username, r, c, op: value.op, index}) } else { Store.cooperativeEdit.checkoutData.push({id, username, r, c, index}) } } //其他客户端切换页面时 Store.cooperativeEdit.checkoutData.forEach(item => { if (item.index != Store.currentSheetIndex) { $("#luckysheet-multipleRange-show-" + item.id).hide(); item.op == '' } }) if ($("#luckysheet-multipleRange-show-" + id)[0]) { let change_bottom = $("#luckysheet-multipleRange-show-" + id)[0].offsetHeight - 1 $("#luckysheet-multipleRange-show-" + id + ">.username").css({"bottom": change_bottom + 'px'}) } } else if (type == 4) { //批量指令更新 // let items = JSON.parse(data.data); // After editing by multiple people, data.data may appear as an empty string let items = data.data === "" ? data.data : JSON.parse(data.data); for (let i = 0; i < items.length; i++) { _this.wsUpdateMsg(item[i]); } } else if (type == 5) { showloading(data.data); } else if (type == 6) { hideloading(); } } //通信发生错误时触发 _this.websocket.onerror = function () { _this.wxErrorCount++; if (_this.wxErrorCount > 3) { showloading(locale().websocket.refresh); } else { showloading(locale().websocket.wait); _this.openWebSocket(); } getOnlineUser(); } //连接关闭时触发 _this.websocket.onclose = function (e) { console.info(locale().websocket.close); if (e.code === 1000) { clearInterval(_this.retryTimer) _this.retryTimer = null } else { alert(locale().websocket.contact); } getOnlineUser(); } } else { alert(locale().websocket.support); } }, wsUpdateMsg: function (item) { let type = item.t, index = item.i, value = item.v; let file = Store.luckysheetfile[getSheetIndex(index)]; if (["v", "rv", "cg", "all", "fc", "drc", "arc", "f", "fsc", "fsr", "sh", "c"].includes(type) && file == null) { return; } if (type == "v") { //单个单元格数据更新 if (file.data == null || file.data.length == 0) { return; } let r = item.r, c = item.c; file.data[r][c] = value; if (index == Store.currentSheetIndex) {//更新数据为当前表格数据 Store.flowdata = file.data; editor.webWorkerFlowDataCache(Store.flowdata);//worker存数据 //如果更新的单元格有批注 if (value != null && value.ps != null) { luckysheetPostil.buildPs(r, c, value.ps); } else { luckysheetPostil.buildPs(r, c, null); } setTimeout(function () { luckysheetrefreshgrid(); }, 1); } } else if (type == "rv") { //范围单元格数据更新 if (Object.keys(item.range).length > 0) { Store.cooperativeEdit.merge_range = item.range Store.cooperativeEdit.merge_range.v = item.v collaborativeEditBox(); } if (file.data == null || file.data.length == 0) { return; } let r1 = item.range.row[0], r2 = item.range.row[1]; let c1 = item.range.column[0], c2 = item.range.column[1]; for (let r = r1; r <= r2; r++) { for (let c = c1; c <= c2; c++) { file.data[r][c] = value[r - r1][c - c1]; } } if (index == Store.currentSheetIndex) {//更新数据为当前表格数据 Store.flowdata = file.data; editor.webWorkerFlowDataCache(Store.flowdata);//worker存数据 //如果更新的单元格有批注 for (let r = r1; r <= r2; r++) { for (let c = c1; c <= c2; c++) { if (value[r - r1][c - c1] != null && value[r - r1][c - c1].ps != null) { luckysheetPostil.buildPs(r, c, value[r - r1][c - c1].ps); } else { luckysheetPostil.buildPs(r, c, null); } } } setTimeout(function () { luckysheetrefreshgrid(); }, 1); } } else if (type == "cg") { //config更新(rowhidden,rowlen,columnlen,merge,borderInfo) let k = item.k; if (k == "borderInfo") { file["config"]["borderInfo"] = value; } else { if (!(k in file["config"])) { file["config"][k] = {}; } // for(let key in value){ // file["config"][k][key] = value[key]; // } // ⚠️ 上面的处理方式会导致部分配置项被遗漏,以致协同编辑的时候多视图出现不一致的情况,调整处理的策略为直接替换配置项: // 可能的配置项为: // columnlen: {0: 65, 1: 186, 2: 52} // customHeight: {0: 1, 5: 1, 6: 1} // customWidth: {0: 1, 1: 1, 2: 1} // merge: {2_1: {…}, 4_2: {…}, 6_2: {…}} // rowlen: {0: 19, 5: 93, 6: 117} if (value && (typeof value == "object")) { file["config"][k] = value; } } if (index == Store.currentSheetIndex) {//更新数据为当前表格数据 Store.config = file["config"]; if (k == "rowlen" || k == "columnlen" || k == "rowhidden") { jfrefreshgrid_rhcw(Store.flowdata.length, Store.flowdata[0].length); } setTimeout(function () { luckysheetrefreshgrid(); }, 1); } } else if (type == "all") { //通用保存更新 let k = item.k; file[k] = value; if (k == "name") { //工作表名 $("#luckysheet-sheet-container-c #luckysheet-sheets-item" + index).find("span.luckysheet-sheets-item-name").html(value); } else if (k == "color") { //工作表颜色 let currentSheetItem = $("#luckysheet-sheet-container-c #luckysheet-sheets-item" + index); currentSheetItem.find(".luckysheet-sheets-item-color").remove(); if (value != null || value != "") { currentSheetItem.append('<div class="luckysheet-sheets-item-color" style=" position: absolute; width: 100%; height: 3px; bottom: 0px; left: 0px; background-color: ' + value + ';"></div>'); } } else if (k == "pivotTable") { //PivotTable // luckysheet.pivotTable.changePivotTable(index); } else if (k == "frozen") { //freezen row and column // tranform frozen luckysheetFreezen.frozenTofreezen(); if (index == Store.currentSheetIndex) { const _locale = locale(); const locale_freezen = _locale.freezen; if (file["freezen"].horizontal == null) { $("#luckysheet-freezen-btn-horizontal").html('<i class="fa fa-list-alt"></i> ' + locale_freezen.freezenRow); luckysheetFreezen.freezenhorizontaldata = null; $("#luckysheet-freezebar-horizontal").hide(); } else { luckysheetFreezen.createFreezenHorizontal(file["freezen"].horizontal.freezenhorizontaldata, file["freezen"].horizontal.top); } if (file["freezen"].vertical == null) { $("#luckysheet-freezen-btn-vertical").html('<i class="fa fa-indent"></i> ' + locale_freezen.freezenColumn); luckysheetFreezen.freezenverticaldata = null; $("#luckysheet-freezebar-vertical").hide(); } else { luckysheetFreezen.createFreezenVertical(file["freezen"].vertical.freezenverticaldata, file["freezen"].vertical.left); } luckysheetFreezen.createAssistCanvas(); } } else if (k == "filter_select") { //筛选范围 if (index == Store.currentSheetIndex) { createFilterOptions(value); } } else if (k == "filter") { //筛选保存 if (index == Store.currentSheetIndex) { createFilterOptions(file.filter_select, value); } } else if (k == "luckysheet_conditionformat_save") { //条件格式 if (index == Store.currentSheetIndex) { setTimeout(function () { luckysheetrefreshgrid(); }, 1); } } else if (k == "luckysheet_alternateformat_save") { //交替颜色 if (index == Store.currentSheetIndex) { setTimeout(function () { luckysheetrefreshgrid(); }, 1); } } else if (k == "config") { //config if (index == Store.currentSheetIndex) { Store.config = value; jfrefreshgrid_rhcw(Store.flowdata.length, Store.flowdata[0].length); } } else if (k == "dynamicArray") { //动态数组 if (index == Store.currentSheetIndex) { setTimeout(function () { luckysheetrefreshgrid(); }, 1); } } else if (k == "images") { //图片 if (index == Store.currentSheetIndex) { imageCtrl.images = value; imageCtrl.allImagesShow(); imageCtrl.init(); } } else if (k == "dataVerification") { //数据验证 if (index == Store.currentSheetIndex) { dataVerificationCtrl.dataVerification = value; dataVerificationCtrl.init(); } } else if (k == "hyperlink") { //链接 if (index == Store.currentSheetIndex) { hyperlinkCtrl.hyperlink = value; hyperlinkCtrl.init(); } } } else if (type == "fc") { //函数链calc let op = item.op, pos = item.pos; if (getObjType(value) != "object") { value = new Function("return " + value)(); } let r = value.r, c = value.c; let calcChain = file["calcChain"] == null ? [] : file["calcChain"]; if (op == "add") { calcChain.push(value); } else if (op == "del") { for (let a = 0; a < calcChain.length; a++) { if (r == calcChain[a].r && c == calcChain[a].c && index == calcChain[a].index) { calcChain.splice(a, 1); } } } // else if(op == "update"){ // for(let a = 0; a < calcChain.length; a++){ // if(r == calcChain[a].r && c == calcChain[a].c && index == calcChain[a].index){ // calcChain[a].func = func; // } // } // } setTimeout(function () { luckysheetrefreshgrid(); }, 1); } else if (type == "drc") { //删除行列 if (file.data == null || file.data.length == 0) { return; } let rc = item.rc, st_i = value.index, len = value.len, mc = value.mc, borderInfo = value.borderInfo; let data = file.data; if (rc == "r") { file["row"] -= len; data.splice(st_i, len); //空白行模板 let row = []; for (let c = 0; c < data[0].length; c++) { row.push(null); } //删除多少行,增加多少行空白行 for (let r = 0; r < len; r++) { data.push(row); } } else { file["column"] -= len; //空白列模板 let addcol = []; for (let r = 0; r < len; r++) { addcol.push(null); } for (let i = 0; i < data.length; i++) { data[i].splice(st_i, len); data[i] = data[i].concat(addcol); } } for (let x in mc) { let r = mc[x].r, c = mc[x].c; data[r][c].mc = mc[x]; } file["config"].merge = mc; file["config"].borderInfo = borderInfo; if (index == Store.currentSheetIndex) { Store.flowdata = data; editor.webWorkerFlowDataCache(Store.flowdata);//worker存数据 Store.config["merge"] = mc; Store.config["borderInfo"] = borderInfo; setTimeout(function () { luckysheetrefreshgrid(); }, 1); } } else if (type == "arc") { //增加行列 if (file.data == null || file.data.length == 0) { return; } let rc = item.rc, st_i = value.index, len = value.len, addData = value.data, direction = value.direction, mc = value.mc, borderInfo = value.borderInfo; let data = $.extend(true, [], file.data); if (rc == "r") { file["row"] += len; //空行模板 let row = []; for (let c = 0; c < data[0].length; c++) { row.push(null); } let arr = []; for (let i = 0; i < len; i++) { if (addData[i] == null) { arr.push(JSON.stringify(row)); } else { arr.push(JSON.stringify(addData[i])); } } if (direction == "lefttop") { if (st_i == 0) { new Function("data", "return " + 'data.unshift(' + arr.join(",") + ')')(data); } else { new Function("data", "return " + 'data.splice(' + st_i + ', 0, ' + arr.join(",") + ')')(data); } } else { new Function("data", "return " + 'data.splice(' + (st_i + 1) + ', 0, ' + arr.join(",") + ')')(data); } } else { file["column"] += len; for (let i = 0; i < data.length; i++) { /* 在每一行的指定位置都插入一列 */ for (let j = 0; j < len; j++) { if (direction == "lefttop") { data[i].splice(st_i, 0, addData[j]); } else { data[i].splice(st_i + 1, 0, addData[j]); } } } } for (let x in mc) { let r = mc[x].r, c = mc[x].c; data[r][c].mc = mc[x]; } file.data = data; file["config"].merge = mc; file["config"].borderInfo = borderInfo; if (index == Store.currentSheetIndex) { Store.flowdata = data; editor.webWorkerFlowDataCache(Store.flowdata);//worker存数据 Store.config["merge"] = mc; Store.config["borderInfo"] = borderInfo; setTimeout(function () { luckysheetrefreshgrid(); }, 1); } } else if (type == "f") { //筛选 let op = item.op, pos = item.pos; let filter = file.filter; if (filter == null) { filter = {}; } if (op == "upOrAdd") { filter[pos] = value; } else if (op == "del") { delete filter[pos]; } if (index == Store.currentSheetIndex) { createFilterOptions(file.filter_select, filter); } } else if (type == "fsc") { //清除筛选 file.filter = null; file.filter_select = null; if (index == Store.currentSheetIndex) { $('#luckysheet-filter-selected-sheet' + Store.currentSheetIndex + ', #luckysheet-filter-options-sheet' + Store.currentSheetIndex).remove(); $("#luckysheet-filter-menu, #luckysheet-filter-submenu").hide(); } } else if (type == "fsr") { //恢复筛选 file.filter = value.filter; file.filter_select = value.filter_select; if (index == Store.currentSheetIndex) { createFilterOptions(file.filter_select, file.filter); } } else if (type == "sha") { //新建sheet Store.luckysheetfile.push(value); let colorset = ''; if (value.color != null) { colorset = '<div class="luckysheet-sheets-item-color" style=" position: absolute; width: 100%; height: 3px; bottom: 0px; left: 0px; background-color: ' + value.color + ';"></div>'; } $("#luckysheet-sheet-container-c").append(replaceHtml(sheetHTML, { "index": value.index, "active": "", "name": value.name, "style": "", "colorset": colorset })); $("#luckysheet-cell-main").append('<div id="luckysheet-datavisual-selection-set-' + value.index + '" class="luckysheet-datavisual-selection-set"></div>'); // *添加sheet之后,要判断是否需要显示sheet滚动按钮 sheetmanage.locationSheet() } else if (type == "shc") { //复制sheet let copyindex = value.copyindex, name = value.name; let copyarrindex = getSheetIndex(copyindex); let copyjson = $.extend(true, {}, Store.luckysheetfile[copyarrindex]); copyjson.index = index; copyjson.name = name; Store.luckysheetfile.splice(copyarrindex + 1, 0, copyjson); let copyobject = $("#luckysheet-sheets-item" + copyindex); $("#luckysheet-sheet-container-c").append(replaceHtml(sheetHTML, { "index": copyjson.index, "active": "", "name": copyjson.name, "style": "", "colorset": "" })); $("#luckysheet-sheets-item" + copyjson.index).insertAfter(copyobject); $("#luckysheet-cell-main").append('<div id="luckysheet-datavisual-selection-set-' + copyjson.index + '" class="luckysheet-datavisual-selection-set"></div>'); } else if (type == "shd") { //删除sheet for (let i = 0; i < Store.luckysheetfile.length; i++) { if (Store.luckysheetfile[i].index == value.deleIndex) { // 如果删除的是当前sheet,则切换到前一个sheet页 if (Store.currentSheetIndex === value.deleIndex) { const index = value.deleIndex; Store.luckysheetfile[sheetmanage.getSheetIndex(index)].hide = 1; let luckysheetcurrentSheetitem = $("#luckysheet-sheets-item" + index); luckysheetcurrentSheetitem.hide(); $("#luckysheet-sheet-area div.luckysheet-sheets-item").removeClass("luckysheet-sheets-item-active"); let indicator = luckysheetcurrentSheetitem.nextAll(":visible"); if (luckysheetcurrentSheetitem.nextAll(":visible").length > 0) { indicator = indicator.eq(0).data("index"); } else { indicator = luckysheetcurrentSheetitem.prevAll(":visible").eq(0).data("index"); } $("#luckysheet-sheets-item" + indicator).addClass("luckysheet-sheets-item-active"); sheetmanage.changeSheetExec(indicator); } server.sheetDeleSave.push(Store.luckysheetfile[i]); Store.luckysheetfile.splice(i, 1); break; } } $("#luckysheet-sheets-item" + value.deleIndex).remove(); $("#luckysheet-datavisual-selection-set-" + value.deleIndex).remove(); sheetmanage.locationSheet() } else if (type == "shr") { //sheet位置 for (let x in value) { Store.luckysheetfile[getSheetIndex(x)].order = value[x]; } } else if (type == "shre") { //删除sheet恢复操作 for (let i = 0; i < server.sheetDeleSave.length; i++) { if (server.sheetDeleSave[i].index == value.reIndex) { let datav = server.sheetDeleSave[i]; Store.luckysheetfile.push(datav); let colorset = ''; if (value.color != null) { colorset = '<div class="luckysheet-sheets-item-color" style=" position: absolute; width: 100%; height: 3px; bottom: 0px; left: 0px; background-color: ' + datav.color + ';"></div>'; } $("#luckysheet-sheet-container-c").append(replaceHtml(sheetHTML, { "index": datav.index, "active": "", "name": datav.name, "style": "", "colorset": colorset })); $("#luckysheet-cell-main").append('<div id="luckysheet-datavisual-selection-set-' + datav.index + '" class="luckysheet-datavisual-selection-set"></div>'); break; } } } else if (type == "sh") { //隐藏sheet let op = item.op, cur = item.cur; if (op == "hide") { file.hide = 1; $("#luckysheet-sheets-item" + index).hide(); if (index == Store.currentSheetIndex) { $("#luckysheet-sheets-item" + cur).addClass("luckysheet-sheets-item-active"); sheetmanage.changeSheetExec(cur); } } else if (op == "show") { file.hide = 0; $("#luckysheet-sheets-item" + index).show(); } sheetmanage.locationSheet() } else if (type == "c") { //图表操作 TODO let op = item.op, cid = item.cid; if (op == "add") { //插入 file.chart.push(value); luckysheet.insertChartTosheet(value.sheetIndex, value.dataSheetIndex, value.option, value.chartType, value.selfOption, value.defaultOption, value.row, value.column, value.chart_selection_color, value.chart_id, value.chart_selection_id, value.chartStyle, value.rangeConfigCheck, value.rangeRowCheck, value.rangeColCheck, value.chartMarkConfig, value.chartTitleConfig, value.winWidth, value.winHeight, value.scrollLeft1, value.scrollTop1, value.chartTheme, value.myWidth, value.myHeight, value.myLeft, value.myTop, value.myindexrank1, true); } else if (op == "xy" || op == "wh" || op == "update") { //移动 缩放 更新 for (let i = 0; i < file.chart.length; i++) { let chartjson = file.chart[i]; if (chartjson.chart_id == cid) { for (let item in chartjson) { for (let vitem in value) { if (item == vitem) { chartjson[item] = value[vitem]; } } } sheetmanage.saveChart(chartjson); return; } } } else if (op == "del") { //删除 for (let i = 0; i < file.chart.length; i++) { let chartjson = file.chart[i]; if (chartjson.chart_id == cid) { file.chart.splice(i, 1); $("#" + cid).remove(); sheetmanage.delChart($("#" + cid).attr("chart_id"), $("#" + cid).attr("sheetIndex")); return; } } } } else if (type == "na") { //表格名称 $("#luckysheet_info_detail_input").val(value).css("width", getByteLen(value) * 10); } }, multipleIndex: 0, multipleRangeShow: function (id, name, r, c, value) { let _this = this; const fullName = name; let row = Store.visibledatarow[r], row_pre = r - 1 == -1 ? 0 : Store.visibledatarow[r - 1], col = Store.visibledatacolumn[c], col_pre = c - 1 == -1 ? 0 : Store.visibledatacolumn[c - 1]; let margeset = menuButton.mergeborer(Store.flowdata, r, c); if (!!margeset) { row = margeset.row[1]; row_pre = margeset.row[0]; col = margeset.column[1]; col_pre = margeset.column[0]; } // *处理光标在靠左或者靠上顶着的时候,光标显示不全的问题 if (col_pre <= 0) { col_pre += 1 } if (row_pre <= 0) { row_pre += 1 } // 超出16个字符就显示... if (getByteLen(name) > 16) { name = getByteLen(name, 16) + "..."; } // 如果正在编辑,就显示“正在输入” if (value === 'enterEdit') { name += " " + locale().edit.typing; } if ($("#luckysheet-multipleRange-show-" + id).length > 0) { $("#luckysheet-multipleRange-show-" + id).css({ "position": "absolute", "left": col_pre - 1, "width": col - col_pre - 1, "top": row_pre - 1, "height": row - row_pre - 1 }); $("#luckysheet-multipleRange-show-" + id + " .username").text(name); $("#luckysheet-multipleRange-show-" + id + " .username").show(); if (Store.cooperativeEdit.usernameTimeout['user' + id] != null) { clearTimeout(Store.cooperativeEdit.usernameTimeout['user' + id]) } Store.cooperativeEdit.usernameTimeout['user' + id] = setTimeout(() => { clearTimeout(Store.cooperativeEdit.usernameTimeout['user' + id]); Store.cooperativeEdit.usernameTimeout['user' + id] = null; }, 10 * 1000) } else { // let itemHtml = '<div id="luckysheet-multipleRange-show-'+ id +'" data-color="'+ luckyColor[_this.multipleIndex] +'" title="'+ name +'" style="position: absolute;left: '+ (col_pre - 1) +'px;width: '+ (col - col_pre - 1) +'px;top: '+ (row_pre - 1) +'px;height: '+ (row - row_pre - 1) +'px;border: 1px solid '+ luckyColor[_this.multipleIndex] +';z-index: 15;">'+ // '<div style="width: 100%;height: 100%;position: absolute;top: 0;right: 0;bottom: 0;left: 0;opacity: 0.03;background-color: '+ luckyColor[_this.multipleIndex] +'"></div>'+ // '</div>'; let itemHtml = `<div id="luckysheet-multipleRange-show-${id}" class="luckysheet-multipleRange-show" data-color="${luckyColor[_this.multipleIndex]}" title="${fullName}" style="position: absolute;left: ${col_pre - 1}px;width: ${col - col_pre - 1}px;top: ${row_pre - 1}px;height: ${row - row_pre - 1}px;border: 1px solid ${luckyColor[_this.multipleIndex]};z-index: 15;"> <div class="username" style="height: 19px;line-height:19px;width: max-content;position: absolute;bottom: ${row - row_pre - 1}px;right: 0;background-color: ${luckyColor[_this.multipleIndex]};color:#ffffff;padding:0 10px;"> ${name} </div> <div style="width: 100%;height: 100%;position: absolute;top: 0;right: 0;bottom: 0;left: 0;opacity: 0.03;background-color: ${luckyColor[_this.multipleIndex]}"> </div> </div>`; // 正在输入 $(itemHtml).appendTo($("#luckysheet-cell-main #luckysheet-multipleRange-show")); _this.multipleIndex++; // 设定允许用户名消失的定时器,10秒后用户名可隐藏 // 10秒之类,用户操作界面不会隐藏用户名;10秒之后如果用户操作了界面,则隐藏用户名,没操作就不隐藏 if (Store.cooperativeEdit.usernameTimeout['user' + id] != null) { clearTimeout(Store.cooperativeEdit.usernameTimeout['user' + id]) } Store.cooperativeEdit.usernameTimeout['user' + id] = setTimeout(() => { clearTimeout(Store.cooperativeEdit.usernameTimeout['user' + id]); Store.cooperativeEdit.usernameTimeout['user' + id] = null; }, 10 * 1000) } }, sheetDeleSave: [], //共享编辑模式下 删除的sheet保存下来,方便恢复时取值 submitInterval: 1000, imagesubmitInterval: 5000, submitdatalimit: 50, submitcompresslimit: 1000, checksubmit: function (data) { let _this = this; //clearTimeout(_this.requestTimeOut); _this.submitTimeout(); clearTimeout(_this.imageRequestTimeout); _this.imageRequestTimeout = setTimeout(function () { _this.imageRequest(); }, _this.imagesubmitInterval); }, submitTimeout: function () { let _this = this; clearTimeout(_this.requestTimeOut); //console.log(_this.requestlast, dayjs(), (_this.requestlast!=null && _this.requestlast.add(10, 'seconds').isBefore(dayjs()) ) ); if (!_this.requestLock && (_this.requestlast != null && _this.requestlast.clone().add(1, 'seconds').isBefore(dayjs()))) { _this.request(); } // if(!_this.imageRequestLock && (_this.imageRequestLast==null || _this.imageRequestLast.clone().add(30, 'seconds').isBefore(dayjs()) ) ){ // } _this.requestTimeOut = setTimeout(function () { _this.submitTimeout(); }, _this.submitInterval); }, requestLock: false, requestlast: null, firstchange: true, requestTimeOut: null, request: function () { let _this = this; let key = this.gridKey; let cahce_key = key + "__qkcache"; _this.cachelocaldata(function (cahce_key, params) { if (params.length == 0) { return; } params = encodeURIComponent(JSON.stringify(params)); let compressBeginLen = params.length; let iscommpress = false; // if (compressBeginLen > _this.submitcompresslimit) { // params = pako.gzip(params, { to: "string" }); // iscommpress = true; // } _this.requestLock = true; //console.log(params); // console.log("request"); if (_this.updateUrl != "") { $.post(_this.updateUrl, {compress: iscommpress, gridKey: _this.gridKey, data: params}, function (data) { let re = new Function("return " + data)(); if (re.status) { $("#luckysheet_info_detail_update").html("最近存档时间:" + dayjs().format("M-D H:m:s")); $("#luckysheet_info_detail_save").html("同步成功"); _this.clearcachelocaldata(); } else { $("#luckysheet_info_detail_save").html("<span style='color:#ff2121'>同步失败</span>"); _this.restorecachelocaldata(); } _this.requestlast = dayjs(); _this.requestLock = false; }); } }); }, imageRequestLast: null, imageRequestLock: false, imageRequestTimeout: null, imageRequest: function () { let _this = this; html2canvas($("#" + container).find(".luckysheet-grid-window").get(0), { onrendered: function (canvas) { //let imgcut = $("#luckysheet-cell-main").find(".luckysheet-grid-window"); //document.body.appendChild(canvas); let old = $(canvas).appendTo("body"); old.hide(); let newwidth = old.width(); let newheight = old.height(); let imageData = old.get(0).getContext("2d").getImageData(0, 0, newwidth, newheight); let cutW = newwidth, cutH = newheight; if (cutW * 0.54 > cutH) { cutW = cutH / 0.54; } else { cutH = cutW * 0.54; } let newCanvas = $("<canvas>").attr("width", cutW).attr("height", cutH)[0]; newCanvas.getContext("2d").putImageData(imageData, 0, 0); old.attr("width", 350); old.attr("height", 189); old.get(0).getContext("2d").drawImage(newCanvas, 0, 0, 350, 189); let base64 = old.get(0).toDataURL('image/jpeg', 0.9); //console.log(base64); //console.log("压缩:", pako.gzip(base64, { to: "string" })); //console.log("imageRequest"); let curindex = luckysheet.sheetmanage.getCurSheetnoset(); _this.imageRequestLock = true; // let data1 = pako.gzip(encodeURIComponent(JSON.stringify({"t":"thumb", "img": base64, "curindex":curindex })), { to: "string" }); let data1 = encodeURIComponent(JSON.stringify({"t": "thumb", "img": base64, "curindex": curindex})); old.remove(); //console.log("缩略图", _this.imageRequestLast,base64); if (_this.updateImageUrl != "") { // $.post(_this.updateImageUrl, { compress: true, gridKey: _this.gridKey, data:data1 }, function (data) { $.post(_this.updateImageUrl, { compress: false, gridKey: _this.gridKey, data: data1 }, function (data) { let re = new Function("return " + data)(); if (re.status) { imageRequestLast = dayjs(); } else { $("#luckysheet_info_detail_save").html("<span style='color:#ff2121'>网络不稳定</span>"); } _this.imageRequestLock = true; }); } } }); }, localdata: [], matchOpt: function (v, d) { for (let vitem in v) { if (vitem == "t" && v["t"] in {"drc": 1, "arc": 1, "sha": 1, "shc": 1, "shd": 1}) { return false; } if (vitem == "v") { continue; } if (!(vitem in d)) { return false; } if (d[vitem] != v[vitem]) { return false; } } return true; }, deleteRepeatOpt: function (data, value) { //let d = $.extend(true, [], data); //原来 let d = data; let _this = this; if (value instanceof Array) { for (let i = 0; i < value.length; i++) { let vitem = value[i]; for (let a = 0; a < d.length; a++) { let ditem = data[i]; //let ditem = data[a];? if (_this.matchOpt(vitem, ditem)) { delete d[a]; } } } } else { for (let a = 0; a < d.length; a++) { let ditem = d[a]; if (_this.matchOpt(value, ditem)) { delete d[a]; } } } let ret = []; for (let i = 0; i < d.length; i++) { if (d[i] != null) { ret.push(d[i]); } } return ret; }, setlocaldata: function (value, func) { let key = this.gridKey; //store.push(key, data); let _this = this; _this.getlocaldata(function (data) { if (data == null) { data = []; } //此处不去重,在request同步后台时统一循环一次去重 //let data = _this.deleteRepeatOpt(data, value); if (value instanceof Array) { data = data.concat(value); } else { data.push(value); } _this.localdata = data; func(_this.localdata); //console.log(value); // localforage.setItem(key, data).then(function () { // console.log(data); // func(data); // }).catch(function (err) { // }); }); }, getlocaldata: function (func) { let key = this.gridKey; //return store.get(key); func(this.localdata); // localforage.getItem(key).then(function(readValue) { // func(readValue); // }); }, clearlocaldata: function (func) { let key = this.gridKey; //store.remove(key); this.localdata = []; func(); // localforage.removeItem(key, function(err,value) { // func(); // }); }, cachelocaldata: function (func) { let key = this.gridKey; let _this = this; let cahce_key = key + "__qkcache"; //store.remove(key); //console.log(key, cahce_key); //处理localdata去重 let updatedata = _this.localdata; let uLen = updatedata.length; if (uLen > 1) { let prevData = []; prevData[0] = updatedata[0]; for (let i = 1; i < uLen; i++) { let value = updatedata[i]; let flag = true; for (let a = 0; a < prevData.length; a++) { let ditem = prevData[a]; if (_this.matchOpt(value, ditem)) { prevData.splice(a, 1, value); flag = false; //如果已匹配重复,则后续无需再加 break; } } if (flag) { prevData = prevData.concat(value); } } updatedata = prevData; } if (updatedata == null || updatedata.length == 0) { return; } //console.log(key, cahce_key,updatedata); _this.clearlocaldata(function () { localforage.setItem(cahce_key, updatedata).then(function () { func(cahce_key, updatedata); }); }); // localforage.getItem(key).then(function(readValue) { // let updatedata = readValue; // if(readValue==null || readValue.length==0){ // return; // } // //console.log(key, cahce_key,updatedata); // _this.clearlocaldata(function(){ // localforage.setItem(cahce_key, updatedata).then(function () { // func(cahce_key, updatedata); // }); // }); // }); }, clearcachelocaldata: function (func) { let key = this.gridKey; let cahce_key = key + "__qkcache"; //store.remove(key); localforage.removeItem(cahce_key, function (err, value) { if (func && typeof (func) == "function") { func(); } }); }, restorecachelocaldata: function (func) { let key = this.gridKey; let cahce_key = key + "__qkcache"; let _this = this; localforage.getItem(cahce_key).then(function (readValue) { let updatedata = readValue; _this.getlocaldata(function (data) { if (data == null) { data = []; } let newdata = updatedata.concat(data); //data.unshift(updatedata); _this.localdata = newdata; if (func instanceof Function) { func(_this.localdata); } // localforage.setItem(key, newdata).then(function () { // func(newdata); // }).catch(function (err) { // }); }); }); }, keepHighLightBox: function () { Store.cooperativeEdit.checkoutData.forEach(value => { if (value.index == Store.currentSheetIndex) { if (value.op === 'enterEdit') { server.multipleRangeShow(value.id, value.username, value.r, value.c, value.op); } else { server.multipleRangeShow(value.id, value.username, value.r, value.c); } } }) } } export default server;