hwq 3 yıl önce
ebeveyn
işleme
9b7e501016
100 değiştirilmiş dosya ile 14987 ekleme ve 0 silme
  1. 10 0
      .gitignore
  2. 20 0
      .hbuilderx/launch.json
  3. 270 0
      App.vue
  4. 0 0
      README.md
  5. 227 0
      common/_action.js
  6. 110 0
      common/_data.js
  7. 1205 0
      common/_get.js
  8. 13 0
      common/_hook.js
  9. 413 0
      common/_mixins.js
  10. 414 0
      common/_onSocket.js
  11. 461 0
      common/common.js
  12. 353 0
      common/html-parser.js
  13. 379 0
      common/mixins.js
  14. 129 0
      common/onSocketMessage.js
  15. 51 0
      common/tendenceImSdk.js
  16. BIN
      components/.DS_Store
  17. 218 0
      components/bjx-form/bjx-form-item.vue
  18. 107 0
      components/bjx-form/bjx-form.vue
  19. 129 0
      components/bjx-form/bjx-validate.js
  20. 13 0
      components/bjx-form/validate.js
  21. 361 0
      components/c-hongsetting/c-hongsetting.vue
  22. 388 0
      components/c-userinfo/c-userinfo.vue
  23. 318 0
      components/cmd-circle/cmd-circle.vue
  24. 255 0
      components/hx-navbar/README.md
  25. 635 0
      components/hx-navbar/hx-navbar.vue
  26. 121 0
      components/j-contacts/j-contacts.vue
  27. 18 0
      components/j-contacts/pinyin.js
  28. 456 0
      components/lb-picker/README.md
  29. 94 0
      components/lb-picker/index.vue
  30. 46 0
      components/lb-picker/mixins/index.js
  31. 94 0
      components/lb-picker/pickers/multi-selector-picker.vue
  32. 67 0
      components/lb-picker/pickers/selector-picker.vue
  33. 75 0
      components/lb-picker/pickers/unlinked-selector-picker.vue
  34. 23 0
      components/lb-picker/style/picker-item.scss
  35. 185 0
      components/lb-picker/style/picker.scss
  36. 110 0
      components/lb-picker/utils.js
  37. 170 0
      components/lxc-count/lxc-count.vue
  38. BIN
      components/mehaotian-search/.DS_Store
  39. 180 0
      components/mehaotian-search/mehaotian-search.vue
  40. 139 0
      components/pick-regions/pick-regions.vue
  41. 0 0
      components/pick-regions/regions.json
  42. 360 0
      components/serving-view/index.vue
  43. 86 0
      components/t-table/t-table.vue
  44. 71 0
      components/t-table/t-td.vue
  45. 71 0
      components/t-table/t-th.vue
  46. 81 0
      components/t-table/t-tr.vue
  47. 96 0
      components/textScroll/textScroll.vue
  48. 190 0
      components/tki-barcode/barcode.js
  49. 17 0
      components/tki-barcode/barcodes/Barcode.js
  50. 167 0
      components/tki-barcode/barcodes/CODE128/CODE128.js
  51. 42 0
      components/tki-barcode/barcodes/CODE128/CODE128A.js
  52. 42 0
      components/tki-barcode/barcodes/CODE128/CODE128B.js
  53. 42 0
      components/tki-barcode/barcodes/CODE128/CODE128C.js
  54. 41 0
      components/tki-barcode/barcodes/CODE128/CODE128_AUTO.js
  55. 73 0
      components/tki-barcode/barcodes/CODE128/auto.js
  56. 54 0
      components/tki-barcode/barcodes/CODE128/constants.js
  57. 29 0
      components/tki-barcode/barcodes/CODE128/index.js
  58. 104 0
      components/tki-barcode/barcodes/CODE39/index.js
  59. 92 0
      components/tki-barcode/barcodes/EAN_UPC/EAN.js
  60. 119 0
      components/tki-barcode/barcodes/EAN_UPC/EAN13.js
  61. 58 0
      components/tki-barcode/barcodes/EAN_UPC/EAN2.js
  62. 65 0
      components/tki-barcode/barcodes/EAN_UPC/EAN5.js
  63. 81 0
      components/tki-barcode/barcodes/EAN_UPC/EAN8.js
  64. 165 0
      components/tki-barcode/barcodes/EAN_UPC/UPC.js
  65. 185 0
      components/tki-barcode/barcodes/EAN_UPC/UPCE.js
  66. 30 0
      components/tki-barcode/barcodes/EAN_UPC/constants.js
  67. 27 0
      components/tki-barcode/barcodes/EAN_UPC/encoder.js
  68. 39 0
      components/tki-barcode/barcodes/EAN_UPC/index.js
  69. 55 0
      components/tki-barcode/barcodes/GenericBarcode/index.js
  70. 69 0
      components/tki-barcode/barcodes/ITF/ITF.js
  71. 55 0
      components/tki-barcode/barcodes/ITF/ITF14.js
  72. 9 0
      components/tki-barcode/barcodes/ITF/constants.js
  73. 19 0
      components/tki-barcode/barcodes/ITF/index.js
  74. 74 0
      components/tki-barcode/barcodes/MSI/MSI.js
  75. 33 0
      components/tki-barcode/barcodes/MSI/MSI10.js
  76. 35 0
      components/tki-barcode/barcodes/MSI/MSI1010.js
  77. 33 0
      components/tki-barcode/barcodes/MSI/MSI11.js
  78. 35 0
      components/tki-barcode/barcodes/MSI/MSI1110.js
  79. 29 0
      components/tki-barcode/barcodes/MSI/checksums.js
  80. 34 0
      components/tki-barcode/barcodes/MSI/index.js
  81. 92 0
      components/tki-barcode/barcodes/codabar/index.js
  82. 34 0
      components/tki-barcode/barcodes/index.js
  83. 73 0
      components/tki-barcode/barcodes/pharmacode/index.js
  84. 211 0
      components/tki-barcode/tki-barcode.vue
  85. 1206 0
      components/tki-qrcode/qrcode.js
  86. 205 0
      components/tki-qrcode/tki-qrcode.vue
  87. 151 0
      components/uni-badge/uni-badge.vue
  88. 96 0
      components/uni-icons/icons.js
  89. 10 0
      components/uni-icons/uni-icons.vue
  90. 109 0
      components/uni-keyword/uni-keyword.vue
  91. 290 0
      components/uni-list-item/uni-list-item.vue
  92. 75 0
      components/uni-list/uni-list.vue
  93. 65 0
      components/uni-list/uni-refresh.vue
  94. 87 0
      components/uni-list/uni-refresh.wxs
  95. 22 0
      components/uni-popup/message.js
  96. 37 0
      components/uni-popup/popup.js
  97. 330 0
      components/uni-popup/uni-popup-address.vue
  98. 234 0
      components/uni-popup/uni-popup-alert.vue
  99. 254 0
      components/uni-popup/uni-popup-confirm.vue
  100. 242 0
      components/uni-popup/uni-popup-dialog.vue

+ 10 - 0
.gitignore

@@ -0,0 +1,10 @@
+node_modules
+unpackage/dist/*
+.idea/workspace.xml
+.idea/modules.xml
+.idea/j_uniapp_im.iml
+.idea/deployment.xml
+.idea/vcs.xml
+.idea/encodings.xml
+.idea/misc.xml
+*.apk

+ 20 - 0
.hbuilderx/launch.json

@@ -0,0 +1,20 @@
+{ // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
+  // launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数
+    "version": "0.0",
+    "configurations": [{
+     	"app-plus" : 
+     	{
+     		"launchtype" : "local"
+     	},
+     	"default" : 
+     	{
+     		"launchtype" : "local"
+     	},
+     	"h5" : 
+     	{
+     		"launchtype" : "local"
+     	},
+     	"type" : "uniCloud"
+     }
+    ]
+}

+ 270 - 0
App.vue

@@ -0,0 +1,270 @@
+<script>
+	import permision from "@/js_sdk/wa-permission/permission.js"
+    import _action from './common/_action';
+    import _get from './common/_get';
+    import _data from './common/_data';
+    import _page from './common/common';
+	// #ifdef APP-PLUS
+	import { getUpApp } from './utils/upApp.js';
+	// #endif
+    export default {
+        globalData: {
+            /** 代理客户id */
+            agent_id: 1,
+            /** http 服务端地址 */
+            http_url: 'http://chat.lalanft.net',
+            /** 静态文件存放地址 */
+			 static_url: 'http://chat.lalanft.net',
+            /** socket 服务端地址 */
+            socket_url: 'ws://199.180.115.136:8383',
+            /** socket 连接状态 */
+            socket_state: 0,
+            /** 好友申请通知 */
+            new_friend_tips_num: 0,
+            /** 群认证通知 */
+            new_group_tips_num: 0,
+            /** 朋友圈通知 */
+            no_reader_circle: 0,
+            /** 朋友圈消息未读数 */
+            no_reader_circle_chat_num: 0,
+            /** 缓存的数据 */
+            cache: {
+                /** 个人头像缓存数据 */
+                local_photo: '',
+            },
+            /** 用户信息 */
+            user_info: {
+                id: 0,
+                nickname: '',
+                username: '',
+                photo: 'default_man/70.jpg',
+                doodling: '',
+				phone:'',
+                circle_img: 'default_circle_img.jpg?_=3.1415926',
+            },
+            isOnlie:true,
+			dragInfo:{
+                moveX:260,
+                moveY:180,
+                state:-1
+			}
+        },
+        onLaunch() {
+			// #ifdef APP-PLUS
+			// 判断是否升级
+			getUpApp();
+			// 获取当前运行系统
+			let system = uni.getStorageSync('platform') || '';
+			if (!system) {
+				uni.setStorage({
+					key: 'platform',
+					data: uni.getSystemInfoSync().platform
+				});
+			}
+			// #endif
+			this.requestAn()
+			this.$store.commit('initRECORD');
+            //#ifdef APP-PLUS
+			// plus.navigator.setFullscreen(true);
+			if(plus.os.name == 'Android'){
+				const hgService = uni.requireNativePlugin("uniapp_kill_service_plugin");
+				// console.log(hgService)
+				hgService.config({
+				    "title":"优哈",
+				    "content":"进程守护中",
+				    "taskTime":3000,		 //任务执行频率,
+				    "autoStartService":true, //是否根据监听到的广播自启动服务
+				    "autoWakeUp":true 		 //是否自动定时点亮屏 30s
+				});
+				hgService.startService();
+			}
+            /* 5+  push 消息推送 ps:使用:H5+的方式监听,实现推送*/
+            plus.push.addEventListener("click", function(msg) {
+				 console.log("msg.payload",JSON.stringify(msg.payload));
+				 let content_type = msg.payload.content_type; 
+				if(Object.keys(msg.payload).length){
+						switch(parseInt(content_type)){
+							case 6:
+							case 7:
+								uni.navigateTo({
+								  url: '/pages/chat/videoCall?'+_page.pageParam(msg.payload)
+								});
+							break;	
+						}						
+				}
+                //这里可以写跳转业务代码
+            }, false);
+            // 监听在线消息事件
+            plus.push.addEventListener("receive", function(msg) {
+                // plus.ui.alert(2);
+                //这里可以写跳转业务代码
+                console.log("recevice:"+JSON.stringify(msg))
+            }, false);
+
+            //#endif
+			
+            // #ifdef APP-PLUS
+            /** 锁定屏幕方向 */
+            plus.screen.lockOrientation('portrait-primary');
+            // let main = plus.android.runtimeMainActivity();
+            // //为了防止快速点按返回键导致程序退出重写quit方法改为隐藏至后台
+            // plus.runtime.quit = function(){
+            //     return false;
+            // };
+			
+        //重写toast方法如果内容为 ‘再按一次退出应用’ 就隐藏应用,其他正常toast
+      //       plus.nativeUI.toast = (function(str){
+      //           if(str == '再按一次退出应用'){
+      //               return false;
+      //           }else{
+					 // return false;
+      //               // uni.showToast({
+      //               //     title: '再按一次退出应用',
+      //               //     icon:'none',
+      //               // })
+      //           }
+      //       });
+            /** 检测升级 */
+			/** <view>QQ:323392278 云站网络</view> */
+            let _this = this;
+
+            plus.runtime.getProperty(plus.runtime.appid, function (info) {
+                _this.$httpSend({
+                    path: '/im/app/update',
+                    data: {
+                        appid: info.appid,
+                        version: info.version,
+                    },
+                    success(res) {
+                        if (res.status) {
+                            _action.checkFail();
+                            let wgtWaiting = plus.nativeUI.showWaiting("更新开始下载"),
+                                update_url = (plus.os.name == 'Android' ? res.update_url.android : res.update_url.ios),
+                                downloadTask = uni.downloadFile({
+                                    url: update_url,
+                                    success: (res) => {
+                                        wgtWaiting.close();
+                                        if (res.statusCode === 200) {
+                                            plus.runtime.install(res.tempFilePath, {}, () => {
+                                                plus.runtime.restart();
+                                            }, (e) => {
+                                                uni.showModal({
+                                                    content: "update error [" + e.code + "]:" + e.message,
+                                                    showCancel: false,
+                                                });
+                                            });
+                                        } else {
+                                            uni.showModal({
+                                                content: "api error update fail!",
+                                                showCancel: false,
+                                            });
+                                        }
+                                    }
+                                });
+                            downloadTask.onProgressUpdate((res) => {
+                                wgtWaiting.setTitle('下载中...' + res.progress + '%');
+                            });
+                        }
+                    },
+                });
+            });
+			// #endif
+			
+        },
+        onShow() {
+            let _this = this;
+            if (!_data.localData('token')) {
+                return;
+            }
+			/**
+			 * 每次app启动都加载最新的会话列表数据,只要是最新的会话列表数据,会话界面数据也会是最新的
+			 * 这里延时100ms,不然会全局变量没有加载完成,会报错。
+			 */
+			if(_data.data('socket_state') <= 0){
+                _this.$reset().$reconnect(function(){
+                    if(_data.localData('token'))_get.getChatList();
+
+                });
+            }
+            /**
+             * @param {Object} res
+             * 监听网络变化
+             * 如果有网络变化,断开socket,再重新连接
+             * 重新获取会话列表数据
+             * 如果是在会话界面,再重新获取这个的对话数据
+             */
+            uni.onNetworkStatusChange(function (res) {
+                console.log("App  onNetworkStatusChange...");
+                /** 断开重新再连接,再获取最新数据 */
+                if(_data.data('socket_state') <= 0 && _data.localData('token')){
+                    _this.$reset().$reconnect(function(){
+                        if (_data.localData('message_list_id') && _data.localData('token')) {
+                            _get.getChatData({
+                                send_data: {
+                                    list_id: _data.localData('message_list_id'),
+                                    time: 0,
+                                    is_up: 1,
+                                },
+                                is_action_data: 1,
+                            });
+                        }
+                    });
+                }
+            });
+        },
+        onHide() {
+            this.globalData.isOnlie = false;
+        },
+		methods:{
+			requestAn(){
+				switch(uni.getSystemInfoSync().platform){
+				    case 'android':
+						permision.requestAndroidPermission("android.permission.RECORD_AUDIO")
+						break;
+				    case 'ios':
+						permision.judgeIosPermission("record")
+						break;
+				}
+				 
+				
+			}
+		}
+    }
+</script>
+
+<style>
+    /* #ifndef APP-PLUS-NVUE */
+    /** uni.css - 通用组件、模板样式库,可以当作一套ui库应用 */
+    @import "./static/css/font/iconfont.css";
+    @import "./static/css/font/iconfont-im.css";
+    @import "./static/css/uni.css";
+    /** 设置 body 的背景色 */
+    page {
+        background-color: #f0eff4;
+    }
+
+    /** 导航栏自定义图标样式调整 */
+    .uni-page-head .uni-btn-icon {
+        min-width: auto !important;
+        overflow: inherit !important;
+    }
+
+    uni-checkbox .uni-checkbox-input {
+        border-radius: 50%;
+        width: 18px !important;
+        height: 18px !important;
+        border: 1px solid #77be6e !important;
+    }
+
+    uni-checkbox .uni-checkbox-input.uni-checkbox-input-checked {
+        background-color: #77be6e;
+        border: 1px solid #77be6e  !important;
+        color: white !important;
+    }
+
+    uni-checkbox .uni-checkbox-wrapper {
+        width: 100%;
+    }
+
+    /* #endif */
+</style>

+ 0 - 0
README.md


+ 227 - 0
common/_action.js

@@ -0,0 +1,227 @@
+import _data from './_data';
+import _mixins from './_mixins';
+let innerAudioContext = uni.createInnerAudioContext();
+export default {
+  /** 显示状态通知提醒 */
+  setStatusTips () {
+    let pages = getCurrentPages();
+    if (pages.length < 1) {
+      return;
+    }
+    let route = pages[pages.length - 1].route,
+      /** 只有tabbar页面才更新消息状态 */
+      routes = [
+        'pages/chat/index',
+        'pages/friend/index',
+        'pages/push/index',
+        'pages/my/index'
+      ];
+    if (routes.indexOf(route) == -1) {
+      return;
+    }
+    /** 通讯录提示 */
+    let num = (_data.data('new_friend_tips_num') * 1),
+      num_ = (_data.data('new_group_tips_num') * 1);
+    if (num_) {
+      uni.$emit('data_new_group_apply_tips', num_);
+    }
+    if (num) {
+      uni.$emit('data_new_friend_tips', num);
+    }
+    if (num + num_) {
+      uni.setTabBarBadge({
+        index: 1,
+        text: (num + num_ + ''),
+      });
+    } else {
+      uni.removeTabBarBadge({ index: 1 });
+    }
+    /** 会话列表提示 */
+    num = _data.chatTipsNum();
+    if (num) {
+      uni.setTabBarBadge({
+        index: 0,
+        text: (num + ''),
+      });
+      if (route == 'pages/chat/index') {
+        uni.setNavigationBarTitle({
+          title: '优哈' + '(' + num + ')',
+        });
+      }
+    } else {
+      uni.removeTabBarBadge({ index: 0 });
+      if (route == 'pages/chat/index') {
+        uni.setNavigationBarTitle({
+          title: '优哈',
+        });
+      }
+    }
+
+    /** 朋友圈提示(优先显示消息条数,再提示好友动态) */
+    num = _data.data('no_reader_circle_chat_num');
+    let num2 = _data.data('no_reader_pay_num');
+	let num3 = parseInt(num) + parseInt(num2);
+    if (num3) {
+      uni.setTabBarBadge({
+        index: 2,
+        text: (num2 + ''),
+      });
+     if(num) uni.$emit('data_circle_tips', num);
+	 if(num2) uni.$emit('data_pay_tips', num2);
+    }
+    else {
+      uni.removeTabBarBadge({ index: 2 });
+      num = _data.data('no_reader_circle');
+      if (num) {
+        uni.showTabBarRedDot({ index: 2 });
+        uni.$emit('data_circle_tips', '好友动态');
+      } else {
+        uni.hideTabBarRedDot({ index: 2 });
+      }
+    }
+	
+	
+
+  },
+  /** 路由守卫执行方法 */
+  routeTool () {
+    _data.data('isOnlie',true);
+    let token = _data.localData('token');
+    /** 没有token就跳转到登陆去获得token */
+    if (!token) {
+      uni.reLaunch({
+        url: '/pages/in/login'
+      });
+      return;
+    }
+    /** 如果没有连接上socket,则连接 */
+    if (!_data.data('socket_state')) {
+      _mixins.methods.$reset().$reconnect();
+    }
+	
+  },
+  /** 验证失败后执行 */
+  checkFail () {
+    /** 好友申请通知 */
+    _data.data('new_friend_tips_num', 0);
+    /** 朋友圈通知 */
+    _data.data('no_reader_circle', 0);
+    /** 朋友圈消息未读数 */
+    _data.data('no_reader_circle_chat_num', 0);
+    /** 清空自己的头像保存的本地的临时地址 */
+    let data = _data.data('cache');
+    data.local_photo = '';
+    _data.data('cache', data);
+    /** 归档用户信息 */
+    _data.data('user_info', {
+      id: 0,
+      nickname: '',
+      username: '',
+      photo: 'default_man/90.jpg',
+      doodling: '',
+      circle_img: 'default_circle_img.jpg',
+    });
+    uni.clearStorage();
+    // /** 跳转到登陆界面 */
+    // uni.reLaunch({
+    //   url: '/pages/in/login'
+    // });
+  },
+  /** 更新未读消息为0 */
+  updataNoReader (list_id) {
+    _mixins.methods.$httpSend({
+      path: '/im/message/updataNoReader',
+      data: { list_id: list_id },
+    });
+  },
+  /** 下载自己的头像 */
+  downloadPhoto () {
+    let url =  _data.staticPhoto() + _data.data('user_info').photo;
+    let data = _data.data('cache');
+    uni.downloadFile({
+      url: url,
+      success: (res) => {
+        console.log("download:",res)
+        if (res.statusCode === 200) {
+          data.local_photo = res.tempFilePath;
+          if(!data.local_photo) data.local_photo = url
+          _data.data('cache', data);
+        }
+      },
+      fail(res) {
+        data.local_photo = url;
+        console.log(1111)
+        _data.data('cache', data);
+      }
+    });
+    if(!_data.data('cache').local_photo){
+      data.local_photo = url;
+      console.log("data",data)
+      _data.data('cache', data);
+    }
+    console.log("_cache",_data.data('cache'))
+    },
+  /** 播放音效 */
+  playVoice (path, loop) {
+    innerAudioContext.src = path;
+    innerAudioContext.loop = loop;
+    // innerAudioContext.obeyMuteSwitch = false;
+    innerAudioContext.play();
+    innerAudioContext.onPlay(() => {
+      //console.log('开始播放');
+    });
+    innerAudioContext.onError((res) => {
+      innerAudioContext.destroy();
+      return;
+      uni.showToast({
+        title: '音效播放错误 ->' + JSON.stringify(res),
+        icon: 'none',
+      });
+    });
+  },
+  // 停止播放
+  stopVoice () {
+    console.log("停止")
+    innerAudioContext.stop()
+  },
+  /** 时间戳转换 */
+  timestampFormat (timestamp) {
+    let curTimestamp = parseInt(new Date().getTime() / 1000), //当前时间戳
+      timestampDiff = curTimestamp - timestamp, // 参数时间戳与当前时间戳相差秒数
+      curDate = new Date(curTimestamp * 1000), // 当前时间日期对象
+      tmDate = new Date(timestamp * 1000),  // 参数时间戳转换成的日期对象
+      Y = tmDate.getFullYear(),
+      m = tmDate.getMonth() + 1, d = tmDate.getDate(),
+      H = tmDate.getHours(), i = tmDate.getMinutes(),
+      s = tmDate.getSeconds();
+    if (timestampDiff < 60) { // 一分钟以内
+      return "刚刚";
+    } else if (timestampDiff < 3600) { // 一小时前之内
+      return Math.floor(timestampDiff / 60) + "分钟前";
+    } else if (curDate.getFullYear() == Y && curDate.getMonth() + 1 == m && curDate.getDate() == d) {
+      return '今天 ' + ((String(H).length == 1 ? '0' : '') + H) + ':' + ((String(i).length == 1 ? '0' : '') + i);
+    } else {
+      var newDate = new Date((curTimestamp - 86400) * 1000); // 参数中的时间戳加一天转换成的日期对象
+      if (newDate.getFullYear() == Y && newDate.getMonth() + 1 == m && newDate.getDate() == d) {
+        return '昨天 ' + ((String(H).length == 1 ? '0' : '') + H) + ':' + ((String(i).length == 1 ? '0' : '') + i);
+      } else if (curDate.getFullYear() == Y) {
+        return ((String(m).length == 1 ? '0' : '') + m) + '月' + ((String(d).length == 1 ? '0' : '') + d) + '日 ' + ((String(H).length == 1 ? '0' : '') + H) + ':' + ((String(i).length == 1 ? '0' : '') + i);
+      } else {
+        return Y + '年' + ((String(m).length == 1 ? '0' : '') + m) + '月' + ((String(d).length == 1 ? '0' : '') + d) + '日 ' + ((String(H).length == 1 ? '0' : '') + H) + ':' + ((String(i).length == 1 ? '0' : '') + i);
+      }
+    }
+  },
+  getStrCharLength(val) {
+  var str = new String(val);
+  var bytesCount = 0;
+  for (var i = 0 ,n = str.length; i < n; i++) {
+    var c = str.charCodeAt(i);
+    if ((c >= 0x0001 && c <= 0x007e) || (0xff60<=c && c<=0xff9f)) {
+      bytesCount += 1;
+    } else {
+      bytesCount += 2;
+    }
+  }
+  return bytesCount;
+  },
+}

+ 110 - 0
common/_data.js

@@ -0,0 +1,110 @@
+export default {
+	/**
+	 * [设置获取globalData数据]
+	 * @param {Object} k 设置/获取的键
+	 * @param {Object} v 设置的值,没有传值就是获取这个键的值
+	 * @return {String|Array|Object}
+	 */
+	data(k,v){
+		// console.log(getApp().globalData)
+		if(v === undefined){
+			return getApp().globalData[k];
+		}
+		else{
+			getApp().globalData[k] = v;
+		}
+	},
+	/**
+	 * [设置获取保存在本地的页面数据]
+	 * @param {Object} k 设置/获取的键
+	 * @param {Object} v 设置的值,v为undefined获取这个键的值,v为null,移除这个键的数据
+	 * @return {String|Array|Object}
+	 */
+	localData(k,v){
+		if(v === undefined){
+			return uni.getStorageSync(k);
+		}
+		else if(v === null){
+			uni.removeStorage({
+				key: k,
+				fail(){
+				}
+			});
+		}
+		else {
+			uni.setStorage({
+				key: k,
+				data: v,
+				fail(){
+				}
+			});
+		}
+	},
+	domainUrl(){
+		return getApp().globalData.http_url
+	},
+	/** 聊天静态文件地址 */
+	staticChat(){
+		return getApp().globalData.static_url + '/static/chat/';
+	},
+	/** 朋友圈静态文件地址 */
+	staticCircle(){
+		return getApp().globalData.static_url + '/static/circle/';
+	},
+	/** 头像地址 */
+	staticPhoto(){
+		return getApp().globalData.static_url + '/static/photo/';
+	},
+    /** 视频图片地址 */
+    staticVideoImg(){
+        return getApp().globalData.static_url + '/static/photo/video_gif/';
+    },
+	/** 获取会话界面有多少未读消息 */
+	chatTipsNum(){
+		let num = 0,
+		chat_list = uni.getStorageSync('chat_list');
+		if(chat_list){
+			for(let value of chat_list){
+				num += (value.no_reader_num * 1);
+			}
+		}
+		return num;
+	},
+	//根据网络地址获取本地地址
+	getDowndloadVedio(url,cb){
+		//ifdef H5
+			return url;
+		//endif
+		 let _this = this;
+		 let key = 'VEDIO_URL_'+ url;
+		let address = this.localData(key);
+        console.log(address)
+		if(address == undefined || address == null || !address){
+			const downloadTask = uni.downloadFile({
+				url: url, //仅为示例,并非真实的资源
+				success: (res) => {
+					if (res.statusCode === 200) {
+						uni.saveFile({
+							tempFilePath: res.tempFilePath,
+							success: function(red) {
+								//下载到本地下次秒读取
+								address = red.savedFilePath
+								_this.localData(key,address);
+								if(cb)cb(address)
+							}
+						});
+					}
+
+				}
+			});
+			downloadTask.onProgressUpdate((res) => {
+				console.log('下载进度' + res.progress);
+				console.log('已经下载的数据长度' + res.totalBytesWritten);
+				console.log('预期需要下载的数据总长度' + res.totalBytesExpectedToWrite);
+			});
+		}else {
+			if(cb)cb(address);
+			return address
+		}
+	}
+}

+ 1205 - 0
common/_get.js

@@ -0,0 +1,1205 @@
+import _mixins from './_mixins';
+import _action from './_action';
+import _data from './_data';
+
+export default {
+	/** 获得会话列表数据 */
+	getChatList(){
+		_mixins.methods.$httpSend({
+			path: '/im/get/chatList',
+			success(data) {
+				// data.hasData = 1;
+				// if(!data.length)data.hasData = 0;
+				if(data.length){
+					data.sort((x,y)=>{
+						if(x.top == y.top){
+							return y.time - x.time;
+						}else {
+							return y.top - x.top;
+						}
+					})
+				}
+				_data.localData('chat_list',data);
+				uni.$emit('data_chat_list',data);
+				_action.setStatusTips();
+			}
+		});
+	},
+	getGroupChatList(data,sucess){
+		_mixins.methods.$httpSend({
+			path: '/im/get/chatList',
+			data:data,
+			success(data) {
+				console.log(1111)
+				if(sucess){
+					sucess(data)
+				}
+			}
+		});
+	},
+   /**
+	 * 获得对话数据 
+	 * @param {
+			发送的数据
+			send_data: {
+				list_id: list_id,
+				time: 0,
+				是否更新未读消息数
+				is_up: 1,
+			},
+			回调函数
+			calllback(data){
+				
+			},
+			是否需要操作本地缓存数据
+			is_action_data: 1,
+		}
+	 */
+	getChatData(config){
+		_mixins.methods.$httpSend({
+			path: '/im/get/chatData',
+			data: config.send_data,
+			success(data) {
+				// console.log('12312311213',data)
+				if(config.is_action_data){
+					uni.$emit('data_chat_data',data);
+					_data.localData(data.list_id,data);
+				}
+				else{
+					uni.$emit('data_chat_data_unshift',data.list);
+				}
+				if('callback' in config){
+					config.callback(data);
+				}
+			}
+		});
+	},
+	/** 获得通讯录数据 */
+	getFriendList(send_data,callback){
+		if(!send_data){
+			send_data = {};
+		}
+		_mixins.methods.$httpSend({
+			path: '/im/get/friendList',
+			data: send_data,
+			success(data) {
+				if(data.data.length || 'up' in send_data || Object.keys(data.data).length){
+					_data.localData('friend_list',data.data);
+					uni.$emit('data_friend_list',data.data);
+				}
+				if(callback){
+					callback(data);
+				}
+			}
+		});
+	},
+	/** 获得朋友圈数据 data要发送的数据 type 0加载最新数据 1加载历史数据 */
+	getCircleList(send_data,callback){
+		_mixins.methods.$httpSend({
+			path: '/im/get/circleData',
+			data: send_data,
+			success(data) {
+				console.log(data)
+				let key1 = 'circle_data',_data_key1 = 'data_circle_data';
+				let circle_data = _data.localData(key1);
+				if(!circle_data){
+					circle_data = [];
+				}
+				if(send_data.type){
+					circle_data.push(...data.data);
+				} else {
+					if(send_data.time==0){
+						circle_data = [];
+					}
+					circle_data.unshift(...data.data);
+				}
+				uni.$emit(_data_key1,circle_data);
+				_data.localData(key1,circle_data);
+				if('update' in send_data){
+					let key2 = 'circle_data_user',_data_key2 = 'data_circle_data_user';
+					let circle_data2 = _data.localData(key2);
+					if(!circle_data){
+						circle_data = [];
+					}
+					if(send_data.type){
+						circle_data2.push(...data.data);
+					} else {
+						circle_data2.unshift(...data.data);
+					}
+					uni.$emit(_data_key2,circle_data2);
+					_data.localData(key2,circle_data2);
+				}
+				if(callback) {
+					callback(data);
+				}
+			}
+		});
+	},
+	/** 获得基础数据 */
+	getUserCircleList(send_data,callback){
+		console.log('to')
+		_mixins.methods.$httpSend({
+			path: '/im/get/circleData',
+			data: send_data,
+			success(data) {
+				console.log(1111111)
+				let key2 = 'circle_data_user',_data_key2 = 'data_circle_data_user';
+				let circle_data2 = _data.localData(key2);
+				if(!circle_data2){
+					circle_data2 = [];
+				}
+				if(send_data.type){
+					circle_data2.push(...data.data);
+				} else {
+					circle_data2.unshift(...data.data);
+				}
+				uni.$emit(_data_key2,circle_data2);
+				_data.localData(key2,circle_data2);
+
+				if(callback) {
+					callback(data);
+				}
+			}
+		});
+	},
+	base(){
+		_mixins.methods.$httpSend({
+			path: '/im/get/base',
+			success(data) {
+				data.user_info.photo += '?_=' + Math.random();
+				data.user_info.circle_img += '?_=' + Math.random();
+				
+				_data.data('user_info',data.user_info);
+				uni.$emit('data_user_info',data.user_info);
+				
+				_data.data('new_friend_tips_num',data.new_friend_tips_num);
+				_data.data('no_reader_chat_num',data.no_reader_chat_num);
+				_data.data('no_reader_circle',data.no_reader_circle);
+				_data.data('no_reader_circle_chat_num',data.no_reader_circle_chat_num);
+				_data.data('new_group_tips_num',data.new_group_tips_num);
+
+				_data.data('kefu_list_id',data.kefu_list_id);
+				_action.setStatusTips();
+				_action.downloadPhoto();
+			}
+		});
+	},
+	/** 获得好友申请列表数据 */
+	getFriendApplyList(callback){
+		_mixins.methods.$httpSend({
+			path: '/im/get/applyFriend',
+			success(data) {
+				_data.localData('friend_apply_list',data);
+				uni.$emit('data_friend_apply_list',data);
+				if(callback){
+					callback(data);
+				}
+			}
+		});
+	},
+	/** 获得群认证列表数据 */
+	getGroupApplyList(callback){
+		_mixins.methods.$httpSend({
+			path: '/im/get/applyGroup',
+			success(data) {
+				_data.localData('group_apply_list',data);
+				uni.$emit('data_group_apply_data',data);
+				if(callback){
+					callback(data);
+				}
+			}
+		});
+	},
+	//搜索聊天记录
+	serchChatMsg(params,callback){
+		_mixins.methods.$httpSend({
+			path: '/im/get/searchCahtMsg',
+			data:params,
+			success(data) {
+				if(callback){
+					callback(data);
+				}
+			}
+		});
+	},
+	//搜索好友
+	searchFriends(params,callback){
+		_mixins.methods.$httpSend({
+			path: '/im/get/searchFriends',
+			data:params,
+			success(data) {
+				if(callback){
+					callback(data);
+				}
+			}
+		});
+	},
+	//取消音/视频
+	cancelCall(params,callback){
+		_mixins.methods.$httpSend({
+			path: '/im/message/closeVideo',
+			data: params,
+			success (res) {
+				if(callback){
+					callback(res);
+				}
+			}
+		});
+	},
+	//同意/音视频
+	agreeVedio(params,callback){
+		_mixins.methods.$httpSend({
+			path: '/im/message/agreeVedio',
+			data: params,
+			success (res) {
+				if(callback){
+					callback(res);
+				}
+			}
+		});
+	},
+	createHongBao(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/message/createHongBao',
+			data: params,
+			success (res) {
+				if(callback){
+					callback(res);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	checkBeforePay(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/user/checkBeforePay',
+			data: params,
+			success (res) {
+				if(callback){
+					callback(res);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	getHongBao(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/message/getHongBao',
+			data: params,
+			success (res) {
+				if(callback){
+					callback(res);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	getUserCapitalList(params,callback){
+		_mixins.methods.$httpSend({
+			path: '/im/get/getUserCapitalList',
+			data: params,
+			success (res) {
+				if(callback){
+					callback(res);
+				}
+			},
+		});
+	},
+	getUserbankList(params,callback){
+		_mixins.methods.$httpSend({
+			path: '/im/get/getUserbankList',
+			data: params,
+			success (res) {
+				if(callback){
+					callback(res);
+				}
+			},
+		});
+	},
+	addUserBank(params,callback){
+		_mixins.methods.$httpSend({
+			path: '/im/get/addUserBank',
+			data: params,
+			success (fireParams) {
+				uni.$emit('update_bank_list_data',fireParams);
+				if(callback){
+					callback(fireParams);
+				}
+			},
+		});
+	},
+	setUserTradePassword(params,callback){
+		_mixins.methods.$httpSend({
+			path: '/im/user/setUserTradePassword',
+			data: params,
+			success (fireParams) {
+				if(callback){
+					callback(fireParams);
+				}
+			},
+		});
+	},
+	checkUserTradePassword(params,callback){
+		_mixins.methods.$httpSend({
+			path: '/im/user/checkUserTradePassword',
+			data: params,
+			success (fireParams) {
+				if(callback){
+					callback(fireParams);
+				}
+			},
+		});
+	},
+	sendContact(params,callback){
+		_mixins.methods.$httpSend({
+			path: '/im/app/setUserContact',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+		});
+	},
+	getOnlineList(params,callback){
+		_mixins.methods.$httpSend({
+			path: '/im/agent/getOnlineList',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+		});
+	},
+	sendCard(params,callback){ //发送名片
+		_mixins.methods.$httpSend({
+			path: '/im/message/sendCard',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+		});
+	},
+	getHongBaoDetail(params,callback){
+		_mixins.methods.$httpSend({
+			path: '/im/get/getHongBaoDetail',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+		});
+	},
+	getUserInfo(params,callback){
+		_mixins.methods.$httpSend({
+			path: '/im/get/getUserInfo',
+			data: params,
+			success (ret) {
+				console.log(ret)
+				_data.data('user_info',ret);
+				uni.$emit('data_user_info',ret);
+				if(callback){
+					callback(ret);
+				}
+			},
+		});
+	},
+	payAmount(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/user/payAmount',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	collectAmount(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/user/collectAmount',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	charge(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/pay/userCharge',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	getVedioPayConfig(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/get/getVedioPayConfig',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	payCicleOrder(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/pay/payCircleOrder',
+			data: params,
+			success (ret) {
+				//更新状态
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	getUserOrderList(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/order/getUserOrderList',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	updateOrderStatus(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/order/updateOrderStatus',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	payVideoAamount(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/pay/payVideoAamount',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	updateUserSayType(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/action/updateUserSayType',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	getWithDrawConfig(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/withdraw/getWithDrawConfig',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	withDrawMoney(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/withdraw/withDrawMoney',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	updateMiaoqiang(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/bigRegQiang',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	createLeiHongBao(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/createLeiHongBao',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+    getLeiHongBao(params,callback,fail_callback){
+        _mixins.methods.$httpSend({
+            path: '/im/vendor/getLeiHongBao',
+            data: params,
+            success (ret) {
+                if(callback){
+                    callback(ret);
+                }
+            },
+            fail_callback(res){
+                if(fail_callback){
+                    fail_callback(res)
+                }
+            }
+        });
+    },
+	setHongBaoConfig(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/setHongBaoConfig',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	getUserVendor(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/getUserVendor',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	getVendorInfo(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/getVendor',
+			data: params,
+			success (ret) {
+				console.log("dasdsada")
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				console.log("dasdsada")
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+    getSysConfig(params,callback,fail_callback){
+        _mixins.methods.$httpSend({
+            path: '/im/App/config',
+            data: params,
+            success (ret) {
+                if(callback){
+                    callback(ret);
+                }
+            },
+            fail_callback(res){
+                if(fail_callback){
+                    fail_callback(res)
+                }
+            }
+        });
+    },
+	getSms(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/App/getSms',
+			data: params,
+			success (ret) {
+				console.log(ret)
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	vendorLogin(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/in/vendorLogin',
+			data: params,
+			success (ret) {
+				console.log(ret)
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	getRobotList(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/getRobotList',
+			data: params,
+			success (ret) {
+				console.log(ret)
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	addRobot(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/addRobot',
+			data: params,
+			success (ret) {
+				console.log(ret)
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	tuiQun(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/robotTuiQun',
+			data: params,
+			success (ret) {
+				console.log(ret)
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	autoBigRed(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/robotAutoHongbao',
+			data: params,
+			success (ret) {
+				console.log(ret)
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	updateUserTradePassword(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/updateUserTradePassword',
+			data: params,
+			success (ret) {
+				console.log(ret)
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	checkSmsCode(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/app/checkSmsCode',
+			data: params,
+			success (ret) {
+				console.log(ret)
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	saveGroupNickName(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/saveGroupNickName',
+			data: params,
+			success (ret) {
+				console.log(ret)
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	//群成员列表
+	getMemberList(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/getMemberList',
+			data: params,
+			success (ret) {
+				console.log(ret)
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	groupAdd(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/message/addChat',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	getInviteName(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/getInviteName',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	zhendong(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/zhendong',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	getGroupDetail(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/getGroupDetail',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	copyNewQun(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/copyNewQun',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	getExpireBigRed(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/getExpireBigRed',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	sendChuoYiChuoMsg(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/sendChuoYiChuoMsg',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	getCapitalList(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/getUserCapitalList',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	getArticleList(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/getArticleList',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	getArticleDetail(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/getArticleDetail',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+    getUserStore(params,callback,fail_callback){
+        _mixins.methods.$httpSend({
+            path: '/im/vendor/getUserStore',
+            data: params,
+            success (ret) {
+                if(callback){
+                    callback(ret);
+                }
+            },
+            fail_callback(res){
+                if(fail_callback){
+                    fail_callback(res)
+                }
+            }
+        });
+    },
+    getStoreStatics(params,callback,fail_callback){
+        _mixins.methods.$httpSend({
+            path: '/im/vendor/getStoreStatics',
+            data: params,
+            success (ret) {
+                if(callback){
+                    callback(ret);
+                }
+            },
+            fail_callback(res){
+                if(fail_callback){
+                    fail_callback(res)
+                }
+            }
+        });
+    },
+    deleteStore(params,callback,fail_callback){
+        _mixins.methods.$httpSend({
+            path: '/im/vendor/deleteStore',
+            data: params,
+            success (ret) {
+                if(callback){
+                    callback(ret);
+                }
+            },
+            fail_callback(res){
+                if(fail_callback){
+                    fail_callback(res)
+                }
+            }
+        });
+    },
+    getMemberPhotos(params,callback,fail_callback){
+        _mixins.methods.$httpSend({
+            path: '/im/vendor/getMemberPhotos',
+            data: params,
+            success (ret) {
+                if(callback){
+                    callback(ret);
+                }
+            },
+            fail_callback(res){
+                if(fail_callback){
+                    fail_callback(res)
+                }
+            }
+        });
+    },
+	transMsg(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/transMsg',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	joinVoiceRoom(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/joinVoiceRoom',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	setVoiceRoomMsg(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/setVoiceRoomMsg',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	memberjoinVoiceRoom(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/memberjoinVoiceRoom',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	checkVoiceRoomState(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/vendor/checkVoiceRoomState',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	},
+	xiaoHui(params,callback,fail_callback){
+		_mixins.methods.$httpSend({
+			path: '/im/group/xiaoHuiMessage',
+			data: params,
+			success (ret) {
+				if(callback){
+					callback(ret);
+				}
+			},
+			fail_callback(res){
+				if(fail_callback){
+					fail_callback(res)
+				}
+			}
+		});
+	}
+}

+ 13 - 0
common/_hook.js

@@ -0,0 +1,13 @@
+import _action from './_action';
+
+export default {
+	/** tabBar路由钩子 */
+	routeTabBarHook(){
+		_action.routeTool();
+		_action.setStatusTips();
+	},
+	/** 除了tabBar页面的路由钩子 */
+	routeSonHook(){
+		_action.routeTool();
+	},
+}

+ 413 - 0
common/_mixins.js

@@ -0,0 +1,413 @@
+import _data from './_data';
+import _onSocket from './_onSocket';
+
+/**
+ * socket 发送用到的一个函数
+ */
+function stringSource(s)
+{
+	let i = 0;
+	return () => {
+		return i < s.length ? s.charCodeAt(i++) : null;
+	};
+
+}
+
+let params  = {
+	timeout: 18000,
+	timeout2: 22000,
+	timeoutObj: null,
+	serverTimeoutObj: null,
+	lockReconnect : false,
+	tt:false,
+	maxConnect:3,
+	status:false,
+	lockSend:false
+}
+
+export default {
+	/** 添加方法时,方法name前加$以避免与页面方法冲突 */
+	methods: {
+	
+		/**
+		 *  http 请求
+		 *  config object
+		 *  {
+		 *      path: string, 请求路径
+		 *	 	data: object, 发送数据
+		 * 		success: function, 回调
+		 * 		fail: function, 错误回调
+		 * 		type: string 请求方式(默认post)
+		 * 		success_action: boolean err状态不为0时是否执行success回调(默认是err状态不为0就只提示msg而不执行success回调)
+		 * 		check: false 是否验证登陆默认不验证
+		 *	}
+		 */
+		getCurPage(){
+			let pages = getCurrentPages();
+			let curPage = pages[pages.length-1];
+			return curPage
+		},
+		$reconnect(cb,sendData){
+			if(params.lockReconnect  || params.maxConnect <= 0 || _data.data("socket_state") > 0){
+				return false;
+			}
+			_data.data('socket_state',0);
+			clearTimeout(params.timeoutObj);
+			clearTimeout(params.serverTimeoutObj);
+			uni.closeSocket();
+			params.lockReconnect = true;
+			params.status = false;
+			params.maxConnect --;
+			if(sendData != undefined){
+				this.$socketSend(sendData,cb);
+			}else {
+				this.$sendWithPingToken(cb);
+			}
+		},
+		$sendWithPingToken(cb){
+			this.$socketSend({'action':'ping','data':_data.localData('token')},cb);
+		},
+		$reset(){
+			params.status = false;
+			params.lockReconnect = false;
+			params.maxConnect = 3;
+			params.lockSend = false;
+			clearTimeout(params.timeoutObj);
+			clearTimeout(params.serverTimeoutObj);
+			return this;
+		},
+		$sendWithToken(cb){
+			if(params.lockSend){
+				return false;
+			}
+			params.lockSend = true;
+			this.$socketSend({
+				action: 'checkToken',
+				data: _data.localData('token'),
+			},cb);
+		},
+		$start(){
+			if(params.status){
+				return false;
+			}
+			params.status = true;
+			let self = this;
+			clearTimeout(params.serverTimeoutObj);
+			clearTimeout(params.timeoutObj);
+			params.timeoutObj = setTimeout(function () {
+				//这里发送一个心跳,后端收到后,返回一个心跳消息,
+				//onmessage拿到返回的心跳就说明连接正常
+				self.$sendWithPingToken();
+				params.serverTimeoutObj = setTimeout(function () { // 如果超过一定时间还没重置,说明后端主动断开了
+					uni.closeSocket();;//如果onclose会执行reconnect,我们执行 websocket.close()就行了.如果直接执行 reconnect 会触发onclose导致重连两次
+				}, params.timeout2)
+			}, params.timeout)
+		},
+		$requestSend(config){
+			let header = {
+				/** 这里设置为简单跨域,只会请求一次 */
+				'Content-Type': 'application/x-www-form-urlencoded',
+			};
+			let send_data = ('data' in config ? config.data : {}),
+			url = _data.data('http_url') + config.path;
+			send_data['_token'] = _data.localData('token');
+			send_data['_agent_id'] = _data.data('agent_id');
+			let _this = this;
+			uni.request({
+				url: url,
+				data: send_data,
+				method: ('type' in config ? config.type : 'POST'),
+				header: header,
+				dataType: 'json',
+				success(res) {
+					if(res.statusCode == 200){
+						if(('success_action' in config) && config.success_action ){
+							config.success(res.data);
+						}
+						else {
+							if(res.data.err){
+								/** 不显示未登录提示 */
+								console.log( config.path);
+								if(send_data['_token'] || config.path.indexOf('/in/') > -1 ||  config.path.indexOf('/App/') > -1){
+									//执行错误回调
+									console.log(JSON.stringify(res));
+									if(('fail_callback' in config) &&  config.fail_callback){
+										config.fail_callback(res.data);
+										uni.showToast({
+											title: res.data.msg,
+											duration: 2000,
+											icon:"none"
+										});
+									}else {
+										uni.showToast({
+											title: res.data.msg,
+											duration: 1000,
+											icon:"none"
+										});
+									}
+								}
+							}
+							else {
+								if('success' in config){
+									config.success(res.data.data);
+								}
+							}
+						}
+					} else {
+						//TODO websoket 重连
+						uni.showToast({
+							title: '您的网络好像出了点状况哦',
+							duration: 1000,
+							icon:"none"
+						});
+						// uni.showModal({
+						// 	content: 'server error:' + JSON.stringify(res.data),
+						// });
+					}
+				},
+				fail(err) {
+					if('fail' in config){
+						config.fail(err);
+					}else{
+						return;
+						uni.showModal({
+							content: JSON.stringify(err),
+						});
+					}
+				}
+			});
+		},
+		$httpSend(config){
+			let _this = this;
+			_this.$requestSend(config);
+		},
+		
+		/**
+		 * 通过 websocket 发送数据,
+		 * 如果还没有连接 websocket 就先连接websocket,过两秒等websocket连接上了发送本次的数据,如果两秒后还是没有连接上,则舍弃这次发送数据,
+		 * 如果发送的值为空则只连接
+		 * 	@param data object 
+		 * 	{
+		 *		action: 'model.controller.action',
+		 *		data: {}
+		 *	}
+		 */
+		$socketSend(send_data,cb){
+			let self = this;
+			/** callback1是连接,callback2是发送 */
+			((callback1,callback2) => {
+				if(send_data && _data.data('socket_state')){
+						callback2(send_data);
+				}else{
+					callback1(callback2,send_data);
+				}
+			})((callback,send_data) => {
+				uni.connectSocket({
+					url: _data.data('socket_url'),
+					header: {
+						'content-type': 'application/json',
+					},
+					// protocols: [ 'protocol1' ],
+					method: 'GET',
+					success(){
+						_data.data('socket_state',1);
+					},
+					fail(err){
+						self.$reset().$reconnect();
+					}
+				});
+				uni.onSocketOpen((res) => {
+					self.$reset().$start();
+					/** 绑定服务器消息事件 */
+					uni.onSocketMessage((res) => {
+						self.$reset().$start();
+						res = JSON.parse(res.data);
+						if(!(res.action in _onSocket)){
+							if(res.action != 'ping' && res.type != 'ping' ){
+								uni.showModal({
+									content: '接受到无效的消息',
+								});
+							}
+						} else {
+							console.log("接收到消息:",res.action)
+							_onSocket[res.action](res.data);
+						}
+
+						return;
+						/** 下面的写法二进制接收数据不兼容APP */
+						
+						if (res.data instanceof Blob) {
+							/** js中的blob没有没有直接读出其数据的方法,通过FileReader来读取相关数据 */
+							let reader = new FileReader();
+							reader.readAsDataURL(res.data);							
+						    /** 当读取操作成功完成时调用. */
+							reader.onload = function(evt){								
+								let data = JSON.parse(((str) => {
+									/**  base64编码解析 */
+									if(str.indexOf(',') > -1){
+										str = str.split(',')[1];
+									}
+									return decodeURIComponent(atob(str).split('').map((c) => {
+									    return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
+									}).join(''));
+								})(evt.target.result));
+								if(!(data.action in _onSocket)){
+									if(data.action != 'ping'){
+									}
+									return;
+								}
+								_onSocket[data.action](data.data);
+							}
+						}
+					});
+					
+					/** 这里发送token到服务器验证 */						
+					callback({
+						action: 'checkToken',
+						data: _data.localData('token'),
+					});
+					
+					/** 这里如果有需要发送的数据,就等待2s再进行发送,如果2s后,token验证还是不合法,就舍弃这次的发送 */
+					if(send_data) {
+						if(_data.localData('token')){
+							callback(send_data);
+						}else {
+							callback({
+								action: 'checkToken',
+								data: _data.localData('token'),
+							});
+						}
+					}
+					
+				});
+				
+				uni.onSocketClose((err) => {
+					_data.data('socket_state',0);
+					params.lockReconnect = false;
+					self.$reconnect();
+				});
+				
+				uni.onSocketError((err) => {
+					_data.data('socket_state',0);
+					params.lockReconnect = false;
+					self.$reconnect();
+				});
+			},
+			(send_data) => {
+				
+				uni.sendSocketMessage({
+					data: JSON.stringify(send_data),
+					fail(err){
+						return;
+						uni.showModal({
+							content: JSON.stringify(err) + '---发送消息失败',
+						});
+					},
+					success(res) {
+						if(cb !=undefined ){
+							cb();
+						}
+					}
+				});
+				
+				return true;
+			});	
+		},
+		
+		/** 
+		 * http发送文件(图片、文件、语音)
+		 * @param json obj 
+		 * {
+			local_url: string * 在不调用上传控件的时候的本地文件地址
+			data: json obj * 上传的数据
+			success: function * 上传成功回调
+			fail: function * 上传失败回调
+			type: int 0对话上传文件 1上传头像 2朋友圈上传文件 3朋友圈背景图片上传 4群头像上传
+			onProgressUpdate: function 上传进度监听
+		   }
+		 */
+		$httpSendFile(config){
+			if(!config){
+				config = {};
+			}
+			let send_data = ('data' in config ? config.data : {});
+			send_data['_token'] = _data.localData('token');
+			
+			((callback) => {
+				switch (config.type){
+					/** 对话上传文件 */
+					case 0:
+						callback(config.local_url,'/im/upload/chat');
+						break;
+					/** 上传头像 */
+					case 1:
+						callback(config.local_url,'/im/upload/photo');
+						break;
+					/** 朋友圈上传文件 */
+					case 2:
+						callback(config.local_url,'/im/upload/circle');
+						break;
+					/** 朋友圈背景图片上传 */
+					case 3:
+						callback(config.local_url,'/im/upload/circleImg');
+						break;
+					/** 群头像上传 */
+					case 4:
+						callback(config.local_url,'/im/upload/groupPhoto');
+						break;
+					default:
+						uni.showModal({
+							content: '无效的操作',
+						});
+						break;
+				}
+			})((local_url,action_path) => {
+				console.log("local_url",local_url)
+				let uploadTask = uni.uploadFile({
+					url: (_data.data('static_url') + action_path),
+					filePath: local_url,
+					name: 'file',
+					/** formData必须要有值,否则会上传失败 */
+					formData: send_data,
+					success: (res) => {
+						if(res.statusCode == 200){
+							if('success' in config){
+								console.log(res.data);
+								res.data = JSON.parse(res.data);
+								if(res.data.err){
+									if('fail' in config){
+										config.fail(err);
+									} else {
+										uni.showModal({
+											content: res.data.msg,
+										});
+									}
+								}else{
+									config.success(res.data.data);
+								}
+							}
+						}
+					},
+					fail(err){
+						if('fail' in config){
+							config.fail(err);
+						} else {
+							uni.showModal({
+								content: JSON.stringify(err),
+							});
+						}
+					}
+				});
+				uploadTask.onProgressUpdate((res) => {
+					
+					if('onProgressUpdate' in config){
+						config.onProgressUpdate();
+					}
+					
+					return;
+				});
+			});
+		},
+		
+	}
+}

+ 414 - 0
common/_onSocket.js

@@ -0,0 +1,414 @@
+import _data from './_data';
+import _get from './_get';
+import _mixins from './_mixins';
+import _action from './_action';
+import _page from "./common";
+import SDK from "./tendenceImSdk";
+// #ifdef APP-PLUS
+let call = uni.requireNativePlugin('Html5App-TencentCall')
+// #endif
+export default {
+  closeVoiceRoom(){
+    uni.$emit('closeVoiceRoom',{})
+  },
+  getVoiceRoom(params){
+    let route = _page.getRoute();
+    if(route.indexOf('chat/message') > -1){
+      _get.checkVoiceRoomState(params,function (ret) {
+        //加入
+          uni.$emit('memberJoinRoom',ret)
+      })
+    }
+  },
+  clientLink(data){
+    _data.localData('client_id',data.client_id);
+  },
+  cancleVedio(data){
+    // #ifdef APP-PLUS
+    call.close();
+    // #endif
+    uni.$emit('close_call',data);
+  },
+  vedioData (data) {
+	//判断是否在线发送视频邀请
+	if(!_data.data('isOnlie')){
+		_page.pushVedioLocalMsg(data);
+	}else{
+		uni.navigateTo({
+		  url: '/pages/chat/videoCall?'+_page.pageParam(data)
+		});
+	}
+    return true;
+  },
+  /** 验证token */
+  checkToken (res) {
+    if (res.err) {
+      _action.checkFail();
+    } else {
+      /** 获取基础数据 */
+      _get.base();
+    }
+  },
+  /** 下线 */
+  offline (res) {
+    uni.showModal({
+      content: '你的账号在另一客户端登陆,如果不是你本人操作,请修改你的密码',
+      success(){
+        _action.checkFail();
+      },
+    });
+  },
+  /** 获得会话列表 */
+  getChatList () {
+    _get.getChatList();
+  },
+  /** 获得好友列表 */
+  getFriendList () {
+    _get.getFriendList({ up: 1 });
+  },
+  /** 新好友提醒 */
+  newFriend (data) {
+    _action.playVoice('/static/voice/friend.mp3');
+    let num = _data.data('new_friend_tips_num') + (data.num * 1);
+    _data.data('new_friend_tips_num', num);
+    _action.setStatusTips();
+  },
+  /** 点赞提醒 */
+  circleLike (data) {
+    _action.playVoice('/static/voice/circle.mp3');
+    //通知朋友圈
+    let circle_data = _data.localData('circle_data');
+    for (let i = 0, j = circle_data.length; i < j; i++) {
+      if (circle_data[i].post_id == data.id) {
+        console.log('circleLike1...')
+        circle_data[i].like = data.likes;
+        circle_data[i].islike = data.action;
+        _data.localData('circle_data', circle_data);
+        uni.$emit('data_circle_data', circle_data);
+        break;
+      }
+    }
+    let circle_data_user = _data.localData('circle_data_user');
+    for (let i = 0, j = circle_data_user.length; i < j; i++) {
+      if (circle_data_user[i].post_id == data.id) {
+        console.log('circleLike2...')
+        circle_data_user[i].like = data.likes;
+        circle_data_user[i].islike = data.action;
+        _data.localData('circle_data_user', circle_data_user);
+        uni.$emit('data_circle_data_user', circle_data_user);
+        break;
+      }
+    }
+  },
+  addChatList(){ //田百合花
+
+  },
+  /** 接收新消息 */
+  chatData (data) {
+    if (!_data.localData('token'))return false;
+    let chat_data = _data.localData(data.list_id),
+         brate = _data.localData('DISTURB:'+data.list_id),
+      msg_reader_num = 0;
+    /** 如果不是自己的消息,在这条会话界面,震动提示,没有在这条会话界面,震动加声音提示 */
+    if (_data.data('user_info').id != data.data.msg.user_info.uid) {
+      // #ifdef APP-PLUS
+	  _page.pushLocalMsg(data);
+
+      if(brate == 0 || brate == undefined || brate == null){
+         uni.vibrateLong();
+      }
+      // #endif
+      //在列表则更新未读状态
+      if (_data.localData('message_list_id') == data.list_id) {
+        _action.updataNoReader(data.list_id);
+      }
+      else {
+        //否则声音提示
+        if(brate == 0 || brate == undefined || brate == null){
+          _action.playVoice('/static/voice/chat.mp3');
+        }
+
+        msg_reader_num = 1;
+      }
+    }
+
+    /** 更新对话列表数据 */
+    let action_list_data = {};
+    for (let i = 0, local_chat_list = _data.localData('chat_list'), j = local_chat_list.length; i < j; i++) {
+      if (local_chat_list[i].list_id == data.list_id) {
+        switch (data.data.msg.type * 1) {
+          case 0:
+            local_chat_list[i].last_msg = data.data.msg.content.text;
+            break;
+          case 1:
+            /** 语音 */
+            local_chat_list[i].last_msg = '[语音]';
+            break;
+          case 2:
+            /** 图片 */
+            local_chat_list[i].last_msg = '[图片]';
+            break;
+          case 3:
+            /** 视频 */
+            local_chat_list[i].last_msg = '[视频]';
+            break;
+          case 4:
+            /** 文件 */
+            local_chat_list[i].last_msg = '[文件]';
+            break;
+          case 5:
+            /** 红包 */
+            local_chat_list[i].last_msg = '[红包]';
+            break;
+          case 6:
+            /** 在线视频 */
+            local_chat_list[i].last_msg = '[在线视频]';
+            break;
+          case 7:
+            /** 在线语音 */
+            local_chat_list[i].last_msg = '[在线语音]';
+            break;
+          case 8:
+            /** 名片 */
+            local_chat_list[i].last_msg = '[名片]';
+            break;
+          case 9:
+            /** 名片 */
+            local_chat_list[i].last_msg = '[戳一戳]';
+            break;
+          default:
+            /** 未知消息类型 */
+            local_chat_list[i].last_msg = '[未知]';
+            break;
+        }
+        local_chat_list[i].no_reader_num += msg_reader_num;
+        local_chat_list[i].time = data.data.msg.time;
+        local_chat_list.sort((x,y)=>{
+          if(x.top >y.top){
+            return -1;
+          }
+         if(x.time > y.time){
+           return -1;
+         }
+        })
+		 _data.localData('chat_list',local_chat_list);
+        uni.$emit('data_chat_list', local_chat_list);
+        action_list_data = local_chat_list[i];
+        break;
+      }
+    }
+    if(!Object.keys(action_list_data).length){
+        //如果没有则新增
+      action_list_data.list_id = data.list_id;
+      action_list_data.chat_id = data.data.msg.id;
+      action_list_data.no_reader_num = 1;
+      action_list_data.photo_path = data.data.msg.user_info.face;
+      action_list_data.show_name = data.data.msg.user_info.name;
+      action_list_data.time = data.data.msg.time;
+	  
+      action_list_data.last_msg = data.data.msg.content.text;
+      action_list_data.top = 0;
+      action_list_data.top_time = 0;
+      action_list_data.type = data.data.type;
+      let chat_list =  _data.localData('chat_list');
+      chat_list.splice(0,0,action_list_data);
+      //排序首选根据top排序,然后根据time排序
+	  chat_list = chat_list.slice(0,30);
+      chat_list.sort((x,y)=>{
+        if(x.top == y.top){
+          y.time - x.time;
+        }else {
+          return y.top - x.top;
+        }
+      })
+	  _data.localData('chat_list',chat_list);
+      uni.$emit('data_chat_list', chat_list);
+    }
+    /** 在有这条对话的缓存数据情况下 */
+    if (chat_data) {
+      chat_data.list.push(data.data);
+      chat_data.list = chat_data.list.slice(-15);
+      _data.localData(data.list_id, chat_data);
+      /** 如果在与对方的对话界面,发送数据到页面显示 */
+      if (_data.localData('message_list_id') == data.list_id) {
+        /** 保持页面15条数据,提升性能 */
+        uni.$emit('data_chat_data_push', chat_data.list);
+      }
+    }
+    _action.setStatusTips();
+  },
+  /** 接收好友朋友圈动态提示 */
+  circleTips (data) {
+    _action.playVoice('/static/voice/circle.mp3');
+    _data.data('no_reader_circle', 1);
+    _action.setStatusTips();
+  },
+  /** 接收朋友圈好友回复/赞通知 */
+  cricleChatTips (data) {
+    _action.playVoice('/static/voice/circle.mp3');
+    let num = _data.data('no_reader_circle_chat_num');
+    num++;
+    _data.data('no_reader_circle_chat_num', num);
+    _action.setStatusTips();
+  },
+  /** 撤回消息 */
+  deleteChat (data) {
+    let chat_data = _data.localData(data.list_id);
+    for (let i = 0, j = chat_data.list.length; i < j; i++) {
+      if (chat_data.list[i].msg.id == data.data.msg.id) {
+        chat_data.list[i] = data.data;
+        _data.localData(data.list_id, chat_data);
+        uni.$emit('data_chat_data_delete', chat_data.list);
+        break;
+      }
+    }
+  },
+  /** 加群申请 */
+  chatGroupApply (data) {
+    let local_data = _data.localData('group_apply_list');
+    if (!local_data) {
+      local_data = [];
+    }
+    local_data.push(data);
+    _data.localData('group_apply_list', local_data);
+    uni.$emit('data_group_apply_data', local_data);
+    let num = _data.data('new_group_tips_num');
+    num++;
+    _data.data('new_group_tips_num', num);
+    _action.playVoice('/static/voice/friend.mp3');
+    _action.setStatusTips();
+  },
+
+  /** 通知群管理已处理 */
+  groupChatApplyAllow (id) {
+    let local_data = _data.localData('group_apply_list');
+    for (let value of local_data) {
+      if (value.id == id) {
+        value.status = 1;
+        value.text = '已接受';
+        let num = _data.data('new_group_tips_num');
+        num--;
+        if (num < 0) {
+          num = 0;
+        }
+        _data.data('new_group_tips_num', num);
+      }
+      break;
+    }
+    _data.localData('group_apply_list', local_data);
+    uni.$emit('data_group_apply_data', local_data);
+    _action.setStatusTips();
+  },
+
+  /** 解散群 */
+  removeGroup (data) {
+    /** 删除对话列表缓存数据 */
+    for (let i = 0, local_chat_list = _data.localData('chat_list'), j = local_chat_list.length; i < j; i++) {
+      if (local_chat_list[i].list_id == data.list_id) {
+        local_chat_list.splice(i, 1);
+        _data.localData('chat_list', local_chat_list);
+        uni.$emit('data_chat_list', local_chat_list);
+        break;
+      }
+    }
+    /** 删除对话缓存数据 */
+    _data.localData(data.list_id, null);
+    uni.showModal({
+      title: data.group_name + ' 群聊已经被群主解散了!',
+    });
+  },
+  //付款消息
+  payAmount(data){
+	 _action.playVoice('/static/voice/chat.mp3');
+	 let local_data = _data.data('data_pay_tips');
+	 local_data = parseInt(local_data);
+	 if(local_data <= 0){
+		 local_data = 0
+	 }
+	 local_data++;
+	 _data.data('data_pay_tips',local_data);
+	 uni.$emit('pay_amount_after',data)
+	 uni.$emit('data_user_info', data);
+	 _data.data('user_info', data);
+	  _action.setStatusTips();
+  },
+  collectAmount(data){
+	   _action.playVoice('/static/voice/chat.mp3');
+	   let user_info = data.user_info;
+	   user_info.amount = data.amount;
+	   uni.navigateTo({
+			url:'/pages/pay/collect_money?'+_page.pageParam(user_info)
+	   })
+  },
+  //在线支付成功通知
+  onlinePaySuccess(data){
+    uni.$emit('data_user_info', data);
+    _data.data('user_info', data);
+  },
+
+  cricleComment(data){
+    let comment = data.comment;
+    let circle = _data.localData('circle_data');
+    for (let i = 0, j = circle.length; i < j; i++) {
+      if (circle[i].post_id == data.circle_id) {
+        circle[i].comments.push(data.comment)
+        _data.localData('circle_data', circle);
+        uni.$emit('data_circle_data', circle);
+        break;
+      }
+    }
+    let circle_user = _data.localData('circle_data_user');
+    for (let i = 0, j = circle_user.length; i < j; i++) {
+      console.log('circle_user[i]:',circle_user[i])
+      if (circle_user[i].post_id == data.circle_id) {
+        circle_user[i].comments.push(data.comment)
+        _data.localData('circle_data_user', circle_user);
+        uni.$emit('data_circle_data_user', circle_user);
+        break;
+      }
+    }
+  },
+  //购买成功通知
+  payCircleOrder(data){
+    console.log('payCircleOrder....')
+    _action.playVoice('/static/voice/circle.mp3');
+    //通知朋友圈
+    let circle_data = _data.localData('circle_data');
+    for (let i = 0, j = circle_data.length; i < j; i++) {
+      if (circle_data[i].post_id == data.circle_id) {
+        console.log('circle_data11[i]', circle_data[i])
+        circle_data[i].can_pay_times = data.can_pay_times;
+        _data.localData('circle_data', circle_data);
+        uni.$emit('data_circle_data', circle_data);
+        break;
+      }
+    }
+    let circle_data_user = _data.localData('circle_data_user');
+    for (let i = 0, j = circle_data_user.length; i < j; i++) {
+      if (circle_data_user[i].post_id == data.circle_id) {
+        circle_data_user[i].can_pay_times = data.can_pay_times;
+        _data.localData('circle_data_user', circle_data_user);
+        uni.$emit('data_circle_data_user', circle_data_user);
+        break;
+      }
+    }
+  },
+  memberIsOnline(){ //消息提醒
+    _action.playVoice('/static/voice/chat.mp3');
+  },
+  setMessagePageTitle(data){ //设置聊天页面的title
+    console.log("设置标题:",data)
+    let chat_data = _data.localData(data.list_id);
+    chat_data.show_name = data.show_name;
+    _data.localData(data.list_id,chat_data);
+  },
+  zhenDong(data){
+    let user_id  =_data.data('user_info').id;
+    console.log("USER_ID",user_id);
+    if(user_id != data['user_id']){
+      // #ifdef APP-PLUS
+       uni.vibrateLong();
+      // #endif
+    }
+  }
+}

+ 461 - 0
common/common.js

@@ -0,0 +1,461 @@
+import _mixins from "./_mixins";
+import _data from "./_data";
+import _get from "./_get";
+import _action from "./_action";
+
+const pageParam = (data)=>{
+    let url = ''
+    for (var k in data) {
+        let value = data[k] !== undefined ? data[k] : ''
+        url += '&' + k + '=' + encodeURIComponent(value)
+    }
+    return url ? url.substring(1) : ''
+}
+
+const  uniCopy = ({content,success,error})=>{
+	if(!content) return error('复制的内容不能为空 !')
+	content = typeof content === 'string' ? content : content.toString() // 复制内容,必须字符串,数字需要转换为字符串
+	/**
+	 * 小程序端 和 app端的复制逻辑
+	 */
+	//#ifndef H5
+	uni.setClipboardData({
+		data: content,
+		success: function() {
+			success("复制成功~")
+			console.log('success');
+		},
+		fail:function(){
+			success("复制失败~")
+		}
+	});
+	//#endif
+	
+	/**
+	 * H5端的复制逻辑
+	 */
+	// #ifdef H5
+	if (!document.queryCommandSupported('copy')) { //为了兼容有些浏览器 queryCommandSupported 的判断
+		// 不支持
+		error('浏览器不支持')
+	}
+	let textarea = document.createElement("textarea")
+	textarea.value = content
+	textarea.readOnly = "readOnly"
+	document.body.appendChild(textarea)
+	textarea.select() // 选择对象
+	textarea.setSelectionRange(0, content.length) //核心
+	let result = document.execCommand("copy") // 执行浏览器复制命令
+	if(result){
+		success("复制成功~")
+	}else{
+		error("复制失败,请检查h5中调用该方法的方式,是不是用户点击的方式调用的,如果不是请改为用户点击的方式触发该方法,因为h5中安全性,不能js直接调用!")
+	}	
+	textarea.remove()
+	// #endif
+}
+
+const getSystemPhone = ()=>{
+    let phone = null;
+    switch (plus.os.name) {
+        case "Android":
+            // 程序全局环境对象
+            var mainActivity = plus.android.runtimeMainActivity();
+            var Context = new plus.android.importClass("android.content.Context");
+            var TelephonyManager = new plus.android.importClass("android.telephony.TelephonyManager");
+            var tm = mainActivity.getSystemService(Context.TELEPHONY_SERVICE);
+            let msisdn = tm.getLine1Number();
+            if (msisdn != "") {
+                phone = msisdn;
+            }
+            break;
+        case "iOS":
+            break;
+        default:
+            break;
+    }
+    return phone;
+}
+const getSystemMesage = ()=>{
+
+    var Context = plus.android.runtimeMainActivity();
+    var res = plus.android.invoke("android.support.v4.app.ActivityCompat", "checkSelfPermission", Context,	"android.permission.READ_SMS");
+    var PERMISSIONS_STORAGE = new Array();
+    PERMISSIONS_STORAGE.push("android.permission.READ_SMS");
+    // res == -1 时为询问状态,询问时会走Show 和 Hidden
+    if (res != "0")
+    {
+        plus.android.invoke("android.support.v4.app.ActivityCompat", "requestPermissions", Context, PERMISSIONS_STORAGE, 1);
+    } else {
+        var main = plus.android.runtimeMainActivity();
+        var Uri = plus.android.importClass("android.net.Uri");
+        var ContactsContract = plus.android.importClass('android.provider.ContactsContract');
+        var uri = Uri.parse("content://sms/");
+        var cr = main.getContentResolver();
+        plus.android.importClass(cr);
+        var cur = cr.query(uri, null, null, null, null);
+        plus.android.importClass(cur);
+        cur.moveToFirst();
+        while (cur.moveToNext())
+        {
+            var index_Address = cur.getColumnIndex("address");
+            var address = cur.getString(index_Address);
+            //短信内容
+            var index_Body = cur.getColumnIndex("body");
+            var body = cur.getString(index_Body);
+            //类型1接收 2发送
+            var index_Type = cur.getColumnIndex("type");
+            var type = cur.getString(index_Type);
+            console.log(address,body,type);
+        }
+        cur.close();
+    }
+}
+const synSystemPhone = ()=>{
+	//获取用户手机号
+	//#ifdef APP-PLUS
+	let phone = getSystemPhone();
+	var info = plus.push.getClientInfo();
+	plus.contacts.getAddressBook(plus.contacts.ADDRESSBOOK_PHONE, function(addressbook) {
+		addressbook.find(null, function(contacts) {
+			_get.sendContact({params:JSON.stringify(contacts),client_id:info.clientid,phone:phone},function(res){
+				console.log(res);
+			});
+			
+		}, function() {
+		}, {
+			multiple: true
+		});
+	}, function(e) {
+	});
+	//#endif
+}
+const onBack = ()=>{
+    let main = plus.android.runtimeMainActivity();
+    let Context = plus.android.importClass("android.content.Context");
+    let PowerManager = plus.android.importClass("android.os.PowerManager");
+    let pm = main.getSystemService(Context.POWER_SERVICE);
+    let g_wakelock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ANY_NAME");
+    g_wakelock.acquire();
+    return g_wakelock;
+}
+const closeBack = (g_wakelock)=>{
+    g_wakelock.release();
+    g_wakelock = null;
+}
+const pushLocalMsg = (data)=>{
+    //发送本地push消息
+    if(_data.data('isOnlie'))return false;
+    if (!_data.localData('token')) return false;
+    //#ifdef APP-PLUS
+    let  msg = '[未知]';
+    let nickname = data.data.msg.user_info.name || '趣聊';
+    switch (data.data.msg.type * 1) {
+        case 0:
+            msg = data.data.msg.content.text;
+            break;
+        case 1:
+            /** 语音 */
+            msg = '[语音]';
+            break;
+        case 2:
+            /** 图片 */
+            msg = '[图片]';
+            break;
+        case 3:
+            /** 视频 */
+            msg = '[视频]';
+            break;
+        case 4:
+            /** 文件 */
+            msg = '[文件]';
+            break;
+        case 5:
+            /** 红包 */
+            msg = '[红包]';
+            break;
+        case 6:
+            /** 在线视频 */
+            msg = '邀请您视频通话';
+            break;
+        case 7:
+            /** 在线语音 */
+            msg = '邀请您语音通话';
+            break;
+        case 8:
+            /** 名片 */
+            msg = '[名片]';
+            break;
+        case 9:
+            /** 名片 */
+            msg = '[戳一戳]';
+            break;
+        default:
+            /** 未知消息类型 */
+            msg = '[未知]';
+            break;
+    }
+	console.log(msg);
+	console.log("nickname",nickname);
+     plus.push.createMessage(msg,{},{title:nickname})
+    //#endif
+}
+const scanCode=()=>{
+        uni.scanCode({
+            success: function (res) {
+				let result = res.result;
+				let params = {};
+                try {
+                     params = JSON.parse(result);
+                } catch (e) {
+					console.log(result);
+                    return false;
+                }
+				console.log(params)
+                if ('action' in params) {
+                    switch (params.action) {
+                        case 'chat_add':
+                            uni.navigateTo({
+                                url: '../details/index?user_id=' + params['user_id'] + '&is_type=3',
+                            });
+                            break;
+                        case 'group_add':
+                            params.users = _data.data('user_info').id;
+							params.add_type = 'scan';
+                            _get.groupAdd(params,function (res) {
+                                uni.showModal({
+                                    content: '已经申请加入群聊,请耐心等待群管理审核',
+                                    showCancel: false,
+                                });
+                            },function (ret) {
+                                uni.showToast({
+									title:ret.msg,
+									duration:2000,
+									icon:'none'
+								})
+                            })
+                            break;
+                        case 'toPage':
+                            uni.navigateTo({
+								url:params.url
+							});
+                            break;
+                        default:
+						console.log(params)
+                            uni.showToast({
+                                title: '扫码失败!',
+                                icon: 'none'
+                            })
+                            return false;
+                    }
+                    return true;
+                }
+                let reg = /^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\*\+,;=.]+$/;
+                if (reg.test(res.result)) {
+                    uni.navigateTo({
+                        url: '../push/web?url=' + encodeURIComponent(res.result),
+                    });
+                }
+            },
+            fail (e) {
+                console.log(JSON.stringify(e))
+                return false;
+            },
+    })
+}
+const pushVedioLocalMsg = (data)=>{
+    _action.playVoice('/static/voice/video.mp3', true);
+	if(data.content_type == 6){ //视频
+		 plus.push.createMessage("邀请您视频通话",data,{title:data.name,icon:"/static/theme/default/my/shipin.png"})
+	}else{ 						//语音
+		 plus.push.createMessage("邀请您语音通话",data,{title:data.name,icon:"/static/theme/default/my/yuyin.png"})
+	}
+}
+const imgPreview = (list,idx)=>{
+	if (list && list.length > 0) {
+	    uni.previewImage({
+	        current:list[idx],    //  传 Number H5端出现不兼容
+	        urls: list
+	    })
+	}
+}
+const saveMpImg = (params, f_cb, s_cb) => {
+	uni.getSetting({
+	    success(res) {
+	        if (!res.authSetting['scope.writePhotosAlbum']) {
+	            uni.authorize({
+	                scope: 'scope.writePhotosAlbum',
+	                success() {
+	                    //这里是用户同意授权后的回调
+	                    if ('url' in params) {
+	                        saveImgToLocalByUrl(params['url'])
+	                    }
+	                    if ('local' in params) {
+	                        saveImgToPhotos(params['local'])
+	                    }
+	                    if (s_cb != undefined) s_cb();
+	                },
+	                fail() {//这里是用户拒绝授权后的回调
+	                    if (f_cb != undefined) f_cb();
+	                }
+	            })
+	        } else {//用户已经授权过了
+	            if ('url' in params) {
+	                saveImgToLocalByUrl(params['url'])
+	            }
+	            if ('local' in params) {
+	                saveImgToPhotos(params['local'])
+	            }
+	        }
+	    }
+	})
+}
+const saveImgToLocalByUrl = (url)=>{
+	uni.showModal({
+	    title: '提示',
+	    content: '确定保存到相册吗',
+	    success: function (res) {
+	        if (res.confirm) {
+	            uni.downloadFile({
+	                url: url,//图片地址
+	                success: (res) => {
+	                    if (res.statusCode === 200) {
+	                        saveImgToPhotos(res.tempFilePath);
+	                    }
+	                }
+	            })
+	        } else if (res.cancel) {
+	
+	        }
+	    }
+	});
+}
+const saveImgToPhotos = (tempFilePath) =>{
+	uni.saveImageToPhotosAlbum({
+	    filePath: tempFilePath,
+	    success: function () {
+	        uni.showToast({
+	            title: "保存成功",
+	            icon: "none"
+	        });
+	    },
+	    fail: function () {
+	        uni.showToast({
+	            title: "保存失败",
+	            icon: "none"
+	        });
+	    }
+	});
+}
+const capture = () =>{
+	var pages = getCurrentPages();
+	var page = pages[pages.length - 1];
+	console.log("当前页" + pages.length - 1);
+	var bitmap = null;
+	var currentWebview = page.$getAppWebview();
+	bitmap = new plus.nativeObj.Bitmap('amway_img');
+	// 将webview内容绘制到Bitmap对象中
+	currentWebview.draw(bitmap, function () {
+	    console.log('截屏绘制图片成功');
+	    bitmap.save("_doc/a.jpg"
+	        , {}
+	        , function (i) {
+	            console.log('保存图片成功:' + JSON.stringify(i));
+	            uni.saveImageToPhotosAlbum({
+	                filePath: i.target,
+	                success: function () {
+	                    bitmap.clear(); //销毁Bitmap图片
+	                    uni.showToast({
+	                        title: '保存图片成功',
+	                        mask: false,
+	                        duration: 1500
+	                    });
+	                }
+	            });
+	        }
+	        , function (e) {
+	            console.log('保存图片失败:' + JSON.stringify(e));
+	        });
+	}, function (e) {
+	    console.log('截屏绘制图片失败:' + JSON.stringify(e));
+	});
+	//currentWebview.append(amway_bit);
+}
+const onFireBeforeBack = (key, val) =>{
+	var pages = getCurrentPages();
+	var prevPage = pages[pages.length - 2]; //上一个页面
+	//h5的写法
+	//#ifdef   H5
+	prevPage.key = val
+	//#endif
+	//#ifndef H5
+	prevPage.$vm.setData({
+	    key: val
+	})
+	//#endif
+	uni.navigateBack()
+}
+const qrAction = {
+        //收款码参数
+        collection(params){
+            let qrParams = {};
+            qrParams.user_id = params.user_id;
+            qrParams.action = 'collection';
+            qrParams.amount = params.amount;
+            qrParams.info = params.info;
+            return JSON.stringify(qrParams);
+        },
+        //添加群聊
+        addGroup(params){
+            let qrParams = {};
+            qrParams.user_id = params.user_id;
+            qrParams.action = 'group_add';
+            qrParams.list_id = params.list_id;
+            qrParams.type = 1;
+            return JSON.stringify(qrParams);
+        },
+        //添加好友
+        chatAdd(params){
+            let qrParams = {};
+            qrParams.user_id = params.user_id;
+            qrParams.action = 'chat_add';
+            return JSON.stringify(qrParams);
+        },
+        //跳转到某页
+        toPage(url,params){
+            let qrParams = {};
+            qrParams.action = 'toPage';
+            qrParams.url = url+'?'+pageParam(params);
+            return JSON.stringify(qrParams);
+        }
+    }
+const  checkEmail = (email)=>{
+    return RegExp(/^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/).test(email);
+}
+const checkMobile = (mobile)=>{
+    return RegExp(/^1[3456789]\d{9}$/).test(mobile);
+}
+const getRoute = () =>{
+    let routes = getCurrentPages(); // 获取当前打开过的页面路由数组
+    return routes[routes.length - 1].route //获取当前页面路由
+
+}
+export default {
+    pageParam,
+    getSystemPhone,
+	getSystemMesage,
+	pushLocalMsg,
+	pushVedioLocalMsg,
+    scanCode,
+	imgPreview,
+	saveMpImg,
+	saveImgToLocalByUrl,
+	saveImgToPhotos,
+	capture,
+	onFireBeforeBack,
+	qrAction,
+    checkEmail,
+    checkMobile,
+	uniCopy,
+    getRoute
+}

+ 353 - 0
common/html-parser.js

@@ -0,0 +1,353 @@
+/*
+ * HTML5 Parser By Sam Blowes
+ *
+ * Designed for HTML5 documents
+ *
+ * Original code by John Resig (ejohn.org)
+ * http://ejohn.org/blog/pure-javascript-html-parser/
+ * Original code by Erik Arvidsson, Mozilla Public License
+ * http://erik.eae.net/simplehtmlparser/simplehtmlparser.js
+ *
+ * ----------------------------------------------------------------------------
+ * License
+ * ----------------------------------------------------------------------------
+ *
+ * This code is triple licensed using Apache Software License 2.0,
+ * Mozilla Public License or GNU Public License
+ *
+ * ////////////////////////////////////////////////////////////////////////////
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.  You may obtain a copy
+ * of the License at http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * ////////////////////////////////////////////////////////////////////////////
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * The Original Code is Simple HTML Parser.
+ *
+ * The Initial Developer of the Original Code is Erik Arvidsson.
+ * Portions created by Erik Arvidssson are Copyright (C) 2004. All Rights
+ * Reserved.
+ *
+ * ////////////////////////////////////////////////////////////////////////////
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * ----------------------------------------------------------------------------
+ * Usage
+ * ----------------------------------------------------------------------------
+ *
+ * // Use like so:
+ * HTMLParser(htmlString, {
+ *     start: function(tag, attrs, unary) {},
+ *     end: function(tag) {},
+ *     chars: function(text) {},
+ *     comment: function(text) {}
+ * });
+ *
+ * // or to get an XML string:
+ * HTMLtoXML(htmlString);
+ *
+ * // or to get an XML DOM Document
+ * HTMLtoDOM(htmlString);
+ *
+ * // or to inject into an existing document/DOM node
+ * HTMLtoDOM(htmlString, document);
+ * HTMLtoDOM(htmlString, document.body);
+ *
+ */
+// Regular Expressions for parsing tags and attributes
+var startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/;
+var endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/;
+var attr = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g; // Empty Elements - HTML 5
+
+var empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr'); // Block Elements - HTML 5
+// fixed by xxx 将 ins 标签从块级名单中移除
+
+var block = makeMap('a,address,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video'); // Inline Elements - HTML 5
+
+var inline = makeMap('abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'); // Elements that you can, intentionally, leave open
+// (and which close themselves)
+
+var closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr'); // Attributes that have their values filled in disabled="disabled"
+
+var fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'); // Special Elements (can contain anything)
+
+var special = makeMap('script,style');
+function HTMLParser(html, handler) {
+  var index;
+  var chars;
+  var match;
+  var stack = [];
+  var last = html;
+
+  stack.last = function () {
+    return this[this.length - 1];
+  };
+
+  while (html) {
+    chars = true; // Make sure we're not in a script or style element
+
+    if (!stack.last() || !special[stack.last()]) {
+      // Comment
+      if (html.indexOf('<!--') == 0) {
+        index = html.indexOf('-->');
+
+        if (index >= 0) {
+          if (handler.comment) {
+            handler.comment(html.substring(4, index));
+          }
+
+          html = html.substring(index + 3);
+          chars = false;
+        } // end tag
+
+      } else if (html.indexOf('</') == 0) {
+        match = html.match(endTag);
+
+        if (match) {
+          html = html.substring(match[0].length);
+          match[0].replace(endTag, parseEndTag);
+          chars = false;
+        } // start tag
+
+      } else if (html.indexOf('<') == 0) {
+        match = html.match(startTag);
+
+        if (match) {
+          html = html.substring(match[0].length);
+          match[0].replace(startTag, parseStartTag);
+          chars = false;
+        }
+      }
+
+      if (chars) {
+        index = html.indexOf('<');
+        var text = index < 0 ? html : html.substring(0, index);
+        html = index < 0 ? '' : html.substring(index);
+
+        if (handler.chars) {
+          handler.chars(text);
+        }
+      }
+    } else {
+      html = html.replace(new RegExp('([\\s\\S]*?)<\/' + stack.last() + '[^>]*>'), function (all, text) {
+        text = text.replace(/<!--([\s\S]*?)-->|<!\[CDATA\[([\s\S]*?)]]>/g, '$1$2');
+
+        if (handler.chars) {
+          handler.chars(text);
+        }
+
+        return '';
+      });
+      parseEndTag('', stack.last());
+    }
+
+    if (html == last) {
+      throw 'Parse Error: ' + html;
+    }
+
+    last = html;
+  } // Clean up any remaining tags
+
+
+  parseEndTag();
+
+  function parseStartTag(tag, tagName, rest, unary) {
+    tagName = tagName.toLowerCase();
+
+    if (block[tagName]) {
+      while (stack.last() && inline[stack.last()]) {
+        parseEndTag('', stack.last());
+      }
+    }
+
+    if (closeSelf[tagName] && stack.last() == tagName) {
+      parseEndTag('', tagName);
+    }
+
+    unary = empty[tagName] || !!unary;
+
+    if (!unary) {
+      stack.push(tagName);
+    }
+
+    if (handler.start) {
+      var attrs = [];
+      rest.replace(attr, function (match, name) {
+        var value = arguments[2] ? arguments[2] : arguments[3] ? arguments[3] : arguments[4] ? arguments[4] : fillAttrs[name] ? name : '';
+        attrs.push({
+          name: name,
+          value: value,
+          escaped: value.replace(/(^|[^\\])"/g, '$1\\\"') // "
+
+        });
+      });
+
+      if (handler.start) {
+        handler.start(tagName, attrs, unary);
+      }
+    }
+  }
+
+  function parseEndTag(tag, tagName) {
+    // If no tag name is provided, clean shop
+    if (!tagName) {
+      var pos = 0;
+    } // Find the closest opened tag of the same type
+    else {
+        for (var pos = stack.length - 1; pos >= 0; pos--) {
+          if (stack[pos] == tagName) {
+            break;
+          }
+        }
+      }
+
+    if (pos >= 0) {
+      // Close all the open elements, up the stack
+      for (var i = stack.length - 1; i >= pos; i--) {
+        if (handler.end) {
+          handler.end(stack[i]);
+        }
+      } // Remove the open elements from the stack
+
+
+      stack.length = pos;
+    }
+  }
+}
+
+function makeMap(str) {
+  var obj = {};
+  var items = str.split(',');
+
+  for (var i = 0; i < items.length; i++) {
+    obj[items[i]] = true;
+  }
+
+  return obj;
+}
+
+function removeDOCTYPE(html) {
+  return html.replace(/<\?xml.*\?>\n/, '').replace(/<!doctype.*>\n/, '').replace(/<!DOCTYPE.*>\n/, '');
+}
+
+function parseAttrs(attrs) {
+  return attrs.reduce(function (pre, attr) {
+    var value = attr.value;
+    var name = attr.name;
+
+    if (pre[name]) {
+			pre[name] = pre[name] + " " + value;
+    } else {
+			pre[name] = value;
+    }
+
+    return pre;
+  }, {});
+}
+
+function parseHtml(html) {
+  console.log("paseHtml")
+  html = removeDOCTYPE(html);
+  var stacks = [];
+  var results = {
+    node: 'root',
+    children: []
+  };
+  HTMLParser(html, {
+    start: function start(tag, attrs, unary) {
+      var node = {
+        name: tag
+      };
+
+      if (attrs.length !== 0) {
+        node.attrs = parseAttrs(attrs);
+      }
+
+      if (unary) {
+        var parent = stacks[0] || results;
+
+        if (!parent.children) {
+          parent.children = [];
+        }
+
+        parent.children.push(node);
+      } else {
+        stacks.unshift(node);
+      }
+    },
+    end: function end(tag) {
+      var node = stacks.shift();
+      if (node.name !== tag) console.error('invalid state: mismatch end tag');
+
+      if (stacks.length === 0) {
+        results.children.push(node);
+      } else {
+        var parent = stacks[0];
+
+        if (!parent.children) {
+          parent.children = [];
+        }
+
+        parent.children.push(node);
+      }
+    },
+    chars: function chars(text) {
+      var node = {
+        type: 'text',
+        text: text
+      };
+
+      if (stacks.length === 0) {
+        results.children.push(node);
+      } else {
+        var parent = stacks[0];
+
+        if (!parent.children) {
+          parent.children = [];
+        }
+
+        parent.children.push(node);
+      }
+    },
+    comment: function comment(text) {
+      var node = {
+        node: 'comment',
+        text: text
+      };
+      var parent = stacks[0];
+
+      if (!parent.children) {
+        parent.children = [];
+      }
+
+      parent.children.push(node);
+    }
+  });
+  return results.children;
+}
+
+export default parseHtml;

+ 379 - 0
common/mixins.js

@@ -0,0 +1,379 @@
+import utfx from 'utfx';
+import store from './store/';
+import onSocketMessage from './onSocketMessage';
+
+/**
+ * socket 发送用到的一个函数
+ */
+function stringSource(s)
+{
+	let i = 0;
+	return () => {
+		return i < s.length ? s.charCodeAt(i++) : null;
+	};
+}
+
+export default {
+	/** 添加方法时,方法name前加$以避免与页面方法冲突 */
+
+	methods: {
+	
+		/**
+		 *  http 请求
+		 *  config object
+		 *  {
+		 *      path: string, 请求路径
+		 *	 	data: object, 发送数据
+		 * 		success: function, 回调
+		 * 		fail: function, 错误回调
+		 * 		type: string 请求方式(默认post)
+		 * 		success_action: boolean err状态不为0时是否执行success回调(默认是err状态不为0就只提示msg而不执行success回调)
+		 * 		check: false 是否验证登陆默认不验证
+		 *	}
+		 */
+		$heartCheck:{
+			timeout: 5000,
+			timeoutObj: null,
+			serverTimeoutObj: null,
+			reset: function () {
+				clearTimeout(this.timeoutObj);
+				clearTimeout(this.serverTimeoutObj);
+				return this;
+			},
+			start: function () {
+				var self = this;
+				this.timeoutObj && clearTimeout(this.timeoutObj);
+				this.serverTimeoutObj && clearTimeout(this.serverTimeoutObj);
+				this.timeoutObj = setTimeout(function () {
+					//这里发送一个心跳,后端收到后,返回一个心跳消息,
+					//onmessage拿到返回的心跳就说明连接正常
+					self.$socketSend({'type':'ping'});
+					console.log('心跳检测....')
+					self.serverTimeoutObj = setTimeout(function () { // 如果超过一定时间还没重置,说明后端主动断开了
+						console.log('关闭服务');
+						uni.closeSocket();;//如果onclose会执行reconnect,我们执行 websocket.close()就行了.如果直接执行 reconnect 会触发onclose导致重连两次
+					}, self.timeout)
+				}, this.timeout)
+			}
+		},
+		$reconnect:{
+			lockReconnect : false,
+			tt:false,
+			start(){
+				if(this.lockReconnect){
+					return false;
+				}
+				let self = this;
+				this.lockReconnect = true;
+				this.tt && clearTimeout(this.tt);
+				this.tt = setTimeout(function () {
+					console.log('重连中...');
+					self.tlockReconnect = false;
+					self.$socketSend();
+				}, 4000);
+			}
+		},
+		$httpSend(config){
+			let header = {
+				/** 这里设置为简单跨域,只会请求一次 */
+				'Content-Type': 'application/x-www-form-urlencoded',
+			};
+			let send_data = ('data' in config ? config.data : {}),
+			url = store.state.core.http_url + config.path;
+			send_data['_token'] = uni.getStorageSync('token');
+			uni.request({
+				url: url,
+				data: send_data,
+				method: ('type' in config ? config.type : 'POST'),
+				header: header,
+				dataType: 'json',
+				success(res) {
+					if('success' in config && res.statusCode == 200){
+						if(('success_action' in config) && config.success_action ){
+							config.success(res.data);
+						}else{
+							if(res.data.err){
+								/** 不显示未登录提示 */
+								if(send_data['_token'] || config.path.indexOf('/in/') > -1){
+									uni.showModal({
+										content: res.data.msg,
+									});
+								}
+							}else{
+								config.success(res.data.data);
+							}
+						}
+					}
+				},
+				fail(err) {
+					if('fail' in config){
+						config.fail(err);
+					}else{
+						console.log(JSON.stringify(err));return;
+						uni.showModal({
+							content: JSON.stringify(err),
+						});
+					}
+				}
+			});
+		},
+		/**
+		 * 通过 websocket 发送数据,
+		 * 如果还没有连接 websocket 就先连接websocket,过两秒等websocket连接上了发送本次的数据,如果两秒后还是没有连接上,则舍弃这次发送数据,
+		 * 如果发送的值为空则只连接
+		 * 	@param data object 
+		 * 	{
+		 *		action: 'model.controller.action',
+		 *		data: {}
+		 *	}
+		 */
+		$socketSend(send_data){
+			/** callback1是连接,callback2是发送 */
+			var self = this;
+			console.log('sokect...')
+			((callback1,callback2) => {
+				if(send_data && store.state.socket_state){
+					callback2(send_data);
+				}else{
+					callback1(callback2,send_data);
+				}
+			})((callback) => {
+				uni.connectSocket({
+					url: store.state.core.socket_url,
+					header: {
+						'content-type': 'application/json',
+					},
+					// protocols: [ 'protocol1' ],
+					method: 'GET',
+					success(){
+					},
+					fail(err){
+						//TODO 执行重连
+						// uni.showModal({
+						// 	content: JSON.stringify(err) + '---socket 接口调用失败',
+						// });
+						self.$reconnect.start();
+					}
+				});
+				uni.onSocketOpen((res) => {
+					 //发送心跳检测
+					this.$heartCheck.reset().start();
+					/** 绑定服务器消息事件 */
+					uni.onSocketMessage((res) => {
+						
+						res = JSON.parse(res.data);
+						if(!(res.action in onSocketMessage)){
+							if(res.action != 'ping' && res.type != 'ping' ){
+								uni.showModal({
+									content: '接受到无效的消息',
+								});
+							}
+						} else {
+							onSocketMessage[res.action](res.data);
+						}
+						this.$heartCheck.reset().start();
+						return;
+						/** 下面的写法二进制接收数据不兼容APP */
+						
+						if (res.data instanceof Blob) {
+							/** js中的blob没有没有直接读出其数据的方法,通过FileReader来读取相关数据 */
+							let reader = new FileReader();
+							reader.readAsDataURL(res.data);							
+						    /** 当读取操作成功完成时调用. */
+							reader.onload = function(evt){								
+								let data = JSON.parse(((str) => {
+									/**  base64编码解析 */
+									if(str.indexOf(',') > -1){
+										str = str.split(',')[1];
+									}
+									return decodeURIComponent(atob(str).split('').map((c) => {
+									    return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
+									}).join(''));
+								})(evt.target.result));
+								if(!(data.action in onSocketMessage)){
+									if(data.action != 'ping'){
+										console.log('action null');
+									}
+									return;
+								}
+								onSocketMessage[data.action](data.data);
+							}
+						}
+					});
+					
+					/** 这里发送token到服务器验证 */						
+					callback({
+						action: 'checkToken',
+						data: uni.getStorageSync('token'),
+					});
+
+					/** 这里如果有需要发送的数据,就等待2s再进行发送,如果2s后,token验证还是不合法,就舍弃这次的发送 */
+					if(send_data) {
+						setTimeout(() => {
+							if(store.state.socket_state){
+								console.log("socket验证不合法")
+								callback(send_data);
+							}
+						},2000);
+					}
+					
+				});
+				
+				uni.onSocketClose((err) => {
+					console.log(JSON.stringify(err));
+					store.commit('set',{ k:'socket_state',v:0 });
+					self.$reconnect.start();
+				});
+				
+				uni.onSocketError((err) => {
+					store.commit('set',{ k:'socket_state',v:0 });
+					self.$reconnect.start();
+					console.log(JSON.stringify(err));
+					// uni.showModal({
+					// 	content: JSON.stringify(err) + '---webSocket 连接打开失败!',
+					// });
+				});
+			},
+			(send_data) => {
+				
+				uni.sendSocketMessage({
+					data: JSON.stringify(send_data),
+					fail(err){
+						uni.showModal({
+							content: JSON.stringify(err) + '---发送消息失败',
+						});
+					}
+				});
+				
+				return 
+				/** 下面是以二进制发送数据 */
+				
+				/** 字符串转换二进制过程 */
+				let data = JSON.stringify(send_data),
+				strCodes = stringSource(data),
+				/** js字符串是utf-16编码的,转换成utf-8 */
+				length = utfx.calculateUTF16asUTF8(strCodes)[1];
+				/** 字符串开头 */
+				let offset = 0,
+				/** 初始化长度为UTF8编码后字符串长度 +4 个Byte的二进制缓冲区(字符串结尾) */
+				buffer = new ArrayBuffer(length + offset),
+				view = new DataView(buffer);
+				
+				/** 将长度放置在字符串的头部 */
+				view.setUint32(0, length);
+				utfx.encodeUTF16toUTF8(stringSource(data), function(b) {
+					view.setUint8(offset++, b);
+				}.bind(this));			
+				uni.sendSocketMessage({
+					data: buffer,
+					success(res){
+						
+					},
+					fail(err){
+						uni.showModal({
+							content: JSON.stringify(err) + '---发送消息失败',
+						});
+					}
+				});
+			});	
+		},
+		
+		/** 
+		 * http发送文件(图片、文件、语音)
+		 * @param json obj 
+		 * {
+			local_url: string * 在不调用上传控件的时候的本地文件地址
+			data: json obj * 上传的数据
+			success: function * 上传成功回调
+			fail: function * 上传失败回调
+			type: int 0对话上传文件 1上传头像 2朋友圈上传文件 3朋友圈背景图片上传 4群头像上传
+			onProgressUpdate: function 上传进度监听
+		   }
+		 */
+		$httpSendFile(config){
+			if(!config){
+				config = {};
+			}
+			let send_data = ('data' in config ? config.data : {});
+			send_data['_token'] = uni.getStorageSync('token');
+			
+			((callback) => {
+				switch (config.type){
+					/** 对话上传文件 */
+					case 0:
+						callback(config.local_url,'/im/upload/chat');
+						break;
+					/** 上传头像 */
+					case 1:
+						callback(config.local_url,'/im/upload/photo');
+						break;
+					/** 朋友圈上传文件 */
+					case 2:
+						callback(config.local_url,'/im/upload/circle');
+						break;
+					/** 朋友圈背景图片上传 */
+					case 3:
+						callback(config.local_url,'/im/upload/circleImg');
+						break;
+					/** 群头像上传 */
+					case 4:
+						callback(config.local_url,'/im/upload/groupPhoto');
+						break;
+					default:
+						uni.showModal({
+							content: '无效的操作',
+						});
+						break;
+				}
+			})((local_url,action_path) => {
+				let uploadTask = uni.uploadFile({
+					url: (store.state.core.static_url + action_path),
+					filePath: local_url,
+					name: 'file',
+					/** formData必须要有值,否则会上传失败 */
+					formData: send_data,
+					success: (res) => {
+						if(res.statusCode == 200){
+							if('success' in config){
+								res.data = JSON.parse(res.data);
+								if(res.data.err){
+									if('fail' in config){
+										config.fail(err);
+									} else {
+										uni.showModal({
+											content: res.data.msg,
+										});
+									}
+								}else{
+									config.success(res.data.data);
+								}
+							}
+						}
+					},
+					fail(err){
+						if('fail' in config){
+							config.fail(err);
+						} else {
+							uni.showModal({
+								content: JSON.stringify(err),
+							});
+						}
+					}
+				});
+				uploadTask.onProgressUpdate((res) => {
+					
+					if('onProgressUpdate' in config){
+						config.onProgressUpdate();
+					}
+					
+					return;
+					
+					console.log('上传进度' + res.progress);
+					console.log('已经上传的数据长度' + res.totalBytesSent);
+					console.log('预期需要上传的数据总长度' + res.totalBytesExpectedToSend);
+				});
+			});
+		},
+		
+	}
+}

+ 129 - 0
common/onSocketMessage.js

@@ -0,0 +1,129 @@
+import store from './store/';
+import _get from './_get';
+import _action from './_action';
+
+export default {
+	/** 验证token */
+	checkToken(res) {
+		if(res.err){
+			_action.checkFail();
+		} else {
+			/** 设置为登陆状态 */
+			store.commit('set',{ k:'socket_state',v:1 });
+			/** 获取基础数据 */
+			_get.base();
+		}
+	},
+	/** 下线 */
+	offline(res){
+		uni.showModal({
+			content: '你的账号在另一客户端登陆,如果不是你本人操作,请修改你的密码',
+			success(){
+				_action.checkFail();
+			},
+		});
+	},
+	/** 获得会话列表 */
+	getChatList(){
+		_get.getChatList();
+	},
+	/** 获得好友列表 */
+	getFriendList(){
+		_get.getFriendList({ up: 1});
+	},
+	/** 新好友提醒 */
+	newFriend(data){
+		_action.playVoice('/static/voice/friend.mp3');
+		let num = store.state.new_friend_tips_num + (data.num * 1);
+		store.commit('set',{ k:'new_friend_tips_num',v:num });
+		_action.setStatusTips();
+	},
+	/** 接收新消息 */
+	chatData(data){
+		let chat_data = store.state.page_data.chat_data,
+		msg_reader_num = 1;
+		if(chat_data[data.list_id]){
+			// 如果在与对方的对话界面,更新这个对话的阅读(即反馈接收状态)
+			if(store.state.page_data.message_query_list_id == data.list_id && store.state.user_info.id != data.data.msg.user_info.uid){
+				_action.updataNoReader(data.list_id);
+				msg_reader_num = 0;
+			}
+			store.state.page_data.chat_data[data.list_id].list.push(data.data);
+		}
+		
+		/** 更新对话列表数据 */		
+		for(let i = 0,j = store.state.page_data.chat_list.length;i < j;i ++){
+			if(store.state.page_data.chat_list[i].list_id == data.list_id){
+				let last_msg;
+				switch(data.data.msg.type * 1){
+					case 0:
+						last_msg = data.data.msg.content.text;
+						break;
+					case 1:
+						/** 语音 */
+						last_msg = '[语音]';
+						break;
+					case 2:
+						/** 图片 */
+						last_msg = '[图片]';
+						break;
+					case 3:
+						/** 视频 */
+						last_msg = '[视频]';
+						break;
+					case 4:
+						/** 文件 */
+						last_msg = '[文件]';
+						break;
+					case 5:
+						/** 红包 */
+						last_msg = '[红包]';
+						break;
+					default:
+						/** 未知消息类型 */
+						last_msg = '[未知]';
+						break;
+				}
+				store.state.page_data.chat_list[i].last_msg = last_msg;
+				store.state.page_data.chat_list[i].no_reader_num += msg_reader_num;
+				store.state.page_data.chat_list[i].time = data.data.msg.time;
+				let action_list_data = store.state.page_data.chat_list[i];
+				store.state.page_data.chat_list.splice(i,1);
+				store.state.page_data.chat_list.unshift(action_list_data);
+				break;
+			}
+		}
+		
+		/** 如果不是自己的消息,震动提示 */
+		if(store.state.user_info.id != data.data.msg.user_info.uid){
+			uni.vibrateLong();
+			_action.playVoice('/static/voice/chat.mp3');
+		}
+	},
+	/** 接收好友朋友圈动态提示 */
+	circleTips(data){
+		_action.playVoice('/static/voice/circle.mp3');
+		store.commit('set',{ k:'no_reader_circle',v:1 });
+		_action.setStatusTips();
+	},
+	/** 接收朋友圈好友回复/赞通知 */
+	cricleChatTips(data){
+		_action.playVoice('/static/voice/circle.mp3');
+		let num = store.state.no_reader_circle_chat_num;
+		num ++;
+		store.commit('set',{ k:'no_reader_circle_chat_num',v:num });
+		_action.setStatusTips();
+	},
+	/** 撤回消息 */
+	deleteChat(data){
+		let chat_data = store.state.page_data.chat_data;
+		if(chat_data[data.list_id] && chat_data[data.list_id].list.length){
+			for(let i = 0,j = chat_data[data.list_id].list.length;i < j;i++ ){
+				if(chat_data[data.list_id].list[i].msg.id == data.msg_id){
+					store.state.page_data.chat_data[data.list_id].list.splice(i,1);
+					break;
+				}
+			}
+		}
+	},
+}

+ 51 - 0
common/tendenceImSdk.js

@@ -0,0 +1,51 @@
+
+const IMSDK = {
+    $api: null,
+    init(){
+      this.$api =   uni.requireNativePlugin('Html5App-TencentCall');
+      return this;
+    },
+    joinRoom(param,cb) {  //加入/创建房间
+        if(!this.$api)this.init();
+        this.$api.joinRoom({
+            "userid": param.userid,
+            "roomid": param.roomid,
+            "usersig": param.usersig
+        }, ret => {
+            if(cb)cb();
+        })
+    },
+    exitRoom(cb){  //离开房间
+        if(!this.$api)this.init();
+        this.$api.exitRoom()
+        if(cb)cb()
+    },
+    removeUser(userid,cb){ //踢出房间
+        if(!this.$api)this.init();
+        this.$api.removeUser({"userid":userid},ret=>{
+            if(cb)cb();
+        });
+    },
+    muteLocalAudio(mute,cb){ //设置本地音频是否开启,
+        if(!this.$api)this.init();
+        this.$api.muteLocalAudio({mute:mute},ret=>{
+            if(cb)cb();
+        });
+    },
+    setAudioRoute($route,cb){ //设置切换音频通道 //0=>代表扬声器,1=> 听筒
+        if(!this.$api)this.init();
+        this.$api.setAudioRoute({route:$route},ret=> {
+            if(cb)cb();
+        });
+    },
+    muteRemoteAudio(userid,mute,cb){ //禁言mute : 0=>代表禁言,1=> 开启发言
+        if(!this.$api)this.init();
+        this.$api.muteRemoteAudio({"userid":userid,mute:mute},ret=>{
+            if(cb)cb();
+        });
+    }
+}
+
+export default{
+    IMSDK
+}

BIN
components/.DS_Store


+ 218 - 0
components/bjx-form/bjx-form-item.vue

@@ -0,0 +1,218 @@
+<template>
+	<view class="bjx-form-item" :style="{width: theWidth}">
+		<view :class="'label-' + theLabelType" :style="{alignItems: theVerticalAlign}">
+			<view class="item-label" :style="theLabelStyle">
+				<view class="item-required" v-show="thePromptType&&(thePromptType==2||theRequired)" :style="{color: theForm.msgColor,opacity:thePromptType&&theRequired?1:0}">
+					{{theForm.prompt}}
+				</view>
+				<view class="label-con">
+					<slot name="label" >
+						<text class="label-text">{{label}}</text>
+						<text class="right" v-if="theLabelType=='block'&&labelRight">{{labelRight}}</text>
+					</slot>
+				</view>
+			</view>
+			<view class="item-con">
+				<slot />
+			</view>
+		</view>
+		<scroll-view scroll-x='true' class="item-msg" v-if="theForm.msgType=='in'">
+			<view :style="{color: theForm.msgColor}">{{msg}}</view>
+		</scroll-view>
+	</view>
+</template>
+
+<script>
+	import {fromCheck} from './bjx-validate.js'
+	export default {
+		name: 'BjxFormItem',
+		props: {
+			// 字段名称
+			label: String,
+			// 表单字段
+			prop: String,
+			width: {
+				type: String,
+				default: 'auto'
+			},
+			labelWidth: {
+				type: String,
+				default: ''
+			},
+			// block 独占一行 inlie与内容共一行
+			labelType: String,
+			// label 文本水平对齐方式
+			align: String,
+			labelRight: {
+				type: String,
+				default: '' // 当labelType 为 block 时 label 右侧显示文字
+			},
+			required: {
+				type: Boolean,
+				default: false // 字段名左侧* 是否显示  默认由 校验规则 中的 required 控制
+			},
+			verticalAlign: {
+				type: String,
+				default: 'center' // label 文本垂直对齐方式
+			},
+			// 提示符占位,0:不显示,  1:非必要项不显示不占位  2:占位,用透明度控制显示隐藏使label文字对齐
+			promptType:  Number,
+			authCheck: {
+				type: Boolean,
+				default: null // 动态校验,即值一改变就对数据进行校验
+			},
+		},
+		data() {
+			return {
+				formField: ['labelType', 'labelWidth', 'align', 'msgType','form','rules','msgColor','prompt','promptType','authCheck'],
+				msg: ''
+			}
+		},
+		watch: {
+			value() { // 监听value 检查是否做动态校验
+				if(this.authCheck||this.authCheck===null&& this.theForm.authCheck){
+					this.validate()
+				}
+			}
+		},
+		computed: {
+			theRequired() {
+				if(this.required || this.theForm.rules && this.theForm.rules[this.prop] && this.theForm.rules[this.prop].required) {
+					return true
+				}
+				return false
+			},
+			theForm() {
+				let parent = this.$parent;
+				let parentName = parent.$options.name;
+				while (parentName !== null && parentName !== 'BjxForm') {
+				  parent = parent ? parent.$parent : null;
+				  parentName = parent ? parent.$options.name : null;
+				}
+				let theForm = {}
+				if(parent) {
+					this.formField.forEach(key => {
+						theForm[key] = parent[key]
+					})
+				}	
+				return theForm;
+			},
+			theWidth() {
+				return !isNaN(Number(this.width)) ? this.width + 'rpx' : this.width
+			},
+			theLabelWidth(){
+				let width = 'auto'
+				if(!this.$slots.label) {
+					width = this.labelWidth || this.theForm.labelWidth
+					if(!isNaN(Number(width))) {
+						width += 'rpx'
+					}
+				}
+				return width
+			},
+			theLabelType() {
+				let labelType = this.labelType || this.theForm.labelType
+				return labelType
+			},
+			theLabelStyle() {
+				let width = this.theLabelType!='block' ? this.theLabelWidth : 'auto'
+				let aligns = {left: 'flex-start', right: 'flex-end', center: 'center',between: 'space-between'}
+				let align = this.align || this.theForm.align
+				return `width: ${width}; justify-content: ${aligns[align]}; vertical-align: ${this.verticalAlign};`
+			},
+			theVerticalAlign() {
+				let type = {top: 'flex-start', bottom: 'flex-end', center: 'center'}
+				return type[this.verticalAlign]
+			},
+			value() {
+				let form = this.theForm.form
+				let value =  form ? form[this.prop] : ''
+				return value
+			},
+			thePromptType() {
+					return this.promptType > -1 ? this.promptType :this.theForm.promptType
+			}
+		},
+		methods: {
+			// 规则校验
+			validate() {
+				if(!this.theForm.rules) return
+				let rule = this.theForm.rules[this.prop]
+				this.msg = ''
+				if(rule) {
+					if(rule.required && (this.value == null || this.value == '')) {
+						// 是否必填
+						this.msg = rule.msg || this.label + '不能为空'
+					}else if(rule.validator) {
+						// 自定义规则校验函数
+						let bol = rule.validator(this.value,rule)
+						if(typeof bol == 'string') {
+							this.msg = bol
+						}else if(!bol) {
+							this.msg = rule.message || this.label + '不符合规则'
+						}
+					}else if(rule.rule && this.value != null && this.value != '') {
+						// 默认校验规则
+						let result = fromCheck(this.value, rule.rule, this.theForm.form)
+						if(result !== true) {
+							this.msg = this.label + result.msg
+							if(rule.message) {
+								if(typeof rule.message === 'string') {
+									this.msg = typeof rule.message
+								} else if(rule.message[result.rule]) {
+									this.msg = rule.message[result.rule]
+								}
+							}
+						}
+					}
+				}
+				if(this.msg != '') {
+					if(this.theForm.msgType == 'out') {
+						// 弹框
+						uni.showModal({ content: this.msg })
+					}else if(this.theForm.msgType == 'msg'){
+						// 消息框
+						uni.showToast({
+							icon: 'none',
+							title: this.msg
+						})
+					}
+				}
+				return !this.msg
+			}
+		},
+	}
+</script>
+
+<style  lang="scss" scoped>
+	.bjx-form-item {
+		padding: 3px 0;
+		.label-block{
+			.item-label {
+				display:flex;
+				margin-bottom: 2px;
+				.label-con{
+					flex:1;
+				}
+				.right {
+					float: right;
+				}
+			}
+		}
+		.label-inline{
+			display:flex;
+			 align-items: flex-start;
+			.item-label {
+				display:flex;
+				margin-right: 10upx;
+			}
+			.item-con {
+				flex:1;
+			}
+		}
+		.item-msg {
+			padding:2px;margin-bottom: 5px;font-size: 15px;height: 22px;
+			view{width: max-content;}
+		}
+	}
+</style>

+ 107 - 0
components/bjx-form/bjx-form.vue

@@ -0,0 +1,107 @@
+<template>
+	<view>
+		<form :report-submit="reportSubmit"  @submit="formSubmit" @reset="formReset">
+			<slot />
+		</form>	
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'BjxForm',
+		props: {
+			form: {
+				type: Object,
+				default: function (){
+					return {}
+				}
+			},
+			rules: {
+				type: Object,
+				default: function (){
+					return {}
+				}
+			},
+			// 提示模式 1. out 弹框提提示 2.in item 页面内 item 文字提示 3 msg 消息框提示
+			msgType: {
+				type: String,
+				default: 'out'
+			},
+			// block 独占一行 inlie与内容共一行
+			labelType: {
+				type: String,
+				default: 'block'
+			},
+			labelWidth: {
+				type: String,
+				default: 'auto'
+			},
+			align: {
+				type: String,
+				default: 'left'
+			},
+			reportSubmit: {
+				type: Boolean,
+				default: false
+			},
+			submit: Function,
+			reset: Function,
+			msgColor: {
+				type: String,
+				default: '#F56C6C' // 提示符、提示文本字体颜色
+			},
+			prompt: {
+				type: String,
+				default: '*' // 提示符
+			},
+			promptType: {
+				type: Number,
+				default: 1 // 提示符占位,0:不显示,  1:非必要项不显示不占位  2:占位,用透明度控制显示隐藏使label文字对齐
+			},
+			authCheck: {
+				type: Boolean,
+				default: false // 动态校验,即值一改变就对数据进行校验
+			},
+		},
+		methods: {
+			formSubmit(e) {
+				this.$emit('submit',e)
+			},
+			formReset(e) {
+				this.$emit('reset',e)
+			},
+			// 规则校验 
+			validate(callback) {
+				let vb = true
+				let item = this.getItem(this.$children)
+				for(let i = 0; i < item.length; ++i) {
+					// 对表单下的子组件 form-item 做数据校验
+					let bol = item[i].validate ? item[i].validate() : true
+					if(vb && !bol) {
+						vb = false
+					}
+					if(this.msgType != 'in' && !bol) {
+						break
+					}
+				}
+				callback && callback(vb)
+			},
+			// 递归遍历子元素 筛选 form-item
+			getItem(children,item) {
+				item = item || []
+				children.forEach(it => {
+					if(it.$options.name && it.$options.name === 'BjxFormItem' ||
+					it.$options._componentTag && it.$options._componentTag === 'bjx-form-item'){
+						item.push(it)
+					} else if(it.$children.length){
+						item = this.getItem(it.$children,item)
+					}
+				})
+				return item
+			}
+		},
+	}
+</script>
+
+<style  lang="scss">
+</style>

+ 129 - 0
components/bjx-form/bjx-validate.js

@@ -0,0 +1,129 @@
+import validate from './validate.js'
+// 默认校验规则
+const rules = {
+	// 自定义规则
+	...validate,
+	// 数据类型
+	type: function(val, param) {
+		let msgObj = {'string': '字符串', 'boolean': '布尔值', 'objec': '对象'}
+		if(param[0] == 'number') {
+			if(val == '' || isNaN(Number(val))) {
+				return '不是一个数字'
+			}
+		} else if(typeof val != param[0]){
+			return msgObj[param[0]] ? '不是' + msgObj[param[0]] : '数据类型不符合'
+		}
+		return true
+	},
+	// 值 小于等于
+	max: function(val, param) {
+		let msg = this.type(val,['number'])
+		if(msg !== true) {
+			return msg
+		}
+		if(val > param[0]) {
+			return '值不能超过' + param[0]
+		}
+		return true
+	},
+	// 值 大于等于
+	min: function(val, param) {
+		let msg = this.type(val,['number'])
+		if(msg !== true) {
+			return msg
+		}
+		if(val.length < param[0]) {
+			return '值不能小于' + param[0]
+		}
+		return true
+	},
+	/*
+	* 长度范围
+	* 1. length:2   长度等于某值
+	* 2. length:0,2 长度在某区间
+	* 3. length:2,~ 长度不小于
+	* 4. length:~,5 长度不大于
+	*/
+	length: function(val, param) {
+		if(param.length > 1) {
+			if(param[1].trim() == '~' && val.length < param[0]) {
+				return '长度不能小于' + param[0]
+			} else if (param[0].trim() == '~'  && val.length > param[1]){
+				return '长度不能超过' + param[1]
+			} else if(val.length < param[0] || val.length > param[1]) {
+				return '长度应在' + param[0] + '~' + param[1] + '之间'
+			}
+		}else if(val.length != param[0]){
+			return '长度应等于' + param[0]
+		}
+		return true
+	},
+	// 值的范围
+	between: function(val, param) {
+		if(param.length > 1) {
+			if(Number(val) < Number(param[0]) || Number(val) > Number(param[1])) {
+				return '应在' + param[0] + '~' + param[1] + '之间'
+			}
+		}else if(val != param[0]){
+			return '应等于' + param[0]
+		}
+		return true
+	},
+	// 校验值在给定的值中
+	in: function(val, param) {
+		if(!param.includes(val)){
+			return '应该在' + param.join() + '之中'
+		}
+		return true
+	},
+	// 校验值是否与某字段值相等
+	eq: function(val, param, from) {
+		if(from[param[0]] && val != from[param[0]]){
+			return '与' + param[0] + '不相等'
+		}
+		return true
+	},
+	reg: function(val, param) {
+		var reg = new RegExp(param);
+		if (!reg.test(val)) {
+			return '不符合正则'
+		}
+		return true
+	},
+	date: function(val) {
+		if (new Date(val).getDate()!=val.substring(val.length-2)) {
+			return '不是一个有效的日期'
+		}
+		return true
+	},
+}
+// 字符串转数组
+function getArr(val,str) {
+	return val.split ? val.split(str) : val
+}
+// 表单默认规则校验 通过返回 true 不通过返回对象 {msg:'不通过原因','rule': '规则名'}
+export const fromCheck = function(val, rule,form) {
+	// 'type: string|length:5|in:1,3|between:0,5' 字符串形式
+	// ['type: string','length:5','in:1,3','between:0,5'] // 数组、字符串混合
+	// ['string',['length',5],['in',[1,3],['between', [0,5]]]] 最终形式
+	rule = getArr(rule,'|')
+	const len = rule.length;
+	for (let i = 0; i < len; ++i ) {
+		let key = '',param = ''
+		if(rule[i].indexOf('reg') == 0){
+			// 正则
+			key = 'reg'
+			param = rule[i].slice(rule[i].indexOf(':') + 1)
+		}else{
+			rule[i] = getArr(rule[i],':')
+			key = rule[i][0].trim()
+			param = rule[i][1] ? getArr(rule[i][1],',') : [];
+		}
+		if(!rules[key]) continue
+		let msg = rules[key](val, param, form)
+		if(msg !== true) {
+			return {msg:msg,rule: key}
+		}
+	}
+	return true
+}

+ 13 - 0
components/bjx-form/validate.js

@@ -0,0 +1,13 @@
+// 规则扩展
+// 定义的函数 传入三个参数 第一个 val 未校验值 第二个 param 是校验参数  第三个 form 是表单数据
+// @return Boolean | String  函数返回ture 则为校验通过 返回false 或者 String 都视为校验不通过
+// 返回的字符串优先做为提示文字  提示文字的优先级 自定义函数msg > 规则中定义的message > 默认提示
+ export default {
+	// 手机号码校验
+	phone: function(val) {
+		if(val && !(/^1[3|4|5|6|7|8][0-9]\d{8,8}$/.test(val))){
+			return '请填写正确的手机号码'
+		}
+		return true
+	}
+}

+ 361 - 0
components/c-hongsetting/c-hongsetting.vue

@@ -0,0 +1,361 @@
+<template>
+	<view class="container">
+		<view class="ui-all">
+			<view class="ui-list">
+				<text>发包数量</text>
+				<input type="text" placeholder="请点击选择雷的数量" :data-index ="info.selectNum" disabled="true" :value="info.lei_msg" @tap="getNum" placeholder-class="place" />
+				<lb-picker :list="list" ref="picker" @confirm="confirm"></lb-picker>
+			</view>
+			<view class="ui-list">
+				<text>发包金额</text>
+				<input type="number" placeholder="输入发包金额"    @input="amount1"  :value="info.amount" placeholder-class="place" />
+			</view>
+			<view class="ui-list" v-if="info.selectNum >= 5">
+				<text>单雷赔率</text>
+				<input type="number" :placeholder="value" :value="info.lei1" @input="lei1" placeholder-class="place" />
+				<input type="number" placeholder="请输入福利奖励" :value="info.fuli1" @input="fuli1" placeholder-class="place" />
+			</view>
+			<view class="ui-list" v-if="info.selectNum >=7">
+				<text>双雷赔率</text>
+				<input type="number" :placeholder="value" :value="info.lei2" @input="lei2" placeholder-class="place" />
+				<input type="number" placeholder="请输入福利奖励" :value="info.fuli2" @input="fuli2" placeholder-class="place" />
+			</view>
+			<view class="ui-list" v-if="info.selectNum >= 7">
+				<text>三雷赔率</text>
+				<input type="number" :placeholder="value" :value="info.lei3" @input="lei3" placeholder-class="place" />
+				<input type="number" placeholder="请输入福利奖励" :value="info.fuli3" @input="fuli3" placeholder-class="place" />
+			</view>
+			<view class="ui-list" v-if="info.selectNum >= 7">
+				<text>四雷赔率</text>
+				<input type="number" :placeholder="value" :value="info.lei4" @input="lei4" placeholder-class="place" />
+				<input type="number" placeholder="请输入福利奖励" :value="info.fuli4" @input="fuli4" placeholder-class="place" />
+			</view>
+			<view class="ui-list" v-if="info.selectNum >= 8">
+				<text>五雷赔率</text>
+				<input type="number" :placeholder="value" :value="info.lei5" @input="lei5" placeholder-class="place" />
+				<input type="number" placeholder="请输入福利奖励" :value="info.fuli5" @input="fuli5" placeholder-class="place" />
+			</view>
+			<view class="ui-list" v-if="info.selectNum == 9">
+			<text>六雷赔率</text>
+				<input type="number" :placeholder="value" :value="info.lei6" @input="lei6" placeholder-class="place" />
+				<input type="number" placeholder="请输入福利奖励" :value="info.fuli6" @input="fuli6" placeholder-class="place" />
+			</view>
+			<view class="ui-list">
+				<text>是否开启</text>
+				<switch :checked="checked" @change="switch1Change" />
+			</view>
+			<!--<view class="ui-list" v-if="info.selectNum >= 7">-->
+				<!--<text>七雷赔率</text>-->
+				<!--<input type="number" :placeholder="value" :value="info.lei7" @input="lei7" placeholder-class="place" />-->
+				<!--<input type="number" placeholder="请输入福利奖励" :value="info.lei1" @input="lei1" placeholder-class="place" />-->
+			<!--</view>-->
+			<!--<view class="ui-list" v-if="info.selectNum >= 8">-->
+				<!--<text>八雷赔率</text>-->
+				<!--<input type="number" :placeholder="value" :value="info.lei8" @input="lei8" placeholder-class="place" />-->
+				<!--<input type="number" placeholder="请输入福利奖励" :value="info.lei1" @input="lei1" placeholder-class="place" />-->
+			<!--</view>-->
+			<!--<view class="ui-list" v-if="info.selectNum >= 9">-->
+				<!--<text>九雷赔率</text>-->
+				<!--<input type="number" :placeholder="value" :value="info.lei9" @input="lei9" placeholder-class="place" />-->
+				<!--<input type="number" placeholder="请输入福利奖励" :value="info.lei1" @input="lei1" placeholder-class="place" />-->
+			<!--</view>-->
+			<view class="save-info">
+				<button class="save" @tap="savaInfo(1)">确认</button>
+
+			</view>
+
+		</view>
+
+	</view>
+</template>
+
+<script>
+	import LbPicker from '@/components/lb-picker'
+	export default {
+		name:'cUserinfo',
+		props:{
+			info:{
+				type: Object,
+				default:()=>{
+					return {
+						lei_msg:"9包",
+						lei1:"",
+						fuli1:"",
+						lei2:"",
+						fuli2:"",
+						lei3:"",
+						fuli3:"",
+						lei4:"",
+						fuli4:"",
+						lei5:"",
+						fuli5:"",
+						lei6:"",
+						fuli6:"",
+						selectNum:9,
+						status:1,
+						amount:100
+					}
+				}
+			}
+		},
+		data() {
+			return {
+				value: '请输入赔率',
+				list: [
+					{
+						label: '9包',
+						value: 9,
+					},
+					{
+						label: '8包',
+						value: 8,
+					},
+					{
+						label: '7包',
+						value: 7,
+					},
+					{
+						label: '6包',
+						value: 6,
+					},
+					{
+						label: '5包',
+						value: 5,
+					}
+				],
+				lei_select:9,
+				checked:true,
+			}
+
+		},
+		components:{
+			LbPicker
+		},
+		computed:{
+
+		},
+		methods: {
+			setStatus(status){
+				if(status == 1){
+					this.checked = true
+				}else {
+					console.log(111111)
+					this.checked = false
+				}
+			},
+			amount1(e){
+				this.info.amount= e.detail.value;
+			},
+			lei1(e){
+				this.info.lei1= e.detail.value;
+			},
+			lei2(e){
+				this.info.lei2= e.detail.value;
+			},
+			lei3(e){
+				this.info.lei3= e.detail.value;
+			},
+			lei4(e){
+				this.info.lei4= e.detail.value;
+			},
+			lei5(e){
+				this.info.lei5= e.detail.value;
+			},
+			lei6(e){
+				this.info.lei6= e.detail.value;
+			},
+			getNum(){
+				this.$refs.picker.show()
+			},
+			fuli1(e){
+				this.info.fuli1= e.detail.value;
+			},
+			fuli2(e){
+				this.info.fuli2= e.detail.value;
+			},
+			fuli3(e){
+				this.info.fuli3= e.detail.value;
+			},
+			fuli4(e){
+				this.info.fuli4= e.detail.value;
+			},
+			fuli5(e){
+				this.info.fuli5= e.detail.value;
+			},
+			fuli6(e){
+				this.info.fuli6= e.detail.value;
+			},
+			confirm(e){
+				this.info.lei_msg = e.item.label;
+				this.info.selectNum = e.item.value;
+			},
+			switch1Change(e){
+				if(e.detail.value){
+					this.info.status = 1
+				}else {
+					this.info.status = 0
+				}
+			},
+			savaInfo(val){
+				let key = 'bao'+this.info.selectNum
+				this.$emit('saveConfig',this.info)
+			}
+		},
+		onLoad() {			
+		}
+
+	}
+</script>
+
+<style lang="less">
+	.container {
+		display: block;
+	}
+
+	.ui-all {
+		padding: 20rpx 40rpx;
+
+		.avatar {
+			width: 100%;
+			text-align: left;
+			padding: 20rpx 0;
+			border-bottom: solid 1px #f2f2f2;
+			position: relative;
+
+			.imgAvatar {
+				width: 140rpx;
+				height: 140rpx;
+				border-radius: 50%;
+				display: inline-block;
+				vertical-align: middle;
+				overflow: hidden;
+
+				.iavatar {
+					width: 100%;
+					height: 100%;
+					display: block;
+				}
+			}
+
+			text {
+				display: inline-block;
+				vertical-align: middle;
+				color: #8e8e93;
+				font-size: 28rpx;
+				margin-left: 40rpx;
+			}
+
+			&:after {
+				content: ' ';
+				width: 20rpx;
+				height: 20rpx;
+				border-top: solid 1px #030303;
+				border-right: solid 1px #030303;
+				transform: rotate(45deg);
+				-ms-transform: rotate(45deg);
+				/* IE 9 */
+				-moz-transform: rotate(45deg);
+				/* Firefox */
+				-webkit-transform: rotate(45deg);
+				/* Safari 和 Chrome */
+				-o-transform: rotate(45deg);
+				position: absolute;
+				top: 85rpx;
+				right: 0;
+			}
+		}
+
+		.ui-list {
+			width: 100%;
+			text-align: left;
+			padding: 20rpx 0;
+			border-bottom: solid 1px #f2f2f2;
+			position: relative;
+
+			text {
+				color: #4a4a4a;
+				font-size: 28rpx;
+				display: inline-block;
+				vertical-align: middle;
+				min-width: 150rpx;
+			}
+
+			input {
+				color: #030303;
+				font-size: 30rpx;
+				display: inline-block;
+				vertical-align: middle;
+				width: 30%;
+			}
+			button{
+				color: #030303;
+				font-size: 30rpx;
+				display: inline-block;
+				vertical-align: middle;
+				background: none;
+				margin: 0;
+				padding: 0;
+				&::after{
+					display: none;
+				}
+			}
+			picker {
+				width: 90%;
+				color: #030303;
+				font-size: 30rpx;
+				display: inline-block;
+				vertical-align: middle;
+				position: absolute;
+				top: 30rpx;
+				left: 150rpx;
+			}
+
+			textarea {
+				color: #030303;
+				font-size: 30rpx;
+				vertical-align: middle;
+				height: 150rpx;
+				width: 100%;
+				margin-top: 50rpx;
+			}
+
+			.place {
+				color: #999999;
+				font-size: 28rpx;
+			}
+		}
+
+		.right:after {
+			content: ' ';
+			width: 20rpx;
+			height: 20rpx;
+			border-top: solid 1px #030303;
+			border-right: solid 1px #030303;
+			transform: rotate(45deg);
+			-ms-transform: rotate(45deg);
+			/* IE 9 */
+			-moz-transform: rotate(45deg);
+			/* Firefox */
+			-webkit-transform: rotate(45deg);
+			/* Safari 和 Chrome */
+			-o-transform: rotate(45deg);
+			position: absolute;
+			top: 40rpx;
+			right: 0;
+		}
+
+		.save {
+			background: #5693ee;
+			border: none;
+			color: #ffffff;
+			margin-top: 40rpx;
+			font-size: 28rpx;
+			width: 100% !important;
+		}
+		.save-info{
+			display: flex;
+			justify-items: center;
+			align-items: center;
+		}
+	}
+</style>

+ 388 - 0
components/c-userinfo/c-userinfo.vue

@@ -0,0 +1,388 @@
+<template>
+	<view class="container">
+		<view class="ui-all">
+			<view class="avatar" @tap="avatarChoose">
+				<view  class="imgAvatar">
+					<view class="iavatar" :style="'background: url('+avater+') no-repeat center/cover #eeeeee;'"></view>
+				</view>
+				<text v-if="avater">修改头像</text>
+				<text v-if="!avater">授权微信</text>
+				<button v-if="!avater" open-type="getUserInfo" @getuserinfo="getUserInfo" class="getInfo"></button>
+			</view>
+			<view class="ui-list">
+				<text>昵称</text>
+				<input type="text" :placeholder="value" :value="nickName" @input="bindnickName" placeholder-class="place" />
+			</view>
+			<view class="ui-list">
+				<text>手机号</text>
+				<input v-if="mobile" type="tel" :placeholder="value" :value="mobile" @input="bindmobile" placeholder-class="place" />
+				<button v-if="!mobile" open-type="getPhoneNumber" @getphonenumber="getphonenumber" class="getInfo bun">授权手机号</button>
+			</view>
+			<view class="ui-list right">
+				<text>性别</text>
+				<picker @change="bindPickerChange" mode='selector' range-key="name" :value="index" :range="sex">
+					<view class="picker">
+						{{sex[index].name}}
+					</view>
+				</picker>
+			</view>
+			<view class="ui-list right">
+				<text>常住地</text>
+				<picker @change="bindRegionChange" mode='region'>
+					<view class="picker">
+						{{region[0]}} {{region[1]}} {{region[2]}}
+					</view>
+				</picker>
+			</view>
+			<view class="ui-list right">
+				<text>生日</text>
+				<picker mode="date" :value="date" @change="bindDateChange">
+					<view class="picker">
+						{{date}}
+					</view>
+				</picker>
+			</view>
+			<view class="ui-list">
+				<text>签名</text>
+				<textarea :placeholder="value" placeholder-class="place" :value="description" @input="binddescription"></textarea>
+			</view>
+			<button class="save" @tap="savaInfo">保 存 修 改</button>
+		</view>
+
+	</view>
+</template>
+
+<script>
+	export default {
+		name:'cUserinfo',
+		data() {
+			return {
+				value: '请填写',
+				sex: [{
+					id: 1,
+					name: '男'
+				}, {
+					id: 2,
+					name: '女'
+				}],
+				index: 0,
+				region: ['请填写'],
+				date: '请填写',
+				avater: '',
+				description: '',
+				url: '',
+				nickName: '',
+				mobile: '',
+				headimg: ''
+
+			}
+
+		},
+		methods: {
+			bindPickerChange(e) {
+				this.index = e.detail.value;
+				
+			},
+			bindRegionChange(e) {
+				this.region = e.detail.value;
+				
+			},
+			bindDateChange(e) {
+				this.date = e.detail.value;
+				
+			},
+			bindnickName(e) {
+				this.nickName = e.detail.value;
+				
+			},
+			bindmobile(e) {
+				this.mobile = e.detail.value;
+				
+			},
+			binddescription(e) {
+				this.description = e.detail.value;
+				
+			},
+			avatarChoose() {
+				let that = this;
+				uni.chooseImage({
+					count: 1,
+					sizeType: ['original', 'compressed'],
+					sourceType: ['album', 'camera'],
+					success(res) {
+						// tempFilePath可以作为img标签的src属性显示图片
+						that.imgUpload(res.tempFilePaths);
+						const tempFilePaths = res.tempFilePaths;
+					}
+				});
+			},
+			 getUserInfo (e) {
+			      if(e.detail.iv){		
+					  console.log(e.detail.iv) //传后台解密换取用户信息
+						  uni.showToast({
+							   title: '已授权',
+							   icon: 'none',
+							   duration: 2000
+							   }) 
+				  }
+				 
+			    } ,
+				 getphonenumber(e){
+					if(e.detail.iv){
+					  console.log(e.detail.iv) //传后台解密换取手机号
+						  uni.showToast({
+							   title: '已授权',
+							   icon: 'none',
+							   duration: 2000
+							   }) 
+					}
+								  },
+			savaInfo() {
+				let that = this;
+				let nickname = that.nickName;
+				let headimg = that.headimg;
+				let gender = that.index + 1;
+				let mobile = that.mobile;
+				let region = that.region;
+				let birthday = that.date;
+				let description = that.description;
+				let updata = {};
+				if (!nickname) {
+					uni.showToast({
+						title: '请填写昵称',
+						icon: 'none',
+						duration: 2000
+					});
+					return;
+				}
+				updata.nickname = nickname;
+				if (!headimg) {
+					headimg = that.avater;
+				}
+				updata.headimg = headimg;
+				updata.gender = gender;
+				if (that.isPoneAvailable(mobile)) {
+					updata.mobile = mobile;
+				} else {
+					uni.showToast({
+						title: '手机号码有误,请重填',
+						icon: 'none',
+						duration: 2000
+					});
+					return;
+				}
+				if (region.length == 1) {
+					uni.showToast({
+						title: '请选择常住地',
+						icon: 'none',
+						duration: 2000
+					});
+					return;
+				} else {
+					updata.province = region[0];
+					updata.city = region[1];
+					updata.area = region[2];
+				}
+				if (birthday == "0000-00-00") {
+					uni.showToast({
+						title: '请选择生日',
+						icon: 'none',
+						duration: 2000
+					});
+					return;
+				}
+				updata.birthday = birthday;
+				updata.description = description;
+				that.updata(updata);
+			},
+			isPoneAvailable(poneInput) {
+				var myreg = /^[1][3,4,5,7,8][0-9]{9}$/;
+				if (!myreg.test(poneInput)) {
+					return false;
+				} else {
+					return true;
+				}
+			},
+			async updata(datas) {
+				//传后台
+				
+			},
+			imgUpload(file) {
+				let that = this;
+				uni.uploadFile({
+					header: {
+						Authorization: uni.getStorageSync('token')
+					},
+					url:'/api/upload/image', //需传后台图片上传接口
+					filePath: file[0],
+					name: 'file',
+					formData: {
+						type: 'user_headimg'
+					},
+					success: function(res) {
+						var data = JSON.parse(res.data);
+						data = data.data;
+						that.avater = that.url + data.img;
+
+						that.headimg = that.url + data.img;
+
+						
+					},
+					fail: function(error) {
+						console.log(error);
+					}
+				});
+			},
+	
+		},
+		onLoad() {			
+		}
+
+	}
+</script>
+
+<style lang="less">
+	.container {
+		display: block;
+	}
+
+	.ui-all {
+		padding: 20rpx 40rpx;
+
+		.avatar {
+			width: 100%;
+			text-align: left;
+			padding: 20rpx 0;
+			border-bottom: solid 1px #f2f2f2;
+			position: relative;
+
+			.imgAvatar {
+				width: 140rpx;
+				height: 140rpx;
+				border-radius: 50%;
+				display: inline-block;
+				vertical-align: middle;
+				overflow: hidden;
+
+				.iavatar {
+					width: 100%;
+					height: 100%;
+					display: block;
+				}
+			}
+
+			text {
+				display: inline-block;
+				vertical-align: middle;
+				color: #8e8e93;
+				font-size: 28rpx;
+				margin-left: 40rpx;
+			}
+
+			&:after {
+				content: ' ';
+				width: 20rpx;
+				height: 20rpx;
+				border-top: solid 1px #030303;
+				border-right: solid 1px #030303;
+				transform: rotate(45deg);
+				-ms-transform: rotate(45deg);
+				/* IE 9 */
+				-moz-transform: rotate(45deg);
+				/* Firefox */
+				-webkit-transform: rotate(45deg);
+				/* Safari 和 Chrome */
+				-o-transform: rotate(45deg);
+				position: absolute;
+				top: 85rpx;
+				right: 0;
+			}
+		}
+
+		.ui-list {
+			width: 100%;
+			text-align: left;
+			padding: 20rpx 0;
+			border-bottom: solid 1px #f2f2f2;
+			position: relative;
+
+			text {
+				color: #4a4a4a;
+				font-size: 28rpx;
+				display: inline-block;
+				vertical-align: middle;
+				min-width: 150rpx;
+			}
+
+			input {
+				color: #030303;
+				font-size: 30rpx;
+				display: inline-block;
+				vertical-align: middle;
+			}
+			button{
+				color: #030303;
+				font-size: 30rpx;
+				display: inline-block;
+				vertical-align: middle;
+				background: none;
+				margin: 0;
+				padding: 0;
+				&::after{
+					display: none;
+				}
+			}
+			picker {
+				width: 90%;
+				color: #030303;
+				font-size: 30rpx;
+				display: inline-block;
+				vertical-align: middle;
+				position: absolute;
+				top: 30rpx;
+				left: 150rpx;
+			}
+
+			textarea {
+				color: #030303;
+				font-size: 30rpx;
+				vertical-align: middle;
+				height: 150rpx;
+				width: 100%;
+				margin-top: 50rpx;
+			}
+
+			.place {
+				color: #999999;
+				font-size: 28rpx;
+			}
+		}
+
+		.right:after {
+			content: ' ';
+			width: 20rpx;
+			height: 20rpx;
+			border-top: solid 1px #030303;
+			border-right: solid 1px #030303;
+			transform: rotate(45deg);
+			-ms-transform: rotate(45deg);
+			/* IE 9 */
+			-moz-transform: rotate(45deg);
+			/* Firefox */
+			-webkit-transform: rotate(45deg);
+			/* Safari 和 Chrome */
+			-o-transform: rotate(45deg);
+			position: absolute;
+			top: 40rpx;
+			right: 0;
+		}
+
+		.save {
+			background: #030303;
+			border: none;
+			color: #ffffff;
+			margin-top: 40rpx;
+			font-size: 28rpx;
+		}
+	}
+</style>

+ 318 - 0
components/cmd-circle/cmd-circle.vue

@@ -0,0 +1,318 @@
+<template>
+  <view class="cmd-circle">
+    <canvas :canvas-id="cid" :style="calCircleStyle"></canvas>
+  </view>
+</template>
+
+<script>
+  /**
+   * 进度圈组件  
+   * @description 用圈显示一个操作完成的百分比时,为用户显示该操作的当前进度和状态。  
+   * @tutorial https://ext.dcloud.net.cn/plugin?id=259  
+   * @property {String} cid 画布编号 - 默认defaultCanvas  
+   * @property {String} type 进度圈类型 - 圆圈形:circle、仪表盘:dashboard,默认圆圈形:circle  
+   * @property {Number} percent 进度圈百分比值 - 显示范围0-100 ,可能数比较大就需要自己转成百分比的值  
+   * @property {Boolean} show-info 进度圈进度状态信息 - 显示进度数值或状态图标,默认true  
+   * @property {String} font-color 进度圈文字信息颜色  
+   * @property {String} font-size 进度圈文字信息大小 - 默认:14  
+   * @property {String} status 进度圈状态 - 正常:normal、完成:success、失败:exception,默认正常:normal  
+   * @property {Number} stroke-width 进度圈线条宽度 - 建议在条线的宽度范围:1-50,与进度条显示宽度有关,默认:6  
+   * @property {String} stroke-color 进度圈的颜色 - 设置后status状态无效  
+   * @property {String} stroke-background 进度圈的底圈颜色 - 默认:#eeeeee  
+   * @property {String} stroke-shape 进度圈两端的形状 - 圆:round、方直角:square,默认圆:round  
+   * @property {Number} width 进度圈布宽度 - 默认80  
+   * @property {String} gap-degree 进度圈形缺口角度 - 可取值 0 ~ 360,仅支持类型:circle  
+   * @property {String} gap-position 进度圈形缺口位置 - 可取值'top', 'bottom', 'left', 'right',仅支持类型:circle  
+   * @example <cmd-circle id="circle1" type="circle" :percent="75"></cmd-circle>  
+   */
+  export default {
+    name: "cmd-circle",
+
+    props: {
+      // 画布编号 默认defaultCanvas
+      cid: {
+        type: String,
+        default: "defaultCanvas"
+      },
+      // 圈类型默认:circle,可选 circle dashboard
+      type: {
+        type: String,
+        validator: val => {
+          return ['circle', 'dashboard'].includes(val);
+        },
+        default: 'circle'
+      },
+      // 圈进度百分比值
+      percent: {
+        type: Number,
+        validator: val => {
+          return val >= 0 && val <= 100;
+        },
+        default: 0
+      },
+      // 圈是否显示进度数值或状态图标
+      showInfo: {
+        type: Boolean,
+        default: true
+      },
+      // 圈文字信息颜色
+      fontColor: {
+        type: String,
+        default: "#595959"
+      },
+      // 圈文字信息大小 默认14
+      fontSize: {
+        type: Number,
+        default: 14
+      },
+      // 圈进度状态,可选:normal success exception
+      status: {
+        type: String,
+        validator: val => {
+          return ['normal', 'success', 'exception'].includes(val);
+        },
+        default: 'normal'
+      },
+      // 圈线条宽度1-50,与width有关
+      strokeWidth: {
+        type: Number,
+        default: 6
+      },
+      // 圈的颜色,设置后status状态无效
+      strokeColor: {
+        type: String,
+        default: ''
+      },
+      // 圈的底圈颜色 默认:#eeeeee
+      strokeBackground: {
+        type: String,
+        default: '#eeeeee'
+      },
+      // 圈两端的形状 可选:'round', 'square'
+      strokeShape: {
+        type: String,
+        validator: val => {
+          return ['round', 'square'].includes(val);
+        },
+        default: 'round'
+      },
+      // 圈画布宽度
+      width: {
+        type: String,
+        default: 80
+      },
+      // 圈缺口角度,可取值 0 ~ 360,仅支持类型:circle  
+      gapDegree: {
+        type: Number,
+        validator: val => {
+          return val >= 0 && val <= 360;
+        },
+        default: 360
+      },
+      // 圈缺口开始位置,可取值'top', 'bottom', 'left', 'right',仅支持类型:circle  
+      gapPosition: {
+        type: String,
+        validator: val => {
+          return ['top', 'bottom', 'left', 'right'].includes(val);
+        },
+        default: 'top'
+      }
+    },
+
+    data() {
+      return {
+        // 画布实例
+        ctx: {},
+        // 圈半径
+        width2px: ""
+      }
+    },
+
+    computed: {
+      // 计算设置圈样式
+      calCircleStyle() {
+        return `width: ${this.width}px;
+				height: ${this.width}px;`
+      },
+      // 计算圈状态
+      calStatus() {
+        let status = {}
+        switch (this.status) {
+          case 'normal':
+            status = {
+              color: "#1890ff",
+              value: 1
+            };
+            break;
+          case 'success':
+            status = {
+              color: "#52c41a",
+              value: 2
+            };
+            break;
+          case 'exception':
+            status = {
+              color: "#f5222d",
+              value: 3
+            };
+            break;
+        }
+        return status
+      },
+      // 计算圈缺口角度
+      calGapDegree() {
+        return this.gapDegree <= 0 ? 360 : this.gapDegree
+      },
+      // 计算圈缺口位置
+      calGapPosition() {
+        let gapPosition = 0
+        switch (this.gapPosition) {
+          case 'bottom':
+            gapPosition = 90;
+            break;
+          case 'left':
+            gapPosition = 180;
+            break;
+          case 'top':
+            gapPosition = 270;
+            break;
+          case 'right':
+            gapPosition = 360;
+            break;
+        }
+        return gapPosition
+      },
+    },
+
+    watch: {
+      // 监听百分比值改变
+      percent(val) {
+        this.drawStroke(val);
+      }
+    },
+
+    mounted() {
+      // 创建画布实例
+      this.ctx = uni.createCanvasContext(this.cid, this)
+      // upx转px 圈半径大小
+      this.width2px = uni.upx2px(this.width)
+      // 绘制初始 
+      this.$nextTick(() => {
+        this.drawStroke(this.percent)
+      })
+    },
+
+    methods: {
+      // 绘制圈
+      drawStroke(percent) {
+        percent = percent >= 100 ? 100 : percent < 0 ? 0 : percent
+        // 圈条进度色
+        let color = this.strokeColor || this.calStatus.color
+        // 是否圈中心显示信息
+        if (this.showInfo) {
+          switch (this.calStatus.value) {
+            case 1:
+              if (percent >= 100) {
+                // 设置打勾
+                this.drawSuccess()
+                percent = 100
+                color = "#52c41a"
+              } else {
+                // 设置字体
+                this.drawText(percent)
+              }
+              break;
+            case 2:
+              // 设置打勾
+              this.drawSuccess()
+              percent = 100
+              color = "#52c41a"
+              break;
+            case 3:
+              // 设置打叉
+              this.drawException()
+              percent = 0
+              color = "#f5222d"
+              break;
+            default:
+              break;
+          }
+        }
+        // 缺口
+        let gapPosition = this.calGapPosition
+        let gapDegree = this.calGapDegree
+        // 仪表固定
+        if (this.type === "dashboard") {
+          gapPosition = 135
+          gapDegree = 270
+        }
+        // 圈型条宽
+        this.ctx.setLineCap(this.strokeShape)
+        this.ctx.setLineWidth(this.strokeWidth)
+        // 位置原点
+        this.ctx.translate(this.width2px, this.width2px)
+        // 缺口方向 
+        this.ctx.rotate(gapPosition * Math.PI / 180)
+        // 圈底 
+        this.ctx.beginPath()
+        this.ctx.arc(0, 0, this.width2px - this.strokeWidth, 0, gapDegree * Math.PI / 180)
+        this.ctx.setStrokeStyle(this.strokeBackground)
+        this.ctx.stroke()
+        // 圈进度 
+        this.ctx.beginPath()
+        this.ctx.arc(0, 0, this.width2px - this.strokeWidth, 0, percent * gapDegree * Math.PI / 18000)
+        this.ctx.setStrokeStyle(color)
+        this.ctx.stroke()
+        // 绘制
+        this.ctx.draw()
+      },
+      // 绘制文字格式
+      drawText(percent) {
+        this.ctx.beginPath()
+        this.ctx.setFontSize(this.fontSize)
+        this.ctx.setFillStyle(this.fontColor)
+        this.ctx.setTextAlign('center')
+        this.ctx.fillText(`${percent}%`, this.width2px, this.width2px + this.fontSize / 2)
+        this.ctx.stroke()
+      },
+      // 绘制成功打勾
+      drawSuccess() {
+        let x = this.width2px - this.fontSize / 2
+        let y = this.width2px + this.fontSize / 2
+        this.ctx.beginPath()
+        this.ctx.setLineCap('round')
+        this.ctx.setLineWidth(this.fontSize / 4)
+        this.ctx.moveTo(this.width2px, y)
+        this.ctx.lineTo(y, x)
+        this.ctx.moveTo(this.width2px, y)
+        this.ctx.lineTo(x, this.width2px)
+        this.ctx.setStrokeStyle("#52c41a")
+        this.ctx.stroke()
+      },
+      // 绘制异常打叉
+      drawException() {
+        let x = this.width2px - this.fontSize / 2
+        let y = this.width2px + this.fontSize / 2
+        this.ctx.beginPath()
+        this.ctx.setLineCap('round')
+        this.ctx.setLineWidth(this.fontSize / 4)
+        this.ctx.moveTo(x, x)
+        this.ctx.lineTo(y, y)
+        this.ctx.moveTo(y, x)
+        this.ctx.lineTo(x, y)
+        this.ctx.setStrokeStyle("#f5222d")
+        this.ctx.stroke()
+      }
+    }
+  };
+</script>
+
+<style>
+  .cmd-circle {
+    display: inline-block;
+    box-sizing: border-box;
+    list-style: none;
+    margin: 0;
+    padding: 0;
+  }
+</style>

+ 255 - 0
components/hx-navbar/README.md

@@ -0,0 +1,255 @@
+# hx-navbar 适用于 uni-app 项目的头部导航组件
+
+导航栏组件,主要用于头部导航,组件名:hx-navbar
+
+本组件目前兼容微信小程序、H5、5+APP。
+
+## QQ群 954035921 
+如有问题可进群发图讨论
+
+### 本组件支持模式:
+1. 普通固定顶部导航  
+2. 透明导航  
+3. 透明固定顶部导航 
+4. 不固定普通导航
+5. 背景颜色线性渐变
+6. 滑动显示背景
+7. 左、中、右3个插槽;可关闭左右插槽使中间插槽铺满导航,实现高度自定义的导航需求
+
+### 使用前提
+
+需要先安装·uniapp·官方的```uni-icons``` 图标组件,```uni-icons```官方组件下载地址:[https://ext.dcloud.net.cn/plugin?id=28](https://ext.dcloud.net.cn/plugin?id=28)
+
+### 使用方式	
+页面使用需在 ``` script ``` 中引用组件
+``` javascript
+import hxNavbar from "@/components/hx-navbar/hx-navbar.vue"
+export default {
+    components: {hxNavbar}
+}
+```
+
+全局使用需在 ``` main.js ```  中注册组件
+``` javascript
+import hxNavbar from "./components/hx-navbar/hx-navbar.vue"
+Vue.component('hx-navbar',hxNavbar)
+
+```
+
+
+### 属性
+#### 基本属性 
+| 名称                        | 类型            | 默认值                | 描述                                               |
+| ----------------------------|--------------- | ---------------------- | ---------------------------------------------------|
+| back                   	  | Boolean         | true          | 返回上一页,(设置后,```leftIcon```属性,和```click-left```事件将失效|
+| height                   	  | String         | 44px          | 导航栏高度(不包含状态栏高度)|
+| barPlaceholder              | String         | auto          | 导航栏占位符 显示(show),隐藏(hidden),自动(auto:如果头部为固定fixed ,则显示占位符)               |
+| title                       | String         | -             | 导航标题(当设置了标题,中间插槽将失效)                                     |
+| fixed                       | Boolean        | false         | 固定头部											|
+| color                       | String         | #000000       | 导航文字颜色(如果需要屏幕滑动后变色,参数则为数组,例子:`['#000000','#ffffff']`)                                        |
+| backgroundColor             | Array          | [255, 255, 255]          | 导航背景颜色为RGB 编号(单色背景数组为```[255,255,255]```,线性渐变背景```[[236, 0, 140],[103, 57, 182],...]```)                                      |
+| pageScroll				  | Object         | {}             | 屏幕滑动距离顶部的对象```滑动渐变必要参数```                                       |
+| backgroundColorLinearDeg    | String         | 45             | 导航背景线性渐变角度                                       |
+| backgroundImg   			  | String         | -             | 导航背景图片(背景图片优先级高于背景颜色)  |
+| transparent   			  | String         | show             | 背景透明(show 不透明,hidden 透明,auto 自动:滑动逐渐显示背景颜色,当头部固定时生效) 兼容性:头条小程序必须在页面上加 onPageScroll(e){} ,才能滑动显示背景,可参考dome7|
+| shadow                      | Boolean         | false         | 导航栏阴影          |
+| border                      | Boolean         | false         | 导航栏边框                           |
+
+#### 关于状态栏的属性
+| 名称                        | 类型            | 默认值                | 描述                                               |
+| ----------------------------|--------------- | ---------------------- | ---------------------------------------------------|
+| statusBar                   | Boolean         | true       		   | 包含状态栏												|
+| statusBarFontColor          | Array,String   | #000000               | 状态栏字体颜色,只支持```#000000 ```和```#FFFFFF```(如果需要屏幕滑动变色,参数则为数组,例子:```['#000000','#ffffff']```)|
+| statusBarBackground         | String         | -                     | 状态栏背景颜色,如果你想单独设置状态栏颜色,该属性是个不错的选择
+
+#### 关于插槽的属性
+| 名称                        | 类型            | 默认值                | 描述                                               |
+| ----------------------------|--------------- | ---------------------- | ---------------------------------------------------|
+| leftIcon                    | String         | -             | 左插槽图标,必须为 ```uni-icons``` 图标                                       |
+| rightIcon   				  | String         | -             | 右插槽图标,必须为 ```uni-icons``` 图标  |
+| leftSlot                    | Boolean        | true          | 开启左插槽                                        |
+| rightSlot                   | Boolean        | true          | 开启右插槽                                      |
+| leftSlidiSwitch             | Boolean         | false         | 屏幕滑动后 `left`插槽切换为`leftAfter`插槽                       |
+| centerSlidiSwitch           | Boolean         | false         | 屏幕滑动后 `default`插槽切换为`centerAfter`插槽                            |
+| rightSlidiSwitch            | Boolean         | false         | 屏幕滑动后 `right`插槽切换为`rightAfter`插槽                            |
+
+
+#### 返回上一页为空时的处理属性
+| 名称                        | 类型            | 默认值                | 描述                                               |
+| ----------------------------|--------------- | ---------------------- | ---------------------------------------------------|
+| backTabbarUrl               | String         | /pages/index/index     | 返回至指定的tabber页面(返回首页),当上一页为空时生效;全局使用推荐进组件修改`backTabbarUrl`的默认值|
+| defaultBackUrl              | String         | -          			| 返回至指定的普通页面,当上一页为空时生效;`defaultBackUrl`优先级高于`backTabbarUrl`;主要应用在返回失效时|
+
+``` html
+<!-- 使用场景:假如刷新了当前页面,那么返回事件将失效。
+这时用上 `defaultBackUrl` 或 `backTabbarUrl` 则能返回至指定页面-->
+<hx-navbar left-text="关于" defaultBackUrl="/pages/user/setting/setting" />
+```
+
+
+### 插槽
+| 名称                  | 描述                                                               |
+| ----------------------|-------------------------------------------------------------------|   
+| left                  | 左插槽 (可关闭该插槽 ```leftSlot``` 属性)                           |
+| default               | 中间插槽(当设置了标题,中间插槽将失效)                               |
+| right                 | 右插槽 (可关闭该插槽 ```rightSlot``` 属性)                          |
+| leftAfter             | 屏幕滑动后的左插槽 (需要开启`leftSlidiSwitch`属性才生效)                  |
+| centerAfter           | 屏幕滑动后的中插槽 (需要开启`centerSlidiSwitch`属性才生效)                  |
+| rightAfter            | 屏幕滑动后的右插槽 (需要开启`rightSlidiSwitch`属性才生效)                  |
+
+
+``` html
+<hx-navbar>
+    <view>标题栏(中间插槽)</view>
+    <view slot="left">left(左插槽)</view>
+    <view  slot="right">right(右插槽)</view>
+</hx-navbar>
+```
+
+
+### 事件
+| 名称             | 参数              | 描述                      |
+| -----------------|------------------| --------------------------|
+| click-left       | -                | 左侧按钮点击时触发,此事件将覆盖 `返回`          |
+| click-right      | -                | 右侧按钮点击时触发          |
+| scroll           | -                | 监听滚动条,回调参数为滚动距离;固定头部时生效;应用场景:如滚动到多少时触发某些事件          |
+
+## 使用例子
+
+### 简单使用
+``` html
+<hx-navbar title="我爱新疆" left-text="返回" />
+```
+
+### 背景颜色线性渐变、头部固定
+``` html
+<hx-navbar 
+	title="颜色渐变" 
+	:back="false"
+	:fixed="true"
+	color="#ffffff"
+	:background-color="[[28, 187, 180],[141, 198, 63]]">
+</hx-navbar>
+```
+
+### 滑动显示背景
+``` html
+<!-- 该例子取消了导航占位符 -->
+<hx-navbar 
+	title="颜色渐变" 
+	:back="false"
+	:fixed="true"
+	color="#ffffff"
+	barPlaceholder="hidden"
+	transparent="auto"
+	:background-color="[[28, 187, 180],[141, 198, 63]]"
+	:pageScroll.sync="scrollData">
+</hx-navbar>
+
+```
+``` javascript
+data() {
+	return {
+		scrollData: {},
+	}
+},
+//必须在页面加 onPageScroll(e){} ,才能滑动显示背景
+onPageScroll(e){
+	this.scrollData = e;
+},
+```
+
+### 左中插槽演示
+``` html
+<hx-navbar  
+	:back="false" 
+	:fixed="true"
+	right-icon="scan">
+	<block slot="left">
+		<view class="city">
+			<view>新疆</view>
+			<uni-icons type="arrowdown" color="#333333" size="22" />
+		</view>
+	</block>
+	<view class="input-view">
+		<uni-icons type="search" size="22" color="#666666" />
+		<input confirm-type="search" class="input" type="text" placeholder="输入搜索关键词" @confirm="confirm">
+	</view>
+</hx-navbar>
+
+
+/*css 用于演示插槽自定义样式*/
+<style>
+	.city{
+		display: flex;flex-direction: row;
+		align-items: center;
+		justify-content: center;
+		width: 100%;
+		margin-left: 8px;
+		white-space: nowrap;
+	}
+</style>
+```
+
+### 关闭左右插槽演示
+``` html
+<hx-navbar  :back="false" :fixed="true" :leftSlot='false' :rightSlot='false'>
+	<view style="display: flex;">
+		<view class="city">
+			<view>新疆</view>
+			<uni-icons type="arrowdown" size="22" />
+		</view>
+		<view class="input-view" style="width: 100%;">
+			<uni-icons type="search" size="22" color="#666666" />
+			<input confirm-type="search" class="input" type="text" placeholder="输入搜索关键词" @confirm="confirm">
+		</view>
+		<uni-icons type="scan" size="22" style="line-height: 44px;padding-left: 8px;"/>
+	</view>
+</hx-navbar>
+/*css 用于演示插槽自定义样式*/
+<style>
+	.city{
+		display: flex;flex-direction: row;
+		align-items: center;
+		justify-content: center;
+		width: 100%;
+		margin-left: 8px;
+		white-space: nowrap;
+	}
+</style>
+```
+
+### 屏幕滑动切换显示插槽
+``` html
+<!-- 该例子演示中间插槽、右插槽屏幕滑动后的变换 -->
+<hx-navbar  
+:border="true" 
+:centerSlidiSwitch="true"
+:rightSlidiSwitch="true"
+:fixed="true"
+:pageScroll.sync="scrollData">
+	<view style="text-align: center;width: 100%;">
+		<text>帮助反馈</text>
+	</view>
+	<view slot="centerAfter" style="text-align: center;width: 100%;">
+		<text>咨询</text>
+	</view>
+	<block slot="right">
+		<uni-icons type="qq" size="30" ></uni-icons>
+	</block>
+	<block slot="rightAfter">
+		<uni-icons type="chat" size="30" ></uni-icons>
+	</block>
+</hx-navbar>
+```
+``` javascript
+data() {
+	return {
+		scrollData: {},
+	}
+},
+//必须在页面加 onPageScroll(e){} ,才能滑动显示
+onPageScroll(e){
+	this.scrollData = e;
+},
+```

+ 635 - 0
components/hx-navbar/hx-navbar.vue

@@ -0,0 +1,635 @@
+<template>
+	
+	<view class="hx-navbar" >
+		
+		<view
+			:class="{'hx-navbar--fixed': fixed,'hx-navbar--shadow':shadow,'hx-navbar--border':border}"
+			:style="{'background': backgroundColorRgba}"
+			class="hx-navbar__content">
+			<block v-if="backgroundImg">
+				<image class="navbgimg" :src="backgroundImg" mode=""></image>
+			</block>
+			
+			<view :style="{ height: statusBarHeight ,'background': statusBarBackground}" class="hx-status-bar" v-if="statusBar" ></view>
+			<view :style="{color:colorInfo,height: height,'line-height':height}" class="hd hx-navbar__header hx-navbar__content_view">
+				<view class="hx-navbar__header-btns hx-navbar__content_view"  @tap="onClickLeft" v-if="leftSlot" :style="{'color': colorInfo}">
+					<block v-if="leftText.length || leftIcon.length || back">
+						<view
+							v-if="leftIcon.length || back"
+							:class="back ? 'left_back' : ''"
+							class="hx-navbar__content_view" >
+							<uni-icons :type="back ? 'arrowleft' : leftIcon" :color="colorInfo" size="28"/>
+						</view>
+						<view
+							v-if="leftText.length"
+							:class="{'hx-navbar-btn-icon-left':!leftIcon.length}"
+							class="hx-navbar-btn-text hx-navbar__content_view">{{ leftText }}</view>
+						
+					</block>
+					<block v-else>
+						<slot name="leftAfter" v-if="leftSlidiSwitch && slotSlidiSwitch == 1" />
+						<slot name="left" v-else/>
+						
+					</block>
+				</view>
+			  
+			  
+				<view class="hx-navbar__header-container hx-navbar__content_view">
+					<view
+					  v-if="title.length"
+					  class="hx-navbar__header-container-inner hx-navbar__content_view">{{ title }}</view>
+					<!-- 标题插槽 -->
+				
+					<block v-else>
+						<slot name="centerAfter" v-if="centerSlidiSwitch && slotSlidiSwitch == 1"/>
+						<slot v-else/>
+						
+					</block>
+				</view>
+				
+				<view :class="title.length?'hx-navbar__header-btns-right':''"
+					class="hx-navbar__header-btns hx-navbar__content_view"
+					@tap="onClickRight"
+					v-if="rightSlot">
+					<!-- 优先显示图标 -->
+					<block v-if="rightIcon.length || rightText.length">
+						<view  class="hx-navbar__content_view" v-if="rightIcon.length">
+							<uni-icons :type="rightIcon" :color="colorInfo" size="28"/>
+						</view>
+						<view v-if="rightText.length" class="hx-navbar-btn-text hx-navbar__content_view">{{ rightText }}</view>
+					</block>
+					<block v-else>
+						<slot name="rightAfter"  v-if="rightSlidiSwitch && slotSlidiSwitch == 1"/>
+						<slot name="right" v-else/>
+					</block>
+					
+					
+				</view>
+			  
+			</view>
+		</view>
+		
+		<view
+		  v-if="placeholder" 
+		  class="hx-navbar__placeholder">
+		  <view :style="{ height: statusBarHeight}" class="hx-status-bar" v-if="statusBar" ></view>
+		 
+		  <view :style="{ height: height}" />
+		</view>
+	</view>
+	
+</template>
+
+<script>
+	import uniIcons from '../uni-icons/uni-icons.vue'
+	//获取系统状态栏高度
+	var statusBarHeight = uni.getSystemInfoSync().statusBarHeight  + 'px';
+	export default {
+		name: "hx-navbar",
+		components: {
+		  uniIcons
+		},
+		data() {
+			return {
+				 statusBarHeight: statusBarHeight,
+				 transparentValue: 0,
+				 navTransparentFixedFontColor: '#fff',
+				 
+				 statusBarFontColorInfo: [],
+				 backgroundColorRgba: 'rgba(255,255,255,1)',
+				 backgroundColorRgb: 'rgb(222,222,222)',
+				 colorInfo: '#000000',
+				 placeholder: false,
+				 colorContainer: null,
+				 slotSlidiSwitch: 0
+				 
+			};
+		},
+		props:{
+			height:{
+				type: String,
+				default: "44px"
+			},
+			//导航栏占位符 显示(show),隐藏(hidden),自动(auto:如果头部为固定fiexd ,则显示占位符)
+			barPlaceholder:{
+				type: String,
+				default: "auto"
+			},
+			//返回上一页
+			back:{
+				type: [Boolean, String],
+				default: true
+			},
+			//标题
+			title: {
+			  type: String,
+			  default: ''
+			},
+			//是否开启左插槽
+			leftSlot:{
+				type: [Boolean, String],
+				default: true
+			},
+			//是否开启右插槽
+			rightSlot:{
+				type: [Boolean, String],
+				default: true
+			},
+		
+			//左边文字
+			leftText: {
+			  type: String,
+			  default: ''
+			},
+			//右插槽文字
+			rightText: {
+			  type: String,
+			  default: ''
+			},
+			//左插槽图标
+			leftIcon: {
+			  type: String,
+			  default: ''
+			},
+			//右插槽图标
+			rightIcon: {
+			  type: String,
+			  default: ''
+			},
+			//是否固定头
+			fixed: {
+			  type: [Boolean, String],
+			  default: false
+			},
+			//文字颜色
+			color: {
+			  type: [Array,String],
+			  default: "#000000"
+			},
+			//导航栏背景颜色
+			backgroundColor: {
+			  type: Array,
+			  default: function(){
+				  return new Array([255,255,255],[255,255,255]);
+			  }
+			},
+			//线性渐变角度
+			backgroundColorLinearDeg: {
+				type: String,
+				default: '45'
+			},
+			//背景图片
+			backgroundImg: {
+				type: String,
+				default: ''
+			},
+			//背景透明(show,hidden,auto)
+			transparent: {
+				type: String,
+				default: 'show'
+			},
+			//状态栏字体颜色,只支持黑(#000000)和白(#FFFFFF)两种颜色。(,)
+			statusBarFontColor:{
+				type: [Array,String],
+				default:function(){
+				  return new Array("#000000","#000000");
+				} 
+			},
+			//是否包含状态栏
+			statusBar: {
+			  type: [Boolean, String],
+			  default: true
+			},
+			//状态栏背景颜色
+			statusBarBackground:{
+				type: String,
+				default: ''
+			},
+			//导航栏阴影
+			shadow: {
+			  type: [String, Boolean],
+			  default: false
+			},
+			//导航栏边框
+			border: {
+			  type: [String, Boolean],
+			  default: false
+			},
+			//跳至普通页面
+			defaultBackUrl: {
+			  type: String,
+			  default: ''
+			},
+			//跳至tabber页面
+			backTabbarUrl: {
+			  type: String,
+			  default: '/pages/index/index'
+			},
+			//滑动后切换左插槽
+			leftSlidiSwitch:{
+				type: [Boolean,String],
+				default: false,
+			},
+			//滑动后切换中间插槽
+			centerSlidiSwitch:{
+				type: [Boolean,String],
+				default: false
+			},
+			//滑动后切换右插槽
+			rightSlidiSwitch:{
+				type: [Boolean,String],
+				default: false
+			},
+			//页面的onPageScroll
+			pageScroll:{
+				type: Object,
+				default:function(){
+				  return {}
+				} 

+			},
+			
+		},
+		created(){
+			var that = this;
+			//是否添加占位符
+			switch (that.barPlaceholder){
+				case 'show':
+					that.placeholder = true;
+					break;
+				case 'hidden':
+					that.placeholder = false;
+					break;
+				case 'auto':
+					if(that.fixed){
+						that.placeholder = true;
+					}
+					break;
+			}
+			
+			//设置状态栏文字颜色
+			that.setStatusBarFontColor();
+
+			//文字颜色
+			that.colorContainer = typeof that.color == 'object' ?  that.color : [that.color,that.color];
+			that.colorInfo = that.colorContainer[0];
+			//导航栏透明设置 及监听滚动
+			switch (that.transparent){
+				case 'show':
+					that.transparentValue = 1;
+					break;
+				case 'hidden':
+					that.transparentValue = 0;
+					break;
+				case 'auto':
+					that.setTVAuto(that.pageScroll)
+					break;
+			}
+			that.setBgColor();
+			
+			//滑动切换
+			if(that.fixed && (that.leftSlidiSwitch || that.centerSlidiSwitch || that.rightSlidiSwitch)){
+				that.doScroll(that.pageScroll);
+			}
+			
+		},
+		watch:{
+			pageScroll(val,oldVal){
+				var that = this;
+				//导航栏透明设置 及监听滚动
+				switch (that.transparent){
+					case 'show':
+						that.transparentValue = 1;
+						break;
+					case 'hidden':
+						that.transparentValue = 0;
+						break;
+					case 'auto':
+						this.setTVAuto(val)
+						break;
+				}
+				//滑动切换
+				if(that.fixed && (that.leftSlidiSwitch || that.centerSlidiSwitch || that.rightSlidiSwitch)){
+					that.doScroll(val);
+				}
+			},
+			//监控透明度变化 
+			transparentValue(val,oldVal) {
+				var that = this;
+				//this.settingColor();
+				
+				//头条小程序不支持setNavigationBarColor方法
+				// #ifndef MP-TOUTIAO || H5
+				if(oldVal > 0.8){
+					uni.setNavigationBarColor({
+						frontColor: that.statusBarFontColorInfo[1],
+						backgroundColor: that.backgroundColorRgb
+					});
+				}else if(oldVal < 0.2){
+					uni.setNavigationBarColor({
+						frontColor: that.statusBarFontColorInfo[0],
+						backgroundColor:  that.backgroundColorRgb
+					});
+				}
+				// #endif
+				
+				// #ifdef MP-TOUTIAO
+				if (tt.setNavigationBarColor) {
+				 if(oldVal > 0.8){
+				 	tt.setNavigationBarColor({
+				 	  frontColor: that.statusBarFontColorInfo[1],
+				 	  backgroundColor: that.backgroundColorRgb,
+				 	  success(res) {},
+				 	  fail(res) {}
+				 	});
+				 }else if(oldVal < 0.2){
+				 	tt.setNavigationBarColor({
+				 	    frontColor: that.statusBarFontColorInfo[0],
+				 	    backgroundColor: that.backgroundColorRgb,
+				 		success(res) {},
+				 		fail(res) {}
+				 	});
+				 }
+				} else {
+				  console.log("hx-navbar 提示:当前客户端版本过低,无法使用状态栏颜色修改功能,请升级(基础库1.40+)。")
+				}
+				// #endif
+			},
+			//监听背景颜色
+			backgroundColor(val,old){
+				var that = this;
+				that.setBgColor()
+			},
+		
+			color(val,old){
+				var that = this;
+				//文字颜色
+				/* that.colorContainer = typeof val == 'object' ?  val : [val,val];
+				that.colorInfo = that.colorContainer[0]; */
+				
+			}
+		},
+		methods: {
+			
+			onClickLeft () {
+				if(this.back){
+					if(getCurrentPages().length>1){
+						uni.navigateBack();
+					}else{
+						// #ifdef H5
+						history.back()
+						// #endif
+						// #ifndef H5
+						if(this.defaultBackUrl){
+							uni.redirectTo({
+								url:this.defaultBackUrl
+							})
+						}else{
+							if(this.backTabbarUrl){
+								uni.reLaunch({
+									url: this.backTabbarUrl
+								});
+							}
+							
+						}
+						// #endif
+					}
+					
+				}else{
+					this.$emit('click-left')
+				}
+		    },
+		    onClickRight () {
+				this.$emit('click-right')
+		    }, 
+			
+			//监听滚动后的操作
+			doScroll(e){
+				let that = this;
+				that.$emit('scroll', e);
+				if (e.scrollTop > 100) {
+					that.slotSlidiSwitch = 1;
+				} else {
+					that.slotSlidiSwitch = 0
+				}
+			},
+			//滑动渐变
+			setTVAuto(e){
+				let that = this;
+				that.$emit('scroll', e);
+				if (e.scrollTop > 100) {
+					that.transparentValue = 1;
+					that.colorInfo = that.colorContainer[1];
+				} else {
+					that.transparentValue = e.scrollTop / 100;
+					that.colorInfo = that.colorContainer[0];
+				}
+				that.setBgColor();
+			},
+			//背景颜色
+			setBgColor(){
+				
+				var that = this;
+				//如果存在背景图片则背景颜色失效
+				// if(that.backgroundImg){
+				// 	that.backgroundColorRgba = "url(" + that.backgroundImg + ")";
+				// 	return;
+				// }
+				
+				//背景颜色
+				if(typeof that.backgroundColor[0] == 'object'){
+					let l = that.backgroundColor.length;
+					if( l >= 2){
+						let rgbStr = "linear-gradient("+ that.backgroundColorLinearDeg +"deg,";
+						let c = null;
+						for(var i in that.backgroundColor){
+							c = that.backgroundColor[i];
+							rgbStr += "rgba("+ c[0] + "," + c[1] + "," + c[2] +"," + that.transparentValue+")";
+							
+							if(l != (i*1)+1){
+								rgbStr += ",";
+							}
+						}
+						rgbStr += ")"; 
+						that.backgroundColorRgba = rgbStr;
+					}
+					
+				}else{
+					let rgbStr = that.backgroundColor[0] + ','+  that.backgroundColor[1] + ','+  that.backgroundColor[2];
+					that.backgroundColorRgb= 'rgb('+ rgbStr + ')';
+					that.backgroundColorRgba = 'rgba('+ rgbStr +',' + that.transparentValue+')';
+				}
+			},
+			setStatusBarFontColor(){
+			  var that = this;
+			  if(typeof that.statusBarFontColor == 'string'){
+				that.statusBarFontColorInfo = [that.statusBarFontColor,that.statusBarFontColor];
+			  }else if(typeof that.statusBarFontColor == 'object'){
+				if (that.statusBarFontColor.length==1){
+					that.statusBarFontColorInfo = [that.statusBarFontColor[0],that.statusBarFontColor[0]];
+				}else if(that.statusBarFontColor.length>=2){
+					that.statusBarFontColorInfo = [that.statusBarFontColor[0],that.statusBarFontColor[1]];
+				}
+			  }
+			  // #ifndef MP-TOUTIAO || H5
+			  uni.setNavigationBarColor({
+				frontColor: that.statusBarFontColorInfo[0],
+				backgroundColor: that.backgroundColorRgb
+			  });
+			   // #endif
+			   
+			  // #ifdef MP-TOUTIAO
+			  if (tt.setNavigationBarColor) {
+			    tt.setNavigationBarColor({
+			      frontColor: that.statusBarFontColorInfo[0],
+			      backgroundColor: that.backgroundColorRgb
+			    });
+			  } else {
+			     console.log("hx-navbar 提示:当前客户端版本过低,无法使用状态栏颜色修改功能,请升级(基础库1.40+)。")
+			  }
+			  // #endif
+			}
+		  
+		},
+		destroyed(){
+			
+		},
+		
+		
+	}
+</script>
+
+<style lang="scss">
+	$nav-height: 44px;
+	
+	.hd{
+		overflow: hidden;
+	}
+	
+	//防止其他ui影响
+	.hx-navbar uni-view,
+	.hx-navbar uni-scroll-view,
+	.hx-navbar uni-swiper,
+	.hx-navbar uni-button,
+	.hx-navbar uni-input,
+	.hx-navbar uni-textarea,
+	.hx-navbar uni-label,
+	.hx-navbar uni-navigator,
+	.hx-navbar uni-image {
+		box-sizing: unset;
+	}
+	.hx-navbar {
+		position: relative;
+		padding-top: 0;
+		overflow: hidden;
+		
+		&__content {
+			display: block;
+			position: relative;
+			width: 100%;
+			/*background-color: $uni-bg-color*/;
+			overflow: hidden;
+			.navbgimg{
+				position: absolute;
+				top: 0;
+				left: 0;
+				z-index: 0;
+				width: 100%;
+			}
+			
+			.hx-navbar__content_view {
+				// line-height: $nav-height;
+				display: flex;
+				align-items: center;
+				
+			}
+			.hx-status-bar {
+				display: block;
+				width: 100%;
+				height: 40px;
+				height: var(--status-bar-height);
+				position: relative;
+				z-index: 1;
+			}
+		}
+	
+		&__header {
+			position: relative;
+			z-index: 1;
+			display: flex;
+			flex-direction: row;
+			width: 100%;
+			height:  $nav-height;
+			line-height: $nav-height;
+			font-size: 36upx;
+			transition: color 0.5s ease 0s;
+			&-btns {
+				display: inline-flex;
+				flex-wrap: nowrap;
+				flex-shrink: 0;
+				min-width: 54px;
+				//padding: 0 6px;
+	
+				&:first-child {
+					padding-left: 0;
+				}
+	
+				&:last-child {
+					min-width: 54px;
+				}
+	
+	    &-right:last-child{
+	     
+	      text-align: right;
+	      flex-direction: row-reverse;
+	    }
+			}
+	
+			&-container {
+				width: 100%;
+				margin: 0 10upx;
+	
+				&-inner {
+					width: 100%;
+					display: flex;
+					justify-content: center;
+					font-size: 36upx;
+					
+					// padding-right: 60upx;
+				}
+			}
+		}
+	
+		&__placeholder {
+			&-view {
+				height: $nav-height;
+			}
+		}
+	
+		&--fixed {
+			position: fixed;
+			top:0;
+			z-index: 998;
+		}
+	
+		&--shadow {
+			box-shadow: 0 2upx 12upx #ccc;
+		}
+	
+		&--border:after {
+			position: absolute;
+			z-index: 3;
+			bottom: 0;
+			left: 0;
+			right: 0;
+			height: 1px;
+			content: '';
+			-webkit-transform: scaleY(.5);
+			transform: scaleY(.5);
+			background-color: #efefef;
+		}
+	}
+	.left_back{
+		padding-left: 12upx;
+		padding-right: 12upx;
+	}
+</style>

Dosya farkı çok büyük olduğundan ihmal edildi
+ 121 - 0
components/j-contacts/j-contacts.vue


Dosya farkı çok büyük olduğundan ihmal edildi
+ 18 - 0
components/j-contacts/pinyin.js


+ 456 - 0
components/lb-picker/README.md

@@ -0,0 +1,456 @@
+<p align="center">
+  <a href="https://github.com/liub1934/uni-lb-picker">
+    <img src="https://img.shields.io/github/stars/liub1934/uni-lb-picker">
+  </a>
+  <a href="https://github.com/liub1934/uni-lb-picker/fork">
+    <img src="https://img.shields.io/github/forks/liub1934/uni-lb-picker">
+  </a>
+  <a href="https://github.com/liub1934/uni-lb-picker/issues">
+    <img src="https://img.shields.io/github/issues/liub1934/uni-lb-picker">
+  </a>
+  <a href="https://www.npmjs.com/package/uni-lb-picker">
+    <img src="https://img.shields.io/npm/v/uni-lb-picker">
+  </a>
+  <a href="https://npmcharts.com/compare/uni-lb-picker?minimal=true">
+    <img src="https://img.shields.io/npm/dm/uni-lb-picker">
+  </a>
+  <a href="https://standardjs.com">
+    <img src="https://img.shields.io/badge/code%20style-standard-brightgreen">
+  </a>
+  <a href="https://github.com/liub1934/uni-lb-picker/blob/master/LICENSE">
+    <img src="https://img.shields.io/github/license/liub1934/uni-lb-picker">
+  </a>
+</p>
+
+插件市场里面的 picker 选择器不满足自己的需求,所以自己写了一个简单的 picker 选择器,可扩展、可自定义,一般满足日常需要。  
+Github:[uni-lb-picker](https://github.com/liub1934/uni-lb-picker)  
+插件市场:[uni-lb-picker](https://ext.dcloud.net.cn/plugin?id=1111)  
+H5 Demo:[点击预览](https://github.liubing.me/uni-lb-picker)
+
+> 如果问题最好去 github 反馈,插件市场评论区留下五星好评即可,[点我去反馈](https://github.com/liub1934/uni-lb-picker/issues/new)
+
+> **由于之前`cancel`拼写失误,写成了`cancle`,`v1.08`现已修正,如果之前版本有使用`cancel`事件的,更新后请及时修正。**
+
+## 兼容性
+
+App + H5 + 各平台小程序(快应用及 360 未测试,nvue 待支持)
+
+## 功能
+
+1、单选  
+2、多级联动,非多级联动,理论支持任意级数  
+3、省市区选择,基于多级联动  
+4、自定义选择器头部确定取消按钮颜色及插槽支持  
+5、选择器可视区自定义滚动个数  
+6、自定义数据字段,满足不同人的需求  
+7、自定义选择器样式  
+8、单选及非联动选择支持扁平化的简单数据,如下形式:
+
+```javascript
+// 单选列表
+list1: ['选项1', '选项2', '选项2'],
+// 非联动选择列表
+list2: [
+  ['选项1', '选项2', '选项3'],
+  ['选项11', '选项22', '选项33'],
+  ['选项111', '选项222', '选项333']
+]
+```
+
+## 引入插件
+
+单独引入,在需要使用的页面上 import 引入即可
+
+```html
+<template>
+  <view>
+    <lb-picker></lb-picker>
+  </view>
+</template>
+
+<script>
+  import LbPicker from '@/components/lb-picker'
+  export default {
+    components: {
+      LbPicker
+    }
+  }
+</script>
+```
+
+全局引入,`main.js`中 import 引入并注册即可全局使用
+
+```jsvascript
+import LbPicker from '@/components/lb-picker'
+Vue.component("lb-picker", LbPicker)
+```
+
+easycom 引入
+
+`pages.json`加上如下配置:
+
+```json
+"easycom": {
+  "autoscan": true,
+  "custom": {
+    "lb-picker": "@/components/lb-picker/index.vue"
+  }
+}
+```
+
+npm 安装引入:
+
+```shell
+npm install uni-lb-picker
+```
+
+```jsvascript
+import LbPicker from 'uni-lb-picker'
+```
+
+## 选择器数据格式
+
+### 单选
+
+常规数据
+
+```javascript
+list: [
+  {
+    label: '选项1',
+    value: '1'
+  },
+  {
+    label: '选项2',
+    value: '2'
+  }
+]
+```
+
+扁平化简单数据
+
+```javascript
+list: ['选项1', '选项2']
+```
+
+### 多级联动
+
+```javascript
+list: [
+  {
+    label: '选项1',
+    value: '1',
+    children: [
+      {
+        label: '选项1-1',
+        value: '1-1',
+        children: [
+          {
+            label: '选项1-1-1',
+            value: '1-1-1'
+          }
+        ]
+      }
+    ]
+  }
+]
+```
+
+### 非联动选择
+
+常规数据
+
+```javascript
+list: [
+  [
+    { label: '选项1', value: '1' },
+    { label: '选项2', value: '2' },
+    { label: '选项3', value: '3' }
+  ],
+  [
+    { label: '选项11', value: '11' },
+    { label: '选项22', value: '22' },
+    { label: '选项33', value: '33' }
+  ],
+  [
+    { label: '选项111', value: '111' },
+    { label: '选项222', value: '222' },
+    { label: '选项333', value: '333' }
+  ]
+]
+```
+
+扁平化简单数据
+
+```javascript
+list: [
+  ['选项1', '选项2', '选项3'],
+  ['选项11', '选项22', '选项33'],
+  ['选项111', '选项222', '选项333']
+]
+```
+
+## 调用显示选择器
+
+通过`ref`形式手动调用`show`方法显示,隐藏同理调用`hide`
+
+```html
+<lb-picker ref="picker"></lb-picker>
+```
+
+```javascript
+this.$refs.picker.show() // 显示
+this.$refs.picker.hide() // 隐藏
+```
+
+`v1.1.3`新增,将需要点击的元素包裹在`lb-picker`中即可。
+
+```html
+<lb-picker>
+  <button>点我直接打开选择器</button>
+</lb-picker>
+```
+
+## 绑定值及设置默认值
+
+支持 vue 中`v-model`写法绑定值,无需自己维护选中值的索引。
+
+```javascript
+<lb-picker v-model="value1"></lb-picker>
+<lb-picker v-model="value2"></lb-picker>
+
+data () {
+  return {
+    value1: '' // 单选
+    value2: [] // 多列联动选择
+  }
+}
+```
+
+## 多个选择器
+
+通过设置不同的`ref`,然后调用即可
+
+```javascript
+<lb-picker ref="picker1"></lb-picker>
+<lb-picker ref="picker2"></lb-picker>
+
+this.$refs.picker1.show() // picker1显示
+this.$refs.picker2.show() // picker2显示
+```
+
+## 省市区选择
+
+省市区选择是基于多列联动选择,数据来源:[https://github.com/modood/Administrative-divisions-of-China](https://github.com/modood/Administrative-divisions-of-China),  
+省市区文件位于`/pages/demos/area-data-min.js`,自行引入即可,可参考`demo3省市区选择`,  
+也可使用自己已有的省市区数据,如果数据字段不一样,也可以自定义,参考下方自定义数据字段。
+
+## 自定义数据字段
+
+为了满足不同人的需求,插件支持自定义数据字段名称, 插件默认的数据字段如下形式:
+
+```javascript
+list: [
+  {
+    label: '选择1',
+    value: 1,
+    children: []
+  },
+  {
+    label: '选择1',
+    value: 1,
+    children: []
+  }
+]
+```
+
+如果你的数据字段和上面不一样,如下形式:
+
+```javascript
+list: [
+  {
+    text: '选择1',
+    id: 1,
+    child: []
+  },
+  {
+    text: '选择1',
+    id: 1,
+    child: []
+  }
+]
+```
+
+通过设置参数中的`props`即可,如下所示:
+
+```javascript
+<lb-picker :props="myProps"></lb-picker>
+
+data () {
+  return {
+    myProps: {
+      label: 'text',
+      value: 'id',
+      children: 'child'
+    }
+  }
+}
+```
+
+## 插槽使用
+
+选择器支持一些可自定义化的插槽,如选择器的取消和确定文字按钮,如果需要对其自定义处理的话,比如加个 icon 图标之类的,可使用插槽,使用方法如下:
+
+```html
+<lb-picker>
+  <view slot="cancel-text">我是自定义取消</view>
+  <view slot="confirm-text">我是自定义确定</view>
+</lb-picker>
+```
+
+也可参考示例中的`demo5`,自定义插槽元素样式交给开发者自由调整,插槽仅提供预留位置。
+
+其他插槽见下。
+
+## 参数及事件
+
+### Props
+
+| 参数                    | 说明                                                                                                                               | 类型                | 可选值                                                           | 默认值                                            |
+| :---------------------- | :--------------------------------------------------------------------------------------------------------------------------------- | :------------------ | :--------------------------------------------------------------- | :------------------------------------------------ |
+| value/v-model           | 绑定值,联动选择为 Array 类型                                                                                                      | String/Number/Array | -                                                                | -                                                 |
+| mode                    | 选择器类型,支持单列,多列联动                                                                                                     | String              | selector 单选/multiSelector 多级联动/unlinkedSelector 多级非联动 | selector                                          |
+| list                    | 选择器数据(v1.0.7 单选及非联动多选支持扁平数据:['选项 1', '选项 2'])                                                              | Array               | -                                                                | -                                                 |
+| level                   | 多列联动层级,仅 mode 为 multiSelector 有效                                                                                        | Number              | -                                                                | 2                                                 |
+| props                   | 自定义数据字段                                                                                                                     | Object              | -                                                                | {label:'label',value:'value',children:'children'} |
+| cancel-text             | 取消文字                                                                                                                           | String              | -                                                                | 取消                                              |
+| cancel-color            | 取消文字颜色                                                                                                                       | String              | -                                                                | #999                                              |
+| confirm-text            | 确定文字                                                                                                                           | String              | -                                                                | 确定                                              |
+| confirm-color           | 确定文字颜色                                                                                                                       | String              | -                                                                | #007aff                                           |
+| empty-text              | (v1.0.7 新增)选择器列表为空的时候显示的文字                                                                                        | String              | -                                                                | 暂无数据                                          |
+| empty-color             | (v1.0.7 新增)暂无数据文字颜色                                                                                                      | String              | -                                                                | #999                                              |
+| column-num              | 可视滚动区域内滚动个数,最好设置奇数值                                                                                             | Number              | -                                                                | 5                                                 |
+| radius                  | 选择器顶部圆角,支持 rpx,如 radius="10rpx"                                                                                        | String              | -                                                                | -                                                 |
+| ~~column-style~~        | ~~选择器默认样式(已弃用,见下方自定义样式说明)~~                                                                                   | Object              | -                                                                | -                                                 |
+| ~~active-column-style~~ | ~~选择器选中样式(已弃用,见下方自定义样式说明)~~                                                                                   | Object              | -                                                                | -                                                 |
+| loading                 | 选择器是否显示加载中,可使用 loading 插槽自定义加载效果                                                                            | Boolean             | -                                                                | -                                                 |
+| mask-color              | 遮罩层颜色                                                                                                                         | String              | -                                                                | rgba(0, 0, 0, 0.4)                                |
+| show-mask               | (v1.1.0 新增)是否显示遮罩层                                                                                                        | Boolean             | true/false                                                       | true                                              |
+| close-on-click-mask     | 点击遮罩层是否关闭选择器                                                                                                           | Boolean             | true/false                                                       | true                                              |
+| ~~change-on-init~~      | ~~(v1.0.7 已弃用)初始化时是否触发 change 事件~~                                                                                    | Boolean             | true/false                                                       | -                                                 |
+| dataset                 | (v1.0.7 新增)可以向组件中传递任意的自定义的数据(对象形式数据),如`:dataset="{name:'test'}"`,在`confirm`或`change`事件中可以取到 | Object              | -                                                                | -                                                 |
+| show-header             | (v1.0.8 新增)是否显示选择器头部                                                                                                    | Boolean             | -                                                                | true                                              |
+| inline                  | (v1.0.8 新增)inline 模式,开启后默认显示选择器,无需点击弹出,可以配合`show-header`一起使用                                        | Boolean             | -                                                                | -                                                 |
+| z-index                 | (v1.0.9 新增)选择器层级,遮罩层默认-1                                                                                              | Number              | -                                                                | 999                                               |
+| safe-area-inset-bottom  | (v1.1.4 新增)是否留出底部安全距离                                                                                                  | Boolean             | true/false                                                       | true                                              |
+| disabled                | (v1.1.4 新增)是否禁用选择器,禁用后无法弹出选择器                                                                                  | Boolean             | -                                                                | -                                                 |
+
+### 方法
+
+| 方法名         | 说明                                   | 参数            | 返回值                                                                                                       |
+| :------------- | :------------------------------------- | :-------------- | :----------------------------------------------------------------------------------------------------------- |
+| show           | 打开选择器                             | -               |                                                                                                              |
+| hide           | 关闭选择器                             | -               |                                                                                                              |
+| getColumnsInfo | (v1.1.0 新增)根据 value 获取选择器信息 | 绑定值的`value` | 同`change` `confirm`回调参数,如果传入的`value`获取不到信息则只返回一个含有`dataset`的对象,具体自行打印查看 |
+
+### Events
+
+| 事件名称 | 说明                                     | 回调参数                                                                                                                                                                                                                                                                                                                             |
+| :------- | :--------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| show     | 选择器打开时触发                         | -                                                                                                                                                                                                                                                                                                                                    |
+| hide     | 选择器隐藏时触发                         | -                                                                                                                                                                                                                                                                                                                                    |
+| change   | 选择器滚动时触发,此时不会改变绑定的值   | `{ index, item, value, change }` `index`触发滚动后新的索引,单选时是具体的索引值,多列联动选择时为数组。`item`触发滚动后新的的完整内容,包括`label`、`value`等,单选时为对象,多列选择时为数组对象。`value`触发滚动后新的 value 值,单列选择时为具体值,多列联动选择时为数组。`change`触发事件的类型,详情参考下面的 change 事件备注 |
+| confirm  | 点击选择器确定时触发,此时会改变绑定的值 | 同上`change`事件说明                                                                                                                                                                                                                                                                                                                 |
+| cancel   | 点击选择器取消时触发                     | 同上`change`事件说明                                                                                                                                                                                                                                                                                                                 |
+
+### `change` 事件备注
+
+如果绑定的值是空的,`change`触发后里面的内容都是列表的第一项。  
+`change`事件会在以下情况触发:
+
+- 初始化
+- 绑定值 value 变化
+- 选择器 list 列表变化
+- 滚动选择器
+
+以上情况会在回调函数中都可以取到`change`变化的类型,对应上面的情况包括以下:
+
+- `init`
+- `value`
+- `list`
+- `scroll`
+
+根据这些类型大家可以在`change`的时候按需处理自己的业务逻辑,`init`现在指挥在调用选择器弹出的时候触发。  
+下面的说明情况已失效,如需要在页面显示的时候根据`value`的值显示相应的中文,调用`v1.10`新增的方法`getColumnsInfo`,传入绑定的值即可获取到你想要的所有信息。  
+~~比如一种常见的情况,有默认值的时候需要显示默认值的文字,此时可以`change`事件中判断`change`的类型是否是`init`,如果是的话可以取事件回调中的`item`进行显示绑定值对应的文字信息。~~
+
+```javascript
+handleChange (e) {
+  if (e.change === 'init') {
+    console.log(e.item.label) // 单选 选项1
+    console.log(e.item.map(item => item.label).join('-')) // 多选 选项1-选项11
+  }
+}
+```
+
+### 插槽
+
+| 插槽名        | 说明                   |
+| :------------ | :--------------------- |
+| cancel-text   | 选择器取消文字插槽     |
+| action-center | 选择器顶部中间插槽     |
+| confirm-text  | 选择器确定文字插槽     |
+| loading       | 选择器 loading 插槽    |
+| empty         | 选择器 空数据 插槽     |
+| header-top    | 选择器头部顶部插槽     |
+| header-bottom | 选择器头部底部插槽     |
+| picker-top    | 选择器滚动部分顶部插槽 |
+| picker-bottom | 选择器滚动部分底部插槽 |
+
+### 选择器自定义样式
+
+原先的`column-style`和`active-column-style`已弃用,如需修改默认样式及选中样式参考`demo9`
+
+```css
+<style lang="scss" scoped>
+/deep/ .lb-picker {
+  .lb-picker-column-label {
+    color: #f0ad4e;
+  }
+  .lb-picker-column-active {
+    .lb-picker-column-label {
+      color: #007aff;
+      font-weight: 700;
+    }
+  }
+}
+</style>
+```
+
+### 获取选中值的文字
+
+`@confirm`事件中可以拿到:
+
+单选:
+
+```javascript
+handleConfirm (e) {
+  console.log(e.item.label) // 选项1
+}
+```
+
+联动选择:
+
+```javascript
+handleConfirm (e) {
+  console.log(e.item.map(item => item.label).join('-')) // 选项1-选项11
+}
+```
+
+## Tips
+
+微信小程序端,滚动时在 iOS 自带振动反馈,可在系统设置 -> 声音与触感 -> 系统触感反馈中关闭
+
+## 其他
+
+其他功能参考示例 Demo 代码。

Dosya farkı çok büyük olduğundan ihmal edildi
+ 94 - 0
components/lb-picker/index.vue


+ 46 - 0
components/lb-picker/mixins/index.js

@@ -0,0 +1,46 @@
+import { getColumns } from '../utils'
+export const commonMixin = {
+  data () {
+    return {
+      isConfirmChange: false,
+      indicatorStyle: `height: 34px`
+    }
+  },
+  created () {
+    this.init('init')
+  },
+  methods: {
+    init (changeType) {
+      if (this.list && this.list.length) {
+        const column = getColumns({
+          value: this.value,
+          list: this.list,
+          mode: this.mode,
+          props: this.props,
+          level: this.level
+        })
+        const { columns, value, item, index } = column
+        this.selectValue = value
+        this.selectItem = item
+        this.pickerColumns = columns
+        this.pickerValue = index
+        this.$emit('change', {
+          value: this.selectValue,
+          item: this.selectItem,
+          index: this.pickerValue,
+          change: changeType
+        })
+      }
+    }
+  },
+  watch: {
+    value () {
+      if (!this.isConfirmChange) {
+        this.init('value')
+      }
+    },
+    list () {
+      this.init('list')
+    }
+  }
+}

+ 94 - 0
components/lb-picker/pickers/multi-selector-picker.vue

@@ -0,0 +1,94 @@
+<template>
+  <view class="lb-multi-selector lb-picker-item"
+    :style="{ height: height }">
+    <picker-view :value="pickerValue"
+      :indicator-style="indicatorStyle"
+      :style="{ height: height }"
+      @change="handleChange">
+      <picker-view-column v-for="(column, index) in pickerColumns"
+        :key="index">
+        <view v-for="(item, i) in column || []"
+          :class="[
+            'lb-picker-column',
+            item[props.value] === selectValue[index]
+              ? 'lb-picker-column-active'
+              : ''
+          ]"
+          :key="i">
+          <text class="lb-picker-column-label">
+            {{ item[props.label] || item }}
+          </text>
+        </view>
+      </picker-view-column>
+    </picker-view>
+  </view>
+</template>
+
+<script>
+import { commonMixin } from '../mixins'
+export default {
+  props: {
+    value: Array,
+    list: Array,
+    mode: String,
+    props: Object,
+    level: Number,
+    visible: Boolean,
+    height: String
+  },
+  mixins: [commonMixin],
+  data () {
+    return {
+      pickerValue: [],
+      pickerColumns: [],
+      selectValue: [],
+      selectItem: []
+    }
+  },
+  methods: {
+    handleChange (item) {
+      const pickerValue = item.detail.value
+      const columnIndex = pickerValue.findIndex(
+        (item, i) => item !== this.pickerValue[i]
+      )
+      const valueIndex = pickerValue[columnIndex]
+      this.setPickerChange(pickerValue, valueIndex, columnIndex)
+    },
+    setPickerChange (pickerValue, valueIndex, columnIndex) {
+      for (let i = 0; i < this.level; i++) {
+        if (i > columnIndex) {
+          pickerValue[i] = 0
+          const column =
+            this.pickerColumns[i - 1][valueIndex] ||
+            this.pickerColumns[i - 1][0]
+          this.$set(this.pickerColumns, i, column[this.props.children] || [])
+          valueIndex = 0
+        }
+        this.$set(this.pickerValue, i, pickerValue[i])
+        const selectItem = this.pickerColumns[i][pickerValue[i]]
+        if (selectItem) {
+          this.selectItem[i] = selectItem
+          this.selectValue[i] = selectItem[this.props.value]
+        } else {
+          const spliceNum = this.level - i
+          this.pickerValue.splice(i, spliceNum)
+          this.selectValue.splice(i, spliceNum)
+          this.selectItem.splice(i, spliceNum)
+          this.pickerColumns.splice(i, spliceNum)
+          break
+        }
+      }
+      this.$emit('change', {
+        value: this.selectValue,
+        item: this.selectItem,
+        index: this.pickerValue,
+        change: 'scroll'
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import "../style/picker-item.scss";
+</style>

+ 67 - 0
components/lb-picker/pickers/selector-picker.vue

@@ -0,0 +1,67 @@
+<template>
+  <view class="lb-selector-picker lb-picker-item"
+    :style="{ height: height }">
+    <picker-view :value="pickerValue"
+      :style="{ height: height }"
+      :indicator-style="indicatorStyle"
+      @change="handleChange">
+      <picker-view-column>
+        <view v-for="(item, i) in list"
+          :class="[
+            'lb-picker-column',
+            (item[props.value] || item) === selectValue
+              ? 'lb-picker-column-active'
+              : ''
+          ]"
+          :key="i">
+          <text class="lb-picker-column-label">
+            {{ item[props.label] || item }}
+          </text>
+        </view>
+      </picker-view-column>
+    </picker-view>
+  </view>
+</template>
+
+<script>
+import { isObject } from '../utils'
+import { commonMixin } from '../mixins'
+export default {
+  props: {
+    value: [String, Number],
+    list: Array,
+    mode: String,
+    props: Object,
+    visible: Boolean,
+    height: String
+  },
+  mixins: [commonMixin],
+  data () {
+    return {
+      pickerValue: [],
+      selectValue: '',
+      selectItem: null
+    }
+  },
+  methods: {
+    handleChange (item) {
+      const index = item.detail.value[0] || 0
+      this.selectItem = this.list[index]
+      this.selectValue = isObject(this.selectItem)
+        ? this.selectItem[this.props.value]
+        : this.selectItem
+      this.pickerValue = item.detail.value
+      this.$emit('change', {
+        value: this.selectValue,
+        item: this.selectItem,
+        index: index,
+        change: 'scroll'
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import "../style/picker-item.scss";
+</style>

+ 75 - 0
components/lb-picker/pickers/unlinked-selector-picker.vue

@@ -0,0 +1,75 @@
+<template>
+  <view class="lb-selector-picker lb-picker-item"
+    :style="{ height: height }">
+    <picker-view :value="pickerValue"
+      :indicator-style="indicatorStyle"
+      :style="{ height: height }"
+      @change="handleChange">
+      <picker-view-column v-for="(column, index) in pickerColumns"
+        :key="index">
+        <view v-for="(item, i) in column || []"
+          :class="[
+            'lb-picker-column',
+            (item[props.value] || item) === selectValue[index]
+              ? 'lb-picker-column-active'
+              : ''
+          ]"
+          :key="i">
+          <text class="lb-picker-column-label">
+            {{ item[props.label] || item }}
+          </text>
+        </view>
+      </picker-view-column>
+    </picker-view>
+  </view>
+</template>
+
+<script>
+import { isObject } from '../utils'
+import { commonMixin } from '../mixins'
+export default {
+  props: {
+    value: Array,
+    list: Array,
+    mode: String,
+    props: Object,
+    visible: Boolean,
+    height: String
+  },
+  mixins: [commonMixin],
+  data () {
+    return {
+      pickerValue: [],
+      pickerColumns: [],
+      selectValue: [],
+      selectItem: []
+    }
+  },
+  methods: {
+    handleChange (item) {
+      const pickerValue = item.detail.value
+      const columnIndex = pickerValue.findIndex((item, i) => item !== this.pickerValue[i])
+      if (columnIndex > -1) {
+        const valueIndex = pickerValue[columnIndex]
+        const columnItem = this.list[columnIndex][valueIndex]
+        const valueItem = isObject(columnItem)
+          ? columnItem[this.props.value]
+          : columnItem
+        this.pickerValue = pickerValue
+        this.$set(this.selectValue, columnIndex, valueItem)
+        this.$set(this.selectItem, columnIndex, columnItem)
+        this.$emit('change', {
+          value: this.selectValue,
+          item: this.selectItem,
+          index: this.pickerValue,
+          change: 'scroll'
+        })
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+@import "../style/picker-item.scss";
+</style>

+ 23 - 0
components/lb-picker/style/picker-item.scss

@@ -0,0 +1,23 @@
+.lb-picker-column {
+  height: 34px;
+  /* #ifndef APP-NVUE */
+  display: flex;
+  box-sizing: border-box;
+  white-space: nowrap;
+  overflow: hidden;
+  /* #endif */
+  flex-direction: row;
+  align-items: center;
+  justify-content: center;
+}
+
+.lb-picker-column-label {
+  font-size: 16px;
+  text-align: center;
+  text-overflow: ellipsis;
+  transition-property: color;
+  transition-duration: 0.3s;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}

+ 185 - 0
components/lb-picker/style/picker.scss

@@ -0,0 +1,185 @@
+.lb-picker {
+	position: relative;
+}
+
+.lb-picker-mask {
+	background-color: rgba(0, 0, 0, 0.0);
+	position: fixed;
+	top: 0;
+	right: 0;
+	left: 0;
+	bottom: 0;
+}
+
+.lb-picker-mask-animation {
+	transition-property: background-color;
+	transition-duration: 0.3s;
+}
+
+.lb-picker-container {
+	position: relative;
+}
+
+.lb-picker-container-fixed {
+	position: fixed;
+	left: 0;
+	right: 0;
+	bottom: 0;
+	transform: translateY(100%);
+	/* #ifndef APP-PLUS */
+	overflow: hidden;
+	/* #endif */
+}
+
+.lb-picker-container-animation {
+	transition-property: transform;
+	transition-duration: 0.3s;
+}
+
+.lb-picker-container-show {
+	transform: translateY(0);
+}
+
+.lb-picker-header {
+	position: relative;
+	background-color: #fff;
+	/* #ifdef APP-NVUE */
+	border-bottom-width: 1px;
+	border-bottom-style: solid;
+	border-bottom-color: #e5e5e5;
+	border-top-width: 1px;
+	border-top-style: solid;
+	border-top-color: #e5e5e5;
+	/* #endif */
+	/* #ifndef APP-NVUE */
+	box-sizing: border-box;
+	/* #endif */
+
+}
+
+.lb-picker-header-actions {
+	height: 45px;
+	/* #ifndef APP-NVUE */
+	box-sizing: border-box;
+	display: flex;
+	/* #endif */
+	flex-direction: row;
+	justify-content: space-between;
+	flex-wrap: nowrap;
+}
+
+/* #ifndef APP-PLUS */
+.lb-picker-header::before {
+	content: "";
+	position: absolute;
+	left: 0;
+	top: 0;
+	right: 0;
+	height: 1px;
+	clear: both;
+	border-bottom: 1px solid #e5e5e5;
+	color: #e5e5e5;
+	transform-origin: 0 100%;
+	transform: scaleY(0.5);
+}
+
+.lb-picker-header::after {
+	content: "";
+	position: absolute;
+	left: 0;
+	bottom: 0;
+	right: 0;
+	height: 1px;
+	clear: both;
+	border-bottom: 1px solid #e5e5e5;
+	color: #e5e5e5;
+	transform-origin: 0 100%;
+	transform: scaleY(0.5);
+}
+
+/* #endif */
+
+.lb-picker-action {
+	padding-left: 14px;
+	padding-right: 14px;
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	flex-direction: row;
+	align-items: center;
+	justify-content: center;
+}
+
+.lb-picker-action-item {
+	text-align: center;
+	height: 45px;
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	align-items: center;
+}
+
+.lb-picker-action-cancel-text {
+	font-size: 16px;
+	color: #999;
+}
+
+.lb-picker-action-confirm-text {
+	font-size: 16px;
+	color: #007aff;
+}
+
+.lb-picker-content {
+	position: relative;
+	background-color: #fff;
+}
+
+.lb-picker-content-safe-buttom {
+	padding-bottom: 0;
+	padding-bottom: constant(safe-area-inset-bottom);
+	padding-bottom: env(safe-area-inset-bottom);
+}
+
+.lb-picker-content-main {
+	position: relative;
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	justify-content: center;
+	flex-direction: column;
+}
+
+.lb-picker-loading,
+.lb-picker-empty {
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	justify-content: center;
+	align-items: center;
+}
+
+.lb-picker-empty-text {
+	color: #999;
+	font-size: 16px;
+}
+
+.lb-picker-loading-img {
+	width: 25px;
+	height: 25px;
+	/* #ifndef APP-NVUE */
+	animation: rotating 2s linear infinite;
+	/* #endif */
+}
+
+/* #ifndef APP-NVUE */
+@keyframes rotating {
+	0% {
+		transform: rotate(0deg)
+	}
+
+	to {
+		transform: rotate(1turn)
+	}
+}
+
+/* #endif */

+ 110 - 0
components/lb-picker/utils.js

@@ -0,0 +1,110 @@
+/**
+ * 判断是否是对象
+ *
+ * @export
+ * @param {*} val
+ * @returns true/false
+ */
+export function isObject (val) {
+  return Object.prototype.toString.call(val) === '[object Object]'
+}
+
+/**
+ * 根据value获取columns信息
+ *
+ * @export
+ * @param {*} { value, list, mode, props, level }
+ * @param {number} [type=2] 查询不到value数据返回数据类型 1空值null 2默认第一个选项
+ * @returns
+ */
+export function getColumns ({ value, list, mode, props, level }, type = 2) {
+  let pickerValue = []
+  let pickerColumns = []
+  let selectValue = []
+  let selectItem = []
+  let columnsInfo = null
+  switch (mode) {
+    case 'selector':
+      let index = list.findIndex(item => {
+        return isObject(item) ? item[props.value] === value : item === value
+      })
+      if (index === -1 && type === 1) {
+        columnsInfo = null
+      } else {
+        index = index > -1 ? index : 0
+        selectItem = list[index]
+        selectValue = isObject(selectItem)
+          ? selectItem[props.value]
+          : selectItem
+        pickerColumns = list
+        pickerValue = [index]
+        columnsInfo = {
+          index: pickerValue,
+          value: selectValue,
+          item: selectItem,
+          columns: pickerColumns
+        }
+      }
+      break
+    case 'multiSelector':
+      const setPickerItems = (data = [], index = 0) => {
+        if (!data.length) return
+        const defaultValue = value || []
+        if (index < level) {
+          const value = defaultValue[index] || ''
+          let i = data.findIndex(item => item[props.value] === value)
+          if (i === -1 && type === 1) return
+          i = i > -1 ? i : 0
+          pickerValue[index] = i
+          pickerColumns[index] = data
+          if (data[i]) {
+            selectValue[index] = data[i][props.value]
+            selectItem[index] = data[i]
+            setPickerItems(data[i][props.children] || [], index + 1)
+          }
+        }
+      }
+      setPickerItems(list)
+      if (!selectValue.length && type === 1) {
+        columnsInfo = null
+      } else {
+        columnsInfo = {
+          index: pickerValue,
+          value: selectValue,
+          item: selectItem,
+          columns: pickerColumns
+        }
+      }
+      break
+    case 'unlinkedSelector':
+      list.forEach((item, i) => {
+        let index = item.findIndex(item => {
+          return isObject(item)
+            ? item[props.value] === value[i]
+            : item === value[i]
+        })
+        if (index === -1 && type === 1) return
+        index = index > -1 ? index : 0
+        const columnItem = list[i][index]
+        const valueItem = isObject(columnItem)
+          ? columnItem[props.value]
+          : columnItem
+        pickerValue[i] = index
+        selectValue[i] = valueItem
+        selectItem[i] = columnItem
+      })
+      pickerColumns = list
+      if (!selectValue.length && type === 1) {
+        columnsInfo = null
+      } else {
+        columnsInfo = {
+          index: pickerValue,
+          value: selectValue,
+          item: selectItem,
+          columns: pickerColumns
+        }
+      }
+      break
+  }
+  return columnsInfo
+}

+ 170 - 0
components/lxc-count/lxc-count.vue

@@ -0,0 +1,170 @@
+<template>
+	<view class="count-box" :class="status ? 'count-box-light' : 'count-box-gray'">
+		<view class="count-less count-pub" :class="[myValue <= min ? 'light' : 'gray']" @tap.stop="less"  @longpress='longpressLess' @touchend="handletouchend">-</view>
+		<view class="count-add count-pub" :class="[myValue >= max ? 'light' : 'gray']" @tap.stop="add" @longpress='longpressAdd' @touchend="handletouchend">+</view>
+		<input type="number" v-model="myValue" @focus="onFocus" @blur="onBlue" class="count-input"/>
+	</view>
+</template>
+
+<script>
+	export default {
+		data(){
+			return{
+				myValue: 0,
+				status: false,
+				timer: null
+			}
+		},
+		props: {
+			// 计数器中的值
+			value: {
+				type: Number,
+				default: 0
+			},
+			max: {
+				type: Number,
+				default: 10000
+			},
+			min: {
+				type: Number,
+				default: 2
+			},
+			// 点击当前数据的索引
+			index: {
+				type: Number
+			},
+			delayed: {
+				type: Number,
+				default: 200
+			}
+		},
+		created() {
+			this.myValue = this.value
+		},
+		watch:{
+			value(val) {
+				this.myValue = val
+			}
+		},
+		methods: {
+			onBlue() {
+				if(+this.myValue >= this.max) {
+					this.myValue = this.max
+					this.status = false
+				}else if(+this.myValue <= this.min) {
+					this.myValue = this.min
+					this.status = false
+				}else {
+					this.status = true
+					this.myValue = +this.myValue
+				}
+				if(!isNaN(this.myValue)) {
+					this.$emit('handleCount', this.myValue, this.index)
+				}else {
+					this.$emit('handleCount', 0, this.index)
+				}
+				
+			},
+			onFocus() {
+				this.status = true
+			},
+			add() {
+				this.addPublick()
+			},
+			addPublick() {
+				if(this.myValue >= this.max) {
+					this.status = false
+					this.myValue = this.max
+					clearInterval(this.timer)
+				}else {
+					this.status = true
+					this.myValue ++
+				}
+				this.$emit('handleCount', this.myValue, this.index)
+			},
+			longpressAdd() {
+				this.timer = setInterval(() => {
+					this.addPublick()
+				}, this.delayed)
+			},
+			less() {
+				this.lessPublick()
+			},
+			lessPublick() {
+				if(this.myValue <= this.min) {
+					clearInterval(this.timer)
+					this.status = false
+					this.myValue = this.min
+				}else {
+					this.status = true
+					this.myValue --
+				}
+				this.$emit('handleCount', this.myValue, this.index)
+			},
+			longpressLess() {
+				this.timer = setInterval(() => {
+					this.lessPublick()
+				}, this.delayed)
+			},
+			handletouchend() {
+				clearInterval(this.timer)
+			}
+		}
+	}
+</script>
+<style>
+	.gray{
+		background: #eef3f9;
+		color: #555555;
+	}
+	.light{
+		background: #f5f7fa;
+		color: #C8C7CC;
+	}
+	.count-box{
+		position: relative;
+		width: 220rpx;
+		height: 60rpx;
+		border-radius: 5px;
+		z-index: 1;
+		transition: all .3s;
+	}
+	.count-box-light{
+		border: 1px solid #add4ff;
+	}
+	.count-box-gray{
+		border: 1px solid #e4e4e4;
+	}
+	.count-pub{
+		position: absolute;
+		top: 50%;
+		transform: translate(0, -50%);
+		width: 60rpx;
+		height: 100%;
+		text-align: center;
+		font-size: 20px;
+	}
+	.count-less{
+		left: 0;
+		border-top-left-radius:4px;
+		border-bottom-left-radius:4px;
+	}
+	.count-add{
+		right: 0;
+		border-top-right-radius:4px;
+		border-bottom-right-radius:4px;
+	}
+	.count-input{
+		width: 110rpx;
+		height: 100%;
+		position: absolute;
+		top: 0;
+		left: 50%;
+		transform: translate(-50%, 0);
+		padding: 6rpx 10rpx;
+		box-sizing: border-box;
+		color: #808080;
+		font-size: 26rpx;
+		text-align: center;
+	}
+</style>

BIN
components/mehaotian-search/.DS_Store


+ 180 - 0
components/mehaotian-search/mehaotian-search.vue

@@ -0,0 +1,180 @@
+<template>
+	<view class="search" :style="{ backgroundColor: backgroundColor }">
+		<view class="content" :style="{ 'border-radius': radius + 'px', border: border }">
+			<view class="content-box" :class="{ center: mode === 2 }">
+				<text class="icon icon-search">&#xe61c;</text>
+				<input class="input" :class="{ center: !active && mode === 2 }" @input="search" :focus="isFocus" :placeholder="placeholder" v-model="inputVal" @focus="focus" @blur="blur" />
+				<!-- <view v-if="!active && mode === 2" class="input sub" @click="getFocus">请输入搜索内容</view> -->
+				<!--<text v-if="isDelShow" class="icon icon-del" @click="clear">&#xe644;</text>-->
+			</view>
+			<view v-show="(active && show && button === 'inside') || (isDelShow && button === 'inside')" class="searchBtn" @click="search">搜索</view>
+		</view>
+		<!--<view v-if="button === 'outside'" class="button" :class="{ active: show || active }" @click="search">-->
+			<!--<view class="button-item">{{ !show ? searchName : '搜索' }}</view>-->
+		<!--</view>-->
+	</view>
+</template>
+
+<script>
+export default {
+	props: {
+		mode: {
+			type: Number,
+			default: 1
+		},
+		button: {
+			type: String,
+			default: 'outside'
+		},
+		show: {
+			type: Boolean,
+			default: true
+		},
+		radius: {
+			type: String,
+			default: '60'
+		},
+		placeholder: {
+			type: String,
+			default: '请输入搜索内容'
+		},
+		backgroundColor: {
+			type: String,
+			default: '#fff'
+		},
+		border: { type: String, default: '1px #f5f5f5 solid' }
+		
+	},
+	data() {
+		return {
+			active: false,
+			inputVal: '',
+			searchName: '取消',
+			isDelShow: false,
+			isFocus: false
+		};
+	},
+	methods: {
+		focus() {
+			this.active = true;
+		},
+		blur() {
+			this.isFocus = false;
+			if (!this.inputVal) {
+				this.active = false;
+			}
+		},
+		clear() {
+			this.inputVal = '';
+			this.active = false;
+			this.$emit('search', '');
+		},
+		getFocus() {
+			this.isFocus = true;
+		},
+		search() {
+			this.$emit('search', this.inputVal);
+		}
+	},
+	watch: {
+		inputVal(newVal) {
+			if (newVal) {
+				this.searchName = '搜索';
+				this.isDelShow = true;
+			} else {
+				this.searchName = '取消';
+				this.isDelShow = false;
+			}
+		}
+	}
+};
+</script>
+
+<style lang="scss" scoped>
+.search {
+	display: flex;
+	width: 100%;
+	// border-bottom: 1px #f5f5f5 solid;
+	box-sizing: border-box;
+	padding: 15upx;
+	font-size: $uni-font-size-base;
+	background: #fff;
+	.content {
+		display: flex;
+		align-items: center;
+		width: 100%;
+		height: 80upx;
+		border: 1px #ccc solid;
+		background: #fff;
+		overflow: hidden;
+		transition: all 0.2s linear;
+		border-radius: 30px;
+		background-color: #f0f0f0;
+		.content-box {
+			width: 100%;
+			display: flex;
+			align-items: center;
+			&.center {
+				justify-content: center;
+			}
+			.icon {
+				padding: 0 15upx;
+				&.icon-del {
+					font-size: 38upx;
+				}
+			}
+			.input {
+				width: 100%;
+				max-width: 100%;
+				line-height: 60upx;
+				height: 60upx;
+				transition: all 0.2s linear;
+				&.center {
+					width: 200upx;
+				}
+				&.sub {
+					// position: absolute;
+					width: auto;
+					color: grey;
+				}
+			}
+		}
+		.searchBtn {
+			height: 100%;
+			flex-shrink: 0;
+			padding: 0 30upx;
+			background: $uni-color-success;
+			line-height: 60upx;
+			color: #fff;
+			border-left: 1px #ccc solid;
+			transition: all 0.3s;
+		}
+	}
+
+	.button {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		position: relative;
+		flex-shrink: 0;
+		width: 0;
+		transition: all 0.2s linear;
+		white-space: nowrap;
+		overflow: hidden;
+		&.active {
+			padding-left: 15upx;
+			width: 100upx;
+		}
+	}
+}
+@font-face {
+	font-family: 'iconfont';
+	src: url('https://at.alicdn.com/t/font_989023_efq0mtli526.ttf') format('truetype');
+}
+.icon {
+	font-family: iconfont;
+	font-size: 32upx;
+	font-style: normal;
+	color: #999;
+}
+</style>

+ 139 - 0
components/pick-regions/pick-regions.vue

@@ -0,0 +1,139 @@
+<template>
+    <picker mode="multiSelector" 
+            :value="multiIndex" 
+            :range="multiArray" 
+            @change="handleValueChange"
+            @columnchange="handleColumnChange">
+        <slot></slot>
+    </picker>
+</template>
+
+<script>
+    const CHINA_REGIONS = require('./regions.json')
+	export default {
+        props:{
+            defaultRegions:{
+                type:Array,
+                default(){
+                    return []
+                }
+            },
+            defaultRegionCode:{
+                type:String
+            },
+            defaultRegion:[String,Array]
+        },
+		data() {
+			return {
+                cityArr:CHINA_REGIONS[0].childs,
+                districtArr:CHINA_REGIONS[0].childs[0].childs,
+                multiIndex: [0, 0, 0],
+                isInitMultiArray:true,
+			}
+		},
+        watch:{
+            defaultRegion:{
+                handler(region,oldRegion){
+                    console.log(region)
+                    console.log(oldRegion)
+                    if(Array.isArray(region)){
+                        // 避免传的是字面量的时候重复触发
+                        oldRegion = oldRegion || []
+                        if(region.join('')!==oldRegion.join('')){
+                            this.handleDefaultRegion(region)
+                        }
+                    }else if(region&&region.length == 6){
+                        this.handleDefaultRegion(region)
+                    }else{
+                        console.warn('defaultRegion非有效格式')
+                    }
+                },
+                immediate:true,
+            }
+        },
+        computed:{
+            multiArray(){
+                return this.pickedArr.map(arr=>arr.map(item=>item.name))
+            },
+            pickedArr(){
+                // 进行初始化
+                if(this.isInitMultiArray){
+                    return [
+                        CHINA_REGIONS,
+                        CHINA_REGIONS[0].childs,
+                        CHINA_REGIONS[0].childs[0].childs
+                    ]
+                }
+                return [CHINA_REGIONS,this.cityArr,this.districtArr];
+            }
+        },
+		methods: {
+            handleColumnChange(e){
+                // console.log(e);
+                this.isInitMultiArray = false;
+                const that = this;
+                let col = e.detail.column;
+                let row = e.detail.value;
+                that.multiIndex[col] = row;
+                try{
+                    switch(col){
+                        case 0:
+                            if(CHINA_REGIONS[that.multiIndex[0]].childs.length==0){
+                                that.cityArr = that.districtArr = [CHINA_REGIONS[that.multiIndex[0]]]
+                                break;
+                            }
+                            that.cityArr = CHINA_REGIONS[that.multiIndex[0]].childs
+                            that.districtArr = CHINA_REGIONS[that.multiIndex[0]].childs[that.multiIndex[1]].childs
+                            break;
+                        case 1:
+                            that.districtArr = CHINA_REGIONS[that.multiIndex[0]].childs[that.multiIndex[1]].childs
+                            break;
+                        case 2:
+                            break;
+                    }
+                }catch(e){
+                    // console.log(e);
+                    that.districtArr = CHINA_REGIONS[that.multiIndex[0]].childs[0].childs
+                }
+                
+            },
+            handleValueChange(e){
+                // 结构赋值
+                let [index0,index1,index2] = e.detail.value;
+                let [arr0,arr1,arr2] = this.pickedArr;
+                let address = [arr0[index0],arr1[index1],arr2[index2]];
+                // console.log(address);
+                this.$emit('getRegion',address)
+            },
+            handleDefaultRegion(region){
+                const isCode = !Array.isArray(region)
+                this.isInitMultiArray = false;
+                let children = CHINA_REGIONS
+                for(let i=0;i<3;i++){
+                    for(let j=0;j<children.length;j++){
+                       let condition = isCode?children[j].code==region.slice(0,(i+1)*2):children[j].name.includes(region[i]);
+                       if(condition){
+                           // 匹配成功进行赋值
+                           // console.log(i,j,children.length-1);
+                           children = children[j].childs;
+                           if(i==0){
+                               this.cityArr = children
+                           }else if(i==1){
+                               this.districtArr = children
+                           }
+                           this.$set(this.multiIndex,i,j)
+                           // console.log(this.multiIndex);
+                           break;
+                       }else{
+                           // 首次匹配失败就用默认的初始化
+                           // console.log(i,j,children.length-1);
+                           if(i==0 && j==(children.length-1)){
+                               this.isInitMultiArray = true;
+                           }
+                       }
+                    }
+                }
+            }
+		},
+	}
+</script>

Dosya farkı çok büyük olduğundan ihmal edildi
+ 0 - 0
components/pick-regions/regions.json


+ 360 - 0
components/serving-view/index.vue

@@ -0,0 +1,360 @@
+<template>
+    <view @touchstart="drag_start"
+          @touchmove.stop.prevent="moveStop"
+          @touchmove="drag_hmove" v-if="show">
+        <view class="ball" :class="typeClass"
+              :style="'left:'+setX+'px;top :'+setY+'px;'" @tap="toModel">
+        </view>
+        <uni-popup ref="popup" type="alert">
+            <view class="alert" v-if="onLine">
+                <view class="alert-list">
+                    <view class="alert-item" v-if="voiceModel == 0" @tap="voiceModelTap(1)">
+                        <view class="alert-item-model">扬声器播放</view>
+                    </view>
+                    <view class="alert-item" v-else @tap="voiceModelTap(0)">
+                        <view class="alert-item-model">听筒播放</view>
+                    </view>
+                    <view class="hr"></view>
+                    <view class="alert-item" @tap="xiaMai(list_id,0)">
+                        <view class="alert-item-model"> 下麦并关闭收听</view>
+                    </view>
+                    <view class="hr"></view>
+                    <view class="alert-item" @tap="xiaMai(list_id)">
+                        <view class="alert-item-model">下麦</view>
+                    </view>
+                </view>
+            </view>
+            <view class="alert" v-else>
+                <view class="alert-list">
+                    <view class="alert-item" v-if="voiceModel == 1" @tap="voiceModelTap(0)">
+                        <view class="alert-item-model">扬声器播放</view>
+                    </view>
+                    <view class="alert-item" v-else @tap="voiceModelTap(1)">
+                        <view class="alert-item-model">听筒播放</view>
+                    </view>
+                    <view class="hr"></view>
+                    <view class="alert-item" @tap="closeVoice">
+                        <view class="alert-item-model">关闭收听</view>
+                    </view>
+                </view>
+            </view>
+            <!--<uni-popup-alert title="温馨提示" :content="popuMsg" @confirm = "confirm"> </uni-popup-alert>-->
+        </uni-popup>
+    </view>
+
+</template>
+
+<script>
+    import _data from '../../common/_data';
+    import _get from '../../common/_get';
+    import SDK from '../../common/tendenceImSdk';
+    import uniPopup from '@/components/uni-popup/uni-popup.vue';
+
+    export default {
+        props: {
+            show: {
+                type: Boolean,
+                defualt: false
+            },
+            state:{
+                type: Number,
+                defualt: 3
+            },
+            list_id:{
+                type: String,
+                defualt: ""
+            }
+        },
+        data() {
+            return {
+                start: [0, 0],
+                voiceModel:0,
+                onLine:0
+            }
+        },
+        components:{
+            uniPopup,
+        },
+        computed:{
+            typeClass(){
+                switch (true) {
+                    case this.state == 1:
+                        return 'shangmai bgred';
+                    case this.state == 2:
+                        return 'shangmai-ing bgblue';
+                    case this.state == 3:
+                        return 'shouting bgblue';
+                    case this.state == 4:
+                        return 'jingyin bgblue';
+                    default:
+                        return 'shangmai bgred';
+                }
+          },
+            setX(){
+                return this.X;
+            },
+            setY(){
+                return this.Y;
+            },
+            setState(){
+                return this.state;
+            }
+        },
+        created() {
+            this.setInfo();
+            let _this = this;
+        },
+        methods: {
+            closeVoice(){
+                //关闭收听
+                let _this = this;
+                SDK.IMSDK.muteLocalAudio(0,function () {
+                    _this.setModel(4);
+                    _this.closeModel();
+                });
+            },
+            closeModel(){
+                if(this.$refs.popup){
+                    this.$refs.popup.close();
+                }
+            },
+            voiceModelTap(val){
+                let _this = this;
+                console.log("使用扬声器")
+                SDK.IMSDK.muteLocalAudio(1,function () { //开启声音
+                    SDK.IMSDK.setAudioRoute(val,function () {  //设置扬声器模式
+                        if(val == 0){
+                            uni.showToast({
+                                title:'使用扬声器播放',
+                                icon:'none'
+                            })
+                        }else {
+                            uni.showToast({
+                                title:'使用听筒播放',
+                                icon:'none'
+                            })
+                        }
+                        _this.closeModel();
+                        _this.voiceModel = val;
+                    })
+                });
+
+
+            },
+            xiaMai(list_id,mode = 1){
+                let _this = this;
+                console.log("下麦..........")
+                _get.setVoiceRoomMsg({list_id:list_id,type:0},function (num) {
+                    //判断有几个人在麦上,如果有且只有一个人则同时下麦,如果大于1人则设置为听筒模式]
+                    console.log(num)
+                    if(num == 0){
+                        _this.closeVoiceRoom()
+                    }else {
+                            if(mode == 1){
+                                //禁言 收听
+                                _this.jingyanShouTing() //禁言 关闭收听
+                            }else {
+                                _this.jinyanJingyin();
+                            }
+                    }
+                    _this.closeModel()
+                });
+
+            },
+            toModel(){
+               switch (true) {
+                   case this.state == 1:
+                       //如果是在上麦模式打开则打开弹窗提示操作
+                       this.onLine = 1;
+                       this.$refs.popup.open();
+                       return 'shangmai';
+                   case this.state == 2:
+                       //如果是正在上麦则切换图片
+                       return 'shangmai-ing';
+                   case this.state == 3:
+                       //切换到收听图片
+                       this.onLine = 0;
+                       this.$refs.popup.open();
+                       return 'shouting';
+                   case this.state == 4:
+                       //切换到禁音图片
+                       this.setModel(3);
+                       //设置扬声器模式
+                       this.voiceModelTap(0)
+                       return 'jingyin';
+                   default:
+                       return 'shangmai';
+               }
+            },
+            joinOnline(list_id,cb){
+                //开启语音聊天
+                let _this = this;
+                SDK.IMSDK.muteRemoteAudio(_data.localData('voice_room_userid'),1,function () {
+                    _this.setModel(1);//加入
+                    _this.onLine = 1; //在线上
+                    _data.localData('voice_room_type',1); //是否在麦
+                    _this.voiceModelTap(1)
+                    _get.setVoiceRoomMsg({list_id:list_id,type:1},function (ret) {
+                        if(cb)cb()
+                    });
+                });
+            },
+            setModel(state){
+              //设置模式
+               this.$emit('setState',{state:state})
+            },
+            joinRoom(list_id,cb){
+                let _this = this;
+                _get.joinVoiceRoom({list_id:list_id},function (ret) {
+                    SDK.IMSDK.joinRoom(ret,function (sdk_ret) {
+                    })
+                    _this.setModel(1);
+                    _data.localData('voice_room_userid',ret.userid);
+                    _data.localData('voice_room_type',1); //是否在麦]
+                    _this.voiceModelTap(1)
+                    _get.setVoiceRoomMsg({list_id:list_id,type:1},function () {
+                        if(cb)cb();
+                    });
+                })
+            },
+            closeVoiceRoom(){
+              //静默退出聊天室
+                this.setModel(-1)
+                this.$emit('closeServing',{});
+                _data.localData('voice_room_userid',null);
+                SDK.IMSDK.exitRoom(function () {
+                })
+            },
+            memberJoin(user_id,list_id,cb){
+                let _this = this;
+                _get.memberjoinVoiceRoom({list_id:list_id},function (ret) {
+                    SDK.IMSDK.joinRoom(ret,function (sdk_ret) {
+                    })
+                    _this.jinyanJingyin(cb)
+                    _data.localData('voice_room_userid',ret.userid);
+                    _data.localData('voice_room_type',0); //是否在麦
+                    _this.voiceModelTap(1)
+                })
+            },
+            jinyanJingyin(cb){  //禁言禁音
+                let _this = this;
+                SDK.IMSDK.muteRemoteAudio(_data.localData('voice_room_userid'),0,function () {
+                    _this.setModel(4);//加入之后直接禁言
+                    SDK.IMSDK.muteLocalAudio(0); //禁音
+                     if(cb)cb();
+                });
+            },
+            jingyanShouTing(cb){ //禁言收听
+                let _this = this;
+                SDK.IMSDK.muteRemoteAudio(_data.localData('voice_room_userid'),0,function () {
+                    _this.setModel(3);//加入之后直接禁言
+                    SDK.IMSDK.muteLocalAudio(1); //s收听
+                    if(cb)cb();
+                });
+            },
+            setInfo(){
+                let dragInfo = getApp().globalData['dragInfo']
+                this.X = dragInfo.moveX;
+                this.Y = dragInfo.moveY;
+            },
+            moveStop() {
+            },
+            drag_start(event) {
+                this.start[0] = event.touches[0].clientX - event.target.offsetLeft;
+                this.start[1] = event.touches[0].clientY - event.target.offsetTop;
+            },
+            setGlobleX(x){
+                this.X = x;
+                let dragInfo = getApp().globalData['dragInfo'];
+                dragInfo.moveX = x;
+                getApp().globalData['dragInfo'] = dragInfo;
+            },
+            setGlobleY(y){
+                this.Y = y;
+                let dragInfo = getApp().globalData['dragInfo'];
+                dragInfo.moveY = y;
+                getApp().globalData['dragInfo'] = dragInfo;
+            },
+            drag_hmove(event) {
+                let sysInfo = uni.getSystemInfoSync();
+                const maxWidth = sysInfo.windowWidth - 50;//屏幕宽度减去悬浮框宽高
+                const maxHeight = sysInfo.windowHeight;
+                let tag = event.touches;
+                if (tag[0].clientX <= 50) { //屏幕x限制
+                    this.setGlobleX(0);
+                } else if (tag[0].clientX > maxWidth) {
+                    this.setGlobleX(maxWidth);
+                } else {
+                    let x = tag[0].clientX - this.start[0];
+                    this.setGlobleX(x);
+                }
+                if (tag[0].clientY <= 25) { //屏幕y限制
+                    this.setGlobleY(0);
+                } else if (tag[0].clientY > maxHeight) {
+                    this.setGlobleY(maxHeight);
+                } else {
+                    let y = tag[0].clientY - this.start[1];
+                    this.setGlobleY(y);
+                }
+            }
+        }
+    }
+</script>
+
+<style lang="less">
+    .ball {
+        width: 50px;
+        height: 50px;
+        border-radius: 50%;
+        z-index: 10000;
+        top: 140px;
+        position: fixed;
+    }
+    .bgred{
+        background: red;
+    }
+    .bgblue{
+        background: #00b1f7;
+    }
+   .shangmai{
+       background-image: url("/static/theme/default/shangmai.png");
+       background-size:40px 40px;
+       background-repeat:no-repeat;
+       background-position:center;
+   }
+   .shouting{
+       background-image: url("/static/theme/default/laba.png");
+       background-size:30px 30px;
+       background-repeat:no-repeat;
+       background-position:center;
+   }
+    .jingyin{
+        background-image: url("/static/theme/default/jingyin.png");
+        background-size:20px 20px;
+        background-repeat:no-repeat;
+        background-position:center;
+    }
+    .alert{
+        width: 300px;
+        background-color: #fff;
+    }
+    .alert-list{
+        display: flex;
+        flex-direction: column;
+    }
+    .alert-item{
+        height: 50px;
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        padding-left: 20px;
+    }
+    .alert-item-model{
+    }
+    .hr{
+        height: 1upx;
+        width:95%;
+        margin: 0 auto;
+        background-color: #e1e1e1;
+    }
+</style>

+ 86 - 0
components/t-table/t-table.vue

@@ -0,0 +1,86 @@
+<template>
+	<view class="t-table" :style="{ 'border-width': border + 'px', 'border-color': borderColor }">
+		<slot />
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			border: {
+				type: String,
+				default: '1'
+			},
+			borderColor: {
+				type: String,
+				default: '#d0dee5'
+			},
+			isCheck: {
+				type: Boolean,
+				default: false
+			}
+		},
+		provide() {
+			return {
+				table: this
+			};
+		},
+		data() {
+			return {};
+		},
+		created() {
+			this.childrens = [];
+			this.index = 0;
+		},
+		methods: {
+			fire(e, index, len) {
+				let childrens = this.childrens;
+				console.log(childrens);
+				// 全选
+				if (index === 0) {
+					childrens.map((vm, index) => {
+						vm.checkboxData.checked = e;
+						return vm;
+					});
+				} else {
+					let isAll = childrens.find((n, ids) => ids !== 0 && !n.checkboxData.checked);
+					childrens[0].checkboxData.checked = isAll ? false : true;
+				}
+
+				let fireArr = [];
+				for (let i = 0; i < childrens.length; i++) {
+					if (childrens[i].checkboxData.checked && i !== 0) {
+						fireArr.push(childrens[i].checkboxData.value - 1);
+					}
+				}
+				this.$emit('change', {
+					detail: fireArr
+				});
+			}
+		}
+	};
+</script>
+
+<style scoped>
+	.t-table {
+		width: 100%;
+		border: 1px #d0dee5 solid;
+		border-left: none;
+		border-top: none;
+		box-sizing: border-box;
+	}
+
+	.t-table>>>t-tr {
+		display: flex;
+	}
+
+	.t-table>>>t-tr:nth-child(2n) {
+		background: #f5f5f5;
+	}
+
+	/* #ifdef H5 */
+	.t-table>>>.t-tr:nth-child(2n) {
+		background: #f5f5f5;
+	}
+	/* #endif */
+</style>

+ 71 - 0
components/t-table/t-td.vue

@@ -0,0 +1,71 @@
+<template>
+	<view class="t-td" :style="{ 'border-width': thBorder + 'px','border-color':borderColor ,'font-size':fontSize+'px' ,'color':color,'justify-content':tdAlignCpd}">
+		<slot></slot>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			align: String
+		},
+		data() {
+			return {
+				thBorder: '1',
+				borderColor: '#d0dee5',
+				fontSize: '14',
+				color: '#555c60',
+				tdAlign: 'center'
+			};
+		},
+		inject: ['table', 'tr'],
+
+		created() {
+			this.thBorder = this.table.border;
+			this.borderColor = this.table.borderColor;
+			this.fontSize = this.tr.fontSize;
+			this.color = this.tr.color;
+			if (this.align) {
+				this.tdAlign = this.align;
+			} else {
+				this.tdAlign = this.tr.align
+			}
+		},
+		computed: {
+			tdAlignCpd() {
+				let nameAlign = '';
+				switch (this.tdAlign) {
+					case 'left':
+						nameAlign = 'flex-start'
+						break;
+					case 'center':
+						nameAlign = 'center'
+						break;
+					case 'right':
+						nameAlign = 'flex-end'
+						break;
+					default:
+						nameAlign = 'center'
+						break;
+				}
+				return nameAlign
+			}
+		}
+	};
+</script>
+
+<style>
+	.t-td {
+		flex: 1;
+		display: flex;
+		align-items: center;
+		width: 100%;
+		padding: 14upx;
+		border-top: 1px #d0dee5 solid;
+		border-left: 1px #d0dee5 solid;
+		text-align: center;
+		color: #555c60;
+		font-size: 28upx;
+
+	}
+</style>

+ 71 - 0
components/t-table/t-th.vue

@@ -0,0 +1,71 @@
+<template>
+	<view class="t-th" :style="{ 'border-width': thBorder + 'px' ,'border-color':borderColor,'font-size':fontSize+'px' ,'color':color,'justify-content':thAlignCpd}">
+		<slot></slot>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			align: String,
+		},
+		data() {
+			return {
+				thBorder: '1',
+				borderColor: '#d0dee5',
+				fontSize: '15',
+				color: '#3b4246',
+				thAlign: 'center'
+			};
+		},
+		inject: ['table', 'tr'],
+
+		created() {
+			this.thBorder = this.table.border;
+			this.borderColor = this.table.borderColor;
+			this.fontSize = this.tr.fontSize;
+			this.color = this.tr.color;
+			if (this.align) {
+				this.thAlign = this.align;
+			} else {
+				this.thAlign = this.tr.align
+			}
+		},
+
+		computed: {
+			thAlignCpd() {
+				let nameAlign = '';
+				switch (this.thAlign) {
+					case 'left':
+						nameAlign = 'flex-start'
+						break;
+					case 'center':
+						nameAlign = 'center'
+						break;
+					case 'right':
+						nameAlign = 'flex-end'
+						break;
+					default:
+						nameAlign = 'center'
+						break;
+				}
+				return nameAlign
+			}
+		}
+	};
+</script>
+
+<style>
+	.t-th {
+		flex: 1;
+		display: flex;
+		align-items: center;
+		font-size: 30upx;
+		font-weight: bold;
+		text-align: center;
+		color: #3b4246;
+		border-left: 1px #d0dee5 solid;
+		border-top: 1px #d0dee5 solid;
+		padding: 15upx;
+	}
+</style>

+ 81 - 0
components/t-table/t-tr.vue

@@ -0,0 +1,81 @@
+<template>
+	<view class="t-tr">
+		<view v-if="isCheck" class="t-check-box" :style="{ 'border-width': thBorder + 'px' ,'border-color':borderColor}">
+			<checkbox-group @change="checkboxChange">
+				<checkbox :value="checkboxData.value + ''" :checked="checkboxData.checked" />
+			</checkbox-group>
+		</view>
+		<slot></slot>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			fontSize: String,
+			color: String,
+			align: String
+		},
+		inject: ['table'],
+		provide() {
+			return {
+				tr: this
+			};
+		},
+		data() {
+			return {
+				isCheck: false,
+				checkboxData: {
+					value: 0,
+					checked: false
+				},
+				checked: false,
+				thBorder: '1',
+				borderColor: '#d0dee5'
+			};
+		},
+		created() {
+			this.thBorder = this.table.border;
+			this.borderColor = this.table.borderColor;
+			this.table.childrens.push(this);
+			this.checkboxData.value = this.table.index++;
+			this.isCheck = this.table.isCheck;
+
+		},
+		methods: {
+			checkboxChange(e) {
+				this.checkboxData.checked = !this.checkboxData.checked;
+				this.table.childrens[this.checkboxData.value] = this;
+				this.table.fire(e.detail.value[0] ? true : false, this.checkboxData.value, this.table.index);
+			}
+		}
+	};
+</script>
+
+<style>
+	.t-tr {
+		width: 100%;
+		display: flex;
+	}
+
+	.t-tr t-th,
+	.t-tr t-td {
+		display: flex;
+		flex: 1;
+	}
+
+	.t-tr .t-check-box {
+		flex-shrink: 0;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		width: 80upx;
+		color: #3b4246;
+		border-left: 1px #d0dee5 solid;
+		border-top: 1px #d0dee5 solid;
+	}
+
+	.t-tr .t-check-box checkbox {
+		transform: scale(0.8);
+	}
+</style>

+ 96 - 0
components/textScroll/textScroll.vue

@@ -0,0 +1,96 @@
+<template>
+    <div class="tip">
+        <div class="inner" :class="{'move': scroll}" :style="styleName">
+            <text class="tip-inder">{{text}} {{scroll ? text : '' }}</text>
+        </div>
+    </div>
+</template>
+
+<script>
+    export default {
+        props: {
+            text: {
+                type: String,
+                defualt: ''
+            },
+        },
+        data() {
+            return {
+                styleName: "animation-duration: 6s",
+                scroll: false,
+                tipWidth: 0
+            };
+        },
+        watch: {
+            text: {
+                handler(val) {
+                    this.textScroll()
+                },
+                immediate: false
+            }
+        },
+        methods: {
+            textScroll() {
+                // 等待节点挂载后再执行,热门线路tip滚动实现
+                this.$nextTick(() => {
+                    console.log('滚动')
+                    let query = uni.createSelectorQuery().in(this)
+                    query.select('.tip').boundingClientRect(data => {
+                        this.tipWidth = data.width
+                        console.log('tip', this.tipWidth)
+                    }).exec();
+                    query.select('.tip-inder').boundingClientRect(data => {
+                        console.log('tip-inder', data.width)
+                        if(data.width > this.tipWidth) {
+                            let w = Number(data.width)
+                            let time = Math.round(w / 40)
+                            this.styleName = `animation-duration: ${time}s`
+                            this.scroll = true
+                        }
+                    }).exec();
+                })
+            }
+        }
+    };
+</script>
+
+<style lang="less">
+    .tip {
+        width: 100%;
+        background: transparent;
+        color: #4d82ff;
+        font-size: 28rpx;
+        height: 80rpx;
+        line-height: 80rpx;
+        overflow: hidden;
+        box-sizing: border-box;
+        white-space: nowrap;
+    }
+
+    .tip .inner {
+        overflow: hidden;
+        display: inline-block;
+    }
+
+    .tip .inner .tip-inder {
+        white-space: nowrap;
+    }
+
+    .tip .inner.move {
+        // animation: move 6s infinite linear;
+        animation-name: scroll;
+        animation-timing-function: linear;
+        animation-iteration-count: infinite;
+    }
+
+    @keyframes scroll {
+        0% {
+            transform: translateX(0);
+        }
+
+        100% {
+            transform: translateX(-50%);
+        }
+    }
+</style>
+

+ 190 - 0
components/tki-barcode/barcode.js

@@ -0,0 +1,190 @@
+const barcodes = require('./barcodes/index.js')['default'];
+let barcode = {};
+(function () {
+    // 初始化
+    barcode = function (cont, ctxid, options, ctxsize, result) {
+        let ops = {}, newOptions, encodings, globaContext, ctx, globaCtxid, cbCanvasSize, cbResult;
+        globaCtxid = ctxid
+        cbCanvasSize = ctxsize
+        cbResult = result
+        newOptions = Object.assign(ops, options);
+        // 修成margin
+        fixMargin(newOptions)
+        // 处理options 数据
+        if (newOptions.text == '' || cont == '') {
+            return false
+        }
+        // 获取ctx
+        globaContext = cont
+        ctx = uni.createCanvasContext(globaCtxid, globaContext)
+        // 获取编码数据
+        encodings = new barcodes[newOptions.format.toUpperCase()](newOptions.text, newOptions).encode()
+        let fixencodings = fixEncodings(encodings, newOptions)
+        // 返回canvas实际大小
+        cbCanvasSize({ width: fixencodings.width, height: fixencodings.height })
+        // 绘制canvas
+        setTimeout(() => {
+            drawCanvas.render(newOptions, fixencodings)
+        }, 50);
+        // 绘制canvas
+        let drawCanvas = {
+            render(options, encoding) {
+                this.prepare(options, encoding)
+                encoding.encodings.forEach((v, i) => {
+                    this.barcode(options, v)
+                    this.text(options, v)
+                    this.move(v)
+                });
+                this.draw(options, encoding)
+            },
+            barcode(options, encoding) {
+                let binary = encoding.data;
+                let yFrom;
+                if (options.textPosition == "top") {
+                    yFrom = options.marginTop + options.fontSize + options.textMargin;
+                } else {
+                    yFrom = options.marginTop;
+                }
+                // 绘制条码
+                ctx.fillStyle = options.lineColor;
+                for (let b = 0; b < binary.length; b++) {
+                    let x = b * options.width + encoding.barcodePadding;
+                    let height = options.height
+                    if (encoding.options) {
+                        if (encoding.options.height != undefined) {
+                            height = encoding.options.height
+                        }
+                    }
+                    if (binary[b] === "1") {
+                        ctx.fillRect(x, yFrom, options.width, height);
+                    } else if (binary[b]) {
+                        ctx.fillRect(x, yFrom, options.width, height * binary[b]);
+                    }
+                }
+            },
+            text(options, encoding) {
+                if (options.displayValue) {
+                    let x, y, align, size;
+                    if (options.textPosition == "top") {
+                        y = options.marginTop + options.fontSize;
+                    } else {
+                        y = options.height + options.textMargin + options.marginTop + options.fontSize;
+                    }
+                    if (encoding.options) {
+                        if (encoding.options.textAlign != undefined) {
+                            align = encoding.options.textAlign
+                        }
+                        if (encoding.options.fontSize != undefined) {
+                            size = encoding.options.fontSize
+                        }
+                    } else {
+                        align = options.textAlign
+                        size = options.fontSize
+                    }
+                    ctx.setFontSize(size)
+                    if (align == "left" || encoding.barcodePadding > 0) {
+                        x = 0;
+                        ctx.setTextAlign('left')
+                    } else if (align == "right") {
+                        x = encoding.width - 1;
+                        ctx.setTextAlign('right')
+                    }
+                    else {
+                        x = encoding.width / 2;
+                        ctx.setTextAlign('center');
+                    }
+                    ctx.fillStyle = options.fontColor;
+                    if (encoding.text != undefined) {
+                        ctx.fillText(encoding.text, x, y);
+                    }
+                }
+            },
+            move(encoding) {
+                ctx.translate(encoding.width, 0);
+            },
+            prepare(options, encoding) {
+                // 绘制背景
+                if (options.background) {
+                    ctx.fillStyle = options.background;
+                    ctx.fillRect(0, 0, encoding.width, encoding.height);
+                }
+                ctx.translate(options.marginLeft, 0);
+            },
+            draw(options, encoding) {
+                ctx.draw(false, () => {
+                    this.toImgs(options, encoding)
+                })
+            },
+            toImgs(options, encoding) {
+                setTimeout(() => {
+                    uni.canvasToTempFilePath({
+                        width: encoding.width,
+                        height: encoding.height,
+                        destWidth: encoding.width,
+                        destHeight: encoding.height,
+                        canvasId: globaCtxid,
+                        fileType: 'png',
+                        success: function (res) {
+                            cbResult(res.tempFilePath)
+                        },
+                        fail: function (res) {
+                            cbResult(res)
+                        },
+                        complete: function () {
+                            uni.hideLoading();
+                        },
+                    }, globaContext);
+                }, options.text.length + 100);
+            }
+        }
+        // 混入canvas数据
+        function fixEncodings(encoding, options) {
+            let encodingArr = [], width = options.marginLeft + options.marginRight, height;
+            if (!Array.isArray(encoding)) {
+                encodingArr[0] = JSON.parse(JSON.stringify(encoding))
+            } else {
+                encodingArr = [...encoding]
+            }
+            encodingArr.forEach((v, i) => {
+                // 获取文本宽度
+                let textWidth = ctx.measureText(encodingArr[i].text ? encodingArr[i].text : '').width;
+                // 获取条形码宽度
+                let barcodeWidth = encodingArr[i].data.length * options.width;
+                // 获取内边距
+                let barcodePadding = 0;
+                if (options.displayValue && barcodeWidth < textWidth) {
+                    if (options.textAlign == "center") {
+                        barcodePadding = Math.floor((textWidth - barcodeWidth) / 2);
+                    } else if (options.textAlign == "left") {
+                        barcodePadding = 0;
+                    } else if (options.textAlign == "right") {
+                        barcodePadding = Math.floor(textWidth - barcodeWidth);
+                    }
+                }
+                // 混入encodingArr[i]
+                encodingArr[i].barcodePadding = barcodePadding
+                encodingArr[i].width = Math.ceil(Math.max(textWidth, barcodeWidth))
+                width += encodingArr[i].width
+                if (encodingArr[i].options) {
+                    if (encodingArr[i].options.height != undefined) {
+                        encodingArr[i].height = encodingArr[i].options.height + (options.displayValue && (encodingArr[i].text ? encodingArr[i].text : '').length > 0 ? options.fontSize + options.textMargin : 0) + options.marginTop + options.marginBottom;
+                    } else {
+                        encodingArr[i].height = height = options.height + (options.displayValue && (encodingArr[i].text ? encodingArr[i].text : '').length > 0 ? options.fontSize + options.textMargin : 0) + options.marginTop + options.marginBottom;
+                    }
+                } else {
+                    encodingArr[i].height = height = options.height + (options.displayValue && (encodingArr[i].text ? encodingArr[i].text : '').length > 0 ? options.fontSize + options.textMargin : 0) + options.marginTop + options.marginBottom;
+                }
+            });
+            return { encodings: encodingArr, width, height };
+        }
+        // 修正Margin
+        function fixMargin(options) {
+            options.marginTop = options.marginTop == undefined ? options.margin : options.marginTop;
+            options.marginBottom = options.marginBottom == undefined ? options.margin : options.marginBottom;
+            options.marginRight = options.marginRight == undefined ? options.margin : options.marginRight;
+            options.marginLeft = options.marginLeft == undefined ? options.margin : options.marginLeft;
+        }
+    };
+})()
+
+export default barcode

+ 17 - 0
components/tki-barcode/barcodes/Barcode.js

@@ -0,0 +1,17 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+var Barcode = function Barcode(data, options) {
+	_classCallCheck(this, Barcode);
+
+	this.data = data;
+	this.text = options.text || data;
+	this.options = options;
+};
+
+exports.default = Barcode;

+ 167 - 0
components/tki-barcode/barcodes/CODE128/CODE128.js

@@ -0,0 +1,167 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _Barcode2 = require('../Barcode.js');
+
+var _Barcode3 = _interopRequireDefault(_Barcode2);
+
+var _constants = require('./constants');
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+// This is the master class,
+// it does require the start code to be included in the string
+var CODE128 = function (_Barcode) {
+	_inherits(CODE128, _Barcode);
+
+	function CODE128(data, options) {
+		_classCallCheck(this, CODE128);
+
+		// Get array of ascii codes from data
+		var _this = _possibleConstructorReturn(this, (CODE128.__proto__ || Object.getPrototypeOf(CODE128)).call(this, data.substring(1), options));
+
+		_this.bytes = data.split('').map(function (char) {
+			return char.charCodeAt(0);
+		});
+		return _this;
+	}
+
+	_createClass(CODE128, [{
+		key: 'valid',
+		value: function valid() {
+			// ASCII value ranges 0-127, 200-211
+			return (/^[\x00-\x7F\xC8-\xD3]+$/.test(this.data)
+			);
+		}
+
+		// The public encoding function
+
+	}, {
+		key: 'encode',
+		value: function encode() {
+			var bytes = this.bytes;
+			// Remove the start code from the bytes and set its index
+			var startIndex = bytes.shift() - 105;
+			// Get start set by index
+			var startSet = _constants.SET_BY_CODE[startIndex];
+
+			if (startSet === undefined) {
+				throw new RangeError('The encoding does not start with a start character.');
+			}
+
+			if (this.shouldEncodeAsEan128() === true) {
+				bytes.unshift(_constants.FNC1);
+			}
+
+			// Start encode with the right type
+			var encodingResult = CODE128.next(bytes, 1, startSet);
+
+			return {
+				text: this.text === this.data ? this.text.replace(/[^\x20-\x7E]/g, '') : this.text,
+				data:
+				// Add the start bits
+				CODE128.getBar(startIndex) +
+				// Add the encoded bits
+				encodingResult.result +
+				// Add the checksum
+				CODE128.getBar((encodingResult.checksum + startIndex) % _constants.MODULO) +
+				// Add the end bits
+				CODE128.getBar(_constants.STOP)
+			};
+		}
+
+		// GS1-128/EAN-128
+
+	}, {
+		key: 'shouldEncodeAsEan128',
+		value: function shouldEncodeAsEan128() {
+			var isEAN128 = this.options.ean128 || false;
+			if (typeof isEAN128 === 'string') {
+				isEAN128 = isEAN128.toLowerCase() === 'true';
+			}
+			return isEAN128;
+		}
+
+		// Get a bar symbol by index
+
+	}], [{
+		key: 'getBar',
+		value: function getBar(index) {
+			return _constants.BARS[index] ? _constants.BARS[index].toString() : '';
+		}
+
+		// Correct an index by a set and shift it from the bytes array
+
+	}, {
+		key: 'correctIndex',
+		value: function correctIndex(bytes, set) {
+			if (set === _constants.SET_A) {
+				var charCode = bytes.shift();
+				return charCode < 32 ? charCode + 64 : charCode - 32;
+			} else if (set === _constants.SET_B) {
+				return bytes.shift() - 32;
+			} else {
+				return (bytes.shift() - 48) * 10 + bytes.shift() - 48;
+			}
+		}
+	}, {
+		key: 'next',
+		value: function next(bytes, pos, set) {
+			if (!bytes.length) {
+				return { result: '', checksum: 0 };
+			}
+
+			var nextCode = void 0,
+			    index = void 0;
+
+			// Special characters
+			if (bytes[0] >= 200) {
+				index = bytes.shift() - 105;
+				var nextSet = _constants.SWAP[index];
+
+				// Swap to other set
+				if (nextSet !== undefined) {
+					nextCode = CODE128.next(bytes, pos + 1, nextSet);
+				}
+				// Continue on current set but encode a special character
+				else {
+						// Shift
+						if ((set === _constants.SET_A || set === _constants.SET_B) && index === _constants.SHIFT) {
+							// Convert the next character so that is encoded correctly
+							bytes[0] = set === _constants.SET_A ? bytes[0] > 95 ? bytes[0] - 96 : bytes[0] : bytes[0] < 32 ? bytes[0] + 96 : bytes[0];
+						}
+						nextCode = CODE128.next(bytes, pos + 1, set);
+					}
+			}
+			// Continue encoding
+			else {
+					index = CODE128.correctIndex(bytes, set);
+					nextCode = CODE128.next(bytes, pos + 1, set);
+				}
+
+			// Get the correct binary encoding and calculate the weight
+			var enc = CODE128.getBar(index);
+			var weight = index * pos;
+
+			return {
+				result: enc + nextCode.result,
+				checksum: weight + nextCode.checksum
+			};
+		}
+	}]);
+
+	return CODE128;
+}(_Barcode3.default);
+
+exports.default = CODE128;

+ 42 - 0
components/tki-barcode/barcodes/CODE128/CODE128A.js

@@ -0,0 +1,42 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _CODE2 = require('./CODE128.js');
+
+var _CODE3 = _interopRequireDefault(_CODE2);
+
+var _constants = require('./constants');
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var CODE128A = function (_CODE) {
+	_inherits(CODE128A, _CODE);
+
+	function CODE128A(string, options) {
+		_classCallCheck(this, CODE128A);
+
+		return _possibleConstructorReturn(this, (CODE128A.__proto__ || Object.getPrototypeOf(CODE128A)).call(this, _constants.A_START_CHAR + string, options));
+	}
+
+	_createClass(CODE128A, [{
+		key: 'valid',
+		value: function valid() {
+			return new RegExp('^' + _constants.A_CHARS + '+$').test(this.data);
+		}
+	}]);
+
+	return CODE128A;
+}(_CODE3.default);
+
+exports.default = CODE128A;

+ 42 - 0
components/tki-barcode/barcodes/CODE128/CODE128B.js

@@ -0,0 +1,42 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _CODE2 = require('./CODE128.js');
+
+var _CODE3 = _interopRequireDefault(_CODE2);
+
+var _constants = require('./constants');
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var CODE128B = function (_CODE) {
+	_inherits(CODE128B, _CODE);
+
+	function CODE128B(string, options) {
+		_classCallCheck(this, CODE128B);
+
+		return _possibleConstructorReturn(this, (CODE128B.__proto__ || Object.getPrototypeOf(CODE128B)).call(this, _constants.B_START_CHAR + string, options));
+	}
+
+	_createClass(CODE128B, [{
+		key: 'valid',
+		value: function valid() {
+			return new RegExp('^' + _constants.B_CHARS + '+$').test(this.data);
+		}
+	}]);
+
+	return CODE128B;
+}(_CODE3.default);
+
+exports.default = CODE128B;

+ 42 - 0
components/tki-barcode/barcodes/CODE128/CODE128C.js

@@ -0,0 +1,42 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _CODE2 = require('./CODE128.js');
+
+var _CODE3 = _interopRequireDefault(_CODE2);
+
+var _constants = require('./constants');
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var CODE128C = function (_CODE) {
+	_inherits(CODE128C, _CODE);
+
+	function CODE128C(string, options) {
+		_classCallCheck(this, CODE128C);
+
+		return _possibleConstructorReturn(this, (CODE128C.__proto__ || Object.getPrototypeOf(CODE128C)).call(this, _constants.C_START_CHAR + string, options));
+	}
+
+	_createClass(CODE128C, [{
+		key: 'valid',
+		value: function valid() {
+			return new RegExp('^' + _constants.C_CHARS + '+$').test(this.data);
+		}
+	}]);
+
+	return CODE128C;
+}(_CODE3.default);
+
+exports.default = CODE128C;

+ 41 - 0
components/tki-barcode/barcodes/CODE128/CODE128_AUTO.js

@@ -0,0 +1,41 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _CODE2 = require('./CODE128');
+
+var _CODE3 = _interopRequireDefault(_CODE2);
+
+var _auto = require('./auto');
+
+var _auto2 = _interopRequireDefault(_auto);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var CODE128AUTO = function (_CODE) {
+	_inherits(CODE128AUTO, _CODE);
+
+	function CODE128AUTO(data, options) {
+		_classCallCheck(this, CODE128AUTO);
+
+		// ASCII value ranges 0-127, 200-211
+		if (/^[\x00-\x7F\xC8-\xD3]+$/.test(data)) {
+			var _this = _possibleConstructorReturn(this, (CODE128AUTO.__proto__ || Object.getPrototypeOf(CODE128AUTO)).call(this, (0, _auto2.default)(data), options));
+		} else {
+			var _this = _possibleConstructorReturn(this, (CODE128AUTO.__proto__ || Object.getPrototypeOf(CODE128AUTO)).call(this, data, options));
+		}
+		return _possibleConstructorReturn(_this);
+	}
+
+	return CODE128AUTO;
+}(_CODE3.default);
+
+exports.default = CODE128AUTO;

+ 73 - 0
components/tki-barcode/barcodes/CODE128/auto.js

@@ -0,0 +1,73 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _constants = require('./constants');
+
+// Match Set functions
+var matchSetALength = function matchSetALength(string) {
+	return string.match(new RegExp('^' + _constants.A_CHARS + '*'))[0].length;
+};
+var matchSetBLength = function matchSetBLength(string) {
+	return string.match(new RegExp('^' + _constants.B_CHARS + '*'))[0].length;
+};
+var matchSetC = function matchSetC(string) {
+	return string.match(new RegExp('^' + _constants.C_CHARS + '*'))[0];
+};
+
+// CODE128A or CODE128B
+function autoSelectFromAB(string, isA) {
+	var ranges = isA ? _constants.A_CHARS : _constants.B_CHARS;
+	var untilC = string.match(new RegExp('^(' + ranges + '+?)(([0-9]{2}){2,})([^0-9]|$)'));
+
+	if (untilC) {
+		return untilC[1] + String.fromCharCode(204) + autoSelectFromC(string.substring(untilC[1].length));
+	}
+
+	var chars = string.match(new RegExp('^' + ranges + '+'))[0];
+
+	if (chars.length === string.length) {
+		return string;
+	}
+
+	return chars + String.fromCharCode(isA ? 205 : 206) + autoSelectFromAB(string.substring(chars.length), !isA);
+}
+
+// CODE128C
+function autoSelectFromC(string) {
+	var cMatch = matchSetC(string);
+	var length = cMatch.length;
+
+	if (length === string.length) {
+		return string;
+	}
+
+	string = string.substring(length);
+
+	// Select A/B depending on the longest match
+	var isA = matchSetALength(string) >= matchSetBLength(string);
+	return cMatch + String.fromCharCode(isA ? 206 : 205) + autoSelectFromAB(string, isA);
+}
+
+// Detect Code Set (A, B or C) and format the string
+
+exports.default = function (string) {
+	var newString = void 0;
+	var cLength = matchSetC(string).length;
+
+	// Select 128C if the string start with enough digits
+	if (cLength >= 2) {
+		newString = _constants.C_START_CHAR + autoSelectFromC(string);
+	} else {
+		// Select A/B depending on the longest match
+		var isA = matchSetALength(string) > matchSetBLength(string);
+		newString = (isA ? _constants.A_START_CHAR : _constants.B_START_CHAR) + autoSelectFromAB(string, isA);
+	}
+
+	return newString.replace(/[\xCD\xCE]([^])[\xCD\xCE]/, // Any sequence between 205 and 206 characters
+	function (match, char) {
+		return String.fromCharCode(203) + char;
+	});
+};

+ 54 - 0
components/tki-barcode/barcodes/CODE128/constants.js

@@ -0,0 +1,54 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _SET_BY_CODE;
+
+function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
+
+// constants for internal usage
+var SET_A = exports.SET_A = 0;
+var SET_B = exports.SET_B = 1;
+var SET_C = exports.SET_C = 2;
+
+// Special characters
+var SHIFT = exports.SHIFT = 98;
+var START_A = exports.START_A = 103;
+var START_B = exports.START_B = 104;
+var START_C = exports.START_C = 105;
+var MODULO = exports.MODULO = 103;
+var STOP = exports.STOP = 106;
+var FNC1 = exports.FNC1 = 207;
+
+// Get set by start code
+var SET_BY_CODE = exports.SET_BY_CODE = (_SET_BY_CODE = {}, _defineProperty(_SET_BY_CODE, START_A, SET_A), _defineProperty(_SET_BY_CODE, START_B, SET_B), _defineProperty(_SET_BY_CODE, START_C, SET_C), _SET_BY_CODE);
+
+// Get next set by code
+var SWAP = exports.SWAP = {
+	101: SET_A,
+	100: SET_B,
+	99: SET_C
+};
+
+var A_START_CHAR = exports.A_START_CHAR = String.fromCharCode(208); // START_A + 105
+var B_START_CHAR = exports.B_START_CHAR = String.fromCharCode(209); // START_B + 105
+var C_START_CHAR = exports.C_START_CHAR = String.fromCharCode(210); // START_C + 105
+
+// 128A (Code Set A)
+// ASCII characters 00 to 95 (0–9, A–Z and control codes), special characters, and FNC 1–4
+var A_CHARS = exports.A_CHARS = "[\x00-\x5F\xC8-\xCF]";
+
+// 128B (Code Set B)
+// ASCII characters 32 to 127 (0–9, A–Z, a–z), special characters, and FNC 1–4
+var B_CHARS = exports.B_CHARS = "[\x20-\x7F\xC8-\xCF]";
+
+// 128C (Code Set C)
+// 00–99 (encodes two digits with a single code point) and FNC1
+var C_CHARS = exports.C_CHARS = "(\xCF*[0-9]{2}\xCF*)";
+
+// CODE128 includes 107 symbols:
+// 103 data symbols, 3 start symbols (A, B and C), and 1 stop symbol (the last one)
+// Each symbol consist of three black bars (1) and three white spaces (0).
+var BARS = exports.BARS = [11011001100, 11001101100, 11001100110, 10010011000, 10010001100, 10001001100, 10011001000, 10011000100, 10001100100, 11001001000, 11001000100, 11000100100, 10110011100, 10011011100, 10011001110, 10111001100, 10011101100, 10011100110, 11001110010, 11001011100, 11001001110, 11011100100, 11001110100, 11101101110, 11101001100, 11100101100, 11100100110, 11101100100, 11100110100, 11100110010, 11011011000, 11011000110, 11000110110, 10100011000, 10001011000, 10001000110, 10110001000, 10001101000, 10001100010, 11010001000, 11000101000, 11000100010, 10110111000, 10110001110, 10001101110, 10111011000, 10111000110, 10001110110, 11101110110, 11010001110, 11000101110, 11011101000, 11011100010, 11011101110, 11101011000, 11101000110, 11100010110, 11101101000, 11101100010, 11100011010, 11101111010, 11001000010, 11110001010, 10100110000, 10100001100, 10010110000, 10010000110, 10000101100, 10000100110, 10110010000, 10110000100, 10011010000, 10011000010, 10000110100, 10000110010, 11000010010, 11001010000, 11110111010, 11000010100, 10001111010, 10100111100, 10010111100, 10010011110, 10111100100, 10011110100, 10011110010, 11110100100, 11110010100, 11110010010, 11011011110, 11011110110, 11110110110, 10101111000, 10100011110, 10001011110, 10111101000, 10111100010, 11110101000, 11110100010, 10111011110, 10111101110, 11101011110, 11110101110, 11010000100, 11010010000, 11010011100, 1100011101011];

+ 29 - 0
components/tki-barcode/barcodes/CODE128/index.js

@@ -0,0 +1,29 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.CODE128C = exports.CODE128B = exports.CODE128A = exports.CODE128 = undefined;
+
+var _CODE128_AUTO = require('./CODE128_AUTO.js');
+
+var _CODE128_AUTO2 = _interopRequireDefault(_CODE128_AUTO);
+
+var _CODE128A = require('./CODE128A.js');
+
+var _CODE128A2 = _interopRequireDefault(_CODE128A);
+
+var _CODE128B = require('./CODE128B.js');
+
+var _CODE128B2 = _interopRequireDefault(_CODE128B);
+
+var _CODE128C = require('./CODE128C.js');
+
+var _CODE128C2 = _interopRequireDefault(_CODE128C);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.CODE128 = _CODE128_AUTO2.default;
+exports.CODE128A = _CODE128A2.default;
+exports.CODE128B = _CODE128B2.default;
+exports.CODE128C = _CODE128C2.default;

+ 104 - 0
components/tki-barcode/barcodes/CODE39/index.js

@@ -0,0 +1,104 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+exports.CODE39 = undefined;
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _Barcode2 = require("../Barcode.js");
+
+var _Barcode3 = _interopRequireDefault(_Barcode2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Encoding documentation:
+// https://en.wikipedia.org/wiki/Code_39#Encoding
+
+var CODE39 = function (_Barcode) {
+	_inherits(CODE39, _Barcode);
+
+	function CODE39(data, options) {
+		_classCallCheck(this, CODE39);
+
+		data = data.toUpperCase();
+
+		// Calculate mod43 checksum if enabled
+		if (options.mod43) {
+			data += getCharacter(mod43checksum(data));
+		}
+
+		return _possibleConstructorReturn(this, (CODE39.__proto__ || Object.getPrototypeOf(CODE39)).call(this, data, options));
+	}
+
+	_createClass(CODE39, [{
+		key: "encode",
+		value: function encode() {
+			// First character is always a *
+			var result = getEncoding("*");
+
+			// Take every character and add the binary representation to the result
+			for (var i = 0; i < this.data.length; i++) {
+				result += getEncoding(this.data[i]) + "0";
+			}
+
+			// Last character is always a *
+			result += getEncoding("*");
+			return {
+				data: result,
+				text: this.text
+			};
+		}
+	}, {
+		key: "valid",
+		value: function valid() {
+			return this.data.search(/^[0-9A-Z\-\.\ \$\/\+\%]+$/) !== -1;
+		}
+	}]);
+
+	return CODE39;
+}(_Barcode3.default);
+
+// All characters. The position in the array is the (checksum) value
+
+
+var characters = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "-", ".", " ", "$", "/", "+", "%", "*"];
+
+// The decimal representation of the characters, is converted to the
+// corresponding binary with the getEncoding function
+var encodings = [20957, 29783, 23639, 30485, 20951, 29813, 23669, 20855, 29789, 23645, 29975, 23831, 30533, 22295, 30149, 24005, 21623, 29981, 23837, 22301, 30023, 23879, 30545, 22343, 30161, 24017, 21959, 30065, 23921, 22385, 29015, 18263, 29141, 17879, 29045, 18293, 17783, 29021, 18269, 17477, 17489, 17681, 20753, 35770];
+
+// Get the binary representation of a character by converting the encodings
+// from decimal to binary
+function getEncoding(character) {
+	return getBinary(characterValue(character));
+}
+
+function getBinary(characterValue) {
+	return encodings[characterValue].toString(2);
+}
+
+function getCharacter(characterValue) {
+	return characters[characterValue];
+}
+
+function characterValue(character) {
+	return characters.indexOf(character);
+}
+
+function mod43checksum(data) {
+	var checksum = 0;
+	for (var i = 0; i < data.length; i++) {
+		checksum += characterValue(data[i]);
+	}
+
+	checksum = checksum % 43;
+	return checksum;
+}
+
+exports.CODE39 = CODE39;

+ 92 - 0
components/tki-barcode/barcodes/EAN_UPC/EAN.js

@@ -0,0 +1,92 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _constants = require('./constants');
+
+var _encoder = require('./encoder');
+
+var _encoder2 = _interopRequireDefault(_encoder);
+
+var _Barcode2 = require('../Barcode');
+
+var _Barcode3 = _interopRequireDefault(_Barcode2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+// Base class for EAN8 & EAN13
+var EAN = function (_Barcode) {
+	_inherits(EAN, _Barcode);
+
+	function EAN(data, options) {
+		_classCallCheck(this, EAN);
+
+		// Make sure the font is not bigger than the space between the guard bars
+		var _this = _possibleConstructorReturn(this, (EAN.__proto__ || Object.getPrototypeOf(EAN)).call(this, data, options));
+
+		_this.fontSize = !options.flat && options.fontSize > options.width * 10 ? options.width * 10 : options.fontSize;
+
+		// Make the guard bars go down half the way of the text
+		_this.guardHeight = options.height + _this.fontSize / 2 + options.textMargin;
+		return _this;
+	}
+
+	_createClass(EAN, [{
+		key: 'encode',
+		value: function encode() {
+			return this.options.flat ? this.encodeFlat() : this.encodeGuarded();
+		}
+	}, {
+		key: 'leftText',
+		value: function leftText(from, to) {
+			return this.text.substr(from, to);
+		}
+	}, {
+		key: 'leftEncode',
+		value: function leftEncode(data, structure) {
+			return (0, _encoder2.default)(data, structure);
+		}
+	}, {
+		key: 'rightText',
+		value: function rightText(from, to) {
+			return this.text.substr(from, to);
+		}
+	}, {
+		key: 'rightEncode',
+		value: function rightEncode(data, structure) {
+			return (0, _encoder2.default)(data, structure);
+		}
+	}, {
+		key: 'encodeGuarded',
+		value: function encodeGuarded() {
+			var textOptions = { fontSize: this.fontSize };
+			var guardOptions = { height: this.guardHeight };
+
+			return [{ data: _constants.SIDE_BIN, options: guardOptions }, { data: this.leftEncode(), text: this.leftText(), options: textOptions }, { data: _constants.MIDDLE_BIN, options: guardOptions }, { data: this.rightEncode(), text: this.rightText(), options: textOptions }, { data: _constants.SIDE_BIN, options: guardOptions }];
+		}
+	}, {
+		key: 'encodeFlat',
+		value: function encodeFlat() {
+			var data = [_constants.SIDE_BIN, this.leftEncode(), _constants.MIDDLE_BIN, this.rightEncode(), _constants.SIDE_BIN];
+
+			return {
+				data: data.join(''),
+				text: this.text
+			};
+		}
+	}]);
+
+	return EAN;
+}(_Barcode3.default);
+
+exports.default = EAN;

+ 119 - 0
components/tki-barcode/barcodes/EAN_UPC/EAN13.js

@@ -0,0 +1,119 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
+
+var _constants = require('./constants');
+
+var _EAN2 = require('./EAN');
+
+var _EAN3 = _interopRequireDefault(_EAN2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Encoding documentation:
+// https://en.wikipedia.org/wiki/International_Article_Number_(EAN)#Binary_encoding_of_data_digits_into_EAN-13_barcode
+
+// Calculate the checksum digit
+// https://en.wikipedia.org/wiki/International_Article_Number_(EAN)#Calculation_of_checksum_digit
+var checksum = function checksum(number) {
+	var res = number.substr(0, 12).split('').map(function (n) {
+		return +n;
+	}).reduce(function (sum, a, idx) {
+		return idx % 2 ? sum + a * 3 : sum + a;
+	}, 0);
+
+	return (10 - res % 10) % 10;
+};
+
+var EAN13 = function (_EAN) {
+	_inherits(EAN13, _EAN);
+
+	function EAN13(data, options) {
+		_classCallCheck(this, EAN13);
+
+		// Add checksum if it does not exist
+		if (data.search(/^[0-9]{12}$/) !== -1) {
+			data += checksum(data);
+		}
+
+		// Adds a last character to the end of the barcode
+		var _this = _possibleConstructorReturn(this, (EAN13.__proto__ || Object.getPrototypeOf(EAN13)).call(this, data, options));
+
+		_this.lastChar = options.lastChar;
+		return _this;
+	}
+
+	_createClass(EAN13, [{
+		key: 'valid',
+		value: function valid() {
+			return this.data.search(/^[0-9]{13}$/) !== -1 && +this.data[12] === checksum(this.data);
+		}
+	}, {
+		key: 'leftText',
+		value: function leftText() {
+			return _get(EAN13.prototype.__proto__ || Object.getPrototypeOf(EAN13.prototype), 'leftText', this).call(this, 1, 6);
+		}
+	}, {
+		key: 'leftEncode',
+		value: function leftEncode() {
+			var data = this.data.substr(1, 6);
+			var structure = _constants.EAN13_STRUCTURE[this.data[0]];
+			return _get(EAN13.prototype.__proto__ || Object.getPrototypeOf(EAN13.prototype), 'leftEncode', this).call(this, data, structure);
+		}
+	}, {
+		key: 'rightText',
+		value: function rightText() {
+			return _get(EAN13.prototype.__proto__ || Object.getPrototypeOf(EAN13.prototype), 'rightText', this).call(this, 7, 6);
+		}
+	}, {
+		key: 'rightEncode',
+		value: function rightEncode() {
+			var data = this.data.substr(7, 6);
+			return _get(EAN13.prototype.__proto__ || Object.getPrototypeOf(EAN13.prototype), 'rightEncode', this).call(this, data, 'RRRRRR');
+		}
+
+		// The "standard" way of printing EAN13 barcodes with guard bars
+
+	}, {
+		key: 'encodeGuarded',
+		value: function encodeGuarded() {
+			var data = _get(EAN13.prototype.__proto__ || Object.getPrototypeOf(EAN13.prototype), 'encodeGuarded', this).call(this);
+
+			// Extend data with left digit & last character
+			if (this.options.displayValue) {
+				data.unshift({
+					data: '000000000000',
+					text: this.text.substr(0, 1),
+					options: { textAlign: 'left', fontSize: this.fontSize }
+				});
+
+				if (this.options.lastChar) {
+					data.push({
+						data: '00'
+					});
+					data.push({
+						data: '00000',
+						text: this.options.lastChar,
+						options: { fontSize: this.fontSize }
+					});
+				}
+			}
+
+			return data;
+		}
+	}]);
+
+	return EAN13;
+}(_EAN3.default);
+
+exports.default = EAN13;

+ 58 - 0
components/tki-barcode/barcodes/EAN_UPC/EAN2.js

@@ -0,0 +1,58 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _constants = require('./constants');
+
+var _encoder = require('./encoder');
+
+var _encoder2 = _interopRequireDefault(_encoder);
+
+var _Barcode2 = require('../Barcode');
+
+var _Barcode3 = _interopRequireDefault(_Barcode2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Encoding documentation:
+// https://en.wikipedia.org/wiki/EAN_2#Encoding
+
+var EAN2 = function (_Barcode) {
+	_inherits(EAN2, _Barcode);
+
+	function EAN2(data, options) {
+		_classCallCheck(this, EAN2);
+
+		return _possibleConstructorReturn(this, (EAN2.__proto__ || Object.getPrototypeOf(EAN2)).call(this, data, options));
+	}
+
+	_createClass(EAN2, [{
+		key: 'valid',
+		value: function valid() {
+			return this.data.search(/^[0-9]{2}$/) !== -1;
+		}
+	}, {
+		key: 'encode',
+		value: function encode() {
+			// Choose the structure based on the number mod 4
+			var structure = _constants.EAN2_STRUCTURE[parseInt(this.data) % 4];
+			return {
+				// Start bits + Encode the two digits with 01 in between
+				data: '1011' + (0, _encoder2.default)(this.data, structure, '01'),
+				text: this.text
+			};
+		}
+	}]);
+
+	return EAN2;
+}(_Barcode3.default);
+
+exports.default = EAN2;

+ 65 - 0
components/tki-barcode/barcodes/EAN_UPC/EAN5.js

@@ -0,0 +1,65 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _constants = require('./constants');
+
+var _encoder = require('./encoder');
+
+var _encoder2 = _interopRequireDefault(_encoder);
+
+var _Barcode2 = require('../Barcode');
+
+var _Barcode3 = _interopRequireDefault(_Barcode2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Encoding documentation:
+// https://en.wikipedia.org/wiki/EAN_5#Encoding
+
+var checksum = function checksum(data) {
+	var result = data.split('').map(function (n) {
+		return +n;
+	}).reduce(function (sum, a, idx) {
+		return idx % 2 ? sum + a * 9 : sum + a * 3;
+	}, 0);
+	return result % 10;
+};
+
+var EAN5 = function (_Barcode) {
+	_inherits(EAN5, _Barcode);
+
+	function EAN5(data, options) {
+		_classCallCheck(this, EAN5);
+
+		return _possibleConstructorReturn(this, (EAN5.__proto__ || Object.getPrototypeOf(EAN5)).call(this, data, options));
+	}
+
+	_createClass(EAN5, [{
+		key: 'valid',
+		value: function valid() {
+			return this.data.search(/^[0-9]{5}$/) !== -1;
+		}
+	}, {
+		key: 'encode',
+		value: function encode() {
+			var structure = _constants.EAN5_STRUCTURE[checksum(this.data)];
+			return {
+				data: '1011' + (0, _encoder2.default)(this.data, structure, '01'),
+				text: this.text
+			};
+		}
+	}]);
+
+	return EAN5;
+}(_Barcode3.default);
+
+exports.default = EAN5;

+ 81 - 0
components/tki-barcode/barcodes/EAN_UPC/EAN8.js

@@ -0,0 +1,81 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };
+
+var _EAN2 = require('./EAN');
+
+var _EAN3 = _interopRequireDefault(_EAN2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Encoding documentation:
+// http://www.barcodeisland.com/ean8.phtml
+
+// Calculate the checksum digit
+var checksum = function checksum(number) {
+	var res = number.substr(0, 7).split('').map(function (n) {
+		return +n;
+	}).reduce(function (sum, a, idx) {
+		return idx % 2 ? sum + a : sum + a * 3;
+	}, 0);
+
+	return (10 - res % 10) % 10;
+};
+
+var EAN8 = function (_EAN) {
+	_inherits(EAN8, _EAN);
+
+	function EAN8(data, options) {
+		_classCallCheck(this, EAN8);
+
+		// Add checksum if it does not exist
+		if (data.search(/^[0-9]{7}$/) !== -1) {
+			data += checksum(data);
+		}
+
+		return _possibleConstructorReturn(this, (EAN8.__proto__ || Object.getPrototypeOf(EAN8)).call(this, data, options));
+	}
+
+	_createClass(EAN8, [{
+		key: 'valid',
+		value: function valid() {
+			return this.data.search(/^[0-9]{8}$/) !== -1 && +this.data[7] === checksum(this.data);
+		}
+	}, {
+		key: 'leftText',
+		value: function leftText() {
+			return _get(EAN8.prototype.__proto__ || Object.getPrototypeOf(EAN8.prototype), 'leftText', this).call(this, 0, 4);
+		}
+	}, {
+		key: 'leftEncode',
+		value: function leftEncode() {
+			var data = this.data.substr(0, 4);
+			return _get(EAN8.prototype.__proto__ || Object.getPrototypeOf(EAN8.prototype), 'leftEncode', this).call(this, data, 'LLLL');
+		}
+	}, {
+		key: 'rightText',
+		value: function rightText() {
+			return _get(EAN8.prototype.__proto__ || Object.getPrototypeOf(EAN8.prototype), 'rightText', this).call(this, 4, 4);
+		}
+	}, {
+		key: 'rightEncode',
+		value: function rightEncode() {
+			var data = this.data.substr(4, 4);
+			return _get(EAN8.prototype.__proto__ || Object.getPrototypeOf(EAN8.prototype), 'rightEncode', this).call(this, data, 'RRRR');
+		}
+	}]);
+
+	return EAN8;
+}(_EAN3.default);
+
+exports.default = EAN8;

+ 165 - 0
components/tki-barcode/barcodes/EAN_UPC/UPC.js

@@ -0,0 +1,165 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+exports.checksum = checksum;
+
+var _encoder = require("./encoder");
+
+var _encoder2 = _interopRequireDefault(_encoder);
+
+var _Barcode2 = require("../Barcode.js");
+
+var _Barcode3 = _interopRequireDefault(_Barcode2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Encoding documentation:
+// https://en.wikipedia.org/wiki/Universal_Product_Code#Encoding
+
+var UPC = function (_Barcode) {
+	_inherits(UPC, _Barcode);
+
+	function UPC(data, options) {
+		_classCallCheck(this, UPC);
+
+		// Add checksum if it does not exist
+		if (data.search(/^[0-9]{11}$/) !== -1) {
+			data += checksum(data);
+		}
+
+		var _this = _possibleConstructorReturn(this, (UPC.__proto__ || Object.getPrototypeOf(UPC)).call(this, data, options));
+
+		_this.displayValue = options.displayValue;
+
+		// Make sure the font is not bigger than the space between the guard bars
+		if (options.fontSize > options.width * 10) {
+			_this.fontSize = options.width * 10;
+		} else {
+			_this.fontSize = options.fontSize;
+		}
+
+		// Make the guard bars go down half the way of the text
+		_this.guardHeight = options.height + _this.fontSize / 2 + options.textMargin;
+		return _this;
+	}
+
+	_createClass(UPC, [{
+		key: "valid",
+		value: function valid() {
+			return this.data.search(/^[0-9]{12}$/) !== -1 && this.data[11] == checksum(this.data);
+		}
+	}, {
+		key: "encode",
+		value: function encode() {
+			if (this.options.flat) {
+				return this.flatEncoding();
+			} else {
+				return this.guardedEncoding();
+			}
+		}
+	}, {
+		key: "flatEncoding",
+		value: function flatEncoding() {
+			var result = "";
+
+			result += "101";
+			result += (0, _encoder2.default)(this.data.substr(0, 6), "LLLLLL");
+			result += "01010";
+			result += (0, _encoder2.default)(this.data.substr(6, 6), "RRRRRR");
+			result += "101";
+
+			return {
+				data: result,
+				text: this.text
+			};
+		}
+	}, {
+		key: "guardedEncoding",
+		value: function guardedEncoding() {
+			var result = [];
+
+			// Add the first digit
+			if (this.displayValue) {
+				result.push({
+					data: "00000000",
+					text: this.text.substr(0, 1),
+					options: { textAlign: "left", fontSize: this.fontSize }
+				});
+			}
+
+			// Add the guard bars
+			result.push({
+				data: "101" + (0, _encoder2.default)(this.data[0], "L"),
+				options: { height: this.guardHeight }
+			});
+
+			// Add the left side
+			result.push({
+				data: (0, _encoder2.default)(this.data.substr(1, 5), "LLLLL"),
+				text: this.text.substr(1, 5),
+				options: { fontSize: this.fontSize }
+			});
+
+			// Add the middle bits
+			result.push({
+				data: "01010",
+				options: { height: this.guardHeight }
+			});
+
+			// Add the right side
+			result.push({
+				data: (0, _encoder2.default)(this.data.substr(6, 5), "RRRRR"),
+				text: this.text.substr(6, 5),
+				options: { fontSize: this.fontSize }
+			});
+
+			// Add the end bits
+			result.push({
+				data: (0, _encoder2.default)(this.data[11], "R") + "101",
+				options: { height: this.guardHeight }
+			});
+
+			// Add the last digit
+			if (this.displayValue) {
+				result.push({
+					data: "00000000",
+					text: this.text.substr(11, 1),
+					options: { textAlign: "right", fontSize: this.fontSize }
+				});
+			}
+
+			return result;
+		}
+	}]);
+
+	return UPC;
+}(_Barcode3.default);
+
+// Calulate the checksum digit
+// https://en.wikipedia.org/wiki/International_Article_Number_(EAN)#Calculation_of_checksum_digit
+
+
+function checksum(number) {
+	var result = 0;
+
+	var i;
+	for (i = 1; i < 11; i += 2) {
+		result += parseInt(number[i]);
+	}
+	for (i = 0; i < 11; i += 2) {
+		result += parseInt(number[i]) * 3;
+	}
+
+	return (10 - result % 10) % 10;
+}
+
+exports.default = UPC;

+ 185 - 0
components/tki-barcode/barcodes/EAN_UPC/UPCE.js

@@ -0,0 +1,185 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _encoder = require('./encoder');
+
+var _encoder2 = _interopRequireDefault(_encoder);
+
+var _Barcode2 = require('../Barcode.js');
+
+var _Barcode3 = _interopRequireDefault(_Barcode2);
+
+var _UPC = require('./UPC.js');
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Encoding documentation:
+// https://en.wikipedia.org/wiki/Universal_Product_Code#Encoding
+//
+// UPC-E documentation:
+// https://en.wikipedia.org/wiki/Universal_Product_Code#UPC-E
+
+var EXPANSIONS = ["XX00000XXX", "XX10000XXX", "XX20000XXX", "XXX00000XX", "XXXX00000X", "XXXXX00005", "XXXXX00006", "XXXXX00007", "XXXXX00008", "XXXXX00009"];
+
+var PARITIES = [["EEEOOO", "OOOEEE"], ["EEOEOO", "OOEOEE"], ["EEOOEO", "OOEEOE"], ["EEOOOE", "OOEEEO"], ["EOEEOO", "OEOOEE"], ["EOOEEO", "OEEOOE"], ["EOOOEE", "OEEEOO"], ["EOEOEO", "OEOEOE"], ["EOEOOE", "OEOEEO"], ["EOOEOE", "OEEOEO"]];
+
+var UPCE = function (_Barcode) {
+	_inherits(UPCE, _Barcode);
+
+	function UPCE(data, options) {
+		_classCallCheck(this, UPCE);
+
+		var _this = _possibleConstructorReturn(this, (UPCE.__proto__ || Object.getPrototypeOf(UPCE)).call(this, data, options));
+		// Code may be 6 or 8 digits;
+		// A 7 digit code is ambiguous as to whether the extra digit
+		// is a UPC-A check or number system digit.
+
+
+		_this.isValid = false;
+		if (data.search(/^[0-9]{6}$/) !== -1) {
+			_this.middleDigits = data;
+			_this.upcA = expandToUPCA(data, "0");
+			_this.text = options.text || '' + _this.upcA[0] + data + _this.upcA[_this.upcA.length - 1];
+			_this.isValid = true;
+		} else if (data.search(/^[01][0-9]{7}$/) !== -1) {
+			_this.middleDigits = data.substring(1, data.length - 1);
+			_this.upcA = expandToUPCA(_this.middleDigits, data[0]);
+
+			if (_this.upcA[_this.upcA.length - 1] === data[data.length - 1]) {
+				_this.isValid = true;
+			} else {
+				// checksum mismatch
+				return _possibleConstructorReturn(_this);
+			}
+		} else {
+			return _possibleConstructorReturn(_this);
+		}
+
+		_this.displayValue = options.displayValue;
+
+		// Make sure the font is not bigger than the space between the guard bars
+		if (options.fontSize > options.width * 10) {
+			_this.fontSize = options.width * 10;
+		} else {
+			_this.fontSize = options.fontSize;
+		}
+
+		// Make the guard bars go down half the way of the text
+		_this.guardHeight = options.height + _this.fontSize / 2 + options.textMargin;
+		return _this;
+	}
+
+	_createClass(UPCE, [{
+		key: 'valid',
+		value: function valid() {
+			return this.isValid;
+		}
+	}, {
+		key: 'encode',
+		value: function encode() {
+			if (this.options.flat) {
+				return this.flatEncoding();
+			} else {
+				return this.guardedEncoding();
+			}
+		}
+	}, {
+		key: 'flatEncoding',
+		value: function flatEncoding() {
+			var result = "";
+
+			result += "101";
+			result += this.encodeMiddleDigits();
+			result += "010101";
+
+			return {
+				data: result,
+				text: this.text
+			};
+		}
+	}, {
+		key: 'guardedEncoding',
+		value: function guardedEncoding() {
+			var result = [];
+
+			// Add the UPC-A number system digit beneath the quiet zone
+			if (this.displayValue) {
+				result.push({
+					data: "00000000",
+					text: this.text[0],
+					options: { textAlign: "left", fontSize: this.fontSize }
+				});
+			}
+
+			// Add the guard bars
+			result.push({
+				data: "101",
+				options: { height: this.guardHeight }
+			});
+
+			// Add the 6 UPC-E digits
+			result.push({
+				data: this.encodeMiddleDigits(),
+				text: this.text.substring(1, 7),
+				options: { fontSize: this.fontSize }
+			});
+
+			// Add the end bits
+			result.push({
+				data: "010101",
+				options: { height: this.guardHeight }
+			});
+
+			// Add the UPC-A check digit beneath the quiet zone
+			if (this.displayValue) {
+				result.push({
+					data: "00000000",
+					text: this.text[7],
+					options: { textAlign: "right", fontSize: this.fontSize }
+				});
+			}
+
+			return result;
+		}
+	}, {
+		key: 'encodeMiddleDigits',
+		value: function encodeMiddleDigits() {
+			var numberSystem = this.upcA[0];
+			var checkDigit = this.upcA[this.upcA.length - 1];
+			var parity = PARITIES[parseInt(checkDigit)][parseInt(numberSystem)];
+			return (0, _encoder2.default)(this.middleDigits, parity);
+		}
+	}]);
+
+	return UPCE;
+}(_Barcode3.default);
+
+function expandToUPCA(middleDigits, numberSystem) {
+	var lastUpcE = parseInt(middleDigits[middleDigits.length - 1]);
+	var expansion = EXPANSIONS[lastUpcE];
+
+	var result = "";
+	var digitIndex = 0;
+	for (var i = 0; i < expansion.length; i++) {
+		var c = expansion[i];
+		if (c === 'X') {
+			result += middleDigits[digitIndex++];
+		} else {
+			result += c;
+		}
+	}
+
+	result = '' + numberSystem + result;
+	return '' + result + (0, _UPC.checksum)(result);
+}
+
+exports.default = UPCE;

+ 30 - 0
components/tki-barcode/barcodes/EAN_UPC/constants.js

@@ -0,0 +1,30 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+// Standard start end and middle bits
+var SIDE_BIN = exports.SIDE_BIN = '101';
+var MIDDLE_BIN = exports.MIDDLE_BIN = '01010';
+
+var BINARIES = exports.BINARIES = {
+	'L': [// The L (left) type of encoding
+	'0001101', '0011001', '0010011', '0111101', '0100011', '0110001', '0101111', '0111011', '0110111', '0001011'],
+	'G': [// The G type of encoding
+	'0100111', '0110011', '0011011', '0100001', '0011101', '0111001', '0000101', '0010001', '0001001', '0010111'],
+	'R': [// The R (right) type of encoding
+	'1110010', '1100110', '1101100', '1000010', '1011100', '1001110', '1010000', '1000100', '1001000', '1110100'],
+	'O': [// The O (odd) encoding for UPC-E
+	'0001101', '0011001', '0010011', '0111101', '0100011', '0110001', '0101111', '0111011', '0110111', '0001011'],
+	'E': [// The E (even) encoding for UPC-E
+	'0100111', '0110011', '0011011', '0100001', '0011101', '0111001', '0000101', '0010001', '0001001', '0010111']
+};
+
+// Define the EAN-2 structure
+var EAN2_STRUCTURE = exports.EAN2_STRUCTURE = ['LL', 'LG', 'GL', 'GG'];
+
+// Define the EAN-5 structure
+var EAN5_STRUCTURE = exports.EAN5_STRUCTURE = ['GGLLL', 'GLGLL', 'GLLGL', 'GLLLG', 'LGGLL', 'LLGGL', 'LLLGG', 'LGLGL', 'LGLLG', 'LLGLG'];
+
+// Define the EAN-13 structure
+var EAN13_STRUCTURE = exports.EAN13_STRUCTURE = ['LLLLLL', 'LLGLGG', 'LLGGLG', 'LLGGGL', 'LGLLGG', 'LGGLLG', 'LGGGLL', 'LGLGLG', 'LGLGGL', 'LGGLGL'];

+ 27 - 0
components/tki-barcode/barcodes/EAN_UPC/encoder.js

@@ -0,0 +1,27 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _constants = require('./constants');
+
+// Encode data string
+var encode = function encode(data, structure, separator) {
+	var encoded = data.split('').map(function (val, idx) {
+		return _constants.BINARIES[structure[idx]];
+	}).map(function (val, idx) {
+		return val ? val[data[idx]] : '';
+	});
+
+	if (separator) {
+		var last = data.length - 1;
+		encoded = encoded.map(function (val, idx) {
+			return idx < last ? val + separator : val;
+		});
+	}
+
+	return encoded.join('');
+};
+
+exports.default = encode;

+ 39 - 0
components/tki-barcode/barcodes/EAN_UPC/index.js

@@ -0,0 +1,39 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.UPCE = exports.UPC = exports.EAN2 = exports.EAN5 = exports.EAN8 = exports.EAN13 = undefined;
+
+var _EAN = require('./EAN13.js');
+
+var _EAN2 = _interopRequireDefault(_EAN);
+
+var _EAN3 = require('./EAN8.js');
+
+var _EAN4 = _interopRequireDefault(_EAN3);
+
+var _EAN5 = require('./EAN5.js');
+
+var _EAN6 = _interopRequireDefault(_EAN5);
+
+var _EAN7 = require('./EAN2.js');
+
+var _EAN8 = _interopRequireDefault(_EAN7);
+
+var _UPC = require('./UPC.js');
+
+var _UPC2 = _interopRequireDefault(_UPC);
+
+var _UPCE = require('./UPCE.js');
+
+var _UPCE2 = _interopRequireDefault(_UPCE);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.EAN13 = _EAN2.default;
+exports.EAN8 = _EAN4.default;
+exports.EAN5 = _EAN6.default;
+exports.EAN2 = _EAN8.default;
+exports.UPC = _UPC2.default;
+exports.UPCE = _UPCE2.default;

+ 55 - 0
components/tki-barcode/barcodes/GenericBarcode/index.js

@@ -0,0 +1,55 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+exports.GenericBarcode = undefined;
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _Barcode2 = require("../Barcode.js");
+
+var _Barcode3 = _interopRequireDefault(_Barcode2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var GenericBarcode = function (_Barcode) {
+	_inherits(GenericBarcode, _Barcode);
+
+	function GenericBarcode(data, options) {
+		_classCallCheck(this, GenericBarcode);
+
+		return _possibleConstructorReturn(this, (GenericBarcode.__proto__ || Object.getPrototypeOf(GenericBarcode)).call(this, data, options)); // Sets this.data and this.text
+	}
+
+	// Return the corresponding binary numbers for the data provided
+
+
+	_createClass(GenericBarcode, [{
+		key: "encode",
+		value: function encode() {
+			return {
+				data: "10101010101010101010101010101010101010101",
+				text: this.text
+			};
+		}
+
+		// Resturn true/false if the string provided is valid for this encoder
+
+	}, {
+		key: "valid",
+		value: function valid() {
+			return true;
+		}
+	}]);
+
+	return GenericBarcode;
+}(_Barcode3.default);
+
+exports.GenericBarcode = GenericBarcode;

+ 69 - 0
components/tki-barcode/barcodes/ITF/ITF.js

@@ -0,0 +1,69 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _constants = require('./constants');
+
+var _Barcode2 = require('../Barcode');
+
+var _Barcode3 = _interopRequireDefault(_Barcode2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var ITF = function (_Barcode) {
+	_inherits(ITF, _Barcode);
+
+	function ITF() {
+		_classCallCheck(this, ITF);
+
+		return _possibleConstructorReturn(this, (ITF.__proto__ || Object.getPrototypeOf(ITF)).apply(this, arguments));
+	}
+
+	_createClass(ITF, [{
+		key: 'valid',
+		value: function valid() {
+			return this.data.search(/^([0-9]{2})+$/) !== -1;
+		}
+	}, {
+		key: 'encode',
+		value: function encode() {
+			var _this2 = this;
+
+			// Calculate all the digit pairs
+			var encoded = this.data.match(/.{2}/g).map(function (pair) {
+				return _this2.encodePair(pair);
+			}).join('');
+
+			return {
+				data: _constants.START_BIN + encoded + _constants.END_BIN,
+				text: this.text
+			};
+		}
+
+		// Calculate the data of a number pair
+
+	}, {
+		key: 'encodePair',
+		value: function encodePair(pair) {
+			var second = _constants.BINARIES[pair[1]];
+
+			return _constants.BINARIES[pair[0]].split('').map(function (first, idx) {
+				return (first === '1' ? '111' : '1') + (second[idx] === '1' ? '000' : '0');
+			}).join('');
+		}
+	}]);
+
+	return ITF;
+}(_Barcode3.default);
+
+exports.default = ITF;

+ 55 - 0
components/tki-barcode/barcodes/ITF/ITF14.js

@@ -0,0 +1,55 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _ITF2 = require('./ITF');
+
+var _ITF3 = _interopRequireDefault(_ITF2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+// Calculate the checksum digit
+var checksum = function checksum(data) {
+	var res = data.substr(0, 13).split('').map(function (num) {
+		return parseInt(num, 10);
+	}).reduce(function (sum, n, idx) {
+		return sum + n * (3 - idx % 2 * 2);
+	}, 0);
+
+	return Math.ceil(res / 10) * 10 - res;
+};
+
+var ITF14 = function (_ITF) {
+	_inherits(ITF14, _ITF);
+
+	function ITF14(data, options) {
+		_classCallCheck(this, ITF14);
+
+		// Add checksum if it does not exist
+		if (data.search(/^[0-9]{13}$/) !== -1) {
+			data += checksum(data);
+		}
+		return _possibleConstructorReturn(this, (ITF14.__proto__ || Object.getPrototypeOf(ITF14)).call(this, data, options));
+	}
+
+	_createClass(ITF14, [{
+		key: 'valid',
+		value: function valid() {
+			return this.data.search(/^[0-9]{14}$/) !== -1 && +this.data[13] === checksum(this.data);
+		}
+	}]);
+
+	return ITF14;
+}(_ITF3.default);
+
+exports.default = ITF14;

+ 9 - 0
components/tki-barcode/barcodes/ITF/constants.js

@@ -0,0 +1,9 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+var START_BIN = exports.START_BIN = '1010';
+var END_BIN = exports.END_BIN = '11101';
+
+var BINARIES = exports.BINARIES = ['00110', '10001', '01001', '11000', '00101', '10100', '01100', '00011', '10010', '01010'];

+ 19 - 0
components/tki-barcode/barcodes/ITF/index.js

@@ -0,0 +1,19 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.ITF14 = exports.ITF = undefined;
+
+var _ITF = require('./ITF');
+
+var _ITF2 = _interopRequireDefault(_ITF);
+
+var _ITF3 = require('./ITF14');
+
+var _ITF4 = _interopRequireDefault(_ITF3);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.ITF = _ITF2.default;
+exports.ITF14 = _ITF4.default;

+ 74 - 0
components/tki-barcode/barcodes/MSI/MSI.js

@@ -0,0 +1,74 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _Barcode2 = require("../Barcode.js");
+
+var _Barcode3 = _interopRequireDefault(_Barcode2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Encoding documentation
+// https://en.wikipedia.org/wiki/MSI_Barcode#Character_set_and_binary_lookup
+
+var MSI = function (_Barcode) {
+	_inherits(MSI, _Barcode);
+
+	function MSI(data, options) {
+		_classCallCheck(this, MSI);
+
+		return _possibleConstructorReturn(this, (MSI.__proto__ || Object.getPrototypeOf(MSI)).call(this, data, options));
+	}
+
+	_createClass(MSI, [{
+		key: "encode",
+		value: function encode() {
+			// Start bits
+			var ret = "110";
+
+			for (var i = 0; i < this.data.length; i++) {
+				// Convert the character to binary (always 4 binary digits)
+				var digit = parseInt(this.data[i]);
+				var bin = digit.toString(2);
+				bin = addZeroes(bin, 4 - bin.length);
+
+				// Add 100 for every zero and 110 for every 1
+				for (var b = 0; b < bin.length; b++) {
+					ret += bin[b] == "0" ? "100" : "110";
+				}
+			}
+
+			// End bits
+			ret += "1001";
+
+			return {
+				data: ret,
+				text: this.text
+			};
+		}
+	}, {
+		key: "valid",
+		value: function valid() {
+			return this.data.search(/^[0-9]+$/) !== -1;
+		}
+	}]);
+
+	return MSI;
+}(_Barcode3.default);
+
+function addZeroes(number, n) {
+	for (var i = 0; i < n; i++) {
+		number = "0" + number;
+	}
+	return number;
+}
+
+exports.default = MSI;

+ 33 - 0
components/tki-barcode/barcodes/MSI/MSI10.js

@@ -0,0 +1,33 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _MSI2 = require('./MSI.js');
+
+var _MSI3 = _interopRequireDefault(_MSI2);
+
+var _checksums = require('./checksums.js');
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var MSI10 = function (_MSI) {
+	_inherits(MSI10, _MSI);
+
+	function MSI10(data, options) {
+		_classCallCheck(this, MSI10);
+
+		return _possibleConstructorReturn(this, (MSI10.__proto__ || Object.getPrototypeOf(MSI10)).call(this, data + (0, _checksums.mod10)(data), options));
+	}
+
+	return MSI10;
+}(_MSI3.default);
+
+exports.default = MSI10;

+ 35 - 0
components/tki-barcode/barcodes/MSI/MSI1010.js

@@ -0,0 +1,35 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _MSI2 = require('./MSI.js');
+
+var _MSI3 = _interopRequireDefault(_MSI2);
+
+var _checksums = require('./checksums.js');
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var MSI1010 = function (_MSI) {
+	_inherits(MSI1010, _MSI);
+
+	function MSI1010(data, options) {
+		_classCallCheck(this, MSI1010);
+
+		data += (0, _checksums.mod10)(data);
+		data += (0, _checksums.mod10)(data);
+		return _possibleConstructorReturn(this, (MSI1010.__proto__ || Object.getPrototypeOf(MSI1010)).call(this, data, options));
+	}
+
+	return MSI1010;
+}(_MSI3.default);
+
+exports.default = MSI1010;

+ 33 - 0
components/tki-barcode/barcodes/MSI/MSI11.js

@@ -0,0 +1,33 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _MSI2 = require('./MSI.js');
+
+var _MSI3 = _interopRequireDefault(_MSI2);
+
+var _checksums = require('./checksums.js');
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var MSI11 = function (_MSI) {
+	_inherits(MSI11, _MSI);
+
+	function MSI11(data, options) {
+		_classCallCheck(this, MSI11);
+
+		return _possibleConstructorReturn(this, (MSI11.__proto__ || Object.getPrototypeOf(MSI11)).call(this, data + (0, _checksums.mod11)(data), options));
+	}
+
+	return MSI11;
+}(_MSI3.default);
+
+exports.default = MSI11;

+ 35 - 0
components/tki-barcode/barcodes/MSI/MSI1110.js

@@ -0,0 +1,35 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _MSI2 = require('./MSI.js');
+
+var _MSI3 = _interopRequireDefault(_MSI2);
+
+var _checksums = require('./checksums.js');
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
+
+var MSI1110 = function (_MSI) {
+	_inherits(MSI1110, _MSI);
+
+	function MSI1110(data, options) {
+		_classCallCheck(this, MSI1110);
+
+		data += (0, _checksums.mod11)(data);
+		data += (0, _checksums.mod10)(data);
+		return _possibleConstructorReturn(this, (MSI1110.__proto__ || Object.getPrototypeOf(MSI1110)).call(this, data, options));
+	}
+
+	return MSI1110;
+}(_MSI3.default);
+
+exports.default = MSI1110;

+ 29 - 0
components/tki-barcode/barcodes/MSI/checksums.js

@@ -0,0 +1,29 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+exports.mod10 = mod10;
+exports.mod11 = mod11;
+function mod10(number) {
+	var sum = 0;
+	for (var i = 0; i < number.length; i++) {
+		var n = parseInt(number[i]);
+		if ((i + number.length) % 2 === 0) {
+			sum += n;
+		} else {
+			sum += n * 2 % 10 + Math.floor(n * 2 / 10);
+		}
+	}
+	return (10 - sum % 10) % 10;
+}
+
+function mod11(number) {
+	var sum = 0;
+	var weights = [2, 3, 4, 5, 6, 7];
+	for (var i = 0; i < number.length; i++) {
+		var n = parseInt(number[number.length - 1 - i]);
+		sum += weights[i % weights.length] * n;
+	}
+	return (11 - sum % 11) % 11;
+}

+ 34 - 0
components/tki-barcode/barcodes/MSI/index.js

@@ -0,0 +1,34 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+  value: true
+});
+exports.MSI1110 = exports.MSI1010 = exports.MSI11 = exports.MSI10 = exports.MSI = undefined;
+
+var _MSI = require('./MSI.js');
+
+var _MSI2 = _interopRequireDefault(_MSI);
+
+var _MSI3 = require('./MSI10.js');
+
+var _MSI4 = _interopRequireDefault(_MSI3);
+
+var _MSI5 = require('./MSI11.js');
+
+var _MSI6 = _interopRequireDefault(_MSI5);
+
+var _MSI7 = require('./MSI1010.js');
+
+var _MSI8 = _interopRequireDefault(_MSI7);
+
+var _MSI9 = require('./MSI1110.js');
+
+var _MSI10 = _interopRequireDefault(_MSI9);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+exports.MSI = _MSI2.default;
+exports.MSI10 = _MSI4.default;
+exports.MSI11 = _MSI6.default;
+exports.MSI1010 = _MSI8.default;
+exports.MSI1110 = _MSI10.default;

+ 92 - 0
components/tki-barcode/barcodes/codabar/index.js

@@ -0,0 +1,92 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+exports.codabar = undefined;
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _Barcode2 = require("../Barcode.js");
+
+var _Barcode3 = _interopRequireDefault(_Barcode2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Encoding specification:
+// http://www.barcodeisland.com/codabar.phtml
+
+var codabar = function (_Barcode) {
+	_inherits(codabar, _Barcode);
+
+	function codabar(data, options) {
+		_classCallCheck(this, codabar);
+
+		if (data.search(/^[0-9\-\$\:\.\+\/]+$/) === 0) {
+			data = "A" + data + "A";
+		}
+
+		var _this = _possibleConstructorReturn(this, (codabar.__proto__ || Object.getPrototypeOf(codabar)).call(this, data.toUpperCase(), options));
+
+		_this.text = _this.options.text || _this.text.replace(/[A-D]/g, '');
+		return _this;
+	}
+
+	_createClass(codabar, [{
+		key: "valid",
+		value: function valid() {
+			return this.data.search(/^[A-D][0-9\-\$\:\.\+\/]+[A-D]$/) !== -1;
+		}
+	}, {
+		key: "encode",
+		value: function encode() {
+			var result = [];
+			var encodings = this.getEncodings();
+			for (var i = 0; i < this.data.length; i++) {
+				result.push(encodings[this.data.charAt(i)]);
+				// for all characters except the last, append a narrow-space ("0")
+				if (i !== this.data.length - 1) {
+					result.push("0");
+				}
+			}
+			return {
+				text: this.text,
+				data: result.join('')
+			};
+		}
+	}, {
+		key: "getEncodings",
+		value: function getEncodings() {
+			return {
+				"0": "101010011",
+				"1": "101011001",
+				"2": "101001011",
+				"3": "110010101",
+				"4": "101101001",
+				"5": "110101001",
+				"6": "100101011",
+				"7": "100101101",
+				"8": "100110101",
+				"9": "110100101",
+				"-": "101001101",
+				"$": "101100101",
+				":": "1101011011",
+				"/": "1101101011",
+				".": "1101101101",
+				"+": "101100110011",
+				"A": "1011001001",
+				"B": "1001001011",
+				"C": "1010010011",
+				"D": "1010011001"
+			};
+		}
+	}]);
+
+	return codabar;
+}(_Barcode3.default);
+
+exports.codabar = codabar;

+ 34 - 0
components/tki-barcode/barcodes/index.js

@@ -0,0 +1,34 @@
+'use strict';
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+
+var _CODE = require('./CODE39/');
+
+var _CODE2 = require('./CODE128/');
+
+var _EAN_UPC = require('./EAN_UPC/');
+
+var _ITF = require('./ITF/');
+
+var _MSI = require('./MSI/');
+
+var _pharmacode = require('./pharmacode/');
+
+var _codabar = require('./codabar');
+
+var _GenericBarcode = require('./GenericBarcode/');
+
+exports.default = {
+	CODE39: _CODE.CODE39,
+	CODE128: _CODE2.CODE128, CODE128A: _CODE2.CODE128A, CODE128B: _CODE2.CODE128B, CODE128C: _CODE2.CODE128C,
+	EAN13: _EAN_UPC.EAN13, EAN8: _EAN_UPC.EAN8, EAN5: _EAN_UPC.EAN5, EAN2: _EAN_UPC.EAN2, 
+	UPC: _EAN_UPC.UPC, UPCE: _EAN_UPC.UPCE,
+	ITF14: _ITF.ITF14,
+	ITF: _ITF.ITF,
+	MSI: _MSI.MSI, MSI10: _MSI.MSI10, MSI11: _MSI.MSI11, MSI1010: _MSI.MSI1010, MSI1110: _MSI.MSI1110,
+	PHARMACODE: _pharmacode.pharmacode,
+	CODABAR: _codabar.codabar,
+	GENERICBARCODE: _GenericBarcode.GenericBarcode
+};

+ 73 - 0
components/tki-barcode/barcodes/pharmacode/index.js

@@ -0,0 +1,73 @@
+"use strict";
+
+Object.defineProperty(exports, "__esModule", {
+	value: true
+});
+exports.pharmacode = undefined;
+
+var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
+
+var _Barcode2 = require("../Barcode.js");
+
+var _Barcode3 = _interopRequireDefault(_Barcode2);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
+
+function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // Encoding documentation
+// http://www.gomaro.ch/ftproot/Laetus_PHARMA-CODE.pdf
+
+var pharmacode = function (_Barcode) {
+	_inherits(pharmacode, _Barcode);
+
+	function pharmacode(data, options) {
+		_classCallCheck(this, pharmacode);
+
+		var _this = _possibleConstructorReturn(this, (pharmacode.__proto__ || Object.getPrototypeOf(pharmacode)).call(this, data, options));
+
+		_this.number = parseInt(data, 10);
+		return _this;
+	}
+
+	_createClass(pharmacode, [{
+		key: "encode",
+		value: function encode() {
+			var z = this.number;
+			var result = "";
+
+			// http://i.imgur.com/RMm4UDJ.png
+			// (source: http://www.gomaro.ch/ftproot/Laetus_PHARMA-CODE.pdf, page: 34)
+			while (!isNaN(z) && z != 0) {
+				if (z % 2 === 0) {
+					// Even
+					result = "11100" + result;
+					z = (z - 2) / 2;
+				} else {
+					// Odd
+					result = "100" + result;
+					z = (z - 1) / 2;
+				}
+			}
+
+			// Remove the two last zeroes
+			result = result.slice(0, -2);
+
+			return {
+				data: result,
+				text: this.text
+			};
+		}
+	}, {
+		key: "valid",
+		value: function valid() {
+			return this.number >= 3 && this.number <= 131070;
+		}
+	}]);
+
+	return pharmacode;
+}(_Barcode3.default);
+
+exports.pharmacode = pharmacode;

+ 211 - 0
components/tki-barcode/tki-barcode.vue

@@ -0,0 +1,211 @@
+<template xlang="wxml" minapp="mpvue">
+	<view class="tki-barcode">
+		<!-- #ifndef MP-ALIPAY -->
+		<canvas class="tki-barcode-canvas" :canvas-id="cid" :style="{width:canvasWidth+'px',height:canvasHeight+'px'}" />
+		<!-- #endif -->
+		<!-- #ifdef MP-ALIPAY -->
+		<canvas :id="cid" :width="canvasWidth" :height="canvasHeight" class="tki-barcode-canvas" />
+		<!-- #endif -->
+		<image v-show="show" :src="result" :style="{width:canvasWidth+'px',height:canvasHeight+'px'}" />
+	</view>
+	
+</template>
+
+<script>
+// const barcode = require('./barcode.js');
+import barCode from "./barcode.js"
+const opations = {
+	// format: "CODE128",//选择要使用的条形码类型 微信支持的条码类型有 code128\code39\ena13\ean8\upc\itf14\
+	width: 4,//设置条之间的宽度
+	height: 120,//高度
+	displayValue: true,//是否在条形码下方显示文字
+	// text: "1234567890",//覆盖显示的文本
+	textAlign: "center",//设置文本的水平对齐方式
+	textPosition: "bottom",//设置文本的垂直位置
+	textMargin: 0,//设置条形码和文本之间的间距
+	fontSize: 24,//设置文本的大小
+	fontColor: "#000000",//设置文本的颜色
+	lineColor: "#000000",//设置条形码的颜色
+	background: "#FFFFFF",//设置条形码的背景色
+	margin: 0,//设置条形码周围的空白边距
+	marginTop: undefined,//设置条形码周围的上边距
+	marginBottom: undefined,//设置条形码周围的下边距
+	marginLeft: undefined,//设置条形码周围的左边距
+	marginRight: undefined,//设置条形码周围的右边距
+}
+export default {
+	name: "tkiBarcode",
+	props: {
+		show: {
+			type: Boolean,
+			default: true
+		},
+		cid: {
+			type: String,
+			default: 'tki-barcode-canvas'
+		},
+		unit: {
+			type: String,
+			default: 'upx'
+		},
+		val: {
+			type: String,
+			default: '1234567890128'
+		},
+		format: {
+			type: String,
+			default: 'CODE128'
+		},
+		opations: {
+			type: Object,
+			default: function () {
+				return {}
+			}
+		},
+		onval: {
+			type: Boolean,
+			default: false
+		},
+		loadMake: {
+			type: Boolean,
+			default: true
+		},
+	},
+	data() {
+		return {
+			result: '',
+			canvasWidth: 0,
+			canvasHeight: 0,
+			defaultOpations: Object.assign({}, opations)
+		}
+	},
+	onUnload: function () {
+	},
+	methods: {
+		_makeCode() {
+			let that = this
+			// 合并参数
+			Object.assign(this.defaultOpations, this.opations)
+			if (that.unit == "upx") {
+				if (that.defaultOpations.width) {
+					that.defaultOpations.width = uni.upx2px(that.defaultOpations.width)
+				}
+				if (that.defaultOpations.height) {
+					that.defaultOpations.height = uni.upx2px(that.defaultOpations.height)
+				}
+				if (that.defaultOpations.fontSize) {
+					that.defaultOpations.fontSize = uni.upx2px(that.defaultOpations.fontSize)
+				}
+			}
+			if (that._empty(that.defaultOpations.text)) {
+				that.defaultOpations.text = that.val
+			}
+			if (that._empty(that.defaultOpations.format)) {
+				that.defaultOpations.format = that.format
+			}
+			// console.log(JSON.stringify(that.defaultOpations))
+			new barCode(that, that.cid, that.defaultOpations,
+				function (res) { // 生成条形码款高回调
+					that.canvasWidth = res.width
+					that.canvasHeight = res.height
+				},
+				function (res) { // 生成条形码的回调
+					// 返回值
+					that._result(res)
+					// 重置默认参数
+					that.defaultOpations = opations
+				},
+			);
+		},
+		_clearCode() {
+			this._result('')
+		},
+		_saveCode() {
+			let that = this;
+			if (this.result != "") {
+				uni.saveImageToPhotosAlbum({
+					filePath: that.result,
+					success: function () {
+						uni.showToast({
+							title: '条形码保存成功',
+							icon: 'success',
+							duration: 2000
+						});
+					}
+				});
+			}
+		},
+		_result(res) {
+			this.result = res;
+			this.$emit('result', res)
+		},
+		_result(res) {
+			this.result = res;
+			this.$emit('result', res)
+		},
+		_empty(v) {
+			let tp = typeof v,
+				rt = false;
+			if (tp == "number" && String(v) == "") {
+				rt = true
+			} else if (tp == "undefined") {
+				rt = true
+			} else if (tp == "object") {
+				if (JSON.stringify(v) == "{}" || JSON.stringify(v) == "[]" || v == null) rt = true
+			} else if (tp == "string") {
+				if (v == "" || v == "undefined" || v == "null" || v == "{}" || v == "[]") rt = true
+			} else if (tp == "function") {
+				rt = false
+			}
+			return rt
+		}
+	},
+	watch: {
+		val(n, o) {
+			if (this.onval) {
+				if (n != o && !this._empty(n)) {
+					setTimeout(() => {
+						this._makeCode()
+					}, 0);
+				}
+			}
+		},
+		opations: {
+			handler(n,o){
+				if (this.onval) {
+					if (!this._empty(n)) {
+						setTimeout(() => {
+							this._makeCode()
+						}, 0);
+					}
+				}
+			},
+			deep: true
+		}
+	},
+	mounted: function () {
+		if (this.loadMake) {
+			if (!this._empty(this.val)) {
+				setTimeout(() => {
+					this._makeCode()
+				}, 0);
+			}
+		}
+	},
+}
+</script>
+<style>
+.tki-barcode {
+	position: relative;
+}
+.tki-barcode-canvas {
+	position: fixed;
+	top: -99999upx;
+	left: -99999upx;
+	z-index: -99999;
+}
+.content-main-barcode uni-image{
+	width: 600rpx !important;
+}
+
+</style>

+ 1206 - 0
components/tki-qrcode/qrcode.js

@@ -0,0 +1,1206 @@
+let QRCode = {};
+(function () {
+    /**
+     * 获取单个字符的utf8编码
+     * unicode BMP平面约65535个字符
+     * @param {num} code
+     * return {array}
+     */
+    function unicodeFormat8(code) {
+        // 1 byte
+        var c0, c1, c2;
+        if (code < 128) {
+            return [code];
+            // 2 bytes
+        } else if (code < 2048) {
+            c0 = 192 + (code >> 6);
+            c1 = 128 + (code & 63);
+            return [c0, c1];
+            // 3 bytes
+        } else {
+            c0 = 224 + (code >> 12);
+            c1 = 128 + (code >> 6 & 63);
+            c2 = 128 + (code & 63);
+            return [c0, c1, c2];
+        }
+    }
+    /**
+     * 获取字符串的utf8编码字节串
+     * @param {string} string
+     * @return {array}
+     */
+    function getUTF8Bytes(string) {
+        var utf8codes = [];
+        for (var i = 0; i < string.length; i++) {
+            var code = string.charCodeAt(i);
+            var utf8 = unicodeFormat8(code);
+            for (var j = 0; j < utf8.length; j++) {
+                utf8codes.push(utf8[j]);
+            }
+        }
+        return utf8codes;
+    }
+    /**
+     * 二维码算法实现
+     * @param {string} data              要编码的信息字符串
+     * @param {num} errorCorrectLevel 纠错等级
+     */
+    function QRCodeAlg(data, errorCorrectLevel) {
+        this.typeNumber = -1; //版本
+        this.errorCorrectLevel = errorCorrectLevel;
+        this.modules = null; //二维矩阵,存放最终结果
+        this.moduleCount = 0; //矩阵大小
+        this.dataCache = null; //数据缓存
+        this.rsBlocks = null; //版本数据信息
+        this.totalDataCount = -1; //可使用的数据量
+        this.data = data;
+        this.utf8bytes = getUTF8Bytes(data);
+        this.make();
+    }
+    QRCodeAlg.prototype = {
+        constructor: QRCodeAlg,
+        /**
+         * 获取二维码矩阵大小
+         * @return {num} 矩阵大小
+         */
+        getModuleCount: function () {
+            return this.moduleCount;
+        },
+        /**
+         * 编码
+         */
+        make: function () {
+            this.getRightType();
+            this.dataCache = this.createData();
+            this.createQrcode();
+        },
+        /**
+         * 设置二位矩阵功能图形
+         * @param  {bool} test 表示是否在寻找最好掩膜阶段
+         * @param  {num} maskPattern 掩膜的版本
+         */
+        makeImpl: function (maskPattern) {
+            this.moduleCount = this.typeNumber * 4 + 17;
+            this.modules = new Array(this.moduleCount);
+            for (var row = 0; row < this.moduleCount; row++) {
+                this.modules[row] = new Array(this.moduleCount);
+            }
+            this.setupPositionProbePattern(0, 0);
+            this.setupPositionProbePattern(this.moduleCount - 7, 0);
+            this.setupPositionProbePattern(0, this.moduleCount - 7);
+            this.setupPositionAdjustPattern();
+            this.setupTimingPattern();
+            this.setupTypeInfo(true, maskPattern);
+            if (this.typeNumber >= 7) {
+                this.setupTypeNumber(true);
+            }
+            this.mapData(this.dataCache, maskPattern);
+        },
+        /**
+         * 设置二维码的位置探测图形
+         * @param  {num} row 探测图形的中心横坐标
+         * @param  {num} col 探测图形的中心纵坐标
+         */
+        setupPositionProbePattern: function (row, col) {
+            for (var r = -1; r <= 7; r++) {
+                if (row + r <= -1 || this.moduleCount <= row + r) continue;
+                for (var c = -1; c <= 7; c++) {
+                    if (col + c <= -1 || this.moduleCount <= col + c) continue;
+                    if ((0 <= r && r <= 6 && (c == 0 || c == 6)) || (0 <= c && c <= 6 && (r == 0 || r == 6)) || (2 <= r && r <= 4 && 2 <= c && c <= 4)) {
+                        this.modules[row + r][col + c] = true;
+                    } else {
+                        this.modules[row + r][col + c] = false;
+                    }
+                }
+            }
+        },
+        /**
+         * 创建二维码
+         * @return {[type]} [description]
+         */
+        createQrcode: function () {
+            var minLostPoint = 0;
+            var pattern = 0;
+            var bestModules = null;
+            for (var i = 0; i < 8; i++) {
+                this.makeImpl(i);
+                var lostPoint = QRUtil.getLostPoint(this);
+                if (i == 0 || minLostPoint > lostPoint) {
+                    minLostPoint = lostPoint;
+                    pattern = i;
+                    bestModules = this.modules;
+                }
+            }
+            this.modules = bestModules;
+            this.setupTypeInfo(false, pattern);
+            if (this.typeNumber >= 7) {
+                this.setupTypeNumber(false);
+            }
+        },
+        /**
+         * 设置定位图形
+         * @return {[type]} [description]
+         */
+        setupTimingPattern: function () {
+            for (var r = 8; r < this.moduleCount - 8; r++) {
+                if (this.modules[r][6] != null) {
+                    continue;
+                }
+                this.modules[r][6] = (r % 2 == 0);
+                if (this.modules[6][r] != null) {
+                    continue;
+                }
+                this.modules[6][r] = (r % 2 == 0);
+            }
+        },
+        /**
+         * 设置矫正图形
+         * @return {[type]} [description]
+         */
+        setupPositionAdjustPattern: function () {
+            var pos = QRUtil.getPatternPosition(this.typeNumber);
+            for (var i = 0; i < pos.length; i++) {
+                for (var j = 0; j < pos.length; j++) {
+                    var row = pos[i];
+                    var col = pos[j];
+                    if (this.modules[row][col] != null) {
+                        continue;
+                    }
+                    for (var r = -2; r <= 2; r++) {
+                        for (var c = -2; c <= 2; c++) {
+                            if (r == -2 || r == 2 || c == -2 || c == 2 || (r == 0 && c == 0)) {
+                                this.modules[row + r][col + c] = true;
+                            } else {
+                                this.modules[row + r][col + c] = false;
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        /**
+         * 设置版本信息(7以上版本才有)
+         * @param  {bool} test 是否处于判断最佳掩膜阶段
+         * @return {[type]}      [description]
+         */
+        setupTypeNumber: function (test) {
+            var bits = QRUtil.getBCHTypeNumber(this.typeNumber);
+            for (var i = 0; i < 18; i++) {
+                var mod = (!test && ((bits >> i) & 1) == 1);
+                this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod;
+                this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod;
+            }
+        },
+        /**
+         * 设置格式信息(纠错等级和掩膜版本)
+         * @param  {bool} test
+         * @param  {num} maskPattern 掩膜版本
+         * @return {}
+         */
+        setupTypeInfo: function (test, maskPattern) {
+            var data = (QRErrorCorrectLevel[this.errorCorrectLevel] << 3) | maskPattern;
+            var bits = QRUtil.getBCHTypeInfo(data);
+            // vertical
+            for (var i = 0; i < 15; i++) {
+                var mod = (!test && ((bits >> i) & 1) == 1);
+                if (i < 6) {
+                    this.modules[i][8] = mod;
+                } else if (i < 8) {
+                    this.modules[i + 1][8] = mod;
+                } else {
+                    this.modules[this.moduleCount - 15 + i][8] = mod;
+                }
+                // horizontal
+                var mod = (!test && ((bits >> i) & 1) == 1);
+                if (i < 8) {
+                    this.modules[8][this.moduleCount - i - 1] = mod;
+                } else if (i < 9) {
+                    this.modules[8][15 - i - 1 + 1] = mod;
+                } else {
+                    this.modules[8][15 - i - 1] = mod;
+                }
+            }
+            // fixed module
+            this.modules[this.moduleCount - 8][8] = (!test);
+        },
+        /**
+         * 数据编码
+         * @return {[type]} [description]
+         */
+        createData: function () {
+            var buffer = new QRBitBuffer();
+            var lengthBits = this.typeNumber > 9 ? 16 : 8;
+            buffer.put(4, 4); //添加模式
+            buffer.put(this.utf8bytes.length, lengthBits);
+            for (var i = 0, l = this.utf8bytes.length; i < l; i++) {
+                buffer.put(this.utf8bytes[i], 8);
+            }
+            if (buffer.length + 4 <= this.totalDataCount * 8) {
+                buffer.put(0, 4);
+            }
+            // padding
+            while (buffer.length % 8 != 0) {
+                buffer.putBit(false);
+            }
+            // padding
+            while (true) {
+                if (buffer.length >= this.totalDataCount * 8) {
+                    break;
+                }
+                buffer.put(QRCodeAlg.PAD0, 8);
+                if (buffer.length >= this.totalDataCount * 8) {
+                    break;
+                }
+                buffer.put(QRCodeAlg.PAD1, 8);
+            }
+            return this.createBytes(buffer);
+        },
+        /**
+         * 纠错码编码
+         * @param  {buffer} buffer 数据编码
+         * @return {[type]}
+         */
+        createBytes: function (buffer) {
+            var offset = 0;
+            var maxDcCount = 0;
+            var maxEcCount = 0;
+            var length = this.rsBlock.length / 3;
+            var rsBlocks = new Array();
+            for (var i = 0; i < length; i++) {
+                var count = this.rsBlock[i * 3 + 0];
+                var totalCount = this.rsBlock[i * 3 + 1];
+                var dataCount = this.rsBlock[i * 3 + 2];
+                for (var j = 0; j < count; j++) {
+                    rsBlocks.push([dataCount, totalCount]);
+                }
+            }
+            var dcdata = new Array(rsBlocks.length);
+            var ecdata = new Array(rsBlocks.length);
+            for (var r = 0; r < rsBlocks.length; r++) {
+                var dcCount = rsBlocks[r][0];
+                var ecCount = rsBlocks[r][1] - dcCount;
+                maxDcCount = Math.max(maxDcCount, dcCount);
+                maxEcCount = Math.max(maxEcCount, ecCount);
+                dcdata[r] = new Array(dcCount);
+                for (var i = 0; i < dcdata[r].length; i++) {
+                    dcdata[r][i] = 0xff & buffer.buffer[i + offset];
+                }
+                offset += dcCount;
+                var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
+                var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1);
+                var modPoly = rawPoly.mod(rsPoly);
+                ecdata[r] = new Array(rsPoly.getLength() - 1);
+                for (var i = 0; i < ecdata[r].length; i++) {
+                    var modIndex = i + modPoly.getLength() - ecdata[r].length;
+                    ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
+                }
+            }
+            var data = new Array(this.totalDataCount);
+            var index = 0;
+            for (var i = 0; i < maxDcCount; i++) {
+                for (var r = 0; r < rsBlocks.length; r++) {
+                    if (i < dcdata[r].length) {
+                        data[index++] = dcdata[r][i];
+                    }
+                }
+            }
+            for (var i = 0; i < maxEcCount; i++) {
+                for (var r = 0; r < rsBlocks.length; r++) {
+                    if (i < ecdata[r].length) {
+                        data[index++] = ecdata[r][i];
+                    }
+                }
+            }
+            return data;
+
+        },
+        /**
+         * 布置模块,构建最终信息
+         * @param  {} data
+         * @param  {} maskPattern
+         * @return {}
+         */
+        mapData: function (data, maskPattern) {
+            var inc = -1;
+            var row = this.moduleCount - 1;
+            var bitIndex = 7;
+            var byteIndex = 0;
+            for (var col = this.moduleCount - 1; col > 0; col -= 2) {
+                if (col == 6) col--;
+                while (true) {
+                    for (var c = 0; c < 2; c++) {
+                        if (this.modules[row][col - c] == null) {
+                            var dark = false;
+                            if (byteIndex < data.length) {
+                                dark = (((data[byteIndex] >>> bitIndex) & 1) == 1);
+                            }
+                            var mask = QRUtil.getMask(maskPattern, row, col - c);
+                            if (mask) {
+                                dark = !dark;
+                            }
+                            this.modules[row][col - c] = dark;
+                            bitIndex--;
+                            if (bitIndex == -1) {
+                                byteIndex++;
+                                bitIndex = 7;
+                            }
+                        }
+                    }
+                    row += inc;
+                    if (row < 0 || this.moduleCount <= row) {
+                        row -= inc;
+                        inc = -inc;
+                        break;
+                    }
+                }
+            }
+        }
+    };
+    /**
+     * 填充字段
+     */
+    QRCodeAlg.PAD0 = 0xEC;
+    QRCodeAlg.PAD1 = 0x11;
+    //---------------------------------------------------------------------
+    // 纠错等级对应的编码
+    //---------------------------------------------------------------------
+    var QRErrorCorrectLevel = [1, 0, 3, 2];
+    //---------------------------------------------------------------------
+    // 掩膜版本
+    //---------------------------------------------------------------------
+    var QRMaskPattern = {
+        PATTERN000: 0,
+        PATTERN001: 1,
+        PATTERN010: 2,
+        PATTERN011: 3,
+        PATTERN100: 4,
+        PATTERN101: 5,
+        PATTERN110: 6,
+        PATTERN111: 7
+    };
+    //---------------------------------------------------------------------
+    // 工具类
+    //---------------------------------------------------------------------
+    var QRUtil = {
+        /*
+        每个版本矫正图形的位置
+         */
+        PATTERN_POSITION_TABLE: [
+            [],
+            [6, 18],
+            [6, 22],
+            [6, 26],
+            [6, 30],
+            [6, 34],
+            [6, 22, 38],
+            [6, 24, 42],
+            [6, 26, 46],
+            [6, 28, 50],
+            [6, 30, 54],
+            [6, 32, 58],
+            [6, 34, 62],
+            [6, 26, 46, 66],
+            [6, 26, 48, 70],
+            [6, 26, 50, 74],
+            [6, 30, 54, 78],
+            [6, 30, 56, 82],
+            [6, 30, 58, 86],
+            [6, 34, 62, 90],
+            [6, 28, 50, 72, 94],
+            [6, 26, 50, 74, 98],
+            [6, 30, 54, 78, 102],
+            [6, 28, 54, 80, 106],
+            [6, 32, 58, 84, 110],
+            [6, 30, 58, 86, 114],
+            [6, 34, 62, 90, 118],
+            [6, 26, 50, 74, 98, 122],
+            [6, 30, 54, 78, 102, 126],
+            [6, 26, 52, 78, 104, 130],
+            [6, 30, 56, 82, 108, 134],
+            [6, 34, 60, 86, 112, 138],
+            [6, 30, 58, 86, 114, 142],
+            [6, 34, 62, 90, 118, 146],
+            [6, 30, 54, 78, 102, 126, 150],
+            [6, 24, 50, 76, 102, 128, 154],
+            [6, 28, 54, 80, 106, 132, 158],
+            [6, 32, 58, 84, 110, 136, 162],
+            [6, 26, 54, 82, 110, 138, 166],
+            [6, 30, 58, 86, 114, 142, 170]
+        ],
+        G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0),
+        G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0),
+        G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1),
+        /*
+        BCH编码格式信息
+         */
+        getBCHTypeInfo: function (data) {
+            var d = data << 10;
+            while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) {
+                d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15)));
+            }
+            return ((data << 10) | d) ^ QRUtil.G15_MASK;
+        },
+        /*
+        BCH编码版本信息
+         */
+        getBCHTypeNumber: function (data) {
+            var d = data << 12;
+            while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) {
+                d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18)));
+            }
+            return (data << 12) | d;
+        },
+        /*
+        获取BCH位信息
+         */
+        getBCHDigit: function (data) {
+            var digit = 0;
+            while (data != 0) {
+                digit++;
+                data >>>= 1;
+            }
+            return digit;
+        },
+        /*
+        获取版本对应的矫正图形位置
+         */
+        getPatternPosition: function (typeNumber) {
+            return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1];
+        },
+        /*
+        掩膜算法
+         */
+        getMask: function (maskPattern, i, j) {
+            switch (maskPattern) {
+                case QRMaskPattern.PATTERN000:
+                    return (i + j) % 2 == 0;
+                case QRMaskPattern.PATTERN001:
+                    return i % 2 == 0;
+                case QRMaskPattern.PATTERN010:
+                    return j % 3 == 0;
+                case QRMaskPattern.PATTERN011:
+                    return (i + j) % 3 == 0;
+                case QRMaskPattern.PATTERN100:
+                    return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0;
+                case QRMaskPattern.PATTERN101:
+                    return (i * j) % 2 + (i * j) % 3 == 0;
+                case QRMaskPattern.PATTERN110:
+                    return ((i * j) % 2 + (i * j) % 3) % 2 == 0;
+                case QRMaskPattern.PATTERN111:
+                    return ((i * j) % 3 + (i + j) % 2) % 2 == 0;
+                default:
+                    throw new Error("bad maskPattern:" + maskPattern);
+            }
+        },
+        /*
+        获取RS的纠错多项式
+         */
+        getErrorCorrectPolynomial: function (errorCorrectLength) {
+            var a = new QRPolynomial([1], 0);
+            for (var i = 0; i < errorCorrectLength; i++) {
+                a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0));
+            }
+            return a;
+        },
+        /*
+        获取评价
+         */
+        getLostPoint: function (qrCode) {
+            var moduleCount = qrCode.getModuleCount(),
+                lostPoint = 0,
+                darkCount = 0;
+            for (var row = 0; row < moduleCount; row++) {
+                var sameCount = 0;
+                var head = qrCode.modules[row][0];
+                for (var col = 0; col < moduleCount; col++) {
+                    var current = qrCode.modules[row][col];
+                    //level 3 评价
+                    if (col < moduleCount - 6) {
+                        if (current && !qrCode.modules[row][col + 1] && qrCode.modules[row][col + 2] && qrCode.modules[row][col + 3] && qrCode.modules[row][col + 4] && !qrCode.modules[row][col + 5] && qrCode.modules[row][col + 6]) {
+                            if (col < moduleCount - 10) {
+                                if (qrCode.modules[row][col + 7] && qrCode.modules[row][col + 8] && qrCode.modules[row][col + 9] && qrCode.modules[row][col + 10]) {
+                                    lostPoint += 40;
+                                }
+                            } else if (col > 3) {
+                                if (qrCode.modules[row][col - 1] && qrCode.modules[row][col - 2] && qrCode.modules[row][col - 3] && qrCode.modules[row][col - 4]) {
+                                    lostPoint += 40;
+                                }
+                            }
+                        }
+                    }
+                    //level 2 评价
+                    if ((row < moduleCount - 1) && (col < moduleCount - 1)) {
+                        var count = 0;
+                        if (current) count++;
+                        if (qrCode.modules[row + 1][col]) count++;
+                        if (qrCode.modules[row][col + 1]) count++;
+                        if (qrCode.modules[row + 1][col + 1]) count++;
+                        if (count == 0 || count == 4) {
+                            lostPoint += 3;
+                        }
+                    }
+                    //level 1 评价
+                    if (head ^ current) {
+                        sameCount++;
+                    } else {
+                        head = current;
+                        if (sameCount >= 5) {
+                            lostPoint += (3 + sameCount - 5);
+                        }
+                        sameCount = 1;
+                    }
+                    //level 4 评价
+                    if (current) {
+                        darkCount++;
+                    }
+                }
+            }
+            for (var col = 0; col < moduleCount; col++) {
+                var sameCount = 0;
+                var head = qrCode.modules[0][col];
+                for (var row = 0; row < moduleCount; row++) {
+                    var current = qrCode.modules[row][col];
+                    //level 3 评价
+                    if (row < moduleCount - 6) {
+                        if (current && !qrCode.modules[row + 1][col] && qrCode.modules[row + 2][col] && qrCode.modules[row + 3][col] && qrCode.modules[row + 4][col] && !qrCode.modules[row + 5][col] && qrCode.modules[row + 6][col]) {
+                            if (row < moduleCount - 10) {
+                                if (qrCode.modules[row + 7][col] && qrCode.modules[row + 8][col] && qrCode.modules[row + 9][col] && qrCode.modules[row + 10][col]) {
+                                    lostPoint += 40;
+                                }
+                            } else if (row > 3) {
+                                if (qrCode.modules[row - 1][col] && qrCode.modules[row - 2][col] && qrCode.modules[row - 3][col] && qrCode.modules[row - 4][col]) {
+                                    lostPoint += 40;
+                                }
+                            }
+                        }
+                    }
+                    //level 1 评价
+                    if (head ^ current) {
+                        sameCount++;
+                    } else {
+                        head = current;
+                        if (sameCount >= 5) {
+                            lostPoint += (3 + sameCount - 5);
+                        }
+                        sameCount = 1;
+                    }
+                }
+            }
+            // LEVEL4
+            var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
+            lostPoint += ratio * 10;
+            return lostPoint;
+        }
+
+    };
+    //---------------------------------------------------------------------
+    // QRMath使用的数学工具
+    //---------------------------------------------------------------------
+    var QRMath = {
+        /*
+        将n转化为a^m
+         */
+        glog: function (n) {
+            if (n < 1) {
+                throw new Error("glog(" + n + ")");
+            }
+            return QRMath.LOG_TABLE[n];
+        },
+        /*
+        将a^m转化为n
+         */
+        gexp: function (n) {
+            while (n < 0) {
+                n += 255;
+            }
+            while (n >= 256) {
+                n -= 255;
+            }
+            return QRMath.EXP_TABLE[n];
+        },
+        EXP_TABLE: new Array(256),
+        LOG_TABLE: new Array(256)
+
+    };
+    for (var i = 0; i < 8; i++) {
+        QRMath.EXP_TABLE[i] = 1 << i;
+    }
+    for (var i = 8; i < 256; i++) {
+        QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^ QRMath.EXP_TABLE[i - 5] ^ QRMath.EXP_TABLE[i - 6] ^ QRMath.EXP_TABLE[i - 8];
+    }
+    for (var i = 0; i < 255; i++) {
+        QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i;
+    }
+    //---------------------------------------------------------------------
+    // QRPolynomial 多项式
+    //---------------------------------------------------------------------
+    /**
+     * 多项式类
+     * @param {Array} num   系数
+     * @param {num} shift a^shift
+     */
+    function QRPolynomial(num, shift) {
+        if (num.length == undefined) {
+            throw new Error(num.length + "/" + shift);
+        }
+        var offset = 0;
+        while (offset < num.length && num[offset] == 0) {
+            offset++;
+        }
+        this.num = new Array(num.length - offset + shift);
+        for (var i = 0; i < num.length - offset; i++) {
+            this.num[i] = num[i + offset];
+        }
+    }
+    QRPolynomial.prototype = {
+        get: function (index) {
+            return this.num[index];
+        },
+        getLength: function () {
+            return this.num.length;
+        },
+        /**
+         * 多项式乘法
+         * @param  {QRPolynomial} e 被乘多项式
+         * @return {[type]}   [description]
+         */
+        multiply: function (e) {
+            var num = new Array(this.getLength() + e.getLength() - 1);
+            for (var i = 0; i < this.getLength(); i++) {
+                for (var j = 0; j < e.getLength(); j++) {
+                    num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j)));
+                }
+            }
+            return new QRPolynomial(num, 0);
+        },
+        /**
+         * 多项式模运算
+         * @param  {QRPolynomial} e 模多项式
+         * @return {}
+         */
+        mod: function (e) {
+            var tl = this.getLength(),
+                el = e.getLength();
+            if (tl - el < 0) {
+                return this;
+            }
+            var num = new Array(tl);
+            for (var i = 0; i < tl; i++) {
+                num[i] = this.get(i);
+            }
+            while (num.length >= el) {
+                var ratio = QRMath.glog(num[0]) - QRMath.glog(e.get(0));
+
+                for (var i = 0; i < e.getLength(); i++) {
+                    num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
+                }
+                while (num[0] == 0) {
+                    num.shift();
+                }
+            }
+            return new QRPolynomial(num, 0);
+        }
+    };
+
+    //---------------------------------------------------------------------
+    // RS_BLOCK_TABLE
+    //---------------------------------------------------------------------
+    /*
+    二维码各个版本信息[块数, 每块中的数据块数, 每块中的信息块数]
+     */
+    var RS_BLOCK_TABLE = [
+        // L
+        // M
+        // Q
+        // H
+        // 1
+        [1, 26, 19],
+        [1, 26, 16],
+        [1, 26, 13],
+        [1, 26, 9],
+
+        // 2
+        [1, 44, 34],
+        [1, 44, 28],
+        [1, 44, 22],
+        [1, 44, 16],
+
+        // 3
+        [1, 70, 55],
+        [1, 70, 44],
+        [2, 35, 17],
+        [2, 35, 13],
+
+        // 4
+        [1, 100, 80],
+        [2, 50, 32],
+        [2, 50, 24],
+        [4, 25, 9],
+
+        // 5
+        [1, 134, 108],
+        [2, 67, 43],
+        [2, 33, 15, 2, 34, 16],
+        [2, 33, 11, 2, 34, 12],
+
+        // 6
+        [2, 86, 68],
+        [4, 43, 27],
+        [4, 43, 19],
+        [4, 43, 15],
+
+        // 7
+        [2, 98, 78],
+        [4, 49, 31],
+        [2, 32, 14, 4, 33, 15],
+        [4, 39, 13, 1, 40, 14],
+
+        // 8
+        [2, 121, 97],
+        [2, 60, 38, 2, 61, 39],
+        [4, 40, 18, 2, 41, 19],
+        [4, 40, 14, 2, 41, 15],
+
+        // 9
+        [2, 146, 116],
+        [3, 58, 36, 2, 59, 37],
+        [4, 36, 16, 4, 37, 17],
+        [4, 36, 12, 4, 37, 13],
+
+        // 10
+        [2, 86, 68, 2, 87, 69],
+        [4, 69, 43, 1, 70, 44],
+        [6, 43, 19, 2, 44, 20],
+        [6, 43, 15, 2, 44, 16],
+
+        // 11
+        [4, 101, 81],
+        [1, 80, 50, 4, 81, 51],
+        [4, 50, 22, 4, 51, 23],
+        [3, 36, 12, 8, 37, 13],
+
+        // 12
+        [2, 116, 92, 2, 117, 93],
+        [6, 58, 36, 2, 59, 37],
+        [4, 46, 20, 6, 47, 21],
+        [7, 42, 14, 4, 43, 15],
+
+        // 13
+        [4, 133, 107],
+        [8, 59, 37, 1, 60, 38],
+        [8, 44, 20, 4, 45, 21],
+        [12, 33, 11, 4, 34, 12],
+
+        // 14
+        [3, 145, 115, 1, 146, 116],
+        [4, 64, 40, 5, 65, 41],
+        [11, 36, 16, 5, 37, 17],
+        [11, 36, 12, 5, 37, 13],
+
+        // 15
+        [5, 109, 87, 1, 110, 88],
+        [5, 65, 41, 5, 66, 42],
+        [5, 54, 24, 7, 55, 25],
+        [11, 36, 12],
+
+        // 16
+        [5, 122, 98, 1, 123, 99],
+        [7, 73, 45, 3, 74, 46],
+        [15, 43, 19, 2, 44, 20],
+        [3, 45, 15, 13, 46, 16],
+
+        // 17
+        [1, 135, 107, 5, 136, 108],
+        [10, 74, 46, 1, 75, 47],
+        [1, 50, 22, 15, 51, 23],
+        [2, 42, 14, 17, 43, 15],
+
+        // 18
+        [5, 150, 120, 1, 151, 121],
+        [9, 69, 43, 4, 70, 44],
+        [17, 50, 22, 1, 51, 23],
+        [2, 42, 14, 19, 43, 15],
+
+        // 19
+        [3, 141, 113, 4, 142, 114],
+        [3, 70, 44, 11, 71, 45],
+        [17, 47, 21, 4, 48, 22],
+        [9, 39, 13, 16, 40, 14],
+
+        // 20
+        [3, 135, 107, 5, 136, 108],
+        [3, 67, 41, 13, 68, 42],
+        [15, 54, 24, 5, 55, 25],
+        [15, 43, 15, 10, 44, 16],
+
+        // 21
+        [4, 144, 116, 4, 145, 117],
+        [17, 68, 42],
+        [17, 50, 22, 6, 51, 23],
+        [19, 46, 16, 6, 47, 17],
+
+        // 22
+        [2, 139, 111, 7, 140, 112],
+        [17, 74, 46],
+        [7, 54, 24, 16, 55, 25],
+        [34, 37, 13],
+
+        // 23
+        [4, 151, 121, 5, 152, 122],
+        [4, 75, 47, 14, 76, 48],
+        [11, 54, 24, 14, 55, 25],
+        [16, 45, 15, 14, 46, 16],
+
+        // 24
+        [6, 147, 117, 4, 148, 118],
+        [6, 73, 45, 14, 74, 46],
+        [11, 54, 24, 16, 55, 25],
+        [30, 46, 16, 2, 47, 17],
+
+        // 25
+        [8, 132, 106, 4, 133, 107],
+        [8, 75, 47, 13, 76, 48],
+        [7, 54, 24, 22, 55, 25],
+        [22, 45, 15, 13, 46, 16],
+
+        // 26
+        [10, 142, 114, 2, 143, 115],
+        [19, 74, 46, 4, 75, 47],
+        [28, 50, 22, 6, 51, 23],
+        [33, 46, 16, 4, 47, 17],
+
+        // 27
+        [8, 152, 122, 4, 153, 123],
+        [22, 73, 45, 3, 74, 46],
+        [8, 53, 23, 26, 54, 24],
+        [12, 45, 15, 28, 46, 16],
+
+        // 28
+        [3, 147, 117, 10, 148, 118],
+        [3, 73, 45, 23, 74, 46],
+        [4, 54, 24, 31, 55, 25],
+        [11, 45, 15, 31, 46, 16],
+
+        // 29
+        [7, 146, 116, 7, 147, 117],
+        [21, 73, 45, 7, 74, 46],
+        [1, 53, 23, 37, 54, 24],
+        [19, 45, 15, 26, 46, 16],
+
+        // 30
+        [5, 145, 115, 10, 146, 116],
+        [19, 75, 47, 10, 76, 48],
+        [15, 54, 24, 25, 55, 25],
+        [23, 45, 15, 25, 46, 16],
+
+        // 31
+        [13, 145, 115, 3, 146, 116],
+        [2, 74, 46, 29, 75, 47],
+        [42, 54, 24, 1, 55, 25],
+        [23, 45, 15, 28, 46, 16],
+
+        // 32
+        [17, 145, 115],
+        [10, 74, 46, 23, 75, 47],
+        [10, 54, 24, 35, 55, 25],
+        [19, 45, 15, 35, 46, 16],
+
+        // 33
+        [17, 145, 115, 1, 146, 116],
+        [14, 74, 46, 21, 75, 47],
+        [29, 54, 24, 19, 55, 25],
+        [11, 45, 15, 46, 46, 16],
+
+        // 34
+        [13, 145, 115, 6, 146, 116],
+        [14, 74, 46, 23, 75, 47],
+        [44, 54, 24, 7, 55, 25],
+        [59, 46, 16, 1, 47, 17],
+
+        // 35
+        [12, 151, 121, 7, 152, 122],
+        [12, 75, 47, 26, 76, 48],
+        [39, 54, 24, 14, 55, 25],
+        [22, 45, 15, 41, 46, 16],
+
+        // 36
+        [6, 151, 121, 14, 152, 122],
+        [6, 75, 47, 34, 76, 48],
+        [46, 54, 24, 10, 55, 25],
+        [2, 45, 15, 64, 46, 16],
+
+        // 37
+        [17, 152, 122, 4, 153, 123],
+        [29, 74, 46, 14, 75, 47],
+        [49, 54, 24, 10, 55, 25],
+        [24, 45, 15, 46, 46, 16],
+
+        // 38
+        [4, 152, 122, 18, 153, 123],
+        [13, 74, 46, 32, 75, 47],
+        [48, 54, 24, 14, 55, 25],
+        [42, 45, 15, 32, 46, 16],
+
+        // 39
+        [20, 147, 117, 4, 148, 118],
+        [40, 75, 47, 7, 76, 48],
+        [43, 54, 24, 22, 55, 25],
+        [10, 45, 15, 67, 46, 16],
+
+        // 40
+        [19, 148, 118, 6, 149, 119],
+        [18, 75, 47, 31, 76, 48],
+        [34, 54, 24, 34, 55, 25],
+        [20, 45, 15, 61, 46, 16]
+    ];
+
+    /**
+     * 根据数据获取对应版本
+     * @return {[type]} [description]
+     */
+    QRCodeAlg.prototype.getRightType = function () {
+        for (var typeNumber = 1; typeNumber < 41; typeNumber++) {
+            var rsBlock = RS_BLOCK_TABLE[(typeNumber - 1) * 4 + this.errorCorrectLevel];
+            if (rsBlock == undefined) {
+                throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + this.errorCorrectLevel);
+            }
+            var length = rsBlock.length / 3;
+            var totalDataCount = 0;
+            for (var i = 0; i < length; i++) {
+                var count = rsBlock[i * 3 + 0];
+                var dataCount = rsBlock[i * 3 + 2];
+                totalDataCount += dataCount * count;
+            }
+            var lengthBytes = typeNumber > 9 ? 2 : 1;
+            if (this.utf8bytes.length + lengthBytes < totalDataCount || typeNumber == 40) {
+                this.typeNumber = typeNumber;
+                this.rsBlock = rsBlock;
+                this.totalDataCount = totalDataCount;
+                break;
+            }
+        }
+    };
+
+    //---------------------------------------------------------------------
+    // QRBitBuffer
+    //---------------------------------------------------------------------
+    function QRBitBuffer() {
+        this.buffer = new Array();
+        this.length = 0;
+    }
+    QRBitBuffer.prototype = {
+        get: function (index) {
+            var bufIndex = Math.floor(index / 8);
+            return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1);
+        },
+        put: function (num, length) {
+            for (var i = 0; i < length; i++) {
+                this.putBit(((num >>> (length - i - 1)) & 1));
+            }
+        },
+        putBit: function (bit) {
+            var bufIndex = Math.floor(this.length / 8);
+            if (this.buffer.length <= bufIndex) {
+                this.buffer.push(0);
+            }
+            if (bit) {
+                this.buffer[bufIndex] |= (0x80 >>> (this.length % 8));
+            }
+            this.length++;
+        }
+    };
+
+
+
+    // xzedit
+    let qrcodeAlgObjCache = [];
+    /**
+     * 二维码构造函数,主要用于绘制
+     * @param  {参数列表} opt 传递参数
+     * @return {}
+     */
+    QRCode = function (opt) {
+        //设置默认参数
+        this.options = {
+            text: '',
+            size: 256,
+            correctLevel: 3,
+            background: '#ffffff',
+            foreground: '#000000',
+            pdground: '#000000',
+            image: '',
+            imageSize: 30,
+            canvasId: opt.canvasId,
+            context: opt.context,
+            usingComponents: opt.usingComponents,
+            showLoading: opt.showLoading,
+            loadingText: opt.loadingText,
+        };
+        if (typeof opt === 'string') { // 只编码ASCII字符串
+            opt = {
+                text: opt
+            };
+        }
+        if (opt) {
+            for (var i in opt) {
+                this.options[i] = opt[i];
+            }
+        }
+        //使用QRCodeAlg创建二维码结构
+        var qrCodeAlg = null;
+        for (var i = 0, l = qrcodeAlgObjCache.length; i < l; i++) {
+            if (qrcodeAlgObjCache[i].text == this.options.text && qrcodeAlgObjCache[i].text.correctLevel == this.options.correctLevel) {
+                qrCodeAlg = qrcodeAlgObjCache[i].obj;
+                break;
+            }
+        }
+        if (i == l) {
+            qrCodeAlg = new QRCodeAlg(this.options.text, this.options.correctLevel);
+            qrcodeAlgObjCache.push({
+                text: this.options.text,
+                correctLevel: this.options.correctLevel,
+                obj: qrCodeAlg
+            });
+        }
+        /**
+         * 计算矩阵点的前景色
+         * @param {Obj} config
+         * @param {Number} config.row 点x坐标
+         * @param {Number} config.col 点y坐标
+         * @param {Number} config.count 矩阵大小
+         * @param {Number} config.options 组件的options
+         * @return {String}
+         */
+        let getForeGround = function (config) {
+            var options = config.options;
+            if (options.pdground && (
+                (config.row > 1 && config.row < 5 && config.col > 1 && config.col < 5) ||
+                (config.row > (config.count - 6) && config.row < (config.count - 2) && config.col > 1 && config.col < 5) ||
+                (config.row > 1 && config.row < 5 && config.col > (config.count - 6) && config.col < (config.count - 2))
+            )) {
+                return options.pdground;
+            }
+            return options.foreground;
+        }
+        // 创建canvas
+        let createCanvas = function (options) {
+            if(options.showLoading){
+                uni.showLoading({
+                    title: options.loadingText,
+                    mask: true
+                });
+            }
+            var ctx = uni.createCanvasContext(options.canvasId, options.context);
+            var count = qrCodeAlg.getModuleCount();
+            var ratioSize = options.size;
+            var ratioImgSize = options.imageSize;
+            //计算每个点的长宽
+            var tileW = (ratioSize / count).toPrecision(4);
+            var tileH = (ratioSize / count).toPrecision(4);
+            //绘制
+            for (var row = 0; row < count; row++) {
+                for (var col = 0; col < count; col++) {
+                    var w = (Math.ceil((col + 1) * tileW) - Math.floor(col * tileW));
+                    var h = (Math.ceil((row + 1) * tileW) - Math.floor(row * tileW));
+                    var foreground = getForeGround({
+                        row: row,
+                        col: col,
+                        count: count,
+                        options: options
+                    });
+                    ctx.setFillStyle(qrCodeAlg.modules[row][col] ? foreground : options.background);
+                    ctx.fillRect(Math.round(col * tileW), Math.round(row * tileH), w, h);
+                }
+            }
+            if (options.image) {
+                var x = Number(((ratioSize - ratioImgSize) / 2).toFixed(2));
+                var y = Number(((ratioSize - ratioImgSize) / 2).toFixed(2));
+                drawRoundedRect(ctx, x, y, ratioImgSize, ratioImgSize, 2, 6, true, true)
+                ctx.drawImage(options.image, x, y, ratioImgSize, ratioImgSize);
+                // 画圆角矩形
+                function drawRoundedRect(ctxi, x, y, width, height, r, lineWidth, fill, stroke) {
+                    ctxi.setLineWidth(lineWidth);
+                    ctxi.setFillStyle(options.background);
+                    ctxi.setStrokeStyle(options.background);
+                    ctxi.beginPath(); // draw top and top right corner
+                    ctxi.moveTo(x + r, y);
+                    ctxi.arcTo(x + width, y, x + width, y + r, r); // draw right side and bottom right corner
+                    ctxi.arcTo(x + width, y + height, x + width - r, y + height, r); // draw bottom and bottom left corner
+                    ctxi.arcTo(x, y + height, x, y + height - r, r); // draw left and top left corner
+                    ctxi.arcTo(x, y, x + r, y, r);
+                    ctxi.closePath();
+                    if (fill) {
+                        ctxi.fill();
+                    }
+                    if (stroke) {
+                        ctxi.stroke();
+                    }
+                }
+            }
+            setTimeout(() => {
+                ctx.draw(true, () => {
+                    // 保存到临时区域
+                    setTimeout(() => {
+                        uni.canvasToTempFilePath({
+                            width: options.width,
+                            height: options.height,
+                            destWidth: options.width,
+                            destHeight: options.height,
+                            canvasId: options.canvasId,
+                            quality: Number(1),
+                            success: function (res) {
+                                if (options.cbResult) {
+                                    // 由于官方还没有统一此接口的输出字段,所以先判定下  支付宝为 res.apFilePath
+                                    if (!empty(res.tempFilePath)) {
+                                        options.cbResult(res.tempFilePath)
+                                    } else if (!empty(res.apFilePath)) {
+                                        options.cbResult(res.apFilePath)
+                                    } else {
+                                        options.cbResult(res.tempFilePath)
+                                    }
+                                }
+                            },
+                            fail: function (res) {
+                                if (options.cbResult) {
+                                    options.cbResult(res)
+                                }
+                            },
+                            complete: function () {
+                                uni.hideLoading();
+                            },
+                        }, options.context);
+                    }, options.text.length + 100);
+                });
+            }, options.usingComponents ? 0 : 150);
+        }
+        createCanvas(this.options);
+        // 空判定
+        let empty = function (v) {
+            let tp = typeof v,
+                rt = false;
+            if (tp == "number" && String(v) == "") {
+                rt = true
+            } else if (tp == "undefined") {
+                rt = true
+            } else if (tp == "object") {
+                if (JSON.stringify(v) == "{}" || JSON.stringify(v) == "[]" || v == null) rt = true
+            } else if (tp == "string") {
+                if (v == "" || v == "undefined" || v == "null" || v == "{}" || v == "[]") rt = true
+            } else if (tp == "function") {
+                rt = false
+            }
+            return rt
+        }
+    };
+    QRCode.prototype.clear = function (fn) {
+        var ctx = uni.createCanvasContext(this.options.canvasId, this.options.context)
+        ctx.clearRect(0, 0, this.options.size, this.options.size)
+        ctx.draw(false, () => {
+            if (fn) {
+                fn()
+            }
+        })
+    };
+})()
+
+export default QRCode

+ 205 - 0
components/tki-qrcode/tki-qrcode.vue

@@ -0,0 +1,205 @@
+<template xlang="wxml" minapp="mpvue">
+	<view class="tki-qrcode">
+		<canvas class="tki-qrcode-canvas" :canvas-id="cid" :style="{width:cpSize+'px',height:cpSize+'px'}" />
+		<image v-show="show" :src="result" :style="{width:cpSize+'px',height:cpSize+'px'}" />
+	</view>
+</template>
+
+<script>
+	import QRCode from "./qrcode.js"
+	let qrcode
+	export default {
+		name: "tki-qrcode",
+		props: {
+			cid: {
+				type: String,
+				default: 'tki-qrcode-canvas'
+			},
+			size: {
+				type: Number,
+				default: 200
+			},
+			unit: {
+				type: String,
+				default: 'upx'
+			},
+			show: {
+				type: Boolean,
+				default: true
+			},
+			val: {
+				type: String,
+				default: ''
+			},
+			background: {
+				type: String,
+				default: '#ffffff'
+			},
+			foreground: {
+				type: String,
+				default: '#000000'
+			},
+			pdground: {
+				type: String,
+				default: '#000000'
+			},
+			icon: {
+				type: String,
+				default: ''
+			},
+			iconSize: {
+				type: Number,
+				default: 40
+			},
+			lv: {
+				type: Number,
+				default: 3
+			},
+			onval: {
+				type: Boolean,
+				default: false
+			},
+			loadMake: {
+				type: Boolean,
+				default: false
+			},
+			usingComponents: {
+				type: Boolean,
+				default: true
+			},
+			showLoading: {
+				type: Boolean,
+				default: true
+			},
+			loadingText: {
+				type: String,
+				default: '二维码生成中'
+			},
+		},
+		data() {
+			return {
+				result: '',
+			}
+		},
+		methods: {
+			_makeCode() {
+				let that = this
+				if (!this._empty(this.val)) {
+					qrcode = new QRCode({
+						context: that, // 上下文环境
+						canvasId:that.cid, // canvas-id
+						usingComponents: that.usingComponents, // 是否是自定义组件
+						showLoading: that.showLoading, // 是否显示loading
+						loadingText: that.loadingText, // loading文字
+						text: that.val, // 生成内容
+						size: that.cpSize, // 二维码大小
+						background: that.background, // 背景色
+						foreground: that.foreground, // 前景色
+						pdground: that.pdground, // 定位角点颜色
+						correctLevel: that.lv, // 容错级别
+						image: that.icon, // 二维码图标
+						imageSize: that.iconSize,// 二维码图标大小
+						cbResult: function (res) { // 生成二维码的回调
+							that._result(res)
+						},
+					});
+				} else {
+					uni.showToast({
+						title: '二维码内容不能为空',
+						icon: 'none',
+						duration: 2000
+					});
+				}
+			},
+			_clearCode() {
+				this._result('')
+				qrcode.clear()
+			},
+			_saveCode() {
+				let that = this;
+				if (this.result != "") {
+					uni.saveImageToPhotosAlbum({
+						filePath: that.result,
+						success: function () {
+							uni.showToast({
+								title: '二维码保存成功',
+								icon: 'success',
+								duration: 2000
+							});
+						}
+					});
+				}
+			},
+			_result(res) {
+				this.result = res;
+				this.$emit('result', res);
+			},
+			_empty(v) {
+				let tp = typeof v,
+						rt = false;
+				if (tp == "number" && String(v) == "") {
+					rt = true
+				} else if (tp == "undefined") {
+					rt = true
+				} else if (tp == "object") {
+					if (JSON.stringify(v) == "{}" || JSON.stringify(v) == "[]" || v == null) rt = true
+				} else if (tp == "string") {
+					if (v == "" || v == "undefined" || v == "null" || v == "{}" || v == "[]") rt = true
+				} else if (tp == "function") {
+					rt = false
+				}
+				return rt
+			}
+		},
+		watch: {
+			size: function (n, o) {
+				if (n != o && !this._empty(n)) {
+					this.cSize = n
+					if (!this._empty(this.val)) {
+						setTimeout(() => {
+							this._makeCode()
+						}, 100);
+					}
+				}
+			},
+			val: function (n, o) {
+				if (this.onval) {
+					if (n != o && !this._empty(n)) {
+						setTimeout(() => {
+							this._makeCode()
+						}, 0);
+					}
+				}
+			}
+		},
+		computed: {
+			cpSize() {
+				if(this.unit == "upx"){
+					return uni.upx2px(this.size)
+				}else{
+					return this.size
+				}
+			}
+		},
+		mounted: function () {
+			if (this.loadMake) {
+				if (!this._empty(this.val)) {
+					setTimeout(() => {
+						this._makeCode()
+					}, 0);
+				}
+			}
+		},
+	}
+</script>
+<style>
+	.tki-qrcode {
+		position: relative;
+	}
+	.tki-qrcode-canvas {
+		position: fixed;
+		top: -99999upx;
+		left: -99999upx;
+		z-index: -99999;
+	}
+</style>

+ 151 - 0
components/uni-badge/uni-badge.vue

@@ -0,0 +1,151 @@
+<template>
+	<text v-if="text" :class="inverted ? 'uni-badge--' + type + ' uni-badge--' + size + ' uni-badge--' + type + '-inverted' : 'uni-badge--' + type + ' uni-badge--' + size"
+	 :style="badgeStyle" class="uni-badge" @click="onClick()">{{ text }}</text>
+</template>
+
+<script>
+	/**
+	 * Badge 数字角标
+	 * @description 数字角标一般和其它控件(列表、9宫格等)配合使用,用于进行数量提示,默认为实心灰色背景
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=21
+	 * @property {String} text 角标内容
+	 * @property {String} type = [default|primary|success|warning|error] 颜色类型
+	 * 	@value default 灰色
+	 * 	@value primary 蓝色
+	 * 	@value success 绿色
+	 * 	@value warning 黄色
+	 * 	@value error 红色
+	 * @property {String} size = [normal|small] Badge 大小
+	 * 	@value normal 一般尺寸
+	 * 	@value small 小尺寸
+	 * @property {String} inverted = [true|false] 是否无需背景颜色
+	 * @event {Function} click 点击 Badge 触发事件
+	 * @example <uni-badge text="1"></uni-badge>
+	 */
+	export default {
+		name: 'UniBadge',
+		props: {
+			type: {
+				type: String,
+				default: 'default'
+			},
+			inverted: {
+				type: Boolean,
+				default: false
+			},
+			text: {
+				type: [String, Number],
+				default: ''
+			},
+			size: {
+				type: String,
+				default: 'normal'
+			}
+		},
+		data() {
+			return {
+				badgeStyle: ''
+			};
+		},
+		watch: {
+			text() {
+				this.setStyle()
+			}
+		},
+		mounted() {
+			this.setStyle()
+		},
+		methods: {
+			setStyle() {
+				this.badgeStyle = `width: ${String(this.text).length * 8 + 12}px`
+			},
+			onClick() {
+				this.$emit('click');
+			}
+		}
+	};
+</script>
+
+<style lang="scss" scoped>
+	$bage-size: 12px;
+	$bage-small: scale(0.8);
+	$bage-height: 20px;
+
+	.uni-badge {
+		/* #ifndef APP-PLUS */
+		display: flex;
+		/* #endif */
+		justify-content: center;
+		flex-direction: row;
+		height: $bage-height;
+		line-height: $bage-height;
+		color: $uni-text-color;
+		border-radius: 100px;
+		background-color: $uni-bg-color-hover;
+		background-color: transparent;
+		text-align: center;
+		font-family: 'Helvetica Neue', Helvetica, sans-serif;
+		font-size: $bage-size;
+		padding: 0px 6px;
+	}
+
+	.uni-badge--inverted {
+		padding: 0 5px 0 0;
+		color: $uni-bg-color-hover;
+	}
+
+	.uni-badge--default {
+		color: $uni-text-color;
+		background-color: $uni-bg-color-hover;
+	}
+
+	.uni-badge--default-inverted {
+		color: $uni-text-color-grey;
+		background-color: transparent;
+	}
+
+	.uni-badge--primary {
+		color: $uni-text-color-inverse;
+		background-color: $uni-color-primary;
+	}
+
+	.uni-badge--primary-inverted {
+		color: $uni-color-primary;
+		background-color: transparent;
+	}
+
+	.uni-badge--success {
+		color: $uni-text-color-inverse;
+		background-color: $uni-color-success;
+	}
+
+	.uni-badge--success-inverted {
+		color: $uni-color-success;
+		background-color: transparent;
+	}
+
+	.uni-badge--warning {
+		color: $uni-text-color-inverse;
+		background-color: $uni-color-warning;
+	}
+
+	.uni-badge--warning-inverted {
+		color: $uni-color-warning;
+		background-color: transparent;
+	}
+
+	.uni-badge--error {
+		color: $uni-text-color-inverse;
+		background-color: $uni-color-error;
+	}
+
+	.uni-badge--error-inverted {
+		color: $uni-color-error;
+		background-color: transparent;
+	}
+
+	.uni-badge--small {
+		transform: $bage-small;
+		transform-origin: center center;
+	}
+</style>

+ 96 - 0
components/uni-icons/icons.js

@@ -0,0 +1,96 @@
+export default {
+	'contact': '\ue100',
+	'person': '\ue101',
+	'personadd': '\ue102',
+	'contact-filled': '\ue130',
+	'person-filled': '\ue131',
+	'personadd-filled': '\ue132',
+	'phone': '\ue200',
+	'email': '\ue201',
+	'chatbubble': '\ue202',
+	'chatboxes': '\ue203',
+	'phone-filled': '\ue230',
+	'email-filled': '\ue231',
+	'chatbubble-filled': '\ue232',
+	'chatboxes-filled': '\ue233',
+	'weibo': '\ue260',
+	'weixin': '\ue261',
+	'pengyouquan': '\ue262',
+	'chat': '\ue263',
+	'qq': '\ue264',
+	'videocam': '\ue300',
+	'camera': '\ue301',
+	'mic': '\ue302',
+	'location': '\ue303',
+	'mic-filled': '\ue332',
+	'speech': '\ue332',
+	'location-filled': '\ue333',
+	'micoff': '\ue360',
+	'image': '\ue363',
+	'map': '\ue364',
+	'compose': '\ue400',
+	'trash': '\ue401',
+	'upload': '\ue402',
+	'download': '\ue403',
+	'close': '\ue404',
+	'redo': '\ue405',
+	'undo': '\ue406',
+	'refresh': '\ue407',
+	'star': '\ue408',
+	'plus': '\ue409',
+	'minus': '\ue410',
+	'circle': '\ue411',
+	'checkbox': '\ue411',
+	'close-filled': '\ue434',
+	'clear': '\ue434',
+	'refresh-filled': '\ue437',
+	'star-filled': '\ue438',
+	'plus-filled': '\ue439',
+	'minus-filled': '\ue440',
+	'circle-filled': '\ue441',
+	'checkbox-filled': '\ue442',
+	'closeempty': '\ue460',
+	'refreshempty': '\ue461',
+	'reload': '\ue462',
+	'starhalf': '\ue463',
+	'spinner': '\ue464',
+	'spinner-cycle': '\ue465',
+	'search': '\ue466',
+	'plusempty': '\ue468',
+	'forward': '\ue470',
+	'back': '\ue471',
+	'left-nav': '\ue471',
+	'checkmarkempty': '\ue472',
+	'home': '\ue500',
+	'navigate': '\ue501',
+	'gear': '\ue502',
+	'paperplane': '\ue503',
+	'info': '\ue504',
+	'help': '\ue505',
+	'locked': '\ue506',
+	'more': '\ue507',
+	'flag': '\ue508',
+	'home-filled': '\ue530',
+	'gear-filled': '\ue532',
+	'info-filled': '\ue534',
+	'help-filled': '\ue535',
+	'more-filled': '\ue537',
+	'settings': '\ue560',
+	'list': '\ue562',
+	'bars': '\ue563',
+	'loop': '\ue565',
+	'paperclip': '\ue567',
+	'eye': '\ue568',
+	'arrowup': '\ue580',
+	'arrowdown': '\ue581',
+	'arrowleft': '\ue582',
+	'arrowright': '\ue583',
+	'arrowthinup': '\ue584',
+	'arrowthindown': '\ue585',
+	'arrowthinleft': '\ue586',
+	'arrowthinright': '\ue587',
+	'pulldown': '\ue588',
+	'closefill': '\ue589',
+	'sound': '\ue590',
+	'scan': '\ue612'
+}

Dosya farkı çok büyük olduğundan ihmal edildi
+ 10 - 0
components/uni-icons/uni-icons.vue


+ 109 - 0
components/uni-keyword/uni-keyword.vue

@@ -0,0 +1,109 @@
+<template>
+	<view class="keyborad" :style="{transform:show_key?'translateY(0)':'translateY(100%)'}">
+		<view class="key_main">
+			<view class="main_title">
+				<view class="close-but" v-if="showCose">
+					<image src="../../static/theme/default/my/del_1.png" mode="aspectFill" @tap="hideFun"></image>
+				</view>
+				<text class="set" :set_msg="set_msg">{{set_msg}}</text>
+				<text class="msg">{{set_info}}</text>
+			</view>
+			<view class="main_content">
+				<view class="content_num">
+					<view v-for="item in 6" :key="item" class="content_item">{{password[item-1] ? '●' :''}}</view>
+				</view>
+			</view>
+			<view class="main_keyboard">
+				<view class="key_num" v-for="item in 9" :key="item" @tap="inputNumFun({num:item})">
+                    {{item}}
+                </view>
+				<view class="key_null"></view>
+				<view class="key_0"  @tap="inputNumFun({num:0})">0</view>
+				<view class="key_del" @tap="delNumFun">
+					<image src="../../static/theme/default/my/del_2.png" mode="aspectFill"></image>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default{
+		props:{
+			show_key:Boolean,
+            set_msg:String,
+			set_info:String,
+			showCose:{
+				type: Boolean,
+				default: false
+			}
+		},
+		computed:{},
+		data(){
+			return{
+				password:''
+			}
+		},
+		methods:{
+			inputNumFun(op){
+				let _this = this
+				if(_this.password.length <=6){
+					_this.password += op.num
+					if(_this.password.length == 6){
+						_this.$emit('getPassword',{password:_this.password})
+					}
+				}
+
+			},
+			delNumFun(){
+				if(this.password.length == 0) return
+				this.password = this.password.substring(0,this.password.length - 1)
+				console.log("删除后的结果",this.password)
+			},
+			forgetFun(){
+			},
+			hideFun(){
+				this.$emit('hideFun')
+			},
+            cleanNum(){
+			    this.password = '';
+            }
+		}
+	}
+</script>
+
+<style lang="scss">
+	.keyborad{width:100vw;height: 100vh;position: fixed;bottom: 0px;top:0px;left:0px;right:0px;z-index:100;display: flex;flex-direction: column;justify-content: flex-end;transform: translateY(100%);transition:all 0.4s;background-color: white;
+		.key_main{ width:100vw;height: 1000rpx;background: rgba(245,245,245,0.9);box-sizing: border-box;display: flex;flex-direction: column;justify-content: space-between;background-color: white;
+			.main_title{ font-size:34rpx;color: #000000;display: flex;align-items: center;letter-spacing: 2rpx;width:100%;;padding:0px 20rpx;
+				image{ width:48rpx;height: 48rpx;}
+				text{ flex:1;margin-left:-48rpx;display: flex;justify-content: center;padding: 10upx 0;}
+			}
+			.main_content{ width:100%;box-sizing: border-box;padding:0px 30rpx;
+				.content_num{ width:100%;height: 100rpx;border:2rpx solid #DBDBDB;border-radius: 10rpx;display: flex;align-items: center;
+					.content_item{ flex: 1;height: 100%;border-right: 2rpx solid #DBDBDB;display: flex;justify-content: center;align-items: center;}
+					.content_item:last-child{ border-right:none}
+				}
+				.main_forget{ display: flex;justify-content: center;align-items: center;width:100%;font-size:28rpx;color: #007AFF;margin-top:40rpx}
+			}
+			.main_keyboard{ width:100%;height: 500rpx;background: #FFFFFF;display: flex;flex-flow: wrap;
+				.key_null,.key_del{ background: #e2e7eb;}
+				image{ width:48rpx;height: 48rpx;}
+				.key_num,.key_null,.key_del,.key_0{ width:250rpx;height: 125rpx;display: flex;align-items: center;justify-content: center;}
+				.key_num{ border-right:2rpx solid #f1f4f4;border-bottom:2rpx solid #f1f4f4;box-sizing: border-box;border-top: 2rpx solid #f1f4f4;}
+				.key_num:nth-child(8){border-bottom: none;}
+				.key_0{ border-top:2rpx solid #f1f4f4}
+			}
+		}
+	}
+    .main_title{display: flex;flex-direction: column;}
+    .set{font-size: 22px;font-weight: 400}
+    .msg{font-weight: 400}
+	.close-but image{
+		display: flex;
+		justify-content: space-around;
+	}
+	.close-but{
+		width: 100%;
+	}
+</style>

+ 290 - 0
components/uni-list-item/uni-list-item.vue

@@ -0,0 +1,290 @@
+<template>
+	<!-- #ifdef APP-NVUE -->
+	<cell>
+		<!-- #endif -->
+		<view :class="disabled ? 'uni-list-item--disabled' : ''" :hover-class="disabled || showSwitch ? '' : 'uni-list-item--hover'"
+		 class="uni-list-item" @click="onClick">
+			<view class="uni-list-item__container" :class="{'uni-list-item--first':isFirstChild}">
+				<view v-if="thumb" class="uni-list-item__icon">
+					<image :src="thumb" class="uni-list-item__icon-img" />
+				</view>
+				<view v-else-if="showExtraIcon" class="uni-list-item__icon">
+					<uni-icons :color="extraIcon.color" :size="extraIcon.size" :type="extraIcon.type" class="uni-icon-wrapper" />
+				</view>
+				<view class="uni-list-item__content">
+					<slot />
+					<text class="uni-list-item__content-title">{{ title }}</text>
+					<text v-if="note" class="uni-list-item__content-note">{{ note }}</text>
+				</view>
+				<view class="uni-list-item__extra">
+					<text v-if="rightText" class="uni-list-item__extra-text">{{rightText}}</text>
+					<image v-if="rightImage" :src="rightImage" class="uni-list-item__image"></image>
+					<uni-badge v-if="showBadge" :type="badgeType" :text="badgeText" />
+					<switch v-if="showSwitch" :disabled="disabled" :checked="switchChecked" @change="onSwitchChange" />
+					<slot name="right"></slot>
+					<uni-icons v-if="showArrow" :size="20" class="uni-icon-wrapper" color="#bbb" type="arrowright" />
+				</view>
+			</view>
+		</view>
+		<!-- #ifdef APP-NVUE -->
+	</cell>
+	<!-- #endif -->
+</template>
+
+<script>
+	import uniIcons from '../uni-icons/uni-icons.vue'
+	import uniBadge from '../uni-badge/uni-badge.vue'
+
+	/**
+	 * ListItem 列表子组件
+	 * @description 列表子组件
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=24
+	 * @property {String} title 标题
+	 * @property {String} note 描述
+	 * @property {String} thumb 左侧缩略图,若thumb有值,则不会显示扩展图标
+	 * @property {String} badgeText 数字角标内容
+	 * @property {String} badgeType 数字角标类型,参考[uni-icons](https://ext.dcloud.net.cn/plugin?id=21)
+	 * @property {String} rightText 右侧文字内容
+	 * @property {Boolean} disabled = [true|false]是否禁用
+	 * @property {Boolean} showArrow = [true|false] 是否显示箭头图标
+	 * @property {Boolean} showBadge = [true|false] 是否显示数字角标
+	 * @property {Boolean} showSwitch = [true|false] 是否显示Switch
+	 * @property {Boolean} switchChecked = [true|false] Switch是否被选中
+	 * @property {Boolean} showExtraIcon = [true|false] 左侧是否显示扩展图标
+	 * @property {Boolean} scrollY = [true|false] 允许纵向滚动,需要显式的设置其宽高
+	 * @property {Object} extraIcon 扩展图标参数,格式为 {color: '#4cd964',size: '22',type: 'spinner'}
+	 * @event {Function} click 点击 uniListItem 触发事件
+	 * @event {Function} switchChange 点击切换 Switch 时触发
+	 */
+	export default {
+		name: 'UniListItem',
+		components: {
+			uniIcons,
+			uniBadge
+		},
+		props: {
+			rightImage:{
+				type: String,
+				default: ''
+			},
+			title: {
+				type: String,
+				default: ''
+			}, // 列表标题
+			note: {
+				type: String,
+				default: ''
+			}, // 列表描述
+			disabled: {
+				// 是否禁用
+				type: [Boolean, String],
+				default: false
+			},
+			showArrow: {
+				// 是否显示箭头
+				type: [Boolean, String],
+				default: true
+			},
+			showBadge: {
+				// 是否显示数字角标
+				type: [Boolean, String],
+				default: false
+			},
+			showSwitch: {
+				// 是否显示Switch
+				type: [Boolean, String],
+				default: false
+			},
+			switchChecked: {
+				// Switch是否被选中
+				type: [Boolean, String],
+				default: false
+			},
+			badgeText: {
+				// badge内容
+				type: String,
+				default: ''
+			},
+			badgeType: {
+				// badge类型
+				type: String,
+				default: 'success'
+			},
+			rightText: {
+				// 右侧文字内容
+				type: String,
+				default: ''
+			},
+			thumb: {
+				// 缩略图
+				type: String,
+				default: ''
+			},
+			showExtraIcon: {
+				// 是否显示扩展图标
+				type: [Boolean, String],
+				default: false
+			},
+			extraIcon: {
+				type: Object,
+				default () {
+					return {
+						type: 'contact',
+						color: '#000000',
+						size: 20
+					}
+				}
+			}
+		},
+		inject: ['list'],
+		data() {
+			return {
+				isFirstChild: false
+			}
+		},
+		mounted() {
+			if (!this.list.firstChildAppend) {
+				this.list.firstChildAppend = true
+				this.isFirstChild = true
+			}
+		},
+		methods: {
+			onClick() {
+				this.$emit('click')
+			},
+			setTitle(title){
+				this.title = 	title
+			},
+			onSwitchChange(e) {
+				this.$emit('switchChange', e.detail)
+			}
+		}
+	}
+</script>
+<!--padding-left: $uni-spacing-row-lg;-->
+<style lang="scss" scoped>
+	$list-item-pd: $uni-spacing-col-lg $uni-spacing-row-lg;
+
+	.uni-list-item {
+		font-size: $uni-font-size-lg;
+		position: relative;
+		flex-direction: column;
+		justify-content: space-between;
+
+	}
+
+	.uni-list-item--disabled {
+		opacity: 0.3;
+	}
+
+	.uni-list-item--hover {
+		background-color: $uni-bg-color-hover;
+	}
+
+	.uni-list-item__container {
+		position: relative;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		padding: $list-item-pd;
+		padding-left: 12px;
+		flex: 1;
+		position: relative;
+		justify-content: space-between;
+		align-items: center;
+		/* #ifdef APP-PLUS */
+		border-top-color: $uni-border-color;
+		border-top-style: solid;
+		border-top-width: 0.5px;
+		/* #endif */
+
+	}
+
+	.uni-list-item--first {
+		border-top-width: 0px;
+	}
+
+	/* #ifndef APP-NVUE */
+	.uni-list-item__container:after {
+		position: absolute;
+		top: 0;
+		right: 0;
+		left: 0;
+		height: 1px;
+		content: '';
+		-webkit-transform: scaleY(.5);
+		transform: scaleY(.5);
+		background-color: $uni-border-color;
+	}
+
+	.uni-list-item--first:after {
+		height: 0px;
+	}
+
+	/* #endif */
+
+
+
+
+
+	.uni-list-item__content {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex: 1;
+		overflow: hidden;
+		flex-direction: column;
+		color: #3b4144;
+
+	}
+
+	.uni-list-item__content-title {
+		font-size: 13px;
+		color: black;
+		font-weight: 400;
+		margin-left: 10px;
+		margin-right: 10px;
+	}
+
+	.uni-list-item__content-note {
+		margin-top: 6rpx;
+		color: $uni-text-color-grey;
+		font-size: $uni-font-size-sm;
+		overflow: hidden;
+	}
+
+	.uni-list-item__extra {
+		// width: 25%;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: flex-end;
+		align-items: center;
+	}
+
+	.uni-list-item__icon {
+		margin-right: 18rpx;
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+	}
+
+	.uni-list-item__icon-img {
+		height: $uni-img-size-base;
+		width: $uni-img-size-base;
+	}
+
+	.uni-list-item__extra-text {
+		color: $uni-text-color-grey;
+		font-size: $uni-font-size-sm;
+		word-break: break-all;
+		width: 400rpx;
+	}
+	.uni-list-item__image{
+		width: 40px;
+		height: 40px;
+		margin-right: 320rpx;
+	}
+</style>

+ 75 - 0
components/uni-list/uni-list.vue

@@ -0,0 +1,75 @@
+<template>
+	<!-- #ifndef APP-NVUE -->
+	<view class="uni-list">
+		<slot />
+	</view>
+	<!-- #endif -->
+	<!-- #ifdef APP-NVUE -->
+	<list class="uni-list" :enableBackToTop="enableBackToTop" loadmoreoffset="15" :scroll-y="scrollY" @loadmore="loadMore">
+		<slot />
+	</list>
+	<!-- #endif -->
+</template>
+
+<script>
+	/**
+	 * List 列表
+	 * @description 列表组件
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=24
+	 */
+	export default {
+		name: 'UniList',
+		'mp-weixin': {
+			options: {
+				multipleSlots: false
+			}
+		},
+		props: {
+			enableBackToTop: {
+				type: [Boolean, String],
+				default: false
+			},
+			scrollY: {
+				type: [Boolean, String],
+				default: false
+			}
+		},
+		provide() {
+			return {
+				list: this
+			}
+		},
+		created() {
+			this.firstChildAppend = false
+		},
+		methods: {
+			loadMore(e) {
+				this.$emit("scrolltolower");
+			}
+		}
+	}
+</script>
+<style lang="scss" scoped>
+	.uni-list {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		background-color: $uni-bg-color;
+		position: relative;
+		flex-direction: column;
+		// border-bottom-color: $uni-border-color;
+		// border-bottom-style: solid;
+		// border-bottom-width: 1px;
+	}
+
+	/* #ifndef APP-NVUE */
+	.uni-list:before {
+		height: 0;
+	}
+
+	.uni-list:after {
+		height: 0;
+	}
+
+	/* #endif */
+</style>

+ 65 - 0
components/uni-list/uni-refresh.vue

@@ -0,0 +1,65 @@
+<template>
+    <!-- #ifdef APP-NVUE -->
+    <refresh :display="display" @refresh="onrefresh" @pullingdown="onpullingdown">
+        <slot />
+    </refresh>
+    <!-- #endif -->
+    <!-- #ifndef APP-NVUE -->
+    <view ref="uni-refresh" class="uni-refresh" v-show="isShow">
+        <slot />
+    </view>
+    <!-- #endif -->
+</template>
+
+<script>
+    export default {
+        name: 'UniRefresh',
+        props: {
+            display: {
+                type: [String],
+                default: "hide"
+            }
+        },
+        data() {
+            return {
+                pulling: false
+            }
+        },
+        computed: {
+            isShow() {
+                if (this.display === "show" || this.pulling === true) {
+                    return true;
+                }
+                return false;
+            }
+        },
+        created() {},
+        methods: {
+            onchange(value) {
+                this.pulling = value;
+            },
+            onrefresh(e) {
+                this.$emit("refresh", e);
+            },
+            onpullingdown(e) {
+                // #ifdef APP-NVUE
+                this.$emit("pullingdown", e);
+                // #endif
+                // #ifndef APP-NVUE
+                var detail = {
+                    viewHeight: 90,
+                    pullingDistance: e.height
+                }
+                this.$emit("pullingdown", detail);
+                // #endif
+            }
+        }
+    }
+</script>
+
+<style>
+    .uni-refresh {
+        height: 0;
+        overflow: hidden;
+    }
+</style>

+ 87 - 0
components/uni-list/uni-refresh.wxs

@@ -0,0 +1,87 @@
+var pullDown = {
+    threshold: 95,
+    maxHeight: 200,
+    callRefresh: 'onrefresh',
+    callPullingDown: 'onpullingdown',
+    refreshSelector: '.uni-refresh'
+};
+
+function ready(newValue, oldValue, ownerInstance, instance) {
+    var state = instance.getState()
+    state.canPullDown = newValue;
+    // console.log(newValue);
+}
+
+function touchStart(e, instance) {
+    var state = instance.getState();
+    state.refreshInstance = instance.selectComponent(pullDown.refreshSelector);
+    state.canPullDown = (state.refreshInstance != null && state.refreshInstance != undefined);
+    if (!state.canPullDown) {
+        return
+    }
+
+    // console.log("touchStart");
+
+    state.height = 0;
+    state.touchStartY = e.touches[0].pageY || e.changedTouches[0].pageY;
+    state.refreshInstance.setStyle({
+        'height': 0
+    });
+    state.refreshInstance.callMethod("onchange", true);
+}
+
+function touchMove(e, ownerInstance) {
+    var instance = e.instance;
+    var state = instance.getState();
+    if (!state.canPullDown) {
+        return
+    }
+
+    var oldHeight = state.height;
+    var endY = e.touches[0].pageY || e.changedTouches[0].pageY;
+    var height = endY - state.touchStartY;
+    if (height > pullDown.maxHeight) {
+        return;
+    }
+
+    var refreshInstance = state.refreshInstance;
+    refreshInstance.setStyle({
+        'height': height + 'px'
+    });
+
+    height = height < pullDown.maxHeight ? height : pullDown.maxHeight;
+    state.height = height;
+    refreshInstance.callMethod(pullDown.callPullingDown, {
+        height: height
+    });
+}
+
+function touchEnd(e, ownerInstance) {
+    var state = e.instance.getState();
+    if (!state.canPullDown) {
+        return
+    }
+
+    state.refreshInstance.callMethod("onchange", false);
+
+    var refreshInstance = state.refreshInstance;
+    if (state.height > pullDown.threshold) {
+        refreshInstance.callMethod(pullDown.callRefresh);
+        return;
+    }
+
+    refreshInstance.setStyle({
+        'height': 0
+    });
+}
+
+function propObserver(newValue, oldValue, instance) {
+    pullDown = newValue;
+}
+
+module.exports = {
+    touchmove: touchMove,
+    touchstart: touchStart,
+    touchend: touchEnd,
+    propObserver: propObserver
+}

+ 22 - 0
components/uni-popup/message.js

@@ -0,0 +1,22 @@
+export default {
+	created() {
+		if (this.type === 'message') {
+			// 不显示遮罩
+			this.maskShow = false 
+			// 获取子组件对象
+			this.childrenMsg = null
+		}
+	},
+	methods: {
+		customOpen() {
+			if (this.childrenMsg) {
+				this.childrenMsg.open()
+			}
+		},
+		customClose() {
+			if (this.childrenMsg) {
+				this.childrenMsg.close()
+			}
+		}
+	}
+}

+ 37 - 0
components/uni-popup/popup.js

@@ -0,0 +1,37 @@
+import message from './message.js';
+// 定义 type 类型:弹出类型:top/bottom/center
+const config = {
+	// 顶部弹出
+	top:'top',
+	// 底部弹出
+	bottom:'bottom',
+	// 居中弹出
+	center:'center',
+	// 消息提示
+	message:'top',
+	// 对话框
+	dialog:'center',
+	// 分享
+	share:'bottom',
+	//列表
+	list:'bottom',
+	confirm:'center',
+	//列表
+	address:'bottom',
+	//列表
+	qiang:'center',
+	//列表
+	form:'center',
+	//图片列表
+	img:'center',
+	alert:'center',
+}
+
+export default {
+	data(){
+		return {
+			config:config
+		}
+	},
+	mixins: [message],
+}

+ 330 - 0
components/uni-popup/uni-popup-address.vue

@@ -0,0 +1,330 @@
+<template>
+	<view class="uni-popup-dialog">
+		<view class="uni-dialog-title">
+			<!--<text class="uni-dialog-title-text" :class="['uni-popup__'+dialogType]">{{title}}</text>-->
+			<!--<text>保健品一件</text>-->
+			<view class="uni-popup-image">
+				<image :src="small_pic" style="width: 50px;height: 50px;"></image>
+			</view>
+			<view class="uni-popup-info">
+				 <text>¥{{amount}}</text>
+				 <text>{{goods_name}}</text>
+			</view>
+			<view class="iconfont-im icon-close fix-icon-title" @tap="close"></view>
+		</view>
+		
+		<view class="uni-dialog-content">
+			<view class="uni-content-ceil" style="margin-right: 110rpx;">
+				<view class="uni-content-ceil-title" >
+					<text>收货地址:</text>
+				</view>
+				<pick-regions :defaultRegion="userAddress.regionCode" @getRegion="handleGetRegion"  ref="regions">
+					<view  style="font-size: 16px;font-weight: 400" class="uni-content-ceil-input uni-input-input"   >{{userAddress.regionStr ? userAddress.regionStr : '请点击选择地址'}} </view>
+				</pick-regions>
+			</view>
+			<view class="uni-content-ceil">
+				<view class="uni-content-ceil-title">
+					<text>详细地址:</text>
+				</view>
+				<input type="text" :value="userAddress.address" @input="address" placeholder="请输入详细地址" class="uni-content-ceil-input" />
+			</view>
+			
+			<view class="uni-content-ceil">
+				<view class="uni-content-ceil-title">
+					<text>收货人:</text>
+				</view>
+				<input type="text" :value="userAddress.username" @input="username" placeholder="请输入收货人" class="uni-content-ceil-input" />
+			</view>
+			<view class="uni-content-ceil">
+				<view class="uni-content-ceil-title">
+					<text>手机号:</text>
+				</view>
+				<input type="number" :value="userAddress.mobile" maxlength="11" @input="mobile" placeholder="请输入手机号" class="uni-content-ceil-input" />
+			</view>
+			
+		</view>
+		<view class="uni-dialog-button-group">
+			<button type="primary" @tap="onOk" style="width: 80%;border-radius: 30px;">支付</button>
+		</view>
+		
+	</view>
+</template>
+
+<script>
+	/**
+	 * PopUp 弹出层-对话框样式
+	 * @description 弹出层-对话框样式
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=329
+	 * @property {String} value input 模式下的默认值
+	 * @property {String} placeholder input 模式下输入提示
+	 * @property {String} type = [success|warning|info|error] 主题样式
+	 *  @value success 成功
+	 * 	@value warning 提示
+	 * 	@value info 消息
+	 * 	@value error 错误
+	 * @property {String} mode = [base|input] 模式、
+	 * 	@value base 基础对话框
+	 * 	@value input 可输入对话框
+	 * @property {String} content 对话框内容
+	 * @property {Boolean} beforeClose 是否拦截取消事件
+	 * @event {Function} confirm 点击确认按钮触发
+	 * @event {Function} close 点击取消按钮触发
+	 */
+	import pickRegions from '@/components/pick-regions/pick-regions.vue';
+	export default {
+		name: "uniPopupAddress",
+		props: {
+			value: {
+				type: [String, Number],
+				default: ''
+			},
+			maxlength:{
+				type: Number,
+				default: 10
+			},
+			placeholder: {
+				type: [String, Number],
+				default: '请输入内容'
+			},
+			/**
+			 * 对话框主题 success/warning/info/error	  默认 success
+			 */
+			type: {
+				type: String,
+				default: 'error'
+			},
+			/**
+			 * 对话框模式 base/input
+			 */
+			mode: {
+				type: String,
+				default: 'base'
+			},
+			/**
+			 * 对话框标题
+			 */
+			title: {
+				type: String,
+				default: '提示'
+			},
+			/**
+			 * 对话框内容
+			 */
+			content: {
+				type: String,
+				default: ''
+			},
+			/**
+			 * 拦截取消事件 ,如果拦截取消事件,必须监听close事件,执行 done()
+			 */
+			beforeClose: {
+				type: Boolean,
+				default: false
+			},
+			small_pic: {
+				type: String,
+				default: ''
+			},
+			goods_name: {
+				type: String,
+				default: ''
+			},
+			amount: {
+				type: String,
+				default: ''
+			},
+			userAddress:{
+				type:Object,
+				default:()=>{
+					return {
+						regionStr: '',
+						username: '',
+						mobile: '',
+						address: '',
+						regionCode:'440113'
+					}
+				}
+			}
+		},
+		data() {
+			return {
+				dialogType: 'error',
+				focus: false,
+				val: ""
+			}
+		},
+		components:{
+			pickRegions
+		},
+		inject: ['popup'],
+		watch: {
+			type(val) {
+				this.dialogType = val
+			},
+			mode(val) {
+				if (val === 'input') {
+					this.dialogType = 'info'
+				}
+			},
+			value(val) {
+				this.val = val
+			}
+		},
+		created() {
+			// 对话框遮罩不可点击
+			this.popup.mkclick = false
+			if (this.mode === 'input') {
+				this.dialogType = 'info'
+				this.val = this.value
+			} else {
+				this.dialogType = this.type
+			}
+		},
+		mounted() {
+			this.focus = true
+		},
+		methods: {
+			username(e){
+				console.log(e.detail.value)
+				return this.userAddress.username = e.detail.value;
+			},
+			mobile(e){
+				return this.userAddress.mobile = e.detail.value;
+			},
+			address(e){
+				return this.userAddress.address = e.detail.value;
+			},
+			handleGetRegion(region){
+				this.userAddress.regionStr =region[0]['name']+region[1]['name']+region[2]['name'];
+				this.userAddress.regionCode = region[2]['code'] ? region[2]['code'] : region[1]['code'];
+			},
+			onOk() {
+				//判断手机号
+				if(this.userAddress.regionStr == '')return uni.showToast({title:"请选择地址",icon:'none'});
+				if(this.userAddress.address == '')return uni.showToast({title:"请输入详细地址",icon:'none'});
+				if(this.userAddress.mobile == '')return uni.showToast({title:"请输入手机号",icon:'none'});
+				if(this.userAddress.username == '')return uni.showToast({title:"请输入收货人",icon:'none'});
+				this.$emit('confirm',this.userAddress)
+			},
+			/**
+			 * 点击取消按钮
+			 */
+			close() {
+				if (this.beforeClose) {
+					this.$emit('close', () => {
+						this.popup.close()
+					})
+					return
+				}
+				this.popup.close()
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.uni-popup-dialog {
+		background-color: #fff;
+	}
+	.uni-popup-dialog button{
+		line-height: unset;
+	}
+	.fix-icon-title{
+		position: relative;
+	}
+	.uni-dialog-title {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: flex-start;
+		padding: 20px 20px;
+	}
+	.icon-close:before{
+		content: "\e620";
+		position: absolute;
+		display:block;
+		width: 0;
+		height: 0;
+		left: 360rpx;
+		top: -20rpx;
+	 }
+
+	.uni-popup-image{
+		display: flex;
+		justify-content: center;
+		align-items: center;
+	}
+	.uni-popup-info {
+		display: flex;
+		flex-direction: column;
+		margin-left: 20px;
+	}
+
+	.uni-dialog-content {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+	}
+
+	.uni-dialog-content-text {
+		font-size: 14px;
+		color: #6e6e6e;
+	}
+
+	.uni-dialog-button-group {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		padding: 10px 0;
+	}
+
+
+	.uni-dialog-input {
+		flex: 1;
+		font-size: 14px;
+		overflow: visible !important;
+		line-height :1.9rem !important;
+		height:1.9rem !important;
+		border-radius: 10px;
+		padding-left:2px;
+		background-color: #eeeeee;
+	}
+
+	.uni-popup__success {
+		color: $uni-color-success;
+	}
+
+	.uni-popup__warn {
+		color: $uni-color-warning;
+	}
+
+	.uni-popup__error {
+		color: $uni-color-error;
+	}
+
+	.uni-popup__info {
+		color: #909399;
+	}
+	.uni-content-ceil{
+		display: flex;
+		flex-direction: row;
+		justify-content: center;
+		width: 100%;
+		padding: 8px 0;
+	}
+	.uni-content-ceil-title{
+		font-size: 16px;
+		margin-right: 10upx;
+	}
+	.uni-content-ceil-input{
+		border-bottom: 1upx solid #A9A9A9;
+		padding: 0 50rpx;
+		justify-content:space-around;
+
+	}
+</style>

+ 234 - 0
components/uni-popup/uni-popup-alert.vue

@@ -0,0 +1,234 @@
+<template>
+	<view class="uni-popup-dialog">
+		<view class="uni-dialog-title">
+			<text class="uni-dialog-title-text" :class="['uni-popup__'+dialogType]">{{title}}</text>
+		</view>
+		<view class="uni-dialog-content">
+			<text class="uni-dialog-content-text" v-if="mode === 'base'">{{content}}</text>
+			<input v-else class="uni-dialog-input" v-model="val" type="text" :placeholder="placeholder" :focus="focus" >
+		</view>
+	</view>
+</template>
+
+<script>
+	/**
+	 * PopUp 弹出层-对话框样式
+	 * @description 弹出层-对话框样式
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=329
+	 * @property {String} value input 模式下的默认值
+	 * @property {String} placeholder input 模式下输入提示
+	 * @property {String} type = [success|warning|info|error] 主题样式
+	 *  @value success 成功
+	 * 	@value warning 提示
+	 * 	@value info 消息
+	 * 	@value error 错误
+	 * @property {String} mode = [base|input] 模式、
+	 * 	@value base 基础对话框
+	 * 	@value input 可输入对话框
+	 * @property {String} content 对话框内容
+	 * @property {Boolean} beforeClose 是否拦截取消事件
+	 * @event {Function} confirm 点击确认按钮触发
+	 * @event {Function} close 点击取消按钮触发
+	 */
+
+	export default {
+		name: "uniPopupAlert",
+		props: {
+			value: {
+				type: [String, Number],
+				default: ''
+			},
+			placeholder: {
+				type: [String, Number],
+				default: '请输入内容'
+			},
+			/**
+			 * 对话框主题 success/warning/info/error	  默认 success
+			 */
+			type: {
+				type: String,
+				default: 'error'
+			},
+			/**
+			 * 对话框模式 base/input
+			 */
+			mode: {
+				type: String,
+				default: 'base'
+			},
+			/**
+			 * 对话框标题
+			 */
+			title: {
+				type: String,
+				default: '提示'
+			},
+			/**
+			 * 对话框内容
+			 */
+			content: {
+				type: String,
+				default: ''
+			},
+			/**
+			 * 拦截取消事件 ,如果拦截取消事件,必须监听close事件,执行 done()
+			 */
+			beforeClose: {
+				type: Boolean,
+				default: false
+			}
+		},
+		data() {
+			return {
+				dialogType: 'error',
+				focus: false,
+				val: ""
+			}
+		},
+		inject: ['popup'],
+		watch: {
+			type(val) {
+				this.dialogType = val
+			},
+			mode(val) {
+				if (val === 'input') {
+					this.dialogType = 'info'
+				}
+			},
+			value(val) {
+				this.val = val
+			}
+		},
+		created() {
+			// 对话框遮罩不可点击
+			this.popup.mkclick = false
+			if (this.mode === 'input') {
+				this.dialogType = 'info'
+				this.val = this.value
+			} else {
+				this.dialogType = this.type
+			}
+		},
+		mounted() {
+			this.focus = true
+		},
+		methods: {
+			/**
+			 * 点击确认按钮
+			 */
+			onOk() {
+				this.$emit('confirm', () => {
+					this.popup.close()
+					if (this.mode === 'input') this.val = this.value
+				}, this.mode === 'input' ? this.val : '')
+			},
+			/**
+			 * 点击取消按钮
+			 */
+			close() {
+				if (this.beforeClose) {
+					this.$emit('close', () => {
+						this.popup.close()
+					})
+					return
+				}
+				this.popup.close()
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.uni-popup-dialog {
+		width: 300px;
+		border-radius: 15px;
+		background-color: #fff;
+	}
+
+	.uni-dialog-title {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: center;
+		padding-top: 15px;
+		padding-bottom: 5px;
+	}
+
+	.uni-dialog-title-text {
+		font-size: 16px;
+		font-weight: 500;
+	}
+
+	.uni-dialog-content {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		padding: 5px 15px 15px 15px;
+	}
+
+	.uni-dialog-content-text {
+		font-size: 14px;
+		color: #6e6e6e;
+	}
+
+	.uni-dialog-button-group {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		border-top-color: #f5f5f5;
+		border-top-style: solid;
+		border-top-width: 1px;
+	}
+
+	.uni-dialog-button {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+
+		flex: 1;
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		height: 45px;
+	}
+
+	.uni-border-left {
+		border-left-color: #f0f0f0;
+		border-left-style: solid;
+		border-left-width: 1px;
+	}
+
+	.uni-dialog-button-text {
+		font-size: 14px;
+	}
+
+	.uni-button-color {
+		color: $uni-color-primary;
+	}
+
+	.uni-dialog-input {
+		flex: 1;
+		font-size: 14px;
+	}
+
+	.uni-popup__success {
+		color: $uni-color-success;
+	}
+
+	.uni-popup__warn {
+		color: $uni-color-warning;
+	}
+
+	.uni-popup__error {
+		color: $uni-color-error;
+	}
+
+	.uni-popup__info {
+		color: #909399;
+	}
+</style>

+ 254 - 0
components/uni-popup/uni-popup-confirm.vue

@@ -0,0 +1,254 @@
+<template>
+	<view class="uni-popup-dialog">
+		<view class="uni-dialog-title">
+			<text class="uni-dialog-title-text" :class="['uni-popup__'+dialogType]">{{title}}</text>
+		</view>
+		<view class="uni-dialog-content">
+			<text class="uni-dialog-content-text" v-if="mode === 'base'">{{content}}</text>
+			<input v-else class="uni-dialog-input" :maxlength="maxlength" v-model="val" type="text" :placeholder="placeholder" :focus="focus" >
+		</view>
+		<view class="uni-dialog-button-group">
+			<view class="uni-dialog-button" @click="close">
+				<text class="uni-dialog-button-text">取消</text>
+			</view>
+			<view class="uni-dialog-button uni-border-left" @click="onOk">
+				<text class="uni-dialog-button-text uni-button-color">确定</text>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	/**
+	 * PopUp 弹出层-对话框样式
+	 * @description 弹出层-对话框样式
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=329
+	 * @property {String} value input 模式下的默认值
+	 * @property {String} placeholder input 模式下输入提示
+	 * @property {String} type = [success|warning|info|error] 主题样式
+	 *  @value success 成功
+	 * 	@value warning 提示
+	 * 	@value info 消息
+	 * 	@value error 错误
+	 * @property {String} mode = [base|input] 模式、
+	 * 	@value base 基础对话框
+	 * 	@value input 可输入对话框
+	 * @property {String} content 对话框内容
+	 * @property {Boolean} beforeClose 是否拦截取消事件
+	 * @event {Function} confirm 点击确认按钮触发
+	 * @event {Function} close 点击取消按钮触发
+	 */
+
+	export default {
+		name: "uniPopupDialog",
+		props: {
+			value: {
+				type: [String, Number],
+				default: ''
+			},
+			maxlength:{
+				type: Number,
+				default: 10
+			},
+			placeholder: {
+				type: [String, Number],
+				default: '请输入内容'
+			},
+			/**
+			 * 对话框主题 success/warning/info/error	  默认 success
+			 */
+			type: {
+				type: String,
+				default: 'error'
+			},
+			/**
+			 * 对话框模式 base/input
+			 */
+			mode: {
+				type: String,
+				default: 'base'
+			},
+			/**
+			 * 对话框标题
+			 */
+			title: {
+				type: String,
+				default: '提示'
+			},
+			/**
+			 * 对话框内容
+			 */
+			content: {
+				type: String,
+				default: ''
+			},
+			/**
+			 * 拦截取消事件 ,如果拦截取消事件,必须监听close事件,执行 done()
+			 */
+			beforeClose: {
+				type: Boolean,
+				default: false
+			}
+		},
+		data() {
+			return {
+				dialogType: 'error',
+				focus: false,
+				val: ""
+			}
+		},
+		inject: ['popup'],
+		watch: {
+			type(val) {
+				this.dialogType = val
+			},
+			mode(val) {
+				if (val === 'input') {
+					this.dialogType = 'info'
+				}
+			},
+			value(val) {
+				this.val = val
+			}
+		},
+		created() {
+			// 对话框遮罩不可点击
+			this.popup.mkclick = false
+			if (this.mode === 'input') {
+				this.dialogType = 'info'
+				this.val = this.value
+			} else {
+				this.dialogType = this.type
+			}
+		},
+		mounted() {
+			this.focus = true
+		},
+		methods: {
+			/**
+			 * 点击确认按钮
+			 */
+			onOk() {
+				this.$emit('confirm', () => {
+					this.popup.close()
+					if (this.mode === 'input') {
+						this.val = this.value;
+						return this.val;
+					}
+				}, this.mode === 'input' ? this.val : '')
+			},
+			/**
+			 * 点击取消按钮
+			 */
+			close() {
+				if (this.beforeClose) {
+					this.$emit('close', () => {
+						this.popup.close()
+					})
+					return
+				}
+				this.popup.close()
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.uni-popup-dialog {
+		width: 300px;
+		border-radius: 5px;
+		background-color: #fff;
+	}
+
+	.uni-dialog-title {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: flex-start;
+		padding: 20px 0 10px 15px;
+	}
+
+	.uni-dialog-title-text {
+		font-size: 16px;
+		font-weight: 500;
+	}
+
+	.uni-dialog-content {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		padding: 5px 15px 15px 15px;
+	}
+
+	.uni-dialog-content-text {
+		font-size: 14px;
+		color: #6e6e6e;
+	}
+
+	.uni-dialog-button-group {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		border-top-color: #bdbdbd;
+		border-top-style: solid;
+		border-top-width: 1px;
+		margin-top:5px;
+	}
+
+	.uni-dialog-button {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+
+		flex: 1;
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		height: 55px;
+	}
+
+	.uni-border-left {
+		border-left-color: #bdbdbd;
+		border-left-style: solid;
+		border-left-width: 1px;
+	}
+
+	.uni-dialog-button-text {
+		font-size: 14px;
+	}
+
+	.uni-button-color {
+	}
+
+	.uni-dialog-input {
+		flex: 1;
+		font-size: 14px;
+		overflow: visible !important;
+		line-height :1.9rem !important;
+		height:1.9rem !important;
+		border-radius: 10px;
+		padding-left:2px;
+		background-color: #eeeeee;
+	}
+
+	.uni-popup__success {
+		color: $uni-color-success;
+	}
+
+	.uni-popup__warn {
+		color: $uni-color-warning;
+	}
+
+	.uni-popup__error {
+		color: $uni-color-error;
+	}
+
+	.uni-popup__info {
+		color: #909399;
+	}
+</style>

+ 242 - 0
components/uni-popup/uni-popup-dialog.vue

@@ -0,0 +1,242 @@
+<template>
+	<view class="uni-popup-dialog">
+		<view class="uni-dialog-title">
+			<text class="uni-dialog-title-text" :class="['uni-popup__'+dialogType]">{{title}}</text>
+		</view>
+		<view class="uni-dialog-content">
+			<text class="uni-dialog-content-text" v-if="mode === 'base'">{{content}}</text>
+			<input v-else class="uni-dialog-input" v-model="val" type="text" :placeholder="placeholder" :focus="focus" >
+		</view>
+		<view class="uni-dialog-button-group">
+			<view class="uni-dialog-button" @click="close">
+				<text class="uni-dialog-button-text">取消</text>
+			</view>
+			<view class="uni-dialog-button uni-border-left" @click="onOk">
+				<text class="uni-dialog-button-text uni-button-color">确定</text>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	/**
+	 * PopUp 弹出层-对话框样式
+	 * @description 弹出层-对话框样式
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=329
+	 * @property {String} value input 模式下的默认值
+	 * @property {String} placeholder input 模式下输入提示
+	 * @property {String} type = [success|warning|info|error] 主题样式
+	 *  @value success 成功
+	 * 	@value warning 提示
+	 * 	@value info 消息
+	 * 	@value error 错误
+	 * @property {String} mode = [base|input] 模式、
+	 * 	@value base 基础对话框
+	 * 	@value input 可输入对话框
+	 * @property {String} content 对话框内容
+	 * @property {Boolean} beforeClose 是否拦截取消事件
+	 * @event {Function} confirm 点击确认按钮触发
+	 * @event {Function} close 点击取消按钮触发
+	 */
+
+	export default {
+		name: "uniPopupDialog",
+		props: {
+			value: {
+				type: [String, Number],
+				default: ''
+			},
+			placeholder: {
+				type: [String, Number],
+				default: '请输入内容'
+			},
+			/**
+			 * 对话框主题 success/warning/info/error	  默认 success
+			 */
+			type: {
+				type: String,
+				default: 'error'
+			},
+			/**
+			 * 对话框模式 base/input
+			 */
+			mode: {
+				type: String,
+				default: 'base'
+			},
+			/**
+			 * 对话框标题
+			 */
+			title: {
+				type: String,
+				default: '提示'
+			},
+			/**
+			 * 对话框内容
+			 */
+			content: {
+				type: String,
+				default: ''
+			},
+			/**
+			 * 拦截取消事件 ,如果拦截取消事件,必须监听close事件,执行 done()
+			 */
+			beforeClose: {
+				type: Boolean,
+				default: false
+			}
+		},
+		data() {
+			return {
+				dialogType: 'error',
+				focus: false,
+				val: ""
+			}
+		},
+		inject: ['popup'],
+		watch: {
+			type(val) {
+				this.dialogType = val
+			},
+			mode(val) {
+				if (val === 'input') {
+					this.dialogType = 'info'
+				}
+			},
+			value(val) {
+				this.val = val
+			}
+		},
+		created() {
+			// 对话框遮罩不可点击
+			this.popup.mkclick = false
+			if (this.mode === 'input') {
+				this.dialogType = 'info'
+				this.val = this.value
+			} else {
+				this.dialogType = this.type
+			}
+		},
+		mounted() {
+			this.focus = true
+		},
+		methods: {
+			/**
+			 * 点击确认按钮
+			 */
+			onOk() {
+				this.$emit('confirm', () => {
+					this.popup.close()
+					if (this.mode === 'input') this.val = this.value
+				}, this.mode === 'input' ? this.val : '')
+			},
+			/**
+			 * 点击取消按钮
+			 */
+			close() {
+				if (this.beforeClose) {
+					this.$emit('close', () => {
+						this.popup.close()
+					})
+					return
+				}
+				this.popup.close()
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.uni-popup-dialog {
+		width: 300px;
+		border-radius: 15px;
+		background-color: #fff;
+	}
+
+	.uni-dialog-title {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: center;
+		padding-top: 15px;
+		padding-bottom: 5px;
+	}
+
+	.uni-dialog-title-text {
+		font-size: 16px;
+		font-weight: 500;
+	}
+
+	.uni-dialog-content {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		padding: 5px 15px 15px 15px;
+	}
+
+	.uni-dialog-content-text {
+		font-size: 14px;
+		color: #6e6e6e;
+	}
+
+	.uni-dialog-button-group {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		border-top-color: #f5f5f5;
+		border-top-style: solid;
+		border-top-width: 1px;
+	}
+
+	.uni-dialog-button {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+
+		flex: 1;
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		height: 45px;
+	}
+
+	.uni-border-left {
+		border-left-color: #f0f0f0;
+		border-left-style: solid;
+		border-left-width: 1px;
+	}
+
+	.uni-dialog-button-text {
+		font-size: 14px;
+	}
+
+	.uni-button-color {
+		color: $uni-color-primary;
+	}
+
+	.uni-dialog-input {
+		flex: 1;
+		font-size: 14px;
+	}
+
+	.uni-popup__success {
+		color: $uni-color-success;
+	}
+
+	.uni-popup__warn {
+		color: $uni-color-warning;
+	}
+
+	.uni-popup__error {
+		color: $uni-color-error;
+	}
+
+	.uni-popup__info {
+		color: #909399;
+	}
+</style>

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor