import _ from 'lodash' import moment from 'moment' let zTool = { /** * @description 表单验证 * @param formRef 组件 * @param callBack 回调方法 */ validate(formRef, callBack) { formRef.validate(valid => { if (!!valid && callBack) { callBack() } }); }, /** * @description 表单验证 * @param formRefs 组件 * @param callBack 回调方法 */ validateForms(formRefs, callBack) { let promises = []; for (let i = 0; i < formRefs.length; i++) { promises.push(new Promise((resolve) => { formRefs[i].validate(valid => { if (valid) { resolve(); } }) })); } Promise.all(promises).then(() => { if (callBack) { callBack() } }).catch(()=>{}) }, /** * @description 表单字段验证 * @param formRef 组件 * @param callBack 回调方法 * @param fields 字段 */ validateFields(formRef, callBack, ...fields) { for (let i = 0; i < fields.length; i++) { formRef.validateField(fields[i],valid => { if (!!valid && callBack && ( i +1 ) === fields.length) { callBack() } }) } }, /** * @description 启用禁用 * @param ref 组件 * @param apiObj API对象 * @param row 行数据 * @param index 行号 * @param props 属性数组 */ switch(ref, apiObj, row, index, props = ['id']) { if (index === -1) { return; } let params = { isActived: row.isActived }; for (let prop of props) { params[`${prop}`] = row[`${prop}`] } this.loading(ref); apiObj.put(params).then(() => { ref.$message.success(row.isActived === 0 ? '禁用成功' : '启用成功'); ref.searchFun(); }).catch(()=>{}).finally(() => { this.loadingHidden(ref); }); }, /** * @description 保存 * @param ref 组件 * @param apiObj API对象 * @param params 保存参数 * @param msg 提示信息 * @param callBack 回调方法 * @param isMessage 是否提示 * @param isCloseDialog 是否关闭弹窗 * @param isSearchFun 是否刷新页面 */ save(ref, apiObj, params, msg = '操作成功', callBack, isMessage = true, isCloseDialog = true, isSearchFun = true) { this.loading(ref); apiObj.post(params).then(() => { if (isMessage) { ref.$message.success(msg); } if (isCloseDialog) { ref.closeDialog(); } if (isSearchFun) { ref.searchFun(); } if (callBack) { callBack(); } }).catch(()=>{}).finally(() => { this.loadingHidden(ref); }) }, /** * @description 响应赋值 * @param ref 组件f * @param apiObj API对象 * @param name 赋值的属性 * @param params 参数 * @param callBack 回调方法 */ resSetValue(ref, apiObj, name, params = {}, callBack, isLoad = false) { let obj = getObjByStrName(ref, name) let attr = getAttrByStrName(ref, name) if (obj[`${attr}`] === undefined) { return } if (isLoad) { this.loading(ref); } apiObj.get(params).then((res) => { obj[`${attr}`] = res; if (callBack) { callBack(res) } }).catch(()=>{}).finally(() => { if (isLoad) { this.loadingHidden(ref); } }) }, /** * @description Number格式化 * @param number Number * @param afterPointDigit 小数点后位数 * @param useThousandSign 是否使用千位符 * @param noExistDisplay 数字不存在时的展示值 * @param zeroDisplayNegative 数字0展示为负数 * @return number 格式化后的时数字/字符串 */ numberFormat(number, afterPointDigit, useThousandSign = true, noExistDisplay, zeroDisplayNegative) { if (number !== 0 && !number) { if (noExistDisplay) { return noExistDisplay } else { return number } } number = Number(number) if (afterPointDigit === 0 || afterPointDigit) { number = number.toFixed(afterPointDigit) } if (useThousandSign) { number = number.toString() if (number.indexOf('.') >= 0) { number = number.replace(/(\d{1,3})(?=(\d{3})+(?:\.))/g, '$1,') } else { number = number.replace(/(\d{1,3})(?=(\d{3})+(?:$))/g, '$1,') } } if (zeroDisplayNegative && Number(number) == 0) { number = '-' + number } return number }, /** * @description 改变输入值 * @param ref 组件 * @param name 属性名称 * @param type change类型 具体类型如下 * STR_1允许输入任意字符; STR_2允许输入数字字母下划线和汉字; STR_3允许输入数字字母下划线; * NUM_1允许输入数字; NUM_2允许输入数字(去除数字前方的0); NUM_3允许输入数字和小数点(去除数字前方多余的0); NUM_4允许输入数字(去除数字前方多余的0);NUM_5允许输入负数,数字和小数点(去除数字前方多余的0); * NULL_XX 不允许非法字符 * @param max1 最大输入长度 NUM类型时为小数点前数字位数 * @param max2 小数点后数字位数 */ changeInput(ref, name, type, max1, max2) { let obj = getObjByStrName(ref, name) let attr = getAttrByStrName(ref, name) if (obj[`${attr}`] === undefined) { return } if (obj[`${attr}`] === null) { return } obj[`${attr}`] = obj[`${attr}`].toString().trim(); if (type === 'STR_1') { obj[`${attr}`] = obj[`${attr}`].substring(0, max1) } else if (type === 'STR_2') { obj[`${attr}`] = obj[`${attr}`].replace(/[^\w_/.*\u4e00-\u9fa5]/g, '').substring(0, max1) } else if (type === 'STR_3') { obj[`${attr}`] = obj[`${attr}`].replace(/[^\w_]/g, '').substring(0, max1) } else if (type === 'NUM_1') { obj[`${attr}`] = obj[`${attr}`].replace(/[^\d]/g, '').substring(0, max1) } else if (type === 'NUM_2') { obj[`${attr}`] = obj[`${attr}`] .replace(/[^\d]/g, '') .replace(/\b(0+)/g, '') .substring(0, max1) } else if (type === 'NUM_3') { let num = obj[`${attr}`] num = num .replace(/[^\d.]/g, '') .replace('.', '$#$') .replace(/\./g, '') .replace('$#$', '.') .replace(/^\./g, '') if (num.indexOf('.') === -1) { num = num == 0 ? num.replace(/\b(0+)/g, '0') : num.replace(/\b(0+)/g, '').substring(0, max1) } else { num = num.substring(0, num.indexOf('.')).substring(0, max1) + '.' + num.substring(num.indexOf('.') + 1).substring(0, max2) } obj[`${attr}`] = num } else if (type === 'NUM_4') { let num = obj[`${attr}`] obj[`${attr}`] = num == 0 ? num.replace(/[^\d]/g, '').replace(/\b(0+)/g, '0') : num.replace(/[^\d]/g, '').replace(/\b(0+)/g, '').substring(0, max1) } else if (type === 'NUM_5') { let num = obj[`${attr}`] num = num .replace(/[^\d.-]/g, '') .replace('.', '$#$') .replace(/\./g, '') .replace('$#$', '.') .replace(/^\./g, '') .replace(/-{2,}/g, '-') .replace(/(?<=-)(.*?)(-)/, '') if (num.indexOf('.') === -1) { num = num == 0 ? num.replace(/\b(0+)/g, '0') : num.replace(/\b(0+)/g, '').substring(0, max1) } else { num = num.substring(0, num.indexOf('.')).substring(0, max1) + '.' + num.substring(num.indexOf('.') + 1).substring(0, max2) } obj[`${attr}`] = num } else if (type === 'NULL_XX') { obj[`${attr}`] = obj[`${attr}`] .replace(/[`~!@#$%^&*()_\-+=<>?:"{}|,./;'\\[\]·~!@#¥%……&*()——\-+={}|《》?:“”【】、;‘’,。、]/g, '') .replace(/\s/g, '') .substring(0, max1) } }, /** * 合计 * @param param 合计参数 * @param array 自定义数组 eg: [ { prop: amount, scopeType: 1 } ] * @returns */ getSummaries(param, array) { const { columns, data } = param const sums = [] columns.forEach((column, index) => { if (index === 0) { sums[index] = '合计' return } array.forEach(item => { if (item.prop === column.property) { const values = data.map(item => Number(item[column.property])) sums[index] = values.reduce((prev, curr) => { const value = Number(curr) if (!isNaN(value)) { return prev + curr } else { return prev } }, 0) if (item.scopeType) { switch (item.scopeType) { case 3: return (sums[index] = this.numberFormat(sums[index], 2, true)); case 4: return (sums[index] = this.numberFormat(sums[index], 2, false)); case 5: return (sums[index] = this.numberFormat(sums[index], 0, false)); case 6: return (sums[index] = this.numberFormat(sums[index], 4, false)); case 7: return (sums[index] = this.numberFormat(sums[index], 6, false)); case 8: return (sums[index] = this.numberFormat(sums[index], 3, false)); case 9: return (sums[index] = this.numberFormat(sums[index], 2, true, undefined, true)); } } } }) }) return sums }, /** * 加载 */ loading(ref) { ref.loadingInstance = ref.$loading({ fullscreen: true, text: '请稍后' }) }, /** * 取消加载 */ loadingHidden(ref) { if (ref.loadingInstance != null) { setTimeout(() => { ref.loadingInstance.close() }, 500); } }, /** * 日期转字符串 */ dateToStr(date = new Date(), format = 'YYYY-MM-DD') { return moment(date).format(format); }, /** * @description 导出EXCEL * @param ref 组件 * @param methodsName 查询方法 * @param params 查询参数 * @param name EXCEL名称 */ zDownloadExcel(ref, methodsName, params, name) { let req = this.zDeleteObjectInvalidKey(params, true) methodsName.get(req) .then(res => { let url = window.URL.createObjectURL(new Blob([res], { type: 'application/vnd.ms-excel;charset=UTF-8' })) let link = document.createElement('a') link.href = url link.download = name document.body.appendChild(link) link.click() document.body.removeChild(link) window.URL.revokeObjectURL(url) }) .catch() .finally(() => { // ref.endLoading() }) }, /** * @description 删除Object对象无效key * @param object1 对象 * @param delEmptyStr 是否删除值为''的key * @return 删除后的对象 */ zDeleteObjectInvalidKey(object1 = {}, delEmptyStr = false) { let object = _.cloneDeep(object1) for (let key in object) { if (object[key] === undefined || object[key] === null) { delete object[key] } if (delEmptyStr && object[key] === '') { delete object[key] } } return object }, /** * @description 导出模板 * @param name 模板名称 */ zDownloadTemplate(name) { let a = document.createElement('a') a.href = '/static/'.concat(name) console.log(a.href); a.download = name a.click() }, /** * @description 导入EXCEL * @param ref 组件 * @param methodsName 导入方法 * @param data 数据 */ zImportExcel(ref, methodsName, data) { this.loading(ref); methodsName.post(data) .then(res => { if (res.message === 'success') { if (!res.errorMsg) { ref.$message.success('批量导入成功') ref.searchFun() } else { ref.$message.error(res.errorMsg, true) } } }).catch(()=>{}).finally(() => { this.loadingHidden(ref); }) }, /** * @description 处理cascader * @param params 参数对象 * @param cascaderNames cascader属性名称 * @return object 处理后的参数对象 */ handleCascader(params = {}, ...cascaderNames) { let object = _.cloneDeep(params) for (let i = 0; i < cascaderNames.length; i++) { let cascaderName = cascaderNames[i] if (object[`${cascaderName}`] && typeof object[`${cascaderName}`] !== 'string') { object[`${cascaderName}`] = object[`${cascaderName}`].length > 0 ? object[`${cascaderName}`][object[`${cascaderName}`].length - 1] : null } } return object }, addWatermark(file,name) { return new Promise((resolve, reject) => { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); const image = new Image(); image.onload = function () { // 设置canvas大小为图片大小 canvas.width = image.width; canvas.height = image.height; // 在canvas上绘制原始图片 ctx.drawImage(image, 0, 0); // 添加水印文本 let size = Math.ceil(image.width*image.height /100000); ctx.font = `${size}px Arial`; ctx.fillStyle = 'rgb(228,233,229)'; const watermarkText = name; // 水印文本 const angle = 15 * Math.PI / 180; // 将15度转换为弧度 // 计算每个部分的高度 const partHeight = canvas.height / 3; // 计算每行的宽度 const rowWidth = canvas.width / Math.ceil(canvas.width / canvas.height); // 遍历每行 for (let i = 0; i < 3; i++) { // 计算水印的y坐标 const y = (i + 0.2) * partHeight; // 在每行的中间位置添加水印 // 遍历每个部分 for (let j = 0; j < Math.ceil(canvas.width / rowWidth); j++) { // 计算水印的x坐标 const x = (j + 0.2) * rowWidth; // 在每个部分的中间位置添加水印 // 保存当前绘图环境状态 ctx.save(); // 将坐标系移动到水印的位置 ctx.translate(x, y); // 应用倾斜角度 ctx.rotate(angle); // 将角度转换为弧度 // 绘制水印文本 ctx.fillText(watermarkText, 0, 0); // 恢复绘图环境到之前的状态 ctx.restore(); } } // const watermarkCount = 3; // 水印数量 // const horizontalSpacing = canvas.width / (watermarkCount+2 ); // 水平间距 // const verticalSpacing = canvas.height / (watermarkCount +2); // 垂直间距 // for (let i = 1; i <= watermarkCount; i++) { // for (let j = 1; j <= watermarkCount; j++) { // const x = i * horizontalSpacing; // const y = j * verticalSpacing; // ctx.save(); // 保存当前的绘图状态 // ctx.translate(x, y); // 将原点移动到水印位置 // ctx.rotate(angle); // 固定倾斜15度 // ctx.fillText(watermarkText, 0, 0); // 绘制倾斜的水印文本 // ctx.restore(); // 恢复之前保存的绘图状态,避免影响后续绘图 // } // } // const watermarkText = '社保信息'; // 水印文本 // const watermarkCountX = Math.ceil(canvas.width / 150); // 根据图片宽度计算水印横向数量 // const watermarkCountY = Math.ceil(canvas.height / 150); // 根据图片高度计算水印纵向数量 // const angle = 10 * Math.PI / 180; // 将5度转换为弧度 // for (let i = 1; i <= watermarkCountX; i++) { // for (let j = 1; j <= watermarkCountY; j++) { // const x = i * (canvas.width / (watermarkCountX + 1)); // const y = j * (canvas.height / (watermarkCountY + 1)); // ctx.save(); // 保存当前的绘图状态 // ctx.translate(x, y); // 将原点移动到水印位置 // ctx.rotate(angle); // 固定倾斜5度 // ctx.fillText(watermarkText, 0, 0); // 绘制倾斜的水印文本 // ctx.restore(); // 恢复之前保存的绘图状态,避免影响后续绘图 // } // } function _dataURLtoBlob(dataurl) { var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while(n--){ u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], {type:mime}); } const dataurl2 = canvas.toDataURL('image/jpeg', 0.7); const blob = _dataURLtoBlob(dataurl2) return resolve(new File([blob], file.name, { type: 'image/jpg' })); }; image.onerror = function () { reject(new Error('Failed to load image')); }; // 使用异步方法加载图片 image.src = URL.createObjectURL(file); }); }, /** * @description 处理多选cascader * @param params 参数对象 * @param cascaderNames cascader属性名称 * @return object 处理后的参数对象 */ handleMultipleCascader(params = {}, ...cascaderNames) { let object = _.cloneDeep(params) for (let i = 0; i < cascaderNames.length; i++) { let cascaderName = cascaderNames[i] if (object[`${cascaderName}`]) { for (let i = 0; i < object[`${cascaderName}`].length; i++) { if (typeof object[`${cascaderName}`][i] !== 'string') { object[`${cascaderName}`][i] = object[`${cascaderName}`][i].length > 0 ? object[`${cascaderName}`][i][object[`${cascaderName}`][i].length - 1] : null } } } } return object } }; /** * @description 双子函数 解析名称字符串 与getAttrByStrName共同使用 对象[`${属性}`] 达到给组件属性赋值作用 * @param ref 组件 * @param name 组件属性名 */ function getObjByStrName(ref, name) { let obj = ref let array = name.split(/\.|\[/) for (let i = 0; i < array.length - 1; i++) { obj = array[i].endsWith(']') ? obj[parseInt(array[i].substring(0, array[i].length - 1))] : obj[`${array[i]}`] } return obj } /** * @description 双子函数 解析名称字符串 与getObjByStrName共同使用 对象[`${属性}`] 达到给组件属性赋值作用 * @param ref 组件 * @param name 组件属性名 */ function getAttrByStrName(ref, name) { let array = name.split(/\.|\[/) return array[array.length - 1] } export default zTool