1. /**
    2. * Helper.js
    3. * 工具函数
    4. */
    5. const Helper = {
    6. timerEnd: null,
    7. timerStart: null
    8. }
    9. String.prototype.trim = function () {
    10. return this.replace(/^\s\s*/, '').replace(/\s\s*$/, '')
    11. }
    12. function getUA() {
    13. return (function () {
    14. let u = navigator.userAgent
    15. let app = navigator.appVersion
    16. return {
    17. trident: u.indexOf('Trident') > -1, // IE内核
    18. presto: u.indexOf('Presto') > -1, // opera内核
    19. webKit: u.indexOf('AppleWebKit') > -1, // 苹果、谷歌内核
    20. gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') === -1, // 火狐内核
    21. mobile: !!u.match(/AppleWebKit.*Mobile.*/), // 是否为移动终端
    22. isIos: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), // ios终端
    23. isAndroid: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, // android终端或者uc浏览器
    24. iPhone: u.indexOf('iPhone') > -1, // 是否为iPhone或者QQHD浏览器
    25. iPad: u.indexOf('iPad') > -1, // 是否iPad
    26. weixin: u.indexOf('MicroMessenger') > -1, // 是否微信
    27. qq: u.match(/\sQQ/i) === ' qq', // 是否QQ
    28. weibo: u.indexOf('weibo') > -1, // 是否sina weibo
    29. inNative: u.indexOf('iting') > -1, // 是否xmly app
    30. version: app
    31. }
    32. })()
    33. }
    34. function getLocal() {
    35. return (function () {
    36. let location = window.location
    37. return {
    38. host: location.host,
    39. origin: location.origin,
    40. path: location.pathname,
    41. href: location.href,
    42. search: location.search,
    43. protocol: location.protocol,
    44. isTest: /test/.test(location.host)
    45. }
    46. })()
    47. }
    48. const ua = {
    49. ...getUA()
    50. }
    51. const local = {
    52. ...getLocal()
    53. }
    54. /* ua场景信息 */
    55. Helper.UA = ua
    56. /* url信息 */
    57. Helper.LOCAL = local
    58. Helper.config = {
    59. static: 'http://static2.test.ximalaya.com',
    60. mstatic: 'http://mstatic.test.ximalaya.com',
    61. xmcdn: 'http://s1.xmcdn.com',
    62. projectCdnUrl: Helper.LOCAL.isTest ? 'http://static2.test.ximalaya.com/lib/hybrid-listening/last/dist/' : 'http://s1.xmcdn.com/lib/hybrid-listening/last/dist/',
    63. crossImgUrl: Helper.LOCAL.isTest ? 'http://static2.test.ximalaya.com/lib/common/last/assets/cross-img/' : 'http://s1.xmcdn.com/lib/common/last/assets/cross-img/',
    64. MSiteLogin: Helper.LOCAL.isTest ? 'http://m.test.ximalaya.com/login?fromUri=' : 'https://m.ximalaya.com/login?fromUri='
    65. }
    66. // Helper.timerEnd = Helper.timerStart = null
    67. /**
    68. * formDataJSONparse
    69. * formData 转queryString
    70. * @param {JSON} json
    71. */
    72. Helper.formDataJSONparse = function (json) {
    73. let res = ''
    74. for (var key in json) {
    75. res += encodeURIComponent(key) + '=' + encodeURIComponent(json[key]) + '&'
    76. }
    77. return res.replace(/&$/, '')
    78. }
    79. /**
    80. * cookie
    81. * cookie存取操作
    82. * @param {String} name
    83. * @param {String} value
    84. * @param {Object} options
    85. */
    86. Helper.cookie = function (name, value, options) {
    87. if (typeof value !== 'undefined') {
    88. options = options || {}
    89. if (value === null) {
    90. value = ''
    91. options = Object.assgin({}, options)
    92. options.expires = -1
    93. }
    94. var expires = ''
    95. if (options.expires && (typeof options.expires === 'number' || options.expires.toUTCString)) {
    96. var date
    97. if (typeof options.expires === 'number') {
    98. date = new Date()
    99. date.setTime(date.getTime() + (options.expires * 1000))
    100. } else {
    101. date = options.expires
    102. }
    103. expires = '; expires=' + date.toUTCString()
    104. }
    105. var path = options.path ? '; path=' + (options.path) : ''
    106. var domain = options.domain ? '; domain=' + (options.domain) : ''
    107. var secure = options.secure ? '; secure' : ''
    108. document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('')
    109. } else {
    110. var cookieValue = null
    111. if (document.cookie && document.cookie !== '') {
    112. var cookies = document.cookie.split(';')
    113. for (var i = 0; i < cookies.length; i++) {
    114. var cookie = (cookies[i] + '').trim()
    115. if (cookie.substring(0, name.length + 1) === (name + '=')) {
    116. cookieValue = decodeURIComponent(cookie.substring(name.length + 1))
    117. break
    118. }
    119. }
    120. }
    121. return cookieValue
    122. }
    123. }
    124. /**
    125. * getUid
    126. * 获取uid
    127. */
    128. Helper.getUid = function () {
    129. let id = null
    130. let isDev = this.LOCAL.isTest
    131. let token = this.cookie((isDev ? 4 : 1) + '&_token')
    132. if (token) {
    133. id = token.split('&')[0]
    134. }
    135. return id
    136. }
    137. /**
    138. * getToken
    139. * 获取cookie token
    140. */
    141. Helper.getToken = function () {
    142. let token = null
    143. let isDev = this.LOCAL.isTest
    144. token = this.cookie((isDev ? 4 : 1) + '&_token')
    145. return token
    146. }
    147. /**
    148. * getBlobBydataURI
    149. * @param {base64} dataURI
    150. * @param {String} type
    151. */
    152. /* base64转二进制 */
    153. Helper.getBlobBydataURI = function (dataURI, type) {
    154. var binary = window.atob(dataURI.split(',')[1])
    155. var array = []
    156. for (var i = 0; i < binary.length; i++) {
    157. array.push(binary.charCodeAt(i))
    158. }
    159. return new Blob([new Uint8Array(array)], { type: type })
    160. }
    161. /* 获取iframe返回数据 */
    162. Helper.getFrameResponse = function (frame) {
    163. let doc = null
    164. let responseText = ''
    165. try {
    166. if (frame.contentWindow) {
    167. doc = frame.contentWindow.document
    168. }
    169. } catch (err) {
    170. console.log('cannot get iframe.contentWindow document: ' + err)
    171. }
    172. if (!doc) {
    173. try {
    174. doc = frame.contentDocument
    175. ? frame.contentDocument
    176. : frame.document
    177. } catch (err) {
    178. console.log('cannot get iframe.contentDocument: ' + err)
    179. doc = frame.document
    180. }
    181. }
    182. // 获取根节点
    183. let docRoot = doc.body
    184. ? doc.body
    185. : doc.documentElement
    186. let pre = doc.getElementsByTagName('pre')[0]
    187. let b = doc.getElementsByTagName('body')[0]
    188. if (pre) {
    189. responseText = pre.textContent
    190. ? pre.textContent
    191. : pre.innerText
    192. } else if (b) {
    193. responseText = b.textContent
    194. ? b.textContent
    195. : b.innerText
    196. }
    197. return responseText
    198. }
    199. /**
    200. * setMetaTitle
    201. * 单页应用设置页面title
    202. * @param {String} title
    203. */
    204. Helper.setMetaTitle = function (title) {
    205. var env = this.LOCAL.isTest ? this.config.static : this.config.xmcdn
    206. document.title = title
    207. let iframe = document.createElement('iframe')
    208. iframe.style.visibility = 'hidden'
    209. // 替换成站标favicon路径或者任意存在的较小的图片即可
    210. iframe.setAttribute('src', env + '/lib/hybrid_grade/last/dist/static/img/v-blue.png')
    211. let iframeCallback = function () {
    212. setTimeout(function () {
    213. iframe.removeEventListener('load', iframeCallback)
    214. document.body.removeChild(iframe)
    215. }, 0)
    216. }
    217. iframe.addEventListener('load', iframeCallback)
    218. document.body.appendChild(iframe)
    219. }
    220. /**
    221. * toast
    222. * toast组件
    223. * @param {String} txt弹出文案
    224. * @param {Number} 动画时间
    225. */
    226. Helper.toast = function (txt, t) {
    227. function styleExtend(target, options) {
    228. Object.assign(target, options)
    229. }
    230. var mToast, mTxt
    231. var mToastStyles = {
    232. position: 'fixed',
    233. width: 'auto',
    234. bottom: '350px',
    235. left: '0',
    236. right: '0',
    237. textAlign: 'center',
    238. opacity: '0',
    239. transition: 'all 0.8s',
    240. webkitTransition: 'all 0.8s',
    241. zIndex: '999999'
    242. }
    243. var mTxtStyles = {
    244. fontSize: '14px',
    245. display: 'inline-block',
    246. background: 'rgba(0, 0, 0, 0.86)',
    247. color: '#fff',
    248. padding: '20px',
    249. overflow: 'hidden',
    250. textOverflow: 'ellipsis',
    251. whiteSpace: 'nowrap',
    252. borderRadius: '5px',
    253. maxWidth: '95%'
    254. }
    255. mToast = document.querySelector('#toast')
    256. if (mToast !== null) {
    257. document.body.removeChild(mToast)
    258. }
    259. mToast = document.createElement('div')
    260. mTxt = document.createElement('span')
    261. mToast.id = 'toast'
    262. mTxt.id = 'toast-txt'
    263. styleExtend(mToast.style, mToastStyles)
    264. styleExtend(mTxt.style, mTxtStyles)
    265. mTxt.innerText = txt
    266. mToast.appendChild(mTxt)
    267. document.body.appendChild(mToast)
    268. this.timerStart = setTimeout(() => {
    269. styleExtend(mToast.style, {
    270. opacity: 1,
    271. zIndex: 999999
    272. })
    273. }, 0)
    274. this.timerEnd = setTimeout(() => {
    275. styleExtend(mToast.style, {
    276. opacity: 0,
    277. zIndex: -999999
    278. })
    279. }, t || 3000)
    280. }
    281. /**
    282. * checkAliIdCard
    283. * 校验idcard是否被占用
    284. * @param {String} idcard
    285. * @param {String} cardType
    286. */
    287. Helper.checkAliIdCard = function (id, cardType = '二代身份证') {
    288. if (id === '') {
    289. return false
    290. }
    291. let formData = new FormData()
    292. formData.append('card_id', id)
    293. formData.append('card_type', cardType)
    294. this.$http.addv
    295. .checkIdCard(formData)
    296. .then(res => {
    297. if (res.status === 200) {
    298. if (res.data.ret === 1) {
    299. if (res.data.data.isValidCard) {
    300. this.validAliIdCard = true
    301. this.needResetAliIdCard = false
    302. } else {
    303. this.validAliIdCard = false
    304. this.needResetAliIdCard = true
    305. Helper.toast('该身份证号已认证,请重新输入')
    306. }
    307. }
    308. }
    309. })
    310. .catch(err => {
    311. this.validAliIdCard = true
    312. this.needResetAliIdCard = false
    313. })
    314. }
    315. // Helper.getUrlQueryOption = function (URL = '') {
    316. // let options = {}
    317. // // 或let urlStr = URL.match((/\?([\w\W]*)/) || [, '/'])[1];
    318. // let urlStr = URL.match(/\?.*/)[0].slice(1)
    319. // urlStr.split('&').forEach(function (item, i) {
    320. // options[item.split('=')[0]] = item.split('=')[1]
    321. // })
    322. // return options
    323. // }
    324. Helper.getUrlQueryOption = function (url) {
    325. var queryOpts = {}
    326. if (url.indexOf('?') !== -1) {
    327. var str = url.substr(1)
    328. var strs = str.split('&')
    329. for (var i = 0; i < strs.length; i++) {
    330. queryOpts[strs[i].split('=')[0]] = (strs[i].split('=')[1])
    331. }
    332. }
    333. return queryOpts
    334. }
    335. /**
    336. * getWeiboToken
    337. * 调客户端接口拿微博授权信息
    338. * @param {Object} success, failure, error 成功失败错误回调
    339. */
    340. Helper.weiboSSOAuth = function ({
    341. success,
    342. failure,
    343. error
    344. }) {
    345. /* === 1.调客户端授权 === */
    346. ya && ya.get3rdAuthInfo({
    347. type: 'sina'
    348. }, res => {
    349. // 授权成功
    350. if (res.ret === 0) {
    351. this.authTokens.accessToken = res.data.accessToken
    352. this.authTokens.refreshToken = res.data.refreshToken
    353. this.authTokens.expiresTime = res.data.expirationDate
    354. this.authTokens.thirdpartyUid = res.data.userID
    355. let wbTokenFormData = new FormData()
    356. wbTokenFormData.append('accessToken', this.authTokens.accessToken)
    357. wbTokenFormData.append('refreshToken', this.authTokens.refreshToken)
    358. wbTokenFormData.append('expiresTime', this.authTokens.expiresTime)
    359. wbTokenFormData.append('thirdpartyUid', this.authTokens.thirdpartyUid)
    360. // alert(JSON.stringify(res.data))
    361. /* === 2.调基础服务微博授权确认接口 === */
    362. this.$http.addv.weiboAuth({
    363. formData: wbTokenFormData,
    364. thirdpartyId: 1
    365. }).then(res => {
    366. if (res.status === 200) {
    367. // alert(JSON.stringify(res.data))
    368. if (res.data.ret === 0) {
    369. /* === 3.调微博信息接口 === */
    370. this.$http.addv.getWeiboInfo().then(res => {
    371. if (res.status === 200) {
    372. // alert(JSON.stringify(res.data))
    373. if (res.data.ret == 1) {
    374. success && success(res)
    375. } else {
    376. failure && failure(res)
    377. }
    378. }
    379. }).catch(e => {
    380. Helper.toast(e)
    381. // error && error(e)
    382. })
    383. } else {
    384. error && error('weiboAuth')
    385. }
    386. }
    387. }).catch(e => {
    388. Helper.toast(e)
    389. // error && error(e)
    390. })
    391. } else {
    392. error && error()
    393. }
    394. })
    395. }
    396. Helper.compareVersion = function (vStr = '0.0.0', appVersion) {
    397. let vStrArr = vStr.split('.')
    398. let appArr = appVersion.split('.')
    399. let n1 = 0
    400. let n2 = 0
    401. function formatVersion (arr = ['0', '0', '0']) {
    402. return arr[0] * 10000 + arr[1] * 100 + arr[2]
    403. }
    404. n1 = formatVersion(vStrArr)
    405. n2 = formatVersion(appArr)
    406. if (n1 > n2) {
    407. return 1
    408. } else if (n1 === n2) {
    409. return 0
    410. } else {
    411. return -1
    412. }
    413. }
    414. Helper./**
    415. * draProcess canvas绘制环形进度条
    416. * @author nardo.li
    417. * @created 2017-07-17
    418. * @param {*} canvas
    419. * @param {*} process
    420. * @param {*} width
    421. * @param {*} height
    422. * @param {*} direct 旋转方向
    423. */
    424. function drawProcess(canvas, process, width, height, direct) {
    425. // console.log(canvas)
    426. var CANVAS_COLOR = {
    427. left: '#FFB43B',
    428. right: '#FF6D5C'
    429. }
    430. var context = canvas.getContext('2d')
    431. if (window.devicePixelRatio) {
    432. canvas.style.width = `${width}px`
    433. canvas.style.height = `${height}px`
    434. canvas.height = height * window.devicePixelRatio
    435. canvas.width = width * window.devicePixelRatio
    436. }
    437. context.scale(window.devicePixelRatio, window.devicePixelRatio)
    438. context.clearRect(0, 0, 60, 60)
    439. /* 开始画一个灰色的圆 */
    440. context.beginPath()
    441. /* 坐标移动到圆心 */
    442. context.moveTo(60, 60)
    443. // 画圆,圆心是60,60,半径60,从角度0开始,画到2PI结束,最后一个参数是方向顺时针还是逆时针
    444. context.arc(60, 60, 60, 0, Math.PI * 2, false)
    445. context.closePath()
    446. // 填充颜色
    447. context.fillStyle = '#F2F2F2'
    448. context.fill()
    449. window._timer = {}
    450. function rewriteCanvas(n) {
    451. window._timer[direct] = setInterval(() => {
    452. if (n > process) {
    453. // console.log(n)
    454. clearInterval(window._timer[direct])
    455. } else {
    456. draw(n)
    457. n += 0.01
    458. }
    459. }, 15)
    460. }
    461. function draw(n) {
    462. // 画进度
    463. context.beginPath()
    464. // 画扇形的时候这步很重要,画笔不在圆心画出来的不是扇形
    465. context.moveTo(60, 60)
    466. // 跟上面的圆唯一的区别在这里,不画满圆,画个扇形
    467. context.arc(60, 60, 60, -Math.PI / 2, -Math.PI / 2 + Math.PI * 2 * n, false)
    468. context.closePath()
    469. context.fillStyle = CANVAS_COLOR[direct]
    470. context.fill()
    471. // 画内部空白
    472. context.beginPath()
    473. context.moveTo(60, 60)
    474. context.arc(60, 60, 52, 0, Math.PI * 2, true)
    475. context.closePath()
    476. context.fillStyle = 'rgba(255,255,255,1)'
    477. context.fill()
    478. }
    479. rewriteCanvas(0)
    480. }
    481. /**
    482. * draProcess canvas绘制环形进度条
    483. * @author nardo.li
    484. * @created 2017-07-17
    485. * @param {*} canvas
    486. * @param {*} process
    487. * @param {*} width
    488. * @param {*} height
    489. * @param {*} direct 旋转方向
    490. */
    491. Helper.drawProcess = function(canvas, process, width, height, direct) {
    492. // console.log(canvas)
    493. var CANVAS_COLOR = {
    494. left: '#FFB43B',
    495. right: '#FF6D5C'
    496. }
    497. var context = canvas.getContext('2d')
    498. if (window.devicePixelRatio) {
    499. canvas.style.width = `${width}px`
    500. canvas.style.height = `${height}px`
    501. canvas.height = height * window.devicePixelRatio
    502. canvas.width = width * window.devicePixelRatio
    503. }
    504. context.scale(window.devicePixelRatio, window.devicePixelRatio)
    505. context.clearRect(0, 0, 60, 60)
    506. /* 开始画一个灰色的圆 */
    507. context.beginPath()
    508. /* 坐标移动到圆心 */
    509. context.moveTo(60, 60)
    510. // 画圆,圆心是60,60,半径60,从角度0开始,画到2PI结束,最后一个参数是方向顺时针还是逆时针
    511. context.arc(60, 60, 60, 0, Math.PI * 2, false)
    512. context.closePath()
    513. // 填充颜色
    514. context.fillStyle = '#F2F2F2'
    515. context.fill()
    516. window._timer = {}
    517. function rewriteCanvas(n) {
    518. window._timer[direct] = setInterval(() => {
    519. if (n > process) {
    520. // console.log(n)
    521. clearInterval(window._timer[direct])
    522. } else {
    523. draw(n)
    524. n += 0.01
    525. }
    526. }, 15)
    527. }
    528. function draw(n) {
    529. // 画进度
    530. context.beginPath()
    531. // 画扇形的时候这步很重要,画笔不在圆心画出来的不是扇形
    532. context.moveTo(60, 60)
    533. // 跟上面的圆唯一的区别在这里,不画满圆,画个扇形
    534. context.arc(60, 60, 60, -Math.PI / 2, -Math.PI / 2 + Math.PI * 2 * n, false)
    535. context.closePath()
    536. context.fillStyle = CANVAS_COLOR[direct]
    537. context.fill()
    538. // 画内部空白
    539. context.beginPath()
    540. context.moveTo(60, 60)
    541. context.arc(60, 60, 52, 0, Math.PI * 2, true)
    542. context.closePath()
    543. context.fillStyle = 'rgba(255,255,255,1)'
    544. context.fill()
    545. }
    546. rewriteCanvas(0)
    547. }
    548. export default Helper