/* * @Company: hugeInfo * @Author: ldh * @Date: 2022-02-16 11:57:54 * @LastEditTime: 2025-06-10 17:40:29 * @LastEditors: lwh * @Version: 1.0.0 * @Description: 公共模块方法 */ import React, { useEffect, useState } from 'react'; import CryptoJS from 'crypto-js'; import { Modal, message, Empty } from 'antd'; import { Modal as ArcoModal } from '@arco-design/web-react'; import * as apiHandler from '../api/apiHandler'; import { debug, web, test } from '../api/appUrl'; import moment from 'moment'; import { pdf, jpg, file, word, excel } from '../assets/images/icon'; import { empty } from '@/assets/images'; export const isDebug = false; // 是否开发环境 export const isTest = true; // 是否测试环境 export const appUrl = isDebug ? debug : isTest ? test : web; // api export const title = isDebug ? '(矛盾纠纷应用测试版)' : isTest ? '(矛盾纠纷应用测试版)' : '(矛盾纠纷应用)'; // api export const windowUrl = isDebug ? '' : isTest ? 'index.html#' : 'index.html#'; const province = ['19']; // 当前用户省id, 默认广东19,海南23 export const myMoment = moment; // 省市区(县)街道社区的下拉框,地理信息文件通过html引入 export const locationOption = () => { // eslint-disable-next-line no-undef return locationSelect; // return province.map((x) => locationSelect[x][0]); }; // aes加密,接口请求数据加密,数据返回解密 const aes_key = 'tVTShp12fFVkNBxV'; const aes_iv = 'PKCS5Padding'; // 下拉框 export { default as options } from './selectOption'; export { default as caseTypeSelect } from './caseTypeSelect'; export { default as caseOptions } from './caseCauseSelect'; export { default as threeLocationSelect } from './threeLocationSelect'; // icon 对照表 export { default as iconContrast } from './icon'; // 加密 export function aes_encrypt(text) { let value = text ? text : ''; return CryptoJS.AES.encrypt(value, CryptoJS.enc.Utf8.parse(aes_key), { iv: CryptoJS.enc.Utf8.parse(aes_iv), mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7, }).toString(); } // 解密 export function aes_decrypt(text) { let value = text ? text : ''; let decrypted = CryptoJS.AES.decrypt(value, CryptoJS.enc.Utf8.parse(aes_key), { iv: CryptoJS.enc.Utf8.parse(aes_iv), mode: CryptoJS.mode.ECB, padding: CryptoJS.pad.Pkcs7, }); return JSON.parse(decrypted.toString(CryptoJS.enc.Utf8) || 'null'); } // axios export const ax = apiHandler; // 缓存 export function setLocal(name, value) { localStorage.setItem(name, JSON.stringify(value || '')); } export function getLocal(name) { let data = localStorage.getItem(name); return !data ? null : JSON.parse(data); } export function clearLocal(name) { return name ? localStorage.removeItem(name) : localStorage.clear(); } export function setSessionStorage(name, value) { sessionStorage.setItem(name, JSON.stringify(value || '')); } export function getSessionStorage(name) { let data = sessionStorage.getItem(name); return !data ? null : JSON.parse(data); } export function clearSessionStorage(name) { return name ? sessionStorage.removeItem(name) : sessionStorage.clear(); } // 地址栏截取 export function getQueryString(name) { let result = window.location.href.match(new RegExp('[?&]' + name + '=([^&]+)', 'i')); if (!result || result.length < 1) { return null; } return decodeURI(result[1]); } // 逗号隔开数字 export function thousands(num) { if (num) { var str = num.toString(); var reg = str.indexOf('.') > -1 ? /(\d)(?=(\d{3})+\.)/g : /(\d)(?=(?:\d{3})+$)/g; return str.replace(reg, '$1,'); } else { return 0; } } // export function getQueryObj(obj) { let strs = ''; for (var str in obj) { strs += str + '=' + obj[str] + '&'; } return strs; } // api错误提示 let errorNum = false; // 控制错误信息不重复弹出 export function catchApiError({ content, loginStatus }) { if (errorNum) return false; errorNum = true; let handleOkFunc = loginStatus === 'lose' ? () => { clearLocal('customerSystemUser'); clearSessionStorage(); errorNum = false; window.location.href = '#/customerSystem/login'; } : () => (errorNum = false); if (content && content?.indexOf('无操作权限') !== -1) { handleOkFunc = () => window.history.back(); } return Modal.error({ title: '错误提示', okText: '知道了', cancelText: null, onOk: handleOkFunc, content, }); } export function modalInfo({ type = 'confirm', title = '提示', content, okText = '确定', cancelText = '取消操作', onCancel, onOk, // icon }) { return Modal[type]({ title: title, content: content, onCancel: onCancel, onOk: onOk, okText: type !== 'confirm' ? '我知道了' : okText, cancelText, closable: true, maskClosable: true, // icon:icon }); } // arco弹窗 export function arcoModalInfo({ type = 'confirm', icon, title = '提示', content, okText = '确定', cancelText = '取消操作', closable = true, style, onCancel, onOk, footer, }) { return ArcoModal[type]({ title: title, content: content, onCancel: onCancel, onOk: onOk, okText: type !== 'confirm' ? '我知道了' : okText, cancelText, style, closable: closable, maskClosable: true, icon: icon, footer, }); } // 全局提示 export function info({ type, content, duration, onClose }) { return message[type](content, duration || 3, onClose); } export function infoSuccess({ content }) { return info({ type: 'success', content }); } // 手机号码正则 export const mobileRegExp = new RegExp('^1([0-9][0-9]|[0-9][0-9]|[0-9][0-9]|[0-9][0-9]|[0-9][0-9])\\d{8}$', 'g'); // 只能输入数字和英文 export const accRegExp = new RegExp('^[A-Za-z0-9]+$', 'g'); // 生成案件,当事人,代理人等随机唯一的id export function getBusinessId() { let four = `${parseInt(Math.random() * 10)}${parseInt(Math.random() * 10)}${parseInt(Math.random() * 10)}${parseInt(Math.random() * 10)}`; return `${moment().format('YYYYMMDDHHmmss')}${four}`; } // 时间格式化 export function timeFormat(value, isValue) { return !!value ? moment(value).format('YYYY-MM-DD HH:mm:ss') : isValue ? '' : '-'; } export function minuteFormat(value, isValue) { return !!value ? moment(value).format('YYYY-MM-DD HH:mm') : isValue ? '' : '-'; } export function dateFormat(value) { return !!value ? moment(value).format('YYYY-MM-DD') : '-'; } export function myTimeFormat(value, str) { return !!value ? moment(value).format(str) : '-'; } // RangePicker 查询条件时间范围的预设标签 export function shortcutsList() { return [ { text: '上月', value: () => [myMoment().subtract(1, 'months').startOf('month'), myMoment().subtract(1, 'months').endOf('month')] }, { text: '上周', value: () => [myMoment().subtract(1, 'weeks').startOf('week'), myMoment().subtract(1, 'weeks').endOf('week')] }, { text: '本月', value: () => [myMoment().startOf('month'), myMoment().endOf('month')] }, { text: '本周', value: () => [myMoment().startOf('week'), myMoment().endOf('week')] }, { text: '本年度', value: () => [myMoment().startOf('year'), myMoment().endOf('year')] }, { text: '上一年度', value: () => [myMoment().subtract(1, 'years').startOf('year'), myMoment().subtract(1, 'years').endOf('year')] }, ]; } // 计算时间范围的中间间隔 export function calculateTimeDifference(startTime, endTime) { const start = moment(startTime); const end = moment(endTime); const duration = moment.duration(end.diff(start)); if (duration.asHours() <= 2) { return `${duration.asMinutes()} 分钟`; } else if (duration.asHours() <= 24) { return `${duration.asHours()} 小时`; } else { return `${duration.asDays()} 天`; } } /** * 将小时数转换为天数和小时数 * @param {number} hours - 输入的小时数 * @returns {string} - 返回格式化的字符串,例如 "X天Y小时" 或 "999+天" */ export function formatHoursToDaysAndHours(hours) { if (hours <= 24) { return `${hours}小时`; } const days = Math.floor(hours / 24); const remainingHours = hours % 24; if (days >= 999) { return '999+天'; } else if (days > 0) { return `${days}天${remainingHours}小时`; } else { return `${remainingHours}小时`; } } // moment时间格式转 标准格式 并拆分为开始和结束字段 export function changeTimeFormat(obj, timeN, timeS, timeE) { const timeArr = obj[timeN] || []; obj[timeS] = timeArr[0]?.format('YYYY-MM-DD') || ''; obj[timeE] = timeArr[1]?.format('YYYY-MM-DD') || ''; delete obj[timeN]; } export function changeTimNeweFormat(obj, timeN, timeS, timeE) { if (!obj[timeN]) { delete obj[timeN]; } else { const timeArr = obj[timeN] || []; obj[timeS] = timeArr[0] || ''; obj[timeE] = timeArr[1] || ''; delete obj[timeN]; } } // 查询时cascader字段变换的展示 export function searchCascader(obj, searchKey, firstLevel, keyList) { // 第一层级 queCity 第二层级 queArea 第三层级 queRoad 第四层级 queVillage // firstLevel 用户的最高权限属于哪一级 1:市,2:区,3:街道,4:村居 if (!obj[searchKey]) { delete obj[searchKey]; } else { const queCodeLength = obj[searchKey].length; const list = keyList.filter((i, idx) => idx >= Number(firstLevel || 1) - 1); let key = list[queCodeLength - 1]; obj[key] = obj[searchKey][queCodeLength - 1]; key !== searchKey && delete obj[searchKey]; } } // 将字符串转换成数组(问题属地专用) export function convertStringToArray(inputString) { if (typeof inputString !== 'string') { throw new Error('Input must be a string'); } const parts = inputString.split('-'); const result = []; for (let i = 1; i <= parts.length; i++) { result.push(parts.slice(0, i).join('-')); } return result; } export function changeSearchArray(obj, timeN, timeS, timeE, timeH) { const timeArr = obj[timeN] || []; obj[timeS] = timeArr[0] || ''; obj[timeE] = timeArr[1] || ''; obj[timeH] = timeArr[2] || ''; delete obj[timeN]; } // 将对象转成url参数 export function useQueryParams(params) { const queryParams = Object.entries(params) .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`) .join('&'); return queryParams; } // 标准格式转moment 把开始和结束字段合并成一个字段 用于回显表单时间范围 export function changeTimeMoment(obj, timeN, timeS, timeE) { if (typeof obj[timeS] === 'string' && typeof obj[timeE] === 'string' && !!obj[timeS] && !!obj[timeE]) { obj[timeN] = []; obj[timeN][0] = moment(obj[timeS], 'YYYY-MM-DD'); obj[timeN][1] = moment(obj[timeE], 'YYYY-MM-DD'); delete obj[timeS]; delete obj[timeE]; } } //获取时间差,返回表格时限组件 export function getDiffTime(timeLimit) { if (timeLimit) { // 转换为Date对象 let targetDate = new Date(timeLimit); // 获取当前时间 let now = new Date(); // 计算时间差(毫秒) let diff = Math.abs(targetDate - now); // 将时间差转换为小时和分钟 let hours = Math.floor(diff / (1000 * 60 * 60)); let minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); // 比较两个时间 if (targetDate.getTime() <= now.getTime()) { return ( <> {`超${hours}小时${minutes}分钟`} ); } else { return ( {`剩${hours}小时${minutes}分钟`} ); } } else { return -; } } // 自动退回剩余小时数 export function getHours(endTime, startTime = new Date()) { if (!endTime) return { hours: 0, min: 0 }; let end = moment(endTime), start = moment(startTime), minDiff = end.diff(start, 'minute'), hoursDiff = minDiff / 60, min = minDiff % 60; return { isNegativeNum: hoursDiff < 12 ? true : false, hours: Math.floor(hoursDiff) < 0 ? 0 : Math.floor(hoursDiff), min, }; } //计算回复时限 export function getRemainingTime(supTime, replyTerm) { if (!supTime || !replyTerm) return { hours: 0, min: 0 }; const endTime = moment(supTime).add(replyTerm, 'hours'); const currentTime = moment(); const minDiff = endTime.diff(currentTime, 'minutes'); const hoursDiff = minDiff / 60; const min = minDiff % 60; return { hours: Math.max(0, Math.floor(hoursDiff)), }; } // 计算两个时间差 export function getFunnel(startTime, endTime = new Date()) { let end = moment(endTime), start = moment(startTime), timeDiff = end.diff(start, 'seconds'); return timeDiff; } // 秒数换算为时分秒 export function getDuration(second) { let hours = Math.floor(second / 3600); let minutes = Math.floor((second % 3600) / 60); let seconds = Math.floor((second % 3600) % 60); hours = hours < 10 ? `0${hours}` : hours; minutes = minutes < 10 ? `0${minutes}` : minutes; seconds = seconds < 10 ? `0${seconds}` : seconds; let duration = hours + ':' + minutes + ':' + seconds; return duration; } // 内容输入长度超出判断 小框64字节 大框512字节 特殊字段特殊匹配 export function isLengthExceeded(str, type, special) { const specialList = [{ key: 'addr', length: 3 }]; let len = 0, chrLen = 0, result = false; if (!!special) { specialList.map((item) => { if (special === item.key) { len = item.length; } }); } else { if (type === 'Input' || type === 'Select' || type === 'RangePicker' || type === 'TreeSelect') { len = 64; } else if (type === 'TextArea') { len = 512; } } chrLen = str.replace(/[^\x00-\xff]/g, '**').length; if (chrLen > len) { result = true; } else { result = false; } return result; } export const ExpandableText = ({ text, numString = 100, collapsedText = '展开全部', expandedText = '折叠' }) => { const [isExpanded, setIsExpanded] = useState(false); const [show, setShow] = useState(false); const toggleText = () => { setIsExpanded(!isExpanded); }; useEffect(() => { if (text?.length <= numString) { setShow(false); setIsExpanded(true); } else { setShow(true); setIsExpanded(false); } }, [text, numString]); return (
{isExpanded ? text : text.substring(0, numString) + '...'} {show && ( {isExpanded ? expandedText : collapsedText} )}
); }; export function formatNumber(inttt) { let num = Number(inttt); // 检查是否为整数或0 if (Number.isInteger(num) || num === 0) { return num; } // 保留两位小数,不足两位补0,超过两位则保留两位小数,并四舍五入 return num.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,'); } // 公共empty export function MyEmpty(value = {}) { return ; } //新empty export function MyNewEmpty(value = {}) { return {value.description || '暂无数据'}} style={value.style} />; } // 睡眠 export function sleep(timeout = 500) { return new Promise((resolve) => setTimeout(resolve, timeout)); } // 判断文件格式 export function fileType(value, isName) { let result = ''; let name = ''; if (!value || value === '22_00017-6') { result = pdf; name = 'PDF'; } else if (value === '22_00017-3') { result = jpg; name = '图片'; } else if (value === '22_00017-4') { result = word; name = 'Word'; } else if (value === '22_00017-4') { result = excel; name = 'Excel'; } else { result = file; } return isName ? name : result; } // 超出文字使用省略号 export function ellipsis(value, len) { if (!value) return ''; if (value.length > len) { return value.slice(0, len) + '...'; } return value; } // 显示99+ export function showMoreNum(value) { return Number(value || 0) > 99 ? '99+' : value || 0; } // 清除字符串中的空格,用于判断是否为空 export function verifyEmpty(value) { return value?.replace(/\s+/g, ''); } // 获取元素距离可视区域顶部、左部的距离 export const getOffset = (ele) => { var top = ele.offsetTop; var left = ele.offsetLeft; while (ele.offsetParent) { ele = ele.offsetParent; if (window.navigator.userAgent.indexOf('MSTE 8') > -1) { top += ele.offsetTop; left += ele.offsetLeft; } else { top += ele.offsetTop + ele.clientTop; left += ele.offsetLeft + ele.clientLeft; } } return { left: left, top: top, }; }; export const getSize = () => { let windowW, windowH, contentH, contentW, scrollT; windowH = window.innerHeight; windowW = window.innerWidth; scrollT = document.documentElement.scrollTop || document.body.scrollTop; contentH = document.documentElement.scrollHeight > document.body.scrollHeight ? document.documentElement.scrollHeight : document.body.scrollHeight; contentW = document.documentElement.scrollWidth > document.body.scrollWidth ? document.documentElement.scrollWidth : document.body.scrollWidth; return { windowW, windowH, contentH, contentW, scrollT, }; }; export function getGenderByIdCard(idCard) { if (typeof idCard !== 'string' || idCard.length !== 18) { return; } const genderCode = parseInt(idCard.charAt(16), 10); return genderCode % 2 === 1 ? '男' : '女'; } export function getAgeByIdCard(idCard) { if (typeof idCard !== 'string' || idCard.length !== 18) { return; } const birthDate = moment(idCard.substring(6, 14), 'YYYYMMDD'); const today = moment(); const age = today.diff(birthDate, 'years'); return age; } //身份号码位数及格式检验 export function checkIdCard(idcard) { var idNum = idcard || ''; var re; var len = idNum.length; //身份证位数检验 if (len != 15 && len != 18) { return false; } else if (len == 15) { re = new RegExp(/^(\d{6})()?(\d{2})(\d{2})(\d{2})(\d{3})$/); return false; } else { re = new RegExp(/^(\d{6})()?(\d{4})(\d{2})(\d{2})(\d{3})([0-9xX])$/); } var area = { 11: '北京', 12: '天津', 13: '河北', 14: '山西', 15: '内蒙古', 21: '辽宁', 22: '吉林', 23: '黑龙江', 31: '上海', 32: '江苏', 33: '浙江', 34: '安徽', 35: '福建', 36: '江西', 37: '山东', 41: '河南', 42: '湖北', 43: '湖南', 44: '广东', 45: '广西', 46: '海南', 50: '重庆', 51: '四川', 52: '贵州', 53: '云南', 54: '西藏', 61: '陕西', 62: '甘肃', 63: '青海', 64: '宁夏', 65: '新疆', 71: '台湾', 81: '香港', 82: '澳门', 83: '台湾', 91: '国外', }; var idcard_array = new Array(); idcard_array = idNum.split(''); //地区检验 if (area[parseInt(idNum.substr(0, 2))] == null) { return false; } //出生日期正确性检验 var a = idNum.match(re); if (a != null) { if (len == 15) { var DD = new Date('19' + a[3] + '/' + a[4] + '/' + a[5]); var flag = DD.getYear() == a[3] && DD.getMonth() + 1 == a[4] && DD.getDate() == a[5]; } else if (len == 18) { var DD = new Date(a[3] + '/' + a[4] + '/' + a[5]); var flag = DD.getFullYear() == a[3] && DD.getMonth() + 1 == a[4] && DD.getDate() == a[5]; } if (!flag) { return false; } //检验校验位 if (len == 18) { var S = (parseInt(idcard_array[0]) + parseInt(idcard_array[10])) * 7 + (parseInt(idcard_array[1]) + parseInt(idcard_array[11])) * 9 + (parseInt(idcard_array[2]) + parseInt(idcard_array[12])) * 10 + (parseInt(idcard_array[3]) + parseInt(idcard_array[13])) * 5 + (parseInt(idcard_array[4]) + parseInt(idcard_array[14])) * 8 + (parseInt(idcard_array[5]) + parseInt(idcard_array[15])) * 4 + (parseInt(idcard_array[6]) + parseInt(idcard_array[16])) * 2 + parseInt(idcard_array[7]) * 1 + parseInt(idcard_array[8]) * 6 + parseInt(idcard_array[9]) * 3; var Y = S % 11; var M = 'F'; var JYM = '10X98765432'; var M = JYM.substr(Y, 1); //判断校验位 //检测ID的校验位 if (M == idcard_array[17]) { return true; } else { return false; } } } else { return false; } return true; } export function validateCertiNo(certiType, certiNo) { const patterns = { '09_00015-12': /^[GDEHSMP]\d{8}$/i, // 中国护照:以G、D、E、H、S、M、P开头,后面8位数字 '09_00015-13': /^[A-Z0-9]{5,15}$/i, // 外国护照:5-15位字母或数字 '09_00015-14': /^[HM]\d{8,10}$/i, // 港澳通行证:H或M开头,后面8到10位数字 '09_00015-16': /^\d{8}$/, // 台湾通行证:8位数字 }; if (!patterns[certiType]) { return false; } if (!patterns[certiType].test(certiNo)) { return false; } return true; }