xiaxiaofeng 7 years ago
parent
commit
b334593e09

+ 24 - 0
LICENSE

@@ -0,0 +1,24 @@
+LICENSE - "MIT License"
+
+Copyright (c) 2016 by Tencent Cloud
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.

+ 51 - 1
README.md

@@ -1 +1,51 @@
-#message
+密件(微信小程序)
+=====================================
+
+本小程序包含:
+
+1. 新建群
+2. 用户申请加入群
+3. 群主管理群
+4. 群主审批申请
+5. 用户参加群列表
+6. 用户可以查看群中的用户的基本信息
+
+
+
+## 源码简介
+
+```tree
+wxgroup
+├── LICENSE
+├── README.md
+├── app.js
+├── app.json
+├── bower.json
+├── config.js
+├── package.json
+├── pages
+│   ├── index(首页)
+│   │   ├── index.js
+│   │   ├── index.wxml
+│   │   └── index.wxss
+│   └── group
+│       ├── add(新建群)
+│       ├── index(群主页)
+│       ├── join(我参加的群列表)
+│       ├── list(我创建的群列表)
+│       ├── manage(群主管理群)
+│       └── user
+|           ├──add(用户申请加入群)
+|           ├──info(用户基本信息)
+|           ├──list(群的用户列表)
+|           └──shenhe(群主审批列表)
+└── vendor
+    └── qcloud-weapp-client-sdk/
+```
+
+`app.js` 是小程序入口文件。
+
+`app.json` 是小程序的微信配置,
+
+`config.js` 是我们小程序自己的业务配置。
+

+ 94 - 0
app.js

@@ -0,0 +1,94 @@
+/**
+ * @fileOverview 微信小程序的入口文件
+ */
+
+var qcloud = require('./vendor/qcloud-weapp-client-sdk/index');
+var config = require('./config');
+var Session = require('./vendor/qcloud-weapp-client-sdk/lib/session');
+
+// 显示繁忙提示
+var showBusy = text => wx.showToast({
+    title: text,
+    icon: 'loading',
+    duration: 10000
+});
+
+// 显示成功提示
+var showSuccess = text => {
+    wx.hideToast();
+    wx.showToast({
+        title: text,
+        icon: 'success'
+    });
+};
+
+// 显示失败提示
+var showModel = (title, content) => {
+    wx.hideToast();
+
+    wx.showModal({
+        title,
+        content: JSON.stringify(content),
+        showCancel: false
+    });
+};
+App({
+    /**
+     * 小程序初始化时执行,我们初始化客户端的登录地址,以支持所有的会话操作
+     */
+    onLaunch() {
+        qcloud.setLoginUrl(config.service.loginUrl);
+        // this.doLogin();
+    },
+    getUserInfo(cb) {
+        var that = this
+        var session=Session.get();
+        if (session && session.id && session.skey) {
+            qcloud.request({
+                // 要请求的地址
+                url: config.service.requestUrl,
+                success(result) {
+                    typeof cb == "function" && cb(result.data.data.userInfo);
+                    console.log('request success', result);
+                },
+
+                fail(error) {
+                    console.log('request fail', error);
+                },
+
+                complete() {
+                    console.log('request complete');
+                }
+            });
+        }else{
+            qcloud.login({
+                success(result) {
+                    showSuccess('登录成功');
+                    console.log('登录成功', result);
+                    qcloud.request({
+                        // 要请求的地址
+                        url: config.service.requestUrl,
+                        success(result) {
+                            typeof cb == "function" && cb(result.data.data.userInfo);
+                            console.log('request success', result);
+                        },
+
+                        fail(error) {
+                            console.log('request fail', error);
+                        },
+
+                        complete() {
+                            console.log('request complete');
+                        }
+                    });
+                },
+
+                fail(error) {
+                    showModel('登录失败', error);
+                    console.log('登录失败', error);
+                }
+            });
+        }
+        
+  }
+});

+ 14 - 0
app.json

@@ -0,0 +1,14 @@
+{
+    "pages": [
+        "pages/index/index",
+        "pages/add/add",
+        "pages/view/view",
+        "pages/send/send"
+    ],
+    "window": {
+        "navigationBarTextStyle": "black",
+        "navigationBarTitleText": "密件",
+        "navigationBarBackgroundColor": "#FBF9FE",
+        "backgroundColor": "#FBF9FE"
+    }
+}

+ 251 - 0
app.wxss

@@ -0,0 +1,251 @@
+/**app.wxss**/
+.container {
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: space-between;
+  padding: 200rpx 0;
+  box-sizing: border-box;
+} 
+page {
+  background-color: #fbf9fe;
+  height: 100%;
+}
+.container {
+  display: flex;
+  flex-direction: column;
+  min-height: 100%;
+  justify-content: space-between;
+}
+.page-header {
+  display: flex;
+  font-size: 32rpx;
+  color: #aaa;
+  margin-top: 50rpx;
+  flex-direction: column;
+  align-items: center;
+}
+.page-header-text {
+  padding: 20rpx 40rpx;
+}
+.page-header-line {
+  width: 150rpx;
+  height: 1px;
+  border-bottom: 1px solid #ccc; 
+}
+
+.page-body {
+  width: 100%;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  flex-grow: 1;
+  overflow-x: hidden;
+}
+.page-body-wrapper {
+  margin-top: 100rpx;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  width: 100%;
+}
+.page-body-wrapper form {
+  width: 100%;
+}
+.page-body-wording {
+  text-align: center;
+  padding: 200rpx 100rpx;
+}
+.page-body-info {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  background-color: #fff;
+  margin-bottom: 50rpx;
+  width: 100%;
+  padding: 50rpx 0 150rpx 0;
+}
+.page-body-title {
+  margin-bottom: 100rpx;
+  font-size: 32rpx;
+}
+.page-body-text {
+  font-size: 30rpx;
+  line-height: 26px;
+  color: #ccc;
+}
+.page-body-text-small {
+  font-size: 24rpx;
+  color: #000;
+  margin-bottom: 100rpx;
+}
+.page-body-form {
+  width: 100%;
+  background-color: #fff;
+  display: flex;
+  flex-direction: column;
+  width: 100%;
+  border: 1px solid #eee;
+}
+.page-body-form-item {
+  display: flex;
+  align-items: center;
+  margin-left: 30rpx;
+  border-bottom: 1px solid #eee;
+  height: 88rpx;
+  font-size: 34rpx;
+}
+.page-body-form-key {
+  width: 180rpx;
+  color: #000;
+}
+.page-body-form-value {
+  flex-grow: 1;
+}
+.page-body-form-value .input-placeholder {
+  color: #b2b2b2;
+}
+
+.page-body-form-picker {
+  display: flex;
+  justify-content: space-between;
+  height: 100rpx;
+  align-items: center;
+  font-size: 36rpx;
+  margin-left: 20rpx;
+  padding-right: 20rpx;
+  border-bottom: 1px solid #eee;
+}
+.page-body-form-picker-value {
+  color: #ccc;
+}
+
+.page-body-buttons {
+  width: 100%;
+}
+.page-body-button {
+  margin: 25rpx;
+}
+.page-body-button image {
+  width: 150rpx;
+  height: 150rpx;
+}
+.page-footer {
+  text-align: center;
+  color: #1aad19;
+  font-size: 24rpx;
+  margin: 20rpx 0;
+}
+
+.green{
+    color: #09BB07;
+}
+.red{
+    color: #F76260;
+}
+.blue{
+    color: #10AEFF;
+}
+.yellow{
+    color: #FFBE00;
+}
+.gray{
+    color: #C9C9C9;
+}
+
+.strong{
+    font-weight: bold;
+}
+
+.bc_green{
+    background-color: #09BB07;
+}
+.bc_red{
+    background-color: #F76260;
+}
+.bc_blue{
+    background-color: #10AEFF;
+}
+.bc_yellow{
+    background-color: #FFBE00;
+}
+.bc_gray{
+    background-color: #C9C9C9;
+}
+
+.tc{
+    text-align: center;
+}
+
+.page input{
+    padding: 20rpx 30rpx;
+    background-color: #fff;
+}
+checkbox, radio{
+    margin-right: 10rpx;
+}
+
+.btn-area{
+    padding: 0 30px;
+}
+.btn-area button{
+    margin-top: 20rpx;
+    margin-bottom: 20rpx;
+}
+
+.page {
+    min-height: 100%;
+    flex: 1;
+    background-color: #FBF9FE;
+    font-size: 32rpx;
+    font-family: -apple-system-font,Helvetica Neue,Helvetica,sans-serif;
+    overflow: hidden;
+}
+.page__hd{
+    padding:200rpx 50rpx 200rpx 50rpx;
+    text-align: center;
+}
+.page__title{
+    display: inline-block;
+    padding: 20rpx 40rpx;
+    font-size: 32rpx;
+    color: #AAAAAA;
+    border-bottom: 1px solid #CCCCCC;
+}
+.page__desc{
+    display: none;
+    margin-top: 20rpx;
+    font-size: 26rpx;
+    color: #BBBBBB;
+}
+
+.section{
+    margin-bottom: 80rpx;
+}
+.section_gap{
+    padding: 0 30rpx;
+}
+.section__title{
+    margin-bottom: 16rpx;
+    padding-left: 30rpx;
+    padding-right: 30rpx;
+}
+.section_gap .section__title{
+    padding-left: 0;
+    padding-right: 0;
+}
+.section__ctn{
+
+}
+
+.title__icon_img{
+  width:80px;
+  height:80px;
+}
+.bottom_title{
+   display: inline-block;
+    padding: 10rpx 40rpx;
+    font-size: 14px;
+    color: #AAAAAA;
+}

+ 27 - 0
bower.json

@@ -0,0 +1,27 @@
+{
+  "name": "qcloud-weapp-client-demo",
+  "description": "QCloud Wechat App Demo",
+  "main": "app.js",
+  "authors": [
+    "Tencent Clound"
+  ],
+  "license": "MIT",
+  "keywords": [
+    "qcloud",
+    "wechat",
+    "weapp",
+    "demo",
+    "sdk"
+  ],
+  "homepage": "",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "test",
+    "tests"
+  ],
+  "dependencies": {
+    "qcloud-weapp-client-sdk": "*"
+  }
+}

+ 37 - 0
config.js

@@ -0,0 +1,37 @@
+/**
+ * 小程序配置文件
+ */
+
+// 此处主机域名修改成腾讯云解决方案分配的域名
+var host = '81391412.qbanling.com';
+
+var config = {
+
+    // 下面的地址配合云端 Demo 工作
+    service: {
+        host,
+
+        // 登录地址,用于建立会话
+        loginUrl: `https://${host}/s/login`,
+
+        // 测试的请求地址,用于测试会话
+        requestUrl: `https://${host}/s/user`,
+
+        //api
+
+        apiUrl:`https://${host}/api/`,
+
+        //上传文件
+
+        uploadUrl:`https://${host}/api/upload`,
+        
+        
+        //新建消息
+
+        messageAddUrl:`https://${host}/api/messages`
+
+    }
+};
+
+
+module.exports = config;

+ 13 - 0
package.json

@@ -0,0 +1,13 @@
+{
+  "name": "qcloud-weapp-client-demo",
+  "version": "1.0.0",
+  "description": "腾讯云微信小程序客户端 DEMO",
+  "main": "app.js",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/tencentyun/weapp-client-demo.git"
+  },
+  "keywords": [],
+  "author": "CFETeam",
+  "license": "MIT"
+}

+ 162 - 0
pages/add/add.js

@@ -0,0 +1,162 @@
+// 引入 QCloud 小程序增强 SDK
+var qcloud = require('../../vendor/qcloud-weapp-client-sdk/index');
+
+// 引入配置
+var config = require('../../config');
+
+// 显示繁忙提示
+var showBusy = text => wx.showToast({
+    title: text,
+    icon: 'loading',
+    duration: 10000
+});
+
+// 显示成功提示
+var showSuccess = text => {
+    wx.hideToast();
+    wx.showToast({
+        title: text,
+        icon: 'success'
+    });
+};
+
+// 显示失败提示
+var showModel = (title, content) => {
+    wx.hideToast();
+
+    wx.showModal({
+        title,
+        content: JSON.stringify(content),
+        showCancel: false
+    });
+};
+var showMsg = (title, content) => {
+    wx.hideToast();
+
+    wx.showModal({
+        title,
+        content: content,
+        showCancel: false
+    });
+};
+//获取应用实例
+var app = getApp()
+Page({
+  data: {
+  "imageSrc":'',
+  "busy":false,
+  "upload_busy":false
+  },
+  onLoad: function () {
+    console.log('onLoad');
+  },
+  onShow: function () {
+    console.log('onShow');
+  },
+  chooseImage: function() {
+    var self = this;
+    if(self.data.upload_busy){
+      return;
+    }
+    wx.chooseImage({
+      count: 1,
+      sizeType: ['compressed'],
+      sourceType: ['album'],
+      success: function(res) {
+        console.log('chooseImage success, temp path is', res.tempFilePaths[0])
+        var imageSrc = res.tempFilePaths[0];
+        self.setData({
+            'upload_busy':true
+        })
+        //上传图片到服务器
+        wx.uploadFile({
+          url: config.service.uploadUrl,
+          filePath: imageSrc,
+          name: 'file',
+          success: function(res) {
+            console.log('uploadImage success, res is:', res);
+            var data=JSON.parse(res.data);
+            console.log(data);
+            if(data.success==true){
+              self.setData({
+                  'imageSrc':data.file.url
+              })
+              showSuccess('上传成功');
+            }else{
+              showMsg('提示信息','上传失败');
+            }
+          },
+          fail: function({errMsg}) {
+            console.log('uploadImage fail, errMsg is', errMsg)
+          },
+          complete:function(){
+            self.setData({
+                'upload_busy':false
+            })
+          }
+        })
+
+      },
+      fail: function({errMsg}) {
+        console.log('chooseImage fail, err is', errMsg)
+      }
+    })
+  },
+  formSubmit: function(e) {
+    var self = this;
+    if(self.data.upload_busy||self.data.busy){
+      return;
+    }
+    if(e.detail.value.text==""&&self.data.imageSrc==""){
+      showMsg("提示信息","内容和图片至少有一个不能为空");
+      return;
+    }
+    var data={};
+    if(e.detail.value.text!=""){
+      data.text=e.detail.value.text;
+    }
+    if(self.data.imageSrc!=""){
+      data.image_url=self.data.imageSrc;
+    }
+    console.log('form发生了submit事件,携带数据为:', e.detail.value);
+    self.setData({
+        'busy':true
+    })
+    qcloud.request({
+            // 要请求的地址
+            url: config.service.messageAddUrl,
+            method:"POST",
+            data: data,
+            success(result) {
+              console.log(result);
+              if(result.data.success==true){
+                 showSuccess("成功");
+                 wx.navigateTo({
+                    url: '/pages/view/view?hash_key='+result.data.id
+                 })
+              }else{
+                showMsg("提示信息","新建消息失败");
+              }
+            },
+
+            fail(error) {
+                console.log('request fail', error);
+                showMsg("提示信息","新建消息失败");
+            },
+
+            complete() {
+                self.setData({
+                      'busy':false
+                  })
+                console.log('request complete');
+            }
+      });
+  },
+  onShareAppMessage: function () {
+    return {
+      title: '密件',
+      desc: '密件',
+      path: 'pages/index/index'
+    }
+  }
+})

+ 1 - 0
pages/add/add.json

@@ -0,0 +1 @@
+{}

+ 38 - 0
pages/add/add.wxml

@@ -0,0 +1,38 @@
+
+<!--add.wxml-->
+<import src="../common/footer.wxml" />
+<form bindsubmit="formSubmit">
+  <view class="page">
+    <template is="head" />
+    <view class="page-body">
+      <view class="page-section">
+        <view class="page-body-info">
+          <block wx:if="{{imageSrc}}">
+            <view bindtap="chooseImage" style="display:inline-block;width:100%;">
+              <image src="{{imageSrc}}" class="image" mode="aspectFit"></image>
+            </view>
+          </block>
+          <block wx:else>
+            <view class="image-plus image-plus-nb" bindtap="chooseImage">
+              <view class="image-plus-horizontal"></view>
+              <view class="image-plus-vertical"></view>
+            </view>
+            <view class="image-plus-text">选择图片</view>
+          </block>
+        </view>
+      </view>
+      <view class="page-section">
+        <view class="page-section-title">内容</view>
+        <view class="textarea-wrp">
+          <textarea name="text" auto-height placeholder="请输入内容" />
+        </view>
+      </view>
+      <view class="page-section">
+        <view class="button-wrapper">
+          <button type="primary" loading="{{busy ? true : false}}" disabled="{{busy ? true : false}}" formType="submit">提交</button>
+        </view>
+      </view>
+    </view>
+    <template is="foot" />
+  </view>
+</form>

+ 82 - 0
pages/add/add.wxss

@@ -0,0 +1,82 @@
+.container {
+  display: flex;
+  flex-direction: column;
+  min-height: 100%;
+  justify-content: space-between;
+  font-size: 32rpx;
+  font-family: -apple-system-font,Helvetica Neue,Helvetica,sans-serif;
+}
+.page-body {
+  width: 100%;
+  flex-grow: 1;
+  overflow-x: hidden;
+}
+.page-section{
+  width: 100%;
+  margin-bottom: 0rpx;
+}
+.image-plus {
+  width: 150rpx;
+  height: 150rpx;
+  border: 2rpx solid #D9D9D9;
+  position: relative;
+}
+.image-plus-nb{
+  border: 0;
+}
+.image-plus-text{
+  color: #888888;
+  font-size: 28rpx;
+}
+.image-plus-horizontal {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  background-color: #d9d9d9;
+  width: 4rpx;
+  height: 80rpx;
+  transform: translate(-50%, -50%);
+}
+.image-plus-vertical {
+  position: absolute;
+  top: 50%;
+  left: 50%;
+  background-color: #d9d9d9;
+  width: 80rpx;
+  height: 4rpx;
+  transform: translate(-50%, -50%);
+}
+.image {
+  width: 100%;
+  height: 360rpx;
+}
+.page-body-info {
+  display: flex;
+  box-sizing: border-box;
+  padding: 30rpx;
+  height: 420rpx;
+  /*border-top: 1rpx solid #D9D9D9;*/
+  /*border-bottom: 1rpx solid #D9D9D9;*/
+  align-items: center;
+  justify-content: center;
+  margin-bottom: 0rpx;
+}
+.page-section-title{
+  font-size: 28rpx;
+  color: #999999;
+  margin-bottom: 0rpx;
+  padding-left: 30rpx;
+  padding-right: 30rpx;
+  line-height:90rpx;
+}
+textarea {
+    width: 700rpx;
+    padding: 25rpx 0;
+}
+.textarea-wrp {
+    padding: 0 25rpx;
+    background-color: #fff;
+}
+.button-wrapper{
+    margin: 1.17647059em 15px 0.3em;
+}

+ 7 - 0
pages/common/footer.wxml

@@ -0,0 +1,7 @@
+<template name="foot">
+  <view class="page__hd">
+    <view class="bottom_title">北京斑羚在线网络科技有限公司 </view>
+    <view class="bottom_title" data-mobile="010-85795663" bindtap="call"> 010-85795663</view>
+    
+  </view>
+</template>

+ 7 - 0
pages/common/header.wxml

@@ -0,0 +1,7 @@
+<template name="head">
+  <view class="page__hd">
+  <navigator url="" open-type="switchTab" >
+    <image src="/pages/images/logo.jpg" style="border-radius:100px;" class="title__icon_img"></image>
+  </navigator>
+  </view>
+</template>

BIN
pages/images/logo.jpg


+ 55 - 0
pages/index/index.js

@@ -0,0 +1,55 @@
+//index.js
+// 引入 QCloud 小程序增强 SDK
+var qcloud = require('../../vendor/qcloud-weapp-client-sdk/index');
+
+// 引入配置
+var config = require('../../config');
+
+// 显示繁忙提示
+var showBusy = text => wx.showToast({
+    title: text,
+    icon: 'loading',
+    duration: 10000
+});
+
+// 显示成功提示
+var showSuccess = text => {
+    wx.hideToast();
+    wx.showToast({
+        title: text,
+        icon: 'success'
+    });
+};
+
+// 显示失败提示
+var showModel = (title, content) => {
+    wx.hideToast();
+
+    wx.showModal({
+        title,
+        content: JSON.stringify(content),
+        showCancel: false
+    });
+};
+//获取应用实例
+var app = getApp()
+Page({
+  data: {
+  },
+  onLoad: function () {
+    console.log('onLoad');
+  },
+  onShow: function () {
+    console.log('onShow');
+    app.getUserInfo(function(userInfo){
+      console.log(userInfo);
+    });
+  },
+  onShareAppMessage: function () {
+    return {
+      title: '密件',
+      desc: '密件',
+      path: 'pages/index/index'
+    }
+  }
+})

+ 3 - 0
pages/index/index.json

@@ -0,0 +1,3 @@
+{
+    "navigationBarTitleText": "首页"
+}

+ 20 - 0
pages/index/index.wxml

@@ -0,0 +1,20 @@
+
+<!--index.wxml-->
+<import src="../common/header.wxml" />
+<import src="../common/footer.wxml" />
+<view class="page">
+  <template is="head" />
+  <view class="page__bd">
+    <view class="section">
+        <view class="button-wrapper">
+            <navigator class="button" url="/pages/add/add">写密件</navigator>
+        </view>
+    </view>
+    <view class="section">
+        <view class="article">
+            <text>密件是一个在微信中使用的小程序,你可以把需要保密发送图片文字的内容通过密件发送。对方只有5秒钟观看的时间,观看之后就会被销毁,不能再转发给他人。</text>
+        </view>
+    </view>
+  </view>
+  <template is="foot" />
+</view>

+ 108 - 0
pages/index/index.wxss

@@ -0,0 +1,108 @@
+/**index.wxss**/
+.switch_section{
+    width: 100%;
+    display: inline-block;
+    background-color:#fff;
+    position:relative;
+}
+.switch_section::before {
+    content: " ";
+    position: absolute;
+    left: 0;
+    top: 0;
+    right: 0;
+    height: 1px;
+    border-top: 1px solid #D9D9D9;
+    color: #D9D9D9;
+    -webkit-transform-origin: 0 0;
+    transform-origin: 0 0;
+    -webkit-transform: scaleY(0.5);
+    transform: scaleY(0.5);
+}
+.switch_section::after {
+    content: " ";
+    position: absolute;
+    left: 0;
+    bottom: 0;
+    right: 0;
+    height: 1px;
+    border-bottom: 1px solid #D9D9D9;
+    color: #D9D9D9;
+    -webkit-transform-origin: 0 100%;
+    transform-origin: 0 100%;
+    -webkit-transform: scaleY(0.5);
+    transform: scaleY(0.5);
+}
+.switch_view{
+    padding-left:30rpx;
+    padding-right:30rpx;
+    height: 40px;
+    position: relative;
+}
+.switch_view::before {
+    content: " ";
+    position: absolute;
+    top: 0;
+    right: 0;
+    height: 1px;
+    border-top: 1px solid #D9D9D9;
+    color: #D9D9D9;
+    -webkit-transform-origin: 0 0;
+    transform-origin: 0 0;
+    -webkit-transform: scaleY(0.5);
+    transform: scaleY(0.5);
+    left: 15px;
+}
+.switch_text{
+    float:left;
+    display: inline-block;
+    font-size:32rpx;
+    color:#000;
+    margin-right:16rpx;
+    height:40px;
+    line-height: 40px;
+}
+switch{
+    float:right;
+    margin-top: 4px;
+}
+.section__title {
+    margin-bottom:16rpx;
+    padding-left:30rpx;
+    padding-right:30rpx;
+    color:#999999;
+    font-size:14px;
+}
+.button-wrapper{
+    margin: 1.17647059em 15px 0.3em;
+}
+.button {
+position:relative;
+display:block;
+margin-left:auto;
+margin-right:auto;
+padding-left:14px;
+padding-right:14px;
+box-sizing:border-box;
+font-size:18px;
+text-align:center;
+text-decoration:none;
+line-height:2.55555556;
+border-radius:5px;
+-webkit-tap-highlight-color:transparent;
+overflow:hidden;
+color:#000000;
+width:200px;
+border:1px solid #AAAAAA;
+}
+.section {
+margin-bottom:10rpx;
+
+}
+.article{
+    padding:50px 40px;
+}
+.article text{
+    line-height: 25px;
+    font-size:16px;
+}

+ 102 - 0
pages/send/send.js

@@ -0,0 +1,102 @@
+// 引入 QCloud 小程序增强 SDK
+var qcloud = require('../../vendor/qcloud-weapp-client-sdk/index');
+
+// 引入配置
+var config = require('../../config');
+
+// 显示繁忙提示
+var showBusy = text => wx.showToast({
+    title: text,
+    icon: 'loading',
+    duration: 10000
+});
+
+// 显示成功提示
+var showSuccess = text => {
+    wx.hideToast();
+    wx.showToast({
+        title: text,
+        icon: 'success'
+    });
+};
+
+// 显示失败提示
+var showModel = (title, content) => {
+    wx.hideToast();
+
+    wx.showModal({
+        title,
+        content: JSON.stringify(content),
+        showCancel: false
+    });
+};
+//获取应用实例
+var app = getApp()
+Page({
+  data: {
+      hash_key:"",
+      text:"",
+      imageSrc:"",
+      nicker_name:"",
+      num:5
+  },
+  Interval:function(){
+       var self=this;
+        this.data.intervarID= setInterval(function(){
+                self.setData({
+                    num:self.data.num-1,
+                });
+                if(self.data.num == 0){
+                    clearInterval(self.data.intervarID);
+                    setTimeout(function(){
+                        wx.redirectTo({
+                            url: '/pages/index/index'
+                        })
+                    }, 1000);
+                }
+            },1000);
+  },
+  onLoad: function (e) {
+    console.log('onLoad');
+    this.setData({
+        hash_key:e.hash_key
+    })
+  },
+  onShow: function () {
+    console.log('onShow');
+    var self=this
+    qcloud.request({
+            // 要请求的地址
+            url: config.service.apiUrl+'messages/'+self.data.hash_key,
+            success(result) {
+              console.log(result);
+              if(result.data.success==true){
+                  if(result.data.message_data.dead==0){
+                      self.setData({
+                            text:result.data.message_data.text,
+                            imageSrc:result.data.message_data.image_url,
+                            nicker_name:result.data.message_data.user.nickname
+                      });
+                      self.Interval();
+                  }else{
+                      wx.redirectTo({
+                            url: '/pages/index/index'
+                      })
+                  }
+              }else{
+                wx.redirectTo({
+                    url: '/pages/index/index'
+                })
+              }
+            },
+
+            fail(error) {
+                console.log('request fail', error);
+            },
+
+            complete() {
+                console.log('request complete');
+            }
+      });
+  }
+})

+ 1 - 0
pages/send/send.json

@@ -0,0 +1 @@
+{}

+ 16 - 0
pages/send/send.wxml

@@ -0,0 +1,16 @@
+<import src="../common/header.wxml" />
+<import src="../common/footer.wxml" />
+<form bindsubmit="formSubmit">
+<view class="page">
+  <template is="head" />
+    <view class="page__bd"  style="padding:50px;padding-left:15px;padding-right:15px;">
+      <view class="page___title" style="margin-bottom:20px;">{{nicker_name}}发来的密件5秒后自动销毁</view>
+      <image src="{{imageSrc}}" class="image" mode="widthFix" wx:if="{{imageSrc}}"></image>
+      <view style="width:100%;margin-top:20px;display:inline-block;line-height:25px;text-align:center" wx:if="{{text}}">{{text}}</view>
+    </view>
+    <view class="fixed">
+      <view class="num">{{num}}</view>
+    </view>
+  <template is="foot" />
+</view>
+</form>

+ 23 - 0
pages/send/send.wxss

@@ -0,0 +1,23 @@
+.page___title{
+    text-align: center;
+    font-size: 30rpx;
+  line-height: 26px;
+}
+.fixed{
+  width:100%;
+  display: inline-block;
+  position: fixed;
+  left: 0;
+  bottom:100px;
+}
+.fixed .num{
+  float:right;
+  margin-right:45px;
+  font-size:30px;
+  line-height: 30px;
+  color: red;
+}
+.image {
+  width: 100%;
+  height: 360rpx;
+}

+ 93 - 0
pages/view/view.js

@@ -0,0 +1,93 @@
+// 引入 QCloud 小程序增强 SDK
+var qcloud = require('../../vendor/qcloud-weapp-client-sdk/index');
+
+// 引入配置
+var config = require('../../config');
+
+// 显示繁忙提示
+var showBusy = text => wx.showToast({
+    title: text,
+    icon: 'loading',
+    duration: 10000
+});
+
+// 显示成功提示
+var showSuccess = text => {
+    wx.hideToast();
+    wx.showToast({
+        title: text,
+        icon: 'success'
+    });
+};
+
+// 显示失败提示
+var showModel = (title, content) => {
+    wx.hideToast();
+
+    wx.showModal({
+        title,
+        content: JSON.stringify(content),
+        showCancel: false
+    });
+};
+//获取应用实例
+var app = getApp()
+Page({
+  data: {
+    "hash_key":"",
+    "imageSrc":"",
+    "text":""
+  },
+  onLoad: function (e) {
+    console.log('onLoad');
+    this.setData({
+        hash_key:e.hash_key
+    })
+  },
+  onShow: function () {
+    console.log('onShow');
+    var self=this
+    qcloud.request({
+            // 要请求的地址
+            url: config.service.apiUrl+'messages/'+self.data.hash_key,
+            success(result) {
+              console.log(result);
+              if(result.data.success==true){
+                  self.setData({
+                    text:result.data.message_data.text,
+                    imageSrc:result.data.message_data.image_url
+                  });
+              }else{
+                wx.redirectTo({
+                    url: '/pages/index/index'
+                })
+              }
+            },
+
+            fail(error) {
+                console.log('request fail', error);
+            },
+
+            complete() {
+                console.log('request complete');
+            }
+      });
+  },
+  edit:function(){
+    wx.redirectTo({
+        url: '/pages/add/add'
+    })
+  },
+  send:function(){
+    wx.redirectTo({
+      url: '/pages/send/send'
+    })
+  },
+  onShareAppMessage: function () {
+    return {
+      title: '密件',
+      desc: '密件',
+      path: 'pages/send/send?hash_key='+this.data.hash_key
+    }
+  }
+})

+ 1 - 0
pages/view/view.json

@@ -0,0 +1 @@
+{}

+ 16 - 0
pages/view/view.wxml

@@ -0,0 +1,16 @@
+<import src="../common/header.wxml" />
+<import src="../common/footer.wxml" />
+<form bindsubmit="formSubmit">
+<view class="page">
+  <template is="head" />
+    <view class="page__bd" style="padding:50px;padding-left:15px;padding-right:15px;">
+      <view class="page___title" style="margin-bottom:20px;">密件已经准备好了,你可以将本页发给你的朋友了</view>
+      <image src="{{imageSrc}}" class="image" mode="widthFix" wx:if="{{imageSrc}}"></image>
+      <view style="width:100%;margin-top:20px;display:inline-block;line-height:25px;text-align:center" wx:if="{{text}}">{{text}}</view>
+    </view>
+    <view class="page__bd" style="padding:10px 50px 0px 50px;text-align:center;">
+      <button class="mini-btn" type="primary" size="mini" bindtap="edit">修改</button>
+    </view>
+  <template is="foot" />
+</view>
+</form>

+ 17 - 0
pages/view/view.wxss

@@ -0,0 +1,17 @@
+.page___title{
+    text-align: center;
+    font-size: 30rpx;
+  line-height: 26px;
+}
+
+
+button[size="mini"] {
+    width:100px;
+    height:34px;
+line-height:34px;
+
+}
+.image {
+  width: 100%;
+  height: 360rpx;
+}

+ 42 - 0
vendor/qcloud-weapp-client-sdk/.bower.json

@@ -0,0 +1,42 @@
+{
+  "name": "qcloud-weapp-client-sdk",
+  "description": "QCloud 微信小程序客户端 SDK",
+  "main": "index.js",
+  "authors": [
+    "Tencent Cloud"
+  ],
+  "license": "MIT",
+  "keywords": [
+    "qcloud",
+    "weapp",
+    "wechat",
+    "sdk",
+    "client",
+    "auth",
+    "websocket"
+  ],
+  "homepage": "https://github.com/tencentyun/weapp-client-sdk",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "test",
+    "tests",
+    "typings.json",
+    "jsconfig.json",
+    "package.json",
+    ".npmignore",
+    ".travis.yml",
+    ".gitignore"
+  ],
+  "version": "0.8.2",
+  "_release": "0.8.2",
+  "_resolution": {
+    "type": "version",
+    "tag": "v0.8.2",
+    "commit": "0944545afe0b6bc4aec8c39e8437dbe95a07a8d9"
+  },
+  "_source": "https://github.com/tencentyun/weapp-client-sdk.git",
+  "_target": "*",
+  "_originalSource": "qcloud-weapp-client-sdk"
+}

+ 24 - 0
vendor/qcloud-weapp-client-sdk/LICENSE

@@ -0,0 +1,24 @@
+LICENSE - "MIT License"
+
+Copyright (c) 2016 by Tencent Cloud
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.

+ 247 - 0
vendor/qcloud-weapp-client-sdk/README.md

@@ -0,0 +1,247 @@
+# 微信小程序客户端腾讯云增强 SDK
+
+[![Build Status](https://travis-ci.org/tencentyun/wafer-client-sdk.svg?branch=master)](https://travis-ci.org/tencentyun/wafer-client-sdk)
+[![Coverage Status](https://coveralls.io/repos/github/tencentyun/wafer-client-sdk/badge.svg?branch=master)](https://coveralls.io/github/tencentyun/wafer-client-sdk?branch=master)
+[![License](https://img.shields.io/github/license/tencentyun/wafer-client-sdk.svg)](LICENSE)
+
+本 项目是 [Wafer](https://github.com/tencentyun/wafer-solution) 的组成部分,为小程序客户端开发提供 SDK 支持会话服务和信道服务。
+
+## SDK 获取与安装
+
+解决方案[客户端 Demo](https://github.com/tencentyun/wafer-client-demo) 已经集成并使用最新版的 SDK,需要快速了解的可以从 Demo 开始。
+
+如果需要单独开始,本 SDK 已经发布为 bower 模块,可以直接安装到小程序目录中。
+
+```sh
+npm install -g bower
+bower install qcloud-weapp-client-sdk
+```
+
+安装之后,就可以使用 `require` 引用 SDK 模块:
+
+```js
+var qcloud = require('./bower_components/qcloud-weapp-client-sdk/index.js');
+```
+
+## 会话服务
+
+[会话服务](https://github.com/tencentyun/wafer-solution/wiki/%E4%BC%9A%E8%AF%9D%E6%9C%8D%E5%8A%A1)让小程序拥有会话管理能力。
+
+### 登录
+
+登录可以在小程序和服务器之间建立会话,服务器由此可以获取到用户的标识和信息。
+
+```js
+var qcloud = require('./bower_components/qcloud-weapp-client-sdk/index.js');
+
+// 设置登录地址
+qcloud.setLoginUrl('https://199447.qcloud.la/login');
+qcloud.login({
+    success: function (userInfo) {
+        console.log('登录成功', userInfo);
+    },
+    fail: function (err) {
+        console.log('登录失败', err);
+    }
+});
+```
+本 SDK 需要配合云端 SDK 才能提供完整会话服务。通过 [setLoginUrl](#setLoginUrl) 设置登录地址,云服务器在该地址上使用云端 SDK 处理登录请求。
+
+> `setLoginUrl` 方法设置登录地址之后会一直有效,因此你可以在微信小程序启动时设置。
+
+登录成功后,可以获取到当前微信用户的基本信息。
+
+### 请求
+
+如果希望小程序的网络请求包含会话,登录之后使用 [request](#request) 方法进行网络请求即可。
+
+```js
+qcloud.request({
+    url: 'http://199447.qcloud.la/user',
+    success: function (response) {
+        console.log(response);
+    },
+    fail: function (err) {
+        console.log(err);
+    }
+});
+```
+
+如果调用 `request` 之前还没有登录,则请求不会带有会话。`request` 方法也支持 `login` 参数支持在请求之前自动登录。
+
+```js
+// 使用 login 参数之前,需要设置登录地址
+qcloud.setLoginUrl('https://199447.qcloud.la/login');
+qcloud.request({
+    login: true,
+    url: 'http://199447.qcloud.la/user',
+    success: function (response) {
+        console.log(response);
+    },
+    fail: function (err) {
+        console.log(err);
+    }
+});
+```
+
+关于会话服务详细技术说明,请参考 [Wiki](https://github.com/tencentyun/wafer-solution/wiki/%E4%BC%9A%E8%AF%9D%E6%9C%8D%E5%8A%A1)。
+
+## 信道服务
+
+[信道服务](https://github.com/tencentyun/wafer-solution/wiki/%E4%BF%A1%E9%81%93%E6%9C%8D%E5%8A%A1)小程序支持利用腾讯云的信道资源使用 WebSocket 服务。
+
+```js
+// 创建信道,需要给定后台服务地址
+var tunnel = this.tunnel = new qcloud.Tunnel('https://199447.qcloud.la/tunnel');
+
+// 监听信道内置消息,包括 connect/close/reconnecting/reconnect/error
+tunnel.on('connect', () => console.log('WebSocket 信道已连接'));
+tunnel.on('close', () => console.log('WebSocket 信道已断开'));
+tunnel.on('reconnecting', () => console.log('WebSocket 信道正在重连...'));
+tunnel.on('reconnect', () => console.log('WebSocket 信道重连成功'));
+tunnel.on('error', error => console.error('信道发生错误:', error));
+
+// 监听自定义消息(服务器进行推送)
+tunnel.on('speak', speak => console.log('收到 speak 消息:', speak));
+
+// 打开信道
+tunnel.open();
+// 发送消息
+tunnel.emit('speak', { word: "hello", who: { nickName: "techird" }});
+// 关闭信道
+tunnel.close();
+```
+
+信道服务同样需要业务服务器配合云端 SDK 支持,构造信道实例的时候需要提供业务服务器提供的信道服务地址。通过监听信道消息以及自定义消息来通过信道实现业务。
+
+关于信道使用的更完整实例,建议参考客户端 Demo 中的[三木聊天室应用源码](https://github.com/tencentyun/wafer-client-demo/blob/master/pages/chat/chat.js)。
+
+关于信道服务详细技术说明,请参考 [Wiki](https://github.com/tencentyun/wafer-solution/wiki/%E4%BF%A1%E9%81%93%E6%9C%8D%E5%8A%A1)。
+
+## API
+
+
+### setLoginUrl
+设置会话服务登录地址。
+
+#### 语法
+```js
+qcloud.setLoginUrl(loginUrl);
+```
+
+#### 参数
+|参数         |类型           |说明
+|-------------|---------------|--------------
+|loginUrl     |string         |会话服务登录地址
+
+### login
+登录,建立微信小程序会话。
+
+#### 语法
+```js
+qcloud.login(options);
+```
+
+#### 参数
+|参数         |类型           |说明
+|-------------|---------------|--------------
+|options      |PlainObject    |会话服务登录地址
+|options.success | () => void | 登录成功的回调
+|options.error | (error) => void | 登录失败的回调
+
+
+### request
+进行带会话的请求。
+
+#### 语法
+```js
+qcloud.request(options);
+```
+
+#### 参数
+|参数         |类型           |说明
+|-------------|---------------|--------------
+|options      |PlainObject    | 会话服务登录地址
+|options.login | bool         | 是否自动登录以获取会话,默认为 false
+|options.url   | string       | 必填,要请求的地址
+|options.header | PlainObject | 请求头设置,不允许设置 Referer
+|options.method | string      | 请求的方法,默认为 GET
+|options.success | (response) => void | 登录成功的回调。<ul><li>`response.statusCode`:请求返回的状态码</li><li>`response.data`:请求返回的数据</li></ul>
+|options.error | (error) => void | 登录失败的回调
+|options.complete | () => void | 登录完成后回调,无论成功还是失败
+
+### Tunnel
+
+表示一个信道。由于小程序的限制,同一时间只能有一个打开的信道。
+
+#### constructor
+
+##### 语法
+```js
+var tunnel = new Tunnel(tunnelUrl);
+```
+
+#### 参数
+|参数         |类型           |说明
+|-------------|---------------|--------------
+|tunnelUrl    |String         | 会话服务登录地址
+
+
+#### on
+监听信道上的事件。信道上事件包括系统事件和服务器推送消息。
+
+##### 语法
+```js
+tunnel.on(type, listener);
+```
+
+##### 参数
+|参数         |类型           |说明
+|-------------|---------------|--------------
+|type         |string         | 监听的事件类型
+|listener     |(message?: any) => void | 监听器,具体类型的事件发生时调用监听器。如果是消息,则会有消息内容。
+
+##### 事件
+|事件         |说明
+|-------------|-------------------------------
+|connect      |信道连接成功后回调
+|close        |信道关闭后回调
+|reconnecting |信道发生重连时回调
+|reconnected  |信道重连成功后回调
+|error        |信道发生错误后回调
+|[message]    |信道服务器推送过来的消息类型,如果消息类型和上面内置的时间类型冲突,需要在监听的时候在消息类型前加 `@`
+|\*           |监听所有事件和消息,监听器第一个参数接收到时间或消息类型 
+
+#### open
+打开信道,建立连接。由于小程序的限制,同一时间只能有一个打开的信道。
+
+##### 语法
+```js
+tunnel.open();
+```
+
+#### emit
+向信道推送消息。
+
+##### 语法
+```js
+tunnel.emit(type, content);
+```
+
+##### 参数
+|参数         |类型           |说明
+|-------------|---------------|--------------
+|type         |string         | 要推送的消息的类型
+|content      |any            | 要推送的消息的内容
+
+#### close
+关闭信道
+
+##### 语法
+```js
+tunnel.close();
+```
+
+## LICENSE
+
+[MIT](LICENSE)

+ 32 - 0
vendor/qcloud-weapp-client-sdk/bower.json

@@ -0,0 +1,32 @@
+{
+  "name": "qcloud-weapp-client-sdk",
+  "description": "QCloud 微信小程序客户端 SDK",
+  "main": "index.js",
+  "authors": [
+    "Tencent Cloud"
+  ],
+  "license": "MIT",
+  "keywords": [
+    "qcloud",
+    "weapp",
+    "wechat",
+    "sdk",
+    "client",
+    "auth",
+    "websocket"
+  ],
+  "homepage": "",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "test",
+    "tests",
+    "typings.json",
+    "jsconfig.json",
+    "package.json",
+    ".npmignore",
+    ".travis.yml",
+    ".gitignore"
+  ]
+}

+ 25 - 0
vendor/qcloud-weapp-client-sdk/index.js

@@ -0,0 +1,25 @@
+var constants = require('./lib/constants');
+var login = require('./lib/login');
+var Session = require('./lib/session');
+var request = require('./lib/request');
+var Tunnel = require('./lib/tunnel');
+
+var exports = module.exports = {
+    login: login.login,
+    setLoginUrl: login.setLoginUrl,
+    LoginError: login.LoginError,
+
+    clearSession: Session.clear,
+
+    request: request.request,
+    RequestError: request.RequestError,
+
+    Tunnel: Tunnel,
+};
+
+// 导出错误类型码
+Object.keys(constants).forEach(function (key) {
+    if (key.indexOf('ERR_') === 0) {
+        exports[key] = constants[key];
+    }
+});

+ 20 - 0
vendor/qcloud-weapp-client-sdk/lib/constants.js

@@ -0,0 +1,20 @@
+module.exports = {
+    WX_HEADER_CODE: 'X-WX-Code',
+    WX_HEADER_ENCRYPTED_DATA: 'X-WX-Encrypted-Data',
+    WX_HEADER_IV: 'X-WX-IV',
+    WX_HEADER_ID: 'X-WX-Id',
+    WX_HEADER_SKEY: 'X-WX-Skey',
+
+    WX_SESSION_MAGIC_ID: 'F2C224D4-2BCE-4C64-AF9F-A6D872000D1A',
+
+    ERR_INVALID_PARAMS: 'ERR_INVALID_PARAMS',
+
+    ERR_WX_LOGIN_FAILED: 'ERR_WX_LOGIN_FAILED',
+    ERR_WX_GET_USER_INFO: 'ERR_WX_GET_USER_INFO',
+    ERR_LOGIN_TIMEOUT: 'ERR_LOGIN_TIMEOUT',
+    ERR_LOGIN_FAILED: 'ERR_LOGIN_FAILED',
+    ERR_LOGIN_SESSION_NOT_RECEIVED: 'ERR_LOGIN_MISSING_SESSION',
+
+    ERR_INVALID_SESSION: 'ERR_INVALID_SESSION',
+    ERR_CHECK_LOGIN_FAILED: 'ERR_CHECK_LOGIN_FAILED',
+};

+ 161 - 0
vendor/qcloud-weapp-client-sdk/lib/login.js

@@ -0,0 +1,161 @@
+var utils = require('./utils');
+var constants = require('./constants');
+var Session = require('./session');
+
+/***
+ * @class
+ * 表示登录过程中发生的异常
+ */
+var LoginError = (function () {
+    function LoginError(type, message) {
+        Error.call(this, message);
+        this.type = type;
+        this.message = message;
+    }
+
+    LoginError.prototype = new Error();
+    LoginError.prototype.constructor = LoginError;
+
+    return LoginError;
+})();
+
+/**
+ * 微信登录,获取 code 和 encryptData
+ */
+var getWxLoginResult = function getLoginCode(callback) {
+    wx.login({
+        success: function (loginResult) {
+            wx.getUserInfo({
+                success: function (userResult) {
+                    callback(null, {
+                        code: loginResult.code,
+                        encryptedData: userResult.encryptedData,
+                        iv: userResult.iv,
+                        userInfo: userResult.userInfo,
+                    });
+                },
+
+                fail: function (userError) {
+                    var error = new LoginError(constants.ERR_WX_GET_USER_INFO, '获取微信用户信息失败,请检查网络状态');
+                    error.detail = userError;
+                    callback(error, null);
+                },
+            });
+        },
+
+        fail: function (loginError) {
+            var error = new LoginError(constants.ERR_WX_LOGIN_FAILED, '微信登录失败,请检查网络状态');
+            error.detail = loginError;
+            callback(error, null);
+        },
+    });
+};
+
+var noop = function noop() {};
+var defaultOptions = {
+    method: 'GET',
+    success: noop,
+    fail: noop,
+    loginUrl: null,
+};
+
+/**
+ * @method
+ * 进行服务器登录,以获得登录会话
+ *
+ * @param {Object} options 登录配置
+ * @param {string} options.loginUrl 登录使用的 URL,服务器应该在这个 URL 上处理登录请求
+ * @param {string} [options.method] 请求使用的 HTTP 方法,默认为 "GET"
+ * @param {Function} options.success(userInfo) 登录成功后的回调函数,参数 userInfo 微信用户信息
+ * @param {Function} options.fail(error) 登录失败后的回调函数,参数 error 错误信息
+ */
+var login = function login(options) {
+    options = utils.extend({}, defaultOptions, options);
+
+    if (!defaultOptions.loginUrl) {
+        options.fail(new LoginError(constants.ERR_INVALID_PARAMS, '登录错误:缺少登录地址,请通过 setLoginUrl() 方法设置登录地址'));
+        return;
+    }
+
+    var doLogin = () => getWxLoginResult(function (wxLoginError, wxLoginResult) {
+        if (wxLoginError) {
+            options.fail(wxLoginError);
+            return;
+        }
+        
+        var userInfo = wxLoginResult.userInfo;
+
+        // 构造请求头,包含 code、encryptedData 和 iv
+        var code = wxLoginResult.code;
+        var encryptedData = wxLoginResult.encryptedData;
+        var iv = wxLoginResult.iv;
+        var header = {};
+
+        header[constants.WX_HEADER_CODE] = code;
+        header[constants.WX_HEADER_ENCRYPTED_DATA] = encryptedData;
+        header[constants.WX_HEADER_IV] = iv;
+
+        // 请求服务器登录地址,获得会话信息
+        wx.request({
+            url: options.loginUrl,
+            header: header,
+            method: options.method,
+            data: options.data,
+
+            success: function (result) {
+                var data = result.data;
+
+                // 成功地响应会话信息
+                if (data && data[constants.WX_SESSION_MAGIC_ID]) {
+                    if (data.session) {
+                        data.session.userInfo = userInfo;
+                        Session.set(data.session);
+                        options.success(userInfo);
+                    } else {
+                        var errorMessage = '登录失败(' + data.error + '):' + (data.message || '未知错误');
+                        var noSessionError = new LoginError(constants.ERR_LOGIN_SESSION_NOT_RECEIVED, errorMessage);
+                        options.fail(noSessionError);
+                    }
+
+                // 没有正确响应会话信息
+                } else {
+                    var errorMessage = '登录请求没有包含会话响应,请确保服务器处理 `' + options.loginUrl + '` 的时候正确使用了 SDK 输出登录结果';
+                    var noSessionError = new LoginError(constants.ERR_LOGIN_SESSION_NOT_RECEIVED, errorMessage);
+                    options.fail(noSessionError);
+                }
+            },
+
+            // 响应错误
+            fail: function (loginResponseError) {
+                var error = new LoginError(constants.ERR_LOGIN_FAILED, '登录失败,可能是网络错误或者服务器发生异常');
+                options.fail(error);
+            },
+        });
+    });
+
+    var session = Session.get();
+    if (session) {
+        wx.checkSession({
+            success: function () {
+                options.success(session.userInfo);
+            },
+
+            fail: function () {
+                Session.clear();
+                doLogin();
+            },
+        });
+    } else {
+        doLogin();
+    }
+};
+
+var setLoginUrl = function (loginUrl) {
+    defaultOptions.loginUrl = loginUrl;
+};
+
+module.exports = {
+    LoginError: LoginError,
+    login: login,
+    setLoginUrl: setLoginUrl,
+};

+ 124 - 0
vendor/qcloud-weapp-client-sdk/lib/request.js

@@ -0,0 +1,124 @@
+var constants = require('./constants');
+var utils = require('./utils');
+var Session = require('./session');
+var loginLib = require('./login');
+
+var noop = function noop() {};
+
+var buildAuthHeader = function buildAuthHeader(session) {
+    var header = {};
+
+    if (session && session.id && session.skey) {
+        header[constants.WX_HEADER_ID] = session.id;
+        header[constants.WX_HEADER_SKEY] = session.skey;
+    }
+
+    return header;
+};
+
+/***
+ * @class
+ * 表示请求过程中发生的异常
+ */
+var RequestError = (function () {
+    function RequestError(type, message) {
+        Error.call(this, message);
+        this.type = type;
+        this.message = message;
+    }
+
+    RequestError.prototype = new Error();
+    RequestError.prototype.constructor = RequestError;
+
+    return RequestError;
+})();
+
+function request(options) {
+    if (typeof options !== 'object') {
+        var message = '请求传参应为 object 类型,但实际传了 ' + (typeof options) + ' 类型';
+        throw new RequestError(constants.ERR_INVALID_PARAMS, message);
+    }
+
+    var requireLogin = options.login;
+    var success = options.success || noop;
+    var fail = options.fail || noop;
+    var complete = options.complete || noop;
+    var originHeader = options.header || {};
+
+    // 成功回调
+    var callSuccess = function () {
+        success.apply(null, arguments);
+        complete.apply(null, arguments);
+    };
+
+    // 失败回调
+    var callFail = function (error) {
+        fail.call(null, error);
+        complete.call(null, error);
+    };
+
+    // 是否已经进行过重试
+    var hasRetried = false;
+
+    if (requireLogin) {
+        doRequestWithLogin();
+    } else {
+        doRequest();
+    }
+
+    // 登录后再请求
+    function doRequestWithLogin() {
+        loginLib.login({ success: doRequest, fail: callFail });
+    }
+
+    // 实际进行请求的方法
+    function doRequest() {
+        var authHeader = buildAuthHeader(Session.get());
+
+        wx.request(utils.extend({}, options, {
+            header: utils.extend({}, originHeader, authHeader),
+
+            success: function (response) {
+                console.log(response);
+                var data = response.data;
+
+                // 如果响应的数据里面包含 SDK Magic ID,表示被服务端 SDK 处理过,此时一定包含登录态失败的信息
+                if (data && data[constants.WX_SESSION_MAGIC_ID]) {
+                    // 清除登录态
+                    Session.clear();
+                    var error, message;
+                    if (data.error === constants.ERR_INVALID_SESSION||data.error === constants.ERR_CHECK_LOGIN_FAILED) {
+                        console.log('123');
+                        // 如果是登录态无效,并且还没重试过,会尝试登录后刷新凭据重新请求
+                        if (!hasRetried) {
+                            hasRetried = true;
+                            doRequestWithLogin();
+                            return;
+                        }
+
+                        message = '登录态已过期';
+                        error = new RequestError(data.error, message);
+
+                    } else {
+                        message = '鉴权服务器检查登录态发生错误(' + (data.error || 'OTHER') + '):' + (data.message || '未知错误');
+                        error = new RequestError(constants.ERR_CHECK_LOGIN_FAILED, message);
+                    }
+
+                    callFail(error);
+                    return;
+                }
+
+                callSuccess.apply(null, arguments);
+            },
+
+            fail: callFail,
+            complete: noop,
+        }));
+    };
+
+};
+
+module.exports = {
+    RequestError: RequestError,
+    request: request,
+};

+ 18 - 0
vendor/qcloud-weapp-client-sdk/lib/session.js

@@ -0,0 +1,18 @@
+var constants = require('./constants');
+var SESSION_KEY = 'weapp_session_' + constants.WX_SESSION_MAGIC_ID;
+
+var Session = {
+    get: function () {
+        return wx.getStorageSync(SESSION_KEY) || null;
+    },
+
+    set: function (session) {
+        wx.setStorageSync(SESSION_KEY, session);
+    },
+
+    clear: function () {
+        wx.removeStorageSync(SESSION_KEY);
+    },
+};
+
+module.exports = Session;

+ 528 - 0
vendor/qcloud-weapp-client-sdk/lib/tunnel.js

@@ -0,0 +1,528 @@
+var requestLib = require('./request');
+var wxTunnel = require('./wxTunnel');
+
+/**
+ * 当前打开的信道,同一时间只能有一个信道打开
+ */
+var currentTunnel = null;
+
+// 信道状态枚举
+var STATUS_CLOSED = Tunnel.STATUS_CLOSED = 'CLOSED';
+var STATUS_CONNECTING = Tunnel.STATUS_CONNECTING = 'CONNECTING';
+var STATUS_ACTIVE = Tunnel.STATUS_ACTIVE = 'ACTIVE';
+var STATUS_RECONNECTING = Tunnel.STATUS_RECONNECTING = 'RECONNECTING';
+
+// 错误类型枚举
+var ERR_CONNECT_SERVICE = Tunnel.ERR_CONNECT_SERVICE = 1001;
+var ERR_CONNECT_SOCKET = Tunnel.ERR_CONNECT_SOCKET = 1002;
+var ERR_RECONNECT = Tunnel.ERR_RECONNECT = 2001;
+var ERR_SOCKET_ERROR = Tunnel.ERR_SOCKET_ERROR = 3001;
+
+// 包类型枚举
+var PACKET_TYPE_MESSAGE = 'message';
+var PACKET_TYPE_PING = 'ping';
+var PACKET_TYPE_PONG = 'pong';
+var PACKET_TYPE_TIMEOUT = 'timeout';
+var PACKET_TYPE_CLOSE = 'close';
+
+// 断线重连最多尝试 5 次
+var DEFAULT_MAX_RECONNECT_TRY_TIMES = 5;
+
+// 每次重连前,等待时间的增量值
+var DEFAULT_RECONNECT_TIME_INCREASE = 1000;
+
+function Tunnel(serviceUrl) {
+    if (currentTunnel && currentTunnel.status !== STATUS_CLOSED) {
+        throw new Error('当前有未关闭的信道,请先关闭之前的信道,再打开新信道');
+    }
+
+    currentTunnel = this;
+
+    // 等确认微信小程序全面支持 ES6 就不用那么麻烦了
+    var me = this;
+
+    //=========================================================================
+    // 暴露实例状态以及方法
+    //=========================================================================
+    this.serviceUrl = serviceUrl;
+    this.socketUrl = null;
+    this.status = null;
+
+    this.open = openConnect;
+    this.on = registerEventHandler;
+    this.emit = emitMessagePacket;
+    this.close = close;
+
+    this.isClosed = isClosed;
+    this.isConnecting = isConnecting;
+    this.isActive = isActive;
+    this.isReconnecting = isReconnecting;
+
+
+    //=========================================================================
+    // 信道状态处理,状态说明:
+    //   closed       - 已关闭
+    //   connecting   - 首次连接
+    //   active       - 当前信道已经在工作
+    //   reconnecting - 断线重连中
+    //=========================================================================
+    function isClosed() { return me.status === STATUS_CLOSED; }
+    function isConnecting() { return me.status === STATUS_CONNECTING; }
+    function isActive() { return me.status === STATUS_ACTIVE; }
+    function isReconnecting() { return me.status === STATUS_RECONNECTING; }
+
+    function setStatus(status) {
+        var lastStatus = me.status;
+        if (lastStatus !== status) {
+            me.status = status;
+        }
+    }
+
+    // 初始为关闭状态
+    setStatus(STATUS_CLOSED);
+
+
+    //=========================================================================
+    // 信道事件处理机制
+    // 信道事件包括:
+    //   connect      - 连接已建立
+    //   close        - 连接被关闭(包括主动关闭和被动关闭)
+    //   reconnecting - 开始重连
+    //   reconnect    - 重连成功
+    //   error        - 发生错误,其中包括连接失败、重连失败、解包失败等等
+    //   [message]    - 信道服务器发送过来的其它事件类型,如果事件类型和上面内置的事件类型冲突,将在事件类型前面添加前缀 `@`
+    //=========================================================================
+    var preservedEventTypes = 'connect,close,reconnecting,reconnect,error'.split(',');
+    var eventHandlers = [];
+
+    /**
+     * 注册消息处理函数
+     * @param {string} messageType 支持内置消息类型("connect"|"close"|"reconnecting"|"reconnect"|"error")以及业务消息类型
+     */
+    function registerEventHandler(eventType, eventHandler) {
+        if (typeof eventHandler === 'function') {
+            eventHandlers.push([eventType, eventHandler]);
+        }
+    }
+
+    /**
+     * 派发事件,通知所有处理函数进行处理
+     */
+    function dispatchEvent(eventType, eventPayload) {
+        eventHandlers.forEach(function (handler) {
+            var handleType = handler[0];
+            var handleFn = handler[1];
+
+            if (handleType === '*') {
+                handleFn(eventType, eventPayload);
+            } else if (handleType === eventType) {
+                handleFn(eventPayload);
+            }
+        });
+    }
+
+    /**
+     * 派发事件,事件类型和系统保留冲突的,事件名会自动加上 '@' 前缀
+     */
+    function dispatchEscapedEvent(eventType, eventPayload) {
+        if (preservedEventTypes.indexOf(eventType) > -1) {
+            eventType = '@' + eventType;
+        }
+
+        dispatchEvent(eventType, eventPayload);
+    }
+
+
+    //=========================================================================
+    // 信道连接控制
+    //=========================================================================
+    var isFirstConnection = true;
+    var isOpening = false;
+
+    /**
+     * 连接信道服务器,获取 WebSocket 连接地址,获取地址成功后,开始进行 WebSocket 连接
+     */
+    function openConnect() {
+        if (isOpening) return;
+        isOpening = true;
+
+        // 只有关闭状态才会重新进入准备中
+        setStatus(isFirstConnection ? STATUS_CONNECTING : STATUS_RECONNECTING);
+
+        requestLib.request({
+            url: serviceUrl,
+            method: 'GET',
+            success: function (response) {
+                if (+response.statusCode === 200 && response.data && response.data.url) {
+                    openSocket(me.socketUrl = response.data.url);
+                } else {
+                    dispatchConnectServiceError(response);
+                }
+            },
+            fail: dispatchConnectServiceError,
+            complete: () => isOpening = false,
+        });
+
+        function dispatchConnectServiceError(detail) {
+            if (isFirstConnection) {
+                setStatus(STATUS_CLOSED);
+
+                dispatchEvent('error', {
+                    code: ERR_CONNECT_SERVICE,
+                    message: '连接信道服务失败,网络错误或者信道服务没有正确响应',
+                    detail: detail || null,
+                });
+
+            } else {
+                startReconnect(detail);
+            }
+        }
+    }
+
+    /**
+     * 打开 WebSocket 连接,打开后,注册微信的 Socket 处理方法
+     */
+    function openSocket(url) {
+        wxTunnel.listen({
+            onOpen: handleSocketOpen,
+            onMessage: handleSocketMessage,
+            onClose: handleSocketClose,
+            onError: handleSocketError,
+        });
+
+        wx.connectSocket({ url: url });
+        isFirstConnection = false;
+    }
+
+
+    //=========================================================================
+    // 处理消息通讯
+    //
+    // packet           - 数据包,序列化形式为 `${type}` 或者 `${type}:${content}`
+    // packet.type      - 包类型,包括 message, ping, pong, close
+    // packet.content?  - 当包类型为 message 的时候,会附带 message 数据
+    //
+    // message          - 消息体,会使用 JSON 序列化后作为 packet.content
+    // message.type     - 消息类型,表示业务消息类型
+    // message.content? - 消息实体,可以为任意类型,表示消息的附带数据,也可以为空
+    //
+    // 数据包示例:
+    //  - 'ping' 表示 Ping 数据包
+    //  - 'message:{"type":"speak","content":"hello"}' 表示一个打招呼的数据包
+    //=========================================================================
+
+    // 连接还没成功建立的时候,需要发送的包会先存放到队列里
+    var queuedPackets = [];
+
+    /**
+     * WebSocket 打开之后,更新状态,同时发送所有遗留的数据包
+     */
+    function handleSocketOpen() {
+        /* istanbul ignore else */
+        if (isConnecting()) {
+            dispatchEvent('connect');
+
+        }
+        else if (isReconnecting()) {
+            dispatchEvent('reconnect');
+            resetReconnectionContext();
+        }
+
+        setStatus(STATUS_ACTIVE);
+        emitQueuedPackets();
+        nextPing();
+    }
+
+    /**
+     * 收到 WebSocket 数据包,交给处理函数
+     */
+    function handleSocketMessage(message) {
+        resolvePacket(message.data);
+    }
+
+    /**
+     * 发送数据包,如果信道没有激活,将先存放队列
+     */
+    function emitPacket(packet) {
+        if (isActive()) {
+            sendPacket(packet);
+        } else {
+            queuedPackets.push(packet);
+        }
+    }
+
+    /**
+     * 数据包推送到信道
+     */
+    function sendPacket(packet) {
+        var encodedPacket = [packet.type];
+
+        if (packet.content) {
+            encodedPacket.push(JSON.stringify(packet.content));
+        }
+
+        wx.sendSocketMessage({
+            data: encodedPacket.join(':'),
+            fail: handleSocketError,
+        });
+    }
+
+    function emitQueuedPackets() {
+        queuedPackets.forEach(emitPacket);
+
+        // empty queued packets
+        queuedPackets.length = 0;
+    }
+
+    /**
+     * 发送消息包
+     */
+    function emitMessagePacket(messageType, messageContent) {
+        var packet = {
+            type: PACKET_TYPE_MESSAGE,
+            content: {
+                type: messageType,
+                content: messageContent,
+            },
+        };
+
+        emitPacket(packet);
+    }
+
+    /**
+     * 发送 Ping 包
+     */
+    function emitPingPacket() {
+        emitPacket({ type: PACKET_TYPE_PING });
+    }
+
+    /**
+     * 发送关闭包
+     */
+    function emitClosePacket() {
+        emitPacket({ type: PACKET_TYPE_CLOSE });
+    }
+
+    /**
+     * 解析并处理从信道接收到的包
+     */
+    function resolvePacket(raw) {
+        var packetParts = raw.split(':');
+        var packetType = packetParts.shift();
+        var packetContent = packetParts.join(':') || null;
+        var packet = { type: packetType };
+
+        if (packetContent) {
+            try {
+                packet.content = JSON.parse(packetContent);
+            } catch (e) {}
+        }
+
+        switch (packet.type) {
+        case PACKET_TYPE_MESSAGE:
+            handleMessagePacket(packet);
+            break;
+        case PACKET_TYPE_PONG:
+            handlePongPacket(packet);
+            break;
+        case PACKET_TYPE_TIMEOUT:
+            handleTimeoutPacket(packet);
+            break;
+        case PACKET_TYPE_CLOSE:
+            handleClosePacket(packet);
+            break;
+        default:
+            handleUnknownPacket(packet);
+            break;
+        }
+    }
+
+    /**
+     * 收到消息包,直接 dispatch 给处理函数
+     */
+    function handleMessagePacket(packet) {
+        var message = packet.content;
+        dispatchEscapedEvent(message.type, message.content);
+    }
+
+
+    //=========================================================================
+    // 心跳、断开与重连处理
+    //=========================================================================
+
+    /**
+     * Ping-Pong 心跳检测超时控制,这个值有两个作用:
+     *   1. 表示收到服务器的 Pong 相应之后,过多久再发下一次 Ping
+     *   2. 如果 Ping 发送之后,超过这个时间还没收到 Pong,断开与服务器的连接
+     * 该值将在与信道服务器建立连接后被更新
+     */
+    let pingPongTimeout = 15000;
+    let pingTimer = 0;
+    let pongTimer = 0;
+
+    /**
+     * 信道服务器返回 Ping-Pong 控制超时时间
+     */
+    function handleTimeoutPacket(packet) {
+        var timeout = packet.content * 1000;
+        /* istanbul ignore else */
+        if (!isNaN(timeout)) {
+            pingPongTimeout = timeout;
+            ping();
+        }
+    }
+
+    /**
+     * 收到服务器 Pong 响应,定时发送下一个 Ping
+     */
+    function handlePongPacket(packet) {
+        nextPing();
+    }
+
+    /**
+     * 发送下一个 Ping 包
+     */
+    function nextPing() {
+        clearTimeout(pingTimer);
+        clearTimeout(pongTimer);
+        pingTimer = setTimeout(ping, pingPongTimeout);
+    }
+
+    /**
+     * 发送 Ping,等待 Pong
+     */
+    function ping() {
+        /* istanbul ignore else */
+        if (isActive()) {
+            emitPingPacket();
+
+            // 超时没有响应,关闭信道
+            pongTimer = setTimeout(handlePongTimeout, pingPongTimeout);
+        }
+    }
+
+    /**
+     * Pong 超时没有响应,信道可能已经不可用,需要断开重连
+     */
+    function handlePongTimeout() {
+        startReconnect('服务器已失去响应');
+    }
+
+    // 已经重连失败的次数
+    var reconnectTryTimes = 0;
+
+    // 最多允许失败次数
+    var maxReconnectTryTimes = Tunnel.MAX_RECONNECT_TRY_TIMES || DEFAULT_MAX_RECONNECT_TRY_TIMES;
+
+    // 重连前等待的时间
+    var waitBeforeReconnect = 0;
+
+    // 重连前等待时间增量
+    var reconnectTimeIncrease = Tunnel.RECONNECT_TIME_INCREASE || DEFAULT_RECONNECT_TIME_INCREASE;
+
+    var reconnectTimer = 0;
+
+    function startReconnect(lastError) {
+        if (reconnectTryTimes >= maxReconnectTryTimes) {
+            close();
+
+            dispatchEvent('error', {
+                code: ERR_RECONNECT,
+                message: '重连失败',
+                detail: lastError,
+            });
+        }
+        else {
+            wx.closeSocket();
+            waitBeforeReconnect += reconnectTimeIncrease;
+            setStatus(STATUS_RECONNECTING);
+            reconnectTimer = setTimeout(doReconnect, waitBeforeReconnect);
+        }
+
+        if (reconnectTryTimes === 0) {
+            dispatchEvent('reconnecting');
+        }
+
+        reconnectTryTimes += 1;
+    }
+
+    function doReconnect() {
+        openConnect();
+    }
+
+    function resetReconnectionContext() {
+        reconnectTryTimes = 0;
+        waitBeforeReconnect = 0;
+    }
+
+    /**
+     * 收到服务器的关闭请求
+     */
+    function handleClosePacket(packet) {
+        close();
+    }
+
+    function handleUnknownPacket(packet) {
+        // throw away
+    }
+
+    var isClosing = false;
+
+    /**
+     * 收到 WebSocket 断开的消息,处理断开逻辑
+     */
+    function handleSocketClose() {
+        /* istanbul ignore if */
+        if (isClosing) return;
+
+        /* istanbul ignore else */
+        if (isActive()) {
+            // 意外断开的情况,进行重连
+            startReconnect('链接已断开');
+        }
+    }
+
+    function close() {
+        isClosing = true;
+        closeSocket();
+        setStatus(STATUS_CLOSED);
+        resetReconnectionContext();
+        isFirstConnection = false;
+        clearTimeout(pingTimer);
+        clearTimeout(pongTimer);
+        clearTimeout(reconnectTimer);
+        dispatchEvent('close');
+        isClosing = false;
+    }
+
+    function closeSocket(emitClose) {
+        if (isActive() && emitClose !== false) {
+            emitClosePacket();
+        }
+
+        wx.closeSocket();
+    }
+
+
+    //=========================================================================
+    // 错误处理
+    //=========================================================================
+
+    /**
+     * 错误处理
+     */
+    function handleSocketError(detail) {
+        switch (me.status) {
+        case Tunnel.STATUS_CONNECTING:
+            dispatchEvent('error', {
+                code: ERR_SOCKET_ERROR,
+                message: '连接信道失败,网络错误或者信道服务不可用',
+                detail: detail,
+            });
+            break;
+        }
+    }
+
+}
+
+module.exports = Tunnel;

+ 18 - 0
vendor/qcloud-weapp-client-sdk/lib/utils.js

@@ -0,0 +1,18 @@
+
+/**
+ * 拓展对象
+ */
+exports.extend = function extend(target) {
+    var sources = Array.prototype.slice.call(arguments, 1);
+
+    for (var i = 0; i < sources.length; i += 1) {
+        var source = sources[i];
+        for (var key in source) {
+            if (source.hasOwnProperty(key)) {
+                target[key] = source[key];
+            }
+        }
+    }
+
+    return target;
+};

+ 32 - 0
vendor/qcloud-weapp-client-sdk/lib/wxTunnel.js

@@ -0,0 +1,32 @@
+/* istanbul ignore next */
+const noop = () => void(0);
+
+let onOpen, onClose, onMessage, onError;
+
+/* istanbul ignore next */
+function listen(listener) {
+    if (listener) {
+        onOpen = listener.onOpen;
+        onClose = listener.onClose;
+        onMessage = listener.onMessage;
+        onError = listener.onError;
+    } else {
+        onOpen = noop;
+        onClose = noop;
+        onMessage = noop;
+        onError = noop;
+    }
+}
+
+/* istanbul ignore next */
+function bind() {
+    wx.onSocketOpen(result => onOpen(result));
+    wx.onSocketClose(result => onClose(result));
+    wx.onSocketMessage(result => onMessage(result));
+    wx.onSocketError(error => onError(error));
+}
+
+listen(null);
+bind();
+
+module.exports = { listen };