mirror of
https://gitee.com/lab1024/smart-admin.git
synced 2025-11-13 14:13:47 +08:00
v1.0.4
This commit is contained in:
21
smart-admin-web/src/lib/cookie.js
Normal file
21
smart-admin-web/src/lib/cookie.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import Cookies from 'js-cookie';
|
||||
import config from '@/config';
|
||||
const { cookieExpires } = config;
|
||||
export const TOKEN_KEY = 'token';
|
||||
|
||||
export default {
|
||||
setToken: token => {
|
||||
Cookies.set(TOKEN_KEY, token, {
|
||||
// token在Cookie中存储的天数,默认1天
|
||||
expires: cookieExpires || 7
|
||||
});
|
||||
},
|
||||
getToken: () => {
|
||||
const token = Cookies.get(TOKEN_KEY);
|
||||
if (token) return token;
|
||||
else return null;
|
||||
},
|
||||
clearToken: () => {
|
||||
Cookies.remove(TOKEN_KEY);
|
||||
}
|
||||
};
|
||||
91
smart-admin-web/src/lib/http.js
Normal file
91
smart-admin-web/src/lib/http.js
Normal file
@@ -0,0 +1,91 @@
|
||||
import Axios from 'axios';
|
||||
import config from '@/config';
|
||||
import { Message, Spin } from 'iview';
|
||||
import cookie from '@/lib/cookie';
|
||||
// 之所以封装这个axios,是因为在一些请求中,无法上传信息,很尴尬,估计原因是继承的有问题,无法携带headers
|
||||
export const baseUrl = config.baseUrl.apiUrl;
|
||||
export const socketBaseUrl = config.baseUrl.webSocketUrl;
|
||||
|
||||
let axios = Axios.create({
|
||||
baseURL: baseUrl,
|
||||
timeout: 30000,
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8'
|
||||
}
|
||||
});
|
||||
// 添加请求拦截器
|
||||
|
||||
// download url
|
||||
const downloadUrl = url => {
|
||||
let iframe = document.createElement('iframe');
|
||||
iframe.style.display = 'none';
|
||||
iframe.src = url;
|
||||
iframe.onload = function () {
|
||||
document.body.removeChild(iframe);
|
||||
};
|
||||
document.body.appendChild(iframe);
|
||||
};
|
||||
|
||||
axios.interceptors.request.use(
|
||||
function (config) {
|
||||
// 在发送请求之前做些什么
|
||||
if (cookie.getToken()) {
|
||||
config.headers['x-access-token'] = cookie.getToken();
|
||||
}
|
||||
return config;
|
||||
},
|
||||
function (error) {
|
||||
// 对请求错误做些什么
|
||||
Spin.hide();
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
// 添加响应拦截器
|
||||
axios.interceptors.response.use(
|
||||
res => {
|
||||
// 处理请求是下载的接口
|
||||
if (
|
||||
res.headers &&
|
||||
(res.headers['content-type'] === 'application/x-msdownload' ||
|
||||
res.headers['content-type'] ===
|
||||
'application/octet-stream;charset=utf-8')
|
||||
) {
|
||||
downloadUrl(res.request.responseURL);
|
||||
res.data = '';
|
||||
res.headers['content-type'] = 'text/json';
|
||||
return res;
|
||||
}
|
||||
let { data } = res;
|
||||
if (data.code !== 1) {
|
||||
if (data.code === 1001) {
|
||||
cookie.clearToken();
|
||||
localStorage.clear();
|
||||
window.location.href = window.location.pathname + '#/login';
|
||||
Message.error('未登录,或登录失效,请登录');
|
||||
} else if (data.code === 502) {
|
||||
window.location.href = window.location.pathname + '#/500';
|
||||
} else {
|
||||
Message.error(data.msg);
|
||||
}
|
||||
Spin.hide();
|
||||
return Promise.reject(res);
|
||||
}
|
||||
return data;
|
||||
},
|
||||
error => {
|
||||
Spin.hide();
|
||||
Message.error('服务内部错误');
|
||||
console.log('1111', error);
|
||||
// 对响应错误做点什么
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
export const postAxios = (url, data) => {
|
||||
return axios.post(url, data);
|
||||
};
|
||||
export const getAxios = (url, data) => {
|
||||
return axios.get(url, {
|
||||
params: data
|
||||
});
|
||||
};
|
||||
8
smart-admin-web/src/lib/local.js
Normal file
8
smart-admin-web/src/lib/local.js
Normal file
@@ -0,0 +1,8 @@
|
||||
export const localSave = (key, value) => {
|
||||
localStorage.setItem(key, value);
|
||||
};
|
||||
|
||||
export const localRead = key => {
|
||||
return localStorage.getItem(key) || '';
|
||||
};
|
||||
|
||||
306
smart-admin-web/src/lib/menu-func.js
Normal file
306
smart-admin-web/src/lib/menu-func.js
Normal file
@@ -0,0 +1,306 @@
|
||||
import { forEach, hasOneOf, objEqual } from '@/lib/util';
|
||||
import config from '@/config';
|
||||
import { localRead, localSave } from '@/lib/local';
|
||||
const { title, useI18n } = config;
|
||||
export const hasChild = item => {
|
||||
return item.children && item.children.length !== 0;
|
||||
};
|
||||
const showThisMenuEle = (item, access) => {
|
||||
if (item.meta && item.meta.access && item.meta.access.length) {
|
||||
if (hasOneOf(item.meta.access, access)) return true;
|
||||
else return false;
|
||||
} else return true;
|
||||
};
|
||||
/**
|
||||
* @param {Array} list 通过路由列表得到菜单列表
|
||||
* @returns {Array}
|
||||
*/
|
||||
export const getMenuByRouter = (list, access) => {
|
||||
let res = [];
|
||||
forEach(list, item => {
|
||||
if (!item.meta || (item.meta && !item.meta.hideInMenu)) {
|
||||
let obj = {
|
||||
icon: (item.meta && item.meta.icon) || '',
|
||||
name: item.name,
|
||||
meta: item.meta
|
||||
};
|
||||
if (
|
||||
(hasChild(item) || (item.meta && item.meta.showAlways)) &&
|
||||
showThisMenuEle(item, access)
|
||||
) {
|
||||
obj.children = getMenuByRouter(item.children, access);
|
||||
}
|
||||
if (item.meta && item.meta.href) obj.href = item.meta.href;
|
||||
if (showThisMenuEle(item, access)) res.push(obj);
|
||||
}
|
||||
});
|
||||
return res;
|
||||
};
|
||||
/**
|
||||
* 通过权限过滤菜单
|
||||
* @param {Object} map 权限对象
|
||||
* @param {Array} menuList 菜单列表
|
||||
* @returns {Array}
|
||||
*/
|
||||
export const getShowMenu = (map = {}, menuList, access = false) => {
|
||||
// 判断是否为超级管理员
|
||||
if (access) {
|
||||
return menuList;
|
||||
}
|
||||
// 返回的菜单列表
|
||||
let result = [];
|
||||
for (let menuItem of menuList) {
|
||||
let routerObj = JSON.parse(JSON.stringify(menuItem));
|
||||
if (
|
||||
map.hasOwnProperty(menuItem.name) &&
|
||||
(menuItem.name !== 'home' && menuItem.name !== '_home')
|
||||
) {
|
||||
// 判断该菜单权限下是否为数组,若为数组,则为功能点权限否则为子菜单
|
||||
if (getType(map[routerObj.name]) === 'array') {
|
||||
let funcPrivilege = localRead('funcPrivilegeInfo')
|
||||
? JSON.parse(localRead('funcPrivilegeInfo'))
|
||||
: {};
|
||||
localSave(
|
||||
'funcPrivilegeInfo',
|
||||
JSON.stringify({
|
||||
...funcPrivilege,
|
||||
[routerObj.name]: map[routerObj.name]
|
||||
})
|
||||
);
|
||||
} else if (
|
||||
getType(map[routerObj.name]) !== 'array' &&
|
||||
!routerObj.children
|
||||
) {
|
||||
// 判断是否为二级菜单,若是则需要多枚举一层赋值
|
||||
let funcPrivilege = localRead('funcPrivilegeInfo')
|
||||
? JSON.parse(localRead('funcPrivilegeInfo'))
|
||||
: {};
|
||||
localSave(
|
||||
'funcPrivilegeInfo',
|
||||
JSON.stringify({
|
||||
...funcPrivilege,
|
||||
[routerObj.name]: map[routerObj.name][routerObj.name]
|
||||
})
|
||||
);
|
||||
} else if (
|
||||
getType(map[routerObj.name]) !== 'array' &&
|
||||
routerObj.children
|
||||
) {
|
||||
// 循环子菜单权限
|
||||
routerObj.children = getShowMenu(
|
||||
map[routerObj.name],
|
||||
routerObj.children
|
||||
);
|
||||
}
|
||||
result.push(routerObj);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
// 获取数据类型
|
||||
export const getType = obj => {
|
||||
return {}.toString
|
||||
.call(obj)
|
||||
.match(/\s([a-zA-Z]+)/)[1]
|
||||
.toLowerCase();
|
||||
};
|
||||
|
||||
/**
|
||||
* @description 本地存储和获取标签导航列表
|
||||
*/
|
||||
export const setTagNavListInLocalStorage = list => {
|
||||
localStorage.tagNaveList = JSON.stringify(list);
|
||||
};
|
||||
/**
|
||||
* @returns {Array} 其中的每个元素只包含路由原信息中的name, path, meta三项
|
||||
*/
|
||||
export const getTagNavListFromLocalStorage = () => {
|
||||
const list = localStorage.tagNaveList;
|
||||
return list ? JSON.parse(list) : [];
|
||||
};
|
||||
export const getBreadCrumbList = (route, homeRoute) => {
|
||||
let homeItem = {
|
||||
...homeRoute,
|
||||
icon: homeRoute.meta.icon
|
||||
};
|
||||
let routeMatched = route.matched;
|
||||
if (routeMatched.some(item => item.name === homeRoute.name)) {
|
||||
return [homeItem];
|
||||
}
|
||||
let res = routeMatched
|
||||
.filter(item => {
|
||||
return item.meta === undefined || !item.meta.hideInBread;
|
||||
})
|
||||
.map(item => {
|
||||
let meta = {
|
||||
...item.meta
|
||||
};
|
||||
if (meta.title && typeof meta.title === 'function') {
|
||||
meta.__titleIsFunction__ = true;
|
||||
meta.title = meta.title(route);
|
||||
}
|
||||
let obj = {
|
||||
icon: (item.meta && item.meta.icon) || '',
|
||||
name: item.name,
|
||||
meta: meta
|
||||
};
|
||||
return obj;
|
||||
});
|
||||
res = res.filter(item => {
|
||||
return !item.meta.hideInMenu;
|
||||
});
|
||||
return [...res];
|
||||
};
|
||||
/**
|
||||
* @param {Array} routers 路由列表数组
|
||||
* @description 用于找到路由列表中name为home的对象
|
||||
*/
|
||||
export const getHomeRoute = (routers, homeName = 'Home') => {
|
||||
let i = -1;
|
||||
let len = routers.length;
|
||||
let homeRoute = {};
|
||||
while (++i < len) {
|
||||
let item = routers[i];
|
||||
if (item.children && item.children.length) {
|
||||
let res = getHomeRoute(item.children, homeName);
|
||||
if (res.name) return res;
|
||||
} else {
|
||||
if (item.name === homeName) homeRoute = item;
|
||||
}
|
||||
}
|
||||
return homeRoute;
|
||||
};
|
||||
/**
|
||||
* @param {Array} list 标签列表
|
||||
* @param {String} name 当前关闭的标签的name
|
||||
*/
|
||||
export const getNextRoute = (list, route) => {
|
||||
let res = {};
|
||||
if (list.length === 2) {
|
||||
res = getHomeRoute(list);
|
||||
} else {
|
||||
const index = list.findIndex(item => routeEqual(item, route));
|
||||
if (index === list.length - 1) res = list[list.length - 2];
|
||||
else res = list[index + 1];
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
/**
|
||||
* 判断打开的标签列表里是否已存在这个新添加的路由对象
|
||||
*/
|
||||
export const routeHasExist = (tagNavList, routeItem) => {
|
||||
let len = tagNavList.length;
|
||||
let res = false;
|
||||
doCustomTimes(len, index => {
|
||||
if (routeEqual(tagNavList[index], routeItem)) res = true;
|
||||
});
|
||||
return res;
|
||||
};
|
||||
/**
|
||||
* @param {*} list 现有标签导航列表
|
||||
* @param {*} newRoute 新添加的路由原信息对象
|
||||
* @description 如果该newRoute已经存在则不再添加
|
||||
*/
|
||||
export const getNewTagList = (list, newRoute) => {
|
||||
const { name, path, meta, query } = newRoute;
|
||||
let newList = [...list];
|
||||
let index = newList.findIndex(item => item.name === name);
|
||||
if (index >= 0) {
|
||||
newList[index] = { name, path, meta, query };
|
||||
} else newList.push({ name, path, meta, query });
|
||||
return newList;
|
||||
};
|
||||
export const routeEqual = (route1, route2) => {
|
||||
return route1.name === route2.name;
|
||||
};
|
||||
export const getRouteTitleHandled = route => {
|
||||
let router = {
|
||||
...route
|
||||
};
|
||||
let meta = {
|
||||
...route.meta
|
||||
};
|
||||
let title = '';
|
||||
if (meta.title) {
|
||||
if (typeof meta.title === 'function') {
|
||||
meta.__titleIsFunction__ = true;
|
||||
title = meta.title(router);
|
||||
} else title = meta.title;
|
||||
}
|
||||
meta.title = title;
|
||||
router.meta = meta;
|
||||
return router;
|
||||
};
|
||||
/**
|
||||
* @param {Number} times 回调函数需要执行的次数
|
||||
* @param {Function} callback 回调函数
|
||||
*/
|
||||
export const doCustomTimes = (times, callback) => {
|
||||
let i = -1;
|
||||
while (++i < times) {
|
||||
callback(i);
|
||||
}
|
||||
};
|
||||
export const showTitle = (item, vm) => {
|
||||
let { title, __titleIsFunction__ } = item.meta;
|
||||
if (!title) return;
|
||||
if (useI18n) {
|
||||
if (title.includes('{{') && title.includes('}}') && useI18n) {
|
||||
title = title.replace(/({{[\s\S]+?}})/, (m, str) =>
|
||||
str.replace(/{{([\s\S]*)}}/, (m, _) => vm.$t(_.trim()))
|
||||
);
|
||||
} else if (__titleIsFunction__) title = item.meta.title;
|
||||
else title = vm.$t(item.name);
|
||||
} else title = (item.meta && item.meta.title) || item.name;
|
||||
return title;
|
||||
};
|
||||
/**
|
||||
* @description 根据当前跳转的路由设置显示在浏览器标签的title
|
||||
* @param {Object} routeItem 路由对象
|
||||
* @param {Object} vm Vue实例
|
||||
*/
|
||||
export const setTitle = (routeItem, vm) => {
|
||||
const handledRoute = getRouteTitleHandled(routeItem);
|
||||
const pageTitle = showTitle(handledRoute, vm);
|
||||
const resTitle = pageTitle ? `${pageTitle} - ${title}` : title;
|
||||
window.document.title = resTitle;
|
||||
};
|
||||
|
||||
export const findNodeUpper = (ele, tag) => {
|
||||
if (ele.parentNode) {
|
||||
if (ele.parentNode.tagName === tag.toUpperCase()) {
|
||||
return ele.parentNode;
|
||||
} else {
|
||||
return findNodeUpper(ele.parentNode, tag);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const findNodeUpperByClasses = (ele, classes) => {
|
||||
let parentNode = ele.parentNode;
|
||||
if (parentNode) {
|
||||
let classList = parentNode.classList;
|
||||
if (
|
||||
classList &&
|
||||
classes.every(className => classList.contains(className))
|
||||
) {
|
||||
return parentNode;
|
||||
} else {
|
||||
return findNodeUpperByClasses(parentNode, classes);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const findNodeDownward = (ele, tag) => {
|
||||
const tagName = tag.toUpperCase();
|
||||
if (ele.childNodes.length) {
|
||||
let i = -1;
|
||||
let len = ele.childNodes.length;
|
||||
while (++i < len) {
|
||||
let child = ele.childNodes[i];
|
||||
if (child.tagName === tagName) return child;
|
||||
else return findNodeDownward(child, tag);
|
||||
}
|
||||
}
|
||||
};
|
||||
133
smart-admin-web/src/lib/printPlugs.js
Normal file
133
smart-admin-web/src/lib/printPlugs.js
Normal file
@@ -0,0 +1,133 @@
|
||||
// 打印类属性、方法定义
|
||||
/* eslint-disable */
|
||||
//第二个参数表明是否要关闭当前窗口
|
||||
const Print = function(dom, close, options) {
|
||||
if (!(this instanceof Print)) return new Print(dom, close, options);
|
||||
|
||||
this.options = this.extend(
|
||||
{
|
||||
noPrint: '.no-print'
|
||||
},
|
||||
options
|
||||
);
|
||||
|
||||
if (typeof dom === 'string') {
|
||||
this.dom = document.querySelector(dom);
|
||||
} else {
|
||||
this.dom = dom;
|
||||
}
|
||||
|
||||
this.init(close);
|
||||
};
|
||||
Print.prototype = {
|
||||
init: function(close) {
|
||||
var content = this.getStyle() + this.getHtml();
|
||||
this.writeIframe(content, close);
|
||||
},
|
||||
extend: function(obj, obj2) {
|
||||
for (var k in obj2) {
|
||||
obj[k] = obj2[k];
|
||||
}
|
||||
return obj;
|
||||
},
|
||||
|
||||
getStyle: function() {
|
||||
var str = '',
|
||||
styles = document.querySelectorAll('style,link');
|
||||
for (var i = 0; i < styles.length; i++) {
|
||||
str += styles[i].outerHTML;
|
||||
}
|
||||
str +=
|
||||
'<style>body, html{height: auto; overflow: auto !important;}' +
|
||||
(this.options.noPrint ? this.options.noPrint : '.no-print') +
|
||||
'{display:none;}</style>';
|
||||
|
||||
return str;
|
||||
},
|
||||
|
||||
getHtml: function() {
|
||||
var inputs = document.querySelectorAll('input');
|
||||
var textareas = document.querySelectorAll('textarea');
|
||||
var selects = document.querySelectorAll('select');
|
||||
|
||||
for (var k in inputs) {
|
||||
if (inputs[k].type == 'checkbox' || inputs[k].type == 'radio') {
|
||||
if (inputs[k].checked == true) {
|
||||
inputs[k].setAttribute('checked', 'checked');
|
||||
} else {
|
||||
inputs[k].removeAttribute('checked');
|
||||
}
|
||||
} else if (inputs[k].type == 'text') {
|
||||
inputs[k].setAttribute('value', inputs[k].value);
|
||||
}
|
||||
}
|
||||
|
||||
for (var k2 in textareas) {
|
||||
if (textareas[k2].type == 'textarea') {
|
||||
textareas[k2].innerHTML = textareas[k2].value;
|
||||
}
|
||||
}
|
||||
|
||||
for (var k3 in selects) {
|
||||
if (selects[k3].type == 'select-one') {
|
||||
var child = selects[k3].children;
|
||||
for (var i in child) {
|
||||
if (child[i].tagName == 'OPTION') {
|
||||
if (child[i].selected == true) {
|
||||
child[i].setAttribute('selected', 'selected');
|
||||
} else {
|
||||
child[i].removeAttribute('selected');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.dom.outerHTML;
|
||||
},
|
||||
|
||||
writeIframe: function(content, close) {
|
||||
var w,
|
||||
doc,
|
||||
iframe = document.createElement('iframe'),
|
||||
f = document.body.appendChild(iframe);
|
||||
iframe.id = 'myIframe';
|
||||
iframe.style = 'position:absolute;';
|
||||
|
||||
w = f.contentWindow || f.contentDocument;
|
||||
doc = f.contentDocument || f.contentWindow.document;
|
||||
doc.open();
|
||||
doc.write(content);
|
||||
doc.close();
|
||||
this.toPrint(w, close);
|
||||
setTimeout(function() {
|
||||
document.body.removeChild(iframe);
|
||||
}, 500);
|
||||
},
|
||||
|
||||
toPrint: function(frameWindow, close) {
|
||||
try {
|
||||
setTimeout(function() {
|
||||
frameWindow.focus();
|
||||
try {
|
||||
if (!frameWindow.document.execCommand('print', false, null)) {
|
||||
frameWindow.print();
|
||||
}
|
||||
} catch (e) {
|
||||
frameWindow.print();
|
||||
}
|
||||
frameWindow.close();
|
||||
if (close) {
|
||||
window.close();
|
||||
}
|
||||
}, 500);
|
||||
} catch (err) {
|
||||
console.log('err', err);
|
||||
}
|
||||
}
|
||||
};
|
||||
const MyPlugin = {};
|
||||
MyPlugin.install = function(Vue, options) {
|
||||
// 4. 添加实例方法
|
||||
Vue.prototype.$print = Print;
|
||||
};
|
||||
export default MyPlugin;
|
||||
10
smart-admin-web/src/lib/render-dom.js
Normal file
10
smart-admin-web/src/lib/render-dom.js
Normal file
@@ -0,0 +1,10 @@
|
||||
export default {
|
||||
name: 'RenderDom',
|
||||
functional: true,
|
||||
props: {
|
||||
render: Function
|
||||
},
|
||||
render: (h, ctx) => {
|
||||
return ctx.props.render(h);
|
||||
}
|
||||
};
|
||||
84
smart-admin-web/src/lib/table-action.js
Normal file
84
smart-admin-web/src/lib/table-action.js
Normal file
@@ -0,0 +1,84 @@
|
||||
// 处理table操作按钮
|
||||
const tableAction = (h, array) => {
|
||||
let btnArray = [];
|
||||
let btnMore = [];
|
||||
array.map((item, index) => {
|
||||
if (index < 2) {
|
||||
let btn = h(
|
||||
'a',
|
||||
{
|
||||
props: {
|
||||
type: !index ? 'primary' : 'info',
|
||||
size: 'small',
|
||||
to: item.to ? item.to : '',
|
||||
target: item.target ? item.target : '_self',
|
||||
ghost: true
|
||||
},
|
||||
style: {
|
||||
marginLeft: '5px'
|
||||
},
|
||||
directives: item.directives,
|
||||
on: {
|
||||
click: item.action
|
||||
}
|
||||
},
|
||||
item.title
|
||||
);
|
||||
btnArray.push(btn);
|
||||
} else {
|
||||
btnMore.push(
|
||||
h(
|
||||
'DropdownItem',
|
||||
{
|
||||
nativeOn: {
|
||||
click: item.action
|
||||
}
|
||||
},
|
||||
item.title
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
let dropdown = h(
|
||||
'Dropdown',
|
||||
{
|
||||
props: {
|
||||
transfer: true
|
||||
}
|
||||
},
|
||||
[
|
||||
h(
|
||||
'a',
|
||||
{
|
||||
props: {
|
||||
type: 'default',
|
||||
size: 'small'
|
||||
},
|
||||
style: {
|
||||
marginLeft: '5px'
|
||||
}
|
||||
},
|
||||
[
|
||||
h('span', '更多'),
|
||||
h('Icon', {
|
||||
props: {
|
||||
type: 'ios-arrow-down'
|
||||
}
|
||||
})
|
||||
]
|
||||
),
|
||||
h(
|
||||
'DropdownMenu',
|
||||
{
|
||||
slot: 'list'
|
||||
},
|
||||
btnMore
|
||||
)
|
||||
]
|
||||
);
|
||||
if (array.length > 2) {
|
||||
btnArray.push(dropdown);
|
||||
}
|
||||
return btnArray;
|
||||
};
|
||||
export default tableAction;
|
||||
499
smart-admin-web/src/lib/util.js
Normal file
499
smart-admin-web/src/lib/util.js
Normal file
@@ -0,0 +1,499 @@
|
||||
/**
|
||||
* @param {String} url
|
||||
* @description 从URL中解析参数
|
||||
*/
|
||||
export const getParams = url => {
|
||||
const keyValueArr = url.split('?')[1].split('&');
|
||||
let paramObj = {};
|
||||
keyValueArr.forEach(item => {
|
||||
const keyValue = item.split('=');
|
||||
paramObj[keyValue[0]] = keyValue[1];
|
||||
});
|
||||
return paramObj;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Any} obj
|
||||
* @description 获取数据类型
|
||||
*/
|
||||
export const getType = obj => {
|
||||
return {}.toString
|
||||
.call(obj)
|
||||
.match(/\s([a-zA-Z]+)/)[1]
|
||||
.toLowerCase();
|
||||
};
|
||||
// 日期格式
|
||||
export const dateFormat = {
|
||||
YMD: 'YMD',
|
||||
YMDHM: 'YMDHM',
|
||||
YMDHMS: 'YMDHMS'
|
||||
};
|
||||
export const forEach = (arr, fn) => {
|
||||
if (!arr.length || !fn) return;
|
||||
let i = -1;
|
||||
let len = arr.length;
|
||||
while (++i < len) {
|
||||
let item = arr[i];
|
||||
fn(item, i, arr);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Array} arr1
|
||||
* @param {Array} arr2
|
||||
* @description 得到两个数组的交集, 两个数组的元素为数值或字符串
|
||||
*/
|
||||
export const getIntersection = (arr1, arr2) => {
|
||||
let len = Math.min(arr1.length, arr2.length);
|
||||
let i = -1;
|
||||
let res = [];
|
||||
while (++i < len) {
|
||||
const item = arr2[i];
|
||||
if (arr1.indexOf(item) > -1) res.push(item);
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Array} arr1
|
||||
* @param {Array} arr2
|
||||
* @description 得到两个数组的并集, 两个数组的元素为数值或字符串
|
||||
*/
|
||||
export const getUnion = (arr1, arr2) => {
|
||||
return Array.from(new Set([...arr1, ...arr2]));
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Array} target 目标数组
|
||||
* @param {Array} arr 需要查询的数组
|
||||
* @description 判断要查询的数组是否至少有一个元素包含在目标数组中
|
||||
*/
|
||||
export const hasOneOf = (targetarr, arr) => {
|
||||
return targetarr.some(_ => arr.indexOf(_) > -1);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {String|Number} value 要验证的字符串或数值
|
||||
* @param {*} validList 用来验证的列表
|
||||
*/
|
||||
export function oneOf (value, validList) {
|
||||
for (let i = 0; i < validList.length; i++) {
|
||||
if (value === validList[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} timeStamp 判断时间戳格式是否是毫秒
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
const isMillisecond = timeStamp => {
|
||||
const timeStr = String(timeStamp);
|
||||
return timeStr.length > 10;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Number} timeStamp 传入的时间戳
|
||||
* @param {Number} currentTime 当前时间时间戳
|
||||
* @returns {Boolean} 传入的时间戳是否早于当前时间戳
|
||||
*/
|
||||
const isEarly = (timeStamp, currentTime) => {
|
||||
return timeStamp < currentTime;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Number} num 数值
|
||||
* @returns {String} 处理后的字符串
|
||||
* @description 如果传入的数值小于10,即位数只有1位,则在前面补充0
|
||||
*/
|
||||
const getHandledValue = num => {
|
||||
return num < 10 ? '0' + num : num;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Number} timeStamp 传入的时间戳
|
||||
* @param {Number} startType 要返回的时间字符串的格式类型,传入'year'则返回年开头的完整时间
|
||||
*/
|
||||
const getDate = (timeStamp, startType) => {
|
||||
const d = new Date(timeStamp * 1000);
|
||||
const year = d.getFullYear();
|
||||
const month = getHandledValue(d.getMonth() + 1);
|
||||
const date = getHandledValue(d.getDate());
|
||||
const hours = getHandledValue(d.getHours());
|
||||
const minutes = getHandledValue(d.getMinutes());
|
||||
const second = getHandledValue(d.getSeconds());
|
||||
let resStr = '';
|
||||
if (startType === 'year')
|
||||
{resStr =
|
||||
year +
|
||||
'-' +
|
||||
month +
|
||||
'-' +
|
||||
date +
|
||||
' ' +
|
||||
hours +
|
||||
':' +
|
||||
minutes +
|
||||
':' +
|
||||
second;}
|
||||
else resStr = month + '-' + date + ' ' + hours + ':' + minutes;
|
||||
return resStr;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {String|Number} timeStamp 时间戳
|
||||
* @returns {String} 相对时间字符串
|
||||
*/
|
||||
export const getRelativeTime = timeStamp => {
|
||||
// 判断当前传入的时间戳是秒格式还是毫秒
|
||||
const IS_MILLISECOND = isMillisecond(timeStamp);
|
||||
// 如果是毫秒格式则转为秒格式
|
||||
if (IS_MILLISECOND) Math.floor((timeStamp /= 1000));
|
||||
// 传入的时间戳可以是数值或字符串类型,这里统一转为数值类型
|
||||
timeStamp = Number(timeStamp);
|
||||
// 获取当前时间时间戳
|
||||
const currentTime = Math.floor(Date.parse(new Date()) / 1000);
|
||||
// 判断传入时间戳是否早于当前时间戳
|
||||
const IS_EARLY = isEarly(timeStamp, currentTime);
|
||||
// 获取两个时间戳差值
|
||||
let diff = currentTime - timeStamp;
|
||||
// 如果IS_EARLY为false则差值取反
|
||||
if (!IS_EARLY) diff = -diff;
|
||||
let resStr = '';
|
||||
const dirStr = IS_EARLY ? '前' : '后';
|
||||
// 少于等于59秒
|
||||
if (diff <= 59) resStr = diff + '秒' + dirStr;
|
||||
// 多于59秒,少于等于59分钟59秒
|
||||
else if (diff > 59 && diff <= 3599)
|
||||
{resStr = Math.floor(diff / 60) + '分钟' + dirStr;}
|
||||
// 多于59分钟59秒,少于等于23小时59分钟59秒
|
||||
else if (diff > 3599 && diff <= 86399)
|
||||
{resStr = Math.floor(diff / 3600) + '小时' + dirStr;}
|
||||
// 多于23小时59分钟59秒,少于等于29天59分钟59秒
|
||||
else if (diff > 86399 && diff <= 2623859)
|
||||
{resStr = Math.floor(diff / 86400) + '天' + dirStr;}
|
||||
// 多于29天59分钟59秒,少于364天23小时59分钟59秒,且传入的时间戳早于当前
|
||||
else if (diff > 2623859 && diff <= 31567859 && IS_EARLY)
|
||||
{resStr = getDate(timeStamp);}
|
||||
else resStr = getDate(timeStamp, 'year');
|
||||
return resStr;
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {String} 当前浏览器名称
|
||||
*/
|
||||
export const getExplorer = () => {
|
||||
const ua = window.navigator.userAgent;
|
||||
const isExplorer = exp => {
|
||||
return ua.indexOf(exp) > -1;
|
||||
};
|
||||
if (isExplorer('MSIE')) return 'IE';
|
||||
else if (isExplorer('Firefox')) return 'Firefox';
|
||||
else if (isExplorer('Chrome')) return 'Chrome';
|
||||
else if (isExplorer('Opera')) return 'Opera';
|
||||
else if (isExplorer('Safari')) return 'Safari';
|
||||
};
|
||||
|
||||
/**
|
||||
* @description 绑定事件 on(element, event, handler)
|
||||
*/
|
||||
export const on = (function () {
|
||||
if (document.addEventListener) {
|
||||
return function (element, event, handler) {
|
||||
if (element && event && handler) {
|
||||
element.addEventListener(event, handler, false);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return function (element, event, handler) {
|
||||
if (element && event && handler) {
|
||||
element.attachEvent('on' + event, handler);
|
||||
}
|
||||
};
|
||||
}
|
||||
})();
|
||||
|
||||
/**
|
||||
* @description 解绑事件 off(element, event, handler)
|
||||
*/
|
||||
export const off = (function () {
|
||||
if (document.removeEventListener) {
|
||||
return function (element, event, handler) {
|
||||
if (element && event) {
|
||||
element.removeEventListener(event, handler, false);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return function (element, event, handler) {
|
||||
if (element && event) {
|
||||
element.detachEvent('on' + event, handler);
|
||||
}
|
||||
};
|
||||
}
|
||||
})();
|
||||
|
||||
/**
|
||||
* 判断一个对象是否存在key,如果传入第二个参数key,则是判断这个obj对象是否存在key这个属性
|
||||
* 如果没有传入key这个参数,则判断obj对象是否有键值对
|
||||
*/
|
||||
export const hasKey = (obj, key) => {
|
||||
if (key) return key in obj;
|
||||
else {
|
||||
let keysArr = Object.keys(obj);
|
||||
return keysArr.length;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {*} obj1 对象
|
||||
* @param {*} obj2 对象
|
||||
* @description 判断两个对象是否相等,这两个对象的值只能是数字或字符串
|
||||
*/
|
||||
export const objEqual = (obj1, obj2) => {
|
||||
const keysArr1 = Object.keys(obj1);
|
||||
const keysArr2 = Object.keys(obj2);
|
||||
if (keysArr1.length !== keysArr2.length) return false;
|
||||
else if (keysArr1.length === 0 && keysArr2.length === 0) return true;
|
||||
/* eslint-disable-next-line */ else
|
||||
{return !keysArr1.some(key => obj1[key] != obj2[key]);}
|
||||
};
|
||||
|
||||
// 相关工具类
|
||||
export const utils = {
|
||||
/**
|
||||
* @description table实现反选
|
||||
* @param {Object} vm Vue实例
|
||||
* @param {Array} tableSelectDate 选中的数据
|
||||
* @param {Array} allData 所有数据
|
||||
* @param {Array} key 数据中的唯一值
|
||||
*/
|
||||
reverseSelect (vm, tableSelectDate, allData, key) {
|
||||
let copyMess = JSON.parse(JSON.stringify(tableSelectDate));
|
||||
// 流程:先全部选中->再部分选中
|
||||
vm.handleSelectAll(false);
|
||||
// 选中的idList
|
||||
let idList = copyMess.map(item => item[key]);
|
||||
console.log(idList);
|
||||
for (let item of allData) {
|
||||
if (idList.every(id => id !== item.id)) {
|
||||
vm.$set(item, '_checked', true);
|
||||
tableSelectDate.push(item);
|
||||
} else {
|
||||
vm.$set(item, '_checked', false);
|
||||
}
|
||||
}
|
||||
},
|
||||
// 校验字符串是否相同 合同使用
|
||||
contrastString (originStr, changeStr) {
|
||||
let origin = originStr
|
||||
.replace(/\s*/g, '')
|
||||
.replace(/"/g, '\'')
|
||||
.replace(/ /g, '')
|
||||
.replace(/disabled=\/'\/'/g, 'disabled');
|
||||
let change = changeStr
|
||||
.replace(/\s*/g, '')
|
||||
.replace(/"/g, '\'')
|
||||
.replace(/ /g, '')
|
||||
.replace(/disabled=\/'\/'/g, 'disabled');
|
||||
return origin === change;
|
||||
},
|
||||
// 获取当前日期getDateStr(0)、前几天getDateStr(-10)、后几天getDateStr(20)
|
||||
getDateStr (AddDayCount, format) {
|
||||
let date = new Date();
|
||||
// 获取AddDayCount天后的日期
|
||||
date.setDate(date.getDate() + AddDayCount);
|
||||
return this.getDate(date, format);
|
||||
},
|
||||
getDate (date, format) {
|
||||
let year = date.getFullYear();
|
||||
// day获取当前几号,不足10补0
|
||||
let day = date.getDate() > 9 ? date.getDate() : '0' + date.getDate();
|
||||
// month获取当前月份的日期,不足10补0
|
||||
let month =
|
||||
date.getMonth() + 1 > 9
|
||||
? date.getMonth() + 1
|
||||
: '0' + (date.getMonth() + 1);
|
||||
// h获取当前小时,不足10补0
|
||||
let h = date.getHours() > 9 ? date.getHours() : '0' + date.getHours();
|
||||
// s获取当前分钟,不足10补0
|
||||
let m = date.getMinutes() > 9 ? date.getMinutes() : '0' + date.getMinutes();
|
||||
// s获取当前秒数,不足10补0
|
||||
let s = date.getSeconds() > 9 ? date.getSeconds() : '0' + date.getSeconds();
|
||||
let resultDate = '';
|
||||
if (format === dateFormat.YMD) {
|
||||
resultDate = year + '-' + month + '-' + day;
|
||||
}
|
||||
if (format === dateFormat.YMDHM) {
|
||||
resultDate = year + '-' + month + '-' + day + ' ' + h + ':' + m;
|
||||
}
|
||||
if (format === dateFormat.YMDHMS) {
|
||||
resultDate = year + '-' + month + '-' + day + ' ' + h + ':' + m + ':' + s;
|
||||
}
|
||||
return resultDate;
|
||||
},
|
||||
// 获取周一和周日日期,返回两种格式时间
|
||||
getDateWeek () {
|
||||
let now = new Date();
|
||||
let nowTime = now.getTime();
|
||||
let day = now.getDay();
|
||||
let oneDayLong = 1000 * 60 * 60 * 24;
|
||||
let MondayTime = nowTime - (day - 1) * oneDayLong;
|
||||
let SundayTime = nowTime + (7 - day) * oneDayLong;
|
||||
let monday = new Date(MondayTime);
|
||||
let sunday = new Date(SundayTime);
|
||||
return {
|
||||
// first: this.getDateAll(monday),
|
||||
// last: this.getDateAll(sunday),
|
||||
firstDate: monday,
|
||||
lastDate: sunday
|
||||
};
|
||||
},
|
||||
// 获取月初与月末日期,返回两种时间格式
|
||||
getDateMonth () {
|
||||
let dateFirter = new Date();
|
||||
let dateLast = new Date();
|
||||
dateFirter.setDate(1);
|
||||
|
||||
let currentMonth = dateLast.getMonth();
|
||||
let nextMonth = ++currentMonth;
|
||||
let nextMonthFirstDay = new Date(dateLast.getFullYear(), nextMonth, 1);
|
||||
let oneDay = 1000 * 60 * 60 * 24;
|
||||
dateLast = new Date(nextMonthFirstDay - oneDay);
|
||||
|
||||
return {
|
||||
// first: this.getDateAll(dateFirter),
|
||||
// last: this.getDateAll(dateLast),
|
||||
firstDate: dateFirter,
|
||||
lastDate: dateLast
|
||||
};
|
||||
},
|
||||
// 计算天数
|
||||
getDayBetweenDate (date) {
|
||||
date = this.getDate(new Date(date), 'YMD');
|
||||
let startTime = Date.parse(new Date(date)); // IE支持“yyyy/MM/dd”格式
|
||||
let endTime = Date.parse(this.getDate(new Date(), 'YMD'));
|
||||
let day = parseInt((endTime - startTime) / (1000 * 60 * 60 * 24));
|
||||
return day;
|
||||
},
|
||||
getDateIntervalYear (firstDate, secondDate) {
|
||||
if (!firstDate || !secondDate) {
|
||||
return 0;
|
||||
}
|
||||
let first = new Date(firstDate);
|
||||
let second = new Date(secondDate);
|
||||
let firstYear = first.getFullYear();
|
||||
let secondYear = second.getFullYear();
|
||||
let intervalYear = secondYear - firstYear;
|
||||
return intervalYear < 0 ? 0 : intervalYear;
|
||||
},
|
||||
getDateIntervalYearFixed2 (firstDate, secondDate) {
|
||||
if (!firstDate || !secondDate) {
|
||||
return 0;
|
||||
}
|
||||
// 格式化时间
|
||||
let startDate = new Date(this.getDate(new Date(firstDate), 'YMD'));
|
||||
let endDate = new Date(this.getDate(new Date(secondDate), 'YMD'));
|
||||
// 得到毫秒值
|
||||
let startTime = Date.parse(startDate);
|
||||
let endTime = Date.parse(endDate);
|
||||
// 得到差了多少天
|
||||
let day = parseInt((endTime - startTime) / (1000 * 60 * 60 * 24));
|
||||
if (day <= 0) {
|
||||
return 0;
|
||||
}
|
||||
// 得到差的多少年 保留两位小数
|
||||
let resultYear = parseFloat((day / (30 * 12)).toFixed(2));
|
||||
return resultYear;
|
||||
},
|
||||
// 数字转化为中文大写
|
||||
// 代码如下所示:
|
||||
convertCurrency (money) {
|
||||
// 汉字的数字
|
||||
let cnNums = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
|
||||
// 基本单位
|
||||
let cnIntRadice = ['', '拾', '佰', '仟'];
|
||||
// 对应整数部分扩展单位
|
||||
let cnIntUnits = ['', '万', '亿', '兆'];
|
||||
// 对应小数部分单位
|
||||
let cnDecUnits = ['角', '分', '毫', '厘'];
|
||||
// 整数金额时后面跟的字符
|
||||
let cnInteger = '整';
|
||||
// 整型完以后的单位
|
||||
let cnIntLast = '元';
|
||||
// 最大处理的数字
|
||||
let maxNum = 999999999999999.9999;
|
||||
// 金额整数部分
|
||||
let integerNum;
|
||||
// 金额小数部分
|
||||
let decimalNum;
|
||||
// 输出的中文金额字符串
|
||||
let chineseStr = '';
|
||||
// 分离金额后用的数组,预定义
|
||||
let parts;
|
||||
if (money === '') {
|
||||
return '';
|
||||
}
|
||||
money = parseFloat(money);
|
||||
if (money >= maxNum) {
|
||||
// 超出最大处理数字
|
||||
return '';
|
||||
}
|
||||
if (money === 0) {
|
||||
chineseStr = cnNums[0] + cnIntLast + cnInteger;
|
||||
return chineseStr;
|
||||
}
|
||||
// 转换为字符串
|
||||
money = money.toString();
|
||||
if (money.indexOf('.') === -1) {
|
||||
integerNum = money;
|
||||
decimalNum = '';
|
||||
} else {
|
||||
parts = money.split('.');
|
||||
integerNum = parts[0];
|
||||
decimalNum = parts[1].substr(0, 4);
|
||||
}
|
||||
// 获取整型部分转换
|
||||
if (parseInt(integerNum, 10) > 0) {
|
||||
let zeroCount = 0;
|
||||
let IntLen = integerNum.length;
|
||||
for (let i = 0; i < IntLen; i++) {
|
||||
let n = integerNum.substr(i, 1);
|
||||
let p = IntLen - i - 1;
|
||||
let q = p / 4;
|
||||
let m = p % 4;
|
||||
if (n === '0') {
|
||||
zeroCount++;
|
||||
} else {
|
||||
if (zeroCount > 0) {
|
||||
chineseStr += cnNums[0];
|
||||
}
|
||||
// 归零
|
||||
zeroCount = 0;
|
||||
chineseStr += cnNums[parseInt(n)] + cnIntRadice[m];
|
||||
}
|
||||
if (m === 0 && zeroCount < 4) {
|
||||
chineseStr += cnIntUnits[q];
|
||||
}
|
||||
}
|
||||
chineseStr += cnIntLast;
|
||||
}
|
||||
// 小数部分
|
||||
if (decimalNum !== '') {
|
||||
let decLen = decimalNum.length;
|
||||
for (let i = 0; i < decLen; i++) {
|
||||
let n = decimalNum.substr(i, 1);
|
||||
if (n !== '0') {
|
||||
chineseStr += cnNums[Number(n)] + cnDecUnits[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chineseStr === '') {
|
||||
chineseStr += cnNums[0] + cnIntLast + cnInteger;
|
||||
} else if (decimalNum === '') {
|
||||
chineseStr += cnInteger;
|
||||
}
|
||||
return chineseStr;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user