import AddressJson from '../json/Address.json'

/**
 * 通用工具类</br>
 * 引用方式：<b>this.TJUtil.&lt;method_name&gt;</b></br>
 * 其中&lt;method_name&gt;包括：
 * 
 * @property {} <b>通用处理</b>
 * @property {method} fillUrlArgments(url,arg1,arg2,arg3,arg4) 将URL地址中的{}参数替换为实际值，最多4个参数<br/>
 *    参数： url = 待处理的URL地址<br/>
 *           &emsp;&emsp;&emsp;&ensp;arg1 = string 实际值参数1<br/>
 *           &emsp;&emsp;&emsp;&ensp;arg2 = string 实际值参数2<br/>
 *           &emsp;&emsp;&emsp;&ensp;arg3 = string 实际值参数3<br/>
 *           &emsp;&emsp;&emsp;&ensp;arg4 = string 实际值参数4<br/>
 *    返回： string = 处理后的url字符串<br/>
 * 
 * @Author: panqb
 * @Date: 2026-5-2 17:24:31
 * @LastEditTime: 
 */
let TJUtil = {
    /**
     * @Description: 将map转换为数组列表
     * 调用示例： map2List(map, true, 'value', 'label')
     * @Author: panqb
     * @Date: 2026-5-4 15:10:54
     * @param {object} map 待处理的map对象
     * @param {boolean} minus1First 是否将key=-1的条目放在第1条
     * @param {string} keyName 转换后的key名称
     * @param {string} valueName 转换后的value名称
     * @return {string} 转换生成的数组列表
     */
    map2List(map, minus1First = true, keyName = 'key', valueName = 'value') {
        if (!map) return [];
        let list = [];
        for (let key in map) {
            let entry = {};
            entry[keyName] = key;
            entry[valueName] = map[key];
            if (key == -1 && minus1First) {
                list.unshift(entry);
            } else {
                list.push(entry);
            }
        }
        return list;
    },
    /**
     * @Description: 判断两个数据是否相等
     * @Author: panqb
     * @Date: 2026-5-4 20:49:01
     * @param {object/array/function/string/number} obj1 比对数据1
     * @param {object/array/function/string/number} obj2 比对数据2
     * @return true/false - 相同/不相同
     */
    equals(obj1, obj2) {
        const classNameA = toString.call(obj1);
        const classNameB = toString.call(obj2);
        // 如果数据类型不相等，则返回false
        if (classNameA !== classNameB) {
            return false;
        }

        switch (classNameA) {
            case '[object Object]':
                return this.compareTwoObjectsAreEqual(obj1, obj2);
            case '[object Array]':
                return this.compareTwoArraysAreEqual(obj1, obj2);
            case '[object Function]':
                return obj1.toString() === obj2.toString();
            default:
                return Object.is(obj1, obj2);
        }
    },
    /**
     * @Description: 将对象数组按指定属性值排序
     * @Author: panqb
     * @Date: 2026-5-4 15:28:03
     * @param {array} array 对象数组
     * @param {string} key 用于排序的属性名
     * @param {number} no 用于升序降序
     */
    sort(array, key, no = 0) {
        return array.sort((a, b) => {
            let x = a[key];
            let y = b[key];
            // 判断是否为日期格式
            const isDate = (value) => {
                // 如果是 Date 对象
                if (value instanceof Date) return true;
                // 如果是字符串日期格式（如：2024-01-01、2024/01/01、2024年1月1日）
                if (typeof value === 'string') {
                    // 常见日期格式正则
                    const dateRegex = /^\d{4}[-/年]\d{1,2}[-/月]\d{1,2}/;
                    if (dateRegex.test(value)) return true;
                    // 检查是否为有效日期
                    return !isNaN(new Date(value).getTime());
                }
                return false;
            }
            // 转换为可比较的时间戳
            const getComparableValue = (value) => {
                if (value instanceof Date) {
                    return value.getTime();
                }
                if (typeof value === 'string' && isDate(value)) {
                    return new Date(value).getTime();
                }
                return value;
            }
            let xVal = getComparableValue(x);
            let yVal = getComparableValue(y);
            // 处理 undefined 或 null 的情况
            if (xVal === undefined || xVal === null) xVal = '';
            if (yVal === undefined || yVal === null) yVal = '';

            if (no == 0) {
                // 正序（升序）
                if (x < y) return -1;
                if (x > y) return 1;
                return 0;
            } else {
                // 倒序（降序）
                if (x > y) return -1;
                if (x < y) return 1;
                return 0;
            }
        })
    },
    /**
     * @Description: 根据身份证号获取身份信息(年龄，性别，出生日期, 地区, 邮编)
     * @Author: panqb
     * @Date: 2026-5-4 15:33:10
     * @param {string} idNo 传入身份证号码
     */
    getIdData(idNo) {
        if (!this.analyzeIDCard(idNo)) return ''
        let data = {}
        // 1. 计算性别
		let genderDigit = parseInt(idNo.charAt(16), 10);
        data.sex = genderDigit % 2 === 1 ? "男" : "女"
        data.sexCode = genderDigit % 2 === 1 ? 1 : 0
        // 2. 提取出生日期
        let birthDateStr = idNo.substring(6, 14);
        let year = parseInt(birthDateStr.substring(0, 4), 10);
        let month = parseInt(birthDateStr.substring(4, 6), 10) - 1;
        let day = parseInt(birthDateStr.substring(6, 8), 10);
        data.birthday = `${year}-${String(month + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`
        // 3. 正确的年龄计算
        const birthDate = new Date(year, month, day);
		let today = new Date();
        // 计算周岁
        let ageYears = today.getFullYear() - birthDate.getFullYear();
        let ageMonths = today.getMonth() - birthDate.getMonth();
        let ageDays = today.getDate() - birthDate.getDate();
        // 如果今天还没到生日
        if (ageDays < 0) {
            ageMonths--;
            // 获取上个月的天数
            const lastDayOfLastMonth = new Date(today.getFullYear(), today.getMonth(), 0).getDate();
            ageDays += lastDayOfLastMonth;
        }
        // 如果月份为负
        if (ageMonths < 0) {
            ageYears--;
            ageMonths += 12;
        }
        data.age = ageYears
        data.ageMonth = (ageYears > 0 ? `${ageYears}岁`: '') + 
            (ageYears > 0 && ageMonths > 0 ? '零' : '') + (ageMonths > 0 ? `${ageMonths}个月` : '')
        data.ageDay = (ageYears > 0 ? `${ageYears}岁`: '') + 
            (ageYears > 0 && ageMonths > 0 ? '零' : '') + (ageMonths > 0 ? `${ageMonths}个月` : '') +
            (ageDays > 0 && ageMonths > 0 ? '零' : '') + (ageDays > 0 ? `${ageDays}天` : '')
        const addressCode = idNo.slice(0, 6)
        let areaInfo = AddressJson.find(item => item.code == addressCode)
        if (!areaInfo) {
            const cityCode = idNo.slice(0, 4)
            areaInfo = AddressJson.find(item => item.cityCode == cityCode)
        }
        if (areaInfo) {
            data.addressCode = areaInfo.code
            data.address = areaInfo.province + areaInfo.city + areaInfo.name
            data.addressTree = [areaInfo.province, areaInfo.city, areaInfo.name]
            data.zipCode = areaInfo.zipCode
        }
        return data
    },
    /**
     * @Description: 身份证效验
     * @Author: panqb
     * @Date: 2026-5-4 15:33:10
     * @param {string} idNo 传入身份证号码
     */
    analyzeIDCard(data){
        let age = 0
        var yearBirth, monthBirth, dayBirth
        //获取用户身份证号码
        var userCard = data
        var resultMap= ''
        //如果身份证号码为undefind则返回空
        if(!userCard){
            resultMap = false
            return resultMap
        }
        // 省份地址码范围
        const provinceCodes = {
            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: "澳门特别行政区",91: "国外"
        }
        var reg = /(^\d{15}$)|(^\d{17}([0-9]|X)$)/ //验证身份证号码的正则
        if (reg.test(userCard)) {
            const addressCode = userCard.slice(0, 6)
            if (!Object.keys(provinceCodes).some(code => addressCode.startsWith(code))) {
            resultMap = false
            return resultMap
            }
            let birthDateStr
            if (userCard.length === 15) {
            let org_birthday = userCard.substring(6, 12)
                //获取出生年月日
                yearBirth = "19" + org_birthday.substring(0, 2)
                monthBirth = org_birthday.substring(2, 4)
                dayBirth = org_birthday.substring(4, 6)
                birthDateStr = "19" + userCard.slice(6, 12)
            } else if (userCard.length === 18) {
                //获取出生年月日
                yearBirth = userCard.substring(6,10)
                monthBirth = userCard.substring(10,12)
                dayBirth = userCard.substring(12,14)
                birthDateStr = userCard.slice(6, 14)
                const factors = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]
                const codes = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2']
                let sum = 0
                for (let i = 0; i < 17; i++) {
                    sum += parseInt(userCard[i], 10) * factors[i]
                }
                const code = codes[sum % 11]
                if (code !== userCard[17].toUpperCase()) {
                    resultMap = false
                    return resultMap
                }
            }
            const year = parseInt(birthDateStr.slice(0, 4), 10)
            const month = parseInt(birthDateStr.slice(4, 6), 10)
            const day = parseInt(birthDateStr.slice(6, 8), 10)
            const date = new Date(year, month - 1, day)
            if (!(date.getFullYear() === year && date.getMonth() === month - 1 && date.getDate() === day)) {
                resultMap = false
                return resultMap
            }
            resultMap = true
            return resultMap
        } else {
            resultMap = false
            return resultMap
        }
    },
    /**
     * @Description: 根据file对象换算其url地址
     * @Author: panqb
     * @Date: 2026-5-4 20:48:35
     * @param {object} file file对象
     * @return {object} url地址
     */
    fileUrl(file) {
        let url = null;
        if (window.createObjectURL !== undefined) {
            url = window.createObjectURL(file.raw) // basic
        } else if (window.URL !== undefined) {
            url = window.URL.createObjectURL(file.raw) // IE,google,360,Safari,firefox
        } else if (window.webkitURL !== undefined) {
            url = window.webkitURL.createObjectURL(file.raw) // webkit
        }
        return url;
    },
    /**
     * @Description: 解码Base64格式的文件数据
     * @Author: panqb
     * @Date: 2026-5-4 20:48:23
     * 
     * @param {string} data base64数据
     * @return {array} 两元素数组：0-解码的数据，Uint8Array数组 1-MIME类型
     */
    decodeBase64FileData(data) {
        let arr = data.split(',');
        let bytes = (arr[0].indexOf('base64') >= 0) ?
            window.atob(arr[1]) : window.decodeURIComponent(arr[1]);
        let mime = arr[0].split(':')[1].split(';')[0];
        let dataArray = new Uint8Array(bytes.length);
        for (let i = 0; i < bytes.length; i++) {
            dataArray[i] = bytes.charCodeAt(i);
        }
        return [dataArray, mime];
    },
    /**
     * @Description: 复制内容到粘贴板
     * @param {object} vue vue实例对象
     * @param {string} content 内容
     * @Author: panqb
     * @Date: 2026-5-4 20:48:11
     */
    copyTextToBoard(vue, content) {
        // 这里做兼容，可能会有浏览器禁用了非安全域的 navigator.clipboard 对象
        if (navigator.clipboard && window.isSecureContext) {
            navigator.clipboard.writeText(content).then(() => {
                vue.$message.success('复制成功');
            });
        } else {
            const input = document.createElement('input');
            input.value = content;
            document.body.appendChild(input);
            input.select();
            vue.$message.success('复制成功');
            // 执行复制命令并移除文本框
            document.execCommand('copy');
            input.remove();
        }
    },

    /**
     * @Description: 过滤字符串，只保留其中的数字和保留字符
     * @Author: panqb
     * @Date: 2026-5-4 20:47:54
     * @param {string} value 待过滤的字符串
     * @param {array} reservedChars 需保留的字符数组，例如['-', '.']
     * @return {string} 过滤结果
     */
    filterDigitals(value, reservedChars = []) {
        return this.filterResult(value, reservedChars, (char, reservedChars2) => {
            return isNaN(char) && reservedChars2.indexOf(char) == -1;
        });
    },
    /**
     * @Description: 过滤字符串，只保留其中的字母和保留字符
     * @Author: panqb
     * @Date: 2026-5-4 20:47:42
     * @param {string} value 待过滤的字符串
     * @param {array} reservedChars 需保留的字符数组，例如['-', '.']
     * @return {string} 过滤结果
     */
    filterLetters(value, reservedChars = []) {
        return this.filterResult(value, reservedChars, (char, reservedChars2) => {
            return !/^[a-zA-Z]+$/.test(char) && reservedChars2.indexOf(char) == -1;
        });
    },
    /**
     * @Description: 过滤字符串，只保留其中的字母、数字和保留字符
     * @Author: panqb
     * @Date: 2026-5-4 20:47:29
     * @param {string} value 待过滤的字符串
     * @param {array} reservedChars 需保留的字符数组，例如['-', '.']
     * @return {string} 过滤结果
     */
    filterDigitalsAndLetters(value, reservedChars = []) {
        return this.filterResult(value, reservedChars, (char, reservedChars2) => {
            return isNaN(char) && !/^[a-zA-Z]+$/.test(char) && reservedChars2.indexOf(char) == -1;
        });
    },
    /**
     * @Description: 过滤字符串，只保留其中的汉字和保留字符
     * @Author: panqb
     * @Date: 2026-5-4 20:47:16
     * @param {string} value 待过滤的字符串
     * @param {array} reservedChars 需保留的字符数组，例如['-', '.']
     * @return {string} 过滤结果
     */
    filterChinese(value, reservedChars = []) {
        return this.filterResult(value, reservedChars, (char, reservedChars2) => {
            return /[^\u4E00-\u9FA5]/.test(char) && reservedChars2.indexOf(char) == -1;
        });
    },
     /**
     * @Description: 过滤字符串，只保留其中的汉字、字母和保留字符
     * @Author: panqb
     * @Date: 2026-5-4 20:47:03
     * @param {string} value 待过滤的字符串
     * @param {array} reservedChars 需保留的字符数组，例如['-', '.']
     * @return {string} 过滤结果
     */
     filterChineseAndLetters(value, reservedChars = []) {
        return this.filterResult(value, reservedChars, (char, reservedChars2) => {
            return /[^\u4e00-\u9fa5a-zA-Z]/.test(char) && reservedChars2.indexOf(char) == -1;
        });
    },

    filterResult(value, reservedChars, conditionFunc) {
        let charArr = Array.from(value);
        let result = '';
        for (let char of charArr) {
            if (conditionFunc(char, reservedChars)) continue;
            result += char;
        }
        return result;
    },

    /**
     * @Description: 验证手机号
     * @Author: panqb
     * @Date: 2026-5-4 20:46:54
     * @param {string} mobile 待验证手机号
     * @return {boolean} true/false
     */
    validateMobile(mobile) {
        let reg = CommonConst.REGEXP_MOBILE;
        return reg.test(mobile);
    },

    /**
     * @Description: 初始化腾讯地图运行环境
     * @Author: panqb
     * @Date: 2026-5-4 20:46:39
     * @param {*} key 腾讯地图key值
     */
    initQQMap(key) {
        // 已加载过，直接返回
        if (window.qq && window.qq.maps) {
            return Promise.resolve(window.qq);
        }
        return new Promise(function(resolve, reject) {
            window.init = function() {
                resolve(qq) //注意这里
            }
            let script = document.createElement("script");
            script.type = "text/javascript";
            script.src = CommonConst.QQMAP_INIT + key;
            script.onerror = reject;
            document.head.appendChild(script);
            let geoScript = document.createElement("script");
            geoScript.type = "text/javascript";
            geoScript.src = CommonConst.QQMAP_GEOlOCATION;
            document.head.appendChild(geoScript);
        })
    },

    /**
     * @Description: select组件支持拼音查询挂载的自定义方法
     * 用于过滤待查询数组返回包含用户输入字母的目标数组
     * @Author: panqb
     * @Date: 2026-5-4 20:46:24
     * @param {*} value    用户输入值
     * @param {*} listName 目标过滤数组名称
     * @param {*} srcList  待过滤数组
     * @param {*} vue      vue实例对象
     */
    handleListFilter(value, listName, srcList, vue) {
        //统一转化为小写
        let lowerCaseValue = value.toLowerCase();
        vue[listName] = srcList.filter(item => (
            item.name.indexOf(lowerCaseValue) != -1 || item.py.indexOf(lowerCaseValue) != -1
        ));
    },

    /**
     * @Description: select组件下拉框出现/隐藏时触发的挂载事件
     * 用于给目标过滤后的数组恢复成初始数组(包含全部下拉选项的数组)
     * @Author: panqb
     * @Date: 2026-5-4 20:46:08
     * @param {*} visible  事件回调参数值 出现则为 true，隐藏则为 false
     * @param {*} listName 目标过滤数组名称
     * @param {*} srcList  待过滤数组
     * @param {*} vue      vue实例对象
     */
    handleListFilterVisibleChange(visible, listName, srcList, vue) {
        if (visible) {
            vue[listName] = JSON.parse(JSON.stringify(srcList));
        }
    },

    /**
	 * @Description: 防抖处理（确保在指定的时间间隔结束后执行一次函数，如果这段时间内多次触发事件，则只有最后一次事件会在延迟后执行函数）
	 * 实现逻辑：由于使用闭包，使得timer不被回收，每次调用该方法时会去判断timer是否存在，如果存在，
	 * 表示上一次操作在等待执行func(...arguments)，期间如果继续操作，且在delay时间内，则会把上一次未执行的（setTimeout中的）func(...arguments)销毁，
	 * 重新定时，以此来达到触发结束超过delay时间才执行func(...arguments)，即触发事件。
	 * 注: 使用...arguments可以捕获并传递所有传递给防抖函数的参数给原始函数，确保原始函数能够接收到正确的参数值。
	 * @Author: panqb
	 * @Date: 2026-5-4 20:45:53
	 * @param {function} func 需要防抖处理的方法
	 * @param {number} delay 等待时间，单位是毫秒，默认1000毫秒
	 * @return {function} 防抖处理后的方法
	 */
	debounce(func, delay = 1000) {
		let timer = null;
		return function() {
			if (timer != null) {
				clearTimeout(timer);
			}
			timer = setTimeout(() => {
				func(...arguments)
				clearTimeout(timer);
			}, delay);
		}
	},
    /**
	 * @Description: 节流处理（控制高频事件执行次数，确保在指定的时间间隔内最多执行一次函数，无论在这段时间内触发了多少次事件，只有第一次事件会立即执行函数）
	 * 实现逻辑：由于使用闭包，使得flag不被回收，每次调用该方法时会去判断flag是否有效(true)，如果有效，则不超过时间间隔，不往下执行func(...arguments)
	 * 反之立即执行func(...arguments)，并且在时间间隔内把flag置为无效(false)，超过时间间隔把状态位flag设为有效。
	 * @Author: panqb
	 * @Date: 2026-5-4 20:45:38
	 * @param {function} func 需要节流处理的方法
	 * @param {number} delay 等待时间，单位是毫秒，默认2000毫秒
	 * @return {function} 节流处理后的方法
	 */
	throttle(func, delay = 2000) {
		let flag = true;
		return function() {
			if (!flag) {
				return;
			}
			func(...arguments);
			flag = false;
			setTimeout(() => {
				flag = true;		
			}, delay);
		}
	},
    /**
     * @Description: 对时间进行处理
     * 用于获取格式化后的时间
     * @Author: panqb
     * @Date: 2026-5-4 20:45:19
     * @param {*} format  日期格式
     * @param {*} dateTime 要格式化的时间
     */
    date(formatter = "YYYY-MM-DD", dateTime = new Date(), seperator = '-') {
        let seperatorCN = ''
        if (seperator == 'CN') seperatorCN = 'CN'
        if (formatter == "YYYY-MM-DD" || formatter == "YYYY" || formatter == "YYYY-MM" || formatter == "MM-DD" ||
            formatter == "YYYY-MM-DD HH:mm:ss" || formatter == "YYYY-MM-DD HH:mm" || formatter == "YYYY-MM-DD HH" ||
            formatter == "HH:mm:ss" || formatter == "HH" || formatter == "HH:mm"
        ) {
            seperator = "-"
        } else if (formatter == "YYYY/MM/DD" || formatter == "YYYY/MM" || formatter == "MM/DD" ||
            formatter == "YYYY/MM/DD HH:mm:ss" || formatter == "YYYY/MM/DD HH:mm" || formatter == "YYYY/MM/DD HH"
        ) {
            seperator = "/"
        } else if (formatter == "YYYY.MM.DD" || formatter == "YYYY.MM" || formatter == "MM.DD" ||
            formatter == "YYYY.MM.DD HH:mm:ss" || formatter == "YYYY.MM.DD HH:mm" || formatter == "YYYY.MM.DD HH"
        ) {
            seperator = "."
        } else {
            formatter = "YYYY-MM-DD"
            seperator = "-"
        }
        if (seperatorCN == 'CN') seperator = 'CN'
        if (Number.isInteger(dateTime)) {
            const now = Date.now(); 
            dateTime = new Date(now + Number(dateTime) * 24 * 60 * 60 * 1000)
        }else if (isNaN(this.parseDate2Millis(dateTime))) {
            console.warn('------当前传入的时间有误，已默认当前时间-----')
            dateTime = new Date()
        }
        return this.dateTimeFormat(dateTime, formatter, seperator)
    },
    
    /**
     * @Description: 将日期时间转换为指定输出格式
     * @Author: liusheng
     * @Date: 2021-11-26 11:43:23
     * @param {object|string} dateTime 待处理的Date对象或字符串(格式为YYYY-MM-DD HH:mm:ss, 支持日期/分隔符)
     * @param {string} formatter 输出的日期时间格式，缺省为YYYY-MM-DD HH:mm:ss。其中日期和时间两部分必须以空格分隔
     * @param {string} seperator 输出的日期时间分隔符，日期支持'-'、'/'或'CN'，缺省为'-'；时间支持':'或'CN'，缺省为':'
     * @return {string} 格式化的日期时间字符串
     */
    dateTimeFormat(dateTime, formatter = "YYYY-MM-DD HH:mm:ss", seperator = '-') {
        dateTime = new Date(this.parseDate2Millis(dateTime));
        if (formatter == 'HH:mm:ss' || formatter == 'HH:mm' || formatter == 'HH') {
            formatter = ' ' + formatter
        }
        let formatters = formatter.split(' ');
        let str = this.dateFormat(dateTime, formatters[0], seperator) + ' ';
        if (formatters[1]) str += this.timeFormat(dateTime, formatters[1], seperator);
        return str;
    },
    /**
     * @Description: 将日期转换为指定输出格式
     * @Author: liusheng
     * @Date: 2021-11-26 11:43:23
     * @param {object|string} date 待处理的Date对象或字符串(格式为YYYY-MM-DD HH:mm:ss或YYYY-MM-DD, 支持日期/分隔符)
     * @param {string} formatter 输出的日期格式，支持YYYY-MM-DD、YYYY-MM、YYYY或MM-DD，缺省为YYYY-MM-DD
     * @param {string} seperator 输出的日期分隔符，支持'-'、'/'、'.'或'CN'，缺省为'-'
     * @return {string} 格式化的日期字符串
     */
    dateFormat(date, formatter = "YYYY-MM-DD", seperator = '-') {
        if (seperator !== '-' && seperator !== '/' && seperator !== 'CN' 
          && seperator !== '.') return 'error';
        date = new Date(this.parseDate2Millis(date));
        let year = date.getFullYear();
        let month = date.getMonth() + 1;
        let day = date.getDate();
        if (seperator !== 'CN') {
            month = this.numberPrefix0(month);
            day = this.numberPrefix0(day);
        }
        let yearSeperator1 = seperator === 'CN' ? '年' : seperator;
        let yearSeperator2 = seperator === 'CN' ? '年' : '';
        let monthSeperator1 = seperator === 'CN' ? '月' : seperator;
        let monthSeperator2 = seperator === 'CN' ? '月' : '';
        let daySeperator = seperator === 'CN' ? '日' : '';
        switch (formatter) {
            case "YYYY-MM-DD":
                return year.toString() + yearSeperator1 + month + monthSeperator1 + day + daySeperator;
            case "YYYY-MM":
                return year.toString() + yearSeperator1 + month + monthSeperator2;
            case "YYYY":
                return year.toString() + yearSeperator2;
            case "MM-DD":
                return month + monthSeperator1 + day + daySeperator;
            default:
                return 'error';
        }
    },
    timeFormat(time, formatter = "HH:mm:ss", seperator = ':') {
        if (typeof(time) == 'string' && /^\d{2}:\d{2}:\d{2}$/.test(time)) {
            time = this.getTodayStr() + ' ' + time;
        }
        time = new Date(this.parseDate2Millis(time));
        switch (formatter) {
            case "HH:mm:ss":
                return this.numberPrefix0(time.getHours()) + (seperator === 'CN' ? '时' : ':') +
                    this.numberPrefix0(time.getMinutes()) + (seperator === 'CN' ? '分' : ':') +
                    this.numberPrefix0(time.getSeconds()) + (seperator === 'CN' ? '秒' : '');
            case "HH:mm":
                return this.numberPrefix0(time.getHours()) + (seperator === 'CN' ? '时' : ':') +
                    this.numberPrefix0(time.getMinutes()) + (seperator === 'CN' ? '分' : '');
            case "HH":
                return this.numberPrefix0(time.getHours()) + (seperator === 'CN' ? '时' : '');
            default:
                return 'error';
        }
    },
    /**
     * @Description: 比较两个日期的大小
     * @Author: wanqian, liusheng
     * @Date: 2022-02-21
     * @param {object|string} date1 日期1对象或字符串
     * @param {object|string} date2 日期2对象或字符串
     * @return {number} 0~日期1=日期2，1~日期1>日期2，-1~日期1<日期2
     */
    compareDate(date1, date2) {
        let millis1 = this.parseDate2Millis(date1);
        let millis2 = this.parseDate2Millis(date2);
        if (millis1 > millis2) return 1;
        return (millis1 < millis2) ? -1 : 0;
    },
    /**
     * @Description: 获取传入日期与 1970 年 1 月 1 日午夜之间相差的毫秒数
     * @Author: wanqian
     * @Date: 2022-11-29 15:51:23
     * @param {string/date} date 日期或者日期字符串
     * @return {number} 与 1970 年 1 月 1 日午夜之间相差的毫秒数
     */
    parseDate2Millis(date) {
        let target = date
        if (typeof date == 'string') {
            target = date.replace(/-/g, "/").replace(/\./g, "/");
        }
        return Date.parse(target);
    },
    /**
     * @Description: 处理传入数值是否前缀新增0
     * @Author: wanqian
     * @Date: 2022-11-29 15:51:23
     * @param {number} n 待处理的数值
     * @return {number} 处理后前缀是否新增0的数值
     */
    numberPrefix0(n) {
        return (n < 10) ? ('0' + n) : ('' + n);
    },
    /**
     * @Description: 处理数字和小数的加减
     * @Author: panqb
     * @Date: 2026-5-5 15:10:29
     * @param {Array,number} 待处理的数组或数字
     * @param {...number} 待处理的数字或是要保留的小数位
     * @return {number} 加减之后的数值
     */
    add(num, ...decimals) {
        let numbers;
        let fixed = null;
        if (Array.isArray(num)) {
            numbers = num;
            fixed = decimals.length > 0 ? decimals[0] : null;
            if (!Number.isInteger(Number(fixed)) || fixed < 0) fixed = null
        } else {
            numbers = [num, ...decimals];
        }
        numbers.forEach(item => {
            item = Number(item)
        })
        if (numbers.length === 0) return 0;
        let maxDec = Math.max(...numbers.map(n => {
            const str = n.toString();
            return str.includes('.') ? str.split('.')[1].length : 0;
        }));
        const factor = Math.pow(10, maxDec);
        const sum = numbers.reduce((s, n) => s + Math.round(n * factor), 0);
        let result = sum / factor;
        return fixed !== null ? Number(result.toFixed(fixed)) : result;
    },
    /**
     * @Description: 处理数字和小数的乘法
     * @Author: panqb
     * @Date: 2026-5-5 15:10:29
     * @param {Array,number} 待处理的数组或数字
     * @param {...number} 待处理的数字或是要保留的小数位
     * @return {number} 乘法之后的数值
     */
    multiply(num, ...decimals) {
        let numbers;
        let fixed = null;
        if (Array.isArray(num)) {
            numbers = num;
            fixed = decimals.length > 0 ? decimals[0] : null;
            if (!Number.isInteger(Number(fixed)) || fixed < 0) fixed = null;
        } else {
            numbers = [num, ...decimals];
        }

        if (numbers.length === 0) return 0;

        // 计算总小数位数（乘积的小数位数 = 各小数位数之和）
        let totalDecimals = numbers.reduce((sum, n) => {
            const str = n.toString();
            const decPart = str.includes('.') ? str.split('.')[1].length : 0;
            return sum + decPart;
        }, 0);

        // 转为整数相乘
        const factor = Math.pow(10, totalDecimals);
        let product = numbers.reduce((acc, n) => {
            const str = n.toString();
            const decIndex = str.indexOf('.');
            let intPart = decIndex === -1 ? str : str.replace('.', '');
            return acc * Number(intPart);
        }, 1);

        let result = product / factor;

        return fixed !== null ? Number(result.toFixed(fixed)) : result;
    },
    /**
     * @Description: 处理数字和小数的除法
     * @Author: panqb
     * @Date: 2026-5-5 15:10:29
     * @param {Array,number} 待处理的数组或数字
     * @param {...number} 待处理的数字或是要保留的小数位
     * @return {number} 除法之后的数值
     */
    divide(num, ...decimals) {
        let numbers;
        let fixed = null;
        if (Array.isArray(num)) {
            numbers = num;
            fixed = decimals.length > 0 ? decimals[0] : null;
            if (!Number.isInteger(Number(fixed)) || fixed < 0) fixed = null;
        } else {
            numbers = [num, ...decimals];
        }

        if (numbers.length === 0) return 0;

        // 除法：依次相除
        let result = numbers[0];
        for (let i = 1; i < numbers.length; i++) {
            result = result / numbers[i];
        }

        // 如果没指定 fixed，计算原始结果的最大小数位数（可选，但建议保留）
        if (fixed !== null) {
            return Number(result.toFixed(fixed));
        }

        // 默认最多保留原始结果的 15 位小数（避免过长）
        const str = result.toString();
        const decLen = str.includes('.') ? str.split('.')[1].length : 0;
        return decLen > 15 ? Number(result.toFixed(15)) : result;
    },
    /**
     * @Description: 处理金额显示千分位点
     * @Author: panqb
     * @Date: 2026-5-5 15:10:29
     * @param {number} 待处理的金额
     * @param {number} 保留的小数位数
     * @param {string} 向上取整还是向下取整还是四舍五入
     * @param {string} 货币类型
     * @return {string} 处理后的值
     */
    moneyFormat(money, decimals = 2, roundtag = 'round', currency = null) {
        if (money === null || money === undefined || money === '') {
            money = 0
        }
        let num = typeof money === 'number' ? money : parseFloat(String(money).replace(/[^0-9.-]/g, ''))
        if (isNaN(num)) {
            num = 0
        }
        const factor = Math.pow(10, decimals)
        let roundedNum
        switch (roundtag) {
            case 'ceil':
                roundedNum = Math.ceil(num * factor) / factor
                break
            case 'floor':
                roundedNum = Math.floor(num * factor) / factor
                break
            case 'round':
            default:
                roundedNum = Math.round(num * factor) / factor
                break
        }
        let country = ''
        if (currency == 'CN') {
            country = 'zh-CN'
            currency = 'CNY'
        } else if (currency == 'US') {
            country = 'en-US'
            currency = 'USD'
        } else {
            return roundedNum.toLocaleString('en-US', {
                minimumFractionDigits: decimals,
                maximumFractionDigits: decimals
            })
        }
        return roundedNum.toLocaleString(country, {
            style: 'currency',
            currency: currency,
            minimumFractionDigits: decimals,
            maximumFractionDigits: decimals
        })
    },
    /**
     * @Description: 处理单个数字
     * @Author: panqb
     * @Date: 2026-5-5 15:10:29
     * @param {number} 待处理的数字
     * @param {number} 保留的小数位数
     * @param {string} 向上取整还是向下取整还是四舍五入
     * @return {number} 处理后的值
     */
    number(value, decimals = 2, roundtag = 'round') {
        if (value === null || value === undefined || value === '') {
            return NaN
        }
        let num = Number(value)
        if (isNaN(num)) {
            return NaN
        }
        const factor = Math.pow(10, decimals)
        let roundedNum
        switch (roundtag) {
            case 'ceil':
                roundedNum = Math.ceil(num * factor) / factor
                break
            case 'floor':
                roundedNum = Math.floor(num * factor) / factor
                break
            case 'round':
            default:
                roundedNum = Math.round(num * factor) / factor
                break
        }
        return roundedNum
    },
    /**
     * @Description: 处理数字
     * @Author: panqb
     * @Date: 2026-5-5 15:10:29
     * @param {number} 待处理的金额
     * @param {number} 保留的小数位数
     * @param {boolean} 是否可以是负数
     * @return {number} 处理后的值
     */
    inpNumber(value, decimalPlaces = null, allowNegative = false) {
        let str = String(value)
        if (!/^(0|[1-9]\d*)$/.test(String(decimalPlaces))) decimalPlaces = null
        if (decimalPlaces === 0 && str.includes('.')) {
            str = str.split('.')[0]
        }
        if (allowNegative && str === '0-') return '-'
        if (allowNegative && str === '-') return '-'
        if (str === '0.') return '0.'
        let raw = allowNegative ? str.replace(/[^\d.-]/g, '') : str.replace(/[^\d.]/g, '')
        if (allowNegative && raw.includes('-')) {
            const hasMinus = raw.startsWith('-');
            raw = raw.replace(/-/g, '');
            if (hasMinus && raw !== '' && raw !== '.') raw = '-' + raw;
        }
        const dotIndex = raw.indexOf('.');
        if (dotIndex !== -1) {
            raw = raw.slice(0, dotIndex + 1) + raw.slice(dotIndex + 1).replace(/\./g, '');
        }
        if (decimalPlaces !== null && decimalPlaces !== undefined) {
            const finalDotIndex = raw.indexOf('.');
            if (finalDotIndex !== -1 && raw.slice(finalDotIndex + 1).length > decimalPlaces) {
                raw = raw.slice(0, finalDotIndex + decimalPlaces + 1);
            }
        }
        if (raw === '' || raw === '.') return 0;
        if (raw.endsWith('.')) {
            return raw
        }
        if (/^0\d+$/.test(raw)) raw = raw.replace(/^0+/, '') || '0';
        if (/^0\d+\./.test(raw)) raw = raw.replace(/^0+/, '');
        let num = parseFloat(raw);
        if (isNaN(num)) return 0;
        if (!allowNegative && num < 0) return 0;
        return decimalPlaces !== null && decimalPlaces !== undefined 
        ? Number(num.toFixed(decimalPlaces)) 
        : Number(num);
    },
    /**
     * @Description: 把数组/对象里的参数值全部转化成字符串
     * @Author: panqb
     * @Date: 2026-5-5 15:10:29
     * @param {Object/list} 待处理的数组或对象
     * @return {Object/list} 处理后的数组或对象
     */
    objToString(obj) {
        if (obj === null || obj === undefined) return obj;
        if (Array.isArray(obj)) {
            return obj.map(item => convertToString(item));
        }
        if (typeof obj === 'object') {
            const result = {};
            for (const [key, value] of Object.entries(obj)) {
            result[key] = convertToString(value);
            }
            return result;
        }
        return obj;
    }
}

export default TJUtil