util.js 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293
  1. // +----------------------------------------------------------------------
  2. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  3. // +----------------------------------------------------------------------
  4. // | Copyright (c) 2016~2021 https://www.crmeb.com All rights reserved.
  5. // +----------------------------------------------------------------------
  6. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  7. // +----------------------------------------------------------------------
  8. // | Author: CRMEB Team <admin@crmeb.com>
  9. // +----------------------------------------------------------------------
  10. import {
  11. TOKENNAME,
  12. HTTP_REQUEST_URL
  13. } from '../config/app.js';
  14. import store from '../store';
  15. import {
  16. customerType
  17. } from '@/api/api.js'
  18. // #ifdef APP-PLUS
  19. import permision from "./permission.js"
  20. // #endif
  21. export default {
  22. /**
  23. * opt object | string
  24. * to_url object | string
  25. * 例:
  26. * this.Tips('/pages/test/test'); 跳转不提示
  27. * this.Tips({title:'提示'},'/pages/test/test'); 提示并跳转
  28. * this.Tips({title:'提示'},{tab:1,url:'/pages/index/index'}); 提示并跳转值table上
  29. * tab=1 一定时间后跳转至 table上
  30. * tab=2 一定时间后跳转至非 table上
  31. * tab=3 一定时间后返回上页面
  32. * tab=4 关闭所有页面,打开到应用内的某个页面
  33. * tab=5 关闭当前页面,跳转到应用内的某个页面
  34. */
  35. Tips: function(opt, to_url) {
  36. if (typeof opt == 'string') {
  37. to_url = opt;
  38. opt = {};
  39. }
  40. let title = opt.title || '',
  41. icon = opt.icon || 'none',
  42. endtime = opt.endtime || 2000,
  43. success = opt.success;
  44. if (title) uni.showToast({
  45. title: title,
  46. icon: icon,
  47. duration: endtime,
  48. success
  49. })
  50. if (to_url != undefined) {
  51. if (typeof to_url == 'object') {
  52. let tab = to_url.tab || 1,
  53. url = to_url.url || '';
  54. switch (tab) {
  55. case 1:
  56. //一定时间后跳转至 table
  57. setTimeout(function() {
  58. uni.navigateTo({
  59. url: url
  60. })
  61. }, endtime);
  62. break;
  63. case 2:
  64. //跳转至非table页面
  65. setTimeout(function() {
  66. uni.navigateTo({
  67. url: url,
  68. })
  69. }, endtime);
  70. break;
  71. case 3:
  72. //返回上页面
  73. setTimeout(function() {
  74. // #ifndef H5
  75. uni.navigateBack({
  76. delta: parseInt(url),
  77. })
  78. // #endif
  79. // #ifdef H5
  80. history.back();
  81. // #endif
  82. }, endtime);
  83. break;
  84. case 4:
  85. //关闭所有页面,打开到应用内的某个页面
  86. setTimeout(function() {
  87. uni.reLaunch({
  88. url: url,
  89. })
  90. }, endtime);
  91. break;
  92. case 5:
  93. //关闭当前页面,跳转到应用内的某个页面
  94. setTimeout(function() {
  95. uni.redirectTo({
  96. url: url,
  97. })
  98. }, endtime);
  99. break;
  100. }
  101. } else if (typeof to_url == 'function') {
  102. setTimeout(function() {
  103. to_url && to_url();
  104. }, endtime);
  105. } else {
  106. //没有提示时跳转不延迟
  107. setTimeout(function() {
  108. uni.navigateTo({
  109. url: to_url,
  110. })
  111. }, title ? endtime : 0);
  112. }
  113. }
  114. },
  115. // 处理价格
  116. HandlePrice: function(num, type) {
  117. let obj = []
  118. if (typeof num == 'number') {
  119. obj = num.toString().split(".");
  120. } else {
  121. obj = num.split(".");
  122. }
  123. if (type) {
  124. if (obj.length) {
  125. return '.' + obj[1];
  126. } else {
  127. return ''
  128. }
  129. } else {
  130. return obj[0];
  131. }
  132. },
  133. // 将网络图片转化为base64
  134. getBase64Image: function(imageUrl) {
  135. return new Promise((resolve, reject) => {
  136. uni.request({
  137. url: imageUrl, // 服务器图片地址
  138. responseType: 'arraybuffer', // 设置响应类型为arraybuffer以接收二进制数据
  139. success: (res) => {
  140. let base64Image = 'data:image/jpeg;base64,' + uni.arrayBufferToBase64(res.data);
  141. resolve(base64Image);
  142. },
  143. fail: (err) => {
  144. reject(err);
  145. }
  146. });
  147. });
  148. },
  149. // 计算头部自定义导航高度;
  150. getWXStatusHeight() {
  151. // 获取距上
  152. const barTop = uni.getSystemInfoSync().statusBarHeight;
  153. // #ifdef MP
  154. // 获取胶囊按钮位置信息
  155. const menuButtonInfo = wx.getMenuButtonBoundingClientRect() || 0
  156. // 获取导航栏高度
  157. const barHeight = menuButtonInfo.height + (menuButtonInfo.top - barTop) * 2
  158. let barWidth = menuButtonInfo.width
  159. // #endif
  160. // #ifndef MP
  161. // 获取导航栏高度
  162. const barHeight = parseInt(barTop) + 10;
  163. let barWidth = '100%'
  164. // #endif
  165. return {
  166. barHeight,
  167. barTop,
  168. barWidth
  169. }
  170. },
  171. /**
  172. * 省市区地址分解
  173. */
  174. addressInfo: function(str) {
  175. let reg = /.+?(省|市|自治区|自治州|行政区|盟|旗|县|区)/g // 省市区的正则
  176. const area = str.match(reg) // 分割省市区
  177. let citys = ['北京市', '天津市', '上海市', '重庆市']
  178. let address_component = {
  179. city: "",
  180. district: "",
  181. province: area[0]
  182. }
  183. if (citys.indexOf(area[0]) == -1) {
  184. address_component.city = area[1]
  185. address_component.district = area[2]
  186. } else {
  187. address_component.city = area[0]
  188. address_component.district = area[1]
  189. }
  190. return address_component
  191. },
  192. /**
  193. * 跳转路径封装函数
  194. * @param url 跳转路径
  195. * 选择跳转到其他小程序时,在h5也可以跳转路径
  196. */
  197. JumpPath: function(url) {
  198. let arr = url.split('@APPID=');
  199. if (arr.length > 1) {
  200. //#ifdef MP
  201. uni.navigateToMiniProgram({
  202. appId: arr[arr.length - 1], // 此为生活缴费appid
  203. path: arr[0], // 此为生活缴费首页路径
  204. envVersion: "release",
  205. success: res => {
  206. console.log("打开成功", res);
  207. },
  208. fail: err => {
  209. console.log('sgdhgf', err);
  210. }
  211. })
  212. //#endif
  213. //#ifndef MP
  214. this.Tips({
  215. title: 'h5与app端不支持跳转外部小程序'
  216. });
  217. //#endif
  218. } else {
  219. if (url == '/pages/short_video/appSwiper/index' || url == '/pages/short_video/nvueSwiper/index') {
  220. //#ifdef APP
  221. url = '/pages/short_video/appSwiper/index'
  222. //#endif
  223. //#ifndef APP
  224. url = '/pages/short_video/nvueSwiper/index'
  225. //#endif
  226. }
  227. if (url.indexOf("http") != -1) {
  228. // #ifdef H5
  229. location.href = url;
  230. // #endif
  231. // #ifdef MP || APP-PLUS
  232. uni.navigateTo({
  233. url: `/pages/annex/web_view/index?url=${url}`
  234. });
  235. // #endif
  236. } else {
  237. if (['/pages/goods_cate/goods_cate', '/pages/order_addcart/order_addcart', '/pages/user/index',
  238. '/pages/index/index'
  239. ]
  240. .indexOf(url) == -1) {
  241. uni.navigateTo({
  242. url: url
  243. })
  244. } else {
  245. uni.reLaunch({
  246. url: url
  247. })
  248. }
  249. }
  250. }
  251. },
  252. /**
  253. * 移除数组中的某个数组并组成新的数组返回
  254. * @param array array 需要移除的数组
  255. * @param int index 需要移除的数组的键值
  256. * @param string | int 值
  257. * @return array
  258. *
  259. */
  260. ArrayRemove: function(array, index, value) {
  261. const valueArray = [];
  262. if (array instanceof Array) {
  263. for (let i = 0; i < array.length; i++) {
  264. if (typeof index == 'number' && array[index] != i) {
  265. valueArray.push(array[i]);
  266. } else if (typeof index == 'string' && array[i][index] != value) {
  267. valueArray.push(array[i]);
  268. }
  269. }
  270. }
  271. return valueArray;
  272. },
  273. /**
  274. * 生成海报获取文字
  275. * @param string text 为传入的文本
  276. * @param int num 为单行显示的字节长度
  277. * @return array
  278. */
  279. textByteLength: function(text, num) {
  280. let strLength = 0;
  281. let rows = 1;
  282. let str = 0;
  283. let arr = [];
  284. for (let j = 0; j < text.length; j++) {
  285. if (text.charCodeAt(j) > 255) {
  286. strLength += 2;
  287. if (strLength > rows * num) {
  288. strLength++;
  289. arr.push(text.slice(str, j));
  290. str = j;
  291. rows++;
  292. }
  293. } else {
  294. strLength++;
  295. if (strLength > rows * num) {
  296. arr.push(text.slice(str, j));
  297. str = j;
  298. rows++;
  299. }
  300. }
  301. }
  302. arr.push(text.slice(str, text.length));
  303. return [strLength, arr, rows] // [处理文字的总字节长度,每行显示内容的数组,行数]
  304. },
  305. /**
  306. * 获取分享海报
  307. * @param array arr2 海报素材
  308. * @param string store_name 素材文字
  309. * @param string price 价格
  310. * @param string ot_price 原始价格
  311. * @param function successFn 回调函数
  312. *
  313. *
  314. */
  315. PosterCanvas: function(fontColor, themeColor, siteName, arr2, store_name, price, ot_price, posterTitle, successFn) {
  316. let that = this;
  317. // uni.showLoading({
  318. // title: '海报生成中',
  319. // mask: true
  320. // });
  321. const ctx = uni.createCanvasContext('myCanvas');
  322. ctx.clearRect(0, 0, 0, 0);
  323. /**
  324. * 只能获取合法域名下的图片信息,本地调试无法获取
  325. *
  326. */
  327. ctx.fillStyle = '#fff';
  328. ctx.fillRect(0, 0, 750, 1306);
  329. uni.getImageInfo({
  330. src: arr2[0],
  331. success: function(res) {
  332. const WIDTH = res.width;
  333. // const HEIGHT = res.height;
  334. // ctx.drawImage(arr2[0], 0, 0, WIDTH, 1050);
  335. ctx.save();
  336. ctx.setFillStyle(themeColor);
  337. ctx.fillRect(0, 0, WIDTH, 108);
  338. ctx.setFontSize(33)
  339. ctx.setFillStyle('#fff');
  340. ctx.setTextAlign('center');
  341. ctx.fillText(posterTitle, WIDTH / 2, 65);
  342. ctx.save();
  343. ctx.drawImage(arr2[1], 32, 141, 685, 685);
  344. ctx.save();
  345. // ctx.setFillStyle(themeColor);
  346. // ctx.fillRect(32, 847, 85, 40);
  347. // ctx.setFontSize(30)
  348. // ctx.setFillStyle('#fff');
  349. // ctx.setTextAlign('left');
  350. // ctx.fillText('商城', 43, 878);
  351. // ctx.save();
  352. // ctx.setFontSize(36)
  353. // ctx.setFillStyle('#000');
  354. // ctx.fillText(siteName, 140, 880);
  355. // ctx.save();
  356. // const CONTENT_ROW_LENGTH = 36;
  357. const CONTENT_ROW_LENGTH = 35;
  358. let [contentLeng, contentArray, contentRows] = that.textByteLength(store_name,
  359. CONTENT_ROW_LENGTH);
  360. if (contentRows > 2) {
  361. contentRows = 2;
  362. let textArray = contentArray.slice(0, 2);
  363. textArray[textArray.length - 1] += '...';
  364. contentArray = textArray;
  365. }
  366. ctx.setTextAlign('left');
  367. ctx.setFontSize(38);
  368. ctx.setFillStyle('#000');
  369. let contentHh = 38;
  370. for (let m = 0; m < contentArray.length; m++) {
  371. if (m) {
  372. ctx.fillText(contentArray[m], 30, 900 + contentHh * m + 18);
  373. } else {
  374. ctx.fillText(contentArray[m], 30, 900 + contentHh * m);
  375. }
  376. }
  377. ctx.save();
  378. ctx.setTextAlign('left')
  379. ctx.setFontSize(32);
  380. ctx.setFillStyle('#999');
  381. ctx.fillText('¥' + ot_price, 30, 1148 + contentHh);
  382. var underline = function(ctx, text, x, y, size, color, thickness, offset) {
  383. var width = ctx.measureText(text).width;
  384. switch (ctx.textAlign) {
  385. case "center":
  386. x -= (width / 2);
  387. break;
  388. case "right":
  389. x -= width;
  390. break;
  391. }
  392. y += size + offset;
  393. ctx.beginPath();
  394. ctx.strokeStyle = color;
  395. ctx.lineWidth = thickness;
  396. ctx.moveTo(x, y);
  397. ctx.lineTo(x + width, y);
  398. ctx.stroke();
  399. }
  400. underline(ctx, '¥' + ot_price, 30, 1146, 28, '#999', 2, 0);
  401. ctx.save();
  402. ctx.setTextAlign('left')
  403. ctx.setFontSize(54);
  404. ctx.setFillStyle(fontColor);
  405. ctx.fillText('¥' + price, 20, 1070 + contentHh);
  406. ctx.save();
  407. ctx.setFillStyle('#F5F5F5');
  408. ctx.fillRect(0, 1222, WIDTH, 84);
  409. ctx.setFontSize(28);
  410. ctx.setFillStyle('#999');
  411. ctx.setTextAlign('center');
  412. ctx.fillText('长按识别图中的二维码查看商品详情', WIDTH / 2, 1272);
  413. ctx.save();
  414. let r = 93;
  415. let d = r * 2;
  416. let cx = WIDTH - d - 30;
  417. // let cy = 1112;
  418. let cy = 1000;
  419. ctx.arc(cx + r, cy + r, r, 0, 2 * Math.PI);
  420. ctx.drawImage(arr2[2], cx, cy, d, d);
  421. ctx.restore();
  422. // ctx.setTextAlign('left')
  423. // ctx.setFontSize(28);
  424. // ctx.setFillStyle('#999');
  425. // ctx.fillText('长按或扫描查看', 490, 1030 + contentHh);
  426. ctx.draw(true, function() {
  427. uni.canvasToTempFilePath({
  428. canvasId: 'myCanvas',
  429. fileType: 'png',
  430. // destWidth: WIDTH,
  431. // destHeight: HEIGHT,
  432. success: function(res) {
  433. // uni.hideLoading();
  434. successFn && successFn(res.tempFilePath);
  435. }
  436. })
  437. });
  438. },
  439. fail: function(err) {
  440. // uni.hideLoading();
  441. that.Tips({
  442. title: '无法获取图片信息'
  443. });
  444. }
  445. })
  446. },
  447. /**
  448. * 获取砍价/拼团海报
  449. * @param array arr2 海报素材 背景图
  450. * @param string store_name 素材文字
  451. * @param string price 价格
  452. * @param string ot_price 原始价格
  453. * @param function successFn 回调函数
  454. *
  455. *
  456. */
  457. bargainPosterCanvas: function(arr2, title, label, msg, price, wd, hg, successFn) {
  458. let that = this;
  459. const ctx = uni.createCanvasContext('myCanvas');
  460. ctx.clearRect(0, 0, 0, 0);
  461. /**
  462. * 只能获取合法域名下的图片信息,本地调试无法获取
  463. *
  464. */
  465. ctx.fillStyle = '#fff';
  466. ctx.fillRect(0, 0, wd * 2, hg * 2);
  467. uni.getImageInfo({
  468. src: arr2[0],
  469. success: function(res) {
  470. const WIDTH = res.width;
  471. const HEIGHT = res.height;
  472. ctx.drawImage(arr2[0], 0, 0, wd, hg);
  473. // 保证在不同机型对应坐标准确
  474. let labelx = 0.6500 //标签x
  475. let labely = 0.166 //标签y
  476. let pricex = 0.1857 //价格x
  477. let pricey = 0.180 //价格x
  478. let codex = 0.385 //二维码
  479. let codey = 0.77
  480. let picturex = 0.1571 //商品图左上点
  481. let picturey = 0.2916
  482. let picturebx = 0.6857 //商品图右下点
  483. let pictureby = 0.3916
  484. let msgx = 0.1036 //msg
  485. let msgy = 0.2306
  486. let codew = 0.25
  487. ctx.drawImage(arr2[1], wd * picturex, hg * picturey, wd * picturebx, hg * pictureby);
  488. ctx.drawImage(arr2[2], wd * codex, hg * codey, wd * codew, wd * codew);
  489. ctx.save();
  490. //标题
  491. const CONTENT_ROW_LENGTH = 28;
  492. let [contentLeng, contentArray, contentRows] = that.textByteLength(title,
  493. CONTENT_ROW_LENGTH);
  494. if (contentRows > 2) {
  495. contentRows = 2;
  496. let textArray = contentArray.slice(0, 2);
  497. textArray[textArray.length - 1] += '…';
  498. contentArray = textArray;
  499. }
  500. ctx.setTextAlign('left');
  501. ctx.setFillStyle('#000');
  502. if (contentArray.length < 2) {
  503. ctx.setFontSize(20);
  504. } else {
  505. ctx.setFontSize(20);
  506. }
  507. let contentHh = 8;
  508. for (let m = 0; m < contentArray.length; m++) {
  509. if (m) {
  510. ctx.fillText(contentArray[m], wd * msgx, 35 + contentHh * m + 18, 1100);
  511. } else {
  512. ctx.fillText(contentArray[m], wd * msgx, 35, 1100);
  513. }
  514. }
  515. // 标签内容
  516. ctx.setTextAlign('left')
  517. ctx.setFontSize(16);
  518. ctx.setFillStyle('#FFF');
  519. ctx.fillText(label, wd * labelx, hg * labely);
  520. ctx.save();
  521. // 价格
  522. ctx.setFillStyle('red');
  523. ctx.setFontSize(26);
  524. ctx.fillText(price, wd * pricex, hg * pricey);
  525. ctx.save();
  526. // msg
  527. ctx.setFillStyle('#333');
  528. ctx.setFontSize(16);
  529. ctx.fillText(msg, wd * msgx, hg * msgy);
  530. ctx.save();
  531. ctx.draw(true, () => {
  532. uni.canvasToTempFilePath({
  533. canvasId: 'myCanvas',
  534. fileType: 'png',
  535. quality: 1,
  536. success: (res) => {
  537. successFn && successFn(res.tempFilePath);
  538. uni.hideLoading();
  539. }
  540. })
  541. });
  542. },
  543. fail: function(err) {
  544. uni.hideLoading();
  545. that.Tips({
  546. title: '无法获取图片信息'
  547. });
  548. }
  549. })
  550. },
  551. /**
  552. * 图片圆角设置
  553. * @param string x x轴位置
  554. * @param string y y轴位置
  555. * @param string w 图片宽
  556. * @param string y 图片高
  557. * @param string r 圆角值
  558. */
  559. handleBorderRect(ctx, x, y, w, h, r) {
  560. ctx.beginPath();
  561. // 左上角
  562. ctx.arc(x + r, y + r, r, Math.PI, 1.5 * Math.PI);
  563. ctx.moveTo(x + r, y);
  564. ctx.lineTo(x + w - r, y);
  565. ctx.lineTo(x + w, y + r);
  566. // 右上角
  567. ctx.arc(x + w - r, y + r, r, 1.5 * Math.PI, 2 * Math.PI);
  568. ctx.lineTo(x + w, y + h - r);
  569. ctx.lineTo(x + w - r, y + h);
  570. // 右下角
  571. ctx.arc(x + w - r, y + h - r, r, 0, 0.5 * Math.PI);
  572. ctx.lineTo(x + r, y + h);
  573. ctx.lineTo(x, y + h - r);
  574. // 左下角
  575. ctx.arc(x + r, y + h - r, r, 0.5 * Math.PI, Math.PI);
  576. ctx.lineTo(x, y + r);
  577. ctx.lineTo(x + r, y);
  578. ctx.fill();
  579. ctx.closePath();
  580. },
  581. /**
  582. * 用户信息分享海报
  583. * @param array arr2 海报素材 1背景 0二维码
  584. * @param string nickname 昵称
  585. * @param string sitename 价格
  586. * @param function successFn 回调函数
  587. *
  588. *
  589. */
  590. userPosterCanvas: function(arr2, nickname, sitename, index, w, h, successFn) {
  591. let that = this;
  592. // uni.showLoading({
  593. // title: '海报生成中',
  594. // mask: true
  595. // });
  596. const ctx = uni.createCanvasContext('myCanvas' + index);
  597. ctx.clearRect(0, 0, 0, 0);
  598. /**
  599. * 只能获取合法域名下的图片信息,本地调试无法获取
  600. *
  601. */
  602. uni.getImageInfo({
  603. src: arr2[1],
  604. success: function(res) {
  605. // const WIDTH = res.width;
  606. // const HEIGHT = res.height;
  607. ctx.fillStyle = '#fff';
  608. ctx.fillRect(0, 0, w, h);
  609. ctx.drawImage(arr2[1], 0, 0, w, h);
  610. ctx.save();
  611. ctx.drawImage(arr2[0], w-86, 386, 70, 70);
  612. ctx.save();
  613. ctx.setFontSize(16);
  614. ctx.setFillStyle('#333');
  615. ctx.fillText(nickname, 45, 414);
  616. ctx.save();
  617. const CONTENT_ROW_LENGTH = 25;
  618. const store_name = '邀请您加入' + sitename;
  619. let [contentLeng, contentArray, contentRows] = that.textByteLength(store_name,
  620. CONTENT_ROW_LENGTH);
  621. if (contentRows > 2) {
  622. contentRows = 2;
  623. let textArray = contentArray.slice(0, 2);
  624. textArray[textArray.length - 1] += '...';
  625. contentArray = textArray;
  626. }
  627. ctx.setTextAlign('left');
  628. ctx.setFillStyle('#999999');
  629. ctx.setFontSize(12);
  630. let contentHh = 38;
  631. for (let m = 0; m < contentArray.length; m++) {
  632. if (m) {
  633. ctx.fillText(contentArray[m], 16, 456);
  634. } else {
  635. ctx.fillText(contentArray[m], 16, 440);
  636. }
  637. }
  638. ctx.save();
  639. that.handleBorderRect(ctx, 16, 396, 24, 24, 12)
  640. ctx.clip();
  641. ctx.drawImage(arr2[2], 16, 396, 24, 24);
  642. ctx.draw(true, function() {
  643. uni.canvasToTempFilePath({
  644. canvasId: 'myCanvas' + index,
  645. fileType: 'png',
  646. quality: 1,
  647. success: function(res) {
  648. uni.hideLoading();
  649. successFn && successFn(res.tempFilePath);
  650. }
  651. })
  652. });
  653. },
  654. fail: function(err) {
  655. uni.hideLoading();
  656. that.Tips({
  657. title: ''
  658. });
  659. }
  660. })
  661. },
  662. // uniapp 判断 IOS和Android的GPS是否开启
  663. checkOpenGPSServiceByAndroidIOS() {
  664. let system = uni.getSystemInfoSync(); // 获取系统信息
  665. console.log('yyy', system);
  666. if (system.platform === 'android') { // 判断平台
  667. var context = plus.android.importClass("android.content.Context");
  668. var locationManager = plus.android.importClass("android.location.LocationManager");
  669. var main = plus.android.runtimeMainActivity();
  670. var mainSvr = main.getSystemService(context.LOCATION_SERVICE);
  671. if (!mainSvr.isProviderEnabled(locationManager.GPS_PROVIDER)) {
  672. return false
  673. } else {
  674. return true
  675. }
  676. } else if (system.platform === 'ios' || 'devtools') {
  677. var cllocationManger = plus.ios.import("CLLocationManager");
  678. var enable = cllocationManger.locationServicesEnabled();
  679. var status = cllocationManger.authorizationStatus();
  680. plus.ios.deleteObject(cllocationManger);
  681. if (enable && status != 2) {
  682. return true
  683. console.log("手机系统的定位已经打开");
  684. } else {
  685. return false
  686. console.log("手机系统的定位没有打开");
  687. }
  688. }
  689. },
  690. /*
  691. * 单图上传
  692. * @param object opt
  693. * @param callable successCallback 成功执行方法 data
  694. * @param callable errorCallback 失败执行方法
  695. */
  696. uploadImageOne: function(opt, successCallback, errorCallback) {
  697. let that = this;
  698. if (typeof opt === 'string') {
  699. let url = opt;
  700. opt = {};
  701. opt.url = url;
  702. }
  703. let count = opt.count || 1,
  704. sizeType = opt.sizeType || ['compressed'],
  705. sourceType = opt.sourceType || ['album', 'camera'],
  706. is_load = opt.is_load || true,
  707. uploadUrl = opt.url || '',
  708. inputName = opt.name || 'pics',
  709. fileType = opt.fileType || 'image';
  710. uni.chooseImage({
  711. count: count, //最多可以选择的图片总数
  712. sizeType: sizeType, // 可以指定是原图还是压缩图,默认二者都有
  713. sourceType: sourceType, // 可以指定来源是相册还是相机,默认二者都有
  714. success: function(res) {
  715. //启动上传等待中...
  716. uni.showLoading({
  717. title: '图片上传中',
  718. });
  719. uni.uploadFile({
  720. url: HTTP_REQUEST_URL + '/api/' + uploadUrl,
  721. filePath: res.tempFilePaths[0],
  722. fileType: fileType,
  723. name: inputName,
  724. formData: {
  725. 'filename': inputName
  726. },
  727. header: {
  728. // #ifdef MP
  729. "Content-Type": "multipart/form-data",
  730. // #endif
  731. [TOKENNAME]: 'Bearer ' + store.state.app.token
  732. },
  733. success: function(res) {
  734. uni.hideLoading();
  735. if (res.statusCode == 403) {
  736. that.Tips({
  737. title: res.data
  738. });
  739. } else if (res.statusCode == 413) {
  740. that.Tips({
  741. title: '上传图片失败,请重新上传小尺寸图片'
  742. });
  743. } else {
  744. let data = res.data ? JSON.parse(res.data) : {};
  745. if (data.status == 200) {
  746. successCallback && successCallback(data)
  747. } else {
  748. errorCallback && errorCallback(data);
  749. that.Tips({
  750. title: data.msg
  751. });
  752. }
  753. }
  754. },
  755. fail: function(res) {
  756. uni.hideLoading();
  757. that.Tips({
  758. title: '上传图片失败'
  759. });
  760. }
  761. })
  762. }
  763. })
  764. },
  765. /*
  766. * 单图上传压缩版
  767. * @param object opt
  768. * @param callable successCallback 成功执行方法 data
  769. * @param callable errorCallback 失败执行方法
  770. */
  771. uploadImageChange: function(opt, successCallback, errorCallback, sizeCallback) {
  772. let that = this;
  773. if (typeof opt === 'string') {
  774. let url = opt;
  775. opt = {};
  776. opt.url = url;
  777. }
  778. let count = opt.count || 1,
  779. sizeType = opt.sizeType || ['compressed'],
  780. sourceType = opt.sourceType || ['album', 'camera'],
  781. is_load = opt.is_load || true,
  782. uploadUrl = opt.url || '',
  783. inputName = opt.name || 'pics',
  784. fileType = opt.fileType || 'image';
  785. uni.chooseImage({
  786. count: count, //最多可以选择的图片总数
  787. sizeType: sizeType, // 可以指定是原图还是压缩图,默认二者都有
  788. sourceType: sourceType, // 可以指定来源是相册还是相机,默认二者都有
  789. success: function(res) {
  790. //启动上传等待中...
  791. let imgSrc
  792. let objImg = res.tempFilePaths;
  793. objImg.forEach(item => {
  794. uni.getImageInfo({
  795. src: item,
  796. success(ress) {
  797. uni.showLoading({
  798. title: '图片上传中',
  799. });
  800. if (res.tempFiles[0].size <= 2097152) {
  801. uploadImg(ress.path)
  802. return
  803. }
  804. // uploadImg(canvasPath.tempFilePath)
  805. let canvasWidth, canvasHeight, xs, maxWidth = 750
  806. xs = ress.width / ress.height // 宽高比例
  807. if (ress.width > maxWidth) {
  808. canvasWidth = maxWidth // 这里是最大限制宽度
  809. canvasHeight = maxWidth / xs
  810. } else {
  811. canvasWidth = ress.width
  812. canvasHeight = ress.height
  813. }
  814. sizeCallback && sizeCallback({
  815. w: canvasWidth,
  816. h: canvasHeight
  817. })
  818. let canvas = uni.createCanvasContext('canvas');
  819. canvas.width = canvasWidth
  820. canvas.height = canvasHeight
  821. canvas.clearRect(0, 0, canvasWidth, canvasHeight);
  822. canvas.drawImage(ress.path, 0, 0, canvasWidth, canvasHeight)
  823. canvas.save();
  824. // 这里的画布drawImage是一种异步属性 可能存在未绘制全就执行了draw的问题 so添加延迟
  825. setTimeout(e => {
  826. canvas.draw(true, () => {
  827. uni.canvasToTempFilePath({
  828. canvasId: 'canvas',
  829. fileType: 'JPEG',
  830. destWidth: canvasWidth,
  831. destHeight: canvasHeight,
  832. quality: 0.7,
  833. success: function(canvasPath) {
  834. uploadImg(canvasPath
  835. .tempFilePath)
  836. }
  837. })
  838. });
  839. }, 200)
  840. }
  841. })
  842. })
  843. }
  844. })
  845. function uploadImg(filePath) {
  846. uni.uploadFile({
  847. url: HTTP_REQUEST_URL + '/api/' + uploadUrl,
  848. filePath,
  849. fileType: fileType,
  850. name: inputName,
  851. formData: {
  852. 'filename': inputName
  853. },
  854. header: {
  855. // #ifdef MP
  856. "Content-Type": "multipart/form-data",
  857. // #endif
  858. [TOKENNAME]: 'Bearer ' + store.state.app.token
  859. },
  860. success: function(res) {
  861. uni.hideLoading();
  862. if (res.statusCode == 403) {
  863. that.Tips({
  864. title: res.data
  865. });
  866. } else {
  867. let data = res.data ? JSON.parse(res.data) : {};
  868. if (data.status == 200) {
  869. successCallback && successCallback(data)
  870. } else {
  871. errorCallback && errorCallback(data);
  872. that.Tips({
  873. title: data.msg
  874. });
  875. }
  876. }
  877. },
  878. fail: function(res) {
  879. uni.hideLoading();
  880. that.Tips({
  881. title: '上传图片失败'
  882. });
  883. }
  884. })
  885. }
  886. },
  887. /**
  888. * 处理客服不同的跳转;
  889. *
  890. */
  891. getCustomer(userInfo, url, storeInfo, show) {
  892. let self = this;
  893. customerType().then(res => {
  894. let data = res.data;
  895. if (data.customer_type == 1) {
  896. uni.makePhoneCall({
  897. phoneNumber: data.customer_phone
  898. });
  899. } else if (data.customer_type == 2) {
  900. let href = data.customer_url;
  901. let hrefO = href + '?uid=' + userInfo.uid + '&nickName=' + userInfo.nickname + '&phone=' +
  902. userInfo.phone + '&sex=' + userInfo.sex + '&avatar=' + userInfo.avatar +
  903. '&openid=' + userInfo.openid;
  904. let hrefT = href + '&uid=' + userInfo.uid + '&nickName=' + userInfo.nickname + '&phone=' +
  905. userInfo.phone + '&sex=' + userInfo.sex + '&avatar=' + userInfo.avatar +
  906. '&openid=' + userInfo.openid;
  907. let urls = encodeURIComponent(href.indexOf('?') === -1 ? hrefO : hrefT);
  908. if (data.customer_url.indexOf('work.weixin.qq.com') > 0) {
  909. // #ifdef MP
  910. wx.openCustomerServiceChat({
  911. extInfo: {
  912. url: data.customer_url
  913. },
  914. corpId: data.wechat_work_corpid,
  915. showMessageCard: show ? true : false,
  916. sendMessageTitle: show ? storeInfo.store_name : '',
  917. sendMessagePath: show ? storeInfo.path : '',
  918. sendMessageImg: show ? storeInfo.image : '',
  919. success(res) {},
  920. fail(err) {
  921. self.Tips({
  922. title: err.errMsg
  923. });
  924. }
  925. })
  926. // #endif
  927. // #ifdef H5
  928. return window.location.href = data.customer_url
  929. // #endif
  930. // #ifdef APP-PLUS
  931. plus.runtime.openURL(data.customer_url)
  932. // #endif
  933. } else {
  934. uni.navigateTo({
  935. url: `/pages/annex/web_view/index?url=${urls}`
  936. });
  937. }
  938. } else {
  939. uni.navigateTo({
  940. url: url || '/pages/extension/customer_list/chat'
  941. })
  942. }
  943. }).catch(err => {
  944. self.Tips({
  945. title: err
  946. });
  947. })
  948. },
  949. /**
  950. * 小程序头像获取上传
  951. * @param uploadUrl 上传接口地址
  952. * @param filePath 上传文件路径
  953. * @param successCallback success回调
  954. * @param errorCallback err回调
  955. */
  956. uploadImgs(uploadUrl, filePath, successCallback, errorCallback) {
  957. let that = this;
  958. uni.uploadFile({
  959. url: HTTP_REQUEST_URL + '/api/' + uploadUrl,
  960. filePath: filePath,
  961. fileType: 'image',
  962. name: 'pics',
  963. formData: {
  964. 'filename': 'pics'
  965. },
  966. header: {
  967. // #ifdef MP
  968. "Content-Type": "multipart/form-data",
  969. // #endif
  970. [TOKENNAME]: 'Bearer ' + store.state.app.token
  971. },
  972. success: (res) => {
  973. uni.hideLoading();
  974. if (res.statusCode == 403) {
  975. that.Tips({
  976. title: res.data
  977. });
  978. } else if (res.statusCode == 413) {
  979. that.Tips({
  980. title: '上传图片失败,请重新上传小尺寸图片'
  981. });
  982. } else {
  983. let data = res.data ? JSON.parse(res.data) : {};
  984. if (data.status == 200) {
  985. successCallback && successCallback(data)
  986. } else {
  987. errorCallback && errorCallback(data);
  988. that.Tips({
  989. title: data.msg
  990. });
  991. }
  992. }
  993. },
  994. fail: (err) => {
  995. uni.hideLoading();
  996. that.Tips({
  997. title: '上传图片失败'
  998. });
  999. }
  1000. })
  1001. },
  1002. /**
  1003. * 小程序比较版本信息
  1004. * @param v1 当前版本
  1005. * @param v2 进行比较的版本
  1006. * @return boolen
  1007. *
  1008. */
  1009. compareVersion(v1, v2) {
  1010. v1 = v1.split('.')
  1011. v2 = v2.split('.')
  1012. const len = Math.max(v1.length, v2.length)
  1013. while (v1.length < len) {
  1014. v1.push('0')
  1015. }
  1016. while (v2.length < len) {
  1017. v2.push('0')
  1018. }
  1019. for (let i = 0; i < len; i++) {
  1020. const num1 = parseInt(v1[i])
  1021. const num2 = parseInt(v2[i])
  1022. if (num1 > num2) {
  1023. return 1
  1024. } else if (num1 < num2) {
  1025. return -1
  1026. }
  1027. }
  1028. return 0
  1029. },
  1030. /**
  1031. * 处理服务器扫码带进来的参数
  1032. * @param string param 扫码携带参数
  1033. * @param string k 整体分割符 默认为:&
  1034. * @param string p 单个分隔符 默认为:=
  1035. * @return object
  1036. *
  1037. */
  1038. // #ifdef MP
  1039. getUrlParams: function(param, k, p) {
  1040. if (typeof param != 'string') return {};
  1041. k = k ? k : '&'; //整体参数分隔符
  1042. p = p ? p : '='; //单个参数分隔符
  1043. var value = {};
  1044. if (param.indexOf(k) !== -1) {
  1045. param = param.split(k);
  1046. for (var val in param) {
  1047. if (param[val].indexOf(p) !== -1) {
  1048. var item = param[val].split(p);
  1049. value[item[0]] = item[1];
  1050. }
  1051. }
  1052. } else if (param.indexOf(p) !== -1) {
  1053. var item = param.split(p);
  1054. value[item[0]] = item[1];
  1055. } else {
  1056. return param;
  1057. }
  1058. return value;
  1059. },
  1060. // #endif
  1061. /*
  1062. * 合并数组
  1063. */
  1064. SplitArray(list, sp) {
  1065. if (typeof list != 'object') return [];
  1066. if (sp === undefined) sp = [];
  1067. for (var i = 0; i < list.length; i++) {
  1068. sp.push(list[i]);
  1069. }
  1070. return sp;
  1071. },
  1072. trim(backUrlCRshlcICwGdGY) {
  1073. return String.prototype.trim.call(backUrlCRshlcICwGdGY);
  1074. },
  1075. $h: {
  1076. //除法函数,用来得到精确的除法结果
  1077. //说明:javascript的除法结果会有误差,在两个浮点数相除的时候会比较明显。这个函数返回较为精确的除法结果。
  1078. //调用:$h.Div(arg1,arg2)
  1079. //返回值:arg1除以arg2的精确结果
  1080. Div: function(arg1, arg2) {
  1081. arg1 = parseFloat(arg1);
  1082. arg2 = parseFloat(arg2);
  1083. var t1 = 0,
  1084. t2 = 0,
  1085. r1, r2;
  1086. try {
  1087. t1 = arg1.toString().split(".")[1].length;
  1088. } catch (e) {}
  1089. try {
  1090. t2 = arg2.toString().split(".")[1].length;
  1091. } catch (e) {}
  1092. r1 = Number(arg1.toString().replace(".", ""));
  1093. r2 = Number(arg2.toString().replace(".", ""));
  1094. return this.Mul(r1 / r2, Math.pow(10, t2 - t1));
  1095. },
  1096. //加法函数,用来得到精确的加法结果
  1097. //说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显。这个函数返回较为精确的加法结果。
  1098. //调用:$h.Add(arg1,arg2)
  1099. //返回值:arg1加上arg2的精确结果
  1100. Add: function(arg1, arg2) {
  1101. arg2 = parseFloat(arg2);
  1102. var r1, r2, m;
  1103. try {
  1104. r1 = arg1.toString().split(".")[1].length
  1105. } catch (e) {
  1106. r1 = 0
  1107. }
  1108. try {
  1109. r2 = arg2.toString().split(".")[1].length
  1110. } catch (e) {
  1111. r2 = 0
  1112. }
  1113. m = Math.pow(100, Math.max(r1, r2));
  1114. return (this.Mul(arg1, m) + this.Mul(arg2, m)) / m;
  1115. },
  1116. //减法函数,用来得到精确的减法结果
  1117. //说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显。这个函数返回较为精确的减法结果。
  1118. //调用:$h.Sub(arg1,arg2)
  1119. //返回值:arg1减去arg2的精确结果
  1120. Sub: function(arg1, arg2) {
  1121. arg1 = parseFloat(arg1);
  1122. arg2 = parseFloat(arg2);
  1123. var r1, r2, m, n;
  1124. try {
  1125. r1 = arg1.toString().split(".")[1].length
  1126. } catch (e) {
  1127. r1 = 0
  1128. }
  1129. try {
  1130. r2 = arg2.toString().split(".")[1].length
  1131. } catch (e) {
  1132. r2 = 0
  1133. }
  1134. m = Math.pow(10, Math.max(r1, r2));
  1135. //动态控制精度长度
  1136. n = (r1 >= r2) ? r1 : r2;
  1137. return ((this.Mul(arg1, m) - this.Mul(arg2, m)) / m).toFixed(n);
  1138. },
  1139. //乘法函数,用来得到精确的乘法结果
  1140. //说明:javascript的乘法结果会有误差,在两个浮点数相乘的时候会比较明显。这个函数返回较为精确的乘法结果。
  1141. //调用:$h.Mul(arg1,arg2)
  1142. //返回值:arg1乘以arg2的精确结果
  1143. Mul: function(arg1, arg2) {
  1144. arg1 = parseFloat(arg1);
  1145. arg2 = parseFloat(arg2);
  1146. var m = 0,
  1147. s1 = arg1.toString(),
  1148. s2 = arg2.toString();
  1149. try {
  1150. m += s1.split(".")[1].length
  1151. } catch (e) {}
  1152. try {
  1153. m += s2.split(".")[1].length
  1154. } catch (e) {}
  1155. return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m);
  1156. },
  1157. },
  1158. // 获取地理位置;
  1159. $L: {
  1160. async getLocation() {
  1161. // #ifdef APP-PLUS
  1162. let status = await this.checkPermission();
  1163. if (status !== 1) {
  1164. return;
  1165. }
  1166. // #endif
  1167. // #ifdef MP-WEIXIN || MP-TOUTIAO || MP-QQ
  1168. let status = await this.getSetting();
  1169. if (status === 2) {
  1170. this.openSetting();
  1171. return;
  1172. }
  1173. // #endif
  1174. this.doGetLocation();
  1175. },
  1176. doGetLocation() {
  1177. uni.getLocation({
  1178. success: (res) => {
  1179. uni.removeStorageSync('CACHE_LONGITUDE');
  1180. uni.removeStorageSync('CACHE_LATITUDE');
  1181. uni.setStorageSync('CACHE_LONGITUDE', res.longitude);
  1182. uni.setStorageSync('CACHE_LATITUDE', res.latitude);
  1183. },
  1184. fail: (err) => {
  1185. // #ifdef MP-BAIDU
  1186. if (err.errCode === 202 || err.errCode === 10003) { // 202模拟器 10003真机 user deny
  1187. this.openSetting();
  1188. }
  1189. // #endif
  1190. // #ifndef MP-BAIDU
  1191. if (err.errMsg.indexOf("auth deny") >= 0) {
  1192. uni.showToast({
  1193. title: "访问位置被拒绝"
  1194. })
  1195. } else {
  1196. uni.showToast({
  1197. title: err.errMsg
  1198. })
  1199. }
  1200. // #endif
  1201. }
  1202. })
  1203. },
  1204. getSetting: function() {
  1205. return new Promise((resolve, reject) => {
  1206. uni.getSetting({
  1207. success: (res) => {
  1208. if (res.authSetting['scope.userLocation'] === undefined) {
  1209. resolve(0);
  1210. return;
  1211. }
  1212. if (res.authSetting['scope.userLocation']) {
  1213. resolve(1);
  1214. } else {
  1215. resolve(2);
  1216. }
  1217. }
  1218. });
  1219. });
  1220. },
  1221. openSetting: function() {
  1222. uni.openSetting({
  1223. success: (res) => {
  1224. if (res.authSetting && res.authSetting['scope.userLocation']) {
  1225. this.doGetLocation();
  1226. }
  1227. },
  1228. fail: (err) => {}
  1229. })
  1230. },
  1231. async checkPermission() {
  1232. let status = permision.isIOS ? await permision.requestIOS('location') :
  1233. await permision.requestAndroid('android.permission.ACCESS_FINE_LOCATION');
  1234. if (status === null || status === 1) {
  1235. status = 1;
  1236. } else if (status === 2) {
  1237. uni.showModal({
  1238. content: "系统定位已关闭",
  1239. confirmText: "确定",
  1240. showCancel: false,
  1241. success: function(res) {}
  1242. })
  1243. } else if (status.code) {
  1244. uni.showModal({
  1245. content: status.message
  1246. })
  1247. } else {
  1248. uni.showModal({
  1249. content: "需要定位权限",
  1250. confirmText: "设置",
  1251. success: function(res) {
  1252. if (res.confirm) {
  1253. permision.gotoAppSetting();
  1254. }
  1255. }
  1256. })
  1257. }
  1258. return status;
  1259. },
  1260. }
  1261. }