util.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. import CONSTANT from "@/constant";
  2. import { mobileReg } from "@/utils/tools/validate";
  3. import { getMiniAppUrl, isWxBrowser } from "@/utils/common";
  4. import permision from "@/utils/wa-permission_1.1/permission.js";
  5. import { afterAppLoginSuccess } from "@/utils/appDevice.js";
  6. // 是否为空
  7. const isEmpty = val => {
  8. if (val instanceof Array) {
  9. if (val.length === 0){
  10. return true
  11. }
  12. } else if (val instanceof Object) {
  13. if (Object.keys(val).length == 0){
  14. return true
  15. }
  16. } else {
  17. if ( val === "null" || val === null || val === "undefined" || val === undefined || val === "" || JSON.stringify(val) == "[]"){
  18. return true
  19. }
  20. return false;
  21. }
  22. return false;
  23. };
  24. /**
  25. * 深拷贝对象
  26. * @param {要拷贝对象} obj
  27. */
  28. export const copyObject = obj => {
  29. let str,
  30. newobj = Array.isArray(obj) === true ? [] : {};
  31. if (typeof obj !== "object") {
  32. return;
  33. } else if (JSON) {
  34. (str = JSON.stringify(obj)), //系列化对象
  35. (newobj = JSON.parse(str)); //还原
  36. } else {
  37. for (let i in obj) {
  38. newobj[i] = typeof obj[i] === "object" ? copyObject(obj[i]) : obj[i];
  39. }
  40. }
  41. return newobj;
  42. };
  43. const numberFormat = (number, type) => {
  44. if(number > 100000000){
  45. let num = (number / 100000000 + "").split(".");
  46. return `${num[0]}.${("" + num[1]).slice(0, 1)} 亿`;
  47. }else if (number > 10000) {
  48. let num = (number / 10000 + "").split(".");
  49. return `${num[0]}.${("" + num[1]).slice(0, 1)} 万`;
  50. } else {
  51. return parseFloat(Number(number))
  52. }
  53. };
  54. // 截取图片上传字符串
  55. const imgSubstr = val => {
  56. if (isEmpty(val)) return [];
  57. if (isArray(val)) {
  58. return val.map(e => {
  59. let index = e.indexOf("/uploads/");
  60. e = e.substring(index);
  61. return e;
  62. });
  63. } else {
  64. let index = val.indexOf("/uploads/");
  65. return val.substring(index);
  66. }
  67. };
  68. // 是否为数组
  69. const isArray = arr => {
  70. return typeof arr == "object" && arr.constructor == Array;
  71. };
  72. // 是否为字符串
  73. const isString = str => {
  74. return typeof str == "string" && str.constructor == String;
  75. };
  76. // 是否为对象
  77. const isObject = obj => {
  78. return typeof obj == "object" && obj.constructor == Object;
  79. };
  80. // 是否为数字
  81. const isNumber = num => {
  82. return typeof num == "number" && num.constructor == Number;
  83. };
  84. //是否金额
  85. const isMoney = money =>{
  86. return /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/.test(money)
  87. }
  88. // 是否为日期类型
  89. const isDate = date => {
  90. return typeof date == "object" && date.constructor == Date;
  91. };
  92. // 是否为函数
  93. const isFunction = obj => {
  94. return typeof obj == "object" && obj.constructor == Function;
  95. };
  96. const checkMobile = num => {
  97. return mobileReg.test(num);
  98. };
  99. const checkName = str => {
  100. return /^[\u4E00-\u9FA5A-Za-z\s]+(·[\u4E00-\u9FA5A-Za-z]+)*$/.test(str);
  101. };
  102. /** *
  103. * 检查登录
  104. * @parmas query 拼接得参数对象
  105. * @parmas isFrist 为true时开头为&
  106. */
  107. export async function getCheckLogin() {
  108. let status = false;
  109. let token = uni.getStorageSync("token");
  110. if (token) {
  111. status = true;
  112. } else {
  113. // #ifdef H5
  114. if (isWxBrowser()) {
  115. let option = JSON.parse(uni.getStorageSync("currentQuery")) || {};
  116. location.href = `${CONSTANT.hostUrl}/auth/prepare?url=${encodeURIComponent(
  117. getMiniAppUrl(option, true)
  118. )}`;
  119. }
  120. // #endif
  121. // #ifndef H5
  122. // #endif
  123. }
  124. return status;
  125. }
  126. export const floatFormat = (f, n) => {
  127. let m = Math.pow(10, n);
  128. return parseInt(f * m, 10) / m;
  129. };
  130. /** *
  131. * 对象参数转为url参数
  132. * @parmas query 拼接得参数对象
  133. * @parmas isFrist 为true时开头为&
  134. */
  135. export const parse = (query, isFrist = false) => {
  136. let str = Object.keys(query)
  137. .filter(key => !isEmpty(query[key]))
  138. .reduce((result, key) => {
  139. const value = query[key];
  140. // in查询特殊处理
  141. if (Array.isArray(value) && !isEmpty(value)) {
  142. return `${result}&${value.reduce(
  143. (val, cVal) => `${val ? `${val}&` : val}${key}=${cVal}`,
  144. ""
  145. )}`;
  146. }
  147. // between查询做特殊处理
  148. if (typeof value === "object" && !isEmpty(value)) {
  149. const [start, end] = value;
  150. return `${result}&${key}[]=${start}&${key}[]=${end}`;
  151. }
  152. return `${result}&${key}=${value}`;
  153. }, "");
  154. return isFrist ? str : str.replace(/^&/, "?");
  155. };
  156. /** *
  157. * 全局时间转换
  158. * @parmas num 时间戳默认为11位时间戳
  159. * @parmas fmt 默认转换的时间格式
  160. * @parmas all 为true时time为13位时间戳
  161. */
  162. export const $formatDate = (num, fmt = "YYYY-MM-DD HH:mm", all) => {
  163. num = all ? num : num * 1000;
  164. let date = new Date();
  165. date.setTime(num);
  166. let o = {
  167. "M+": date.getMonth() + 1,
  168. "D+": date.getDate(),
  169. "h+": date.getHours() % 12 === 0 ? 12 : date.getHours() % 12,
  170. "H+": date.getHours(),
  171. "m+": date.getMinutes(),
  172. "s+": date.getSeconds(),
  173. "q+": Math.floor((date.getMonth() + 3) / 3),
  174. S: date.getMilliseconds()
  175. };
  176. let week = {
  177. "0": "\u65e5",
  178. "1": "\u4e00",
  179. "2": "\u4e8c",
  180. "3": "\u4e09",
  181. "4": "\u56db",
  182. "5": "\u4e94",
  183. "6": "\u516d"
  184. };
  185. if (/(Y+)/.test(fmt)) {
  186. fmt = fmt.replace(
  187. RegExp.$1,
  188. (date.getFullYear() + "").substr(4 - RegExp.$1.length)
  189. );
  190. }
  191. if (/(E+)/.test(fmt)) {
  192. fmt = fmt.replace(
  193. RegExp.$1,
  194. (RegExp.$1.length > 1
  195. ? RegExp.$1.length > 2
  196. ? "\u661f\u671f"
  197. : "\u5468"
  198. : "") + week[date.getDay() + ""]
  199. );
  200. }
  201. for (let k in o) {
  202. if (new RegExp("(" + k + ")").test(fmt)) {
  203. fmt = fmt.replace(
  204. RegExp.$1,
  205. RegExp.$1.length === 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length)
  206. );
  207. }
  208. }
  209. return fmt;
  210. };
  211. /** *
  212. * 全局公共按钮跳转
  213. * @parmas item.funtion 为可执行函数
  214. * @parmas item.url 为跳转的路径
  215. * @parmas item.query 为跳转携带的参数
  216. * @parmas item.type 为跳转调用的函数 1为navigateTo, 2为redirectTo 关闭当前页面,跳转到应用内的某个页面 3为reLaunch 关闭所有页面,打开到应用内的某个页面 4为switchTab
  217. */
  218. export const pageTo = item => {
  219. if (isNumber(item)) {
  220. uni.navigateBack({
  221. delta: item
  222. });
  223. }
  224. if (isString(item)) {
  225. uni.navigateTo({
  226. url: item
  227. });
  228. return false;
  229. }
  230. if (item.funtion) {
  231. item.funtion();
  232. }
  233. if (item.url) {
  234. let query = item.query ? parse(item.query) : "";
  235. let allUrl = `${item.url}${query}`;
  236. if (item.type == 2) {
  237. uni.redirectTo({
  238. url: allUrl,
  239. success(res) {
  240. },
  241. fail(err) {
  242. console.log(err);
  243. }
  244. });
  245. } else if (item.type == 3) {
  246. uni.reLaunch({
  247. url: allUrl,
  248. success(res) {
  249. },
  250. fail(err) {
  251. console.log(err);
  252. }
  253. });
  254. } else if (item.type == 4) {
  255. uni.setStorageSync("switchTabQuery", item.query);
  256. uni.switchTab({
  257. url: item.url,
  258. success(res) {
  259. },
  260. fail(err) {
  261. console.log(err);
  262. }
  263. });
  264. } else {
  265. uni.navigateTo({
  266. url: allUrl,
  267. success(res) {
  268. },
  269. fail(err) {
  270. console.log(err);
  271. }
  272. });
  273. }
  274. }
  275. };
  276. /** *
  277. * 是否登录
  278. */
  279. export const isLogin = () => {
  280. let token = uni.getStorageSync("token");
  281. if (token) {
  282. return true;
  283. }
  284. return false;
  285. };
  286. export async function callUp(mobile){
  287. //#ifdef MP-WEIXIN
  288. uni.makePhoneCall({phoneNumber: mobile})
  289. //#endif
  290. //#ifdef APP-PLUS
  291. let env = uni.getSystemInfoSync().platform
  292. if(env == 'android'){
  293. //Android是动态权限,请求权限状态时会触发弹框询问是否赋权(如果已经同意或永久禁止则不会询问),所以必须使用异步方式来处理
  294. var result = await permision.requestAndroidPermission('android.permission.CALL_PHONE')
  295. if(Number(result) == -1){
  296. confirmModal({content:'请在权限管理中开启【拨打电话】','okText':'去开启'},() => {
  297. permision.gotoAppPermissionSetting()
  298. })
  299. return
  300. }
  301. }
  302. uni.makePhoneCall({phoneNumber: mobile})
  303. //#endif
  304. }
  305. // 库存不足提示音 - 缓存对象,避免重复创建
  306. let noStockAudioContext = null
  307. let lastNoStockPlayTime = 0
  308. const NO_STOCK_MIN_INTERVAL = 1000
  309. const initNoStockAudio = () => {
  310. if (noStockAudioContext) return
  311. try {
  312. if (uni.getSystemInfoSync().platform === 'windows') return
  313. noStockAudioContext = uni.createInnerAudioContext()
  314. noStockAudioContext.autoplay = false
  315. noStockAudioContext.src = "/static/noStock.mp3"
  316. noStockAudioContext.volume = 1
  317. } catch (e) {
  318. console.error('[noStockRemind] 初始化失败:', e)
  319. noStockAudioContext = null
  320. }
  321. }
  322. export const noStockRemind = () => {
  323. try {
  324. // 防抖:1秒内只播放一次
  325. const now = Date.now()
  326. if (now - lastNoStockPlayTime < NO_STOCK_MIN_INTERVAL) {
  327. return
  328. }
  329. // 初始化音频
  330. if (!noStockAudioContext) {
  331. initNoStockAudio()
  332. }
  333. if (!noStockAudioContext) {
  334. return
  335. }
  336. // 更新时间戳
  337. lastNoStockPlayTime = now
  338. // 停止之前的播放
  339. try {
  340. noStockAudioContext.stop()
  341. } catch (e) {
  342. // 忽略停止失败
  343. }
  344. // 设置音量并播放
  345. noStockAudioContext.volume = 1
  346. try {
  347. noStockAudioContext.play()
  348. } catch (playError) {
  349. console.error('[noStockRemind] 播放异常:', playError)
  350. noStockAudioContext = null
  351. }
  352. } catch (e) {
  353. console.error('[noStockRemind] 执行出错:', e)
  354. }
  355. }
  356. // 点击声效 - 缓存对象,避免重复创建
  357. let hitAudioContext = null
  358. let lastHitPlayTime = 0
  359. const HIT_MIN_INTERVAL = 100
  360. const initHitAudio = () => {
  361. if (hitAudioContext) return
  362. try {
  363. if (uni.getSystemInfoSync().platform === 'windows') return
  364. hitAudioContext = uni.createInnerAudioContext()
  365. hitAudioContext.autoplay = false
  366. hitAudioContext.src = '/static/hit.mp3'
  367. hitAudioContext.volume = 1
  368. } catch (e) {
  369. console.error('[hitRemind] 初始化失败:', e)
  370. hitAudioContext = null
  371. }
  372. }
  373. export const hitRemind = () => {
  374. try {
  375. // 防抖:100ms 内只播放一次
  376. const now = Date.now()
  377. if (now - lastHitPlayTime < HIT_MIN_INTERVAL) {
  378. return
  379. }
  380. // 初始化音频
  381. if (!hitAudioContext) {
  382. initHitAudio()
  383. }
  384. if (!hitAudioContext) {
  385. return
  386. }
  387. // 更新时间戳
  388. lastHitPlayTime = now
  389. // 停止之前的播放
  390. try {
  391. hitAudioContext.stop()
  392. } catch (e) {
  393. // 忽略停止失败
  394. }
  395. // 设置音量并播放
  396. hitAudioContext.volume = 1
  397. try {
  398. hitAudioContext.play()
  399. } catch (playError) {
  400. console.error('[hitRemind] 播放异常:', playError)
  401. hitAudioContext = null
  402. }
  403. } catch (e) {
  404. console.error('[hitRemind] 执行出错:', e)
  405. }
  406. }
  407. //去重 姜枫 2021.05.05
  408. export const unique = (arr) => {
  409. for(var i=0; i<arr.length; i++){
  410. for(var j=i+1; j<arr.length; j++){
  411. if(arr[i].classId==arr[j].classId){ //第一个等同于第二个,splice方法删除第二个
  412. arr.splice(j,1);
  413. j--;
  414. }
  415. }
  416. }
  417. return arr;
  418. };
  419. //#ifdef APP-PLUS
  420. const CLDialog=uni.requireNativePlugin("CL-Dialog")
  421. //#endif
  422. export const confirmModal = (item,okCallback=null,cancelCallback=null) => {
  423. let title = item.title || '提示'
  424. let content = item.content || '确认操作?'
  425. let okText = item.okText || '确认'
  426. let cancelText = item.cancelText || '取消'
  427. let cacelTextColor = '#999999'
  428. let okTextColor = '#38ADFF'
  429. let singer = item.singer || false
  430. //#ifdef APP-PLUS
  431. let platform=uni.getSystemInfoSync().platform
  432. if(platform=='ios'){
  433. uni.showModal({
  434. title: title,
  435. content: content,
  436. showCancel: true,
  437. cancelText: cancelText,
  438. cancelColor: cacelTextColor,
  439. confirmText: okText,
  440. confirmColor: okTextColor,
  441. success: function (res) {
  442. if (res.confirm) {
  443. if(okCallback!=null){
  444. okCallback()
  445. }
  446. } else if (res.cancel) {
  447. if(cancelCallback!=null){
  448. cancelCallback()
  449. }
  450. }
  451. }
  452. })
  453. }else if(platform=='android'){
  454. let options={
  455. title:title,//内容(可选)但是标题和内容至少选择一个
  456. con:content,
  457. okTitle:okText,//确认按钮文字(可选)
  458. cancleTitle:cancelText,//取消按钮文字(可选)
  459. okTextColor:"#38ADFF",//确认按钮颜色(可选)
  460. cancleTextColor:"#999999",//取消按钮颜色(可选)
  461. singer:singer,//是否只显示确认按钮,默认false(可选)
  462. textAlign:"center",//对齐方式 //left居左,center居中,right 居右 默认居中
  463. conColor:"",
  464. bgColor:"#FFFFFF",//自定义弹框颜色
  465. titleColor:"#3d3d3d"//自定义title颜色
  466. }
  467. CLDialog.show(options,()=>{
  468. if(okCallback!=null){
  469. okCallback()
  470. }
  471. },()=>{
  472. if(cancelCallback!=null){
  473. cancelCallback()
  474. }
  475. })
  476. }
  477. //#endif
  478. // #ifdef MP-WEIXIN
  479. uni.showModal({
  480. title: title,
  481. content: content,
  482. showCancel: true,
  483. cancelText: cancelText,
  484. cancelColor: cacelTextColor,
  485. confirmText: okText,
  486. confirmColor: okTextColor,
  487. success: function (res) {
  488. if (res.confirm) {
  489. if(okCallback!=null){
  490. okCallback()
  491. }
  492. } else if (res.cancel) {
  493. if(cancelCallback!=null){
  494. cancelCallback()
  495. }
  496. }
  497. }
  498. })
  499. //#endif
  500. }
  501. //判断是否有扫码的条件
  502. export const isScanEnv = () =>{
  503. let isScanEnv = false
  504. //#ifdef APP-PLUS
  505. if(plus.device.vendor == 'Newland'){
  506. isScanEnv = true
  507. }
  508. //#endif
  509. return isScanEnv
  510. }
  511. /** 海报/太阳码:开发构建用 develop,正式构建用 release */
  512. export const getMiniEnvVersion = () => {
  513. return process.env.NODE_ENV === 'development' ? 'develop' : 'release'
  514. }
  515. export default {
  516. isEmpty,
  517. copyObject,
  518. imgSubstr,
  519. isArray,
  520. parse,
  521. checkMobile,
  522. checkName,
  523. $formatDate,
  524. floatFormat,
  525. pageTo,
  526. isLogin,
  527. getCheckLogin,
  528. numberFormat,
  529. isString,
  530. unique,
  531. isMoney,
  532. isNumber,
  533. noStockRemind,
  534. callUp,
  535. hitRemind,
  536. confirmModal,
  537. isScanEnv,
  538. afterAppLoginSuccess,
  539. getMiniEnvVersion
  540. };