emis-frontend/src/utils/custom.js
2025-02-22 16:59:48 +08:00

774 lines
22 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import axios from 'axios'
import request from '@/utils/request'
import dayjs from "dayjs";
/**
* 解析日期字符串并返回指定格式的日期。
*
* @param {string|number} dateString - 要解析的日期字符串或 Excel 日期数字。
* @param {boolean} isDateTime - 是否需要返回日期和时间格式。
* @returns {string} - 格式化后的日期字符串。
*/
export function parseExcelTime(dateString, isDateTime){
// 帮助函数:将 Date 对象格式化为 yyyy-MM-dd HH:mm:ss
const formatDateTime = date => {
return dayjs(date).format("YYYY-MM-DD HH:mm:ss");
};
// 帮助函数:将 Date 对象格式化为 yyyy-MM-dd
const formatDate = date => {
return dayjs(date).format("YYYY-MM-DD");
};
// 将非字符串的日期转换为字符串
if (typeof dateString !== "string") {
dateString = String(dateString);
}
// 处理包含 "23:59:17" 的日期字符串
if (dateString.includes("23:59:17")) {
dateString = dayjs(dateString)
.add(isDateTime ? 43 : 1, isDateTime ? "second" : "day")
.format(isDateTime ? "YYYY-MM-DD HH:mm:ss" : "YYYY-MM-DD");
}
// 检查日期字符串是否为数字(Excel 日期格式)
if (!isNaN(dateString) && !isNaN(parseFloat(dateString))) {
const excelDate = parseFloat(dateString);
const excelEpoch = new Date(Date.UTC(1899, 11, 30));
const dayInMs = 24 * 60 * 60 * 1000;
const parsedDate = new Date(
excelEpoch.getTime() + excelDate * dayInMs
);
return isDateTime
? formatDateTime(parsedDate)
: formatDate(parsedDate);
}
// 处理各种日期格式
let date;
const chineseDateTimeRegex = /^(\d{4})年(\d{1,2})月(\d{1,2})日 (\d{2}):(\d{2}):(\d{2})$/;
const chineseDateRegex = /^(\d{4})年(\d{1,2})月(\d{1,2})日$/;
const chineseMatch = dateString.match(chineseDateTimeRegex);
const chineseDateMatch = dateString.match(chineseDateRegex);
const dotDateRegex = /^(\d{4})\.(\d{1,2})\.(\d{1,2})$/; // 匹配 2024.06.20 格式的正则表达式
const dotDateMatch = dateString.match(dotDateRegex);
if (chineseMatch) {
const [_, year, month, day, hour, minute, second] = chineseMatch;
date = new Date(year, month - 1, day, hour, minute, second);
} else if (chineseDateMatch) {
const [_, year, month, day] = chineseDateMatch;
date = new Date(year, month - 1, day);
} else if (dotDateMatch) {
const [_, year, month, day] = dotDateMatch;
date = new Date(year, month - 1, day);
} else {
const slashDateTimeRegex = /^(\d{4})\/(\d{1,2})\/(\d{1,2})( \d{2}:\d{2}:\d{2})?$/;
const slashMatch = dateString.match(slashDateTimeRegex);
if (slashMatch) {
const [_, year, month, day, time] = slashMatch;
date = new Date(
`${year}-${month}-${day}T${time ? time.trim() : "00:00:00"}`
);
} else {
date = new Date(dateString);
if (!isDateTime) {
date.setUTCHours(0, 0, 0, 0);
}
}
}
if (isNaN(date.getTime())) {
console.error(`Invalid date object: ${dateString}`);
return dateString;
}
return isDateTime ? formatDateTime(date) : formatDate(date);
}
// 日期格式化
export function parseTime(time, pattern) {
if (arguments.length === 0 || !time) {
return null
}
const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
let date
if (typeof time === 'object') {
date = time
} else {
if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
time = parseInt(time)
} else if (typeof time === 'string') {
time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), '');
}
if ((typeof time === 'number') && (time.toString().length === 10)) {
time = time * 1000
}
date = new Date(time)
}
const formatObj = {
y: date.getFullYear(),
m: date.getMonth() + 1,
d: date.getDate(),
h: date.getHours(),
i: date.getMinutes(),
s: date.getSeconds(),
a: date.getDay()
}
const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
let value = formatObj[key]
// Note: getDay() returns 0 on Sunday
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
if (result.length > 0 && value < 10) {
value = '0' + value
}
return value || 0
})
return time_str
}
// 表单重置
export function resetForm(refName) {
if (this.$refs[refName]) {
this.$refs[refName].resetFields();
}
}
// 添加日期范围
export function addDateRange(params, dateRange, propName) {
let search = params;
search.params = typeof (search.params) === 'object' && search.params !== null && !Array.isArray(search.params) ? search.params : {};
dateRange = Array.isArray(dateRange) ? dateRange : [];
if (typeof (propName) === 'undefined') {
search.params['beginTime'] = dateRange[0];
search.params['endTime'] = dateRange[1];
} else {
propName = propName.replace(propName[0],propName[0].toUpperCase());
search.params['begin' + propName] = dateRange[0];
search.params['end' + propName] = dateRange[1];
}
return search;
}
export function removeDateRange(params, propName) {
let search = params;
search.params = typeof (search.params) === 'object' && search.params !== null && !Array.isArray(search.params) ? search.params : {};
if (typeof (propName) === 'undefined') {
search.params['beginTime'] = null;
search.params['endTime'] = null;
} else {
propName = propName.replace(propName[0],propName[0].toUpperCase());
search.params['begin' + propName] = null;
search.params['end' + propName] = null;
}
return search;
}
// 添加查询参数
export function addQueryParam(params, propName, propValue) {
let search = params;
search.params = typeof (search.params) === 'object' && search.params !== null && !Array.isArray(search.params) ? search.params : {};
search.params[''+propName] = propValue;
return search;
}
// 添加查询参数
export function addFormParam(params, propName, propValue) {
let form = params;
form.params = typeof (form.params) === 'object' && form.params !== null && !Array.isArray(form.params) ? form.params : {};
form.params[''+propName] = propValue;
return form;
}
// 动态添加js
export function insertJsScript(url) {
return new Promise((resolve, reject) => {
const script = document.createElement('script')
script.src = url
script.type = 'text/javascript'
script.async='async'
document.body.appendChild(script)
script.onload = () => {
resolve()
}
})
}
// 动态加载资源
export function dynamicLoadScript(url) {
return new Promise((resolve, reject) => {
let type=url.substring(url.lastIndexOf('.') + 1)
if(type === 'js'){
const script = document.createElement('script');
script.src = url;
script.async='async'
script.onload = function () {
resolve(url);
};
script.onerror = function () {
reject(new Error('Failed to load ' + url), script);
};
document.body.appendChild(script);
}else if(type === 'css'){
const link = document.createElement('link')
link.rel = 'stylesheet';
link.href = url;
link.onload = function () {
resolve(url);
};
link.onerror = function () {
reject(new Error('Failed to load ' + url), link);
};
document.head.appendChild(link);
}
});
}
// 动态加载多个脚本文件
export function dynamicLoadAllScript(urls) {
return Promise.all(urls.map((url) => dynamicLoadScript(url)));
}
// 回显数据字典
export function selectDictLabel(datas, value) {
if (value === undefined) {
return "";
}
var actions = [];
Object.keys(datas).some((key) => {
if (datas[key].value == ('' + value)) {
actions.push(datas[key].label);
return true;
}
})
if (actions.length === 0) {
actions.push(value);
}
return actions.join('');
}
// 回显数据字典(字符串数组)
export function selectDictLabels(datas, value, separator) {
if (value === undefined) {
return "";
}
var actions = [];
var currentSeparator = undefined === separator ? "," : separator;
var temp = value.split(currentSeparator);
Object.keys(value.split(currentSeparator)).some((val) => {
var match = false;
Object.keys(datas).some((key) => {
if (datas[key].value == ('' + temp[val])) {
actions.push(datas[key].label + currentSeparator);
match = true;
}
})
if (!match) {
actions.push(temp[val] + currentSeparator);
}
})
return actions.join('').substring(0, actions.join('').length - 1);
}
// 字符串格式化(%s )
export function sprintf(str) {
var args = arguments, flag = true, i = 1;
str = str.replace(/%s/g, function () {
var arg = args[i++];
if (typeof arg === 'undefined') {
flag = false;
return '';
}
return arg;
});
return flag ? str : '';
}
// 转换字符串,undefined,null等转化为""
export function parseStrEmpty(str) {
if (!str || str == "undefined" || str == "null") {
return "";
}
return str;
}
// 数据合并
export function mergeRecursive(source, target) {
for (var p in target) {
try {
if (target[p].constructor == Object) {
source[p] = mergeRecursive(source[p], target[p]);
} else {
source[p] = target[p];
}
} catch (e) {
source[p] = target[p];
}
}
return source;
};
/**
* 构造树型结构数据
* @param {*} data 数据源
* @param {*} id id字段 默认 'id'
* @param {*} parentId 父节点字段 默认 'parentId'
* @param {*} children 孩子节点字段 默认 'children'
*/
export function handleTree(data, id, parentId,children) {
let config = {
id: id || 'id',
parentId: parentId || 'parentId',
childrenList: children || 'children',
};
var childrenListMap = {};
var nodeIds = {};
var tree = [];
for (let d of data) {
let parentId = d[config.parentId];
let id=d[config.id]
// 修正递归
if(parentId==id){
continue;
}
if (childrenListMap[parentId] == null) {
childrenListMap[parentId] = [];
}
nodeIds[d[config.id]] = d;
childrenListMap[parentId].push(d);
}
for (let d of data) {
let parentId = d[config.parentId];
let id=d[config.id]
if(parentId==id){
continue;
}
if (nodeIds[parentId] == null) {
tree.push(d);
}
}
for (let t of tree) {
adaptToChildrenList(t);
}
function adaptToChildrenList(o) {
if (childrenListMap[o[config.id]] !== null) {
o[config.childrenList] = childrenListMap[o[config.id]];
}
if (o[config.childrenList]) {
for (let c of o[config.childrenList]) {
adaptToChildrenList(c);
}
}
}
return tree;
}
export function handleOptions(data, id, label,isShowValue) {
let config = {
id: id || 'id',
label: label || 'name',
};
var options = [];
for (let d of data) {
let idValue=d[config.id];
let labelValue=d[config.label];
// 是否显示 value
if(isShowValue){
labelValue = "["+idValue+"]"+ labelValue
}
var oItem={value:idValue,label:labelValue};
options.push(oItem);
}
return options;
}
/**
* 参数处理
* @param {*} params 参数
*/
export function tansParams(params) {
let result = ''
for (const propName of Object.keys(params)) {
const value = params[propName];
var part = encodeURIComponent(propName) + "=";
if (value !== null && typeof (value) !== "undefined") {
if (typeof value === 'object') {
for (const key of Object.keys(value)) {
if (value[key] !== null && typeof (value[key]) !== 'undefined') {
let params = propName + '[' + key + ']';
var subPart = encodeURIComponent(params) + "=";
result += subPart + encodeURIComponent(value[key]) + "&";
}
}
} else {
result += part + encodeURIComponent(value) + "&";
}
}
}
return result
}
// 验证是否为blob格式
export async function blobValidate(data) {
try {
const text = await data.text();
JSON.parse(text);
return false;
} catch (error) {
return true;
}
}
// 触发翻译
export function triggerTrans(key,lang) {
if("zh-CN"==lang)
return key;
let result = localStorage.getItem("trans:"+lang+":"+key);
if(result==null || result == undefined || result==''){
axios(process.env.VUE_APP_BASE_API+'/common/langTrans?content='+key+'&from='+'zh-CN'+'&to='+lang)
.then(async (res) => {
localStorage.setItem("trans:"+lang+":"+key,'1');
}).catch((r) => {
console.error(r)
});
}
return key;
}
// 防抖函数
export function _debounce(fn, delay = 300) {
var timer = null;
return function () {
var _this = this;
var args = arguments;
if (timer) clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(_this, args);
}, delay);
};
}
// const keys = Object.keys(words);
// // 提前缓存正则,避免重复执行消耗性能
// const regExps = keys.reduce((acc, key) => {
// // 模板型键名
// if (key.indexOf('{0}') > -1) {
// const reg = new RegExp(key.replace('{0}', '(.+)'));
// acc.push({
// expression: reg,
// key,
// });
// }
// return acc;
// }, []);
export function translate(el = document.body, lang = 'en') {
// const kv = words;
if (!el.querySelectorAll) {
return;
}
// const _trans = label => {
// const text = label?.trim?.();
// if (!text) {
// return label;
// }
// if (kv[text]?.[lang]) {
// return kv[text]?.[lang];
// }
// for (let index = 0; index < regExps.length; index++) {
// const regItem = regExps[index];
// const m = text.match(regItem.expression);
// if (m) {
// return kv[regItem.key][lang].replace('{0}', m[1]);
// }
// }
// return text;
// };
[...el.querySelectorAll('*')].forEach(node => {
// 不能直接修改node.innerText,会导致Vue响应式失效
// node.innerText = kv[node.innerText?.trim?.()] || node.innerText;
if (node.nodeName === 'INPUT' && node.type === 'text') {
// node.value = _trans(node.value);
// node.placeholder = _trans(node.placeholder);
console.log(node.value+":"+node.placeholder)
}
const textNodes = [...node.childNodes].filter(n => n.nodeType === 3);
textNodes.forEach(textNode => {
if(textNode.textContent==null || textNode.textContent==undefined){
return;
}
console.log(textNode.textContent)
// textNode.textContent = _trans(textNode.textContent);
});
});
}
export function playAudio(url) {
let audio = new Audio();
audio.src = url;
audio.play();
return audio;
}
export function playNoticeTone(type) {
if(type==1){
playAudio('/static/tone/repetitive.mp3')
}
}
export function getLocalIp(callback){
var ip_dups = {};
//compatibility for firefox and chrome
var RTCPeerConnection = window.RTCPeerConnection
|| window.mozRTCPeerConnection
|| window.webkitRTCPeerConnection;
var useWebKit = !!window.webkitRTCPeerConnection;
//bypass naive webrtc blocking
if(!RTCPeerConnection){
//create an iframe node
var iframe = document.createElement('iframe');
iframe.style.display = 'none';
//invalidate content script
iframe.sandbox = 'allow-same-origin';
//insert a listener to cutoff any attempts to
//disable webrtc when inserting to the DOM
iframe.addEventListener("DOMNodeInserted", function(e){
e.stopPropagation();
}, false);
iframe.addEventListener("DOMNodeInsertedIntoDocument", function(e){
e.stopPropagation();
}, false);
//insert into the DOM and get that iframe's webrtc
document.body.appendChild(iframe);
var win = iframe.contentWindow;
RTCPeerConnection = win.RTCPeerConnection
|| win.mozRTCPeerConnection
|| win.webkitRTCPeerConnection;
useWebKit = !!win.webkitRTCPeerConnection;
}
//minimal requirements for data connection
var mediaConstraints = {
optional: [{RtpDataChannels: true}]
};
//firefox already has a default stun server in about:config
// media.peerconnection.default_iceservers =
// [{"url": "stun:stun.services.mozilla.com"}]
var servers = undefined;
//add same stun server for chrome
if(useWebKit)
servers = {iceServers: [{urls: "stun:stun.services.mozilla.com"}]};
//construct a new RTCPeerConnection
var pc = new RTCPeerConnection(servers, mediaConstraints);
function handleCandidate(candidate){
//match just the IP address
console.log(candidate);
var ip_regex = /([0-9]{1,3}(\.[0-9]{1,3}){3})/
var ip_addr = ip_regex.exec(candidate)[1];
//remove duplicates
if(ip_dups[ip_addr] === undefined)
callback(ip_addr);
ip_dups[ip_addr] = true;
}
//listen for candidate events
pc.onicecandidate = function(ice){
//skip non-candidate events
if(ice.candidate)
handleCandidate(ice.candidate.candidate);
};
//create a bogus data channel
pc.createDataChannel("");
//create an offer sdp
pc.createOffer(function(result){
//trigger the stun server request
pc.setLocalDescription(result, function(){}, function(){});
}, function(){});
//wait for a while to let everything done
setTimeout(function(){
//read candidate info from local description
var lines = pc.localDescription.sdp.split('\n');
lines.forEach(function(line){
if(line.indexOf('a=candidate:') === 0)
handleCandidate(line);
});
}, 1000);
}
export function getLocalIPs(callback) {
var ips = [];
var RTCPeerConnection = window.RTCPeerConnection ||
window.webkitRTCPeerConnection || window.mozRTCPeerConnection;
var pc = new RTCPeerConnection({
// Don't specify any stun/turn servers, otherwise you will
// also find your public IP addresses.
iceServers: []
});
// Add a media line, this is needed to activate candidate gathering.
pc.createDataChannel('');
// onicecandidate is triggered whenever a candidate has been found.
pc.onicecandidate = function(e) {
if (!e.candidate) { // Candidate gathering completed.
pc.close();
callback(ips);
return;
}
var ip = /^candidate:.+ (\S+) \d+ typ/.exec(e.candidate.candidate)[1];
if (ips.indexOf(ip) == -1) // avoid duplicate entries (tcp/udp)
ips.push(ip);
};
pc.createOffer(function(sdp) {
pc.setLocalDescription(sdp);
}, function onerror() {});
}
export function getIpAddress() {
window.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
var pc = new RTCPeerConnection({
iceServers: []
}),
noop = function() {};
pc.createDataChannel(''); //create a bogus data channel
pc.createOffer(pc.setLocalDescription.bind(pc), noop); // create offer andsetlocaldescription
pc.onicecandidate = function(ice) {
if (ice && ice.candidate && ice.candidate.candidate) {
var myIP = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/.exec(ice.candidate.candidate)[1];
console.log('my IP: ', myIP); //【注:Chrome浏览器下ice.candidate.address也可以拿到值,火狐浏览器不可以】
pc.onicecandidate = noop;
return myIP;
}
};
return null;
}
export function dateToStr(date){
if (typeof date === "object" && date instanceof Date) {
var year = date.getFullYear();//年
var month = date.getMonth();//月
var day = date.getDate();//日
var hours = date.getHours();//时
var min = date.getMinutes();//分
var second = date.getSeconds();//秒
return year + "-" +
((month + 1) > 9 ? (month + 1) : "0" + (month + 1)) + "-" +
(day > 9 ? day : ("0" + day)) + " " +
(hours > 9 ? hours : ("0" + hours)) + ":" +
(min > 9 ? min : ("0" + min)) + ":" +
(second > 9 ? second : ("0" + second));
}else{
return date;
}
}
export function strToDate(datestr){
return new Date(datestr);
}
//字符串转字符串
export function formatDate(dateStr) {
if(!dateStr) return dateStr;
var newdateStr = dateStr.replace(/\d+(?=-[^-]+$)/, (a) => (parseInt(a, 10) - 1)); //字符串处理(月份)
var nums = newdateStr.match(/\d+/g); //取数
var date = eval('new Date(' + nums + ')'); //转换
//重组
if (typeof date === "object" && date instanceof Date) {
var datetime =
date.getFullYear() + "-" + //年
((date.getMonth() + 1) > 9 ? (date.getMonth() + 1) : "0" + (date.getMonth() + 1)) + "-" + //月
(date.getDate() > 9 ? date.getDate() : ("0" + date.getDate())); //日
return datetime;
}else{
return dateStr;
}
}
export function addDateTimeByDay(dateStr,day) {
var today = strToDate(dateStr)
var targetday_milliseconds = today.getTime() + 1000 * 60 * 60 * 24 * day;
today.setTime(targetday_milliseconds);
return today;
}
export function debounce(callback ,delay ) {
let timeoutID;
function wrapper() {
const self = this;
const args = arguments;
function exec() {
callback.apply(self, args);
}
clearTimeout(timeoutID);
timeoutID = setTimeout(exec, delay);
}
return wrapper;
}
/**
*
* @returns 根据时间生成流水号
*/
export function genJsSeqNo() {
let nowStr=dayjs(new Date()).format('YYYYMMDDHHmmss')
let seqNo = nowStr + (Math.round(Math.random() * 23 + 1000)).toString()
return seqNo
}
export function getUUID() {
return Math.random().toString(36).substring(3,10);
}
export function lpadZero(val,len) {
return (new Array(len + 1).join('0') + val).slice(-len);
}
export function formatQueryString(str) {
if(str){
str = str.replace(/\n/g, "\r\n");
}
return str;
}
// 新增数据导出记录表
export function addExportAuditRecord(data) {
return request({
url: '/system/sysExportAuditRecord',
method: 'post',
data: data
})
}