Commit 96738d8f authored by lipengcheng 's avatar lipengcheng

引入uitls

parent 0be858bb
...@@ -23,6 +23,9 @@ module.exports = { ...@@ -23,6 +23,9 @@ module.exports = {
* "warn" 或 1 - 开启规则,使用警告级别的错误:warn (不会导致程序退出) * "warn" 或 1 - 开启规则,使用警告级别的错误:warn (不会导致程序退出)
* "error" 或 2 - 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出) * "error" 或 2 - 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)
*/ */
globals: {
window: true
},
rules: { rules: {
// 会报各种奇怪的错误 如:error: Delete ⏎ (prettier/prettier) at src/pages/xxx 等; // 会报各种奇怪的错误 如:error: Delete ⏎ (prettier/prettier) at src/pages/xxx 等;
// 这是因为prettier配置和编辑器prettier配置冲突导致的 在下面配置覆盖掉就可以了 // 这是因为prettier配置和编辑器prettier配置冲突导致的 在下面配置覆盖掉就可以了
...@@ -80,6 +83,8 @@ module.exports = { ...@@ -80,6 +83,8 @@ module.exports = {
singleline: 'never', singleline: 'never',
multiline: 'never' multiline: 'never'
} }
] ],
// 去掉空白报错
'no-irregular-whitespace': 'off'
} }
} }
...@@ -12,6 +12,7 @@ import layoutComponents from '@/components/layout/index.js' ...@@ -12,6 +12,7 @@ import layoutComponents from '@/components/layout/index.js'
import globalComponents from '@/components/global/index.js' import globalComponents from '@/components/global/index.js'
import filters from '@/filters/index.js' import filters from '@/filters/index.js'
import directives from '@/directives/index.js' import directives from '@/directives/index.js'
import utils from '@/utils/index.js'
// 全局注册layout组件 // 全局注册layout组件
Vue.use(layoutComponents) Vue.use(layoutComponents)
// 注册自定义全局组件 // 注册自定义全局组件
...@@ -29,6 +30,7 @@ console.log('baseURL:', baseURL) ...@@ -29,6 +30,7 @@ console.log('baseURL:', baseURL)
Vue.config.productionTip = false Vue.config.productionTip = false
Vue.prototype.$http = axios Vue.prototype.$http = axios
Vue.prototype.$mt = moment Vue.prototype.$mt = moment
Vue.prototype.$ = utils
new Vue({ new Vue({
router, router,
......
/** ===========
* 全局自定义工具方法
* ============
*/
import axios from 'axios'
const util = {
/**
* 处理所有非本地的资源链接,返回为七牛云地址
* @param {String} url 资源链接
*/
handleAssetsUrl(url) {
if (!url) return
const httpReg = /^http/
const reg = /^\//
const qiniuAssetsUrl = 'https://resources.laihua.com'
if (httpReg.test(url) || url.indexOf('base64') != -1) {
// 兼容第三方登录的头像地址为http的情况,替换为https
return url.replace(/http:/, 'https:')
}
if (!reg.test(url)) {
return qiniuAssetsUrl + '/' + url
} else {
return qiniuAssetsUrl + url
}
},
/**
* 去掉首尾空格及回车产生的\r
* @param {String} str 字符串
*/
delSpacesOfStr(str) {
if (/^( |[\s ])+|( |[\s ])+$/g.test(str)) {
str = str.replace(/^( |[\s ])+|( |[\s ])+$/g, '')
}
return str
},
/**
* 判断客户端,移动端返回1,pc端返回0
*/
judgeAgent() {
if (navigator) {
let uaInfo = navigator.userAgent
let agents = ['Android', 'iPhone', 'SymbianOS', 'iPod', 'micromessenger']
agents.forEach((i) => {
if (uaInfo.indexOf(i) !== -1) {
//移动端
return 1
} else {
return 0
}
})
} else {
console.log('非浏览器环境')
}
},
/**
* 获取文档滚动条宽度
*/
getScrollBarWidth() {
var odiv = document.createElement('div'), //创建一个div
styles = {
width: '100px',
height: '100px',
overflowY: 'scroll' //让他有滚动条
},
i,
scrollbarWidth
for (i in styles) odiv.style[i] = styles[i]
document.body.appendChild(odiv) //把div添加到body中
scrollbarWidth = odiv.offsetWidth - odiv.clientWidth //相减
odiv.remove() //移除创建的div
return scrollbarWidth //返回滚动条宽度
},
/**
*
* @param {String} val show显示html滚动条,hide隐藏html滚动条
*/
toggleHtmlScroll(val) {
let ww = window.outerWidth
let hw = document.documentElement.clientWidth || document.body.clientWidth
if (val == 'hide') {
document.querySelector('html').style.paddingRight = `${ww - hw}px`
document.querySelector('html').style.overflowY = 'hidden'
} else if (val == 'show') {
document.querySelector('html').style.paddingRight = '0px'
document.querySelector('html').style.overflowY = 'scroll'
}
},
/**
* 生成uuid
*/
generateUuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = (Math.random() * 16) | 0,
v = c == 'x' ? r : (r & 0x3) | 0x8
return v.toString(16)
})
},
/**
* 判断是否为json格式的字符串
*/
isJsonString(str) {
try {
let obj = JSON.parse(str)
if (typeof obj === 'object' && obj) {
return true
}
} catch (e) {
return false
}
},
/**
* 秒转化为分钟格式
*/
secToMin(secs) {
return [
// parseInt(secs / 60 / 60),
parseInt((secs / 60) % 60),
parseInt(secs % 60)
]
.join(':')
.replace(/\b(\d)\b/g, '0$1')
},
/**
* 处理时间戳
*/
handleTs(ts, type, _od = 0) {
if (!ts) return
//分钟必须是两位数
function checkTime(t) {
if (t < 10) {
t = '0' + t
return t
} else {
return t
}
}
//浏览器兼容,不能用toLocaleString()
ts = new Date(parseInt(ts * 1000))
let y, mon, day, hou, min
y = ts.getFullYear()
mon = ts.getMonth() + 1 < 10 ? '0' + (ts.getMonth() + 1) : ts.getMonth() + 1
day = ts.getDate() < 10 ? '0' + ts.getDate() : ts.getDate()
hou = ts.getHours()
min = checkTime(ts.getMinutes())
if (_od == 0) {
let type1 = `${y}-${mon}-${day} ${hou}:${min}`
let type2 = `${y}/${mon}/${day}`
return type ? type1 : type2
} else {
let type1 = `${y}-${mon}-${day}`
return type1
}
},
/**
* 时间格式化
* @param {*} times 可以为秒或者毫秒,必填
* @param {*} formatStr 返回时间格式 非必填
*/
formatDate(times, formatStr) {
var timestamp
if (/^\d{12,14}$/.test(times)) {
timestamp = times
} else if (/^\d{9,11}$/.test(times)) {
timestamp = times * 1000
} else {
return times
}
var format = formatStr || 'yyyy/MM/dd'
var currentDate = new Date(parseInt(timestamp))
var date = {
'M+': currentDate.getMonth() + 1,
'd+': currentDate.getDate(),
'h+': currentDate.getHours(),
'm+': currentDate.getMinutes(),
's+': currentDate.getSeconds()
}
if (/(y+)/i.test(format)) {
format = format.replace(RegExp.$1, (currentDate.getFullYear() + '').substr(4 - RegExp.$1.length))
}
for (var k in date) {
if (new RegExp('(' + k + ')').test(format)) {
format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? date[k] : ('00' + date[k]).substr(('' + date[k]).length))
}
}
return format
},
/**
* 处理时区转换
* @param {*} UTCDateString 时区字符串
*/
convertUTCTimeToLocalTime(UTCDateString) {
if (!UTCDateString) {
return '-'
}
function formatFunc(str) {
//格式化显示
return str > 9 ? str : '0' + str
}
var date2 = new Date(UTCDateString) //这步是关键
var year = date2.getFullYear()
var mon = formatFunc(date2.getMonth() + 1)
var day = formatFunc(date2.getDate())
var hour = date2.getHours()
hour = formatFunc(hour)
var min = formatFunc(date2.getMinutes())
var dateStr = year + '/' + mon + '/' + day + ' ' + hour + ':' + min
return dateStr
},
/**
* 过滤输入字符中的emoji
*/
emojiFilter(emojireg) {
const ranges = ['\ud83c[\udf00-\udfff]', '\ud83d[\udc00-\ude4f]', '\ud83d[\ude80-\udeff]']
return emojireg && emojireg.replace(new RegExp(ranges.join('|'), 'g'), '')
},
/**
* 判断设备类型
*/
GetMobelType() {
var browser = {
versions: (function() {
var ua = window.navigator.userAgent
return {
trident: ua.indexOf('Trident') > -1, //IE内核
presto: ua.indexOf('Presto') > -1, //opera内核
Alipay: ua.indexOf('Alipay') > -1, //支付宝
webKit: ua.indexOf('AppleWebKit') > -1, //苹果、谷歌内核
gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') == -1, //火狐内核
mobile: !!ua.match(/AppleWebKit.*Mobile.*/), //是否为移动终端
ios: !!ua.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端
android: ua.indexOf('Android') > -1 || ua.indexOf('Linux') > -1, //android终端或者uc浏览器
iPhone: ua.indexOf('iPhone') > -1 || ua.indexOf('Mac') > -1, //是否为iPhone或者安卓QQ浏览器
//iPhone: ua.match(/iphone|ipod|ipad/),//
iPad: ua.indexOf('iPad') > -1, //是否为iPad
webApp: ua.indexOf('Safari') == -1, //是否为web应用程序,没有头部与底部
weixin: ua.indexOf('MicroMessenger') > -1, //是否为微信浏览器
qq: ua.match(/\sQQ/i) !== null, //是否QQ
Safari: ua.indexOf('Safari') > -1, //Safari浏览器,
weibo: ua.indexOf('Weibo') > -1, //是否微博
isMobile: /(iPhone|iPod|Opera Mini|Android.*Mobile|NetFront|PSP|BlackBerry|Windows Phone|micromessenger|)/gi.test(ua),
isEdge: ua.includes('Edge'),
isFF: ua.includes('Firefox'),
isBB: ua.includes('BlackBerry'),
isChrome: ua.includes('Chrome'),
isMaxthon: ua.includes('Maxthon'),
isIos: /(iPhone|iPad|iPod|iOS)/i.test(ua),
isIE: ['compatible', 'MSIE'].every((n) => ua.includes(n)),
isSafari: ua.includes('Safari') && !ua.includes('Chrome')
}
})()
}
return browser.versions
},
//file兼容
getObjectURL(file) {
var url = null
if (window.createObjectURL != undefined) {
// basic
url = window.createObjectURL(file)
} else if (window.URL != undefined) {
// mozilla(firefox)
url = window.URL.createObjectURL(file)
} else if (window.webkitURL != undefined) {
// webkit or chrome
url = window.webkitURL.createObjectURL(file)
}
return url
},
/**
* 正则匹配
*/
reg: {
/**
*
* @param {Number} idChinese 15及18位长度大陆身份证校验
*/
idChinese(id) {
const reg = /(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx])|([1−9]\d5\d2((0[1−9])|(10|11|12))(([0−2][1−9])|10|20|30|31)\d2[0−9Xx])|([1−9]\d5\d2((0[1−9])|(10|11|12))(([0−2][1−9])|10|20|30|31)\d2[0−9Xx])/
return reg.test(id)
},
/**
*
* @param {Number} idHk 8位长度香港身份证校验
*/
idHK(id) {
const reg = /[A-Z]{1,2}[0-9]{6}([0-9A])/
return reg.test(id)
},
/**
*
* @param {Number} phone 手机号码校验
*/
phone(phone) {
const reg = /^(0|86|17951|12593)?((13[0-9])|(14[014]0[0-9])|(14[5-9])|(15([0-3]))|(15([5-9]))|(16[2567])|(170[0-9])|(174[0-5])|(17[1235678])|(18[0-9])|(19[012356789]))\d{8}$/
return reg.test(phone)
}
},
/**
* 基于localStorage封装,可以对设置有效期。
*/
storage: (() => {
class Storage {
constructor() {}
/**
* @param {string} key 存储的key值
* @param {any} val 存储内容
* @param {number} duration 存储有效期,单位秒s。未设置或格式错误默认为永久有效。
*/
set(key, val, duration) {
if (!localStorage) {
return false
}
if (!key || !val) return false
// 未设置有效期或者格式错误,默认永久生效
if (!duration || isNaN(duration)) {
duration = -1
}
let expire = duration === -1 ? -1 : new Date().getTime() + duration * 1000
let storageVal = {
val,
expire
}
localStorage.setItem(key, JSON.stringify(storageVal))
}
/**
* @param {string} key 存储的key值
* 过期或不存在则返回空
*/
get(key) {
if (!key || !localStorage) return false
let storageVal = localStorage.getItem(key) ? JSON.parse(localStorage.getItem(key)) : ''
let nowTime = new Date().getTime()
// (storageVal.expire - nowTime)/1000/60/60/24
if (storageVal.expire === -1) {
return storageVal.val
} else if (nowTime - storageVal.expire >= 0) {
this.remove(key)
console.log('已过期')
return ''
} else {
return storageVal.val
}
}
remove(key) {
if (!localStorage || !key) {
return false
}
localStorage.removeItem(key)
}
clear() {
if (!localStorage) {
return false
}
localStorage.clear()
}
}
let storage = new Storage()
return storage
})(),
/**
* 进入工具的不同入口做数据上报。
* id:templateId,如果是通过模板进入的话,一定要传模板的uuid
* type: 进入方式,0:空白页,1:场景页,2:模板 3:草稿
* client: 1:web、2:uwp、3:app
* userId: 用户id
*/
toToolCollect(id, type, client, userId) {
axios
.post('/collectapi/tool', {
templateId: id,
type,
client,
userId
})
.then((res) => {
console.log('res:', res)
})
.catch((err) => {
console.log('err:', err)
})
},
/**
* 报错信息上报
*/
errCollect(func, cause) {
axios
.post('/collectapi/err', {
func,
cause,
client: 1
})
.then((res) => {
console.log('res:', res)
})
.catch((err) => {
console.log('err:', err)
})
},
/**
* 深拷贝
*/
deepClone(obj) {
let _obj = JSON.stringify(obj),
objClone = JSON.parse(_obj)
return objClone
},
ifLaihua() {
let lhAndroid = false,
lhIOS = false
// 是否在安卓来画中
lhAndroid = navigator.userAgent.indexOf('os=Android') == -1 ? false : true
// 是否在ios来画中
lhIOS = navigator.userAgent.indexOf('os=ios') == -1 ? false : true
return lhAndroid || lhIOS
},
/**
* 保存参数到链接,用于登陆后自动跳转到指定链接。
* target:登陆后要跳转的链接;
* cover:是否覆盖当前url已存在参数,默认true;
* 组件内需要通过call调用,同时传入Vue实例this
*/
save2skip(target, cover = true) {
let path = this.$route.path.replace('/', '')
let skipParam = {
login: true,
url: target
}
let query = this.$route.query
query = cover ? skipParam : Object.assign(skipParam, query)
this.$router.push({ path, query })
},
/**
* 对象转为url的参数字符串
* @param {object} obj - 要转换为字符串输出的对象,如{name:'jack',age: 18}
* @returns {string} - name=jack&age=18
*/
obj2qury(obj) {
let str = '',
arr = []
Object.entries(obj).map((v) => {
let param = `${v[0]}=${v[1]}`
arr.push(param)
str = arr.join('&')
})
return str
},
/**
* query对象转为url查询字符串search,空对象则返回空字符串
* 例如{a:1,b:2}为`?a=1&b=2`
* @param {Object} query
* @returns {String}
*/
query2Search(query) {
let search = ''
if (Object.keys(query).length) {
Object.keys(query).forEach((k) => {
search += `${k}=${query[k]}&`
})
search = `?${search.substr(0, search.lastIndexOf('&'))}`
}
return search
},
/**
* url的查询参数字符串search转为query对象,字符串为空的话,返回{},
* 例如: `a=1&b=2`返回{a:1, b:2}
* @param {String} search - a=1或者a=1&b=2
* @returns {Object} -
*/
search2Query(search) {
if (!search) return {}
let kvArr = search.split('&'),
query = {},
k = ''
kvArr.forEach((kv) => {
k = kv.split('=')[0]
query[k] = kv.split('=')[1] || ''
})
return query
},
/**
* 将对象为空(‘’,null,undefinted)的属性过滤掉,false、0和{}不会过滤
* @param {object}} obj 需要处理的对象
* @return {object}} resultObj 过滤掉空属性后的对象
*/
objFunnel(obj) {
let resultObj = {}
Object.keys(obj).forEach((k) => {
if (obj[k] || obj[k] === 0 || typeof obj[k] === 'boolean') {
resultObj[k] = obj[k]
}
})
return resultObj
},
/**
* 根据指定属性名的值,按照升序排序
*/
sortList(propertyName) {
return function(object1, object2) {
var value1 = parseFloat(object1[propertyName])
var value2 = parseFloat(object2[propertyName])
if (value1 < value2) {
return -1
} else if (value1 > value2) {
return 1
} else {
return 0
}
}
},
/**
* 获取元素/伪元素样式。ie浏览器中无法获取伪元素样式值。
* 获取el宽度:css(el, 'width', null,) || css(el).width
* 获取el的伪元素宽度:css(el, 'with', ':before',) || css(el,'', ':before').width
*/
css(el, attr, pseudo = null) {
if (typeof el !== 'object') return false
let fn = window.getComputedStyle || document.defaultView.getComputedStyle
if (fn) {
return attr ? fn(el, pseudo)[attr] : fn(el, pseudo)
} else {
return attr ? el.currentStyle[attr] : el.currentStyle
}
},
/**
* 下载生成txt文件
* @param {*} filename 文件名 xxx.txt
* @param {*} text 文件显示内容
*/
downloadTxt(filename, text) {
var element = document.createElement('a')
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text))
element.setAttribute('download', filename)
element.style.display = 'none'
document.body.appendChild(element)
element.click()
document.body.removeChild(element)
},
/** 获取媒体文件(音频及视频)的时长
* media: 上传时读取到的本地文件
*/
getDuration(media) {
// oncanplay是异步方法
return new Promise((resolve) => {
// let duration = 0;
if (media.type.indexOf('video') == -1 && media.type.indexOf('audio') == -1) {
resolve(0)
}
let mediaEl = document.createElement('audio')
mediaEl.src =
(window.createObjectURL && window.createObjectURL(media)) ||
(window.URL && window.URL.createObjectURL(media)) ||
(window.webkitURL && window.webkitURL.createObjectURL(media))
mediaEl.oncanplay = () => {
resolve(mediaEl.duration)
}
})
},
/**
* 视频第一帧截取为封面。
* 参数:url:需要截封面的视频地址。
* 返回:res为截图上传到服务器后返回的内容。
*/
getVideoThumbnail(url) {
return new Promise((resolve, reject) => {
let video = document.createElement('video')
video.crossOrigin = 'anonymous'
video.currentTime = 2
let crop = () => {
let timer = setTimeout(() => {
video.removeEventListener('loadeddata', crop)
clearTimeout(timer)
let canvas = document.createElement('canvas')
canvas.width = video.videoWidth
canvas.height = video.videoHeight
let ctx = canvas.getContext('2d')
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
canvas.toBlob((dataUrl) => {
let formData = new FormData()
formData.append('imageName', dataUrl)
axios({
url: '/webapi/upload/file',
method: 'post',
data: formData,
dataType: 'json',
headers: { 'Content-Type': 'multipart/form-data; boundary=---12321' }
})
.then((res) => {
resolve(res)
})
.catch((err) => {
console.log('err:', err)
reject(err)
})
})
}, 1000)
}
video.addEventListener('loadeddata', crop)
video.setAttribute('src', url)
}).catch((reason) => {
console.log('catch:', reason)
})
},
/**判断str是否为json格式 */
isJSON(str) {
if (typeof str == 'string') {
try {
var obj = JSON.parse(str)
if (typeof obj == 'object' && obj) {
return true
} else {
return false
}
} catch (e) {
// console.log("error:" + str + "!!!" + e);
return false
}
}
return false
},
// 防止window.open被拦截
openWin(url) {
let tagA = document.createElement('a')
tagA.href = url
tagA.target = '_blank'
tagA.click() //点击事件
tagA.remove()
},
/**
* 复制到剪贴板
* @param {*} text 复制内容
*/
copyText(text) {
var oInput = document.createElement('input')
oInput.value = text
document.body.appendChild(oInput)
oInput.select() // 选择对象
document.execCommand('Copy') // 执行浏览器复制命令
oInput.className = 'oInput'
oInput.style.display = 'none'
},
/**
* 判断活动状态
* st: 开始时间;et: 结束时间;
* deatil:是否需要详细进度信息,默认false,只会返回布尔值,若为true,则会返回详细进度信息,1未开始,0进行中,2已结束
*/
isActive(st, et, detail = false) {
if (!st || !et) throw new Error('参数不全')
const nt = new Date().getTime()
st = new Date(st).getTime()
et = new Date(et).getTime()
const state = nt < st ? 1 : nt > et ? 2 : 0
return detail ? state : !state
},
/**
* 判断剩余天数
* targetTs 目标时间
* 返回值>0 未过期;返回值小于0 已过期
* type: 取整方式或者返回数据格式,默认ceil向上取整,可选值 deil/round/floor/ms,如果ms,直接以毫秒形式返回。
*/
timeRemaining(targetTs, type = 'ceil') {
let nowTs = Date.now()
// 兼容s与ms两种个格式
let tTs = new Date(targetTs).getTime().toString()
const tLength = tTs.length
tTs = tLength === 10 ? parseInt(tTs) * 1000 : parseInt(tTs)
return type === 'ms' ? tTs - nowTs : Math[type]((tTs - nowTs) / 1000 / 60 / 60 / 24)
}
}
export const {
handleAssetsUrl,
delSpacesOfStr,
judgeAgent,
getScrollBarWidth,
toggleHtmlScroll,
generateUuid,
isJsonString,
secToMin,
handleTs,
formatDate,
convertUTCTimeToLocalTime,
emojiFilter,
GetMobelType,
getObjectURL,
reg,
storage,
toToolCollect,
errCollect,
deepClone,
ifLaihua,
save2skip,
obj2qury,
sortList,
css,
downloadTxt,
getDuration,
isJSON,
openWin,
copyText,
isActive,
timeRemaining
} = util
export default util
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment