From f1818ada5022d1f32eedade9e186c9f670b45619 Mon Sep 17 00:00:00 2001 From: cdswyda Date: Tue, 9 Nov 2021 18:54:06 +0800 Subject: [PATCH 1/7] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E5=8D=95=E7=8B=AC=E4=B8=8A=E4=BC=A0=EF=BC=8C=E5=8F=AA?= =?UTF-8?q?=E5=9C=A8=E6=95=B0=E6=8D=AE=E4=B8=AD=E7=95=99=E5=9C=B0=E5=9D=80?= =?UTF-8?q?=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controllers/handler.js | 24 +++--------------------- src/controllers/imageCtrl.js | 25 ++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/controllers/handler.js b/src/controllers/handler.js index d98c7ab..ae345a4 100644 --- a/src/controllers/handler.js +++ b/src/controllers/handler.js @@ -1476,13 +1476,7 @@ export default function luckysheetHandler() { if(!checkProtectionAuthorityNormal(Store.currentSheetIndex, "editObjects")){ return; } - let render = new FileReader(); - render.readAsDataURL(files[0]); - - render.onload = function(event){ - let src = event.target.result; - imageCtrl.inserImg(src); - } + imageCtrl.insertImg(files[0]); } handleCellDragStopEvent(e); }, false); @@ -4886,14 +4880,7 @@ export default function luckysheetHandler() { return; } let file = e.currentTarget.files[0]; - let render = new FileReader(); - render.readAsDataURL(file); - - render.onload = function(event){ - let src = event.target.result; - imageCtrl.inserImg(src); - $("#luckysheet-imgUpload").val(""); - } + imageCtrl.insertImg(file); }); //菜单栏 插入链接按钮 @@ -5620,12 +5607,7 @@ export default function luckysheetHandler() { } //复制的是图片 else if(clipboardData.files.length == 1 && clipboardData.files[0].type.indexOf('image') > -1){ - let render = new FileReader(); - render.readAsDataURL(clipboardData.files[0]); - render.onload = function(event){ - let src = event.target.result; - imageCtrl.inserImg(src); - } + imageCtrl.insertImg(clipboardData.files[0]); return; } diff --git a/src/controllers/imageCtrl.js b/src/controllers/imageCtrl.js index 949c13e..ce0df59 100644 --- a/src/controllers/imageCtrl.js +++ b/src/controllers/imageCtrl.js @@ -8,6 +8,7 @@ import { setluckysheet_scroll_status } from '../methods/set'; import { replaceHtml } from '../utils/util'; import Store from '../store'; import locale from '../locale/locale'; +import tooltip from '../global/tooltip'; const imageCtrl = { imgItem: { @@ -49,7 +50,29 @@ const imageCtrl = { cropChangeXY: null, cropChangeObj: null, copyImgItemObj: null, - inserImg: function(src){ + insertImg: function (file) { + const uploadImage = Store.toJsonOptions && Store.toJsonOptions['uploadImage']; + if (typeof uploadImage === 'function') { + // 上传形式 + uploadImage(file).then(url => { + imageCtrl._insertImg(url); + }).catch(error => { + tooltip.info('', '图片上传失败'); + }); + } else { + // 内部base64形式 + let render = new FileReader(); + render.readAsDataURL(file); + + render.onload = function(event){ + let src = event.target.result; + imageCtrl._insertImg(src); + $("#luckysheet-imgUpload").val(""); + } + } + }, + + _insertImg: function(src){ let _this = this; let last = Store.luckysheet_select_save[Store.luckysheet_select_save.length - 1]; From d830c151e4b245e8f8043590bfec2b38cb393c00 Mon Sep 17 00:00:00 2001 From: cdswyda Date: Wed, 10 Nov 2021 10:39:08 +0800 Subject: [PATCH 2/7] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E8=B7=AF=E5=BE=84=E5=A4=84=E7=90=86=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 图片上传返回获取地址,不应将图片的协议、域名等信息可能不能写入数据中。 --- src/controllers/imageCtrl.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/controllers/imageCtrl.js b/src/controllers/imageCtrl.js index ce0df59..6fcb720 100644 --- a/src/controllers/imageCtrl.js +++ b/src/controllers/imageCtrl.js @@ -118,7 +118,8 @@ const imageCtrl = { modelHtml: function(id, imgItem) { let _this = this; - let src = imgItem.src; + let imgUrlHandle = Store.toJsonOptions && Store.toJsonOptions['imgUrlHandle']; + let src = typeof imgUrlHandle === 'function' ? imgUrlHandle(imgItem.src) : imgItem.src; let imgItemParam = _this.getImgItemParam(imgItem); let width = imgItemParam.width * Store.zoomRatio; @@ -391,9 +392,10 @@ const imageCtrl = { "top": top, "position": position }); - + let imgUrlHandle = Store.toJsonOptions && Store.toJsonOptions['imgUrlHandle']; + let imgUrl = typeof imgUrlHandle === 'function' ? imgUrlHandle(item.src) : item.src; $("#luckysheet-modal-dialog-activeImage .luckysheet-modal-dialog-content").css({ - "background-image": "url(" + item.src + ")", + "background-image": "url(" + imgUrl + ")", "background-size": item.default.width * Store.zoomRatio + "px " + item.default.height * Store.zoomRatio + "px", "background-position": -item.crop.offsetLeft * Store.zoomRatio + "px " + -item.crop.offsetTop * Store.zoomRatio + "px" }) From 8682011c33f6459e346ae1ad17048d2b81a00a44 Mon Sep 17 00:00:00 2001 From: cdswyda Date: Wed, 10 Nov 2021 10:45:50 +0800 Subject: [PATCH 3/7] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E5=88=A0=E9=99=A4=E9=92=A9=E5=AD=90=20imageDeleteBefo?= =?UTF-8?q?re=20imageDeleteAfter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 可用于清理单独上传的图片附件 --- src/controllers/imageCtrl.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/controllers/imageCtrl.js b/src/controllers/imageCtrl.js index 6fcb720..97841ec 100644 --- a/src/controllers/imageCtrl.js +++ b/src/controllers/imageCtrl.js @@ -9,6 +9,7 @@ import { replaceHtml } from '../utils/util'; import Store from '../store'; import locale from '../locale/locale'; import tooltip from '../global/tooltip'; +import method from '../global/method'; const imageCtrl = { imgItem: { @@ -877,15 +878,24 @@ const imageCtrl = { }, removeImgItem: function() { let _this = this; + let imgItem = _this.images[_this.currentImgId]; + + // 钩子 imageDeleteBefore + if(!method.createHookFunction('imageDeleteBefore', imgItem)){ + return; + } $("#luckysheet-modal-dialog-activeImage").hide(); $("#luckysheet-modal-dialog-cropping").hide(); $("#luckysheet-modal-dialog-slider-imageCtrl").hide(); $("#" + _this.currentImgId).remove(); + delete _this.images[_this.currentImgId]; _this.currentImgId = null; + // 钩子 imageDeleteAfter + method.createHookFunction('imageDeleteAfter', imgItem); _this.ref(); }, copyImgItem: function(e) { From f9e383c193aee1a9a3215e5cf52075691bd91a9f Mon Sep 17 00:00:00 2001 From: cdswyda Date: Wed, 10 Nov 2021 10:48:38 +0800 Subject: [PATCH 4/7] =?UTF-8?q?fix:=20=E7=BB=9F=E4=B8=80=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controllers/imageCtrl.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/controllers/imageCtrl.js b/src/controllers/imageCtrl.js index 97841ec..7e5ddde 100644 --- a/src/controllers/imageCtrl.js +++ b/src/controllers/imageCtrl.js @@ -119,8 +119,8 @@ const imageCtrl = { modelHtml: function(id, imgItem) { let _this = this; - let imgUrlHandle = Store.toJsonOptions && Store.toJsonOptions['imgUrlHandle']; - let src = typeof imgUrlHandle === 'function' ? imgUrlHandle(imgItem.src) : imgItem.src; + let imageUrlHandle = Store.toJsonOptions && Store.toJsonOptions['imageUrlHandle']; + let src = typeof imageUrlHandle === 'function' ? imageUrlHandle(imgItem.src) : imgItem.src; let imgItemParam = _this.getImgItemParam(imgItem); let width = imgItemParam.width * Store.zoomRatio; @@ -393,8 +393,8 @@ const imageCtrl = { "top": top, "position": position }); - let imgUrlHandle = Store.toJsonOptions && Store.toJsonOptions['imgUrlHandle']; - let imgUrl = typeof imgUrlHandle === 'function' ? imgUrlHandle(item.src) : item.src; + let imageUrlHandle = Store.toJsonOptions && Store.toJsonOptions['imageUrlHandle']; + let imgUrl = typeof imageUrlHandle === 'function' ? imageUrlHandle(item.src) : item.src; $("#luckysheet-modal-dialog-activeImage .luckysheet-modal-dialog-content").css({ "background-image": "url(" + imgUrl + ")", "background-size": item.default.width * Store.zoomRatio + "px " + item.default.height * Store.zoomRatio + "px", From 0eb38b98b47a8cb92455f8f206c0fac93df723b3 Mon Sep 17 00:00:00 2001 From: cdswyda Date: Wed, 10 Nov 2021 11:08:31 +0800 Subject: [PATCH 5/7] =?UTF-8?q?docs:=20=E8=A1=A5=E5=85=85=E6=96=87?= =?UTF-8?q?=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/zh/guide/config.md | 102 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/docs/zh/guide/config.md b/docs/zh/guide/config.md index 029e88d..d770967 100644 --- a/docs/zh/guide/config.md +++ b/docs/zh/guide/config.md @@ -78,6 +78,8 @@ Luckysheet开放了更细致的自定义配置选项,分别有 - 是否限制工作表名长度 [limitSheetNameLength](#limitSheetNameLength) - 默认允许工作表名的最大长度 [defaultSheetNameMaxLength](#defaultSheetNameMaxLength) - 分页器 [pager](#pager) +- 自定义图片上传 [uploadImage](#uploadImage) +- 自定义图片地址处理 [imageUrlHandle](#imageUrlHandle) ### container - 类型:String @@ -714,6 +716,79 @@ Luckysheet开放了更细致的自定义配置选项,分别有 } ``` +### uploadImage + +用于自定义图片的上传,默认情况下,插入的图片是以base64的形式放入sheet数据中,如果需要单独上传图片,仅在sheet中引用图片地址可使用此配置。 + +- 类型: `function (file) => Promise(imgUrl)`,接受file对象,返回Promise,值为上传完成的图片url +- 默认值: `undefined` + +:::deatil 查看示例配置 + +```js +{ + uploadImage: function (file) { + return new Promise(function (resolve, reject) { + var xhr = new XMLHttpRequest(); + xhr.open('POST', 'http://192.168.210.159/miniuiServer/imageUploader.php'); + + // 额外的请求头 + var headers = {}; + if (headers) { + Object.keys(headers).forEach(function (k) { + xhr.setRequestHeader(k, headers[k]); + }); + } + var data = new FormData(); + // 要上传的图片文件 + data.append('file', file, file.name || ''); + + xhr.send(data); + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + if (xhr.status === 200) { + var res = JSON.parse(xhr.responseText); + var url = res.downloadUrl; + if (url) { + resolve(url); // 给上传的后的地址 + } else { + reject('image upload error'); + } + } else { + reject('image upload error'); + } + } + }; + }); + } +} + +``` + +::: + +### imageUrlHandle + +图片上传的路径处理函数,和 [uploadImage](#uploadImage) 相关,一般只有使用自定义图片上传才需要此配置。 + +- 类型: `function (string) => string`,接受原始路径,返回新路径 +- 默认值: `undefined` +- 作用,处理图片显示时的路径。 + 如上传返回地址为接口地址,如: `rest/attach/[fileguid]`, 则需要处理为 `http://localhost:8080/xxx/rest/attach/[fileguid]` 才能显示,但将前面域名信息写入数据,后续使用可能会有问题,因此可使用此方法处理路径,全路径仅在展示使用,数据内仅存储 `rest/attach/[fileguid]` + +```js +{ + // 处理上传图片的地址 + imageUrlHandle: function (url) { + // 已经是 // http data 开头则不处理 + if (/^(?:\/\/|(?:http|https|data):)/i.test(url)) { + return url; + } + return location.origin + url; + } +} +``` + ------------ ## 钩子函数 @@ -1461,6 +1536,33 @@ Luckysheet开放了更细致的自定义配置选项,分别有 - 作用:工作表从活动状态转为非活动状态后 - 参数: - {Number} [i]: sheet页的`index` + +### imageDeleteBefore + +- 类型:Function +- 默认值:null +- 作用:图片删除前触发 +- 参数: + - {Object} [imageItem]: 要删除的图片配置对象 + +### imageDeleteAfter + +- 类型:Function +- 默认值:null +- 作用:图片删除后触发,如果自定义了图片上传,可在此处发请求删除图片 +- 参数: + - {Object} [imageItem]: 删除的图片配置对象 + +```js +{ + hook: { + imageDeleteAfter: function (imageItem) { + var src = imgItem.src; + $.post('/rest/file/deletebyurl', {downloadUrl: src}); + } + } +} +``` ------------ From 374d0b9d4aa178aaa3aa5d93ffa483894d8b90a3 Mon Sep 17 00:00:00 2001 From: cdswyda Date: Wed, 10 Nov 2021 11:12:50 +0800 Subject: [PATCH 6/7] =?UTF-8?q?docs:=20=E4=BF=AE=E5=A4=8D=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/zh/guide/config.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/zh/guide/config.md b/docs/zh/guide/config.md index d770967..97ad353 100644 --- a/docs/zh/guide/config.md +++ b/docs/zh/guide/config.md @@ -723,7 +723,7 @@ Luckysheet开放了更细致的自定义配置选项,分别有 - 类型: `function (file) => Promise(imgUrl)`,接受file对象,返回Promise,值为上传完成的图片url - 默认值: `undefined` -:::deatil 查看示例配置 +:::details 查看示例配置 ```js { @@ -773,7 +773,7 @@ Luckysheet开放了更细致的自定义配置选项,分别有 - 类型: `function (string) => string`,接受原始路径,返回新路径 - 默认值: `undefined` -- 作用,处理图片显示时的路径。 +- 作用,处理图片显示时的路径。 如上传返回地址为接口地址,如: `rest/attach/[fileguid]`, 则需要处理为 `http://localhost:8080/xxx/rest/attach/[fileguid]` 才能显示,但将前面域名信息写入数据,后续使用可能会有问题,因此可使用此方法处理路径,全路径仅在展示使用,数据内仅存储 `rest/attach/[fileguid]` ```js From 4b57f95208490a9749ce1316f0e281173844aa2d Mon Sep 17 00:00:00 2001 From: cdswyda Date: Wed, 10 Nov 2021 15:59:47 +0800 Subject: [PATCH 7/7] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E5=9C=A8=E8=A3=81=E5=89=AA=E7=AD=89=E6=83=85=E5=86=B5=E4=B8=8B?= =?UTF-8?q?=E7=9A=84=E5=8A=A0=E8=BD=BD=E6=98=BE=E7=A4=BA=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/controllers/handler.js | 7 +++++-- src/controllers/imageCtrl.js | 19 ++++++++++++++----- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/controllers/handler.js b/src/controllers/handler.js index ae345a4..73c011d 100644 --- a/src/controllers/handler.js +++ b/src/controllers/handler.js @@ -3168,17 +3168,20 @@ export default function luckysheetHandler() { "left": left, "top": top }); + + let imageUrlHandle = Store.toJsonOptions && Store.toJsonOptions['imageUrlHandle']; + let imgSrc = typeof imageUrlHandle === 'function' ? imageUrlHandle(imgItem.src) : imgItem.src; $("#luckysheet-modal-dialog-cropping .cropping-mask").css({ "width": imgItem.default.width, "height": imgItem.default.height, - "background-image": "url(" + imgItem.src + ")", + "background-image": "url(" + imgSrc + ")", "left": -offsetLeft, "top": -offsetTop }) $("#luckysheet-modal-dialog-cropping .cropping-content").css({ - "background-image": "url(" + imgItem.src + ")", + "background-image": "url(" + imgSrc + ")", "background-size": imgItem.default.width + "px " + imgItem.default.height + "px", "background-position": -offsetLeft + "px " + -offsetTop + "px" }) diff --git a/src/controllers/imageCtrl.js b/src/controllers/imageCtrl.js index 7e5ddde..3120654 100644 --- a/src/controllers/imageCtrl.js +++ b/src/controllers/imageCtrl.js @@ -97,7 +97,8 @@ const imageCtrl = { _this.addImgItem(img); } - image.src = src; + let imageUrlHandle = Store.toJsonOptions && Store.toJsonOptions['imageUrlHandle']; + image.src = typeof imageUrlHandle === 'function' ? imageUrlHandle(src) : src; }, generateRandomId: function(prefix) { if(prefix == null){ @@ -773,16 +774,19 @@ const imageCtrl = { "position": position }); + let imageUrlHandle = Store.toJsonOptions && Store.toJsonOptions['imageUrlHandle']; + let imgSrc = typeof imageUrlHandle === 'function' ? imageUrlHandle(item.src) : item.src; + $("#luckysheet-modal-dialog-cropping .cropping-mask").css({ "width": item.default.width, "height": item.default.height, - "background-image": "url(" + item.src + ")", + "background-image": "url(" + imgSrc + ")", "left": -item.crop.offsetLeft, "top": -item.crop.offsetTop }) $("#luckysheet-modal-dialog-cropping .cropping-content").css({ - "background-image": "url(" + item.src + ")", + "background-image": "url(" + imgSrc + ")", "background-size": item.default.width + "px " + item.default.height + "px", "background-position": -item.crop.offsetLeft + "px " + -item.crop.offsetTop + "px" }) @@ -820,9 +824,11 @@ const imageCtrl = { "top": top, "position": position }); + let imageUrlHandle = Store.toJsonOptions && Store.toJsonOptions['imageUrlHandle']; + let imgSrc = typeof imageUrlHandle === 'function' ? imageUrlHandle(item.src) : item.src; $("#luckysheet-modal-dialog-activeImage .luckysheet-modal-dialog-content").css({ - "background-image": "url(" + item.src + ")", + "background-image": "url(" + imgSrc + ")", "background-size": item.default.width + "px " + item.default.height + "px", "background-position": -item.crop.offsetLeft + "px " + -item.crop.offsetTop + "px" }) @@ -868,8 +874,11 @@ const imageCtrl = { "position": position }); + let imageUrlHandle = Store.toJsonOptions && Store.toJsonOptions['imageUrlHandle']; + let imgSrc = typeof imageUrlHandle === 'function' ? imageUrlHandle(imgItem.src) : imgItem.src; + $("#luckysheet-modal-dialog-activeImage .luckysheet-modal-dialog-content").css({ - "background-image": "url(" + imgItem.src + ")", + "background-image": "url(" + imgSrc + ")", "background-size": imgItem.default.width + "px " + imgItem.default.height + "px", "background-position": -imgItem.crop.offsetLeft + "px " + -imgItem.crop.offsetTop + "px" })