util.js 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. import CONSTANT from '@/constant'
  2. import { mobileReg } from '@/utils/tools/validate'
  3. import { getMiniAppUrl, isWxBrowser } from '@/utils/common'
  4. import { TOKEN_STORAGE_KEY } from '@/constant/storageKeys'
  5. // 是否为空
  6. const isEmpty = (val) => {
  7. if (val instanceof Array) {
  8. if (val.length === 0) return true
  9. } else if (val instanceof Object) {
  10. if (!Object.keys(val).length) return true
  11. } else {
  12. if (val === 'null' || val === null || val === 'undefined' || val === undefined || val === '') return true
  13. return false
  14. }
  15. return false
  16. }
  17. /**
  18. * 深拷贝对象
  19. * @param {要拷贝对象} obj
  20. */
  21. export const copyObject = obj => {
  22. let str,
  23. newobj = Array.isArray(obj) === true ? [] : {};
  24. if (typeof obj !== "object") {
  25. return;
  26. } else if (JSON) {
  27. (str = JSON.stringify(obj)), //系列化对象
  28. (newobj = JSON.parse(str)); //还原
  29. } else {
  30. for (let i in obj) {
  31. newobj[i] = typeof obj[i] === "object" ? copyObject(obj[i]) : obj[i];
  32. }
  33. }
  34. return newobj;
  35. };
  36. // 截取图片上传字符串
  37. const imgSubstr = (val) => {
  38. if (isEmpty(val)) return []
  39. if (isArray(val)) {
  40. return val.map(e => {
  41. let index = e.indexOf('/uploads/')
  42. e = e.substring(index)
  43. return e
  44. })
  45. } else {
  46. let index = val.indexOf('/uploads/')
  47. return val.substring(index)
  48. }
  49. }
  50. // 是否为数组
  51. const isArray = (arr) => {
  52. return (typeof arr == 'object') && arr.constructor == Array
  53. }
  54. // 是否为字符串
  55. const isString = (str) => {
  56. return (typeof str == 'string') && str.constructor == String
  57. }
  58. // 是否为对象
  59. const isObject = (obj) => {
  60. return (typeof obj == 'object') && obj.constructor == Object
  61. }
  62. // 是否为数字
  63. const isNumber = (num) => {
  64. return (typeof num == 'number') && num.constructor == Number
  65. }
  66. // 是否为整数
  67. const isInteger = (num) => {
  68. return (typeof num == 'number') && num.constructor == Number && num % 1 === 0
  69. }
  70. // 是否为日期类型
  71. const isDate = (date) => {
  72. return (typeof date == 'object') && date.constructor == Date
  73. }
  74. // 是否为函数
  75. const isFunction = (obj) => {
  76. return (typeof obj == 'object') && obj.constructor == Function
  77. }
  78. const checkMobile = (num) => {
  79. return mobileReg.test(num)
  80. }
  81. const checkName = (str) => {
  82. return /^[\u4E00-\u9FA5A-Za-z\s]+(·[\u4E00-\u9FA5A-Za-z]+)*$/.test(str)
  83. }
  84. /** *
  85. * 检查登录
  86. * @parmas query 拼接得参数对象
  87. * @parmas isFrist 为true时开头为&
  88. */
  89. export async function getCheckLogin() {
  90. let status = false
  91. let token = uni.getStorageSync(TOKEN_STORAGE_KEY)
  92. if (token) {
  93. status = true
  94. } else {
  95. // #ifdef H5
  96. if (isWxBrowser()) {
  97. let option = JSON.parse(uni.getStorageSync('currentQuery')) || {}
  98. console.log('option', option)
  99. // console.log('option', getMiniAppUrl(option, true))
  100. // return false
  101. location.href = `${CONSTANT.hostUrl}/auth/prepare?url=${encodeURIComponent(getMiniAppUrl(option, true))}`
  102. } else {
  103. // uni.showToast({
  104. // title: '请用微信浏览器打开!',
  105. // icon: 'none',
  106. // mask: true
  107. // })
  108. }
  109. // #endif
  110. // #ifndef H5
  111. // #endif
  112. }
  113. return status
  114. }
  115. export const floatFormat = (f, n) => {
  116. let m = Math.pow(10, n)
  117. return parseInt(f * m, 10) / m
  118. }
  119. /** *
  120. * 对象参数转为url参数
  121. * @parmas query 拼接得参数对象
  122. * @parmas isFrist 为true时开头为&
  123. */
  124. export const parse = (query, isFrist = false) => {
  125. let str = Object.keys(query)
  126. .filter(key => !isEmpty(query[key]))
  127. .reduce((result, key) => {
  128. const value = query[key]
  129. // in查询特殊处理
  130. if (Array.isArray(value) && !isEmpty(value)) {
  131. return `${result}&${value.reduce((val, cVal) => `${val ? `${val}&` : val}${key}=${cVal}`, '')}`
  132. }
  133. // between查询做特殊处理
  134. if (typeof value === 'object' && !isEmpty(value)) {
  135. const [start, end] = value
  136. return `${result}&${key}[]=${start}&${key}[]=${end}`
  137. }
  138. return `${result}&${key}=${value}`
  139. }, '')
  140. return isFrist ? str : str.replace(/^&/, '?')
  141. }
  142. /** *
  143. * 全局时间转换
  144. * @parmas num 时间戳默认为11位时间戳
  145. * @parmas fmt 默认转换的时间格式
  146. * @parmas all 为true时time为13位时间戳
  147. */
  148. export const $formatDate = (num, fmt = 'YYYY-MM-DD HH:mm', all) => {
  149. num = all ? num : num * 1000
  150. let date = new Date()
  151. date.setTime(num)
  152. let o = {
  153. 'M+': date.getMonth() + 1,
  154. 'D+': date.getDate(),
  155. 'h+': date.getHours() % 12 === 0 ? 12 : date.getHours() % 12,
  156. 'H+': date.getHours(),
  157. 'm+': date.getMinutes(),
  158. 's+': date.getSeconds(),
  159. 'q+': Math.floor((date.getMonth() + 3) / 3),
  160. 'S': date.getMilliseconds()
  161. }
  162. let week = {
  163. '0': '\u65e5',
  164. '1': '\u4e00',
  165. '2': '\u4e8c',
  166. '3': '\u4e09',
  167. '4': '\u56db',
  168. '5': '\u4e94',
  169. '6': '\u516d'
  170. }
  171. if (/(Y+)/.test(fmt)) {
  172. fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
  173. }
  174. if (/(E+)/.test(fmt)) {
  175. fmt = fmt.replace(RegExp.$1, ((RegExp.$1.length > 1) ? (RegExp.$1.length > 2 ? '\u661f\u671f' : '\u5468') : '') + week[date.getDay() + ''])
  176. }
  177. for (let k in o) {
  178. if (new RegExp('(' + k + ')').test(fmt)) {
  179. fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)))
  180. }
  181. }
  182. return fmt
  183. }
  184. /** *
  185. * 全局公共按钮跳转
  186. * @parmas item.funtion 为可执行函数
  187. * @parmas item.url 为跳转的路径
  188. * @parmas item.query 为跳转携带的参数
  189. * @parmas item.type 为跳转调用的函数 1为navigateTo, 2为redirectTo, 3为reLaunch, 4为switchTab
  190. */
  191. export const pageTo = (item) => {
  192. if (isNumber(item)) {
  193. uni.navigateBack({
  194. delta: item
  195. })
  196. }
  197. if (isString(item)) {
  198. uni.navigateTo({
  199. url: item
  200. })
  201. return false
  202. }
  203. if (item.funtion) {
  204. item.funtion()
  205. }
  206. if (item.url) {
  207. let query = item.query ? parse(item.query) : ''
  208. let allUrl = `${item.url}${query}`
  209. if (item.type == 2) {
  210. uni.redirectTo({
  211. url: allUrl
  212. })
  213. } else if (item.type == 3) {
  214. uni.reLaunch({
  215. url: allUrl
  216. })
  217. } else if (item.type == 4) {
  218. console.log('item', item)
  219. console.log('switch shop', item.query)
  220. uni.setStorageSync('switchTabQuery', item.query)
  221. if (item.query.account) {
  222. uni.setStorageSync('account', item.query.account)
  223. }
  224. uni.switchTab({
  225. url: item.url
  226. })
  227. } else {
  228. uni.navigateTo({
  229. url: allUrl
  230. })
  231. }
  232. }
  233. }
  234. /** *
  235. * 是否登录
  236. */
  237. export const isLogin = () => {
  238. let token = uni.getStorageSync(TOKEN_STORAGE_KEY)
  239. if (token) {
  240. return true
  241. }
  242. return false
  243. }
  244. /**
  245. * 去重
  246. * 姜枫 2021.05.05
  247. * **/
  248. export const unique = (arr) => {
  249. for(var i=0; i<arr.length; i++){
  250. for(var j=i+1; j<arr.length; j++){
  251. if(arr[i].classId==arr[j].classId){ //第一个等同于第二个,splice方法删除第二个
  252. arr.splice(j,1);
  253. j--;
  254. }
  255. }
  256. }
  257. return arr;
  258. };
  259. // 点击声效 - 缓存对象,避免重复创建
  260. let hitAudioContext = null
  261. let lastHitPlayTime = 0
  262. const HIT_MIN_INTERVAL = 100
  263. const initHitAudio = () => {
  264. if (hitAudioContext) return
  265. try {
  266. if (uni.getSystemInfoSync().platform === 'windows') return
  267. hitAudioContext = uni.createInnerAudioContext()
  268. hitAudioContext.autoplay = false
  269. hitAudioContext.src = '/static/hit.mp3'
  270. hitAudioContext.volume = 1
  271. } catch (e) {
  272. console.error('[hitRemind] 初始化失败:', e)
  273. hitAudioContext = null
  274. }
  275. }
  276. export const hitRemind = () => {
  277. try {
  278. // 防抖:100ms 内只播放一次
  279. const now = Date.now()
  280. if (now - lastHitPlayTime < HIT_MIN_INTERVAL) {
  281. return
  282. }
  283. // 初始化音频
  284. if (!hitAudioContext) {
  285. initHitAudio()
  286. }
  287. if (!hitAudioContext) {
  288. return
  289. }
  290. // 更新时间戳
  291. lastHitPlayTime = now
  292. // 停止之前的播放
  293. try {
  294. hitAudioContext.stop()
  295. } catch (e) {
  296. // 忽略停止失败
  297. }
  298. // 设置音量并播放
  299. hitAudioContext.volume = 1
  300. try {
  301. hitAudioContext.play()
  302. } catch (playError) {
  303. console.error('[hitRemind] 播放异常:', playError)
  304. hitAudioContext = null
  305. }
  306. } catch (e) {
  307. console.error('[hitRemind] 执行出错:', e)
  308. }
  309. }
  310. //#ifdef APP-PLUS
  311. const CLDialog=uni.requireNativePlugin("CL-Dialog")
  312. //#endif
  313. export const confirmModal = (item,okCallback=null,cancelCallback=null) => {
  314. let title = item.title || '提示'
  315. let content = item.content || '确认操作?'
  316. let okText = item.okText || '确认'
  317. let cancelText = item.cancelText || '取消'
  318. let cacelTextColor = '#999999'
  319. let okTextColor = '#38ADFF'
  320. let singer = item.singer || false
  321. //#ifdef APP-PLUS
  322. let platform=uni.getSystemInfoSync().platform
  323. if(platform=='ios'){
  324. uni.showModal({
  325. title: title,
  326. content: content,
  327. showCancel: true,
  328. cancelText: cancelText,
  329. cancelColor: cacelTextColor,
  330. confirmText: okText,
  331. confirmColor: okTextColor,
  332. success: function (res) {
  333. if (res.confirm) {
  334. if(okCallback!=null){
  335. okCallback()
  336. }
  337. } else if (res.cancel) {
  338. if(cancelCallback!=null){
  339. cancelCallback()
  340. }
  341. }
  342. }
  343. })
  344. }else if(platform=='android'){
  345. let options={
  346. title:title,//内容(可选)但是标题和内容至少选择一个
  347. con:content,
  348. okTitle:okText,//确认按钮文字(可选)
  349. cancleTitle:cancelText,//取消按钮文字(可选)
  350. okTextColor:"#38ADFF",//确认按钮颜色(可选)
  351. cancleTextColor:"#999999",//取消按钮颜色(可选)
  352. singer:singer,//是否只显示确认按钮,默认false(可选)
  353. textAlign:"center",//对齐方式 //left居左,center居中,right 居右 默认居中
  354. conColor:"",
  355. bgColor:"#FFFFFF",//自定义弹框颜色
  356. titleColor:"#3d3d3d"//自定义title颜色
  357. }
  358. CLDialog.show(options,()=>{
  359. if(okCallback!=null){
  360. okCallback()
  361. }
  362. },()=>{
  363. if(cancelCallback!=null){
  364. cancelCallback()
  365. }
  366. })
  367. }
  368. //#endif
  369. // #ifdef MP-WEIXIN
  370. uni.showModal({
  371. title: title,
  372. content: content,
  373. showCancel: true,
  374. cancelText: cancelText,
  375. cancelColor: cacelTextColor,
  376. confirmText: okText,
  377. confirmColor: okTextColor,
  378. success: function (res) {
  379. if (res.confirm) {
  380. if(okCallback!=null){
  381. okCallback()
  382. }
  383. } else if (res.cancel) {
  384. if(cancelCallback!=null){
  385. cancelCallback()
  386. }
  387. }
  388. }
  389. })
  390. //#endif
  391. }
  392. export default {
  393. isEmpty,
  394. copyObject,
  395. imgSubstr,
  396. isArray,
  397. parse,
  398. checkMobile,
  399. checkName,
  400. $formatDate,
  401. floatFormat,
  402. pageTo,
  403. isLogin,
  404. getCheckLogin,
  405. unique,
  406. confirmModal,
  407. hitRemind,
  408. }