mixins.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. import utfx from 'utfx';
  2. import store from './store/';
  3. import onSocketMessage from './onSocketMessage';
  4. /**
  5. * socket 发送用到的一个函数
  6. */
  7. function stringSource(s)
  8. {
  9. let i = 0;
  10. return () => {
  11. return i < s.length ? s.charCodeAt(i++) : null;
  12. };
  13. }
  14. export default {
  15. /** 添加方法时,方法name前加$以避免与页面方法冲突 */
  16. methods: {
  17. /**
  18. * http 请求
  19. * config object
  20. * {
  21. * path: string, 请求路径
  22. * data: object, 发送数据
  23. * success: function, 回调
  24. * fail: function, 错误回调
  25. * type: string 请求方式(默认post)
  26. * success_action: boolean err状态不为0时是否执行success回调(默认是err状态不为0就只提示msg而不执行success回调)
  27. * check: false 是否验证登陆默认不验证
  28. * }
  29. */
  30. $heartCheck:{
  31. timeout: 5000,
  32. timeoutObj: null,
  33. serverTimeoutObj: null,
  34. reset: function () {
  35. clearTimeout(this.timeoutObj);
  36. clearTimeout(this.serverTimeoutObj);
  37. return this;
  38. },
  39. start: function () {
  40. var self = this;
  41. this.timeoutObj && clearTimeout(this.timeoutObj);
  42. this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
  43. this.timeoutObj = setTimeout(function () {
  44. //这里发送一个心跳,后端收到后,返回一个心跳消息,
  45. //onmessage拿到返回的心跳就说明连接正常
  46. self.$socketSend({'type':'ping'});
  47. console.log('心跳检测....')
  48. self.serverTimeoutObj = setTimeout(function () { // 如果超过一定时间还没重置,说明后端主动断开了
  49. console.log('关闭服务');
  50. uni.closeSocket();;//如果onclose会执行reconnect,我们执行 websocket.close()就行了.如果直接执行 reconnect 会触发onclose导致重连两次
  51. }, self.timeout)
  52. }, this.timeout)
  53. }
  54. },
  55. $reconnect:{
  56. lockReconnect : false,
  57. tt:false,
  58. start(){
  59. if(this.lockReconnect){
  60. return false;
  61. }
  62. let self = this;
  63. this.lockReconnect = true;
  64. this.tt && clearTimeout(this.tt);
  65. this.tt = setTimeout(function () {
  66. console.log('重连中...');
  67. self.tlockReconnect = false;
  68. self.$socketSend();
  69. }, 4000);
  70. }
  71. },
  72. $httpSend(config){
  73. let header = {
  74. /** 这里设置为简单跨域,只会请求一次 */
  75. 'Content-Type': 'application/x-www-form-urlencoded',
  76. };
  77. let send_data = ('data' in config ? config.data : {}),
  78. url = store.state.core.http_url + config.path;
  79. send_data['_token'] = uni.getStorageSync('token');
  80. uni.request({
  81. url: url,
  82. data: send_data,
  83. method: ('type' in config ? config.type : 'POST'),
  84. header: header,
  85. dataType: 'json',
  86. success(res) {
  87. if('success' in config && res.statusCode == 200){
  88. if(('success_action' in config) && config.success_action ){
  89. config.success(res.data);
  90. }else{
  91. if(res.data.err){
  92. /** 不显示未登录提示 */
  93. if(send_data['_token'] || config.path.indexOf('/in/') > -1){
  94. uni.showModal({
  95. content: res.data.msg,
  96. });
  97. }
  98. }else{
  99. config.success(res.data.data);
  100. }
  101. }
  102. }
  103. },
  104. fail(err) {
  105. if('fail' in config){
  106. config.fail(err);
  107. }else{
  108. console.log(JSON.stringify(err));return;
  109. uni.showModal({
  110. content: JSON.stringify(err),
  111. });
  112. }
  113. }
  114. });
  115. },
  116. /**
  117. * 通过 websocket 发送数据,
  118. * 如果还没有连接 websocket 就先连接websocket,过两秒等websocket连接上了发送本次的数据,如果两秒后还是没有连接上,则舍弃这次发送数据,
  119. * 如果发送的值为空则只连接
  120. * @param data object
  121. * {
  122. * action: 'model.controller.action',
  123. * data: {}
  124. * }
  125. */
  126. $socketSend(send_data){
  127. /** callback1是连接,callback2是发送 */
  128. var self = this;
  129. console.log('sokect...')
  130. ((callback1,callback2) => {
  131. if(send_data && store.state.socket_state){
  132. callback2(send_data);
  133. }else{
  134. callback1(callback2,send_data);
  135. }
  136. })((callback) => {
  137. uni.connectSocket({
  138. url: store.state.core.socket_url,
  139. header: {
  140. 'content-type': 'application/json',
  141. },
  142. // protocols: [ 'protocol1' ],
  143. method: 'GET',
  144. success(){
  145. },
  146. fail(err){
  147. //TODO 执行重连
  148. // uni.showModal({
  149. // content: JSON.stringify(err) + '---socket 接口调用失败',
  150. // });
  151. self.$reconnect.start();
  152. }
  153. });
  154. uni.onSocketOpen((res) => {
  155. //发送心跳检测
  156. this.$heartCheck.reset().start();
  157. /** 绑定服务器消息事件 */
  158. uni.onSocketMessage((res) => {
  159. res = JSON.parse(res.data);
  160. if(!(res.action in onSocketMessage)){
  161. if(res.action != 'ping' && res.type != 'ping' ){
  162. uni.showModal({
  163. content: '接受到无效的消息',
  164. });
  165. }
  166. } else {
  167. onSocketMessage[res.action](res.data);
  168. }
  169. this.$heartCheck.reset().start();
  170. return;
  171. /** 下面的写法二进制接收数据不兼容APP */
  172. if (res.data instanceof Blob) {
  173. /** js中的blob没有没有直接读出其数据的方法,通过FileReader来读取相关数据 */
  174. let reader = new FileReader();
  175. reader.readAsDataURL(res.data);
  176. /** 当读取操作成功完成时调用. */
  177. reader.onload = function(evt){
  178. let data = JSON.parse(((str) => {
  179. /** base64编码解析 */
  180. if(str.indexOf(',') > -1){
  181. str = str.split(',')[1];
  182. }
  183. return decodeURIComponent(atob(str).split('').map((c) => {
  184. return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
  185. }).join(''));
  186. })(evt.target.result));
  187. if(!(data.action in onSocketMessage)){
  188. if(data.action != 'ping'){
  189. console.log('action null');
  190. }
  191. return;
  192. }
  193. onSocketMessage[data.action](data.data);
  194. }
  195. }
  196. });
  197. /** 这里发送token到服务器验证 */
  198. callback({
  199. action: 'checkToken',
  200. data: uni.getStorageSync('token'),
  201. });
  202. /** 这里如果有需要发送的数据,就等待2s再进行发送,如果2s后,token验证还是不合法,就舍弃这次的发送 */
  203. if(send_data) {
  204. setTimeout(() => {
  205. if(store.state.socket_state){
  206. console.log("socket验证不合法")
  207. callback(send_data);
  208. }
  209. },2000);
  210. }
  211. });
  212. uni.onSocketClose((err) => {
  213. console.log(JSON.stringify(err));
  214. store.commit('set',{ k:'socket_state',v:0 });
  215. self.$reconnect.start();
  216. });
  217. uni.onSocketError((err) => {
  218. store.commit('set',{ k:'socket_state',v:0 });
  219. self.$reconnect.start();
  220. console.log(JSON.stringify(err));
  221. // uni.showModal({
  222. // content: JSON.stringify(err) + '---webSocket 连接打开失败!',
  223. // });
  224. });
  225. },
  226. (send_data) => {
  227. uni.sendSocketMessage({
  228. data: JSON.stringify(send_data),
  229. fail(err){
  230. uni.showModal({
  231. content: JSON.stringify(err) + '---发送消息失败',
  232. });
  233. }
  234. });
  235. return
  236. /** 下面是以二进制发送数据 */
  237. /** 字符串转换二进制过程 */
  238. let data = JSON.stringify(send_data),
  239. strCodes = stringSource(data),
  240. /** js字符串是utf-16编码的,转换成utf-8 */
  241. length = utfx.calculateUTF16asUTF8(strCodes)[1];
  242. /** 字符串开头 */
  243. let offset = 0,
  244. /** 初始化长度为UTF8编码后字符串长度 +4 个Byte的二进制缓冲区(字符串结尾) */
  245. buffer = new ArrayBuffer(length + offset),
  246. view = new DataView(buffer);
  247. /** 将长度放置在字符串的头部 */
  248. view.setUint32(0, length);
  249. utfx.encodeUTF16toUTF8(stringSource(data), function(b) {
  250. view.setUint8(offset++, b);
  251. }.bind(this));
  252. uni.sendSocketMessage({
  253. data: buffer,
  254. success(res){
  255. },
  256. fail(err){
  257. uni.showModal({
  258. content: JSON.stringify(err) + '---发送消息失败',
  259. });
  260. }
  261. });
  262. });
  263. },
  264. /**
  265. * http发送文件(图片、文件、语音)
  266. * @param json obj
  267. * {
  268. local_url: string * 在不调用上传控件的时候的本地文件地址
  269. data: json obj * 上传的数据
  270. success: function * 上传成功回调
  271. fail: function * 上传失败回调
  272. type: int 0对话上传文件 1上传头像 2朋友圈上传文件 3朋友圈背景图片上传 4群头像上传
  273. onProgressUpdate: function 上传进度监听
  274. }
  275. */
  276. $httpSendFile(config){
  277. if(!config){
  278. config = {};
  279. }
  280. let send_data = ('data' in config ? config.data : {});
  281. send_data['_token'] = uni.getStorageSync('token');
  282. ((callback) => {
  283. switch (config.type){
  284. /** 对话上传文件 */
  285. case 0:
  286. callback(config.local_url,'/im/upload/chat');
  287. break;
  288. /** 上传头像 */
  289. case 1:
  290. callback(config.local_url,'/im/upload/photo');
  291. break;
  292. /** 朋友圈上传文件 */
  293. case 2:
  294. callback(config.local_url,'/im/upload/circle');
  295. break;
  296. /** 朋友圈背景图片上传 */
  297. case 3:
  298. callback(config.local_url,'/im/upload/circleImg');
  299. break;
  300. /** 群头像上传 */
  301. case 4:
  302. callback(config.local_url,'/im/upload/groupPhoto');
  303. break;
  304. default:
  305. uni.showModal({
  306. content: '无效的操作',
  307. });
  308. break;
  309. }
  310. })((local_url,action_path) => {
  311. let uploadTask = uni.uploadFile({
  312. url: (store.state.core.static_url + action_path),
  313. filePath: local_url,
  314. name: 'file',
  315. /** formData必须要有值,否则会上传失败 */
  316. formData: send_data,
  317. success: (res) => {
  318. if(res.statusCode == 200){
  319. if('success' in config){
  320. res.data = JSON.parse(res.data);
  321. if(res.data.err){
  322. if('fail' in config){
  323. config.fail(err);
  324. } else {
  325. uni.showModal({
  326. content: res.data.msg,
  327. });
  328. }
  329. }else{
  330. config.success(res.data.data);
  331. }
  332. }
  333. }
  334. },
  335. fail(err){
  336. if('fail' in config){
  337. config.fail(err);
  338. } else {
  339. uni.showModal({
  340. content: JSON.stringify(err),
  341. });
  342. }
  343. }
  344. });
  345. uploadTask.onProgressUpdate((res) => {
  346. if('onProgressUpdate' in config){
  347. config.onProgressUpdate();
  348. }
  349. return;
  350. console.log('上传进度' + res.progress);
  351. console.log('已经上传的数据长度' + res.totalBytesSent);
  352. console.log('预期需要上传的数据总长度' + res.totalBytesExpectedToSend);
  353. });
  354. });
  355. },
  356. }
  357. }