野兽111111111

53221

博客园 首页 新随笔 联系 订阅 管理

代码

            // 我的脚本
            console.log('========================= 程序脚本执行成功 ==============================')
            let appConfig = {
                host: 'http://sz.emtailor.com:8068/',
                // host: 'http://localhost:8068/',
                // host: 'http://e.7mo.org:8068/',
                /*
                客户端类型: client,middle,file
                client: 1.客户端模式,不进行心跳;
                middle: 1.中间件模式,进行心跳;
                file:   1.文件端模式,不进行心跳;
                one:    4.一体端模式,不进行心跳;
                */
                serviceType: 'one',
                /*
                是否debug模式: true,false
                影响一些日志的输出
                */
                isDebug: false,
                /*
                是否全局结束所有任务,默认false
                */
                allStop: false,
                /*
                axios全局超时时间ms
                */
                axiosTimeOut: 60 * 1000,
                heartBeatPunish: 10,
                heartBeatFixedDelay: 10,
                /*
                用户解封时间ms
                */
                userUnBanIntervalMs: 172800000,
                /*
                默认任务间隔ms
                */
                defaultSleepTaskMs: 86400000,
                defaultUserCheckUrl: 'https://www.instagram.com/graphql/query/?query_id=17888483320059182&id=4143607182&first=40',
                /*
                忽略图片下载失败
                */
                ignoreGetImage: true,
                /*
                是否健康检查(自动启动任务)
                */
                isHealthCheck: true,
                /*
                健康检查周期(阀值,超过此时间将尝试启动任务)
                */
                healthCheckIntervalMs: 10 * 60 * 1000,
                /*
                邮件告警间隔(触发第多少次发送邮件,才发送邮件;不要让邮件发送太频繁,添加容错范围)
                */
                emailCountIgnore : 6,
            };

            /*
            ==============================================
            */
            // common.js
            String.prototype.reverse = function () {
                return this.split('').reverse().join('')
            };

            String.prototype.toSize = function () {
                let size = this;
                if (!!size && size > 0) {
                    const KB = 1024;
                    const MB = 1024 * KB;
                    const GB = 1024 * MB;
                    const TB = 1024 * GB;
                    let sizeStr = size > TB ? size / TB + "TB" : size > GB ? size / GB + "GB" : size > MB ? size / MB + "MB" : size > KB ? size / KB + "KB" : size;
                    let unit = sizeStr.substr(-2);
                    let number = sizeStr.replace(unit, '');
                    number = Math.floor(number * 10) / 10;
                    sizeStr = number + unit;
                    return sizeStr;
                } else {
                    return '0KB';
                }
            };

            String.prototype.between = function (start = '', end = '', isInner = true) {
                let str = this;
                if (!!str && str.length > 0) {
                    let startIndex = 0;
                    if (start) {
                        let io = str.indexOf(start);
                        if (io >= 0) {
                            if (isInner) {
                                io = io + start.length;
                            }
                            startIndex = io;
                        } else {
                            return '';
                        }
                    }
                    let endIndex = str.length;
                    if (end) {
                        let io = str.indexOf(end, startIndex);
                        if (io >= 0) {
                            if (!isInner) {
                                io = io + end.length;
                            }
                            endIndex = io;
                        } else {
                            return '';
                        }
                    }
                    return str.substring(startIndex, endIndex);
                } else {
                    return '';
                }
            };

            let UUID = (len) => {
                let max = 520 << 520;
                len = len === null || isNaN(len) || len > max ? 6 : len;
                let uuid = '';
                let rand = () => ('' + Math.random()).substring(2);
                do {
                    uuid += rand();
                } while (uuid.length < len) ;
                return uuid.substring(0, len);
            };

            let trimQuote = (str) => {
                let trimStr = String(str).trim();
                if (!!trimStr) {
                    let quote = '"';
                    if (trimStr.startsWith(quote)) {
                        trimStr = trimStr.substr(1);
                    }
                    if (trimStr.endsWith(quote)) {
                        trimStr = trimStr.substring(0, trimStr.lastIndexOf(quote));
                    }
                }
                return trimStr;
            };

            /**
             * 获取字符串的 哈希值
             * @param str 字符串
             * @param caseSensitive 区分大小写
             * @returns {number}
             */
            let getHashCode = (str, caseSensitive = true) => {
                str = '' + str;
                if (!caseSensitive) {
                    str = str.toLowerCase();
                }
                let hash = 13709061665, i, ch;
                for (i = str.length - 1; i >= 0; i--) {
                    ch = str.charCodeAt(i);
                    hash ^= ((hash << 5) + ch + (hash >> 2));
                }
                return (hash & 2147483647);
            };

            /**
             * fake flat for webStorm,idea
             * @type {string}
             */
            let fakeU = 'fake webStorm,idea';
            if (!fakeU) {
                Array.prototype.flat = () => Array.prototype.flat();
                /**
                 *
                 * @param url{string}
                 * @param param{object}
                 * @returns {object}
                 */
                let axiosParam = (url, param = {}) => Object.assign(url, param);
                /**
                 *
                 * @type {{request: (function(string, Object): string & Object), post: (function(string, Object): string & Object), get: (function(string, Object): string & Object), delete: (function(string, Object): string & Object), put: (function(string, Object): string & Object)}}
                 */
                axios = {
                    get: axiosParam,
                    put: axiosParam,
                    post: axiosParam,
                    delete: axiosParam,
                    request: axiosParam,
                };
                Vue = {
                    getCurrentInstance: () => 0,
                    // @see <a href="https://blog.csdn.net/weixin_34370347/article/details/89617464">Vue获取组件name属性</a>
                    $options: {},
                    globalProperties: {},
                    $emit: () => 0,
                    mount: () => 0,
                    unmount: () => 0,
                    createApp: () => 0,
                    reactive: () => 0,
                    $el: {},
                };
                /**
                 * js-sha1
                 * @see https://github.com/emn178/js-sha1
                 * @param str
                 * @returns {string}
                 */
                sha1 = (str) => '';
                VueRouter = {
                    createRouter: () => 0,
                    createWebHashHistory: () => 0,
                };
                /**
                 * js 代码格式化工具
                 * @link https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.11.0/beautify.min.js
                 * @param jsCode js脚本文本
                 * @returns {string}
                 */
                js_beautify = (jsCode) => String(jsCode);
            }

            /**
             * 验证脚本合法性
             * @returns {boolean}
             */
            String.prototype.validScript = function () {
                let scriptStrObj = this;
                try {
                    // 这里要转换为字符串才能正确验证, 否则传入的是String()对象, 无法验证
                    eval(String(scriptStrObj));
                    return true;
                } catch (e) {
                    console.error('无效的脚本: %o, error: {}', scriptStrObj, e);
                }
                return false;
            };

            /**
             *  禁止用F5键
             * @returns {boolean}
             */
            document.onkeydown = () => {
                console.log('event.keyCode', event.keyCode);
                if (event.keyCode === 116) {
                    //event.keyCode = 0;
                    //event.cancelBubble = true;
                    //// window.location.href = '/';
                    // return false;
                }
            };

            /**
             * 从数组中的对象中查找key键名对应的值包含被查找的值数组
             * @param sourceArr 源对象数组
             * @param key 数组中对象的key键名
             * @param valuesArr key的值数组
             * @returns {*}
             */
            let findKey = (sourceArr, key, valuesArr) => sourceArr.filter(e => valuesArr.filter(f => f === e[key]).length === 1);

            let randNumber = (min, max) => parseInt(Math.random() * (max - min + 1) + min, 10);

            let deepClone = (obj) => JSON.parse(JSON.stringify(obj));

            /**
             * 日期转指定格式字符串
             * @param fmt 日期格式化函数
             * @returns {string} 格式化后的日期字符串
             * @modified zhongbo
             * @date 2020/5/22
             */
            Date.prototype.fmt = function dateFormat(fmt = 'MM月dd日HH:mm:ss,SSS') {
                //eg: yyyy-MM-dd HH:mm:ss
                let date = this;
                let ret;
                let opt = {
                    "y+": date.getFullYear().toString(),        //
                    "Y+": date.getFullYear().toString(),        //
                    "M+": (date.getMonth() + 1).toString(),     //
                    "d+": date.getDate().toString(),            //
                    "D+": date.getDate().toString(),            //
                    "H+": date.getHours().toString(),           //
                    "m+": date.getMinutes().toString(),         //
                    "s+": date.getSeconds().toString(),          //
                    "S+": date.getMilliseconds().toString()          //
                    // 有其他格式化字符需求可以继续添加,必须转化成字符串
                };
                for (let k in opt) {
                    ret = new RegExp("(" + k + ")").exec(fmt);
                    if (ret) {
                        fmt = fmt.replace(ret[1], (ret[1].length === 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
                    }
                }
                return fmt;
            };

            /**
             * 秒转时间字符串
             * @param second
             * @returns {string}
             */
            let timeUnit = (second) => {
                if (!!Math.floor(second)) {
                    const MINUTE = 60;
                    const HOUR = 60 * MINUTE;
                    const DAY = 24 * HOUR;
                    let timeStr = second > DAY ? second / DAY + '天' : second > HOUR ? second / HOUR + '时' : second > MINUTE ? second / MINUTE + '分' : second + '秒';
                    let unit = timeStr.substr(-1);
                    let number = timeStr.replace(unit, '');
                    number = Math.floor(number * 10) / 10;
                    timeStr = number + unit;
                    return timeStr;
                } else {
                    return '0秒'
                }
            };

            /**
             * 按键事件检测
             *
             * 特殊按键说明
             * metaKey : 即Win键
             * ctrlKey : 即Ctrl键
             * altKey : 即Alt键
             * shiftKey : 即Shift键
             * 'Tab' : 即Tab键
             * 'Escape' : 即Esc键
             * @param {KeyboardEvent} event
             * @param {array} param
             * @return {boolean}
             */
            let isEventKey = (event, param = []) => {
                let matchAllKey = true;
                // 判断 event 按键事件需要使用 event.nativeEvent 来判断事件类型
                if (!!event && !!param && event.nativeEvent instanceof KeyboardEvent && param instanceof Array) {
                    param.forEach(key => {
                        if (matchAllKey) {
                            if ('ctrl' === key) {
                                matchAllKey = event.ctrlKey;
                            } else if ('alt' === key) {
                                matchAllKey = event.altKey;
                            } else {
                                matchAllKey = event.key === key;
                            }
                        }
                    })
                } else {
                    matchAllKey = false;
                }
                return matchAllKey;
            };

            /**
             * 字符串中间插入文本
             * @param sourceStr
             * @param start
             * @param insertStr
             * @return {*}
             */
            let insertStr = (sourceStr, start, insertStr) => {
                if (!!sourceStr && !!insertStr && !isNaN(start) && sourceStr instanceof String && insertStr instanceof String) {
                    return sourceStr.slice(0, start) + insertStr + sourceStr.slice(start);
                }
                return sourceStr;
            };

            /**
             * 数组中间插入内容
             * @param {array} sourceArr
             * @param {number} start
             * @param {*} insertObj
             * @return {*}
             */
            let insertArr = (sourceArr, start, insertObj) => {
                if (!!sourceArr && !!insertObj) {
                    sourceArr = _.clone(sourceArr);
                    if (sourceArr instanceof Array) {
                        // 判断超越最大下标
                        if (sourceArr[start] === undefined) {
                            sourceArr.push(insertObj);
                        } else {
                            // 中间添加一行
                            sourceArr = sourceArr.map((v, i) => i === start ? [v, insertObj] : v).flat();
                        }
                    }
                }
                return sourceArr;
            };

            /**
             * 数组中间插入内容
             * @param {array} sourceArr
             * @param {number} start
             * @return {*}
             */
            let removeArr = (sourceArr, start) => {
                if (!!sourceArr && typeof start === 'number') {
                    sourceArr = _.clone(sourceArr);
                    if (sourceArr instanceof Array) {
                        // 中间删除一行
                        sourceArr = sourceArr.filter((url, index) => index !== start);
                    }
                } else {
                    console.log('移除数组错误! 参数错误 sourceArr: %o start: %o', sourceArr, start);
                }
                return sourceArr;
            };

            /**
             * 字节转字符串
             * @param byteSize
             * @returns {string}
             */
            let byteUnit = (byteSize) => {
                if (!!Math.floor(byteSize)) {
                    const KB = 1024;
                    const MB = 1024 * KB;
                    const GB = 1024 * MB;
                    let timeStr = byteSize > GB ? byteSize / GB + 'GB' : byteSize > MB ? byteSize / MB + 'MB' : byteSize > KB ? byteSize / KB + 'KB' : byteSize + 'B';
                    let unit = timeStr.substr(-1);
                    let unitHigh = timeStr.substr(-2, 1);
                    unit = unitHigh > '9' ? unitHigh + unit : unit;
                    let number = timeStr.replace(unit, '');
                    number = Math.floor(number * 10) / 10;
                    timeStr = number + unit;
                    return timeStr;
                } else {
                    return '0B'
                }
            };

            /**
             * 判断是否管理员
             * @return {boolean}
             */
            let isAdmin = () => !!localStorage.getItem('token');

            /**
             * 判断字符串是否为json
             * @param str
             * @returns {boolean}
             * @see <a href="https://www.cnblogs.com/lanleiming/p/7096973.html">【最简单的方法】js判断字符串是否为JSON格式(20180115更新)</a>
             */
            let isJson = (str) => {
                if (typeof str === 'string') {
                    try {
                        let obj = JSON.parse(str);
                        return !!(typeof obj === 'object' && obj);
                    } catch (e) {
                        console.log('isJson error: %o !!!', str, e);
                    }
                }
                return false;
            };

            /**
             * 提取日志打印FormData信息
             * @param params 请求参数
             * @returns {object}
             */
            let extractFormData = (params) => FormData && params && params instanceof FormData ? (() => {
                let next, returnObj = {}, pk = params.keys();
                while ((next = pk.next()) && !next.done) returnObj[next.value] = params.getAll(next.value);
                return returnObj;
            })() : params;

            //console.__proto__.blue = {
            //    log: (...e) => console.log('%c[ %s ] Proxy' + e.map((e) => typeof(e) === 'object' ? '%o' : '%s').join(' ')
            //        , 'background-color:blue;color:white;line-height:20px;', new Date().fmt(), ...e)
            //};
            //
            //console.__proto__.green = {
            //    log: (...e) => console.log('%c[ %s ] Proxy' + e.map((e) => typeof(e) === 'object' ? '%o' : '%s').join(' ')
            //        , 'background-color:blue;color:blue;line-height:20px;', new Date().fmt(), ...e)
            //};
            //
            //console.__proto__.yellow = {
            //    log: (...e) => console.log('%c[ %s ] Proxy' + e.map((e) => typeof(e) === 'object' ? '%o' : '%s').join(' ')
            //        , 'background-color:blue;color:yellow;line-height:20px;', new Date().fmt(), ...e)
            //};
            //
            //console.__proto__.green = {
            //    log: (...e) => console.log('%c[ %s ] Proxy' + e.map((e) => typeof(e) === 'object' ? '%o' : '%s').join(' ')
            //        , 'background-color:blue;color:green;line-height:20px;', new Date().fmt(), ...e)
            //};

            /**
             * 禁用调试模式
             * @see <a href="https://zmingcx.com/wp-content/cache/autoptimize/js/autoptimize_e7a8a795e88cf81ddfa417af57368243.js">提取自源码forbidDebug()</a>
             */
            let forbidDebug = function () {
                // 是否允许调试
                let enableDebug = true;
                if (enableDebug) {
                    return;
                }
                try {
                    ((function () {
                        let callbacks = [], timeLimit = 50, open = false;
                        setInterval(loop, 1);
                        return {
                            addListener: function (fn) {
                                callbacks.push(fn)
                            }, cancleListenr: function (fn) {
                                callbacks = callbacks.filter(function (v) {
                                    return v !== fn
                                })
                            }
                        };

                        function loop() {
                            let startTime = new Date();
                            debugger;
                            if (new Date() - startTime > timeLimit) {
                                if (!open) {
                                    callbacks.forEach(function (fn) {
                                        fn.call(null)
                                    })
                                }
                                open = true;
                                window.stop();
                                alert("\u5173\u95ed\u63a7\u5236\u53f0\u540e\u5237\u65b0\uff01");
                                document.body.innerHTML = ""
                            } else {
                                open = false
                            }
                        }
                    })()).addListener(function () {
                        window.location.reload()
                    })
                } catch (e) {
                }
            };
            forbidDebug();

            /**
             * 自制禁用调试
             */
            (() => {
                // 是否启用
                let enable = false;
                let c = String.fromCharCode;
                let d = [40, 40, 41, 61, 62, 123, 100, 101, 98, 117, 103, 103, 101, 114, 125, 41, 40, 41];
                try {
                    enable && eval(d.map(e => c(e)).join(''));
                } catch (e) {
                    console.error(e);
                    window.stop();
                }
            })();


            /*
            ===========================================
            */
            // api.js
            // api配置
            let apis = {
                style: {
                    getApp: {
                        // url: 'http://127.0.0.1:3003/src/css/app.css',
                        url: 'src/css/app.css',
                        method: 'get'
                    }
                },
                swagger: {
                    apiDocs: {
                        url: 'v3/api-docs',
                        method: 'get'
                    },
                },
                task: {
                    getOne: {
                        url: 'Task/${id}',
                        method: 'get'
                    },
                    getAll: {
                        url: 'Task/findAll',
                        method: 'get'
                    },
                    add: {
                        url: 'Task',
                        method: 'post'
                    },
                    update: {
                        url: 'Task',
                        method: 'put'
                    },
                    delete: {
                        url: 'Task/${id}',
                        method: 'delete'
                    },
                    start: {
                        url: 'Task/${id}/start',
                        method: 'get'
                    },
                    stop: {
                        url: 'Task/${id}/stop',
                        method: 'get'
                    },
                    pause: {
                        url: 'Task/${id}/pause',
                        method: 'get'
                    },
                    resume: {
                        url: 'Task/${id}/resume',
                        method: 'get'
                    },
                    test: {
                        url: 'Task/test',
                        method: 'post'
                    }
                },
                proxy: {
                    getOne: {
                        url: 'Proxy/${id}',
                        method: 'get'
                    },
                    getAll: {
                        url: 'Proxy/findAll',
                        method: 'get'
                    },
                    add: {
                        url: 'Proxy',
                        method: 'post'
                    },
                    update: {
                        url: 'Proxy',
                        method: 'put'
                    },
                    delete: {
                        url: 'Proxy/${id}',
                        method: 'delete'
                    }
                },
                config: {
                    getOne: {
                        url: 'Config/${id}',
                        method: 'get'
                    },
                    getAll: {
                        url: 'Config/findAll',
                        method: 'get'
                    },
                    add: {
                        url: 'Config',
                        method: 'post'
                    },
                    update: {
                        url: 'Config',
                        method: 'put'
                    },
                    delete: {
                        url: 'Config/${id}',
                        method: 'delete'
                    }
                },
                user: {
                    getOne: {
                        url: 'User/${id}',
                        method: 'get'
                    },
                    getAll: {
                        url: 'User/findAll',
                        method: 'get'
                    },
                    add: {
                        url: 'User',
                        method: 'post'
                    },
                    update: {
                        url: 'User',
                        method: 'put'
                    },
                    delete: {
                        url: 'User/${id}',
                        method: 'delete'
                    }
                },
                notifyEmail: {
                    getOne: {
                        url: 'NotifyEmail/${id}',
                        method: 'get'
                    },
                    getAll: {
                        url: 'NotifyEmail/findAll',
                        method: 'get'
                    },
                    add: {
                        url: 'NotifyEmail',
                        method: 'post'
                    },
                    update: {
                        url: 'NotifyEmail',
                        method: 'put'
                    },
                    delete: {
                        url: 'NotifyEmail/${id}',
                        method: 'delete'
                    }
                },
                eMail: {
                    send: {
                        url: 'Email',
                        method: 'post',
                        param_example: {content: "发送一封邮件", title: "swagger测试", to: "ni81@qq.com"},
                    },
                },
                ins: {
                    count: {
                        url: 'Ins/user/count',
                        method: 'get'
                    },
                    current: {
                        url: 'Ins/user/current',
                        method: 'get'
                    },
                    move: {
                        url: 'Ins/user/move',
                        method: 'get'
                    },
                    next: {
                        url: 'Ins/user/next',
                        method: 'get'
                    },
                    reset: {
                        url: 'Ins/user/reset',
                        method: 'get'
                    },
                },
                post: {
                    getOne: {
                        url: 'Ins/post/${id}',
                        method: 'get'
                    },
                    getPage: {
                        url: 'Ins/post',
                        method: 'get'
                    },
                    addOrUpdate: {
                        url: 'Ins/post',
                        method: 'post'
                    },
                    delete: {
                        url: 'Ins/post/${id}',
                        method: 'delete'
                    },
                    deleteMany: {
                        url: 'Ins/post/delete',
                        method: 'delete'
                    },
                    count: {
                        url: 'Ins/post/count',
                        method: 'get'
                    },
                },
                middle: {
                    heartBeat: {
                        url: 'middle/ping',
                        method: 'get'
                    },
                    lastHeartBeat: {
                        url: 'middle/lastHeart',
                        method: 'get'
                    },
                },
                file: {
                    listJson: {
                        url: 'file/json',
                        method: 'get'
                    },
                    list: {
                        url: 'file',
                        method: 'get'
                    },
                    delete: {
                        // file?del=<String fileName>
                        url: 'file?del=${file}',
                        method: 'get',
                        param_example: {file: 'aaa.txt0.8008880603584201'}
                    },
                    getOne: {
                        // file?get=<String fileName>
                        url: 'file?get=${file}',
                        method: 'get',
                        param_example: {file: 'aaa.txt0.8008880603584201'},
                        config: {
                            responseType: 'blob'
                        },
                    },
                    upload: {
                        url: 'file',
                        method: 'post',
                        param_example: '/*FormData*/tmp=await api.file.getOne({file:\'aaa.jpg\'});fd=new FormData();fd.append(\'file\',tmp.data,\'test.jpg\'+Math.random());up=await api.file.upload(fd)',
                        config: {
                            overrideMimeType: 'multipart/form-data'
                        },
                        info: '参数格式为 FormData'
                    },
                },
                gram: {
                    // https://www.instagram.com/graphql/query/?query_id=17888483320059182&id=1001283596&first=40
                    getPost: {
                        url: 'https://www.instagram.com/graphql/query/?query_id=17888483320059182&id=${id}&first=40',
                        method: 'get',
                        param_example: {id: '1001283596'}
                    },
                    // https://www.instagram.com/graphql/query/?query_hash=8c2a529969ee035a5063f2fc8602a0fd&variables={"id":"51132914782","first":12}
                    getPostNew: {
                        url: 'https://www.instagram.com/graphql/query/?query_hash=${queryHash}&variables={"id":"${id}","first":40}',
                        method: 'get',
                        queryHash: true,
                        // 多图id: '51132914782'
                        // 多图__typename: 'GraphSidecar'
                        param_example: {id: '1001283596'}
                    },
                    getJpeg: {
                        url: 'http${url}',
                        method: 'get',
                        param_example: {url: '1001283596'},
                        usage_example: 'await api.gram.getJpeg({url:decodeURIComponent(\'https://scontent-hkt1-1.cdninstagram.com/v/t51.2885-15/sh0.08/e35/c0.180.1440.1440a/s640x640/271796139_918243432220319_6606270248120166088_n.jpg?_nc_ht=scontent-hkt1-1.cdninstagram.com\u0026_nc_cat=111\u0026_nc_ohc=2KPbEtGsfIIAX9MVvN3\u0026edm=APU89FABAAAA\u0026ccb=7-4\u0026oh=00_AT9LlzKJwZxDGjaZyEI4ov4XEGonwuvdU0xr2oAZ4kCgWA\u0026oe=61EC5D1C\u0026_nc_sid=86f79a\').substr(4)})',
                        config: {
                            responseType: 'blob'
                        },
                    },
                }
            };

            let doBuildUrl = (apiCfg, params) => {
                let url = apiCfg.url.startsWith('http') ? apiCfg.url : appConfig.host + apiCfg.url;
                let pathParams = url.match(/\${\w+}/g);
                if (pathParams) {
                    pathParams.forEach(param => {
                        let paramKey = param.match(/\${(.*?)}/)[1];
                        let paramValue = params[paramKey] || '';
                        if (apiCfg.queryHash && 'queryHash' === paramKey && !paramValue) {
                            paramValue = store.state.queryHash;
                        }
                        url = url.replace(param, paramValue);
                        delete params[paramKey];
                    })
                }
                return url;
            };

            /**
             * build for axios
             * @param apiCfg
             * @returns {(function(*=): *)|*}
             */
            let build = (apiCfg) => {
                if (apiCfg) {
                    let keys = Object.keys(apiCfg);
                    if (keys.includes('url') && apiCfg.url) {
                        let method = apiCfg.method || 'get';
                        axios[method].toString();
                        //try {
                        //} catch (e) {
                        //    throw new Error('错误的方法名! method: ' + method + ' url: ' + apiCfg.url);
                        //}
                        return (originParams = {}) => {
                            let params = deepClone(originParams);
                            let url = doBuildUrl(apiCfg, params);
                            // 支持配置信息(如文件下载 blob)
                            if (apiCfg.config) {
                                Object.assign(params, apiCfg.config)
                            }
                            // 支持表单提交(如文件上传 FormData)
                            if (typeof (originParams) && originParams instanceof FormData) {
                                if (appConfig.isDebug) {
                                    console.log('url', url, extractFormData(originParams), params, apiCfg);
                                }
                                return axios[method](url, originParams, params);
                            }
                            if (appConfig.isDebug) {
                                console.log('url', url, extractFormData(params), apiCfg);
                            }
                            return axios[method](url, params);
                        }
                    } else {
                        keys.forEach(key => apiCfg[key] = build(apiCfg[key]));
                        return apiCfg;
                    }
                }
            };

            /**
             * build for GM_xmlhttpRequest
             * @param apiCfg
             * @returns {(function(*=): *)|*}
             */
            let buildGm = (apiCfg) => {
                if (apiCfg) {
                    let keys = Object.keys(apiCfg);
                    if (keys.includes('url') && apiCfg.url) {
                        let method = apiCfg.method || 'get';
                        return (params = {}) => {
                            params = deepClone(params);
                            let url = doBuildUrl(apiCfg, params);
                            let param = {
                                url,
                                method,
                                data: JSON.stringify(params),
                            };
                            console.log('url', url, params, apiCfg, param);
                            window.GM_xmlhttpRequest = typeof (GM_xmlhttpRequest) === 'undefined' ? undefined : GM_xmlhttpRequest;
                            return new Promise((resolve, reject) => {
                                param.onerror = (error) => {
                                    reject(error)
                                };
                                param.onload = (resp) => {
                                    let headers = {};
                                    let headArr = resp.responseHeaders.split("\n");
                                    headArr.forEach(head => {
                                        let hArr = head.split(";");
                                        let key = hArr.shift();
                                        headers[key] = hArr.join().trim();
                                    });
                                    resp.headers = headers;
                                    let data = {};
                                    if (isJson(resp.responseText)) {
                                        data = JSON.parse(resp.responseText);
                                    }
                                    resp.data = data;
                                    resolve(resp);
                                };
                                if (!!GM_xmlhttpRequest) {
                                    GM_xmlhttpRequest(param)
                                } else {
                                    console.error("没有找到GM_xmlhttpRequest");
                                }
                            });
                        }
                    } else {
                        keys.forEach(key => apiCfg[key] = buildGm(apiCfg[key]));
                        return apiCfg;
                    }
                }
            };

            /**
             * usage in tamperMonkey:
             * let gmDownFile = buildGmDownFile();
             *
             * @returns {function(String): Promise<Object>}
             * @see <a href="https://www.tampermonkey.net/documentation.php#GM_xmlhttpRequest">tamperMonkey doc</a>
             * @author http://mmbro.gitee.com
             * @since 2022110
             */
            let buildGmDownFile = () => {
                window.GM_xmlhttpRequest = typeof (GM_xmlhttpRequest) === 'undefined' ? undefined : GM_xmlhttpRequest;
                return (url) => {
                    url = String(url).startsWith('http') ? url : appConfig.host + url;
                    return new Promise((resolve, reject) => {
                        let param = {
                            url,
                            method: 'get',
                            responseType: 'blob'
                        };
                        param.onerror = (error) => {
                            reject(error)
                        };
                        param.onload = (resp) => {
                            resp.data = resp.response;
                            resolve(resp);
                        };
                        if (!!GM_xmlhttpRequest) {
                            GM_xmlhttpRequest(param)
                        } else {
                            console.error("没有找到GM_xmlhttpRequest");
                        }
                    })
                }
            };

            /**
             * usage in tamperMonkey:
             * let gmUpLoad = buildGmUpLoadFile();
             *
             * @returns {function(String, FormData): Promise<Object>}
             * @see <a href="https://www.tampermonkey.net/documentation.php#GM_xmlhttpRequest">tamperMonkey doc</a>
             * @author http://mmbro.gitee.com
             * @since 2022110
             */
            let buildGmUpLoadFile = () => {
                window.GM_xmlhttpRequest = typeof (GM_xmlhttpRequest) === 'undefined' ? undefined : GM_xmlhttpRequest;
                return (url, formData) => {
                    url = String(url).startsWith('http') ? url : appConfig.host + url;
                    return new Promise((resolve, reject) => {
                        let param = {
                            url,
                            data: formData,
                            method: 'post',
                            responseType: 'blob',
                            overrideMimeType: 'multipart/form-data',
                        };
                        if (typeof (formData) === 'undefined') {
                            reject('error! formData is not a FormData Object!')
                        }
                        param.onerror = (error) => {
                            reject(error)
                        };
                        let isHeadersJson = (headers) => headers && headers['content-type'] && String(headers['content-type']).indexOf('application/json') >= 0;
                        param.onload = (resp) => {
                            let extractRespHeaders = (responseHeaders) => {
                                let headers = {};
                                let headArr = responseHeaders.split("\n");
                                headArr.forEach(head => {
                                    if (head) {
                                        let hArr = head.split(":");
                                        let key = hArr.shift();
                                        headers[key] = hArr.join().trim();
                                    }
                                });
                                return headers;
                            };
                            resp.headers = extractRespHeaders(resp.responseHeaders);
                            let data;
                            if (isHeadersJson(headers)) {
                                if (isJson(resp.responseText)) {
                                    data = JSON.parse(resp.responseText);
                                } else {
                                    if (appConfig.isDebug) {
                                        let contentType = headers['content-type'];
                                        console.error('响应非json文本,contentType: %s', contentType);
                                    }
                                    data = resp.responseText;
                                }
                            } else {
                                data = resp.responseText;
                            }
                            resp.data = data;
                            resp.request = param;
                            resolve(resp);
                        };
                        if (!!GM_xmlhttpRequest) {
                            GM_xmlhttpRequest(param)
                        } else {
                            console.error("没有找到GM_xmlhttpRequest");
                        }
                    })
                }
            };

            /*
            ================================================
            */
            // store.js
            /**
             * Vue3 简单状态管理
             * @see <a href="https://v3.cn.vuejs.org/guide/state-management.html">从零打造简单状态管理</a>
             */
            let store = {
                debug: true,
                state: Vue.reactive({
                    runTask: null,
                    apiDocs: null,
                    lastMessageTime: new Date(),
                    healthState: true,
                    queryHash: '',
                }),

                setRunTask(newValue) {
                    if (this.debug) {
                        console.log('setRunTask triggered with', newValue)
                    }

                    this.state.runTask = newValue
                },

                clearRunTask(newValue) {
                    if (this.debug) {
                        console.log('clearRunTask triggered with', newValue)
                    }

                    let {runTask} = this.state;
                    if (newValue && runTask && runTask.id === newValue.id) {
                        this.state.runTask = null
                    }
                },
            };

            /*
            =================================================
            */
            // list.js
            var template = `
            <div class="list">
                <table v-if="list.length > 0 && Object.keys(showModel).length > 0" border="0" cellspacing="0" cellpadding="5">
                    <tr><th v-for="key in Object.keys(showModel)">{{doGetKey(key)}}</th><th v-if="controlSlot">操作</th></tr>
                    <tr :class="{green: doSuccess(item)}" v-for="item in list">
                        <td v-for="key in Object.keys(showModel)">{{doFormat(item,key)}}</td>
                        <td v-if="controlSlot"><slot :item="item"></slot></td>
                        
                    </tr>
                </table>
                <div class="no-data" v-else>没有数据</div>
            </div>
            `;

            let List = {
                name: 'List',
                components: {},
                template,
                props: {
                    list: {
                        type: Array,
                        default: []
                    },
                    showModel: {
                        type: Object,
                        default: {}
                    },
                    schema: {
                        type: String,
                        default: ''
                    },
                },
                methods: {
                    doFormat(item, key) {
                        if (this.showModel[key] && this.showModel[key].formatter) {
                            if ('date' === this.showModel[key].type) {
                                return new Date(item[key]).fmt(this.showModel[key].formatter);
                            } else {
                                return item[key];
                            }
                        } else if ('text' === this.showModel[key].type) {
                            if (this.showModel[key].maxLength && this.showModel[key].maxLength > 0) {
                                let maxLength = this.showModel[key].maxLength;
                                if (typeof (item[key]) === 'string' && item[key].length > maxLength) {
                                    return item[key].substr(0, maxLength) + '...';
                                } else {
                                    return item[key];
                                }
                            } else {
                                return item[key];
                            }
                        } else {
                            return item[key];
                        }
                    },
                    doSuccess(item) {
                        let successKeys = Object.keys(this.showModel).filter(key => !!this.showModel[key] && this.showModel[key].hasOwnProperty('success'));
                        let success = successKeys.length > 0;
                        successKeys.forEach(key => {
                            if (item[key] !== this.showModel[key]['success']) {
                                success = false;
                            }
                        });
                        return success;
                    },
                    doGetKey(key = '') {
                        let {apiDocs} = this.sharedState;
                        if (apiDocs) {
                            let {schemas = {}} = apiDocs.components;
                            let schemaObj = schemas[this.schema];
                            if (schemaObj) {
                                return schemaObj.properties && schemaObj.properties[key] && schemaObj.properties[key].description || key;
                            }
                        }
                        return key;
                    },
                },
                data() {
                    const {useSlots} = Vue;
                    return {
                        sharedState: store.state,
                        controlSlot: !!useSlots().default
                    }
                }
            };

            /*
            ===============================================
            */
            // message.js
            var template = `
                <div class="message" v-if="isShow">
                    <div :class="'content ' + level">
                        <button @click="close" :class="level">X</button>
                        <div class="text" v-if="message instanceof Array" v-for="msg in message">
                            {{ msg }}
                        </div>
                        <div class="text" v-else>
                            {{ message }}
                        </div>
                    </div>
                </div>
            `;

            let Message = {
                name: 'Message',
                data() {
                    return {
                        list: []
                    }
                },
                props: {
                    message: {
                        // @see <a href="https://v3.cn.vuejs.org/guide/component-props.html#prop-%E9%AA%8C%E8%AF%81">Vue3 Prop 验证</a>
                        type: [String, Array], required: true,
                    },
                    level: {
                        type: String, default: 'success'
                    },
                    duration: {
                        type: Number, default: 3,
                    },
                },
                setup(props) {
                    let {ref} = Vue;
                    let isShow = ref(false);
                    const show = () => {
                        isShow.value = true;
                    };
                    const close = () => {
                        isShow.value = false;
                    };
                    let {level} = props;
                    if ('success' === level) {
                        store.state.lastMessageTime = Date.now();
                    }
                    return {isShow, show, close};
                },
                created() {
                    this.show();
                },
                template,
                watch: {
                    isShow(nVal, oVal) {

                    }
                }
            };

            /*
            ===============================================
            */
            // app.js
            // <!-- 展示模板 -->
            var template = `
            <div>
                <div class="nav">
                    <h1 class="title">{{appName}}!</h1>
                    <p class="menu">
                        <!--使用 router-link 组件进行导航 -->
                        <!--通过传递 \`to\` 来指定链接 -->
                        <!--\`<router-link>\` 将呈现一个带有正确 \`href\` 属性的 \`<a>\` 标签-->
                        <router-link to="/">任务管理</router-link>
                        <router-link to="/proxy">代理配置</router-link>
                        <router-link to="/user">用户配置</router-link>
                        <router-link to="/config">系统配置</router-link>
                        <router-link to="/notify-email">通知邮箱</router-link>
                    </p>
                </div>
                
                <!-- 路由出口 -->
                <!-- 路由匹配到的组件将渲染在这里 -->
                <router-view></router-view>
                <!-- <a href="https://www.jianshu.com/p/b0c16bab3388">vue3使用is和v-is</a> -->
                <div v-is="'style'" scoped>
                </div>
                <!-- <Css></Css> -->
                <!-- <HeartBeat></HeartBeat> -->
            </div>
            `;
            // <!-- Vue 代码 -->


            let App = {
                name: 'App',
                data: () => {
                    return {
                        sharedState: store.state,
                        appName: 'Instagram Crawler Admin',
                        book: 'book1'
                    }
                },
                components: {
                    // Css, HeartBeat
                },
                template: template,
                mounted: () => {
                    const {proxy} = Vue.getCurrentInstance();
                    console.log('%s mounted', proxy.$options.name);
                    proxy.initApiDocs();
                },
                methods: {
                    initApiDocs() {
                        api.swagger.apiDocs().then(res => {
                            if (res.status === 200 && res.data && res.data.components) {
                                this.sharedState.apiDocs = res.data;
                                console.log('load apiDocs', this.sharedState.apiDocs);
                            }
                        }).catch(e => {
                            console.log('load apiDocs error', e)
                        });
                    }
                }
            };

            /*
            ==================== 路由 =================================
            ================================================
            */
            // 1. 定义路由组件.
            // 也可以从其他文件导入
            // const Task = { template: '<div>Task Page</div>' };
            // const Proxy = { template: '<div>Proxy Page</div>' };

            // 2. 定义一些路由
            // 每个路由都需要映射到一个组件。
            // 我们后面再讨论嵌套路由。
            const routes = [
                // {path: '/', component: Task},
                // {path: '/proxy', component: ProxyCom},
                // {path: '/config', component: Config},
                // {path: '/user', component: User},
                // {path: '/notify-email', component: NotifyEmail},
            ];



            /*
            ==================== 初始化 =================================
            =============================================================
            */
            // axios 自定义超时时间
            axios.defaults.timeout = appConfig.axiosTimeOut;

            let cloneApis = JSON.parse(JSON.stringify(apis));
            let api = build(cloneApis);
            window.api = api;
            window.appConfig = appConfig;

            // 3. 创建路由实例并传递 `routes` 配置
            // 你可以在这里输入更多的配置,但我们在这里
            // 暂时保持简单
            const router = VueRouter.createRouter({
                // 4. 内部提供了 history 模式的实现。为了简单起见,我们在这里使用 hash 模式。
                history: VueRouter.createWebHashHistory(),
                routes, // `routes: routes` 的缩写
            });

            // 5. 创建并挂载根实例
            const app = Vue.createApp(App);
            
            /**
             * @see <a href="https://blog.csdn.net/qq_27694835/article/details/114243019">Vue3.0 挂载axios全局方法</a>
             * @type {(function(*=): *)|undefined}
             */
            app.config.globalProperties.$api = api;
            //确保 _use_ 路由实例使
            //整个应用支持路由。
            app.use(router);

            app.mount('#app-main');

            // 现在,应用已经启动了!


            // 消息组件 https://blog.csdn.net/hncu1990/article/details/119273475
            const {createApp, h} = Vue;

            const message = (props) => {
                const container = document.createElement("div");
                // 获取组件的DOM,将其挂载到body上
                const vm = createApp({
                    render() {
                        return h(Message, props);
                    },
                });
                const appMessage = document.getElementById("app-message");
                appMessage.appendChild(vm.mount(container).$el);
                // @see <a href="https://v3.cn.vuejs.org/api/application-api.html#unmount">Vue3 unmount</a>
                let {duration = 3} = props;
                setTimeout(() => {
                    vm.unmount();
                }, duration * 1000);
                return {
                    close: () => (vm.component.proxy.isShow = false),
                };
            };
            app.config.globalProperties.$message = message;

            console.log('================================ 程序脚本初始化完成 ================================')

 

posted on 2022-03-27 12:34  53221  阅读(21)  评论(0编辑  收藏  举报
页脚11111111111