const deepmerge = require("deepmerge"); /** * 判断对象类型 * @param {*} obj 对象 */ export function objTypeOf(obj) { const toString = Object.prototype.toString; const map = { "[object Boolean]": "boolean", "[object Number]": "number", "[object String]": "string", "[object Function]": "function", "[object Array]": "array", "[object Date]": "date", "[object RegExp]": "regExp", "[object Undefined]": "undefined", "[object Null]": "null", "[object Object]": "object", "[object Blob]": "blob", }; return map[toString.call(obj)]; } /** * 深拷贝 * @param {Object/Array} data 需要拷贝的数据 */ export function deepCopy(data, options) { const defObj = objTypeOf(data) === "array" ? [] : {}; return deepmerge(defObj, data, options || {}); } /** * 将目标对象中有的属性值与源对象中的属性值合并 * @param {Object} target 目标对象 * @param {Object} sources 源对象 */ export function objAssign(target, sources) { let targ = { ...target }; for (let k in targ) { targ[k] = Object.prototype.hasOwnProperty.call(sources, k) ? sources[k] : targ[k]; } return targ; } /** * 文件流下载 * @param {Object} option 文件下载设置 */ export function download(option) { let defOpt = { type: "get", url: "", data: "", fileName: "", header: "", responseType: "", }; let opt = objAssign(defOpt, option); return new Promise((resolve, reject) => { let xhr = new XMLHttpRequest(); xhr.open(opt.type.toUpperCase(), opt.url, true); if (opt.responseType) xhr.responseType = opt.responseType; // header set if (opt.header && objTypeOf(opt.header) === "object") { for (let key in opt.header) { xhr.setRequestHeader(key, opt.header[key]); } } xhr.onload = function () { if (this.readyState === 4 && this.status === 200) { resolve(this.response); } else { reject("请求错误!"); } }; if (opt.type.toUpperCase() === "POST") { let fromData = new FormData(); for (let key in opt.data) { fromData.append(key, opt.data[key]); } xhr.send(fromData); } else { xhr.send(); } }); } /** * 构建图表btn * @param {Function} h createElement * @param {Array} actions 操作分类数组 */ export function tableAction(h, actions) { return actions.map((item) => { let attr = { props: { type: item.type || "primary", size: "small", disabled: !!item.disabled, }, style: { marginRight: "5px", }, on: { click: () => { item.action(); }, }, }; return h("el-button", attr, item.name); }); } /** * 获取随机code,默认获取16位 * @param {Number} len 推荐8的倍数 * */ export function randomCode(len = 16) { if (len <= 0) return; let steps = Math.ceil(len / 8); let stepNums = []; for (let i = 0; i < steps; i++) { let ranNum = Math.random().toString(32).slice(-8); stepNums.push(ranNum); } return stepNums.join(""); } /** * 序列化参数 * @param {Object} params 参数对象 */ export function qsParams(params) { return Object.entries(params) .map((el) => `${el[0]}=${el[1]}`) .join("&"); } /** * * @param {String} format 时间格式 * @param {Date} date 需要格式化的时间对象 */ export function formatDate(format = "YYYY/MM/DD HH:mm:ss", date = new Date()) { if (objTypeOf(date) !== "date") return; const options = { "Y+": date.getFullYear(), "M+": date.getMonth() + 1, "D+": date.getDate(), "H+": date.getHours(), "m+": date.getMinutes(), "s+": date.getSeconds(), }; Object.entries(options).map(([key, val]) => { if (new RegExp("(" + key + ")").test(format)) { const zeros = key === "Y+" ? "0000" : "00"; const value = (zeros + val).substr(("" + val).length); format = format.replace(RegExp.$1, value); } }); return format; } /** * 获取时间长度文字 * @param {Number} timeNumber 时间数值,单位:毫秒 */ export function timeNumberToText(timeNumber) { const DAY_TIME = 24 * 60 * 60 * 1000; const HOUR_TIME = 60 * 60 * 1000; const MINUTE_TIME = 60 * 1000; const SECOND_TIME = 1000; let [day, hour, minute, second] = [0, 0, 0, 0]; let residueTime = timeNumber; if (residueTime >= DAY_TIME) { day = Math.floor(residueTime / DAY_TIME); residueTime -= day * DAY_TIME; day += "天"; } if (residueTime >= HOUR_TIME) { hour = Math.floor(residueTime / HOUR_TIME); residueTime -= hour * HOUR_TIME; hour += "小时"; } if (residueTime >= MINUTE_TIME) { minute = Math.floor(residueTime / MINUTE_TIME); residueTime -= minute * MINUTE_TIME; minute += "分钟"; } if (residueTime >= SECOND_TIME) { second = Math.round(residueTime / SECOND_TIME); second += "秒"; } return [day, hour, minute, second].filter((item) => !!item).join(""); } /** * 警告时间 * @param {Number} timeNumber 时间数值,单位:毫秒 * @param {Number} wainingTime 最大剩余警告时间数值,单位:毫秒 */ export function residueFloorTime(timeNumber, wainingTime = 0) { if (timeNumber < 0) { return { status: "danger", title: "已过期" }; } const DAY_TIME = 24 * 60 * 60 * 1000; const HOUR_TIME = 60 * 60 * 1000; const MINUTE_TIME = 60 * 1000; const status = timeNumber < wainingTime ? "warning" : "primary"; let [day, hour, minute] = [0, 0, 0]; let residueTime = timeNumber; if (residueTime >= DAY_TIME) { day = Math.floor(residueTime / DAY_TIME); residueTime -= day * DAY_TIME; return { status, title: `剩余${day}天`, }; } if (residueTime >= HOUR_TIME) { hour = Math.floor(residueTime / HOUR_TIME); residueTime -= hour * HOUR_TIME; return { status, title: `剩余${hour}小时`, }; } if (residueTime >= MINUTE_TIME) { minute = Math.floor(residueTime / MINUTE_TIME); return { status, title: `剩余${minute}分钟`, }; } return { status, title: `不足1分钟`, }; } export function parseTimeRangeDateAndTime(startTime, endTime) { if (!startTime || !endTime) return { date: "", time: "", }; const st = formatDate("YYYY-MM-DD HH:mm", new Date(startTime)).split(" "); const et = formatDate("YYYY-MM-DD HH:mm", new Date(endTime)).split(" "); return { date: st[0], time: `${st[1]}-${et[1]}`, }; } /** * 获取本地时间,格式:年月日时分秒 */ export function localNowDateTime() { return formatDate("YYYY年MM月DD日HH时mm分ss秒"); } /** * * @param {Number} time 时间戳 */ export function getTimeDatestamp(time) { const date = formatDate("YYYY-MM-DD HH:mm", new Date(time)).split(" ")[0]; return new Date(`${date} 00:00:00`).getTime(); } export function getExamDateTime(startTime, endTime) { const examDate = startTime ? formatDate("YYYY-MM-DD", new Date(startTime)) : "-"; const examSt = startTime ? formatDate("HH:mm", new Date(startTime)) : ""; const examEt = endTime ? formatDate("HH:mm", new Date(endTime)) : ""; return { examDate, examTime: `${examSt}-${examEt}`, }; } /** * 获取指定元素个数的数组 * @param {Number} num */ export function getNumList(num) { return "#".repeat(num).split(""); } /** * 清除html标签 * @param {String} str html字符串 */ export function removeHtmlTag(str) { return str.replace(/<[^>]+>/g, ""); } /** * 计算总数 * @param {Array} dataList 需要统计的数组 */ export function calcSum(dataList) { if (!dataList.length) return 0; return dataList.reduce(function (total, item) { return total + item; }, 0); } /** * 计算评卷数 * @param {Array} dataList 需要统计的数组 */ export function calcAvg(dataList) { if (!dataList.length) return 0; return calcSum(dataList) / dataList.length; } /** 获取数组最大数 */ export function maxNum(dataList) { if (!dataList.length) return 0; return Math.max.apply(null, dataList); } export function isEmptyObject(obj) { return !Object.keys(obj).length; } /** * 解决后台返回的数据中number位数超过16位的情况 * @param {String} text json格式字符串 */ export function jsonBigNumberToString(text) { return text .replace(/\\":[0-9]{16,19}/g, function (match) { return match.slice(0, 3) + '\\"' + match.slice(3) + '\\"'; }) .replace(/:[0-9]{16,19}/g, function (match) { return match[0] + '"' + match.slice(1) + '"'; }); } export function humpToLowLine(a) { return a .replace(/([A-Z])/g, "-$1") .toLowerCase() .slice(1); } export function pickByNotNull(params) { let nData = {}; Object.entries(params).forEach(([key, val]) => { if (val === null || val === "null" || val === "") return; nData[key] = val; }); return nData; } export function autoSubmitForm(url, params) { const form = document.createElement("form"); form.action = url; form.method = "post"; Object.entries(params).forEach(([key, val]) => { const input = document.createElement("input"); input.type = "hidden"; input.name = key; input.value = val; form.appendChild(input); }); document.body.appendChild(form); form.submit(); } export function blobToText(blob) { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsText(blob, "utf-8"); reader.onload = function () { resolve(reader.result); }; reader.onerror = function () { reject(); }; }); } export function parseHrefParam(urlStr, paramName = null) { if (!urlStr) return; const url = new URL(urlStr); const urlParams = new URLSearchParams(url.search); if (paramName) return urlParams.get(paramName); let params = {}; for (const kv of urlParams.entries()) { params[kv[0]] = kv[1]; } return params; } export function objFilterNull(obj) { let nobj = {}; Object.entries(obj).forEach(([key, val]) => { if (val === null || val === "null" || val === "") return; nobj[key] = val; }); return nobj; } /** * 百以下数字转中文汉字 * @param {Number} num 大于0的100以下数字,其他数值直接转字符串 * * @returns {String} */ export function numberToChinese(num) { if (num >= 100 || num <= 0) return num + ""; const cnNums = "一二三四五六七八九十".split(""); if (num <= 10) return cnNums[num - 1]; return (num + "") .split("") .map((item) => item * 1) .map((item, index) => { if (index) { return !item ? "" : cnNums[item - 1]; } else { return item === 1 ? "" : cnNums[item - 1]; } }) .join("十"); } /** * 移除富文本json字符串中的type=text的value值 * @param {string} data 富文本json字符串 * @returns 字符串 */ export function removeRichTextValue(data) { return data.replace( /"type":"text","value":"(.*?)"/g, '"type":"text","value":""' ); } /** * 将给定的字符串按设置的字符个数分段 * @param {string} content 字符串内容 * @param {number} countPerGroup 每段字符最大个数 * @returns 分段数组 */ export function splitContent(content, countPerGroup) { if (!countPerGroup) return content; const gCount = Math.ceil(content.length / countPerGroup); const cpg = Math.ceil(content.length / gCount); const groups = []; for (let i = 0; i < gCount; i++) { groups.push(content.substr(i * cpg, (i + 1) * cpg)); } return groups; } /** * 获取远程json文件的内容 * @param {string} url json文件远程地址 */ export async function getJsonDataFormUrl(url) { const response = await fetch(url); if (!response.ok) { throw new Error(`fetch error! response.status: ${response.status}`); } const data = await response.json(); return data; }