common.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  1. /**
  2. * # common.js 代码问题深度批判
  3. ## 代码结构:混乱不堪的功能堆砌
  4. 1. 模块化缺失 :整个文件长达647行,包含了46个导出函数,从登录认证到时间格式化,从页面跳转到底层工具,所有功能混杂在一起,严重违反单一职责原则。这种"一锅炖"的设计导致代码难以维护和测试。
  5. 2. 函数组织无序 :相关功能没有分组,例如登录相关的 toLogin 、 isLogin 、 saveLogin 等函数散布在文件不同位置,增加了代码阅读和理解的难度。
  6. 3. 命名规范混乱 :函数命名风格不一致,有的使用驼峰命名(如 navigateTo ),有的使用下划线风格(如 cmsGetList ),甚至存在 modelShow 这样的混合命名,严重影响代码可读性。
  7. ## 安全性:漏洞百出的实现
  8. 1. 认证机制薄弱 : isLogin 函数(48-66行)仅检查本地存储中是否存在用户数据,没有验证登录状态的有效性,容易被伪造登录状态。
  9. 2. URL处理存在风险 : toUrl 函数(378-407行)对外部链接的处理过于简单,没有进行严格的URL格式验证和安全过滤,可能导致XSS攻击或恶意URL执行。
  10. 3. 本地存储安全隐患 : saveLogin 函数(414-421行)直接将用户认证信息存储在本地,没有任何加密措施,一旦设备被破解,用户信息将直接泄露。
  11. 4. 密码处理缺失 :代码中完全没有密码加密相关的逻辑,登录凭证的安全性无法保障。
  12. ## 性能:低效冗余的实现
  13. 1. 不必要的延迟 : initPages 函数(334-372行)中存在硬编码的1秒延迟(366行 setTimeout(() => { ... }, 1000); ),没有任何合理的业务逻辑支持,纯粹浪费用户时间。
  14. 2. 重复的正则表达式创建 : testString 函数(475-501行)和 checkMobile 函数(556-558行)每次调用都创建新的正则表达式对象,造成性能损耗,应该将正则表达式提升为模块级常量。
  15. 3. 网络请求冗余 : initPages 函数在有缓存的情况下仍然会发起网络请求,没有实现有效的缓存策略,增加了服务器负担和用户等待时间。
  16. 4. 内存泄漏风险 :多处使用 setTimeout 但没有清理机制,特别是在 modelShow 函数中,可能导致回调函数无法及时释放。
  17. ## 逻辑:错误百出的实现
  18. 1. 函数功能与命名不符 : userInfo 函数(562-569行)返回的是 auth 对象而不是用户信息,与函数名严重不符,容易误导调用者。
  19. 2. 条件判断逻辑错误 : isArray 函数(178-180行)的实现 return object && typeof object === 'object' 是错误的,因为对象和null也会返回true,正确的实现应该是 Array.isArray(object) 。
  20. 3. 导航逻辑混乱 : navigateBack 函数(222-253行)包含大量硬编码的路由判断,逻辑复杂且难以维护,一旦路由结构变化,就需要修改多处代码。
  21. 4. 错误处理不完善 :多处API调用(如 api.login 、 api.uploadImage )只处理了成功情况,没有捕获和处理网络错误或服务器异常,可能导致程序崩溃。
  22. ## 代码质量:粗制滥造的实现
  23. 1. 硬编码泛滥 :代码中存在大量硬编码值,如 cmsGetList 中硬编码的 /uploads/ 路径(287行), toLogin 中硬编码的登录提示信息(19行)等,这些值应该通过配置文件管理。
  24. 2. 注释与代码不符 : isLogin 函数的注释(46-47行)声称"是否登陆,和绑定手机号,否则返回登录页",但实际代码中绑定手机号的逻辑被注释掉了(53-57行),注释与实现严重不符。
  25. 3. 冗余代码 : testString 函数中 case null 分支(482-484行)直接返回false,没有任何实际作用,属于冗余代码。
  26. 4. 缩进与格式混乱 :代码缩进不一致,有时使用空格,有时使用制表符,部分代码行尾存在多余的空格,影响代码可读性。
  27. ## 架构设计:过时落后的方案
  28. 1. 回调地狱 :多处使用嵌套回调函数(如 initPages 、 cmsGetList ),没有使用Promise或async/await,导致代码可读性差,错误处理困难。
  29. 2. 全局依赖 :直接导入 db 、 api 等模块,没有使用依赖注入,增加了模块间的耦合度,难以进行单元测试。
  30. 3. 平台兼容性处理粗糙 :使用条件编译(如 #ifdef H5 、 #ifdef MP )处理不同平台的差异,但逻辑分散在各个函数中,没有统一的平台适配层。
  31. 4. 缺乏错误边界 :整个代码库没有统一的错误处理机制,每个函数都需要单独处理错误,增加了代码复杂度和维护成本。
  32. ## 总结
  33. 这份 common.js 代码是一个典型的"代码坏味道"集合体,从架构设计到具体实现,从安全性到性能,几乎每一个方面都存在严重问题。它反映了开发过程中的敷衍了事和缺乏专业素养,是前端代码质量的反面教材。
  34. 这样的代码不仅会增加开发和维护成本,还会给应用带来严重的安全隐患和性能问题。如果不进行彻底重构,随着项目规模的扩大,这些问题将会像滚雪球一样越积越多,最终导致整个应用崩溃或被黑客攻击。
  35. 作为一名专业的开发者,应该严格遵循代码规范和最佳实践,注重代码质量和安全性,而不是像这样随意堆砌功能。这份代码的存在,本身就是对软件工程这门学科的不尊重。
  36. *
  37. */
  38. import * as db from './db.js' //引入common
  39. import * as api from './api.js'
  40. import {
  41. baseUrl,
  42. cndUrl,
  43. bgClass,
  44. title,
  45. baseLogo,
  46. } from './config.js'
  47. import htmlParser from '@/common/html-parser' //引入htmlParser
  48. /**
  49. * 跳转登陆页面
  50. */
  51. function toLogin() {
  52. uni.showToast({
  53. title: '请登录...',
  54. icon: 'loading',
  55. duration: 2000,
  56. success: function(res) {
  57. var pages = getCurrentPages() // 获取栈实例
  58. let currentRoute = pages[pages.length - 1].route; // 获取当前页面路由
  59. //console.log("路由当前页面路径"+currentRoute)
  60. let currentPage = pages[pages.length - 1]['$page']['fullPath'] //当前页面路径(带参数)
  61. // console.log(currentPage)
  62. // #ifdef H5 || APP-PLUS
  63. uni.navigateTo({
  64. url: '/pages/user/login?redirect=' + escape(currentPage)
  65. })
  66. // #endif
  67. // #ifdef MP-WEIXIN
  68. uni.navigateTo({
  69. url: '/pages/user/login?redirect=' + escape(currentPage),
  70. animationType: 'pop-in',
  71. animationDuration: 200
  72. });
  73. // #endif
  74. }
  75. })
  76. }
  77. /**
  78. * 是否登陆,和绑定手机号,否则返回登录页
  79. */
  80. function isLogin() {
  81. let user = db.get('user');
  82. //用户存在,不跳转,不存在直接跳转
  83. if (user) {
  84. if (user.id) {
  85. // if(user.mobile==''){
  86. // uni.navigateTo({
  87. // url: '/pages/user/bind'
  88. // })
  89. // }
  90. } else {
  91. console.log("user: ", user);
  92. db.del('user');
  93. db.del('auth');
  94. toLogin()
  95. }
  96. }
  97. }
  98. /**
  99. * 无图标提示
  100. * @param {String} msg 提示消息
  101. * @param {Function} callback 回调函数
  102. */
  103. function normalToShow(msg = '保存成功', callback = function() {}) {
  104. uni.showToast({
  105. title: msg,
  106. icon: 'none',
  107. duration: 2000,
  108. });
  109. setTimeout(function() {
  110. callback();
  111. }, 1000);
  112. }
  113. /**
  114. * 成功提示
  115. * @param {String} msg 提示消息
  116. * @param {Function} callback 回调函数
  117. */
  118. function successToShow(msg = '保存成功', callback = function() {}) {
  119. uni.showToast({
  120. title: msg,
  121. icon: 'success',
  122. duration: 2000,
  123. });
  124. setTimeout(function() {
  125. callback();
  126. }, 1500);
  127. }
  128. /**
  129. * 失败提示
  130. * @param {String} msg 提示消息
  131. * @param {Function} callback 回调函数
  132. */
  133. function errorToShow(msg = '操作失败', callback = function() {}) {
  134. uni.showToast({
  135. title: msg,
  136. icon: 'none',
  137. duration: 2000,
  138. });
  139. setTimeout(function() {
  140. callback();
  141. }, 2000);
  142. }
  143. /**
  144. * 加载显示
  145. * @param {String} msg 提示消息
  146. */
  147. function loadToShow(msg = '加载中', icon = 'loading') {
  148. uni.showToast({
  149. title: msg,
  150. icon: icon,
  151. });
  152. }
  153. /**
  154. * 加载隐藏
  155. */
  156. function loadToHide() {
  157. uni.hideToast();
  158. }
  159. /**
  160. * 提示框
  161. * @param {String} title 提示标题
  162. * @param {String} content 提示内容
  163. * @param {Function} callback 回调函数
  164. * @param {Boolean} showCancel = [true|false] 显示关闭按钮
  165. * @param {String} cancelText 关闭按钮文字
  166. * @param {String} confirmText 确定按钮文字
  167. * @example
  168. * modelShow('提示','确认执行此操作吗?',()=>{},()=>{},true,'取消','确定')
  169. */
  170. function modelShow(title = '提示', content = '确认执行此操作吗?', callback = () => {}, callback2 = () => {}, showCancel = true,
  171. cancelText = '拒绝',
  172. confirmText = '通过') {
  173. uni.showModal({
  174. title: title,
  175. content: content,
  176. showCancel: showCancel,
  177. cancelText: cancelText,
  178. confirmText: confirmText,
  179. success: function(res) {
  180. if (res.confirm) {
  181. // 用户点击确定操作
  182. setTimeout(() => {
  183. callback()
  184. }, 500)
  185. } else if (res.cancel) {
  186. // 用户取消操作
  187. setTimeout(() => {
  188. callback2()
  189. }, 500)
  190. }
  191. }
  192. });
  193. }
  194. /**
  195. * 判断数组
  196. * @param {Object} arr 数组
  197. */
  198. function isArray(object) {
  199. return object && typeof object === 'object'
  200. }
  201. /**
  202. * 统一跳转
  203. * @param {String} url 跳转链接
  204. */
  205. function navigateTo(url) {
  206. if (url == '')
  207. return;
  208. if (url.indexOf("/pages/index/index") >= 0 || url.indexOf("answer_pages/home/dashboard") >= 0 || url.indexOf(
  209. "/pages/shouhu/shouhu") >= 0 || url.indexOf("/pages/feiyi/feiyi") >= 0 || url.indexOf(
  210. "/pages/user/index") >= 0) {
  211. uni.switchTab({
  212. url: url,
  213. animationType: 'pop-in',
  214. animationDuration: 300
  215. });
  216. } else {
  217. uni.navigateTo({
  218. url: url,
  219. animationType: 'pop-in',
  220. animationDuration: 300
  221. });
  222. }
  223. }
  224. /**
  225. * 关闭当前页面并跳转
  226. * @param {String} url 跳转链接
  227. */
  228. function redirectTo(url) {
  229. uni.redirectTo({
  230. url: url,
  231. animationType: 'pop-in',
  232. animationDuration: 300
  233. })
  234. }
  235. /**
  236. * 返回上一层的逻辑判断
  237. * @param {num} delta 跳转上一层,或者几层
  238. */
  239. function navigateBack(delta = 1) {
  240. let pages = getCurrentPages(); //当前页
  241. //console.log(pages);
  242. //当有前一页的时候。
  243. if (pages.length > 1) {
  244. let page = pages[pages.length - 2]; //上个页面
  245. // console.log(page.route);
  246. if (page.route == "pages/index/index" || page.route == 'pages/index/homepage' || page.route ==
  247. 'pages/user/index' || page.route == 'pages/consult/index') {
  248. uni.switchTab({
  249. url: '/' + page.route
  250. })
  251. } else if (page.route == "pages/user/login") {
  252. uni.switchTab({
  253. url: '/pages/user/index'
  254. })
  255. } else if (page.route == "pages/user/register") {
  256. uni.switchTab({
  257. url: '/pages/user/user'
  258. })
  259. } else {
  260. uni.navigateBack({
  261. delta: delta
  262. })
  263. }
  264. } else {
  265. uni.switchTab({
  266. url: '/pages/index/index'
  267. })
  268. }
  269. }
  270. /**
  271. * 判断是否在微信浏览器
  272. */
  273. function isWeiXinBrowser() {
  274. // #ifdef H5
  275. // window.navigator.userAgent属性包含了浏览器类型、版本、操作系统类型、浏览器引擎类型等信息,这个属性可以用来判断浏览器类型
  276. let ua = window.navigator.userAgent.toLowerCase()
  277. // 通过正则表达式匹配ua中是否含有MicroMessenger字符串
  278. if (ua.match(/MicroMessenger/i) == 'micromessenger') {
  279. return true
  280. } else {
  281. return false
  282. }
  283. // #endif
  284. // #ifdef MP
  285. return false;
  286. // #endif
  287. }
  288. /**
  289. * 加载cms列表
  290. * @param {Array} data
  291. *
  292. */
  293. function cmsGetList(data, callback = function() {}) {
  294. api.cmsGetList(data, res => {
  295. if (res.code) {
  296. res.data.list.forEach(function(ele, index) {
  297. ele.ctime = timeToDate(ele.createtime);
  298. if (ele.image.substring(0, 9) == '/uploads/') {
  299. ele.image = cndUrl + ele.image
  300. }
  301. });
  302. callback(res.data)
  303. } else {
  304. errorToShow(res.msg)
  305. }
  306. })
  307. }
  308. /**
  309. * 加载cms详情
  310. * @param {Array} data
  311. *
  312. */
  313. function cmsGetDetails(data, callback = function() {}) {
  314. api.cmsGetDetails(data, res => {
  315. //console.log(data)
  316. if (res.code) {
  317. res.data.content = htmlParser(res.data.content); // 设置资源cdn;
  318. res.data.ctime = timeToDate(res.data.createtime);
  319. if (res.data.image) {
  320. if (res.data.image.substring(0, 9) == '/uploads/') {
  321. res.data.image = cndUrl + res.data.image
  322. }
  323. }
  324. callback(res.data)
  325. } else {
  326. modelShow(
  327. '错误提示',
  328. res.msg,
  329. () => {
  330. uni.navigateBack({})
  331. },
  332. false
  333. );
  334. }
  335. })
  336. }
  337. /**
  338. * 初始化页面
  339. * @param {Function} callback 回调函数
  340. * @param {String} route 页面路径/默认当前路径
  341. */
  342. function initPages(callback = function() {}, route) {
  343. if (!route) {
  344. let pages = getCurrentPages();
  345. let page = pages[pages.length - 1];
  346. route = page.route
  347. }
  348. let init_data = db.get('init_' + route)
  349. setTimeout(() => {
  350. api.getInit({
  351. route: route
  352. }, res => {
  353. // console.log(res);
  354. if (res.code) {
  355. res.data.slide.forEach(function(ele, index) {
  356. if (ele.image.substring(0, 9) == '/uploads/') {
  357. ele.image = cndUrl + ele.image
  358. }
  359. });
  360. res.data.content.forEach(function(ele, index) {
  361. ele.content = ele.content.replace(new RegExp(`style="width: 100%;`, 'g'),
  362. 'style="width: 100%;margin-top: -3px;') // 无缝连接图片;
  363. ele.content = ele.content.replace(new RegExp(`src="/uploads`, 'g'),
  364. 'src="' + cndUrl + '/uploads')
  365. ele.content = htmlParser(ele.content); // 设置资源cdn;
  366. });
  367. db.set('init_' + route, res.data)
  368. callback(res.data)
  369. }
  370. });
  371. }, 1000);
  372. if (init_data) {
  373. callback(init_data)
  374. } else {
  375. // loadToShow('初始化页面...');
  376. }
  377. }
  378. /**
  379. * 跳转链接
  380. * @param {String} url 跳转链接
  381. */
  382. function toUrl(url) {
  383. if (url) {
  384. var objExp = new RegExp(/http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w- .\/?%&=]*)?/);
  385. if (objExp.test(url) != true) {
  386. // #ifdef APP-PLUS
  387. url = baseUrl + url
  388. // #endif
  389. // #ifdef H5
  390. url = baseUrl + url
  391. // #endif
  392. }
  393. //console.log(url)
  394. //return false
  395. // #ifdef MP
  396. uni.navigateTo({
  397. url: url
  398. })
  399. // #endif
  400. // #ifdef APP-PLUS
  401. plus.runtime.openURL(url);
  402. // #endif
  403. // #ifdef H5
  404. window.open(url);
  405. // #endif
  406. }
  407. }
  408. /**
  409. * 保存登陆状态
  410. * @param {Array} data 用户数据
  411. */
  412. function saveLogin(data) {
  413. db.set('auth', data.auth)
  414. if (data.user.avatar.substring(0, 9) == '/uploads/') {
  415. data.user.avatar = cndUrl + data.user.avatar
  416. }
  417. db.set('user', data.user)
  418. }
  419. /**
  420. * 刷新用户
  421. * @param {Function} callback 回调函数(用户数据)
  422. * @example
  423. * refreshUser((user)=>{_this.user = user})
  424. */
  425. function refreshUser(callback = function() {}) {
  426. let user = db.get('user');
  427. if (user.id) {
  428. api.refreshUser({}, res => {
  429. if (res.code == 1) {
  430. saveLogin(res.data)
  431. callback(res.data)
  432. } else {
  433. db.del('user');
  434. toLogin()
  435. }
  436. })
  437. } else {
  438. db.del('user');
  439. db.del('auth');
  440. toLogin()
  441. }
  442. }
  443. /**
  444. * 清理用户
  445. * @param {String} page 清理后跳转页面
  446. */
  447. function cleanUser(page) {
  448. db.del('user')
  449. db.del('auth')
  450. if (page) {
  451. redirectTo(page)
  452. }
  453. }
  454. /**
  455. * 字符串校验
  456. * @param {String} str 字符串
  457. * @param {String} model = [number|mobile|name|idcard|] 模式
  458. * @example
  459. * testString('17080057443','mobile')
  460. * testString('17080057443','mobile')
  461. */
  462. function testString(str, model = null) {
  463. if (typeof(model) == 'number') {
  464. if (str.length >= model) {
  465. return true
  466. }
  467. } else {
  468. switch (model) {
  469. case null:
  470. return false
  471. break
  472. case 'idcard':
  473. return RegExp(/^[1-9]\d{5}(19|20)\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/)
  474. .test(str)
  475. break
  476. case 'mobile':
  477. return RegExp(/^1[0-9]{10}$/).test(str)
  478. break
  479. case 'name':
  480. return RegExp(/^[\u4E00-\u9FA5\uf900-\ufa2d·s]{2,20}$/).test(str)
  481. break
  482. default:
  483. return false
  484. break
  485. }
  486. }
  487. return false
  488. }
  489. /**
  490. * 时间戳转时差
  491. * @param {String} date 时间戳
  492. */
  493. function timeToDate(time) {
  494. time = time * 1000
  495. var interval = new Date().getTime() - time;
  496. //计算出相差天数
  497. var returnTime = "";
  498. var days = Math.floor(interval / (24 * 3600 * 1000))
  499. if (days == 0) {
  500. //计算出小时数
  501. var leaveTime = interval % (24 * 3600 * 1000) //计算天数后剩余的毫秒数
  502. var hours = Math.floor(leaveTime / (3600 * 1000))
  503. if (hours == 0) {
  504. //计算相差分钟数
  505. leaveTime = leaveTime % (3600 * 1000) //计算小时数后剩余的毫秒数
  506. var minutes = Math.floor(leaveTime / (60 * 1000))
  507. if (minutes == 0) {
  508. //计算相差秒数
  509. leaveTime = leaveTime % (60 * 1000) //计算分钟数后剩余的毫秒数
  510. var seconds = Math.round(leaveTime / 1000)
  511. return seconds + "秒前";
  512. }
  513. return minutes + "分钟前";
  514. }
  515. return hours + "小时前";
  516. }
  517. return days + "天前";
  518. }
  519. /**
  520. * 基本信息
  521. */
  522. function baseInfo() {
  523. return {
  524. bgClass: bgClass,
  525. title: title,
  526. baseLogo: baseLogo,
  527. }
  528. }
  529. //校验邮箱格式
  530. function checkEmail(email) {
  531. return RegExp(/^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/).test(
  532. email);
  533. }
  534. //校验手机格式
  535. function checkMobile(mobile) {
  536. return RegExp(/^1[0-9]{10}$/).test(mobile);
  537. }
  538. /**
  539. * 用户信息
  540. */
  541. function userInfo() {
  542. let user = db.get('auth')
  543. if (user) {
  544. return user
  545. } else {
  546. return false;
  547. }
  548. // return {
  549. // bgClass: bgClass,
  550. // title: title,
  551. // baseLogo: baseLogo,
  552. // }
  553. }
  554. /**
  555. * 上传图片
  556. * @param {Array} data 附带数据
  557. * @param {Function} callback 回调函数
  558. * @param {int} num 限制数量
  559. * @param {String} type 类型
  560. * @return {String} url
  561. */
  562. function uploadImage(data = {}, callback = function() {}, num = 1, type) {
  563. api.uploadImage(
  564. 'common/upload', data, (res) => {
  565. if (res.code) {
  566. if (res.data.url.substring(0, 9) == '/uploads/') {
  567. res.data.url = cndUrl + res.data.url
  568. }
  569. callback(res.data.url)
  570. } else {
  571. errorToShow(res.msg)
  572. }
  573. }, type)
  574. }
  575. function formatRichText(html) {
  576. let newContent = html.replace(/<img[^>]*>/gi, function(match, capture) {
  577. match = match.replace(/style="[^"]+"/gi, '').replace(/style='[^']+'/gi, '');
  578. match = match.replace(/width="[^"]+"/gi, '').replace(/width='[^']+'/gi, '');
  579. match = match.replace(/height="[^"]+"/gi, '').replace(/height='[^']+'/gi, '');
  580. return match;
  581. });
  582. newContent = newContent.replace(/style="[^"]+"/gi, function(match, capture) {
  583. match = match.replace(/width:[^;]+;/gi, 'max-width:100%;').replace(/width:[^;]+;/gi, 'max-width:100%;');
  584. return match;
  585. });
  586. newContent = newContent.replace(/<br[^>]*\/>/gi, '');
  587. newContent = newContent.replace(/\<img/gi, '<img style="max-width:100%;height:auto;display:block;margin:10px 0;"');
  588. return newContent;
  589. }
  590. export {
  591. toLogin,
  592. isLogin,
  593. normalToShow,
  594. successToShow,
  595. errorToShow,
  596. isArray,
  597. loadToShow,
  598. loadToHide,
  599. navigateTo,
  600. navigateBack,
  601. redirectTo,
  602. modelShow,
  603. isWeiXinBrowser,
  604. initPages,
  605. toUrl,
  606. saveLogin,
  607. refreshUser,
  608. cleanUser,
  609. testString,
  610. timeToDate,
  611. cmsGetList,
  612. cmsGetDetails,
  613. baseInfo,
  614. userInfo,
  615. uploadImage,
  616. checkEmail,
  617. checkMobile,
  618. formatRichText
  619. }