diff --git a/package.json b/package.json
index 08ce0971..8beb0480 100644
--- a/package.json
+++ b/package.json
@@ -16,24 +16,26 @@
"jquery": "^3.5.1",
"laravel-mix": "^6.0.6",
"lodash": "^4.17.19",
+ "postcss": "^8.1.14",
+ "resolve-url-loader": "^3.1.3",
+ "sass": "^1.34.0",
+ "sass-loader": "^11.1.1",
"stylus": "^0.54.8",
"stylus-loader": "^3.0.2",
"vue": "^2.6.12",
+ "vue-loader": "^15.9.7",
"vue-router": "^3.4.2",
- "vue-template-compiler": "^2.6.11",
- "postcss": "^8.1.14"
+ "vue-template-compiler": "^2.6.11"
},
"dependencies": {
- "@chenfengyuan/vue-qrcode": "^1.0.2",
- "echarts": "^5.0.0",
- "internal-ip": "^6.1.0",
- "tinymce": "^5.6.2",
+ "echarts": "^5.1.1",
+ "tinymce": "^5.8.1",
"view-design-hi": "^4.5.0-4",
"vue-clipboard2": "^0.3.1",
"vue-emoji-picker": "^1.0.1",
"vue-kityminder-gg": "^1.3.6",
"vue-resize-observer": "^1.0.37",
"vuedraggable": "^2.24.3",
- "xlsx": "^0.16.9"
+ "xlsx": "^0.17.0"
}
}
diff --git a/resources/css/app.css b/resources/css/app.css
deleted file mode 100644
index e69de29b..00000000
diff --git a/resources/js/App.vue b/resources/js/App.vue
new file mode 100755
index 00000000..62c9008f
--- /dev/null
+++ b/resources/js/App.vue
@@ -0,0 +1,212 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/resources/js/app.js b/resources/js/app.js
index 40c55f65..da57313f 100644
--- a/resources/js/app.js
+++ b/resources/js/app.js
@@ -1 +1,81 @@
-require('./bootstrap');
+import Vue from 'vue'
+import App from './App.vue'
+import routes from './routes'
+import VueRouter from 'vue-router'
+import ViewUI from 'view-design-hi';
+import Language from './common/language/index'
+import Mixins from './common/mixins/index'
+
+import './common/functions/index'
+import './main'
+
+Vue.use(VueRouter);
+Vue.use(ViewUI);
+Vue.use(Language);
+Vue.use(Mixins);
+
+import PageTitle from './common/components/PageTitle.vue'
+import Loading from './common/components/Loading.vue'
+import AutoTip from './common/components/AutoTip.vue'
+import TableAction from './common/components/TableAction.vue'
+
+Vue.component('PageTitle', PageTitle);
+Vue.component('Loading', Loading);
+Vue.component('AutoTip', AutoTip);
+Vue.component('TableAction', TableAction);
+
+
+const originalPush = VueRouter.prototype.push
+VueRouter.prototype.push = function push(location) {
+ return originalPush.call(this, location).catch(err => err)
+}
+const router = new VueRouter({
+ mode: 'history',
+ routes
+});
+
+//进度条配置
+ViewUI.LoadingBar.config({
+ color: '#3fcc25',
+ failedColor: '#ff0000'
+});
+router.beforeEach((to, from, next) => {
+ ViewUI.LoadingBar.start();
+ next();
+});
+router.afterEach((to, from, next) => {
+ ViewUI.LoadingBar.finish();
+});
+
+//加载函数
+Vue.prototype.goForward = function(location, isReplace) {
+ if (typeof location === 'string') location = {name: location};
+ if (isReplace === true) {
+ this.$router.replace(location);
+ }else{
+ this.$router.push(location);
+ }
+};
+
+//返回函数
+Vue.prototype.goBack = function (number) {
+ let history = $A.jsonParse(window.sessionStorage['__history__'] || '{}');
+ if ($A.runNum(history['::count']) > 2) {
+ this.$router.go(typeof number === 'number' ? number : -1);
+ } else {
+ this.$router.replace(typeof number === "object" ? number : {path: '/'});
+ }
+};
+
+Vue.prototype.$A = $A;
+
+Vue.config.productionTip = false;
+
+const app = new Vue({
+ el: '#app',
+ router,
+ template: '',
+ components: { App }
+});
+
+$A.app = app;
diff --git a/resources/js/bootstrap.js b/resources/js/bootstrap.js
deleted file mode 100644
index 69225776..00000000
--- a/resources/js/bootstrap.js
+++ /dev/null
@@ -1,28 +0,0 @@
-window._ = require('lodash');
-
-/**
- * We'll load the axios HTTP library which allows us to easily issue requests
- * to our Laravel back-end. This library automatically handles sending the
- * CSRF token as a header based on the value of the "XSRF" token cookie.
- */
-
-window.axios = require('axios');
-
-window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
-
-/**
- * Echo exposes an expressive API for subscribing to channels and listening
- * for events that are broadcast by Laravel. Echo and event broadcasting
- * allows your team to easily build robust real-time web applications.
- */
-
-// import Echo from 'laravel-echo';
-
-// window.Pusher = require('pusher-js');
-
-// window.Echo = new Echo({
-// broadcaster: 'pusher',
-// key: process.env.MIX_PUSHER_APP_KEY,
-// cluster: process.env.MIX_PUSHER_APP_CLUSTER,
-// forceTLS: true
-// });
diff --git a/resources/js/common/components/AutoTip.vue b/resources/js/common/components/AutoTip.vue
new file mode 100644
index 00000000..86012f2c
--- /dev/null
+++ b/resources/js/common/components/AutoTip.vue
@@ -0,0 +1,85 @@
+
+
+
+
+ {{text}}
+
+
+
+
+
diff --git a/resources/js/common/components/ImgUpload.vue b/resources/js/common/components/ImgUpload.vue
new file mode 100755
index 00000000..adb423d3
--- /dev/null
+++ b/resources/js/common/components/ImgUpload.vue
@@ -0,0 +1,594 @@
+
+
+
+
+
+
+
+
+
+ {{$L('浏览')}}{{$L('图片')}}
+
+
+
+ {{$L('上传')}}{{$L('图片')}}
+
+
+
+
+
+ {{$L('加载中...')}}
+
+
+
+
+
+
![]()
+
+
+
+
+
+
+
diff --git a/resources/js/common/components/Loading.vue b/resources/js/common/components/Loading.vue
new file mode 100644
index 00000000..b3e67673
--- /dev/null
+++ b/resources/js/common/components/Loading.vue
@@ -0,0 +1,108 @@
+
+
+
+
+
+
diff --git a/resources/js/common/components/PageTitle.vue b/resources/js/common/components/PageTitle.vue
new file mode 100755
index 00000000..3375a9b2
--- /dev/null
+++ b/resources/js/common/components/PageTitle.vue
@@ -0,0 +1,64 @@
+
+
+
+
+
diff --git a/resources/js/common/components/Spinner.vue b/resources/js/common/components/Spinner.vue
new file mode 100644
index 00000000..f41c5a45
--- /dev/null
+++ b/resources/js/common/components/Spinner.vue
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
diff --git a/resources/js/common/components/TEditor.vue b/resources/js/common/components/TEditor.vue
new file mode 100755
index 00000000..cd5c4095
--- /dev/null
+++ b/resources/js/common/components/TEditor.vue
@@ -0,0 +1,545 @@
+
+
+
+
+
+
+ {{$L('加载组件中...')}}
+
+
+
+
+
+
+ {{$L('正在上传文件...')}}
+
+
+
+
+
+
+
+
+
+
+ {{$L('正在上传文件...')}}
+
+
+
+
+
+
+
+
+
diff --git a/resources/js/common/components/TableAction.vue b/resources/js/common/components/TableAction.vue
new file mode 100644
index 00000000..8b61e31c
--- /dev/null
+++ b/resources/js/common/components/TableAction.vue
@@ -0,0 +1,84 @@
+
+
+
+
+
diff --git a/resources/js/common/components/TagInput.vue b/resources/js/common/components/TagInput.vue
new file mode 100755
index 00000000..208e52c6
--- /dev/null
+++ b/resources/js/common/components/TagInput.vue
@@ -0,0 +1,222 @@
+
+
+
+
+
+
diff --git a/resources/js/common/directives/clickoutside.js b/resources/js/common/directives/clickoutside.js
new file mode 100755
index 00000000..6d75fc3d
--- /dev/null
+++ b/resources/js/common/directives/clickoutside.js
@@ -0,0 +1,21 @@
+export default {
+ bind (el, binding, vnode) {
+ function documentHandler (e) {
+ if (el.contains(e.target)) {
+ return false;
+ }
+ if (binding.expression) {
+ binding.value(e);
+ }
+ }
+ el.__vueClickOutside__ = documentHandler;
+ document.addEventListener('click', documentHandler);
+ },
+ update () {
+
+ },
+ unbind (el, binding) {
+ document.removeEventListener('click', el.__vueClickOutside__);
+ delete el.__vueClickOutside__;
+ }
+};
\ No newline at end of file
diff --git a/resources/js/common/directives/popper-novalue.js b/resources/js/common/directives/popper-novalue.js
new file mode 100755
index 00000000..b4b83f1b
--- /dev/null
+++ b/resources/js/common/directives/popper-novalue.js
@@ -0,0 +1,108 @@
+/**
+ * https://github.com/freeze-component/vue-popper
+ * */
+import Vue from 'vue';
+const isServer = Vue.prototype.$isServer;
+const Popper = isServer ? function() {} : require('popper.js/dist/umd/popper.js'); // eslint-disable-line
+
+export default {
+ props: {
+ placement: {
+ type: String,
+ default: 'bottom'
+ },
+ boundariesPadding: {
+ type: Number,
+ default: 5
+ },
+ reference: Object,
+ popper: Object,
+ offset: {
+ default: 0
+ },
+ transition: String,
+ options: {
+ type: Object,
+ default () {
+ return {
+ modifiers: {
+ computeStyle:{
+ gpuAcceleration: false,
+ },
+ preventOverflow :{
+ boundariesElement: 'window'
+ }
+ }
+ };
+ }
+ }
+ },
+ data () {
+ return {
+ visible: false
+ };
+ },
+ watch: {
+ visible(val) {
+ if (val) {
+ if (this.handleIndexIncrease) this.handleIndexIncrease(); // just use for Poptip
+ this.updatePopper();
+ this.$emit('on-popper-show');
+ } else {
+ this.$emit('on-popper-hide');
+ }
+ }
+ },
+ methods: {
+ createPopper() {
+ if (isServer) return;
+ if (!/^(top|bottom|left|right)(-start|-end)?$/g.test(this.placement)) {
+ return;
+ }
+
+ const options = this.options;
+ const popper = this.popper || this.$refs.popper;
+ const reference = this.reference || this.$refs.reference;
+
+ if (!popper || !reference) return;
+
+ if (this.popperJS && this.popperJS.hasOwnProperty('destroy')) {
+ this.popperJS.destroy();
+ }
+
+ options.placement = this.placement;
+
+ if (!options.modifiers.offset) {
+ options.modifiers.offset = {};
+ }
+ options.modifiers.offset.offset = this.offset;
+ options.onCreate =()=>{
+ this.$nextTick(this.updatePopper);
+ this.$emit('created', this);
+ };
+
+ this.popperJS = new Popper(reference, popper, options);
+
+ },
+ updatePopper() {
+ if (isServer) return;
+ this.popperJS ? this.popperJS.update() : this.createPopper();
+ },
+ doDestroy() {
+ if (isServer) return;
+ if (this.visible) return;
+ this.popperJS.destroy();
+ this.popperJS = null;
+ }
+ },
+ updated (){
+ this.$nextTick(()=>this.updatePopper());
+
+ },
+ beforeDestroy() {
+ if (isServer) return;
+ if (this.popperJS) {
+ this.popperJS.destroy();
+ }
+ }
+};
diff --git a/resources/js/common/directives/transfer-dom.js b/resources/js/common/directives/transfer-dom.js
new file mode 100644
index 00000000..6c2a0cf0
--- /dev/null
+++ b/resources/js/common/directives/transfer-dom.js
@@ -0,0 +1,77 @@
+// Thanks to: https://github.com/airyland/vux/blob/v2/src/directives/transfer-dom/index.js
+// Thanks to: https://github.com/calebroseland/vue-dom-portal
+
+/**
+ * Get target DOM Node
+ * @param {(Node|string|Boolean)} [node=document.body] DOM Node, CSS selector, or Boolean
+ * @return {Node} The target that the el will be appended to
+ */
+function getTarget (node) {
+ if (node === void 0) {
+ node = document.body
+ }
+ if (node === true) { return document.body }
+ return node instanceof window.Node ? node : document.querySelector(node)
+}
+
+const directive = {
+ inserted (el, { value }, vnode) {
+ if ( el.dataset && el.dataset.transfer !== 'true') return false;
+ el.className = el.className ? el.className + ' v-transfer-dom' : 'v-transfer-dom';
+ const parentNode = el.parentNode;
+ if (!parentNode) return;
+ const home = document.createComment('');
+ let hasMovedOut = false;
+
+ if (value !== false) {
+ parentNode.replaceChild(home, el); // moving out, el is no longer in the document
+ getTarget(value).appendChild(el); // moving into new place
+ hasMovedOut = true
+ }
+ if (!el.__transferDomData) {
+ el.__transferDomData = {
+ parentNode: parentNode,
+ home: home,
+ target: getTarget(value),
+ hasMovedOut: hasMovedOut
+ }
+ }
+ },
+ componentUpdated (el, { value }) {
+ if ( el.dataset && el.dataset.transfer !== 'true') return false;
+ // need to make sure children are done updating (vs. `update`)
+ const ref$1 = el.__transferDomData;
+ if (!ref$1) return;
+ // homes.get(el)
+ const parentNode = ref$1.parentNode;
+ const home = ref$1.home;
+ const hasMovedOut = ref$1.hasMovedOut; // recall where home is
+
+ if (!hasMovedOut && value) {
+ // remove from document and leave placeholder
+ parentNode.replaceChild(home, el);
+ // append to target
+ getTarget(value).appendChild(el);
+ el.__transferDomData = Object.assign({}, el.__transferDomData, { hasMovedOut: true, target: getTarget(value) });
+ } else if (hasMovedOut && value === false) {
+ // previously moved, coming back home
+ parentNode.replaceChild(el, home);
+ el.__transferDomData = Object.assign({}, el.__transferDomData, { hasMovedOut: false, target: getTarget(value) });
+ } else if (value) {
+ // already moved, going somewhere else
+ getTarget(value).appendChild(el);
+ }
+ },
+ unbind (el) {
+ if (el.dataset && el.dataset.transfer !== 'true') return false;
+ el.className = el.className.replace('v-transfer-dom', '');
+ const ref$1 = el.__transferDomData;
+ if (!ref$1) return;
+ if (el.__transferDomData.hasMovedOut === true) {
+ el.__transferDomData.parentNode && el.__transferDomData.parentNode.appendChild(el)
+ }
+ el.__transferDomData = null
+ }
+};
+
+export default directive;
\ No newline at end of file
diff --git a/resources/js/common/directives/v-click-outside-x.js b/resources/js/common/directives/v-click-outside-x.js
new file mode 100644
index 00000000..12505f82
--- /dev/null
+++ b/resources/js/common/directives/v-click-outside-x.js
@@ -0,0 +1,219 @@
+const CLICK = 'click';
+const captureInstances = Object.create(null);
+const nonCaptureInstances = Object.create(null);
+const instancesList = [captureInstances, nonCaptureInstances];
+
+/**
+ * The common event handler for bot capture and non-capture events.
+ *
+ * @param {!Object} context - The event context.
+ * @param {!Object} instances - The capture or non-capture registered instances.
+ * @param {Event} event - The event object.
+ * @returns {undefined} Default.
+ */
+const commonHandler = function _onCommonEvent(context, instances, event) {
+ const {target} = event;
+
+ const itemIteratee = function _itemIteratee(item) {
+ const {el} = item;
+
+ if (el !== target && !el.contains(target)) {
+ const {binding} = item;
+
+ if (binding.modifiers.stop) {
+ event.stopPropagation();
+ }
+
+ if (binding.modifiers.prevent) {
+ event.preventDefault();
+ }
+
+ binding.value.call(context, event);
+ }
+ };
+
+ const keysIteratee = function _keysIteratee(eventName) {
+ return instances[eventName].forEach(itemIteratee);
+ };
+
+ Object.keys(instances).forEach(keysIteratee);
+};
+
+/**
+ * Event handler for capture events.
+ *
+ * @param {Event} event - The event object.
+ */
+const captureEventHandler = function onCaptureEvent(event) {
+ /* eslint-disable-next-line babel/no-invalid-this */
+ commonHandler(this, captureInstances, event);
+};
+
+/**
+ * Event handler for non-capture events.
+ *
+ * @param {Event} event - The event object.
+ */
+const nonCaptureEventHandler = function onNonCaptureEvent(event) {
+ /* eslint-disable-next-line babel/no-invalid-this */
+ commonHandler(this, nonCaptureInstances, event);
+};
+
+/**
+ * Get the correct event handler: Capture or non-capture.
+ *
+ * @param {boolean} useCapture - Indicate which handler to use; 'true' to use
+ * capture handler or 'false' for non-capture.
+ * @returns {Function} - The event handler.
+ */
+const getEventHandler = function _getEventHandler(useCapture) {
+ return useCapture ? captureEventHandler : nonCaptureEventHandler;
+};
+
+/**
+ * The directive definition.
+ * {@link https://vuejs.org/v2/guide/custom-directive.html|Custom directive}
+ *
+ * @namespace
+ * @property {!Object} $_captureInstances - Registered capture instances.
+ * @property {!Object} $_nonCaptureInstances - Registered non-capture instances.
+ * @property {Function} $_onCaptureEvent - Event handler for capture events.
+ * @property {Function} $_onNonCaptureEvent - Event handler for non-capture events.
+ * @property {Function} bind - Called only once, when the directive is first
+ * bound to the element.
+ * @property {Function} unbind - Called only once, when the directive is unbound
+ * from the element.
+ * @property {string} version - The version number of this release.
+ */
+export const directive = Object.defineProperties(
+ {},
+ {
+ $_captureInstances: {
+ value: captureInstances,
+ },
+
+ $_nonCaptureInstances: {
+ value: nonCaptureInstances,
+ },
+
+ $_onCaptureEvent: {
+ value: captureEventHandler,
+ },
+
+ $_onNonCaptureEvent: {
+ value: nonCaptureEventHandler,
+ },
+
+ /**
+ * 注意,这里的 arg 修改为 capture,这样可以动态设置,原先的事件作为 modifiers
+ * */
+ bind: {
+ value: function bind(el, binding) {
+ if (typeof binding.value !== 'function') {
+ throw new TypeError('Binding value must be a function.');
+ }
+
+ let eventType;
+ const modifiers = binding.modifiers;
+ if (modifiers.click) eventType = 'click';
+ else if (modifiers.mousedown) eventType = 'mousedown';
+ else if (modifiers.touchstart) eventType = 'touchstart';
+ else eventType = CLICK;
+
+ const useCapture = binding.arg;
+
+ const normalisedBinding = {
+ ...binding,
+ ...{
+ modifiers: {
+ ...{
+ capture: false,
+ prevent: false,
+ stop: false,
+ },
+ ...binding.modifiers,
+ },
+ },
+ };
+
+ const instances = useCapture ? captureInstances : nonCaptureInstances;
+
+ if (!Array.isArray(instances[eventType])) {
+ instances[eventType] = [];
+ }
+
+ if (instances[eventType].push({el, binding: normalisedBinding}) === 1) {
+ if (typeof document === 'object' && document) {
+ document.addEventListener(
+ eventType,
+ getEventHandler(useCapture),
+ useCapture,
+ );
+ }
+ }
+ },
+ },
+
+ unbind: {
+ value: function unbind(el) {
+ const compareElements = function _compareElements(item) {
+ return item.el !== el;
+ };
+
+ const instancesIteratee = function _instancesIteratee(instances) {
+ const instanceKeys = Object.keys(instances);
+
+ if (instanceKeys.length) {
+ const useCapture = instances === captureInstances;
+
+ const keysIteratee = function _keysIteratee(eventName) {
+ const newInstance = instances[eventName].filter(compareElements);
+
+ if (newInstance.length) {
+ instances[eventName] = newInstance;
+ } else {
+ if (typeof document === 'object' && document) {
+ document.removeEventListener(
+ eventName,
+ getEventHandler(useCapture),
+ useCapture,
+ );
+ }
+
+ delete instances[eventName];
+ }
+ };
+
+ instanceKeys.forEach(keysIteratee);
+ }
+ };
+
+ instancesList.forEach(instancesIteratee);
+ },
+ },
+
+ /* Note: This needs to be manually updated to match package.json. */
+ version: {
+ enumerable: true,
+ value: '3.7.1',
+ },
+ },
+);
+
+/**
+ * @typedef {Function} Vue - The constructor.
+ * @property {Function} directive - You can register a global custom directive
+ * with the Vue.directive() method, passing in a directiveID followed by a
+ * definition object.
+ */
+
+/**
+ * A Vue.js plugin should expose an install method. The method will be called
+ * with the Vue constructor as the first argument, along with possible options.
+ * {@link https://vuejs.org/v2/guide/plugins.html#Writing-a-Plugin|Writing a plugin}.
+ *
+ * @param {Vue} Vue - The Vue function.
+ */
+export function install(Vue) {
+ Vue.directive('click-outside', directive);
+}
diff --git a/resources/js/common/functions/index.js b/resources/js/common/functions/index.js
new file mode 100755
index 00000000..03d41cf1
--- /dev/null
+++ b/resources/js/common/functions/index.js
@@ -0,0 +1,1549 @@
+/**
+ * 基础函数
+ */
+(function (window, $, undefined) {
+
+ let serverUrl = window.location.origin + '/';
+
+ /**
+ * =============================================================================
+ * ************************** 基础函数类 **************************
+ * =============================================================================
+ */
+ $.extend({
+ /**
+ * 是否数组
+ * @param obj
+ * @returns {boolean}
+ */
+ isArray(obj) {
+ return typeof (obj) == "object" && Object.prototype.toString.call(obj).toLowerCase() == '[object array]' && typeof obj.length == "number";
+ },
+
+ /**
+ * 是否数组对象
+ * @param obj
+ * @returns {boolean}
+ */
+ isJson(obj) {
+ return typeof (obj) == "object" && Object.prototype.toString.call(obj).toLowerCase() == "[object object]" && typeof obj.length == "undefined";
+ },
+
+ /**
+ * 身份识别码
+ * @param text
+ * @returns {*|string}
+ */
+ token: function (text) {
+ let token = this.storage('token') || '';
+ if (typeof text === 'string') {
+ this.storage('token', text);
+ token = text;
+ }
+ return token;
+ },
+
+ /**
+ * 随机获取范围
+ * @param Min
+ * @param Max
+ * @returns {*}
+ */
+ randNum(Min,Max){
+ let Range = Max - Min;
+ let Rand = Math.random();
+ return Min + Math.round(Rand * Range); //四舍五入
+ },
+
+ /**
+ * 获取数组最后一个值
+ * @param array
+ * @returns {boolean}
+ */
+ last: function (array) {
+ let str = false;
+ if (typeof array === 'object' && array.length > 0) {
+ str = array[array.length - 1];
+ }
+ return str;
+ },
+
+
+ /**
+ * 字符串是否包含
+ * @param string
+ * @param find
+ * @param lower
+ * @returns {boolean}
+ */
+ strExists: function (string, find, lower = false) {
+ string += "";
+ find += "";
+ if (lower !== true) {
+ string = string.toLowerCase();
+ find = find.toLowerCase();
+ }
+ return (string.indexOf(find) !== -1);
+ },
+
+ /**
+ * 字符串是否左边包含
+ * @param string
+ * @param find
+ * @param lower
+ * @returns {boolean}
+ */
+ leftExists: function (string, find, lower = false) {
+ string += "";
+ find += "";
+ if (lower !== true) {
+ string = string.toLowerCase();
+ find = find.toLowerCase();
+ }
+ return (string.substring(0, find.length) === find);
+ },
+
+ /**
+ * 删除左边字符串
+ * @param string
+ * @param find
+ * @param lower
+ * @returns {string}
+ */
+ leftDelete: function (string, find, lower = false) {
+ string += "";
+ find += "";
+ if (this.leftExists(string, find, lower)) {
+ string = string.substring(find.length)
+ }
+ return string ? string : '';
+ },
+
+ /**
+ * 字符串是否右边包含
+ * @param string
+ * @param find
+ * @param lower
+ * @returns {boolean}
+ */
+ rightExists: function (string, find, lower = false) {
+ string += "";
+ find += "";
+ if (lower !== true) {
+ string = string.toLowerCase();
+ find = find.toLowerCase();
+ }
+ return (string.substring(string.length - find.length) === find);
+ },
+
+ /**
+ * 取字符串中间
+ * @param string
+ * @param start
+ * @param end
+ * @returns {*}
+ */
+ getMiddle: function (string, start, end) {
+ string = string.toString();
+ if (this.ishave(start) && this.strExists(string, start)) {
+ string = string.substring(string.indexOf(start) + start.length);
+ }
+ if (this.ishave(end) && this.strExists(string, end)) {
+ string = string.substring(0, string.indexOf(end));
+ }
+ return string;
+ },
+
+ /**
+ * 截取字符串
+ * @param string
+ * @param start
+ * @param end
+ * @returns {string}
+ */
+ subString: function(string, start, end) {
+ string += "";
+ if (!this.ishave(end)) {
+ end = string.length;
+ }
+ return string.substring(start, end);
+ },
+
+ /**
+ * 随机字符
+ * @param len
+ * @returns {string}
+ */
+ randomString: function (len) {
+ len = len || 32;
+ let $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678oOLl9gqVvUuI1';
+ let maxPos = $chars.length;
+ let pwd = '';
+ for (let i = 0; i < len; i++) {
+ pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
+ }
+ return pwd;
+ },
+
+ /**
+ * 判断是否有
+ * @param set
+ * @returns {boolean}
+ */
+ ishave: function (set) {
+ return !!(set !== null && set !== "null" && set !== undefined && set !== "undefined" && set);
+ },
+
+ /**
+ * 相当于 intval
+ * @param str
+ * @param fixed
+ * @returns {number}
+ */
+ runNum: function (str, fixed) {
+ let _s = Number(str);
+ if (_s + "" === "NaN") {
+ _s = 0;
+ }
+ if (/^[0-9]*[1-9][0-9]*$/.test(fixed)) {
+ _s = _s.toFixed(fixed);
+ let rs = _s.indexOf('.');
+ if (rs < 0) {
+ _s += ".";
+ for (let i = 0; i < fixed; i++) {
+ _s += "0";
+ }
+ }
+ }
+ return _s;
+ },
+
+ /**
+ * 服务器地址
+ * @param str
+ * @returns {string}
+ */
+ serverUrl: function (str) {
+ if (str.substring(0, 2) === "//" ||
+ str.substring(0, 7) === "http://" ||
+ str.substring(0, 8) === "https://" ||
+ str.substring(0, 6) === "ftp://" ||
+ str.substring(0, 1) === "/") {
+ return str;
+ }
+ return serverUrl + str;
+ },
+
+ /**
+ * 获取IP地址详情
+ * @param ip
+ * @param callback
+ */
+ getIpInfo: function(ip, callback) {
+ if (!this.strExists(ip, ".")) {
+ return;
+ }
+ let keyName = '__ip' + ip.substring(0, 1) + '__';
+ let key = this.getMiddle(ip, '', '.');
+ let res = this.loadFromlLocal(key, ip, '', keyName);
+ if (typeof res == "object") {
+ if (typeof callback == "function") {
+ callback(res);
+ }
+ return;
+ }
+ $A.ajaxc({
+ url: $A.serverUrl('api/system/get/ipinfo'),
+ data: { ip: ip },
+ timeout: 8000,
+ success: (res) => {
+ this.savaToLocal(key, ip, res, keyName);
+ if (typeof callback == "function") {
+ callback(res);
+ }
+ }
+ });
+ },
+
+ /**
+ * 新增&&获取缓存数据
+ * @param key
+ * @param value
+ * @returns {*}
+ */
+ storage: function(key, value) {
+ let keyName = 'app';
+ switch (window.location.pathname) {
+ case "/admin":
+ keyName+= ":" + window.location.pathname.substr(1);
+ break;
+ }
+ if (typeof value === 'undefined') {
+ return this.loadFromlLocal('__::', key, '', '__' + keyName + '__');
+ }else{
+ this.savaToLocal('__::', key, value, '__' + keyName + '__');
+ }
+ },
+
+ /**
+ * 新增&&修改本地缓存
+ * @param {string} id 唯一id
+ * @param {string} key 标示
+ * @param value 新增&修改的值
+ * @param keyName 主键名称
+ */
+ savaToLocal: function(id, key, value, keyName) {
+ try {
+ if (typeof keyName === 'undefined') keyName = '__seller__';
+ let seller = window.localStorage[keyName];
+ if (!seller) {
+ seller = {};
+ seller[id] = {};
+ } else {
+ seller = JSON.parse(seller);
+ if (!seller[id]) {
+ seller[id] = {};
+ }
+ }
+ seller[id][key] = value;
+ window.localStorage[keyName] = JSON.stringify(seller);
+ } catch(e) { }
+ },
+
+ /**
+ * 查询本地缓存
+ * @param {string} id 唯一id
+ * @param {string} key 标示
+ * @param def 如果查询不到显示的值
+ * @param keyName 主键名称
+ */
+ loadFromlLocal: function(id, key, def, keyName) {
+ if (typeof keyName === 'undefined') keyName = '__seller__';
+ let seller = window.localStorage[keyName];
+ if (!seller) {
+ return def;
+ }
+ seller = JSON.parse(seller)[id];
+ if (!seller) {
+ return def;
+ }
+ let ret = seller[key];
+ return ret || def;
+ },
+
+ /**
+ * 补零
+ * @param str
+ * @param length
+ * @param after
+ * @returns {*}
+ */
+ zeroFill: function(str, length, after) {
+ str+= "";
+ if (str.length >= length) {
+ return str;
+ }
+ let _str = '', _ret = '';
+ for (let i = 0; i < length; i++) {
+ _str += '0';
+ }
+ if (after || typeof after === 'undefined') {
+ _ret = (_str + "" + str).substr(length * -1);
+ } else {
+ _ret = (str + "" + _str).substr(0, length);
+ }
+ return _ret;
+ },
+
+ /**
+ * 时间戳转时间格式
+ * @param format
+ * @param v
+ * @returns {string}
+ */
+ formatDate: function(format, v) {
+ if (format === '') {
+ format = 'Y-m-d H:i:s';
+ }
+ let dateObj;
+ if (v instanceof Date) {
+ dateObj = v;
+ }else {
+ if (typeof v === 'undefined') {
+ v = new Date().getTime();
+ }else if (/^(-)?\d{1,10}$/.test(v)) {
+ v = v * 1000;
+ } else if (/^(-)?\d{1,13}$/.test(v)) {
+ v = v * 1000;
+ } else if (/^(-)?\d{1,14}$/.test(v)) {
+ v = v * 100;
+ } else if (/^(-)?\d{1,15}$/.test(v)) {
+ v = v * 10;
+ } else if (/^(-)?\d{1,16}$/.test(v)) {
+ v = v * 1;
+ } else {
+ return v;
+ }
+ dateObj = new Date(v);
+ }
+ //
+ format = format.replace(/Y/g, dateObj.getFullYear());
+ format = format.replace(/m/g, this.zeroFill(dateObj.getMonth() + 1, 2));
+ format = format.replace(/d/g, this.zeroFill(dateObj.getDate(), 2));
+ format = format.replace(/H/g, this.zeroFill(dateObj.getHours(), 2));
+ format = format.replace(/i/g, this.zeroFill(dateObj.getMinutes(), 2));
+ format = format.replace(/s/g, this.zeroFill(dateObj.getSeconds(), 2));
+ return format;
+ },
+
+ /**
+ * 租用时间差(不够1个小时算一个小时)
+ * @param s
+ * @param e
+ * @returns {*}
+ */
+ timeDiff: function(s, e) {
+ if (typeof e === 'undefined') {
+ e = Math.round(new Date().getTime()/1000);
+ }
+ let d = e - s;
+ if (d > 86400) {
+ let day = Math.floor(d / 86400);
+ let hour = Math.ceil((d - (day * 86400)) / 3600);
+ if (hour > 0) {
+ return day + '天' + hour + '小时';
+ } else {
+ return day + '天';
+ }
+ } else if (d > 3600) {
+ return Math.ceil(d / 3600) + '小时';
+ } else if (d > 60) {
+ return Math.ceil(d / 60) + '分钟';
+ } else if (d > 10) {
+ return d + '秒';
+ } else {
+ return '刚刚';
+ }
+ },
+
+ /**
+ * 检测手机号码格式
+ * @param str
+ * @returns {boolean}
+ */
+ isMobile: function(str) {
+ return /^1([3456789])\d{9}$/.test(str);
+ },
+
+ /**
+ * 是否手机号码
+ * @param phone
+ * @returns {boolean}
+ */
+ isPhone: function (phone) {
+ return this.isMobile(phone);
+ },
+
+ /**
+ * 根据两点间的经纬度计算距离
+ * @param lng1
+ * @param lat1
+ * @param lng2
+ * @param lat2
+ * @returns {string|*}
+ */
+ getDistance: function (lng1, lat1, lng2, lat2) {
+ let DEF_PI = 3.14159265359; // PI
+ let DEF_2PI = 6.28318530712; // 2*PI
+ let DEF_PI180 = 0.01745329252; // PI/180.0
+ let DEF_R = 6370693.5; // radius of earth
+ //
+ let ew1, ns1, ew2, ns2;
+ let dx, dy, dew;
+ let distance;
+ // 角度转换为弧度
+ ew1 = lng1 * DEF_PI180;
+ ns1 = lat1 * DEF_PI180;
+ ew2 = lng2 * DEF_PI180;
+ ns2 = lat2 * DEF_PI180;
+ // 经度差
+ dew = ew1 - ew2;
+ // 若跨东经和西经180 度,进行调整
+ if (dew > DEF_PI)
+ dew = DEF_2PI - dew;
+ else if (dew < -DEF_PI)
+ dew = DEF_2PI + dew;
+ dx = DEF_R * Math.cos(ns1) * dew; // 东西方向长度(在纬度圈上的投影长度)
+ dy = DEF_R * (ns1 - ns2); // 南北方向长度(在经度圈上的投影长度)
+ // 勾股定理求斜边长
+ distance = Math.sqrt(dx * dx + dy * dy).toFixed(0);
+ return distance;
+ },
+
+ /**
+ * 设置网页标题
+ * @param title
+ */
+ setTile(title) {
+ document.title = title;
+ let mobile = navigator.userAgent.toLowerCase();
+ if (/iphone|ipad|ipod/.test(mobile)) {
+ let iframe = document.createElement('iframe');
+ iframe.style.display = 'none';
+ iframe.setAttribute('src', '/favicon.ico');
+ let iframeCallback = function () {
+ setTimeout(function () {
+ iframe.removeEventListener('load', iframeCallback);
+ document.body.removeChild(iframe)
+ }, 0)
+ };
+ iframe.addEventListener('load', iframeCallback);
+ document.body.appendChild(iframe)
+ }
+ },
+
+ /**
+ * 克隆对象
+ * @param myObj
+ * @returns {*}
+ */
+ cloneData(myObj) {
+ if(typeof(myObj) !== 'object') return myObj;
+ if(myObj === null) return myObj;
+ //
+ if (typeof myObj.length === 'number') {
+ let [ ...myNewObj ] = myObj;
+ return myNewObj;
+ }else{
+ let { ...myNewObj } = myObj;
+ return myNewObj;
+ }
+ },
+
+ /**
+ * 克隆对象
+ * @param myObj
+ * @returns {*}
+ */
+ cloneJSON(myObj) {
+ if(typeof(myObj) !== 'object') return myObj;
+ if(myObj === null) return myObj;
+ //
+ return $A.jsonParse($A.jsonStringify(myObj))
+ },
+
+ /**
+ * 将一个 JSON 字符串转换为对象(已try)
+ * @param str
+ * @param defaultVal
+ * @returns {*}
+ */
+ jsonParse(str, defaultVal) {
+ if (str === null) {
+ return defaultVal ? defaultVal : {};
+ }
+ if (typeof str === "object") {
+ return str;
+ }
+ try {
+ return JSON.parse(str.replace(/\n/g,"\\n").replace(/\r/g,"\\r"));
+ } catch (e) {
+ return defaultVal ? defaultVal : {};
+ }
+ },
+
+ /**
+ * 将 JavaScript 值转换为 JSON 字符串(已try)
+ * @param json
+ * @param defaultVal
+ * @returns {string}
+ */
+ jsonStringify(json, defaultVal) {
+ if (typeof json !== 'object') {
+ return json;
+ }
+ try{
+ return JSON.stringify(json);
+ }catch (e) {
+ return defaultVal ? defaultVal : "";
+ }
+ },
+
+ /**
+ * 监听对象尺寸发生改变
+ * @param obj
+ * @param callback
+ */
+ resize(obj, callback) {
+ let myObj = $A(obj);
+ if (myObj.length === 0) return;
+ let height = parseInt(myObj.outerHeight()),
+ width = parseInt(myObj.outerWidth());
+ let inter = setInterval(()=>{
+ if (myObj.length === 0) clearInterval(inter);
+ let tmpHeight = parseInt(myObj.outerHeight()),
+ tmpWidth = parseInt(myObj.outerWidth());
+ if (height !== tmpHeight || width !== tmpWidth) {
+ height = tmpHeight;
+ width = tmpWidth;
+ console.log(width, height);
+ if (typeof callback === 'function') callback();
+ }
+ }, 250);
+ },
+
+ /**
+ * 是否IOS
+ * @returns {boolean|string}
+ */
+ isIos() {
+ let ua = typeof window !== 'undefined' && window.navigator.userAgent.toLowerCase();
+ return ua && /iphone|ipad|ipod|ios/.test(ua);
+ },
+
+ /**
+ * 是否安卓
+ * @returns {boolean|string}
+ */
+ isAndroid() {
+ let ua = typeof window !== 'undefined' && window.navigator.userAgent.toLowerCase();
+ return ua && ua.indexOf('android') > 0;
+ },
+
+ /**
+ * 是否微信
+ * @returns {boolean}
+ */
+ isWeixin() {
+ let ua = typeof window !== 'undefined' && window.navigator.userAgent.toLowerCase();
+ return (ua.match(/MicroMessenger/i) + '' === 'micromessenger');
+ },
+
+ /**
+ * 获取对象
+ * @param obj
+ * @param keys
+ * @returns {string|*}
+ */
+ getObject(obj, keys) {
+ let object = obj;
+ if (this.count(obj) === 0 || this.count(keys) === 0) {
+ return "";
+ }
+ let arr = keys.replace(/,/g, "|").replace(/\./g, "|").split("|");
+ $A.each(arr, (index, key) => {
+ object = typeof object[key] === "undefined" ? "" : object[key];
+ });
+ return object;
+ },
+
+ /**
+ * 统计数组或对象长度
+ * @param obj
+ * @returns {number}
+ */
+ count(obj) {
+ try {
+ if (typeof obj === "undefined") {
+ return 0;
+ }
+ if (typeof obj === "number") {
+ obj+= "";
+ }
+ if (typeof obj.length === 'number') {
+ return obj.length;
+ } else {
+ let i = 0, key;
+ for (key in obj) {
+ i++;
+ }
+ return i;
+ }
+ }catch (e) {
+ return 0;
+ }
+ },
+
+ /**
+ * 将数组或对象内容部分拼成字符串
+ * @param obj
+ * @returns {string}
+ */
+ objImplode(obj) {
+ if (obj === null) {
+ return "";
+ }
+ let str = "";
+ $A.each(obj, (key, val) => {
+ if (val !== null) {
+ if (typeof val === "object" && this.count(val) > 0) {
+ str += this.objImplode(val);
+ } else {
+ str += String(val);
+ }
+ }
+ });
+ return str.replace(/\s/g, "").replace(/undefined/g, "");
+ },
+
+ /**
+ * 指定键获取url参数
+ * @param key
+ * @returns {*}
+ */
+ urlParameter(key) {
+ let params = this.urlParameterAll();
+ return typeof key === "undefined" ? params : params[key];
+ },
+
+ urlParameterAll() {
+ let search = window.location.search || "";
+ let arr = [];
+ if (this.strExists(search, "?")) {
+ arr = this.getMiddle(search, "?").split("&");
+ }
+ let params = {};
+ for (let i = 0; i < arr.length; i++) {
+ let data = arr[i].split("=");
+ if (data.length === 2) {
+ params[data[0]] = data[1];
+ }
+ }
+ return params;
+ },
+
+ /**
+ * 删除地址中的参数
+ * @param url
+ * @param parameter
+ * @returns {string|*}
+ */
+ removeURLParameter(url, parameter) {
+ if (parameter instanceof Array) {
+ parameter.forEach((key) => {
+ url = $A.removeURLParameter(url, key)
+ });
+ return url;
+ }
+ var urlparts = url.split('?');
+ if (urlparts.length >= 2) {
+ //参数名前缀
+ var prefix = encodeURIComponent(parameter) + '=';
+ var pars = urlparts[1].split(/[&;]/g);
+
+ //循环查找匹配参数
+ for (var i = pars.length; i-- > 0;) {
+ if (pars[i].lastIndexOf(prefix, 0) !== -1) {
+ //存在则删除
+ pars.splice(i, 1);
+ }
+ }
+
+ return urlparts[0] + (pars.length > 0 ? '?' + pars.join('&') : '');
+ }
+ return url;
+ },
+
+ /**
+ * 连接加上参数
+ * @param url
+ * @param params
+ * @returns {*}
+ */
+ urlAddParams(url, params) {
+ if (typeof params === "object" && params !== null) {
+ url+= "";
+ url+= url.indexOf("?") === -1 ? '?' : '';
+ for (var key in params) {
+ if (!params.hasOwnProperty(key)) {
+ continue;
+ }
+ url+= '&' + key + '=' + params[key];
+ }
+ }
+ return url.replace("?&", "?");
+ },
+
+ /**
+ * 链接字符串
+ * @param value 第一个参数为连接符
+ * @returns {string}
+ */
+ stringConnect(...value) {
+ let s = null;
+ let text = "";
+ value.forEach((val) => {
+ if (s === null) {
+ s = val;
+ }else if (val){
+ if (val && text) text+= s;
+ text+= val;
+ }
+ });
+ return text;
+ },
+
+ /**
+ * 判断两个对象是否相等
+ * @param x
+ * @param y
+ * @returns {boolean}
+ */
+ objEquals(x, y) {
+ let f1 = x instanceof Object;
+ let f2 = y instanceof Object;
+ if (!f1 || !f2) {
+ return x === y
+ }
+ if (Object.keys(x).length !== Object.keys(y).length) {
+ return false
+ }
+ for (let p in x) {
+ if (x.hasOwnProperty(p)) {
+ let a = x[p] instanceof Object;
+ let b = y[p] instanceof Object;
+ if (a && b) {
+ if (!this.objEquals(x[p], y[p])) {
+ return false;
+ }
+ } else if (x[p] != y[p]) {
+ return false;
+ }
+ }
+ }
+ return true;
+ },
+
+ /**
+ * 输入框内插入文本
+ * @param object
+ * @param content
+ */
+ insert2Input (object, content) {
+ if (object === null || typeof object !== "object") return;
+ if (typeof object.length === 'number' && object.length > 0) object = object[0];
+
+ let ele = typeof object.$el === "object" ? $A(object.$el) : $A(object);
+ if (ele.length === 0) return;
+ let eleDom = ele[0];
+
+ if (eleDom.tagName != "INPUT" && eleDom.tagName != "TEXTAREA") {
+ if (ele.find("input").length === 0) {
+ ele = ele.find("textarea");
+ }else{
+ ele = ele.find("input");
+ }
+ }
+ if (ele.length === 0) return;
+ eleDom = ele[0];
+
+ if (eleDom.tagName != "INPUT" && eleDom.tagName != "TEXTAREA") return;
+
+ let text = ele.val();
+ let { selectionStart, selectionEnd } = eleDom;
+
+ ele.val(`${text.substring(0, selectionStart)}${content}${text.substring(selectionEnd, text.length)}`);
+ eleDom.dispatchEvent(new Event('input'));
+
+ setTimeout(() => {
+ if (eleDom.setSelectionRange) {
+ let pos = text.substring(0, selectionStart).length + content.length;
+ eleDom.focus();
+ eleDom.setSelectionRange(pos, pos);
+ }
+ }, 10);
+ },
+
+ /**
+ * iOS上虚拟键盘引起的触控错位
+ */
+ iOSKeyboardFixer() {
+ if (!this.isIos()) {
+ return;
+ }
+ document.body.scrollTop = document.body.scrollTop + 1;
+ document.body.scrollTop = document.body.scrollTop - 1;
+ },
+
+ autoDevwid(width) {
+ let _width = width || 640;
+ new function () {
+ let _self = this;
+ _self.width = _width; //设置默认最大宽度
+ _self.fontSize = 30; //默认字体大小
+ _self.widthProportion = function () {
+ let p = (document.body && document.body.clientWidth || document.getElementsByTagName("html")[0].offsetWidth) / _self.width;
+ return p > 1 ? 1 : p < 0.38 ? 0.38 : p;
+ };
+ _self.changePage = function () {
+ document.getElementsByTagName("html")[0].setAttribute("style", "font-size:" + _self.widthProportion() * _self.fontSize + "px !important");
+ };
+ _self.changePage();
+ window.addEventListener('resize', function () {
+ _self.changePage();
+ }, false);
+ };
+ //
+ let scale = $A(window).width() / _width;
+ $A(".__auto").each(function () {
+ if ($A(this).attr("data-original") !== "1") {
+ $A(this).attr("data-original-top", parseInt($A(this).css("top")));
+ $A(this).attr("data-original-right", parseInt($A(this).css("right")));
+ $A(this).attr("data-original-bottom", parseInt($A(this).css("bottom")));
+ $A(this).attr("data-original-left", parseInt($A(this).css("left")));
+ $A(this).attr("data-original-width", parseInt($A(this).css("width")));
+ $A(this).attr("data-original-height", parseInt($A(this).css("height")));
+ $A(this).attr("data-original-line-height", parseInt($A(this).css("line-height")));
+ $A(this).attr("data-original", "1");
+ }
+ let _t = parseInt($A(this).attr("data-original-top"));
+ let _r = parseInt($A(this).attr("data-original-right"));
+ let _b = parseInt($A(this).attr("data-original-bottom"));
+ let _l = parseInt($A(this).attr("data-original-left"));
+ let _w = parseInt($A(this).attr("data-original-width"));
+ let _h = parseInt($A(this).attr("data-original-height"));
+ let _lh = parseInt($A(this).attr("data-original-line-height"));
+ //
+ let _css = {};
+ if (_t > 0) _css['top'] = _t * scale;
+ if (_r > 0) _css['right'] = _r * scale;
+ if (_b > 0) _css['bottom'] = _b * scale;
+ if (_l > 0) _css['left'] = _l * scale;
+ if (_w > 0) _css['width'] = _w * scale;
+ if (_h > 0) _css['height'] = _h * scale;
+ if (_lh > 0) _css['line-height'] = (_lh * scale) + 'px';
+ $A(this).css(_css);
+ });
+ return scale;
+ }
+
+ });
+
+ /**
+ * =============================================================================
+ * **************************** ihttp ****************************
+ * =============================================================================
+ */
+ $.extend({
+
+ serializeObject (obj, parents) {
+ if (typeof obj === 'string') return obj;
+ let resultArray = [];
+ let separator = '&';
+ parents = parents || [];
+ let newParents;
+
+ function var_name(name) {
+ if (parents.length > 0) {
+ let _parents = '';
+ for (let j = 0; j < parents.length; j++) {
+ if (j === 0) _parents += parents[j];
+ else _parents += '[' + encodeURIComponent(parents[j]) + ']';
+ }
+ return _parents + '[' + encodeURIComponent(name) + ']';
+ }
+ else {
+ return encodeURIComponent(name);
+ }
+ }
+
+ function var_value(value) {
+ return encodeURIComponent(value);
+ }
+
+ for (let prop in obj) {
+ if (obj.hasOwnProperty(prop)) {
+ let toPush;
+ if (Array.isArray(obj[prop])) {
+ toPush = [];
+ for (let i = 0; i < obj[prop].length; i++) {
+ if (!Array.isArray(obj[prop][i]) && typeof obj[prop][i] === 'object') {
+ newParents = parents.slice();
+ newParents.push(prop);
+ newParents.push(i + '');
+ toPush.push($.serializeObject(obj[prop][i], newParents));
+ }
+ else {
+ toPush.push(var_name(prop) + '[]=' + var_value(obj[prop][i]));
+ }
+
+ }
+ if (toPush.length > 0) resultArray.push(toPush.join(separator));
+ }
+ else if (obj[prop] === null) {
+ resultArray.push(var_name(prop) + '=');
+ }
+ else if (typeof obj[prop] === 'object') {
+ // Object, convert to named array
+ newParents = parents.slice();
+ newParents.push(prop);
+ toPush = $.serializeObject(obj[prop], newParents);
+ if (toPush !== '') resultArray.push(toPush);
+ }
+ else if (typeof obj[prop] !== 'undefined' && obj[prop] !== '') {
+ // Should be string or plain value
+ resultArray.push(var_name(prop) + '=' + var_value(obj[prop]));
+ }
+ else if (obj[prop] === '') resultArray.push(var_name(prop));
+ }
+ }
+ return resultArray.join(separator);
+ },
+
+ // Global Ajax Setup
+ globalAjaxOptions: {},
+ ajaxSetup (options) {
+ if (options.type) options.method = options.type;
+ $.each(options, function (optionName, optionValue) {
+ $.globalAjaxOptions[optionName] = optionValue;
+ });
+ },
+
+ // Ajax
+ _jsonpRequests: 0,
+ ihttp(options) {
+ let defaults = {
+ method: 'GET',
+ data: false,
+ async: true,
+ cache: true,
+ user: '',
+ password: '',
+ headers: {},
+ xhrFields: {},
+ statusCode: {},
+ processData: true,
+ dataType: 'text',
+ contentType: 'application/x-www-form-urlencoded',
+ timeout: 0
+ };
+ let callbacks = ['beforeSend', 'error', 'complete', 'success', 'statusCode'];
+
+
+ //For jQuery guys
+ if (options.type) options.method = options.type;
+
+ // Merge global and defaults
+ $.each($.globalAjaxOptions, function (globalOptionName, globalOptionValue) {
+ if (callbacks.indexOf(globalOptionName) < 0) defaults[globalOptionName] = globalOptionValue;
+ });
+
+ // Function to run XHR callbacks and events
+ function fireAjaxCallback(eventName, eventData, callbackName) {
+ let a = arguments;
+ if (eventName) $(document).trigger(eventName, eventData);
+ if (callbackName) {
+ // Global callback
+ if (callbackName in $.globalAjaxOptions) $.globalAjaxOptions[callbackName](a[3], a[4], a[5], a[6]);
+ // Options callback
+ if (options[callbackName]) options[callbackName](a[3], a[4], a[5], a[6]);
+ }
+ }
+
+ // Merge options and defaults
+ $.each(defaults, function (prop, defaultValue) {
+ if (!(prop in options)) options[prop] = defaultValue;
+ });
+
+ // Default URL
+ if (!options.url) {
+ options.url = window.location.toString();
+ }
+ // Parameters Prefix
+ let paramsPrefix = options.url.indexOf('?') >= 0 ? '&' : '?';
+
+ // UC method
+ let _method = options.method.toUpperCase();
+ // Data to modify GET URL
+ if ((_method === 'GET' || _method === 'HEAD' || _method === 'OPTIONS' || _method === 'DELETE') && options.data) {
+ let stringData;
+ if (typeof options.data === 'string') {
+ // Should be key=value string
+ if (options.data.indexOf('?') >= 0) stringData = options.data.split('?')[1];
+ else stringData = options.data;
+ }
+ else {
+ // Should be key=value object
+ stringData = $.serializeObject(options.data);
+ }
+ if (stringData.length) {
+ options.url += paramsPrefix + stringData;
+ if (paramsPrefix === '?') paramsPrefix = '&';
+ }
+ }
+ // JSONP
+ if (options.dataType === 'json' && options.url.indexOf('callback=') >= 0) {
+
+ let callbackName = 'f7jsonp_' + Date.now() + ($._jsonpRequests++);
+ let abortTimeout;
+ let callbackSplit = options.url.split('callback=');
+ let requestUrl = callbackSplit[0] + 'callback=' + callbackName;
+ if (callbackSplit[1].indexOf('&') >= 0) {
+ let addVars = callbackSplit[1].split('&').filter(function (el) {
+ return el.indexOf('=') > 0;
+ }).join('&');
+ if (addVars.length > 0) requestUrl += '&' + addVars;
+ }
+
+ // Create script
+ let script = document.createElement('script');
+ script.type = 'text/javascript';
+ script.onerror = function () {
+ clearTimeout(abortTimeout);
+ fireAjaxCallback(undefined, undefined, 'error', null, 'scripterror');
+ fireAjaxCallback('ajaxComplete ajax:complete', {scripterror: true}, 'complete', null, 'scripterror');
+ };
+ script.src = requestUrl;
+
+ // Handler
+ window[callbackName] = function (data) {
+ clearTimeout(abortTimeout);
+ fireAjaxCallback(undefined, undefined, 'success', data);
+ script.parentNode.removeChild(script);
+ script = null;
+ delete window[callbackName];
+ };
+ document.querySelector('head').appendChild(script);
+
+ if (options.timeout > 0) {
+ abortTimeout = setTimeout(function () {
+ script.parentNode.removeChild(script);
+ script = null;
+ fireAjaxCallback(undefined, undefined, 'error', null, 'timeout');
+ }, options.timeout);
+ }
+
+ return;
+ }
+
+ // Cache for GET/HEAD requests
+ if (_method === 'GET' || _method === 'HEAD' || _method === 'OPTIONS' || _method === 'DELETE') {
+ if (options.cache === false) {
+ options.url += (paramsPrefix + '_nocache=' + Date.now());
+ }
+ }
+
+ // Create XHR
+ let xhr = new XMLHttpRequest();
+
+ // Save Request URL
+ xhr.requestUrl = options.url;
+ xhr.requestParameters = options;
+
+ // Open XHR
+ xhr.open(_method, options.url, options.async, options.user, options.password);
+
+ // Create POST Data
+ let postData = null;
+
+ if ((_method === 'POST' || _method === 'PUT' || _method === 'PATCH') && options.data) {
+ if (options.processData) {
+ let postDataInstances = [ArrayBuffer, Blob, Document, FormData];
+ // Post Data
+ if (postDataInstances.indexOf(options.data.constructor) >= 0) {
+ postData = options.data;
+ }
+ else {
+ // POST Headers
+ let boundary = '---------------------------' + Date.now().toString(16);
+
+ if (options.contentType === 'multipart\/form-data') {
+ xhr.setRequestHeader('Content-Type', 'multipart\/form-data; boundary=' + boundary);
+ }
+ else {
+ xhr.setRequestHeader('Content-Type', options.contentType);
+ }
+ postData = '';
+ let _data = $.serializeObject(options.data);
+ if (options.contentType === 'multipart\/form-data') {
+ boundary = '---------------------------' + Date.now().toString(16);
+ _data = _data.split('&');
+ let _newData = [];
+ for (let i = 0; i < _data.length; i++) {
+ _newData.push('Content-Disposition: form-data; name="' + _data[i].split('=')[0] + '"\r\n\r\n' + _data[i].split('=')[1] + '\r\n');
+ }
+ postData = '--' + boundary + '\r\n' + _newData.join('--' + boundary + '\r\n') + '--' + boundary + '--\r\n';
+ }
+ else {
+ postData = _data;
+ }
+ }
+ }
+ else {
+ postData = options.data;
+ }
+
+ }
+
+ // Additional headers
+ if (options.headers) {
+ $.each(options.headers, function (headerName, headerCallback) {
+ xhr.setRequestHeader(headerName, headerCallback);
+ });
+ }
+
+ // Check for crossDomain
+ if (typeof options.crossDomain === 'undefined') {
+ options.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(options.url) && RegExp.$2 !== window.location.host;
+ }
+
+ if (!options.crossDomain) {
+ xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
+ }
+
+ if (options.xhrFields) {
+ $.each(options.xhrFields, function (fieldName, fieldValue) {
+ xhr[fieldName] = fieldValue;
+ });
+ }
+
+ let xhrTimeout;
+ // Handle XHR
+ xhr.onload = function (e) {
+ if (xhrTimeout) clearTimeout(xhrTimeout);
+ if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 0) {
+ let responseData;
+ if (options.dataType === 'json') {
+ try {
+ responseData = JSON.parse(xhr.responseText);
+ fireAjaxCallback('ajaxSuccess ajax:success', {xhr: xhr}, 'success', responseData, xhr.status, xhr);
+ }
+ catch (err) {
+ fireAjaxCallback('ajaxError ajax:error', {
+ xhr: xhr,
+ parseerror: true
+ }, 'error', xhr, 'parseerror');
+ }
+ }
+ else {
+ responseData = xhr.responseType === 'text' || xhr.responseType === '' ? xhr.responseText : xhr.response;
+ fireAjaxCallback('ajaxSuccess ajax:success', {xhr: xhr}, 'success', responseData, xhr.status, xhr);
+ }
+ }
+ else {
+ fireAjaxCallback('ajaxError ajax:error', {xhr: xhr}, 'error', xhr, xhr.status);
+ }
+ if (options.statusCode) {
+ if ($.globalAjaxOptions.statusCode && $.globalAjaxOptions.statusCode[xhr.status]) $.globalAjaxOptions.statusCode[xhr.status](xhr);
+ if (options.statusCode[xhr.status]) options.statusCode[xhr.status](xhr);
+ }
+ fireAjaxCallback('ajaxComplete ajax:complete', {xhr: xhr}, 'complete', xhr, xhr.status);
+ };
+
+ xhr.onerror = function (e) {
+ if (xhrTimeout) clearTimeout(xhrTimeout);
+ fireAjaxCallback('ajaxError ajax:error', {xhr: xhr}, 'error', xhr, xhr.status);
+ fireAjaxCallback('ajaxComplete ajax:complete', {xhr: xhr, error: true}, 'complete', xhr, 'error');
+ };
+
+ // Ajax start callback
+ fireAjaxCallback('ajaxStart ajax:start', {xhr: xhr}, 'start', xhr);
+ fireAjaxCallback(undefined, undefined, 'beforeSend', xhr);
+
+ // Timeout
+ if (options.timeout > 0) {
+ xhr.onabort = function () {
+ if (xhrTimeout) clearTimeout(xhrTimeout);
+ };
+ xhrTimeout = setTimeout(function () {
+ xhr.abort();
+ fireAjaxCallback('ajaxError ajax:error', {xhr: xhr, timeout: true}, 'error', xhr, 'timeout');
+ fireAjaxCallback('ajaxComplete ajax:complete', {
+ xhr: xhr,
+ timeout: true
+ }, 'complete', xhr, 'timeout');
+ }, options.timeout);
+ }
+
+ // Send XHR
+ xhr.send(postData);
+
+ // Return XHR object
+ return xhr;
+ }
+ });
+
+ /**
+ * =============================================================================
+ * ***************************** ajaxc ****************************
+ * =============================================================================
+ */
+ $.extend({
+
+ ajaxc(params) {
+ if (!params) return false;
+ if (typeof params.url === 'undefined') return false;
+ if (typeof params.data === 'undefined') params.data = {};
+ if (typeof params.cache === 'undefined') params.cache = false;
+ if (typeof params.method === 'undefined') params.method = 'GET';
+ if (typeof params.timeout === 'undefined') params.timeout = 30000;
+ if (typeof params.dataType === 'undefined') params.dataType = 'json';
+ if (typeof params.beforeSend === 'undefined') params.beforeSend = () => { };
+ if (typeof params.complete === 'undefined') params.complete = () => { };
+ if (typeof params.afterComplete === 'undefined') params.afterComplete = () => { };
+ if (typeof params.success === 'undefined') params.success = () => { };
+ if (typeof params.error === 'undefined') params.error = () => { };
+ //
+ let loadText = "数据加载中.....";
+ let busyNetwork = "网络繁忙,请稍后再试!";
+ if (typeof $A.app === 'object' && typeof $A.app.$L === 'function') {
+ loadText = $A.app.$L(loadText);
+ busyNetwork = $A.app.$L(busyNetwork);
+ }
+ //
+ let toastID = null, beforeTitle = '', errorTitle = '';
+ if (typeof $A.app === 'object' && typeof $A.app.$Message === 'object') {
+ if (typeof params.beforeSend === 'string') {
+ beforeTitle = params.beforeSend;
+ params.beforeSend = () => { toastID = $A.app.$Message.loading({content:beforeTitle, duration: 0}); };
+ }else if (params.beforeSend === true) {
+ params.beforeSend = () => { toastID = $A.app.$Message.loading({content:loadText, duration: 0}); };
+ }
+ if (typeof params.error === 'string') {
+ errorTitle = params.error;
+ params.error = () => { $A.app.$Message.error({content:errorTitle, duration: 5}); };
+ }else if (params.error === true) {
+ params.error = () => { $A.app.$Message.error({content:busyNetwork, duration: 5}); };
+ }
+ if (params.complete === true) {
+ params.complete = () => { toastID?toastID():'' };
+ }
+ }else{
+ if (typeof params.beforeSend === 'string') {
+ beforeTitle = params.beforeSend;
+ params.beforeSend = () => { toastID = $A.toast({title:beforeTitle, fixed: true, timeout: false}); };
+ }else if (params.beforeSend === true) {
+ params.beforeSend = () => { toastID = $A.toast({title:loadText, fixed: true, timeout: false}); };
+ }
+ if (typeof params.error === 'string') {
+ errorTitle = params.error;
+ params.error = () => { $A.toast(errorTitle, "danger"); };
+ }else if (params.error === true) {
+ params.error = () => { $A.toast(busyNetwork, "danger"); };
+ }
+ if (params.complete === true) {
+ params.complete = () => { toastID?$A.toast(toastID):'' };
+ }
+ }
+ //
+ let language = window.localStorage['__language:type__'] || 'en';
+ if (typeof $A.app === 'object') {
+ language = $A.app.languageType || language;
+ }
+ //
+ if (typeof params.header !== 'object') params.header = {};
+ params.header['Content-Type'] = 'application/json';
+ params.header['language'] = language;
+ params.header['token'] = $A.token();
+ //
+ params.data['__Access-Control-Allow-Origin'] = true;
+ params.beforeSend();
+ $A.ihttp({
+ url: params.url,
+ data: params.data,
+ cache: params.cache,
+ headers: params.header,
+ method: params.method.toUpperCase(),
+ contentType: "OPTIONS",
+ crossDomain: true,
+ dataType: params.dataType,
+ timeout: params.timeout,
+ success: function(data, status, xhr) {
+ params.complete();
+ params.success(data, status, xhr);
+ params.afterComplete(true);
+ },
+ error: function(xhr, status) {
+ params.complete();
+ params.error(xhr, status);
+ params.afterComplete(false);
+ }
+ });
+ }
+ });
+
+
+ /**
+ * =============================================================================
+ * ***************************** manage assist ****************************
+ * =============================================================================
+ */
+ $.extend({
+
+ /**
+ * 对象中有Date格式的转成指定格式
+ * @param myObj
+ * @param format 默认格式:Y-m-d
+ * @returns {*}
+ */
+ date2string(myObj, format) {
+ if (myObj === null) {
+ return myObj;
+ }
+ if (typeof format === "undefined") {
+ format = "Y-m-d";
+ }
+ if (typeof myObj === "object") {
+ if (myObj instanceof Date) {
+ return $A.formatDate(format, myObj);
+ }
+ $A.each(myObj, (key, val)=>{
+ myObj[key] = $A.date2string(val, format);
+ });
+ return myObj;
+ }
+ return myObj;
+ },
+
+ /**
+ * 获取一些指定时间
+ * @param str
+ * @param retInt
+ * @returns {*|string}
+ */
+ getData(str, retInt = false) {
+ let now = new Date(); //当前日期
+ let nowDayOfWeek = now.getDay(); //今天本周的第几天
+ let nowDay = now.getDate(); //当前日
+ let nowMonth = now.getMonth(); //当前月
+ let nowYear = now.getYear(); //当前年
+ nowYear += (nowYear < 2000) ? 1900 : 0;
+ let lastMonthDate = new Date(); //上月日期
+ lastMonthDate.setDate(1);
+ lastMonthDate.setMonth(lastMonthDate.getMonth()-1);
+ let lastMonth = lastMonthDate.getMonth();
+ let getQuarterStartMonth = () => {
+ let quarterStartMonth = 0;
+ if(nowMonth < 3) {
+ quarterStartMonth = 0;
+ }
+ if (2 < nowMonth && nowMonth < 6) {
+ quarterStartMonth = 3;
+ }
+ if (5 < nowMonth && nowMonth < 9) {
+ quarterStartMonth = 6;
+ }
+ if (nowMonth > 8) {
+ quarterStartMonth = 9;
+ }
+ return quarterStartMonth;
+ };
+ let getMonthDays = (myMonth) => {
+ let monthStartDate = new Date(nowYear, myMonth, 1);
+ let monthEndDate = new Date(nowYear, myMonth + 1, 1);
+ return (monthEndDate - monthStartDate)/(1000 * 60 * 60 * 24);
+ };
+ //
+ let time = now.getTime();
+ switch (str) {
+ case '今天':
+ time = now;
+ break;
+ case '昨天':
+ time = now - 86400000;
+ break;
+ case '前天':
+ time = now - 86400000 * 2;
+ break;
+ case '本周':
+ time = new Date(nowYear, nowMonth, nowDay - nowDayOfWeek);
+ break;
+ case '本周结束':
+ time = new Date(nowYear, nowMonth, nowDay + (6 - nowDayOfWeek));
+ break;
+ case '上周':
+ time = new Date(nowYear, nowMonth, nowDay - nowDayOfWeek - 7);
+ break;
+ case '上周结束':
+ time = new Date(nowYear, nowMonth, nowDay - nowDayOfWeek - 1);
+ break;
+ case '本周2':
+ time = new Date(nowYear, nowMonth, nowDay - nowDayOfWeek + 1);
+ break;
+ case '本周结束2':
+ time = new Date(nowYear, nowMonth, nowDay + (6 - nowDayOfWeek) + 1);
+ break;
+ case '上周2':
+ time = new Date(nowYear, nowMonth, nowDay - nowDayOfWeek - 7 + 1);
+ break;
+ case '上周结束2':
+ time = new Date(nowYear, nowMonth, nowDay - nowDayOfWeek - 1 + 1);
+ break;
+ case '本月':
+ time = new Date(nowYear, nowMonth, 1);
+ break;
+ case '本月结束':
+ time = new Date(nowYear, nowMonth, getMonthDays(nowMonth));
+ break;
+ case '上个月':
+ time = new Date(nowYear, lastMonth, 1);
+ break;
+ case '上个月结束':
+ time = new Date(nowYear, lastMonth, getMonthDays(lastMonth));
+ break;
+ case '本季度':
+ time = new Date(nowYear, getQuarterStartMonth(), 1);
+ break;
+ case '本季度结束':
+ let quarterEndMonth = getQuarterStartMonth() + 2;
+ time = new Date(nowYear, quarterEndMonth, getMonthDays(quarterEndMonth));
+ break;
+ }
+ if (retInt === true) {
+ return time;
+ }
+ return $A.formatDate("Y-m-d", parseInt(time / 1000))
+ },
+
+ /**
+ * 字节转换
+ * @param bytes
+ * @returns {string}
+ */
+ bytesToSize(bytes) {
+ if (bytes === 0) return '0 B';
+ let k = 1024;
+ let sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
+ let i = Math.floor(Math.log(bytes) / Math.log(k));
+ if (typeof sizes[i] === "undefined") {
+ return '0 B';
+ }
+ return $A.runNum((bytes / Math.pow(k, i)), 2) + ' ' + sizes[i];
+ },
+
+ /**
+ * html代码转义
+ * @param sHtml
+ * @returns {*}
+ */
+ html2Escape(sHtml) {
+ if (!sHtml || sHtml == '') {
+ return '';
+ }
+ return sHtml.replace(/[<>&"]/g, function (c) {
+ return {'<': '<', '>': '>', '&': '&', '"': '"'}[c];
+ });
+ },
+
+ /**
+ * 搜索高亮
+ * @param string
+ * @param key
+ * @returns {string|*}
+ */
+ sreachHighlight(string, key) {
+ if (!string || string == '') {
+ return '';
+ }
+ if (!key || key == '') {
+ return $A.html2Escape(string);
+ }
+ string = $A.html2Escape(string.replace(new RegExp(key, "g"), "[highlight]" + key + "[/highlight]"));
+ string = string.replace(/\[highlight\]/g, '');
+ string = string.replace(/\[\/highlight\]/g, '');
+ return string;
+ },
+ });
+
+ window.$A = $;
+})(window, window.jQuery);
diff --git a/resources/js/common/language/index.js b/resources/js/common/language/index.js
new file mode 100644
index 00000000..336ff217
--- /dev/null
+++ b/resources/js/common/language/index.js
@@ -0,0 +1,233 @@
+const languageTypeLists = {
+ "EN": "English",
+ "KM": "ភាសាខ្មែរ",
+ "TH": "ภาษาไทย",
+ "KO": "한국어",
+ "JA": "日本語",
+ "CN": "中文-简体",
+ "TC": "中文-繁體",
+};
+const languageCachesObjects = {};
+const languageListenerObjects = [];
+
+export default {
+ install(Vue) {
+ Vue.mixin({
+ data() {
+ return {
+ languageInit: false,
+ languageData: [],
+ languageType: window.localStorage['__language:type__'] || this.__getNavigatorLanguage(),
+ languageList: languageTypeLists,
+ }
+ },
+
+ watch: {
+ languageType: {
+ handler(type) {
+ if (type && typeof this.initLanguage === "function") {
+ this.initLanguage();
+ }
+ },
+ immediate: true
+ },
+ },
+
+ methods: {
+ /**
+ * 获取浏览器默认语言
+ * @returns {string}
+ * @private
+ */
+ __getNavigatorLanguage() {
+ let lang = 'EN';
+ let navLang = (navigator.language || navigator.userLanguage + "").toUpperCase();
+ switch (navLang) {
+ case "EN":
+ case "KM":
+ case "TH":
+ case "KO":
+ case "JA":
+ lang = navLang
+ break;
+ case "ZH-CN":
+ case "ZH":
+ lang = 'CN'
+ break;
+ case "ZH-TW":
+ case "ZH-HK":
+ lang = 'TC'
+ break;
+ }
+ return window.localStorage['__language:type__'] = lang;
+ },
+
+ /**
+ * 初始化语言数据
+ * @private
+ */
+ __initLanguageData() {
+ if (this.languageInit === false) {
+ this.languageInit = true;
+ //
+ this.addLanguageData(require("../../../lang/language.js").default);
+ //
+ languageListenerObjects.push((lang) => {
+ this.languageType = lang;
+ });
+ }
+ },
+
+ /**
+ * 是否数组
+ * @param obj
+ * @returns {boolean}
+ * @private
+ */
+ __isArray(obj) {
+ return typeof (obj) == "object" && Object.prototype.toString.call(obj).toLowerCase() == '[object array]' && typeof obj.length == "number";
+ },
+
+ /**
+ * 监听语言变化
+ * @param callback
+ */
+ setLanguageListener(callback) {
+ if (typeof callback === 'function') {
+ languageListenerObjects.push((lang) => {
+ callback(lang);
+ });
+ }
+ },
+
+ /**
+ * 语言包数据
+ * @param data
+ */
+ addLanguageData(data) {
+ if (!this.__isArray(data)) {
+ return;
+ }
+ this.__initLanguageData();
+ this.languageData.push(...data);
+ },
+
+ /**
+ * 变化语言
+ * @param language
+ */
+ setLanguage(language) {
+ this.__initLanguageData();
+ setTimeout(() => {
+ window.localStorage['__language:type__'] = language;
+ languageListenerObjects.forEach((call) => {
+ if (typeof call === 'function') {
+ call(language);
+ }
+ });
+ }, 10)
+ },
+
+ /**
+ * 获取语言
+ * @returns {*}
+ */
+ getLanguage() {
+ this.__initLanguageData();
+ return this.languageType;
+ },
+
+ /**
+ * 替换%遍历
+ * @param text
+ * @param objects
+ */
+ replaceArgumentsLanguage(text, objects) {
+ let j = 1;
+ while (text.indexOf("%") !== -1) {
+ if (typeof objects[j] === "object") {
+ text = text.replace("%", "");
+ } else {
+ text = text.replace("%", objects[j]);
+ }
+ j++;
+ }
+ return text;
+ },
+
+ /**
+ * 译文转义
+ * @param val
+ * @returns {string|*}
+ */
+ replaceEscape(val) {
+ if (!val || val == '') {
+ return '';
+ }
+ return val.replace(/%/g, '%').replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
+ },
+
+ /**
+ * 显示语言
+ * @return {string}
+ */
+ $L(text) {
+ if (typeof arguments[1] !== "undefined") {
+ return this.$L(this.replaceArgumentsLanguage(text, arguments));
+ }
+ if (typeof text !== "string" || !text) {
+ return text;
+ }
+ this.__initLanguageData();
+ //
+ if (typeof languageCachesObjects[text] === "undefined") {
+ let tmpRege = null;
+ let tmpData = this.languageData.find((obj) => {
+ return Object.values(obj).find((val) => {
+ tmpRege = new RegExp("^" + this.replaceEscape(val).replace(/%/g, "(.*?)") + "$", "g");
+ return !!text.match(tmpRege);
+ })
+ });
+ languageCachesObjects[text] = {
+ rege: tmpRege,
+ data: tmpData,
+ };
+ }
+ const {rege, data} = languageCachesObjects[text];
+ if (data
+ && typeof data === "object"
+ && typeof data[this.languageType] !== "undefined"
+ && data[this.languageType]) {
+ let index = 0;
+ let value = data[this.languageType];
+ value = value.replace(/%/g, function () {
+ return "$" + (++index);
+ });
+ return text.replace(rege, value);
+ }
+ //
+ if (this.languageType == "CN") {
+ try {
+ let key = '__language:Undefined__';
+ let languageTmp = JSON.parse(window.localStorage[key] || '[]');
+ if (!this.__isArray(languageTmp)) {
+ languageTmp = [];
+ }
+ let tmpRege = null;
+ let tmpData = languageTmp.find((val) => {
+ tmpRege = new RegExp("^" + val.replace(/%/g, "(.*?)") + "$", "g");
+ return !!text.match(tmpRege);
+ });
+ if (!tmpData) {
+ languageTmp.push(text);
+ window.localStorage[key] = JSON.stringify(languageTmp);
+ }
+ } catch (e) { }
+ }
+ //
+ return text;
+ }
+ }
+ });
+ }
+}
diff --git a/resources/js/common/mixins/index.js b/resources/js/common/mixins/index.js
new file mode 100644
index 00000000..b84d04d5
--- /dev/null
+++ b/resources/js/common/mixins/index.js
@@ -0,0 +1,55 @@
+export default {
+ install(Vue) {
+ Vue.mixin({
+ data() {
+ return {
+ mixinId: 0,
+ //用户信息
+ userLogin: false,
+ userInfo: {},
+ userName: '',
+ userId: 0,
+ //浏览器宽度≤768返回true
+ windowMax768: window.innerWidth <= 768,
+ }
+ },
+
+ mounted() {
+ if (typeof window.__mixinId != "number") window.__mixinId = 0;
+ this.mixinId = window.__mixinId++;
+ //
+ this.userLogin = $A.getToken() !== false;
+ this.userInfo = $A.getUserInfo();
+ this.userName = this.userInfo.username || '';
+ this.userId = parseInt(this.userInfo.userid);
+ $A.setOnUserInfoListener('mixins_' + this.mixinId, (data, isLogin) => {
+ this.userLogin = isLogin;
+ this.userInfo = data;
+ this.userName = this.userInfo.username || '';
+ this.userId = parseInt(this.userInfo.userid);
+ });
+ //
+ window.addEventListener('resize', this.windowMax768Listener);
+ },
+
+ beforeDestroy() {
+ $A.removeUserInfoListener('mixins_' + this.mixinId);
+ window.removeEventListener('resize', this.windowMax768Listener);
+ },
+
+ methods: {
+ isArray(obj) {
+ return typeof (obj) == "object" && Object.prototype.toString.call(obj).toLowerCase() == '[object array]' && typeof obj.length == "number";
+ },
+
+ isJson(obj) {
+ return typeof (obj) == "object" && Object.prototype.toString.call(obj).toLowerCase() == "[object object]" && typeof obj.length == "undefined";
+ },
+
+ windowMax768Listener() {
+ this.windowMax768 = window.innerWidth <= 768
+ }
+ }
+ });
+ }
+}
diff --git a/resources/js/main.js b/resources/js/main.js
new file mode 100755
index 00000000..5e1c3f96
--- /dev/null
+++ b/resources/js/main.js
@@ -0,0 +1,1027 @@
+/**
+ * 页面专用
+ */
+(function (window) {
+
+ let apiUrl = window.location.origin + '/api/';
+ let $ = window.$A;
+
+ $.extend({
+
+ fillUrl(str) {
+ if (str.substring(0, 2) === "//" ||
+ str.substring(0, 7) === "http://" ||
+ str.substring(0, 8) === "https://" ||
+ str.substring(0, 6) === "ftp://" ||
+ str.substring(0, 1) === "/") {
+ return str;
+ }
+ return window.location.origin + '/' + str;
+ },
+
+ webUrl(str) {
+ return $A.fillUrl(str || '');
+ },
+
+ apiUrl(str) {
+ if (str.substring(0, 2) === "//" ||
+ str.substring(0, 7) === "http://" ||
+ str.substring(0, 8) === "https://" ||
+ str.substring(0, 6) === "ftp://" ||
+ str.substring(0, 1) === "/") {
+ return str;
+ }
+ return apiUrl + str;
+ },
+
+ apiAjax(params) {
+ if (typeof params !== 'object') return false;
+ if (typeof params.success === 'undefined') params.success = () => { };
+ if (typeof params.header !== 'object') params.header = {};
+ params.url = this.apiUrl(params.url);
+ //
+ let beforeCall = params.beforeSend;
+ params.beforeSend = () => {
+ $A.aAjaxLoadNum++;
+ $A(".w-spinner").show();
+ //
+ if (typeof beforeCall == "function") {
+ beforeCall();
+ }
+ };
+ //
+ let completeCall = params.complete;
+ params.complete = () => {
+ $A.aAjaxLoadNum--;
+ if ($A.aAjaxLoadNum <= 0) {
+ $A(".w-spinner").hide();
+ }
+ //
+ if (typeof completeCall == "function") {
+ completeCall();
+ }
+ };
+ //
+ let callback = params.success;
+ params.success = (data, status, xhr) => {
+ if (typeof data === 'object') {
+ if (data.ret === -1 && params.checkRole !== false) {
+ //身份丢失
+ $A.modalError({
+ content: data.msg,
+ onOk: () => {
+ $A.userLogout();
+ }
+ });
+ return;
+ }
+ if (data.ret === -2 && params.role !== false) {
+ //没有权限
+ $A.modalError({
+ content: data.msg ? data.msg : "你没有相关的权限查看或编辑!"
+ });
+ }
+ }
+ if (typeof callback === "function") {
+ callback(data, status, xhr);
+ }
+ };
+ //
+ if (params.websocket === true || params.ws === true) {
+ const apiWebsocket = $A.randomString(16);
+ const apiTimeout = setTimeout(() => {
+ const WListener = $A.aAjaxWsListener.find((item) => item.apiWebsocket == apiWebsocket);
+ $A.aAjaxWsListener = $A.aAjaxWsListener.filter((item) => item.apiWebsocket != apiWebsocket);
+ if (WListener) {
+ WListener.complete();
+ WListener.error("timeout");
+ WListener.afterComplete();
+ }
+ }, params.timeout || 30000);
+ $A.aAjaxWsListener.push({
+ apiWebsocket: apiWebsocket,
+ complete: typeof params.complete === "function" ? params.complete : () => { },
+ afterComplete: typeof params.afterComplete === "function" ? params.afterComplete : () => { },
+ success: typeof params.success === "function" ? params.success : () => { },
+ error: typeof params.error === "function" ? params.error : () => { },
+ });
+ //
+ params.complete = () => { };
+ params.afterComplete = () => { };
+ params.success = () => { };
+ params.error = () => { };
+ params.header['Api-Websocket'] = apiWebsocket;
+ //
+ if ($A.aAjaxWsReady === false) {
+ $A.aAjaxWsReady = true;
+ $A.WSOB.setOnMsgListener("apiWebsocket", [
+ 'apiWebsocket',
+ ], (msgDetail) => {
+ switch (msgDetail.messageType) {
+ case 'apiWebsocket':
+ clearTimeout(apiTimeout);
+ const apiWebsocket = msgDetail.apiWebsocket;
+ const apiSuccess = msgDetail.apiSuccess;
+ const apiResult = msgDetail.body;
+ const WListener = $A.aAjaxWsListener.find((item) => item.apiWebsocket == apiWebsocket);
+ $A.aAjaxWsListener = $A.aAjaxWsListener.filter((item) => item.apiWebsocket != apiWebsocket);
+ if (WListener) {
+ WListener.complete();
+ if (apiSuccess) {
+ WListener.success(apiResult);
+ } else {
+ WListener.error(apiResult);
+ }
+ WListener.afterComplete();
+ }
+ break;
+ }
+ });
+ }
+ }
+ //
+ $A.ajaxc(params);
+ },
+ aAjaxLoadNum: 0,
+ aAjaxWsReady: false,
+ aAjaxWsListener: [],
+
+ /**
+ * 编辑器参数配置
+ * @returns {{modules: {toolbar: *[]}}}
+ */
+ editorOption() {
+ return {
+ modules: {
+ toolbar: [
+ ['bold', 'italic'],
+ [{ 'list': 'ordered'}, { 'list': 'bullet' }],
+ [{ 'size': ['small', false, 'large', 'huge'] }],
+ [{ 'header': [1, 2, 3, 4, 5, 6, false] }],
+ [{ 'color': [] }, { 'background': [] }],
+ [{ 'align': [] }]
+ ]
+ }
+ };
+ },
+
+ /**
+ * 获取token
+ * @returns {boolean}
+ */
+ getToken() {
+ let token = $A.token();
+ return $A.count(token) < 10 ? false : token;
+ },
+
+ /**
+ * 设置token
+ * @param token
+ */
+ setToken(token) {
+ $A.token(token);
+ },
+
+ /**
+ * 获取会员ID
+ * @returns string
+ */
+ getUserId() {
+ if ($A.getToken() === false) {
+ return "";
+ }
+ let userInfo = $A.getUserInfo();
+ return $A.runNum(userInfo.userid);
+ },
+
+ /**
+ * 获取会员账号
+ * @returns string
+ */
+ getUserName() {
+ if ($A.getToken() === false) {
+ return "";
+ }
+ let userInfo = $A.getUserInfo();
+ return $A.ishave(userInfo.username) ? userInfo.username : '';
+ },
+
+ /**
+ * 获取会员昵称
+ * @param nullName
+ * @returns {string|*}
+ */
+ getNickName(nullName = true) {
+ if ($A.getToken() === false) {
+ return "";
+ }
+ let userInfo = $A.getUserInfo();
+ return $A.ishave(userInfo.nickname) ? userInfo.nickname : '';
+ },
+
+ /**
+ * 获取用户信息(并保存)
+ * @param callback 网络请求获取到用户信息回调(监听用户信息发生变化)
+ * @returns Object
+ */
+ getUserInfo(callback) {
+ if (typeof callback === 'function' || callback === true) {
+ $A.apiAjax({
+ url: 'users/info',
+ error: () => {
+ $A.userLogout();
+ },
+ success: (res) => {
+ if (res.ret === 1) {
+ $A.storage("userInfo", res.data);
+ $A.setToken(res.data.token);
+ $A.triggerUserInfoListener(res.data);
+ $A.updateUserBasic({
+ username: res.data.username,
+ nickname: res.data.nickname,
+ userimg: res.data.userimg,
+ });
+ typeof callback === "function" && callback(res.data, $A.getToken() !== false);
+ }
+ },
+ });
+ }
+ return $A.jsonParse($A.storage("userInfo"));
+ },
+
+ /**
+ * 根据用户名获取用户基本信息
+ * @param params Object{username,callback,listenerName,cacheTime}
+ */
+ getUserBasic(params) {
+ if (typeof params !== 'object' || params === null) return;
+ if (typeof params.listenerName === 'undefined') params.listenerName = $A.randomString(16);
+ if (typeof params.cacheTime === 'undefined') params.cacheTime = 300;
+
+ if (typeof params.callback !== "function") {
+ return;
+ }
+ if (!params.username) {
+ params.callback({}, false);
+ return;
+ }
+ //
+ $A.__userBasicFuncUpdate.push({
+ listenerName: params.listenerName,
+ username: params.username,
+ callback: params.callback
+ });
+ //
+ let keyName = '__userBasic:' + params.username.substring(0, 1) + '__';
+ let localData = $A.jsonParse(window.localStorage[keyName]);
+ if ($A.getObject(localData, params.username + '.success') === true) {
+ params.callback(localData[params.username].data, true);
+ if (localData[params.username].update + params.cacheTime > Math.round(new Date().getTime() / 1000)) {
+ return;
+ }
+ }
+ //
+ $A.__userBasicFuncAjax.push({
+ username: params.username,
+ callback: params.callback
+ });
+ //
+ $A.__userBasicTimeout++;
+ let timeout = $A.__userBasicTimeout;
+ setTimeout(() => {
+ timeout === $A.__userBasicTimeout && $A.__userBasicEvent();
+ }, 100);
+ },
+ __userBasicEvent() {
+ if ($A.__userBasicLoading === true) {
+ return;
+ }
+ $A.__userBasicLoading = true;
+ //
+ let userArray = [];
+ $A.__userBasicFuncAjax.some((item) => {
+ userArray.push(item.username);
+ if (userArray.length >= 30) {
+ return true;
+ }
+ });
+ //
+ $A.apiAjax({
+ url: 'users/basic',
+ data: {
+ username: $A.jsonStringify(userArray),
+ },
+ error: () => {
+ userArray.forEach((username) => {
+ let tmpLists = $A.__userBasicFuncAjax.filter((item) => item.username == username);
+ tmpLists.forEach((item) => {
+ if (typeof item.callback === "function") {
+ item.callback({}, false);
+ item.callback = null;
+ }
+ });
+ });
+ //
+ $A.__userBasicLoading = false;
+ $A.__userBasicFuncAjax = $A.__userBasicFuncAjax.filter((item) => typeof item.callback === "function");
+ if ($A.__userBasicFuncAjax.length > 0) {
+ $A.__userBasicEvent();
+ }
+ },
+ success: (res) => {
+ if (res.ret === 1) {
+ res.data.forEach((data) => {
+ let keyName = '__userBasic:' + data.username.substring(0, 1) + '__';
+ let localData = $A.jsonParse(window.localStorage[keyName]);
+ localData[data.username] = {
+ success: true,
+ update: Math.round(new Date().getTime() / 1000),
+ data: data
+ };
+ window.localStorage[keyName] = $A.jsonStringify(localData);
+ });
+ }
+ userArray.forEach((username) => {
+ let tmpLists = $A.__userBasicFuncAjax.filter((item) => item.username == username);
+ tmpLists.forEach((item) => {
+ if (typeof item.callback === "function") {
+ let info = res.data.filter((data) => data.username == username);
+ if (info.length === 0) {
+ item.callback({}, false);
+ } else {
+ item.callback(info[0], true);
+ }
+ item.callback = null;
+ }
+ });
+ });
+ //
+ $A.__userBasicLoading = false;
+ $A.__userBasicFuncAjax = $A.__userBasicFuncAjax.filter((item) => typeof item.callback === "function");
+ if ($A.__userBasicFuncAjax.length > 0) {
+ $A.__userBasicEvent();
+ }
+ }
+ });
+ },
+ __userBasicTimeout: 0,
+ __userBasicLoading: false,
+ __userBasicFuncAjax: [],
+ __userBasicFuncUpdate: [],
+
+ /**
+ * 主动更新缓存
+ * @param params Object{username,....}
+ */
+ updateUserBasic(params) {
+ if (typeof params !== 'object' || params === null) return;
+
+ if (!params.username) {
+ return;
+ }
+ let keyName = '__userBasic:' + params.username.substring(0, 1) + '__';
+ let localData = $A.jsonParse(window.localStorage[keyName]);
+ if ($A.getObject(localData, params.username + '.success') === true) {
+ localData[params.username].data = Object.assign(localData[params.username].data, params);
+ window.localStorage[keyName] = $A.jsonStringify(localData);
+ //
+ let tmpLists = $A.__userBasicFuncUpdate.filter((item) => item.username == params.username);
+ tmpLists.forEach((item) => {
+ if (typeof item.callback === "function") {
+ item.callback(localData[params.username].data, true);
+ }
+ });
+ }
+ },
+
+ /**
+ * 销毁监听
+ * @param listenerName
+ */
+ destroyUserBasicListener(listenerName) {
+ $A.__userBasicFuncUpdate = $A.__userBasicFuncUpdate.filter((item) => item.listenerName != listenerName);
+ },
+
+ /**
+ * 打开登录页面
+ */
+ userLogout() {
+ $A.token("");
+ $A.storage("userInfo", {});
+ $A.triggerUserInfoListener({});
+ let from = window.location.pathname == '/' ? '' : encodeURIComponent(window.location.href);
+ if (typeof $A.app === "object") {
+ $A.app.goForward({path: '/login', query: from ? {from: from} : {}}, true);
+ } else {
+ window.location.replace($A.webUrl('login') + (from ? ('?from=' + from) : ''));
+ }
+ },
+
+ /**
+ * 权限是否通过
+ * @param role
+ * @returns {boolean}
+ */
+ identityCheck(role) {
+ let userInfo = $A.getUserInfo();
+ return $A.identityRaw(role, userInfo.identity);
+ },
+
+ /**
+ * 权限是否通过
+ * @param role
+ * @param identity
+ * @returns {boolean}
+ */
+ identityRaw(role, identity) {
+ let isRole = false;
+ $A.each(identity, (index, res) => {
+ if (res === role) {
+ isRole = true;
+ }
+ });
+ return isRole;
+ },
+
+ /**
+ * 监听用户信息发生变化
+ * @param listenerName 监听标识
+ * @param callback 监听回调
+ */
+ setOnUserInfoListener(listenerName, callback) {
+ if (typeof listenerName != "string") {
+ return;
+ }
+ if (typeof callback === "function") {
+ $A.__userInfoListenerObject[listenerName] = {
+ callback: callback,
+ }
+ }
+ },
+ removeUserInfoListener(listenerName) {
+ if (typeof listenerName != "string") {
+ return;
+ }
+ if (typeof $A.__userInfoListenerObject[listenerName] != "undefined") {
+ delete $A.__userInfoListenerObject[listenerName];
+ }
+ },
+ triggerUserInfoListener(userInfo) {
+ let key, item;
+ for (key in $A.__userInfoListenerObject) {
+ if (!$A.__userInfoListenerObject.hasOwnProperty(key)) continue;
+ item = $A.__userInfoListenerObject[key];
+ if (typeof item.callback === "function") {
+ item.callback(userInfo, $A.getToken() !== false);
+ }
+ }
+ },
+ __userInfoListenerObject: {},
+ });
+
+ /**
+ * =============================================================================
+ * **************************** websocket assist ***************************
+ * =============================================================================
+ */
+ $.extend({
+ /**
+ * @param config {userid, url, token, logCallback}
+ */
+ WTWS: function (config) {
+ this.__instance = null;
+ this.__connected = false;
+ this.__callbackid = {};
+ this.__openNum = 0;
+ this.__autoNum = 0;
+ this.__lastSend = 0;
+
+ this.__autoLine = function (timeout) {
+ var tempNum = this.__autoNum;
+ var thas = this;
+ setTimeout(function () {
+ if (tempNum === thas.__autoNum) {
+ thas.__autoNum++
+ if (!thas.__config.token) {
+ thas.__log("[WS] No token");
+ thas.__autoLine(timeout);
+ } else {
+ // 发refresh之前判断10秒内没有使用过sendTo的再发送refresh
+ if (thas.__lastSend + 10 < Math.round(new Date().getTime() / 1000)) {
+ thas.sendTo('refresh', function (res) {
+ thas.__log("[WS] Connection " + (res.status ? 'success' : 'error'));
+ thas.__autoLine(timeout);
+ });
+ }
+ }
+ }
+ }, Math.min(timeout, 30) * 1000);
+ }
+ this.__log = function (text, event) {
+ typeof this.__config.logCallback === "function" && this.__config.logCallback(text, event);
+ }
+ this.__lExists = function (string, find, lower) {
+ string += "";
+ find += "";
+ if (lower !== true) {
+ string = string.toLowerCase();
+ find = find.toLowerCase();
+ }
+ return (string.substring(0, find.length) === find);
+ }
+ this.__rNum = function (str, fixed) {
+ var _s = Number(str);
+ if (_s + "" === "NaN") {
+ _s = 0;
+ }
+ if (/^[0-9]*[1-9][0-9]*$/.test(fixed)) {
+ _s = _s.toFixed(fixed);
+ var rs = _s.indexOf('.');
+ if (rs < 0) {
+ _s += ".";
+ for (var i = 0; i < fixed; i++) {
+ _s += "0";
+ }
+ }
+ }
+ return _s;
+ }
+ this.__jParse = function (str, defaultVal) {
+ if (str === null) {
+ return defaultVal ? defaultVal : {};
+ }
+ if (typeof str === "object") {
+ return str;
+ }
+ try {
+ return JSON.parse(str);
+ } catch (e) {
+ return defaultVal ? defaultVal : {};
+ }
+ }
+ this.__randString = function (len) {
+ len = len || 32;
+ var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678oOLl9gqVvUuI1';
+ var maxPos = $chars.length;
+ var pwd = '';
+ for (var i = 0; i < len; i++) {
+ pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
+ }
+ return pwd;
+ }
+ this.__urlParams = function(url, params) {
+ if (typeof params === "object" && params !== null) {
+ url+= "";
+ url+= url.indexOf("?") === -1 ? '?' : '';
+ for (var key in params) {
+ if (!params.hasOwnProperty(key)) {
+ continue;
+ }
+ url+= '&' + key + '=' + params[key];
+ }
+ }
+ return url.replace("?&", "?");
+ }
+ this.__isArr = function (obj){
+ return Object.prototype.toString.call(obj)=='[object Array]';
+ }
+
+ /**
+ * 设置参数
+ * @param config
+ */
+ this.config = function (config) {
+ if (typeof config !== "object" || config === null) {
+ config = {};
+ }
+ config.userid = config.userid || '';
+ config.url = config.url || '';
+ config.token = config.token || '';
+ config.logCallback = config.logCallback || null;
+ this.__config = config;
+ return this;
+ }
+
+ /**
+ * 连接
+ * @param force
+ */
+ this.connection = function (force) {
+ if (!this.__lExists(this.__config.url, "ws://") && !this.__lExists(this.__config.url, "wss://")) {
+ this.__log("[WS] No connection address");
+ return this;
+ }
+
+ if (!this.__config.token) {
+ this.__log("[WS] No connected token");
+ return this;
+ }
+
+ if (this.__instance !== null && force !== true) {
+ this.__log("[WS] Connection exists");
+ return this;
+ }
+
+ var thas = this;
+
+ // 初始化客户端套接字并建立连接
+ this.__instance = new WebSocket(this.__urlParams(this.__config.url, {
+ mode: 'console',
+ token: this.__config.token,
+ }));
+
+ // 连接建立时触发
+ this.__instance.onopen = function (event) {
+ thas.__log("[WS] Connection opened", event);
+ }
+
+ // 接收到服务端推送时执行
+ this.__instance.onmessage = function (event) {
+ thas.__log("[WS] Message", event);
+ var msgDetail = thas.__jParse(event.data);
+ if (msgDetail.messageType === 'open') {
+ thas.__log("[WS] Connection connected");
+ msgDetail.openNum = thas.__openNum;
+ msgDetail.config = thas.__config;
+ thas.__openNum++;
+ thas.__connected = true;
+ thas.__autoLine(30);
+ } else if (msgDetail.messageType === 'back') {
+ typeof thas.__callbackid[msgDetail.messageId] === "function" && thas.__callbackid[msgDetail.messageId](msgDetail.body);
+ delete thas.__callbackid[msgDetail.messageId];
+ return;
+ }
+ if (thas.__rNum(msgDetail.contentId) > 0) {
+ thas.sendTo('roger', msgDetail.contentId);
+ }
+ thas.triggerMsgListener(msgDetail);
+ };
+
+ // 连接关闭时触发
+ this.__instance.onclose = function (event) {
+ thas.__log("[WS] Connection closed", event);
+ thas.__connected = false;
+ thas.__instance = null;
+ thas.__autoLine(3);
+ }
+
+ // 连接出错
+ this.__instance.onerror = function (event) {
+ thas.__log("[WS] Connection error", event);
+ thas.__connected = false;
+ thas.__instance = null;
+ thas.__autoLine(3);
+ }
+
+ return this;
+ }
+
+ /**
+ * 添加消息监听
+ * @param listenerName
+ * @param listenerType
+ * @param callback
+ */
+ this.setOnMsgListener = function (listenerName, listenerType, callback) {
+ if (typeof listenerName != "string") {
+ return this;
+ }
+ if (typeof listenerType === "function") {
+ callback = listenerType;
+ listenerType = [];
+ }
+ if (!this.__isArr(listenerType)) {
+ listenerType = [listenerType];
+ }
+ if (typeof callback === "function") {
+ window.webSocketConfig.LISTENER[listenerName] = {
+ callback: callback,
+ listenerType: listenerType,
+ }
+ }
+ return this;
+ }
+ this.triggerMsgListener = function (msgDetail) {
+ var key, item;
+ for (key in window.webSocketConfig.LISTENER) {
+ if (!window.webSocketConfig.LISTENER.hasOwnProperty(key)) {
+ continue;
+ }
+ item = window.webSocketConfig.LISTENER[key];
+ if (item.listenerType.length > 0 && item.listenerType.indexOf(msgDetail.messageType) === -1) {
+ continue;
+ }
+ if (typeof item.callback === "function") {
+ try {
+ item.callback(msgDetail);
+ } catch (e) { }
+ }
+ }
+ }
+
+ /**
+ * 发送消息
+ * @param messageType 会话类型
+ * - refresh: 刷新
+ * @param target 发送目标
+ * @param body 发送内容(对象或数组)
+ * @param callback 发送回调
+ * @param againNum
+ */
+ this.sendTo = function (messageType, target, body, callback, againNum = 0) {
+ if (typeof target === "object" && typeof body === "undefined") {
+ body = target;
+ target = null;
+ }
+ if (typeof target === "function") {
+ body = target;
+ target = null;
+ }
+ if (typeof body === "function") {
+ callback = body;
+ body = null;
+ }
+ if (body === null || typeof body !== "object") {
+ body = {};
+ }
+ //
+ var thas = this;
+ if (this.__instance === null || this.__connected === false) {
+ if (againNum < 10 && messageType != 'team') {
+ setTimeout(function () {
+ thas.sendTo(messageType, target, body, callback, thas.__rNum(againNum) + 1)
+ }, 600);
+ if (againNum === 0) {
+ this.connection();
+ }
+ } else {
+ if (this.__instance === null) {
+ this.__log("[WS] Service not connected");
+ typeof callback === "function" && callback({status: 0, message: '服务未连接'});
+ } else {
+ this.__log("[WS] Failed connection");
+ typeof callback === "function" && callback({status: 0, message: '未连接成功'});
+ }
+ }
+ return this;
+ }
+ if (['refresh', 'notificationStatus'].indexOf(messageType) === -1) {
+ this.__log("[WS] Wrong message messageType: " + messageType);
+ typeof callback === "function" && callback({status: 0, message: '错误的消息类型: ' + messageType});
+ return this;
+ }
+ //
+ var contentId = 0;
+ if (messageType === 'roger') {
+ contentId = target;
+ target = null;
+ }
+ var messageId = '';
+ if (typeof callback === "function") {
+ messageId = this.__randString(16);
+ this.__callbackid[messageId] = callback;
+ }
+ this.__lastSend = Math.round(new Date().getTime()/1000);
+ this.__instance.send(JSON.stringify({
+ messageType: messageType,
+ messageId: messageId,
+ contentId: contentId,
+ userid: this.__config.userid,
+ target: target,
+ body: body,
+ time: this.__lastSend,
+ }));
+ return this;
+ }
+
+ /**
+ * 关闭连接
+ */
+ this.close = function () {
+ if (this.__instance === null) {
+ this.__log("[WS] Service not connected");
+ return this;
+ }
+ if (this.__connected === false) {
+ this.__log("[WS] Failed connection");
+ return this;
+ }
+ this.__instance.close();
+ return this;
+ }
+
+ return this.config(config);
+ },
+
+ WSOB: {
+ instance: null,
+ isClose: false,
+
+ /**
+ * 初始化
+ */
+ initialize() {
+ let url = window.webSocketConfig.URL;
+ if (!url) {
+ url = window.location.origin;
+ url = url.replace("https://", "wss://");
+ url = url.replace("http://", "ws://");
+ url+= "/ws";
+ }
+ let config = {
+ userid: $A.getUserId(),
+ url: url,
+ token: $A.getToken(),
+ };
+ if (window.webSocketConfig.DEBUG) {
+ config.logCallback = function (msg) {
+ console.log(msg);
+ };
+ }
+ if (this.instance === null) {
+ this.instance = new $A.WTWS(config);
+ this.instance.connection()
+ } else {
+ this.instance.config(config);
+ if (this.isClose) {
+ this.isClose = false
+ this.instance.connection();
+ }
+ }
+ },
+
+ /**
+ * 主动连接
+ */
+ connection() {
+ this.initialize();
+ this.instance.connection();
+ },
+
+ /**
+ * 监听消息
+ * @param listenerName
+ * @param listenerType
+ * @param callback
+ */
+ setOnMsgListener(listenerName, listenerType, callback) {
+ this.initialize();
+ this.instance.setOnMsgListener(listenerName, listenerType, callback);
+ },
+
+ /**
+ * 发送消息
+ * @param messageType
+ * @param target
+ * @param body
+ * @param callback
+ */
+ sendTo(messageType, target, body, callback) {
+ this.initialize();
+ this.instance.sendTo(messageType, target, body, callback);
+ },
+
+ /**
+ * 关闭连接
+ */
+ close() {
+ if (this.instance === null) {
+ return;
+ }
+ this.isClose = true
+ this.instance.config(null).close();
+ },
+ }
+ });
+
+ /**
+ * =============================================================================
+ * ***************************** iviewui assist ****************************
+ * =============================================================================
+ */
+ $.extend({
+ // 弹窗
+ modalConfig(config) {
+ if (typeof config === "string") {
+ config = {
+ content: config
+ };
+ }
+ config.title = $A.app.$L(config.title || (typeof config.render === 'undefined' ? '温馨提示' : ''));
+ config.content = $A.app.$L(config.content || '');
+ config.okText = $A.app.$L(config.okText || '确定');
+ config.cancelText = $A.app.$L(config.cancelText || '取消');
+ return config;
+ },
+
+ modalConfirm(config, millisecond = 0) {
+ if (millisecond > 0) {
+ setTimeout(() => { $A.modalConfirm(config) }, millisecond);
+ return;
+ }
+ $A.app.$Modal.confirm($A.modalConfig(config));
+ },
+
+ modalSuccess(config, millisecond = 0) {
+ if (millisecond > 0) {
+ setTimeout(() => { $A.modalSuccess(config) }, millisecond);
+ return;
+ }
+ $A.app.$Modal.success($A.modalConfig(config));
+ },
+
+ modalInfo(config, millisecond = 0) {
+ if (millisecond > 0) {
+ setTimeout(() => { $A.modalInfo(config) }, millisecond);
+ return;
+ }
+ $A.app.$Modal.info($A.modalConfig(config));
+ },
+
+ modalWarning(config, millisecond = 0) {
+ if (millisecond > 0) {
+ setTimeout(() => { $A.modalWarning(config) }, millisecond);
+ return;
+ }
+ $A.app.$Modal.warning($A.modalConfig(config));
+ },
+
+ modalError(config, millisecond = 0) {
+ if (millisecond > 0) {
+ setTimeout(() => { $A.modalError(config) }, millisecond);
+ return;
+ }
+ $A.app.$Modal.error($A.modalConfig(config));
+ },
+
+ modalInfoShow(title, data, addConfig) {
+ let content = '';
+ for (let i in data) {
+ let item = data[i];
+ content += `
`;
+ content += `
${item.column}:
`;
+ content += `
${item.value || item.value == '0' ? item.value : '-'}
`;
+ content += `
`;
+ }
+ let config = {
+ title: title,
+ content: content,
+ okText: $A.app.$L('关闭'),
+ closable: true
+ };
+ if (typeof addConfig == 'object' && addConfig) {
+ config = Object.assign(config, addConfig);
+ }
+ this.app.$Modal.info(config);
+ },
+
+ modalAlert(msg) {
+ alert($A.app.$L(msg));
+ },
+
+ //提示
+ messageSuccess(msg) {
+ $A.app.$Message.success($A.app.$L(msg));
+ },
+
+ messageWarning(msg) {
+ $A.app.$Message.warning($A.app.$L(msg));
+ },
+
+ messageError(msg) {
+ $A.app.$Message.error($A.app.$L(msg));
+ },
+
+ //通知
+ noticeConfig(config) {
+ if (typeof config === "string") {
+ config = {
+ desc: config
+ };
+ }
+ config.title = $A.app.$L(config.title || (typeof config.render === 'undefined' ? '温馨提示' : ''));
+ config.desc = $A.app.$L(config.desc || '');
+ return config;
+ },
+
+ noticeSuccess(config) {
+ $A.app.$Notice.success($A.noticeConfig(config));
+ },
+
+ noticeWarning(config) {
+ $A.app.$Notice.warning($A.noticeConfig(config));
+ },
+
+ noticeError(config) {
+ if (typeof config === "string") {
+ config = {
+ desc: config,
+ duration: 6
+ };
+ }
+ $A.app.$Notice.error($A.noticeConfig(config));
+ },
+ });
+
+ window.$A = $;
+})(window);
diff --git a/resources/js/pages/404.vue b/resources/js/pages/404.vue
new file mode 100644
index 00000000..438f8cbd
--- /dev/null
+++ b/resources/js/pages/404.vue
@@ -0,0 +1,45 @@
+
+
+
+
+
diff --git a/resources/js/pages/dashboard/index.vue b/resources/js/pages/dashboard/index.vue
new file mode 100644
index 00000000..970698b5
--- /dev/null
+++ b/resources/js/pages/dashboard/index.vue
@@ -0,0 +1,14 @@
+
+ dashboard
+
+
+
diff --git a/resources/js/pages/index.vue b/resources/js/pages/index.vue
new file mode 100644
index 00000000..544abe6e
--- /dev/null
+++ b/resources/js/pages/index.vue
@@ -0,0 +1,21 @@
+
+
+
+
+
diff --git a/resources/js/pages/login/index.vue b/resources/js/pages/login/index.vue
new file mode 100644
index 00000000..4afd47b0
--- /dev/null
+++ b/resources/js/pages/login/index.vue
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
diff --git a/resources/js/routes.js b/resources/js/routes.js
new file mode 100755
index 00000000..c95a5c23
--- /dev/null
+++ b/resources/js/routes.js
@@ -0,0 +1,22 @@
+export default [
+ {
+ path: '/',
+ name: 'index',
+ component: resolve => require(['./pages/index.vue'], resolve)
+ },
+ {
+ path: '*',
+ name: '404',
+ component: resolve => require(['./pages/404.vue'], resolve),
+ },
+ {
+ path: '/login',
+ name: 'login',
+ component: resolve => require(['./pages/login/index.vue'], resolve),
+ },
+ {
+ path: '/dashboard',
+ name: 'dashboard',
+ component: resolve => require(['./pages/dashboard/index.vue'], resolve),
+ },
+]
diff --git a/resources/lang/language.js b/resources/lang/language.js
new file mode 100644
index 00000000..49e15457
--- /dev/null
+++ b/resources/lang/language.js
@@ -0,0 +1,2 @@
+exports.default = [
+];
diff --git a/resources/public/js/html2md.js b/resources/public/js/html2md.js
deleted file mode 100644
index c7c08c83..00000000
--- a/resources/public/js/html2md.js
+++ /dev/null
@@ -1,876 +0,0 @@
-(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.toMarkdown = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0) {
- elem = inqueue.shift()
- outqueue.push(elem)
- children = elem.childNodes
- for (i = children.length - 1; i >= 0; i--) {
- if (children[i].nodeType === 1) inqueue.push(children[i])
- }
- }
- outqueue.shift()
- return outqueue
- }
-
- /*
- * Contructs a Markdown string of replacement text for a given node
- */
-
- function getContent (node) {
- var text = ''
- for (var i = 0; i < node.childNodes.length; i++) {
- if (node.childNodes[i].nodeType === 1) {
- text += node.childNodes[i]._replacement
- } else if (node.childNodes[i].nodeType === 3) {
- text += node.childNodes[i].data
- } else continue
- }
- return text
- }
-
- /*
- * Returns the HTML string of an element with its contents converted
- */
-
- function outer (node, content) {
- return node.cloneNode(false).outerHTML.replace('><', '>' + content + '<')
- }
-
- function canConvert (node, filter) {
- if (typeof filter === 'string') {
- return filter === node.nodeName.toLowerCase()
- }
- if (Array.isArray(filter)) {
- return filter.indexOf(node.nodeName.toLowerCase()) !== -1
- } else if (typeof filter === 'function') {
- return filter.call(toMarkdown, node)
- } else {
- throw new TypeError('`filter` needs to be a string, array, or function')
- }
- }
-
- function isFlankedByWhitespace (side, node) {
- var sibling
- var regExp
- var isFlanked
-
- if (side === 'left') {
- sibling = node.previousSibling
- regExp = / $/
- } else {
- sibling = node.nextSibling
- regExp = /^ /
- }
-
- if (sibling) {
- if (sibling.nodeType === 3) {
- isFlanked = regExp.test(sibling.nodeValue)
- } else if (sibling.nodeType === 1 && !isBlock(sibling)) {
- isFlanked = regExp.test(sibling.textContent)
- }
- }
- return isFlanked
- }
-
- function flankingWhitespace (node, content) {
- var leading = ''
- var trailing = ''
-
- if (!isBlock(node)) {
- var hasLeading = /^[ \r\n\t]/.test(content)
- var hasTrailing = /[ \r\n\t]$/.test(content)
-
- if (hasLeading && !isFlankedByWhitespace('left', node)) {
- leading = ' '
- }
- if (hasTrailing && !isFlankedByWhitespace('right', node)) {
- trailing = ' '
- }
- }
-
- return { leading: leading, trailing: trailing }
- }
-
- /*
- * Finds a Markdown converter, gets the replacement, and sets it on
- * `_replacement`
- */
-
- function process (node) {
- var replacement
- var content = getContent(node)
-
- // Remove blank nodes
- if (!isVoid(node) && !/A|TH|TD/.test(node.nodeName) && /^\s*$/i.test(content)) {
- node._replacement = ''
- return
- }
-
- for (var i = 0; i < converters.length; i++) {
- var converter = converters[i]
-
- if (canConvert(node, converter.filter)) {
- if (typeof converter.replacement !== 'function') {
- throw new TypeError(
- '`replacement` needs to be a function that returns a string'
- )
- }
-
- var whitespace = flankingWhitespace(node, content)
-
- if (whitespace.leading || whitespace.trailing) {
- content = content.trim()
- }
- replacement = whitespace.leading +
- converter.replacement.call(toMarkdown, content, node) +
- whitespace.trailing
- break
- }
- }
-
- node._replacement = replacement
- }
-
- toMarkdown = function (input, options) {
- options = options || {}
-
- if (typeof input !== 'string') {
- throw new TypeError(input + ' is not a string')
- }
-
- if (input === '') {
- return ''
- }
-
- // Escape potential ol triggers
- input = input.replace(/(\d+)\. /g, '$1\\. ')
-
- var clone = htmlToDom(input).body
- var nodes = bfsOrder(clone)
- var output
-
- converters = mdConverters.slice(0)
- if (options.gfm) {
- converters = gfmConverters.concat(converters)
- }
-
- if (options.converters) {
- converters = options.converters.concat(converters)
- }
-
- // Process through nodes in reverse (so deepest child elements are first).
- for (var i = nodes.length - 1; i >= 0; i--) {
- process(nodes[i])
- }
- output = getContent(clone)
-
- return output.replace(/^[\t\r\n]+|[\t\r\n\s]+$/g, '')
- .replace(/\n\s+\n/g, '\n\n')
- .replace(/\n{3,}/g, '\n\n')
- }
-
- toMarkdown.isBlock = isBlock
- toMarkdown.isVoid = isVoid
- toMarkdown.outer = outer
-
- module.exports = toMarkdown
-
- },{"./lib/gfm-converters":2,"./lib/html-parser":3,"./lib/md-converters":4,"collapse-whitespace":6}],2:[function(require,module,exports){
- 'use strict'
-
- function cell (content, node) {
- var index = Array.prototype.indexOf.call(node.parentNode.childNodes, node)
- var prefix = ' '
- if (index === 0) prefix = '| '
- return prefix + content + ' |'
- }
-
- var highlightRegEx = /highlight highlight-(\S+)/
-
- module.exports = [
- {
- filter: 'br',
- replacement: function () {
- return '\n'
- }
- },
- {
- filter: ['del', 's', 'strike'],
- replacement: function (content) {
- return '~~' + content + '~~'
- }
- },
-
- {
- filter: function (node) {
- return node.type === 'checkbox' && node.parentNode.nodeName === 'LI'
- },
- replacement: function (content, node) {
- return (node.checked ? '[x]' : '[ ]') + ' '
- }
- },
-
- {
- filter: ['th', 'td'],
- replacement: function (content, node) {
- return cell(content, node)
- }
- },
-
- {
- filter: 'tr',
- replacement: function (content, node) {
- var borderCells = ''
- var alignMap = { left: ':--', right: '--:', center: ':-:' }
-
- if (node.parentNode.nodeName === 'THEAD') {
- for (var i = 0; i < node.childNodes.length; i++) {
- var align = node.childNodes[i].attributes.align
- var border = '---'
-
- if (align) border = alignMap[align.value] || border
-
- borderCells += cell(border, node.childNodes[i])
- }
- }
- return '\n' + content + (borderCells ? '\n' + borderCells : '')
- }
- },
-
- {
- filter: 'table',
- replacement: function (content) {
- return '\n\n' + content + '\n\n'
- }
- },
-
- {
- filter: ['thead', 'tbody', 'tfoot'],
- replacement: function (content) {
- return content
- }
- },
-
- // Fenced code blocks
- {
- filter: function (node) {
- return node.nodeName === 'PRE' &&
- node.firstChild &&
- node.firstChild.nodeName === 'CODE'
- },
- replacement: function (content, node) {
- return '\n\n```\n' + node.firstChild.textContent + '\n```\n\n'
- }
- },
-
- // Syntax-highlighted code blocks
- {
- filter: function (node) {
- return node.nodeName === 'PRE' &&
- node.parentNode.nodeName === 'DIV' &&
- highlightRegEx.test(node.parentNode.className)
- },
- replacement: function (content, node) {
- var language = node.parentNode.className.match(highlightRegEx)[1]
- return '\n\n```' + language + '\n' + node.textContent + '\n```\n\n'
- }
- },
-
- {
- filter: function (node) {
- return node.nodeName === 'DIV' &&
- highlightRegEx.test(node.className)
- },
- replacement: function (content) {
- return '\n\n' + content + '\n\n'
- }
- }
- ]
-
- },{}],3:[function(require,module,exports){
- /*
- * Set up window for Node.js
- */
-
- var _window = (typeof window !== 'undefined' ? window : this)
-
- /*
- * Parsing HTML strings
- */
-
- function canParseHtmlNatively () {
- var Parser = _window.DOMParser
- var canParse = false
-
- // Adapted from https://gist.github.com/1129031
- // Firefox/Opera/IE throw errors on unsupported types
- try {
- // WebKit returns null on unsupported types
- if (new Parser().parseFromString('', 'text/html')) {
- canParse = true
- }
- } catch (e) {}
-
- return canParse
- }
-
- function createHtmlParser () {
- var Parser = function () {}
-
- // For Node.js environments
- if (typeof document === 'undefined') {
- var jsdom = require('jsdom')
- Parser.prototype.parseFromString = function (string) {
- return jsdom.jsdom(string, {
- features: {
- FetchExternalResources: [],
- ProcessExternalResources: false
- }
- })
- }
- } else {
- if (!shouldUseActiveX()) {
- Parser.prototype.parseFromString = function (string) {
- var doc = document.implementation.createHTMLDocument('')
- doc.open()
- doc.write(string)
- doc.close()
- return doc
- }
- } else {
- Parser.prototype.parseFromString = function (string) {
- var doc = new window.ActiveXObject('htmlfile')
- doc.designMode = 'on' // disable on-page scripts
- doc.open()
- doc.write(string)
- doc.close()
- return doc
- }
- }
- }
- return Parser
- }
-
- function shouldUseActiveX () {
- var useActiveX = false
-
- try {
- document.implementation.createHTMLDocument('').open()
- } catch (e) {
- if (window.ActiveXObject) useActiveX = true
- }
-
- return useActiveX
- }
-
- module.exports = canParseHtmlNatively() ? _window.DOMParser : createHtmlParser()
-
- },{"jsdom":8}],4:[function(require,module,exports){
- 'use strict'
- module.exports = [
- // P标签处理
- {
- filter: 'p',
- replacement: function (content, node) {
- var attrClass = node.getAttribute('class') || ''
-
- if (attrClass === 'command') {
- if (!content.endsWith('\n')) {
- content += '\n'
- }
- return '\n```\n' + content + '```\n'
- } else {
- return '\n\n' + content + '\n\n'
- }
- }
- },
- // BR 标签处理
- {
- filter: 'br',
- replacement: function () {
- return ' \n'
- }
- },
- // H1 处理
- {
- filter: 'h1',
- replacement: function (content, node) {
- if (typeof titleLock === "undefined") {
- var titleLock = false;
- }
- if (!titleLock) {
- titleLock = true;
- return content + "\n" + "=".repeat(60);
- }
- else {
- return '\n\n' + '# ' + content + '\n\n'
- }
- }
- },
- // H2-H7 标签处理
- {
- filter: ['h2', 'h3', 'h4', 'h5', 'h6', 'h7'],
- replacement: function (content, node) {
- var hLevel = node.nodeName.charAt(1)
- var hPrefix = '##'
- hLevel = hLevel - 2
- for (var i = 0; i < hLevel; i++) {
- hPrefix += '#'
- }
- return '\n\n' + hPrefix + ' ' + content + '\n\n'
- }
- },
- // HR 标签处理
- {
- filter: 'hr',
- replacement: function () {
- return '\n\n* * *\n\n'
- }
- },
- // em i 斜体处理
- {
- filter: ['em', 'i'],
- replacement: function (content) {
- return ' _' + content + '_ '
- }
- },
- // Strong b 粗体处理
- {
- filter: ['strong', 'b'],
- replacement: function (content) {
- return '**' + content + '**'
- }
- },
- // Inline code
- {
- filter: function (node) {
- var hasSiblings = node.previousSibling || node.nextSibling
- var isCodeBlock = node.parentNode.nodeName === 'PRE' && !hasSiblings
-
- return node.nodeName === 'CODE' && !isCodeBlock
- },
- replacement: function (content) {
- return '`' + content + '`'
- }
- },
- // A 标签处理
- {
- filter: function (node) {
- return node.nodeName === 'A' && node.getAttribute('href')
- },
- replacement: function (content, node) {
- return '[' + content + '](' + node.getAttribute('href') + ')'
- }
- },
- // 特殊情况下的A标签处理
- {
- filter: function (node) {
- return node.nodeName === 'A' && node.getAttribute('style')
- },
- replacement: function (content, node) {
- return content
- }
- },
- // IMG 标签处理
- {
- filter: 'img',
- replacement: function (content, node) {
- var alt = node.alt || ''
- var src = node.getAttribute('src') || ''
- var title = node.title || ''
- var titlePart = title ? ' "' + title + '"' : ''
- return src ? '\n![' + alt + ']' + '(' + src + titlePart + ')\n' : ''
- }
- },
- // 代码块处理
- {
- filter: 'pre',
- replacement: function (content, node) {
- let contentText = node.innerText
- if (!contentText.endsWith('\n')) {
- contentText += '\n'
- }
- return '\n```\n' + contentText + '```\n'
- }
- },
- // 行内代码处理
- {
- filter: 'code',
- replacement: function (content, node) {
- return '`' + content + '`'
- }
- },
- // IFrame 提醒
- {
- filter: 'iframe',
- replacement: function (content, node) {
- console.log(node);
- console.log(content);
- return '\n ** 此处有iframe,请手动处理 ** \n'
- }
- },
- // Canvas 提醒
- {
- filter: 'canvas',
- replacement: function (content, node) {
- return '\n ** 此处有Canvas,请手动处理 ** \n'
- }
- },
- // div 处理
- {
- filter: 'div',
- replacement: function (content, node) {
- var attrClass = node.getAttribute('class') || ''
- if (attrClass === 'code') {
- if (!content.endsWith('\n')) {
- content += '\n'
- }
- return '\n```\n' + content + '```\n'
- } else {
- return content
- }
- }
- },
- {
- 'filter': 'textarea',
- replacement: function (content, node) {
- return ''
- }
- },
- // 直接返回内容的标签
- {
- filter: ['figure', 'span', 'small', 'section', 'font', 'asymspc', 'button', 'article', 'figcaption'],
- replacement: function (content) {
- return content
- }
- },
- // 引用
- {
- filter: 'blockquote',
- replacement: function (content) {
- content = content.trim()
- content = content.replace(/\n{3,}/g, '\n\n')
- content = content.replace(/^/gm, '> ')
- return '\n\n' + content + '\n\n'
- }
- },
- // 列表项
- {
- filter: 'li',
- replacement: function (content, node) {
- content = content.replace(/^\s+/, '').replace(/\n/gm, '\n ')
- var prefix = '* '
- var parent = node.parentNode
- var index = Array.prototype.indexOf.call(parent.children, node) + 1
-
- prefix = /ol/i.test(parent.nodeName) ? index + '. ' : '* '
- return prefix + content + '\n'
- }
- },
- // 有序/无序列表
- {
- filter: ['ul', 'ol'],
- replacement: function (content, node) {
- var strings = []
- for (var i = 0; i < node.childNodes.length; i++) {
- strings.push(node.childNodes[i]._replacement)
- }
-
- if (/li/i.test(node.parentNode.nodeName)) {
- return '\n' + strings.join('\n')
- }
- return '\n\n' + strings.join('\n') + '\n\n'
- }
- },
- // 判断是否是block,如果是block,前后加空行
- {
- filter: function (node) {
- return this.isBlock(node)
- },
- replacement: function (content, node) {
- return '\n\n' + this.outer(node, content) + '\n\n'
- }
- },
-
- // Anything else!
- {
- filter: function () {
- return true
- },
- replacement: function (content, node) {
- return this.outer(node, content)
- }
- }
- ]
-
- },{}],5:[function(require,module,exports){
- /**
- * This file automatically generated from `build.js`.
- * Do not manually edit.
- */
-
- module.exports = [
- "address",
- "article",
- "aside",
- "blockquote",
- "canvas",
- "dd",
- "div",
- "dl",
- "dt",
- "fieldset",
- "figcaption",
- "figure",
- "footer",
- "form",
- "h1",
- "h2",
- "h3",
- "h4",
- "h5",
- "h6",
- "h7",
- "header",
- "hgroup",
- "hr",
- "li",
- "main",
- "nav",
- "noscript",
- "ol",
- "output",
- "p",
- "pre",
- "section",
- "table",
- "tfoot",
- "ul",
- "video"
- ];
-
- },{}],6:[function(require,module,exports){
- 'use strict';
-
- var voidElements = require('void-elements');
- Object.keys(voidElements).forEach(function (name) {
- voidElements[name.toUpperCase()] = 1;
- });
-
- var blockElements = {};
- require('block-elements').forEach(function (name) {
- blockElements[name.toUpperCase()] = 1;
- });
-
- /**
- * isBlockElem(node) determines if the given node is a block element.
- *
- * @param {Node} node
- * @return {Boolean}
- */
- function isBlockElem(node) {
- return !!(node && blockElements[node.nodeName]);
- }
-
- /**
- * isVoid(node) determines if the given node is a void element.
- *
- * @param {Node} node
- * @return {Boolean}
- */
- function isVoid(node) {
- return !!(node && voidElements[node.nodeName]);
- }
-
- /**
- * whitespace(elem [, isBlock]) removes extraneous whitespace from an
- * the given element. The function isBlock may optionally be passed in
- * to determine whether or not an element is a block element; if none
- * is provided, defaults to using the list of block elements provided
- * by the `block-elements` module.
- *
- * @param {Node} elem
- * @param {Function} blockTest
- */
- function collapseWhitespace(elem, isBlock) {
- if (!elem.firstChild || elem.nodeName === 'PRE') return;
-
- if (typeof isBlock !== 'function') {
- isBlock = isBlockElem;
- }
-
- var prevText = null;
- var prevVoid = false;
-
- var prev = null;
- var node = next(prev, elem);
-
- while (node !== elem) {
- if (node.nodeType === 3) {
- // Node.TEXT_NODE
- var text = node.data.replace(/[ \r\n\t]+/g, ' ');
-
- if ((!prevText || / $/.test(prevText.data)) && !prevVoid && text[0] === ' ') {
- text = text.substr(1);
- }
-
- // `text` might be empty at this point.
- if (!text) {
- node = remove(node);
- continue;
- }
-
- node.data = text;
- prevText = node;
- } else if (node.nodeType === 1) {
- // Node.ELEMENT_NODE
- if (isBlock(node) || node.nodeName === 'BR') {
- if (prevText) {
- prevText.data = prevText.data.replace(/ $/, '');
- }
-
- prevText = null;
- prevVoid = false;
- } else if (isVoid(node)) {
- // Avoid trimming space around non-block, non-BR void elements.
- prevText = null;
- prevVoid = true;
- }
- } else {
- node = remove(node);
- continue;
- }
-
- var nextNode = next(prev, node);
- prev = node;
- node = nextNode;
- }
-
- if (prevText) {
- prevText.data = prevText.data.replace(/ $/, '');
- if (!prevText.data) {
- remove(prevText);
- }
- }
- }
-
- /**
- * remove(node) removes the given node from the DOM and returns the
- * next node in the sequence.
- *
- * @param {Node} node
- * @return {Node} node
- */
- function remove(node) {
- var next = node.nextSibling || node.parentNode;
-
- node.parentNode.removeChild(node);
-
- return next;
- }
-
- /**
- * next(prev, current) returns the next node in the sequence, given the
- * current and previous nodes.
- *
- * @param {Node} prev
- * @param {Node} current
- * @return {Node}
- */
- function next(prev, current) {
- if (prev && prev.parentNode === current || current.nodeName === 'PRE') {
- return current.nextSibling || current.parentNode;
- }
-
- return current.firstChild || current.nextSibling || current.parentNode;
- }
-
- module.exports = collapseWhitespace;
-
- },{"block-elements":5,"void-elements":7}],7:[function(require,module,exports){
- /**
- * This file automatically generated from `pre-publish.js`.
- * Do not manually edit.
- */
-
- module.exports = {
- "area": true,
- "base": true,
- "br": true,
- "col": true,
- "embed": true,
- "hr": true,
- "img": true,
- "input": true,
- "keygen": true,
- "link": true,
- "menuitem": true,
- "meta": true,
- "param": true,
- "source": true,
- "track": true,
- "wbr": true
- };
-
- },{}],8:[function(require,module,exports){
-
- },{}]},{},[1])(1)
-});
\ No newline at end of file
diff --git a/resources/scss/app.scss b/resources/scss/app.scss
new file mode 100644
index 00000000..b20be79a
--- /dev/null
+++ b/resources/scss/app.scss
@@ -0,0 +1,2 @@
+@import "loading";
+@import "main";
diff --git a/resources/scss/loading.scss b/resources/scss/loading.scss
new file mode 100755
index 00000000..fb3ca46c
--- /dev/null
+++ b/resources/scss/loading.scss
@@ -0,0 +1,75 @@
+.app-view-loading {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 99999;
+ background-color: rgba(255, 255, 255, 0.7);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ > div {
+ text-align: center;
+
+ > div {
+ color: #ccc;
+ margin: 0;
+ font: 11px verdana;
+ line-height: 16px;
+ text-transform: uppercase;
+ letter-spacing: 1px;
+ }
+
+ > span {
+ display: inline-block;
+ vertical-align: middle;
+ width: 8px;
+ height: 8px;
+ margin: 2px;
+ background: #007DB6;
+ border-radius: 8px;
+ animation: app-view-loadanim 1s infinite alternate;
+
+ &:nth-of-type(2) {
+ background: #008FB2;
+ animation-delay: 0.2s;
+ }
+
+ &:nth-of-type(3) {
+ background: #009B9E;
+ animation-delay: 0.4s;
+ }
+
+ &:nth-of-type(4) {
+ background: #00A77D;
+ animation-delay: 0.6s;
+ }
+
+ &:nth-of-type(5) {
+ background: #00B247;
+ animation-delay: 0.8s;
+ }
+
+ &:nth-of-type(6) {
+ background: #5AB027;
+ animation-delay: 1.0s;
+ }
+
+ &:nth-of-type(7) {
+ background: #A0B61E;
+ animation-delay: 1.2s;
+ }
+ }
+
+ @keyframes app-view-loadanim {
+ 0% {
+ opacity: 0;
+ }
+ 100% {
+ opacity: 1;
+ }
+ }
+ }
+}
diff --git a/resources/scss/main.scss b/resources/scss/main.scss
new file mode 100755
index 00000000..0b37fb61
--- /dev/null
+++ b/resources/scss/main.scss
@@ -0,0 +1,285 @@
+*[hidden="hidden"] {
+ display: none !important;
+}
+
+.icon-loading {
+ animation: icon-loading-load 0.6s infinite linear;
+}
+
+@keyframes icon-loading-load {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
+
+.ivu-modal-wrap {
+ &.simple-modal {
+ .ivu-modal {
+ top: 100px;
+ padding-bottom: 100px;
+ @media (max-height: 900px) {
+ top: 35px;
+ padding-bottom: 35px;
+ }
+ }
+ .ivu-modal-header,
+ .ivu-modal-footer {
+ border-color: transparent;
+ }
+
+ .form-network-add-tabs {
+ .ivu-tabs-tabpane {
+ padding: 10px 6px 0;
+ }
+ }
+ .form-network-add-in-out {
+ padding: 0 6px;
+ .select-in-type {
+ span.ivu-radio {
+ display: none;
+ }
+ .select-in-type-item-checked {
+ color: #2d8cf0;
+ border: 1px solid #2d8cf0 !important;
+ }
+ .select-in-type-item {
+ display: flex;
+ align-items: center;
+ min-width: 90px;
+ border: 1px solid #E8EBEE;
+ border-radius: 4px;
+ padding: 0 12px;
+ margin: 0 8px 0 0;
+ > span {
+ flex: 1;
+ }
+ &:hover {
+ cursor: pointer;
+ }
+ .select-in-type-icon {
+ margin-left: 12px;
+ }
+ }
+ }
+ .select-in-node {
+ margin-top: 18px;
+ }
+ }
+ }
+}
+
+.modal-info-show {
+ display: flex;
+ .column {
+ color: #6D6D6D;
+ margin: 5px 0;
+ min-width: 70px;
+ max-width: 100px;
+ text-align: right;
+ }
+ .value {
+ flex: 1;
+ width: 0;
+ color: #414141;
+ margin: 5px 0 5px 5px;
+ word-break: break-all;
+ }
+}
+
+.ivu-select-dropdown {
+ max-height: 360px;
+ &.select-node {
+ .ivu-select-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ .option-title {
+ flex: 1;
+ }
+ .ivu-tag {
+ margin-left: 18px;
+ margin-right: 0;
+ transform: scale(0.9);
+ transform-origin: right center;
+ }
+ }
+ }
+}
+
+.ivu-tooltip-popper {
+ .ivu-tooltip-inner {
+ white-space: normal;
+ }
+}
+
+.ivu-table {
+ table {
+ width: 100% !important;
+ .ivu-table-cell {
+ padding-left: 12px;
+ padding-right: 12px;
+ }
+ thead {
+ .ivu-table-cell {
+ display: block;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ }
+ }
+ tbody {
+ .tree-icon-loading {
+ .ivu-table-cell {
+ display: flex;
+ align-items: center;
+ .ivu-table-cell-tree {
+ margin-right: 6px;
+ }
+ }
+ }
+ }
+ }
+ .td-ellipsis {
+ display: flex;
+ align-items: center;
+ max-width: 100%;
+ .remark-text {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ align-items: center;
+ white-space: nowrap;
+ height: 20px;
+ line-height: 20px;
+ margin-right: 6px;
+ }
+ .remark-icon {
+ display: none;
+ font-size: 16px;
+ cursor: pointer;
+ }
+ .remark-tag {
+ display: inline-block;
+ height: 22px;
+ line-height: 22px;
+ margin: 2px 4px 2px 0;
+ border: 1px solid #e8eaec;
+ border-radius: 3px;
+ background: #f7f7f7;
+ font-size: 12px;
+ vertical-align: middle;
+ opacity: 1;
+ color: #515a6e;
+ padding: 0 4px;
+ white-space: nowrap;
+ overflow: visible;
+ &.pointer-tag {
+ cursor: pointer;
+ color: #1890ff;
+ background: #e6f7ff;
+ border-color: #91d5ff;
+ }
+ }
+ .icon-tooltip {
+ .ivu-tooltip-rel {
+ display: flex;
+ align-items: center;
+ }
+ }
+ }
+ .td-action {
+ max-width: 100%;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ vertical-align: middle;
+ .td-action-container {
+ display: inline-block;
+ a {
+ font-size: 12px;
+ padding: 0 5px;
+ }
+ }
+ }
+ .ivu-table-row-hover {
+ &:hover {
+ .td-ellipsis {
+ .remark-icon {
+ display: inline-block;
+ }
+ }
+ }
+ }
+ &:before {
+ background-color: #efefef;
+ }
+}
+.auto-height-top {
+ .ivu-table {
+ .ivu-table-body {
+ table {
+ td {
+ height: auto;
+ vertical-align: top;
+ .ivu-table-cell {
+ display: flex;
+ align-items: center;
+ min-height: 48px;
+ padding: 8px 12px;
+ .node-line {
+ max-width: 100%;
+ .td-ellipsis {
+ .remark-line {
+ margin: 2px 6px 2px 0;
+ &:hover {
+ border-color: #888;
+ }
+ }
+ .remark-tag {
+ margin: 0;
+ transform: scale(0.8);
+ }
+ .remark-icon {
+ cursor: pointer;
+ &:hover {
+ color: #2d8cf0;
+ }
+ .ivu-icon {
+ vertical-align: unset;
+ transform: scale(1.2);
+ &.ivu-icon-md-remove-circle {
+ background-image: url("data:image/svg+xml;base64,PHN2ZyB0PSIxNjIxMDAxMDg0MzAxIiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjE4NjUiIHdpZHRoPSIyNTYiIGhlaWdodD0iMjU2Ij48cGF0aCBkPSJNNTEyIDUxMm0tNTEyIDBhNTEyIDUxMiAwIDEgMCAxMDI0IDAgNTEyIDUxMiAwIDEgMC0xMDI0IDBaIiBmaWxsPSIjRkZGRkZGIiBwLWlkPSIxODY2Ij48L3BhdGg+PHBhdGggZD0iTTUxMiAwYTUxMiA1MTIgMCAxIDAgMCAxMDI0QTUxMiA1MTIgMCAwIDAgNTEyIDB6IG0zODQgNTEyYzAgODIuNzM5Mi0yNi40MTkyIDE1OS4zMzQ0LTcxLjA2NTYgMjIyLjEwNTZMMjg5Ljg5NDQgMTk5LjA2NTZBMzgxLjc0NzIgMzgxLjc0NzIgMCAwIDEgNTEyIDEyOCAzODQuNDA5NiAzODQuNDA5NiAwIDAgMSA4OTYgNTEyeiBtLTc2OCAwYzAtODMuMzUzNiAyNi43MjY0LTE2MC40NjA4IDcxLjk4NzItMjIzLjQzNjhsNTM1LjU1MiA1MzUuMzQ3MkEzODEuNzQ3MiAzODEuNzQ3MiAwIDAgMSA1MTIgODk2IDM4NC40MDk2IDM4NC40MDk2IDAgMCAxIDEyOCA1MTJ6IiBmaWxsPSIjZmYwMDAwIiBwLWlkPSIxODY3IiBkYXRhLXNwbS1hbmNob3ItaWQ9ImEzMTN4Ljc3ODEwNjkuMC5pMCIgY2xhc3M9InNlbGVjdGVkIj48L3BhdGg+PC9zdmc+");
+ background-repeat: no-repeat;
+ width: 12px;
+ height: 12px;
+ background-size: 94%;
+ background-position: center;
+ vertical-align: text-top;
+ &:before {
+ display: none;
+ }
+ }
+ }
+ }
+ .node-signal-box {
+ margin-left: 1px;
+ .node-ping-value {
+ margin-left: 2px;
+ }
+ }
+ .ivu-table-cell-tooltip {
+ width: auto;
+ .ivu-tooltip-rel {
+ max-width: 100%;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/webpack.mix.js b/webpack.mix.js
index 5fef3e4f..76b16a17 100644
--- a/webpack.mix.js
+++ b/webpack.mix.js
@@ -11,8 +11,21 @@ const mix = require('laravel-mix');
|
*/
+function getFileName(str) {
+ if (/resources_js_pages_(.*?)_vue/.test(str)) {
+ return /resources_js_pages_(.*?)_vue/.exec(str)[1];
+ }
+ return str;
+}
-mix.js('resources/js/app.js', 'public/js')
- .postCss('resources/css/app.css', 'public/css', [
- //
- ]).copy('resources/public', 'public');
+mix.vue({ version: 2 })
+ .copy('resources/public', 'public')
+ .js('resources/js/app.js', 'public/js')
+ .sass('resources/scss/app.scss','public/css')
+ .webpackConfig({
+ output: {
+ chunkFilename: function ({chunk}) {
+ return `js/build/${ getFileName(chunk.id) }.${ mix.inProduction() ? '[hash:8].' : '' }js`
+ }
+ },
+ });