window.teaweb = { set: function (key, value) { localStorage.setItem(key, JSON.stringify(value)); }, get: function (key) { var item = localStorage.getItem(key); if (item == null || item.length == 0) { return null; } return JSON.parse(item); }, getString: function (key) { var value = this.get(key); if (typeof (value) == "string") { return value; } return ""; }, getBool: function (key) { return Boolean(this.get(key)); }, remove: function (key) { localStorage.removeItem(key) }, match: function (source, keyword) { if (source == null) { return false; } if (keyword == null) { return true; } source = source.trim(); keyword = keyword.trim(); if (keyword.length == 0) { return true; } if (source.length == 0) { return false; } var pieces = keyword.split(/\s+/); for (var i = 0; i < pieces.length; i++) { var pattern = pieces[i]; pattern = pattern.replace(/(\+|\*|\?|[|]|{|}|\||\\|\(|\)|\.)/g, "\\$1"); var reg = new RegExp(pattern, "i"); if (!reg.test(source)) { return false; } } return true; }, loadJS: function (file, callback) { let element = document.createElement("script") element.setAttribute("type", "text/javascript") element.setAttribute("src", file) if (typeof callback == "function") { element.addEventListener("load", callback) } document.head.append(element) }, loadCSS: function (file, callback) { let element = document.createElement("link") element.setAttribute("rel", "stylesheet") element.setAttribute("type", "text/css") element.setAttribute("href", file) if (typeof callback == "function") { element.addEventListener("load", callback) } document.head.append(element) }, datepicker: function (element, callback, bottomLeft) { // 加载 if (typeof Pikaday == "undefined") { let that = this this.loadJS("/js/moment.min.js", function () { that.loadJS("/js/pikaday.js", function () { that.datepicker(element, callback, bottomLeft) }) }) this.loadCSS("/js/pikaday.css") this.loadCSS("/js/pikaday.theme.css") this.loadCSS("/js/pikaday.triangle.css") return } if (typeof (element) == "string") { element = document.getElementById(element); } let year = new Date().getFullYear(); let picker = new Pikaday({ field: element, firstDay: 1, minDate: new Date(year - 1, 0, 1), maxDate: new Date(year + 10, 11, 31), yearRange: [year - 1, year + 10], format: "YYYY-MM-DD", i18n: { previousMonth: '上月', nextMonth: '下月', months: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'], weekdays: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'], weekdaysShort: ['周日', '周一', '周二', '周三', '周四', '周五', '周六'] }, theme: 'triangle-theme', onSelect: function () { if (typeof (callback) == "function") { callback.call(Tea.Vue, picker.toString()); } }, reposition: !bottomLeft }) }, formatBytes: function (bytes) { bytes = Math.ceil(bytes); if (bytes < Math.pow(1024, 1)) { return bytes + "B"; } if (bytes < Math.pow(1024, 2)) { return (Math.round(bytes * 100 / Math.pow(1024, 1)) / 100) + "KB"; } if (bytes < Math.pow(1024, 3)) { return (Math.round(bytes * 100 / Math.pow(1024, 2)) / 100) + "MB"; } if (bytes < Math.pow(1024, 4)) { return (Math.round(bytes * 100 / Math.pow(1024, 3)) / 100) + "GB"; } if (bytes < Math.pow(1024, 5)) { return (Math.round(bytes * 100 / Math.pow(1024, 4)) / 100) + "TB"; } if (bytes < Math.pow(1024, 6)) { return (Math.round(bytes * 100 / Math.pow(1024, 5)) / 100) + "PB"; } return (Math.round(bytes * 100 / Math.pow(1024, 6)) / 100) + "EB"; }, formatNumber: function (x) { if (x == null) { return "null" } let s = x.toString() let dotIndex = s.indexOf(".") if (dotIndex >= 0) { return this.formatNumber(s.substring(0, dotIndex)) + "." + s.substring(dotIndex + 1) } if (s.length <= 3) { return s; } let result = [] for (let i = 0; i < Math.floor(s.length / 3); i++) { let start = s.length - (i + 1) * 3 result.push(s.substring(start, start + 3)) } if (s.length % 3 != 0) { result.push(s.substring(0, s.length % 3)) } return result.reverse().join(", ") }, formatCount: function (x) { let unit = "" let divider = "" if (x >= 1000 * 1000 * 1000) { unit = "B" divider = 1000 * 1000 * 1000 } else if (x >= 1000 * 1000) { unit = "M" divider = 1000 * 1000 } else if (x >= 1000) { unit = "K" divider = 1000 } if (unit.length == 0) { return x.toString() } return (Math.round(x * 100 / divider) / 100) + unit }, bytesAxis: function (stats, countFunc) { let max = Math.max.apply(this, stats.map(countFunc)) let divider = 1 let unit = "" if (max >= Math.pow(1024, 6)) { unit = "E" divider = Math.pow(1024, 6) } else if (max >= Math.pow(1024, 5)) { unit = "P" divider = Math.pow(1024, 5) } else if (max >= Math.pow(1024, 4)) { unit = "T" divider = Math.pow(1024, 4) } else if (max >= Math.pow(1024, 3)) { unit = "G" divider = Math.pow(1024, 3) } else if (max >= Math.pow(1024, 2)) { unit = "M" divider = Math.pow(1024, 2) } else if (max >= Math.pow(1024, 1)) { unit = "K" divider = Math.pow(1024, 1) } return { unit: unit, divider: divider } }, countAxis: function (stats, countFunc) { let max = Math.max.apply(this, stats.map(countFunc)) let divider = 1 let unit = "" if (max >= 1000 * 1000 * 1000) { unit = "B" divider = 1000 * 1000 * 1000 } else if (max >= 1000 * 1000) { unit = "M" divider = 1000 * 1000 } else if (max >= 1000) { unit = "K" divider = 1000 } return { unit: unit, divider: divider, max: max } }, popup: function (url, options) { if (url != null && url.length > 0 && url.substring(0, 1) == '.') { url = Tea.url(url) } if (options == null) { options = {}; } var width = "40em"; var height = "20em"; window.POPUP_CALLBACK = function () { Swal.close(); }; if (options["width"] != null) { width = options["width"]; } if (options["height"] != null) { height = options["height"]; } if (typeof (options["callback"]) == "function") { window.POPUP_CALLBACK = function () { Swal.close(); options["callback"].apply(Tea.Vue, arguments); }; } Swal.fire({ html: '', width: width, padding: "0.5em", showConfirmButton: false, showCloseButton: true, focusConfirm: false, onClose: function (popup) { if (typeof (options["onClose"]) == "function") { options["onClose"].apply(Tea.Vue, arguments) } } }); }, popupSuccess: function (url, width, height) { let options = {} if (width != null) { options["width"] = width } if (height != null) { options["height"] = height } options["callback"] = function () { teaweb.success("保存成功", function () { teaweb.reload() }) } this.popup(url, options) }, popupFinish: function () { if (window.POPUP_CALLBACK != null) { window.POPUP_CALLBACK.apply(window, arguments); } }, popupTip: function (html) { Swal.fire({ html: '
' + html + "
", width: "30em", padding: "4em", showConfirmButton: false, showCloseButton: true, focusConfirm: false }); }, isPopup: function () { var hash = window.location.hash; return hash != null && hash.startsWith("#popup"); }, closePopup: function () { if (this.isPopup()) { window.parent.Swal.close(); } }, Swal: function () { return this.isPopup() ? window.parent.Swal : window.Swal; }, success: function (message, callback) { var width = "20em"; if (message.length > 30) { width = "30em"; } let config = { confirmButtonText: "确定", buttonsStyling: false, icon: "success", customClass: { closeButton: "ui button", cancelButton: "ui button", confirmButton: "ui button primary" }, width: width, onAfterClose: function () { if (typeof (callback) == "function") { setTimeout(function () { callback(); }); } else if (typeof (callback) == "string") { window.location = callback } } } if (message.startsWith("html:")) { config.html = message.substring(5) } else { config.text = message } Swal.fire(config); }, toast: function (message, timeout, callback) { if (timeout == null) { timeout = 2000 } var width = "20em"; if (message.length > 30) { width = "30em"; } Swal.fire({ text: message, icon: "info", width: width, timer: timeout, showConfirmButton: false, onAfterClose: function () { if (typeof callback == "function") { callback() } } }); }, successToast: function (message, timeout, callback) { if (timeout == null) { timeout = 2000 } var width = "20em"; if (message.length > 30) { width = "30em"; } Swal.fire({ text: message, icon: "success", width: width, timer: timeout, showConfirmButton: false, onAfterClose: function () { if (typeof callback == "function") { callback() } } }); }, successRefresh: function (message) { teaweb.success(message, function () { teaweb.reload() }) }, warn: function (message, callback) { var width = "20em"; if (message.length > 30) { width = "30em"; } Swal.fire({ text: message, confirmButtonText: "确定", buttonsStyling: false, customClass: { closeButton: "ui button", cancelButton: "ui button", confirmButton: "ui button primary" }, icon: "warning", width: width, onAfterClose: function () { if (typeof (callback) == "function") { setTimeout(function () { callback(); }); } } }); }, confirm: function (message, callback) { let width = "20em"; if (message.length > 30) { width = "30em"; } let config = { confirmButtonText: "确定", cancelButtonText: "取消", showCancelButton: true, showCloseButton: false, buttonsStyling: false, customClass: { closeButton: "ui button", cancelButton: "ui button", confirmButton: "ui button primary" }, icon: "warning", width: width, preConfirm: function () { if (typeof (callback) == "function") { callback.call(Tea.Vue); } } } if (message.startsWith("html:")) { config.html = message.substring(5) } else { config.text = message } Swal.fire(config); }, reload: function () { window.location.reload() }, renderBarChart: function (options) { let chartId = options.id if (chartId == null || chartId.length == 0) { throw new Error("'options.id' should not be empty") } let name = options.name let values = options.values if (values == null || !(values instanceof Array)) { throw new Error("'options.values' should be array") } let xFunc = options.x if (typeof (xFunc) != "function") { throw new Error("'options.x' should be a function") } let tooltipFunc = options.tooltip if (typeof (tooltipFunc) != "function") { throw new Error("'options.tooltip' should be a function") } let axis = options.axis if (axis == null) { axis = {unit: "", count: 1} } let valueFunc = options.value if (typeof (valueFunc) != "function") { throw new Error("'options.value' should be a function") } let click = options.click let bottom = 24 let rotate = 0 let chartBox = document.getElementById(chartId) if (chartBox == null) { return } let chart = this.initChart(chartBox) let result = this.xRotation(chart, values.map(xFunc)) if (result != null) { bottom = result[0] rotate = result[1] } let option = { xAxis: { data: values.map(xFunc), axisLabel: { interval: 0, rotate: rotate } }, yAxis: { axisLabel: { formatter: function (value) { return value + axis.unit } } }, tooltip: { show: true, trigger: "item", formatter: function (args) { return tooltipFunc.apply(this, [args, values]) } }, grid: { left: 40, top: 10, right: 20, bottom: bottom }, series: [ { name: name, type: "bar", data: values.map(valueFunc), itemStyle: { color: "#9DD3E8" }, barWidth: "20em" } ], animation: true, } chart.setOption(option) if (click != null) { chart.on("click", function (args) { click.call(this, args, values) }) } chart.resize() }, renderLineChart: function (options) { let chartId = options.id let name = options.name let values = options.values let xFunc = options.x let tooltipFunc = options.tooltip let axis = options.axis let valueFunc = options.value let max = options.max let interval = options.interval let chartBox = document.getElementById(chartId) if (chartBox == null) { return } let chart = this.initChart(chartBox) let option = { xAxis: { data: values.map(xFunc), axisLabel: { interval: interval } }, yAxis: { axisLabel: { formatter: function (value) { return value + axis.unit } }, max: max }, tooltip: { show: true, trigger: "item", formatter: function (args) { return tooltipFunc.apply(this, [args, values]) } }, grid: { left: 40, top: 10, right: 20, bottom: 20 }, series: [ { name: name, type: "line", data: values.map(valueFunc), itemStyle: { color: "#9DD3E8" }, areaStyle: {}, smooth: true } ], animation: true, smooth: true } chart.setOption(option) chart.resize() }, renderGaugeChart: function (options) { let chartId = options.id let name = options.name // 标题 let min = options.min // 最小值 let max = options.max // 最大值 let value = options.value // 当前值 let unit = options.unit // 单位 let detail = options.detail // 说明文字 let color = options.color // 颜色 let startAngle = options.startAngle if (startAngle == null) { startAngle = 225 } let endAngle = options.endAngle if (endAngle == null) { endAngle = -45 } color = this.chartColor(color) let chartBox = document.getElementById(chartId) if (chartBox == null) { return } let chart = this.initChart(chartBox) let option = { textStyle: { fontFamily: "Lato,'Helvetica Neue',Arial,Helvetica,sans-serif" }, color: color, title: (name != null && name.length > 0) ? { text: name, top: 1, bottom: 0, x: "center", textStyle: { fontSize: 12, fontWeight: "bold", fontFamily: "Lato,'Helvetica Neue',Arial,Helvetica,sans-serif" } } : null, legend: { data: [""] }, xAxis: { data: [] }, yAxis: {}, series: [{ name: "", type: "gauge", min: min, max: max, startAngle: startAngle, endAngle: endAngle, data: [ { "name": "",// 不显示名称 "value": Math.round(value * 100) / 100 } ], radius: "100%", center: ["50%", (name != null && name.length > 0) ? "60%" : "50%"], splitNumber: 5, splitLine: { length: 4 }, axisLine: { lineStyle: { width: 4 } }, axisTick: { show: true, length: 2 }, axisLabel: { formatter: function (v) { return v; }, textStyle: { fontSize: 8 } }, progress: { show: true, width: 4 }, detail: { formatter: function (v) { return unit; }, textStyle: { fontSize: 12, fontWeight: "normal", fontFamily: "Arial,Helvetica,sans-serif", color: "grey" //lineHeight: 16 }, valueAnimation: true }, pointer: { width: 2 } }], grid: { left: -2, right: 0, bottom: 0, top: 0 }, axisPointer: { show: false }, tooltip: { formatter: 'X:{b0} Y:{c0}', show: false }, animation: true }; chart.setOption(option) }, renderPercentChart: function (options) { let chartId = options.id let color = this.chartColor(options.color) let value = options.value let name = options.name let total = options.total if (total == null) { total = 100 } let unit = options.unit if (unit == null) { unit = "" } let max = options.max if (max != null && max <= value) { max = null } let maxColor = this.chartColor(options.maxColor) let maxName = options.maxName let chartBox = document.getElementById(chartId) if (chartBox == null) { return } let chart = this.initChart(chartBox) let option = { tooltip: { formatter: "{a}
{b} : {c}" + unit }, series: [ { name: name, max: total, type: "gauge", radius: "100%", detail: { formatter: "{value}", show: false, valueAnimation: true }, data: [ { value: value, name: name } ], pointer: { show: false }, splitLine: { show: false }, axisTick: { show: false }, axisLine: { show: true, lineStyle: { width: 4 } }, progress: { show: true, width: 4, itemStyle: { color: color } }, splitNumber: { show: false }, title: { show: false }, startAngle: 270, endAngle: -90 } ] } if (max != null) { option.series.push({ name: maxName, max: total, type: "gauge", radius: "100%", detail: { formatter: "{value}", show: false, valueAnimation: true }, data: [ { value: max, name: maxName } ], pointer: { show: false }, splitLine: { show: false }, axisTick: { show: false }, axisLine: { show: true, lineStyle: { width: 4 } }, progress: { show: true, width: 4, itemStyle: { color: maxColor, opacity: 0.3 } }, splitNumber: { show: false }, title: { show: false }, startAngle: 270, endAngle: -90 }) } chart.setOption(option) }, xRotation: function (chart, names) { let chartWidth = chart.getWidth() let width = 0 names.forEach(function (name) { width += name.length * 10 }) if (width <= chartWidth) { return null } return [40, -20] }, chartMap: {}, // dom id => chart initChart: function (dom) { let domId = dom.getAttribute("id") if (domId != null && domId.length > 0 && typeof (this.chartMap[domId]) == "object") { return this.chartMap[domId] } let instance = echarts.init(dom) window.addEventListener("resize", function () { instance.resize() }) this.chartMap[domId] = instance return instance }, encodeHTML: function (s) { s = s.replace(/&/g, "&") s = s.replace(//g, ">") s = s.replace(/"/, """) return s }, chartColor: function (color) { if (color == null || color.length == 0) { color = "#5470c6" } if (color == "red") { color = "#ee6666" } if (color == "yellow") { color = "#fac858" } if (color == "blue") { color = "#5470c6" } if (color == "green") { color = "#3ba272" } return color } } String.prototype.quoteIP = function () { let ip = this.toString() if (ip.length == 0) { return "" } if (ip.indexOf(":") < 0) { return ip } if (ip.substring(0, 1) == "[") { return ip } return "[" + ip + "]" }