import { LoDashStatic } from "lodash"; import _ from "lodash"; /* @ts-ignore */ import dayjs from "dayjs"; import $ from "jquery"; import { iStorage } from "./tools/storage"; import { State_UI } from "."; //@ts-ignore import axios from "axios"; import { getCurrentInstance, onMounted, onUnmounted, reactive } from "vue"; /* 组件属性是否是on开头,组件的事件监听*/ const onRE = /^on[^a-z]/; const VueComponents: any = {}; const cache = {}; const privateLodash = { WORDS: { INVALID_DATE: "Invalid Date", format_ymd: "YYYY-MM-DD" }, useScopeCss() { const state = reactive({ id: "", cssEleSelector: "", content: "" }); function scopeCss(genCssStringFn) { const content = genCssStringFn({ selector: `[data-style-id-${state.cssEleSelector}]` }); $(state.id).html(content); } onMounted(() => { /* getCurrentInstance获取的vue实例与optional的this实例属性略有不同,ctx才是上下文,带有_.id */ const vm = getCurrentInstance(); state.cssEleSelector = `scope-css_${vm.uid}`; state.id = `#${state.cssEleSelector}`; let $cssEle = $(state.id); if ($cssEle.length === 0) { const domStyle = document.createElement("style"); domStyle.id = state.cssEleSelector; const domWrapper = vm.ctx.$el.__vnode ? vm.ctx.$el : vm.ctx.$el.parentElement; $(domWrapper) .attr(`data-style-id-${state.cssEleSelector}`, "") .append(domStyle); $cssEle = $(`#${state.cssEleSelector}`); } }); onUnmounted(() => { const wrapperAttr = `data-style-id-${state.cssEleSelector}`; const selector = `[${wrapperAttr}]`; $(state.id).remove(); $(selector).removeAttr(wrapperAttr); }); return { scopeCss }; }, launchFullscreen(element: any) { if (element.requestFullscreen) { element.requestFullscreen(); } }, exitFullscreen() { /* @ts-ignore */ document.exitFullscreen && document.exitFullscreen(); }, hashCode(str: string) { var hash = 0, i, chr; if (str.length === 0) { return "0"; } for (i = 0; i < str.length; i++) { chr = str.charCodeAt(i); hash = (hash << 5) - hash + chr; /* Convert to 32bit integer */ hash |= 0; } return String(hash); }, /* 从jQuery对象中,获取leftTop的数值 */ getLeftTopFromAbsolute($ele: JQuery) { const _top = $ele.css("top"); const _left = $ele.css("left"); const getNum = (x: string) => { const match = String(x).match(/^(.*)px$/); /* @ts-ignore */ if (match && match[1]) { /* @ts-ignore */ return Number(match[1]); } else { return 0; } }; const top = getNum(_top); const left = getNum(_left); return { top, left }; }, getLeftTopFromTranslate($ele: JQuery) { const transform = $ele.css("transform"); const match = String(transform).match(/^matrix\((.*)\)$/); if (!match) { return { top: 0, left: 0 }; } /* @ts-ignore */ if (match && match[1]) { /* @ts-ignore */ const [a, b, c, d, e, f] = String(match[1]) .split(",") .map(i => Number(_.trim(i))); return { left: a + c + e, top: b + d + f }; } }, /** * 用于Boundless 解析vue SFC文件 * @param {*} code * @returns */ async asyncImportSFC( url: string, /* window.Vue */ __Vue: object ): Promise { if (VueComponents[url]) { return VueComponents[url]; } const scfSourceCode = await privateLodash.asyncLoadText(url); const scfObjSourceCode = privateLodash.VueLoader(scfSourceCode); VueComponents[url] = await privateLodash.getVueComponentBySourceCode( url, scfObjSourceCode, __Vue ); return VueComponents[url]; }, async getVueComponentBySourceCode( url: string, scfObjSourceCode: string, __Vue: object ): Promise { /* @ts-ignore */ __Vue = __Vue || window.Vue || {}; scfObjSourceCode = scfObjSourceCode.replace("export default", ""); const scfObjAsyncFn = new Function( "argVue", `const THIS_FILE_URL = (\`${url}\`);try{const fn = ${scfObjSourceCode};return fn(argVue);}catch(e){console.error(e)}` ); const scfObj = await scfObjAsyncFn(__Vue); return scfObj; }, /* * @parseContent:满足`return {}`形式的字符串 */ parseContent: (returnSentence: string) => { if (!returnSentence) return; try { const fn = new Function(`${returnSentence} return module();`); return fn(); } catch (error) { xU(error); } }, genId, VueLoader: (code: string) => { function getSource(source: string, type: string) { var regex = new RegExp("<" + type + "[^>]*>"); var openingTag: any = source.match(regex); if (!openingTag) return ""; else openingTag = openingTag[0]; var targetSource = source.slice( source.indexOf(openingTag) + openingTag.length, source.lastIndexOf("") ); return type === "template" ? targetSource.replace(/`/g, "\\`") : targetSource; } function splitCode() { if (!/TEMPLATE_PLACEHOLDER/.test(code)) { /* @ts-ignore */ alert("SFC miss TEMPLATE_PLACEHOLDER"); /* @ts-ignore */ console.error(code); } return getSource(code, "script").replace( /TEMPLATE_PLACEHOLDER/, `template: \`${getSource(code, "template")}\`` ); } return splitCode(); }, /** * async 执行jsx module 文件 * @param {*} url */ async asyncExecFnString(url: string) { const data = await privateLodash.asyncLoadText(url); return privateLodash.parseContent(data); }, /*lodash IDE 能识别*/ doNothing: (...args: any[]) => { /* @ts-ignore */ if (localStorage.isShowDevLog) { const e = new Error(); /* @ts-ignore */ console.log("🚀:", e?.stack?.split("\n")[2].replace(" at ", "")); /* @ts-ignore */ /* @ts-ignore */ console.log.apply(console, args); } }, /* 睡眠 t:setTimeout during time*/ /* @ts-ignore */ sleep, isOn: (key: string) => onRE.test(key), isModelListener: (key: string) => { key = String(key); if (!key) { return false; } return key.startsWith("onUpdate:"); }, isListener: (key: any) => { key = String(key); if (!key) { return false; } return privateLodash.isOn(key) || privateLodash.isModelListener(key); }, /*是否非空数组*/ isArrayFill: (arr: any) => { if (Array.isArray(arr)) { if (arr.length > 0) { return true; } } return false; }, /*对象至少有一个属性*/ isObjectFill: (obj: any) => _.isPlainObject(obj) && Object.keys(obj).length > 0, /*** * 返回数组的第一个value, * 通过check, * 为真则返回value, * 否则返回false, * 默认check为 xU.isInput * @param arr * @param fnCheck * @return {firstValue|false} */ safeFirst: (arr: any[], fnCheck: Function) => { fnCheck = fnCheck || ((value: any) => privateLodash.isInput(value)); const obj = _.first(arr); return fnCheck(obj) ? obj : false; }, /*** * * @param val * @param isBeautiful * @return {string} */ safeToString: (val: object, isBeautiful = false) => { try { if (isBeautiful) { return JSON.stringify(val, null, 2); } else { return JSON.stringify(val); } } catch (error) { return ""; } }, safeParse: (val: string, defaultObj: {}) => { let obj = defaultObj; try { obj = JSON.parse(val); if (!val) { obj = defaultObj; throw new Error("json parse error"); } } catch (error) { privateLodash.doNothing(error); } return obj; }, safeSplit: (target: string, sp = "") => { return target?.split ? target.split(sp) : []; }, /*** * dayjs对象或者"" * @param val * @return {string|dayjs.Dayjs} */ safeDate: (val: dayjs.ConfigType) => { if (!val) { return ""; } let date = dayjs(val); /* @ts-ignore */ if (date === privateLodash.WORDS.INVALID_DATE) { return ""; } else { return date; } }, /* */ /*** * false 0 都算已输入 * @param val {any} * @returns {boolean} */ isInput, /*jquery到底有没有选中目标DOM?*/ is$Selected: ($ele: JQuery) => $ele && $ele.jquery && $ele.length > 0, /** * 获取对象的键和值 * 这个方法很灵性,有时候后面来的结构长这样 {id:value},有且只有一个属性, * 但凡写个Interface 规定数据长这样,通用性都更好 * [{ * prop:'id', * value:'12345', * label:'唯一标识符' * }] * @param {*} obj * @param {*} defaultValue * @returns */ getObjectFirstKeyValue: (obj: object, defaultValue: "") => { if (!obj) { return defaultValue; } const keyArray = Object.keys(obj); if (!privateLodash.isArrayFill(keyArray)) return defaultValue; const prop = keyArray[0]; /* @ts-ignore */ return privateLodash.isInput(prop) && obj[prop] ? obj[prop] : defaultValue; }, /** * * @param {*} cssname * @returns */ loadCss(cssname: string) { const cssPath = `${cssname}`; let $link = $("", { rel: "stylesheet", type: "text/css" }); $link.appendTo($("head")); /* @ts-ignore */ $link[0].href = `${cssPath}?_t=${Date.now()}`; /* destroy 的时候移除已加载的模块css,酌情使用 */ return () => { $link.remove(); /* @ts-ignore */ $link = null; }; }, async asyncLoadStyle(cssURL: string, options?: object) { /* @ts-ignore */ let { isReplace, id } = options || { isReplace: false, id: "" }; /* 提供ID 用于替换同一个style 元素的内容 */ id = id || _.camelCase(cssURL); let content; let $style = $(`#${id}`); if ($style.length == 0) { /* 如果不存在,加载内容 */ $style = $("