├── client
├── utils
│ ├── wechat.js
│ └── util.js
├── pages
│ ├── login
│ │ ├── login.json
│ │ ├── login.wxss
│ │ ├── login.wxml
│ │ └── login.js
│ ├── test
│ │ ├── test.json
│ │ ├── test.wxss
│ │ ├── test.wxml
│ │ ├── test.js
│ │ ├── index.wxml
│ │ ├── index.wxss
│ │ └── index.js
│ ├── index
│ │ ├── index.json
│ │ ├── rule.wxss
│ │ ├── rule.json
│ │ ├── user-unlogin.png
│ │ ├── index.wxss
│ │ ├── rule.js
│ │ ├── rule.wxml
│ │ ├── index.wxml
│ │ └── index.js
│ ├── chat
│ │ ├── chat.json
│ │ ├── chat.wxml
│ │ ├── chat.js
│ │ └── chat.wxss
│ ├── shouhuo
│ │ ├── shouhuo.wxss
│ │ ├── shouhuo.json
│ │ ├── shouhuo.wxml
│ │ └── shouhuo.js
│ ├── fahuo
│ │ ├── fahuo.json
│ │ ├── fahuo.wxss
│ │ ├── fahuo.wxml
│ │ └── fahuo.js
│ ├── yaoqiu
│ │ ├── yaoqiu.json
│ │ ├── yaoqiu.wxss
│ │ ├── yaoqiu.wxml
│ │ └── yaoqiu.js
│ ├── addCgi
│ │ ├── addCgi.json
│ │ ├── code1.png
│ │ ├── code2.png
│ │ ├── addCgi.wxml
│ │ ├── addCgi.js
│ │ └── addCgi.wxss
│ ├── userCenter
│ │ ├── user.json
│ │ ├── user.wxss
│ │ ├── user.js
│ │ └── user.wxml
│ └── libs
│ │ ├── qqmap-wx-jssdk.min.js
│ │ └── qqmap-wx-jssdk.js
├── app.wxss
├── images
│ ├── logo.png
│ ├── refresh.png
│ ├── icon
│ │ ├── cake.png
│ │ ├── eat.png
│ │ ├── end.png
│ │ ├── file.png
│ │ ├── kefu.png
│ │ ├── key.png
│ │ ├── order.png
│ │ ├── other.png
│ │ ├── shuma.png
│ │ ├── start.png
│ │ ├── user.png
│ │ ├── advice.png
│ │ ├── clothes.png
│ │ ├── flower.png
│ │ ├── redbag.png
│ │ ├── shezhi.png
│ │ ├── tianjia.png
│ │ ├── weight.png
│ │ ├── yaopin.png
│ │ ├── zhaomu.png
│ │ ├── kuaidiyuan.png
│ │ ├── newredbag.png
│ │ └── songredbag.png
│ └── location.png
├── sitemap.json
├── app.js
├── vendor
│ └── wafer2-client-sdk
│ │ ├── package.json
│ │ ├── lib
│ │ ├── utils.js
│ │ ├── session.js
│ │ ├── constants.js
│ │ ├── wxTunnel.js
│ │ ├── request.js
│ │ ├── login.js
│ │ └── tunnel.js
│ │ ├── index.js
│ │ ├── LICENSE
│ │ └── README.md
├── package.json
├── config.js
├── app.json
├── LICENSE
└── weui.wxss
├── README.md
├── server
├── controllers
│ ├── upload.js
│ ├── login.js
│ ├── user.js
│ ├── helloworld.js
│ ├── index.js
│ ├── message.js
│ └── tunnel.js
├── process.prod.json
├── .eslintrc.json
├── nodemon.json
├── config.local.js.example
├── app.js
├── tools.md
├── middlewares
│ ├── bodyparser.js
│ └── response.js
├── qcloud.js
├── config.js
├── tools
│ ├── initdb.js
│ └── cAuth.sql
├── package.json
├── routes
│ └── index.js
└── README.md
└── .gitignore
/client/utils/wechat.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/client/pages/login/login.json:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/client/pages/test/test.json:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/client/app.wxss:
--------------------------------------------------------------------------------
1 | @import 'weui.wxss';
2 |
--------------------------------------------------------------------------------
/client/pages/index/index.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | }
--------------------------------------------------------------------------------
/client/pages/test/test.wxss:
--------------------------------------------------------------------------------
1 | /* pages/test/test.wxss */
--------------------------------------------------------------------------------
/client/pages/index/rule.wxss:
--------------------------------------------------------------------------------
1 | /* pages/index/rule.wxss */
--------------------------------------------------------------------------------
/client/pages/chat/chat.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {}
3 | }
--------------------------------------------------------------------------------
/client/pages/shouhuo/shouhuo.wxss:
--------------------------------------------------------------------------------
1 | /* pages/shouhuo/shouhuo.wxss */
--------------------------------------------------------------------------------
/client/pages/fahuo/fahuo.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "选择发货地址"
3 | }
--------------------------------------------------------------------------------
/client/pages/index/rule.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "计价规则"
3 | }
--------------------------------------------------------------------------------
/client/pages/yaoqiu/yaoqiu.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "物品信息"
3 | }
--------------------------------------------------------------------------------
/client/pages/addCgi/addCgi.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "快速添加 CGI"
3 | }
--------------------------------------------------------------------------------
/client/pages/shouhuo/shouhuo.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "选择收获地址"
3 | }
--------------------------------------------------------------------------------
/client/pages/userCenter/user.json:
--------------------------------------------------------------------------------
1 | {
2 | "navigationBarTitleText": "个人中心"
3 | }
--------------------------------------------------------------------------------
/client/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/logo.png
--------------------------------------------------------------------------------
/client/pages/test/test.wxml:
--------------------------------------------------------------------------------
1 |
2 | pages/test/test.wxml
3 |
--------------------------------------------------------------------------------
/client/images/refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/refresh.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 项目暂未上线,提供演示视频
2 | ## 演示视频链接
3 | (链接:https://pan.baidu.com/s/18BD5VwNrvcoFyadGfovJww 提取码:d2mj)
4 |
--------------------------------------------------------------------------------
/client/images/icon/cake.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/cake.png
--------------------------------------------------------------------------------
/client/images/icon/eat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/eat.png
--------------------------------------------------------------------------------
/client/images/icon/end.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/end.png
--------------------------------------------------------------------------------
/client/images/icon/file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/file.png
--------------------------------------------------------------------------------
/client/images/icon/kefu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/kefu.png
--------------------------------------------------------------------------------
/client/images/icon/key.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/key.png
--------------------------------------------------------------------------------
/client/images/icon/order.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/order.png
--------------------------------------------------------------------------------
/client/images/icon/other.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/other.png
--------------------------------------------------------------------------------
/client/images/icon/shuma.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/shuma.png
--------------------------------------------------------------------------------
/client/images/icon/start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/start.png
--------------------------------------------------------------------------------
/client/images/icon/user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/user.png
--------------------------------------------------------------------------------
/client/images/location.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/location.png
--------------------------------------------------------------------------------
/client/images/icon/advice.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/advice.png
--------------------------------------------------------------------------------
/client/images/icon/clothes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/clothes.png
--------------------------------------------------------------------------------
/client/images/icon/flower.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/flower.png
--------------------------------------------------------------------------------
/client/images/icon/redbag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/redbag.png
--------------------------------------------------------------------------------
/client/images/icon/shezhi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/shezhi.png
--------------------------------------------------------------------------------
/client/images/icon/tianjia.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/tianjia.png
--------------------------------------------------------------------------------
/client/images/icon/weight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/weight.png
--------------------------------------------------------------------------------
/client/images/icon/yaopin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/yaopin.png
--------------------------------------------------------------------------------
/client/images/icon/zhaomu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/zhaomu.png
--------------------------------------------------------------------------------
/client/pages/addCgi/code1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/pages/addCgi/code1.png
--------------------------------------------------------------------------------
/client/pages/addCgi/code2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/pages/addCgi/code2.png
--------------------------------------------------------------------------------
/client/images/icon/kuaidiyuan.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/kuaidiyuan.png
--------------------------------------------------------------------------------
/client/images/icon/newredbag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/newredbag.png
--------------------------------------------------------------------------------
/client/images/icon/songredbag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/images/icon/songredbag.png
--------------------------------------------------------------------------------
/client/pages/shouhuo/shouhuo.wxml:
--------------------------------------------------------------------------------
1 |
2 | pages/shouhuo/shouhuo.wxml
3 |
--------------------------------------------------------------------------------
/client/pages/index/user-unlogin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xmc1214/fmeituan/HEAD/client/pages/index/user-unlogin.png
--------------------------------------------------------------------------------
/client/pages/login/login.wxss:
--------------------------------------------------------------------------------
1 | /* pages/login/login.wxss */
2 | #queding{
3 | background: #FDA81C;
4 | }
5 | #shouquan{
6 | margin-top: 100rpx;
7 | }
--------------------------------------------------------------------------------
/client/sitemap.json:
--------------------------------------------------------------------------------
1 | {
2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
3 | "rules": [{
4 | "action": "allow",
5 | "page": "*"
6 | }]
7 | }
--------------------------------------------------------------------------------
/server/controllers/upload.js:
--------------------------------------------------------------------------------
1 | const { uploader } = require('../qcloud')
2 |
3 | module.exports = async ctx => {
4 | // 获取上传之后的结果
5 | // 具体可以查看:
6 | const data = await uploader(ctx.req)
7 |
8 | ctx.state.data = data
9 | }
10 |
--------------------------------------------------------------------------------
/server/controllers/login.js:
--------------------------------------------------------------------------------
1 | // 登录授权接口
2 | module.exports = async (ctx, next) => {
3 | // 通过 Koa 中间件进行登录之后
4 | // 登录信息会被存储到 ctx.state.$wxInfo
5 | // 具体查看:
6 | if (ctx.state.$wxInfo.loginState) {
7 | ctx.state.data = ctx.state.$wxInfo.userinfo
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/client/pages/fahuo/fahuo.wxss:
--------------------------------------------------------------------------------
1 | /* pages/fahuo/fahuo.wxss */
2 | #addAddress{
3 | width:95%;
4 | position:fixed;
5 | top:540px;
6 | border-bottom: 1px solid #ccc;
7 | text-align: center;
8 | }
9 | .weui-cell__bd span{
10 | position: relative;
11 | bottom: 15px;
12 | left: -10px;
13 | }
--------------------------------------------------------------------------------
/server/process.prod.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "session",
3 | "script": "app.js",
4 | "cwd": "./",
5 | "exec_mode": "fork",
6 | "watch": true,
7 | "ignore_watch": ["tmp"],
8 | "env": {
9 | "NODE_ENV": "production"
10 | },
11 | "engines": {
12 | "node": ">=7.6"
13 | }
14 | }
--------------------------------------------------------------------------------
/server/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "parser": "babel-eslint",
4 | "parserOptions": {
5 | "sourceType": "module"
6 | },
7 | "extends": "standard",
8 | "rules": {
9 | "indent": [2, 4, { "SwitchCase": 1 }],
10 | "arrow-parens": 0,
11 | "generator-star-spacing": 0
12 | },
13 | "env": {
14 | "mocha": true
15 | }
16 | }
--------------------------------------------------------------------------------
/client/pages/index/index.wxss:
--------------------------------------------------------------------------------
1 | /* pages/index/index.wxss */
2 |
3 | .title{
4 | font-size: 28rpx;
5 | font-family: "微软雅黑";
6 | margin-left: 170rpx;
7 | }
8 | .mainmap{
9 | width: 100%;
10 | height:600rpx;
11 | }
12 |
13 | .weui-footer{
14 | margin-top: 15px;
15 | }
16 |
17 | .refresh{
18 | position: relative;
19 | top: 85%;
20 | left: 90%;
21 | }
--------------------------------------------------------------------------------
/server/controllers/user.js:
--------------------------------------------------------------------------------
1 | module.exports = async (ctx, next) => {
2 | // 通过 Koa 中间件进行登录态校验之后
3 | // 登录信息会被存储到 ctx.state.$wxInfo
4 | // 具体查看:
5 | if (ctx.state.$wxInfo.loginState === 1) {
6 | // loginState 为 1,登录态校验成功
7 | ctx.state.data = ctx.state.$wxInfo.userinfo
8 | } else {
9 | ctx.state.code = -1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/server/nodemon.json:
--------------------------------------------------------------------------------
1 | {
2 | "restartable": "rs",
3 | "ignore": [
4 | ".git",
5 | "node_modules/**/node_modules"
6 | ],
7 | "verbose": true,
8 | "execMap": {
9 | "js": "node --harmony"
10 | },
11 | "env": {
12 | "NODE_ENV": "local",
13 | "DEBUG": "*,-nodemon:*,-nodemon,-knex:pool"
14 | },
15 | "ext": "js json"
16 | }
17 |
--------------------------------------------------------------------------------
/client/app.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @fileOverview 微信小程序的入口文件
3 | */
4 |
5 | var qcloud = require('./vendor/wafer2-client-sdk/index');
6 | var config = require('./config');
7 |
8 | App({
9 | /**
10 | * 小程序初始化时执行,我们初始化客户端的登录地址,以支持所有的会话操作
11 | */
12 | globalData: {
13 |
14 | },
15 | onLaunch() {
16 | qcloud.setLoginUrl(config.service.loginUrl);
17 | }
18 |
19 |
20 | });
--------------------------------------------------------------------------------
/client/vendor/wafer2-client-sdk/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "wafer2-client-sdk",
3 | "version": "2.0.0",
4 | "description": "Wafer client SDK",
5 | "main": "index.js",
6 | "directories": {
7 | "lib": "lib"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/tencentyun/wafer2-client-sdk.git"
12 | },
13 | "author": "CFETeam",
14 | "license": "MIT"
15 | }
16 |
--------------------------------------------------------------------------------
/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "qcloud-weapp-client-demo",
3 | "version": "2.0.0",
4 | "description": "腾讯云微信小程序客户端 DEMO",
5 | "main": "app.js",
6 | "repository": {
7 | "type": "git",
8 | "url": "https://github.com/tencentyun/weapp-client-demo.git"
9 | },
10 | "keywords": [],
11 | "author": "CFETeam",
12 | "license": "MIT",
13 | "dependencies": {
14 | "wafer2-client-sdk": "^2.1.0"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/server/controllers/helloworld.js:
--------------------------------------------------------------------------------
1 | const { mysql } = require('../qcloud')
2 |
3 |
4 | module.exports = async ctx => {
5 | var userId = 1
6 | // 增
7 | var user = {
8 |
9 | username:"xmq",
10 | password:'qwe'
11 | }
12 | await mysql("userInfo").insert(user)
13 | await mysql("userInfo").update({username:'谢名丞'}).where({userId})
14 |
15 | var res = await mysql("userInfo").where({ userId }).first()
16 |
17 | ctx.state.data = res
18 | }
--------------------------------------------------------------------------------
/client/vendor/wafer2-client-sdk/lib/utils.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * 拓展对象
4 | */
5 | exports.extend = function extend(target) {
6 | var sources = Array.prototype.slice.call(arguments, 1);
7 |
8 | for (var i = 0; i < sources.length; i += 1) {
9 | var source = sources[i];
10 | for (var key in source) {
11 | if (source.hasOwnProperty(key)) {
12 | target[key] = source[key];
13 | }
14 | }
15 | }
16 |
17 | return target;
18 | };
--------------------------------------------------------------------------------
/server/config.local.js.example:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | mysql: {
3 | host: 'localhost',
4 | port: 3306,
5 | user: '',
6 | pass: '',
7 | db: '',
8 | char: 'utf8mb4'
9 | },
10 | serverHost: 'localhost',
11 | tunnelServerUrl: '',
12 | tunnelSignatureKey: '',
13 | // 腾讯云相关配置可以查看云 API 秘钥控制台:https://console.qcloud.com/capi
14 | qcloudAppId: '',
15 | qcloudSecretId: '',
16 | qcloudSecretKey: '',
17 | wxMessageToken: ''
18 | }
19 |
--------------------------------------------------------------------------------
/client/vendor/wafer2-client-sdk/lib/session.js:
--------------------------------------------------------------------------------
1 | var constants = require('./constants');
2 | var SESSION_KEY = 'weapp_session_' + constants.WX_SESSION_MAGIC_ID;
3 |
4 | var Session = {
5 | get: function () {
6 | return wx.getStorageSync(SESSION_KEY) || null;
7 | },
8 |
9 | set: function (session) {
10 | wx.setStorageSync(SESSION_KEY, session);
11 | },
12 |
13 | clear: function () {
14 | wx.removeStorageSync(SESSION_KEY);
15 | },
16 | };
17 |
18 | module.exports = Session;
--------------------------------------------------------------------------------
/server/app.js:
--------------------------------------------------------------------------------
1 | const Koa = require('koa')
2 | const app = new Koa()
3 | const debug = require('debug')('koa-weapp-demo')
4 | const response = require('./middlewares/response')
5 | const bodyParser = require('./middlewares/bodyparser')
6 | const config = require('./config')
7 |
8 | // 使用响应处理中间件
9 | app.use(response)
10 |
11 | // 解析请求体
12 | app.use(bodyParser())
13 |
14 | // 引入路由分发
15 | const router = require('./routes')
16 | app.use(router.routes())
17 |
18 | // 启动程序,监听端口
19 | app.listen(config.port, () => debug(`listening on port ${config.port}`))
20 |
--------------------------------------------------------------------------------
/client/config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 小程序配置文件
3 | */
4 |
5 | // 此处主机域名修改成腾讯云解决方案分配的域名
6 | var host = 'https://s8sagp6p.qcloud.la';
7 |
8 | var config = {
9 |
10 | // 下面的地址配合云端 Demo 工作
11 | service: {
12 | host,
13 |
14 | // 登录地址,用于建立会话
15 | loginUrl: `${host}/weapp/login`,
16 |
17 | // 测试的请求地址,用于测试会话
18 | requestUrl: `${host}/weapp/user`,
19 |
20 | // 测试的信道服务地址
21 | tunnelUrl: `${host}/weapp/tunnel`,
22 |
23 | // 上传图片接口
24 | uploadUrl: `${host}/weapp/upload`
25 | }
26 | };
27 |
28 | module.exports = config;
--------------------------------------------------------------------------------
/server/tools.md:
--------------------------------------------------------------------------------
1 | # 腾讯云小程序解决方案 Demo 工具使用文档
2 |
3 | 本文件夹下的脚本为腾讯云小程序解决方案 Demo 配套的工具,旨在让用户方便快捷的使用并创建小程序的开发环境。
4 |
5 | 工具包括:
6 |
7 | - [数据库初始化工具](#数据库初始化工具)
8 |
9 | ## 数据库初始化工具
10 |
11 | 本工具是为了让用户快速的按照腾讯云制定的数据库 schema 创建符合 SDK 标准的数据库结构。
12 |
13 | _**注意**:本工具支持的 MySQL 版本为 **5.7**,并且需提前在数据库中创建名为 `cAuth` 的数据库。`charset` 设置为 `utf8mb4`。_
14 |
15 | 快速使用:
16 |
17 | ```bash
18 | npm run initdb
19 | ```
20 |
21 | 或直接执行 `tools` 目录下的 `initdb.js` 文件:
22 |
23 | ```bash
24 | # 请保证已经执行了 npm install 安装了所需要的依赖
25 | node tools/initdb.js
26 | ```
27 |
28 | 我们提供了初始化的 SQL 文件,你也可以用其他数据库工具(如 Navicat)直接导入 SQL 文件。
29 |
--------------------------------------------------------------------------------
/server/middlewares/bodyparser.js:
--------------------------------------------------------------------------------
1 | const bodyParser = require('koa-bodyparser')
2 |
3 | /**
4 | * 这里做一个兼容
5 | * 由于微信方面客服接口 post 过来的数据是 JSON
6 | * 但是 header 里的 Content-Type 却错误标记为 text/xml
7 | * 这里对所有 Content-Type 为 text/xml 的用 JSON 解析
8 | * 如果你在消息推送后台配置的是 xml,请直接将 detectJSON 设置为空
9 | */
10 | module.exports = (opts = {}) => {
11 | const options = Object.assign({}, {
12 | detectJSON (ctx) {
13 | if (ctx.request.type === 'text/xml') {
14 | return true
15 | } else {
16 | return false
17 | }
18 | }
19 | }, opts)
20 |
21 | return bodyParser(options)
22 | }
23 |
--------------------------------------------------------------------------------
/client/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages": [
3 | "pages/index/index",
4 | "pages/test/test",
5 | "pages/chat/chat",
6 | "pages/shouhuo/shouhuo",
7 | "pages/fahuo/fahuo",
8 | "pages/yaoqiu/yaoqiu",
9 | "pages/index/rule",
10 | "pages/userCenter/user",
11 | "pages/login/login"
12 | ],
13 | "window": {
14 | "backgroundTextStyle": "dark",
15 | "navigationBarBackgroundColor": "white",
16 | "navigationBarTitleText": "跑腿帮",
17 | "navigationBarTextStyle": "black"
18 | },
19 | "sitemapLocation": "sitemap.json",
20 | "permission": {
21 | "scope.userLocation": {
22 | "desc": "你的位置信息将用于实时显示跑腿员的位置"
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/client/pages/login/login.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/client/vendor/wafer2-client-sdk/index.js:
--------------------------------------------------------------------------------
1 | var constants = require('./lib/constants');
2 | var login = require('./lib/login');
3 | var Session = require('./lib/session');
4 | var request = require('./lib/request');
5 | var Tunnel = require('./lib/tunnel');
6 |
7 | var exports = module.exports = {
8 | login: login.login,
9 | loginWithCode: login.loginWithCode,
10 | setLoginUrl: login.setLoginUrl,
11 |
12 | Session,
13 | clearSession: Session.clear,
14 |
15 | request: request.request,
16 | RequestError: request.RequestError,
17 |
18 | Tunnel: Tunnel,
19 | };
20 |
21 | // 导出错误类型码
22 | Object.keys(constants).forEach(function (key) {
23 | if (key.indexOf('ERR_') === 0) {
24 | exports[key] = constants[key];
25 | }
26 | });
--------------------------------------------------------------------------------
/client/pages/userCenter/user.wxss:
--------------------------------------------------------------------------------
1 | /* pages/userCenter/user.wxss */
2 | page{
3 | background-color: #F8F8F8;
4 | font-size: 16px;
5 | font-family: -apple-system-font,Helvetica Neue,Helvetica,sans-serif;
6 | }
7 | .page__hd {
8 | padding: 40px;
9 | }
10 | .page__bd {
11 | padding-bottom: 40px;
12 | }
13 | .page__bd_spacing {
14 | padding-left: 15px;
15 | padding-right: 15px;
16 | }
17 |
18 | .page__ft{
19 | padding-bottom: 10px;
20 | text-align: center;
21 | }
22 |
23 | .page__title {
24 | text-align: left;
25 | font-size: 20px;
26 | font-weight: 400;
27 | }
28 |
29 | .page__desc {
30 | margin-top: 5px;
31 | color: #888888;
32 | text-align: left;
33 | font-size: 14px;
34 | }
35 |
36 | #list{
37 | font-size: 14px;
38 | }
--------------------------------------------------------------------------------
/client/vendor/wafer2-client-sdk/lib/constants.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | WX_HEADER_CODE: 'X-WX-Code',
3 | WX_HEADER_ENCRYPTED_DATA: 'X-WX-Encrypted-Data',
4 | WX_HEADER_IV: 'X-WX-IV',
5 | WX_HEADER_ID: 'X-WX-Id',
6 | WX_HEADER_SKEY: 'X-WX-Skey',
7 |
8 | WX_SESSION_MAGIC_ID: 'F2C224D4-2BCE-4C64-AF9F-A6D872000D1A',
9 |
10 | ERR_INVALID_PARAMS: 'ERR_INVALID_PARAMS',
11 |
12 | ERR_WX_LOGIN_FAILED: 'ERR_WX_LOGIN_FAILED',
13 | ERR_WX_GET_USER_INFO: 'ERR_WX_GET_USER_INFO',
14 | ERR_LOGIN_TIMEOUT: 'ERR_LOGIN_TIMEOUT',
15 | ERR_LOGIN_FAILED: 'ERR_LOGIN_FAILED',
16 | ERR_LOGIN_SESSION_NOT_RECEIVED: 'ERR_LOGIN_MISSING_SESSION',
17 |
18 | ERR_SESSION_INVALID: 'ERR_SESSION_INVALID',
19 | ERR_CHECK_LOGIN_FAILED: 'ERR_CHECK_LOGIN_FAILED',
20 | };
--------------------------------------------------------------------------------
/server/controllers/index.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash')
2 | const fs = require('fs')
3 | const path = require('path')
4 |
5 | /**
6 | * 映射 d 文件夹下的文件为模块
7 | */
8 | const mapDir = d => {
9 | const tree = {}
10 |
11 | // 获得当前文件夹下的所有的文件夹和文件
12 | const [dirs, files] = _(fs.readdirSync(d)).partition(p => fs.statSync(path.join(d, p)).isDirectory())
13 |
14 | // 映射文件夹
15 | dirs.forEach(dir => {
16 | tree[dir] = mapDir(path.join(d, dir))
17 | })
18 |
19 | // 映射文件
20 | files.forEach(file => {
21 | if (path.extname(file) === '.js') {
22 | tree[path.basename(file, '.js')] = require(path.join(d, file))
23 | }
24 | })
25 |
26 | return tree
27 | }
28 |
29 | // 默认导出当前文件夹下的映射
30 | module.exports = mapDir(path.join(__dirname))
31 |
--------------------------------------------------------------------------------
/client/pages/yaoqiu/yaoqiu.wxss:
--------------------------------------------------------------------------------
1 | /* pages/yaoqiu/yaoqiu.wxss */
2 | slider{
3 | margin-bottom: 30px;
4 | }
5 | page{
6 |
7 | font-size: 16px;
8 | font-family: -apple-system-font,Helvetica Neue,Helvetica,sans-serif;
9 | }
10 |
11 | .page__bd {
12 | padding-bottom: 40px;
13 | }
14 | .page__bd_spacing {
15 | padding-left: 15px;
16 | padding-right: 15px;
17 | }
18 |
19 | .page__ft{
20 | padding-bottom: 10px;
21 | text-align: center;
22 | }
23 |
24 | .page__title {
25 | text-align: left;
26 | font-size: 20px;
27 | font-weight: 400;
28 | text-align: center;
29 | }
30 |
31 | .page__desc {
32 | margin-top: 5px;
33 | color: #888888;
34 | text-align: center;
35 | font-size: 14px;
36 | }
37 |
38 | #queding{
39 | background: #FDA81C;
40 | }
41 |
42 | .weui-grid:hover{
43 | background-color: #DFDAD8;
44 |
45 | }
--------------------------------------------------------------------------------
/server/controllers/message.js:
--------------------------------------------------------------------------------
1 | const { message: { checkSignature } } = require('../qcloud')
2 |
3 | /**
4 | * 响应 GET 请求(响应微信配置时的签名检查请求)
5 | */
6 | async function get (ctx, next) {
7 | const { signature, timestamp, nonce, echostr } = ctx.query
8 | if (checkSignature(signature, timestamp, nonce)) ctx.body = echostr
9 | else ctx.body = 'ERR_WHEN_CHECK_SIGNATURE'
10 | }
11 |
12 | async function post (ctx, next) {
13 | // 检查签名,确认是微信发出的请求
14 | const { signature, timestamp, nonce } = ctx.query
15 | if (!checkSignature(signature, timestamp, nonce)) ctx.body = 'ERR_WHEN_CHECK_SIGNATURE'
16 |
17 | /**
18 | * 解析微信发送过来的请求体
19 | * 可查看微信文档:https://mp.weixin.qq.com/debug/wxadoc/dev/api/custommsg/receive.html#接收消息和事件
20 | */
21 | const body = ctx.request.body
22 |
23 | ctx.body = 'success'
24 | }
25 |
26 | module.exports = {
27 | post,
28 | get
29 | }
30 |
--------------------------------------------------------------------------------
/server/middlewares/response.js:
--------------------------------------------------------------------------------
1 | const debug = require('debug')('koa-weapp-demo')
2 |
3 | /**
4 | * 响应处理模块
5 | */
6 | module.exports = async function (ctx, next) {
7 | try {
8 | // 调用下一个 middleware
9 | await next()
10 |
11 | // 处理响应结果
12 | // 如果直接写入在 body 中,则不作处理
13 | // 如果写在 ctx.body 为空,则使用 state 作为响应
14 | ctx.body = ctx.body ? ctx.body : {
15 | code: ctx.state.code !== undefined ? ctx.state.code : 0,
16 | data: ctx.state.data !== undefined ? ctx.state.data : {}
17 | }
18 | } catch (e) {
19 | // catch 住全局的错误信息
20 | debug('Catch Error: %o', e)
21 |
22 | // 设置状态码为 500 - 服务端错误
23 | ctx.status = 200
24 |
25 | // 输出详细的错误信息
26 | ctx.body = {
27 | code: -1,
28 | error: e && e.message ? e.message : e.toString()
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/client/vendor/wafer2-client-sdk/lib/wxTunnel.js:
--------------------------------------------------------------------------------
1 | /* istanbul ignore next */
2 | const noop = () => void(0);
3 |
4 | let onOpen, onClose, onMessage, onError;
5 |
6 | /* istanbul ignore next */
7 | function listen(listener) {
8 | if (listener) {
9 | onOpen = listener.onOpen;
10 | onClose = listener.onClose;
11 | onMessage = listener.onMessage;
12 | onError = listener.onError;
13 | } else {
14 | onOpen = noop;
15 | onClose = noop;
16 | onMessage = noop;
17 | onError = noop;
18 | }
19 | }
20 |
21 | /* istanbul ignore next */
22 | function bind() {
23 | wx.onSocketOpen(result => onOpen(result));
24 | wx.onSocketClose(result => onClose(result));
25 | wx.onSocketMessage(result => onMessage(result));
26 | wx.onSocketError(error => onError(error));
27 | }
28 |
29 | listen(null);
30 | bind();
31 |
32 | module.exports = { listen };
--------------------------------------------------------------------------------
/client/pages/test/test.js:
--------------------------------------------------------------------------------
1 | // pages/test/test.js
2 | Page({
3 |
4 | /**
5 | * 页面的初始数据
6 | */
7 | data: {
8 |
9 | },
10 |
11 | /**
12 | * 生命周期函数--监听页面加载
13 | */
14 | onLoad: function (options) {
15 |
16 | },
17 |
18 | /**
19 | * 生命周期函数--监听页面初次渲染完成
20 | */
21 | onReady: function () {
22 |
23 | },
24 |
25 | /**
26 | * 生命周期函数--监听页面显示
27 | */
28 | onShow: function () {
29 |
30 | },
31 |
32 | /**
33 | * 生命周期函数--监听页面隐藏
34 | */
35 | onHide: function () {
36 |
37 | },
38 |
39 | /**
40 | * 生命周期函数--监听页面卸载
41 | */
42 | onUnload: function () {
43 |
44 | },
45 |
46 | /**
47 | * 页面相关事件处理函数--监听用户下拉动作
48 | */
49 | onPullDownRefresh: function () {
50 |
51 | },
52 |
53 | /**
54 | * 页面上拉触底事件的处理函数
55 | */
56 | onReachBottom: function () {
57 |
58 | },
59 |
60 | /**
61 | * 用户点击右上角分享
62 | */
63 | onShareAppMessage: function () {
64 |
65 | }
66 | })
--------------------------------------------------------------------------------
/client/pages/index/rule.js:
--------------------------------------------------------------------------------
1 | // pages/index/rule.js
2 | Page({
3 |
4 | /**
5 | * 页面的初始数据
6 | */
7 | data: {
8 |
9 | },
10 |
11 | /**
12 | * 生命周期函数--监听页面加载
13 | */
14 | onLoad: function (options) {
15 |
16 | },
17 |
18 | /**
19 | * 生命周期函数--监听页面初次渲染完成
20 | */
21 | onReady: function () {
22 |
23 | },
24 |
25 | /**
26 | * 生命周期函数--监听页面显示
27 | */
28 | onShow: function () {
29 |
30 | },
31 |
32 | /**
33 | * 生命周期函数--监听页面隐藏
34 | */
35 | onHide: function () {
36 |
37 | },
38 |
39 | /**
40 | * 生命周期函数--监听页面卸载
41 | */
42 | onUnload: function () {
43 |
44 | },
45 |
46 | /**
47 | * 页面相关事件处理函数--监听用户下拉动作
48 | */
49 | onPullDownRefresh: function () {
50 |
51 | },
52 |
53 | /**
54 | * 页面上拉触底事件的处理函数
55 | */
56 | onReachBottom: function () {
57 |
58 | },
59 |
60 | /**
61 | * 用户点击右上角分享
62 | */
63 | onShareAppMessage: function () {
64 |
65 | }
66 | })
--------------------------------------------------------------------------------
/client/pages/shouhuo/shouhuo.js:
--------------------------------------------------------------------------------
1 | // pages/shouhuo/shouhuo.js
2 | Page({
3 |
4 | /**
5 | * 页面的初始数据
6 | */
7 | data: {
8 |
9 | },
10 |
11 | /**
12 | * 生命周期函数--监听页面加载
13 | */
14 | onLoad: function (options) {
15 |
16 | },
17 |
18 | /**
19 | * 生命周期函数--监听页面初次渲染完成
20 | */
21 | onReady: function () {
22 |
23 | },
24 |
25 | /**
26 | * 生命周期函数--监听页面显示
27 | */
28 | onShow: function () {
29 |
30 | },
31 |
32 | /**
33 | * 生命周期函数--监听页面隐藏
34 | */
35 | onHide: function () {
36 |
37 | },
38 |
39 | /**
40 | * 生命周期函数--监听页面卸载
41 | */
42 | onUnload: function () {
43 |
44 | },
45 |
46 | /**
47 | * 页面相关事件处理函数--监听用户下拉动作
48 | */
49 | onPullDownRefresh: function () {
50 |
51 | },
52 |
53 | /**
54 | * 页面上拉触底事件的处理函数
55 | */
56 | onReachBottom: function () {
57 |
58 | },
59 |
60 | /**
61 | * 用户点击右上角分享
62 | */
63 | onShareAppMessage: function () {
64 |
65 | }
66 | })
--------------------------------------------------------------------------------
/client/pages/yaoqiu/yaoqiu.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {{item.name}}
9 |
10 |
11 |
12 |
13 |
14 | 重量
15 | {{weight}}公斤
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/server/qcloud.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const qcloud = require('wafer-node-sdk')
3 |
4 | // 获取基础配置
5 | const configs = require('./config')
6 |
7 | // 获取 sdk.config
8 | const sdkConfig = (() => {
9 | const sdkConfigPath = '/data/release/sdk.config.json'
10 |
11 | // 检查文件是否存在
12 | try {
13 | const stats = fs.statSync(sdkConfigPath)
14 |
15 | if (!stats.isFile()) {
16 | console.log('sdk.config.json 不存在,将使用 config.js 中的配置')
17 | return {}
18 | }
19 | } catch (e) {
20 | return {}
21 | }
22 |
23 | // 返回配置信息
24 | try {
25 | const content = fs.readFileSync(sdkConfigPath, 'utf8')
26 | return JSON.parse(content)
27 | } catch (e) {
28 | // 如果配置读取错误或者 JSON 解析错误,则输出空配置项
29 | console.log('sdk.config.json 解析错误,不是 JSON 字符串')
30 | return {}
31 | }
32 | })()
33 |
34 | // 初始化 SDK
35 | // 将基础配置和 sdk.config 合并传入 SDK 并导出初始化完成的 SDK
36 | module.exports = qcloud(Object.assign({}, sdkConfig, configs))
37 |
--------------------------------------------------------------------------------
/client/utils/util.js:
--------------------------------------------------------------------------------
1 | const formatTime = date => {
2 | const year = date.getFullYear()
3 | const month = date.getMonth() + 1
4 | const day = date.getDate()
5 | const hour = date.getHours()
6 | const minute = date.getMinutes()
7 | const second = date.getSeconds()
8 |
9 | return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
10 | }
11 |
12 | const formatNumber = n => {
13 | n = n.toString()
14 | return n[1] ? n : '0' + n
15 | }
16 |
17 |
18 | // 显示繁忙提示
19 | var showBusy = text => wx.showToast({
20 | title: text,
21 | icon: 'loading',
22 | duration: 10000
23 | })
24 |
25 | // 显示成功提示
26 | var showSuccess = text => wx.showToast({
27 | title: text,
28 | icon: 'success'
29 | })
30 |
31 | // 显示失败提示
32 | var showModel = (title, content) => {
33 | wx.hideToast();
34 |
35 | wx.showModal({
36 | title,
37 | content: JSON.stringify(content),
38 | showCancel: false
39 | })
40 | }
41 |
42 | module.exports = { formatTime, showBusy, showSuccess, showModel }
43 |
--------------------------------------------------------------------------------
/server/config.js:
--------------------------------------------------------------------------------
1 | const CONF = {
2 | port: '5757',
3 | rootPathname: '',
4 |
5 | // 微信小程序 App ID
6 | appId: 'wxf20f36c2e7dba430',
7 |
8 | // 微信小程序 App Secret
9 | appSecret: '',
10 |
11 | // 是否使用腾讯云代理登录小程序
12 | useQcloudLogin: true,
13 |
14 | /**
15 | * MySQL 配置,用来存储 session 和用户信息
16 | * 若使用了腾讯云微信小程序解决方案
17 | * 开发环境下,MySQL 的初始密码为您的微信小程序 appid
18 | */
19 | mysql: {
20 | host: 'localhost',
21 | port: 3306,
22 | user: 'root',
23 | db: 'cAuth',
24 | pass: '1214xmc0709fl',
25 | char: 'utf8mb4'
26 | },
27 |
28 | cos: {
29 | /**
30 | * 区域
31 | * @查看 https://cloud.tencent.com/document/product/436/6224
32 | */
33 | region: 'ap-guangzhou',
34 | // Bucket 名称
35 | fileBucket: 'wximg',
36 | // 文件夹
37 | uploadFolder: ''
38 | },
39 |
40 | // 微信登录态有效期
41 | wxLoginExpires: 7200
42 | }
43 |
44 | module.exports = process.env.NODE_ENV === 'local' ? Object.assign({}, CONF, require('./config.local')) : CONF;
45 |
--------------------------------------------------------------------------------
/server/tools/initdb.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 腾讯云微信小程序解决方案
3 | * Demo 数据库初始化脚本
4 | * @author Jason
5 | */
6 | const fs = require('fs')
7 | const path = require('path')
8 | const { mysql: config } = require('../config')
9 |
10 | console.log('\n======================================')
11 | console.log('开始初始化数据库...')
12 |
13 | // 初始化 SQL 文件路径
14 | const INIT_DB_FILE = path.join(__dirname, './cAuth.sql')
15 |
16 | const DB = require('knex')({
17 | client: 'mysql',
18 | connection: {
19 | host: config.host,
20 | port: config.port,
21 | user: config.user,
22 | password: config.pass,
23 | database: config.db,
24 | charset: config.char,
25 | multipleStatements: true
26 | }
27 | })
28 |
29 | console.log(`准备读取 SQL 文件:${INIT_DB_FILE}`)
30 |
31 | // 读取 .sql 文件内容
32 | const content = fs.readFileSync(INIT_DB_FILE, 'utf8')
33 |
34 | console.log('开始执行 SQL 文件...')
35 |
36 | // 执行 .sql 文件内容
37 | DB.raw(content).then(res => {
38 | console.log('数据库初始化成功!')
39 | process.exit(0)
40 | }, err => {
41 | throw new Error(err)
42 | })
43 |
--------------------------------------------------------------------------------
/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "koa-weapp-demo",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "app.js",
6 | "scripts": {
7 | "start": "pm2 start process.prod.json --no-daemon",
8 | "local-dev": "nodemon --config nodemon.json app.js",
9 | "initdb": "npm install && node tools/initdb.js"
10 | },
11 | "author": "Jason",
12 | "license": "MIT",
13 | "dependencies": {
14 | "axios": "^0.15.3",
15 | "knex": "^0.20.1",
16 | "koa": "^2.0.0",
17 | "koa-bodyparser": "^3.2.0",
18 | "koa-log4": "^2.1.0",
19 | "koa-router": "^7.0.1",
20 | "lodash": "^4.17.4",
21 | "mkdir-p": "0.0.7",
22 | "mysql": "^2.14.1",
23 | "pify": "^2.3.0",
24 | "wafer-node-sdk": "^1.4.1"
25 | },
26 | "devDependencies": {
27 | "babel-eslint": "^7.1.0",
28 | "debug": "^2.6.8",
29 | "eslint": "^3.9.1",
30 | "eslint-config-standard": "^6.2.1",
31 | "eslint-plugin-promise": "^3.3.1",
32 | "eslint-plugin-standard": "^2.0.1"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 | *.pid.lock
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 | # Coverage directory used by tools like istanbul
13 | coverage
14 | # nyc test coverage
15 | .nyc_output
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 | # Bower dependency directory (https://bower.io/)
19 | bower_components
20 | # node-waf configuration
21 | .lock-wscript
22 | # Compiled binary addons (http://nodejs.org/api/addons.html)
23 | build/Release
24 | # Dependency directories
25 | node_modules/
26 | jspm_packages/
27 | # Typescript v1 declaration files
28 | typings/
29 | # Optional npm cache directory
30 | .npm
31 | # Optional eslint cache
32 | .eslintcache
33 | # Optional REPL history
34 | .node_repl_history
35 | # Output of 'npm pack'
36 | *.tgz
37 | # Yarn Integrity file
38 | .yarn-integrity
39 | # dotenv environment variables file
40 | .env
41 | .vscode
42 | # ignore sh
43 | sh/
44 | # ignore test sdk.config.json
45 | sdk.config.json
46 | # ignore local config
47 | server/config.local.js
48 |
--------------------------------------------------------------------------------
/client/pages/fahuo/fahuo.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 常用地址
6 |
7 |
8 | {{item.provinceName}}{{item.cityName}}{{item.countyName}}{{item.detailInfo}}
9 | {{item.userName}} {{item.telNumber}}
10 |
11 |
12 |
13 |
14 |
15 |
16 | 添加发件地址
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/client/LICENSE:
--------------------------------------------------------------------------------
1 | LICENSE - "MIT License"
2 |
3 | Copyright (c) 2016 by Tencent Cloud
4 |
5 | Permission is hereby granted, free of charge, to any person
6 | obtaining a copy of this software and associated documentation
7 | files (the "Software"), to deal in the Software without
8 | restriction, including without limitation the rights to use,
9 | copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the
11 | Software is furnished to do so, subject to the following
12 | conditions:
13 |
14 | The above copyright notice and this permission notice shall be
15 | included in all copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 | OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/client/vendor/wafer2-client-sdk/LICENSE:
--------------------------------------------------------------------------------
1 | LICENSE - "MIT License"
2 |
3 | Copyright (c) 2016 by Tencent Cloud
4 |
5 | Permission is hereby granted, free of charge, to any person
6 | obtaining a copy of this software and associated documentation
7 | files (the "Software"), to deal in the Software without
8 | restriction, including without limitation the rights to use,
9 | copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the
11 | Software is furnished to do so, subject to the following
12 | conditions:
13 |
14 | The above copyright notice and this permission notice shall be
15 | included in all copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 | OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/client/pages/chat/chat.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | {{message.user.nickName}}
8 | {{message.content}}
9 |
10 |
11 |
12 | {{message.content}}
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/server/routes/index.js:
--------------------------------------------------------------------------------
1 | /**
2 | * ajax 服务路由集合
3 | */
4 | const router = require('koa-router')({
5 | prefix: '/weapp' // 定义所有路由的前缀都已 /weapp 开头
6 | })
7 | const controllers = require('../controllers')
8 |
9 | // 从 sdk 中取出中间件
10 | // 这里展示如何使用 Koa 中间件完成登录态的颁发与验证
11 | const { auth: { authorizationMiddleware, validationMiddleware } } = require('../qcloud')
12 |
13 | // --- 登录与授权 Demo --- //
14 | // 登录接口 /weapp/login
15 | router.get('/login', authorizationMiddleware, controllers.login)
16 | // 用户信息接口(可以用来验证登录态) /weapp/user
17 | router.get('/user', validationMiddleware, controllers.user)
18 |
19 |
20 | // --- 图片上传 Demo --- //
21 | // 图片上传接口,小程序端可以直接将 url 填入 wx.uploadFile 中 /weapp/upload
22 | router.post('/upload', controllers.upload)
23 |
24 | // --- 信道服务接口 Demo --- //
25 | // GET 用来响应请求信道地址的 /weapp/tunnel
26 | router.get('/tunnel', controllers.tunnel.get)
27 | // POST 用来处理信道传递过来的消息
28 | router.post('/tunnel', controllers.tunnel.post)
29 |
30 | // --- 客服消息接口 Demo --- //
31 | // GET 用来响应小程序后台配置时发送的验证请求 /weapp/message
32 | router.get('/message', controllers.message.get)
33 | // POST 用来处理微信转发过来的客服消息
34 | router.post('/message', controllers.message.post)
35 |
36 |
37 | router.get('/helloworld', controllers.helloworld)
38 | module.exports = router
39 |
--------------------------------------------------------------------------------
/client/pages/userCenter/user.js:
--------------------------------------------------------------------------------
1 | // pages/userCenter/user.js
2 | Page({
3 |
4 | /**
5 | * 页面的初始数据
6 | */
7 | data: {
8 |
9 |
10 | User:{}
11 | },
12 |
13 | /**
14 | * 生命周期函数--监听页面加载
15 | */
16 | onLoad: function(options) {
17 | var that = this;
18 | var temp;
19 | var Temp;
20 | wx.getStorage({
21 | key: 'weapp_session_F2C224D4-2BCE-4C64-AF9F-A6D872000D1A',
22 | success: function(res) {
23 | temp = res.data;
24 | Temp = Object.assign({},temp.userinfo)
25 | that.setData({
26 | User: Temp
27 | })
28 | },
29 | })
30 |
31 | },
32 |
33 | /**
34 | * 生命周期函数--监听页面初次渲染完成
35 | */
36 | onReady: function() {
37 |
38 | },
39 |
40 | /**
41 | * 生命周期函数--监听页面显示
42 | */
43 | onShow: function() {
44 |
45 | },
46 |
47 | /**
48 | * 生命周期函数--监听页面隐藏
49 | */
50 | onHide: function() {
51 |
52 | },
53 |
54 | /**
55 | * 生命周期函数--监听页面卸载
56 | */
57 | onUnload: function() {
58 |
59 | },
60 |
61 | /**
62 | * 页面相关事件处理函数--监听用户下拉动作
63 | */
64 | onPullDownRefresh: function() {
65 |
66 | },
67 |
68 | /**
69 | * 页面上拉触底事件的处理函数
70 | */
71 | onReachBottom: function() {
72 |
73 | },
74 |
75 | /**
76 | * 用户点击右上角分享
77 | */
78 | onShareAppMessage: function() {
79 |
80 | }
81 | })
--------------------------------------------------------------------------------
/server/tools/cAuth.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Navicat Premium Data Transfer
3 |
4 | Source Server : Localhost
5 | Source Server Type : MySQL
6 | Source Server Version : 50717
7 | Source Host : localhost
8 | Source Database : cAuth
9 |
10 | Target Server Type : MySQL
11 | Target Server Version : 50717
12 | File Encoding : utf-8
13 |
14 | Date: 08/10/2017 22:22:52 PM
15 | */
16 |
17 | SET NAMES utf8;
18 | SET FOREIGN_KEY_CHECKS = 0;
19 |
20 | -- ----------------------------
21 | -- Table structure for `cSessionInfo`
22 | -- ----------------------------
23 | DROP TABLE IF EXISTS `cSessionInfo`;
24 | CREATE TABLE `cSessionInfo` (
25 | `open_id` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
26 | `uuid` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
27 | `skey` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
28 | `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
29 | `last_visit_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
30 | `session_key` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
31 | `user_info` varchar(2048) COLLATE utf8mb4_unicode_ci NOT NULL,
32 | PRIMARY KEY (`open_id`),
33 | KEY `openid` (`open_id`) USING BTREE,
34 | KEY `skey` (`skey`) USING BTREE
35 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='会话管理用户信息';
36 |
37 | SET FOREIGN_KEY_CHECKS = 1;
38 |
--------------------------------------------------------------------------------
/client/pages/addCgi/addCgi.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 测试 CGI
7 |
8 |
9 | 期望输出:{"code":0,"data":{"msg":"Hello World"}}
10 |
11 |
12 | {{'请求结果:' + requestResult}}
13 |
14 |
15 |
16 |
17 |
18 | 快速添加CGI指引
19 | 1. 打开 server/routes/index.js 文件,添加如下语句:
20 |
21 |
22 | 2. 在 server/controllers 下新建一个 demo.js 文件,写入如下代码:
23 |
24 |
25 | 3. 点击开发者工具右上角“腾讯云” - “上传测试代码”,勾选“智能上传”
26 | 4. 点击测试 CGI 按钮,即可看到结果
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/client/pages/addCgi/addCgi.js:
--------------------------------------------------------------------------------
1 | //index.js
2 | var qcloud = require('../../vendor/wafer2-client-sdk/index')
3 | var config = require('../../config')
4 | var util = require('../../utils/util.js')
5 |
6 | Page({
7 | data: {
8 | requestResult: '',
9 | canIUseClipboard: wx.canIUse('setClipboardData')
10 | },
11 |
12 | testCgi: function () {
13 | util.showBusy('请求中...')
14 | var that = this
15 | qcloud.request({
16 | url: `${config.service.host}/weapp/demo`,
17 | login: false,
18 | success (result) {
19 | util.showSuccess('请求成功完成')
20 | that.setData({
21 | requestResult: JSON.stringify(result.data)
22 | })
23 | },
24 | fail (error) {
25 | util.showModel('请求失败', error);
26 | console.log('request fail', error);
27 | }
28 | })
29 | },
30 |
31 | copyCode: function (e) {
32 | var codeId = e.target.dataset.codeId
33 | wx.setClipboardData({
34 | data: code[codeId - 1],
35 | success: function () {
36 | util.showSuccess('复制成功')
37 | }
38 | })
39 | }
40 | })
41 |
42 | var code = [
43 | `router.get('/demo', controllers.demo)`,
44 | `module.exports = ctx => {
45 | ctx.state.data = {
46 | msg: 'Hello World'
47 | }
48 | }`
49 | ]
50 |
--------------------------------------------------------------------------------
/client/pages/fahuo/fahuo.js:
--------------------------------------------------------------------------------
1 | // pages/fahuo/fahuo.js
2 | var Address = new Array();
3 | Page({
4 |
5 | /**
6 | * 页面的初始数据
7 | */
8 | data: {
9 | address:[]
10 | },
11 |
12 | /**
13 | * 生命周期函数--监听页面加载
14 | */
15 | onLoad: function (options) {
16 | var that = this
17 | wx.getStorage({
18 | key: 'address',
19 | success: function(res) {
20 | that.setData({
21 | address:res.data
22 | })
23 | },
24 | })
25 | },
26 |
27 | /**
28 | * 生命周期函数--监听页面初次渲染完成
29 | */
30 | onReady: function () {
31 |
32 | },
33 |
34 | /**
35 | * 生命周期函数--监听页面显示
36 | */
37 | onShow: function () {
38 |
39 | },
40 |
41 | /**
42 | * 生命周期函数--监听页面隐藏
43 | */
44 | onHide: function () {
45 |
46 | },
47 |
48 | /**
49 | * 生命周期函数--监听页面卸载
50 | */
51 | onUnload: function () {
52 |
53 | },
54 |
55 | /**
56 | * 页面相关事件处理函数--监听用户下拉动作
57 | */
58 | onPullDownRefresh: function () {
59 |
60 | },
61 |
62 | /**
63 | * 页面上拉触底事件的处理函数
64 | */
65 | onReachBottom: function () {
66 |
67 | },
68 |
69 | /**
70 | * 用户点击右上角分享
71 | */
72 | onShareAppMessage: function () {
73 |
74 | },
75 |
76 | //用户选择收货地址
77 | chooseAddress: function () {
78 | var that = this;
79 | if (wx.chooseAddress) {
80 | wx.chooseAddress({
81 | success: function (res) {
82 | console.log(JSON.stringify(res));
83 | console.log(res);
84 | Address.push(res);
85 | console.log(Address);
86 | wx.setStorage({
87 | key: 'address',
88 | data:Address,
89 | });
90 | that.setData({
91 | address:Address
92 | })
93 | },
94 | fail: function (err) {
95 | console.log(JSON.stringify(err));
96 | console.info("收货地址授权失败");
97 | wx.showModal({
98 | title: '授权失败',
99 | content: '您将无法进行下单支付;重新授权请删除小程序后再次进入',
100 | duration: 2000
101 | })
102 | }
103 | })
104 | } else {
105 | console.log('当前微信版本不支持chooseAddress');
106 | }
107 | }
108 | })
--------------------------------------------------------------------------------
/client/pages/addCgi/addCgi.wxss:
--------------------------------------------------------------------------------
1 | /**index.wxss**/
2 | page {
3 | background: #F6F6F6;
4 | display: flex;
5 | flex-direction: column;
6 | justify-content: flex-start;
7 | }
8 |
9 | .list {
10 | margin-top: 40rpx;
11 | height: auto;
12 | width: 100%;
13 | background: #FFF;
14 | padding: 0 0 0 40rpx;
15 | border: 1px solid rgba(0, 0, 0, .1);
16 | border-left: none;
17 | border-right: none;
18 | transition: all 300ms ease;
19 | display: flex;
20 | flex-direction: column;
21 | align-items: flex-start;
22 | box-sizing: border-box;
23 | }
24 |
25 | .list-item {
26 | width: 100%;
27 | padding: 0;
28 | line-height: 104rpx;
29 | font-size: 34rpx;
30 | color: #007AFF;
31 | border-top: 1px solid rgba(0, 0, 0, .1);
32 | display: flex;
33 | flex-direction: row;
34 | align-content: center;
35 | justify-content: space-between;
36 | box-sizing: border-box;
37 | }
38 |
39 | .list-item:first-child {
40 | border-top: none;
41 | }
42 |
43 | .request-text {
44 | color: #222;
45 | padding: 20rpx 0;
46 | font-size: 24rpx;
47 | line-height: 36rpx;
48 | word-break: break-all;
49 | }
50 |
51 | .guide {
52 | width: 100%;
53 | padding: 40rpx;
54 | box-sizing: border-box;
55 | display: flex;
56 | flex-direction: column;
57 | }
58 |
59 | .guide .headline {
60 | font-size: 34rpx;
61 | font-weight: bold;
62 | color: #555;
63 | line-height: 40rpx;
64 | }
65 |
66 | .guide .p {
67 | margin-top: 20rpx;
68 | font-size: 28rpx;
69 | line-height: 36rpx;
70 | color: #666;
71 | }
72 |
73 | .guide .code {
74 | margin-top: 20rpx;
75 | background: rgba(0, 0, 0, .8);
76 | padding: 20rpx;
77 | font-size: 28rpx;
78 | line-height: 36rpx;
79 | border-radius: 6rpx;
80 | color: #FFF;
81 | }
82 |
83 | .guide .image1 {
84 | margin-top: 20rpx;
85 | max-width: 100%;
86 | width: 356px;
87 | height: 47px;
88 | }
89 |
90 | .guide .image2 {
91 | margin-top: 20rpx;
92 | width: 264px;
93 | height: 100px;
94 | }
95 |
96 | .guide .copyBtn {
97 | width: 180rpx;
98 | font-size: 20rpx;
99 | margin-top: 16rpx;
100 | margin-left: 0;
101 | }
102 |
--------------------------------------------------------------------------------
/client/pages/index/rule.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 里程费
9 |
10 |
11 | 3公里内:12元
12 |
13 |
14 |
15 |
16 | 3-10公里:2.0元/公里
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | 超过10公里:2.5元/公里
25 |
26 |
27 |
28 | OFFICE订单费
29 |
30 |
31 | 5公里内:19元
32 |
33 |
34 |
35 |
36 | 5-10公里:2.0元/公里
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | 超过10公里:2.5元/公里
45 |
46 |
47 |
48 |
49 | 排队费用
50 |
51 |
52 | 起步价(含60分钟)20.0元
53 |
54 |
55 |
56 |
57 | 1-10小时:15元/半小时
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | 延长排队(线下支付)15元/半小时
66 |
67 |
68 |
69 | 夜间服务费
70 |
71 |
72 | 00:00-07:00每单加8元
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/client/pages/login/login.js:
--------------------------------------------------------------------------------
1 | // pages/login/login.js
2 |
3 | // pages/message/message.js
4 | var qcloud = require('../../vendor/wafer2-client-sdk/index');
5 |
6 | // 引入配置
7 | var config = require('../../config');
8 | // 显示成功提示
9 | var showSuccess = text => wx.showToast({
10 | title: text,
11 | icon: 'success'
12 | });
13 |
14 | // 显示失败提示
15 | var showModel = (title, content) => {
16 | wx.hideToast();
17 |
18 | wx.showModal({
19 | title,
20 | content: JSON.stringify(content),
21 | showCancel: false
22 | });
23 | };
24 | Page({
25 |
26 | /**
27 | * 页面的初始数据
28 | */
29 | data: {
30 |
31 | },
32 |
33 | /**
34 | * 生命周期函数--监听页面加载
35 | */
36 | onLoad: function (options) {
37 |
38 | },
39 |
40 | /**
41 | * 生命周期函数--监听页面初次渲染完成
42 | */
43 | onReady: function () {
44 |
45 | },
46 |
47 | /**
48 | * 生命周期函数--监听页面显示
49 | */
50 | onShow: function () {
51 |
52 | },
53 |
54 | /**
55 | * 生命周期函数--监听页面隐藏
56 | */
57 | onHide: function () {
58 |
59 | },
60 |
61 | /**
62 | * 生命周期函数--监听页面卸载
63 | */
64 | onUnload: function () {
65 |
66 | },
67 |
68 | /**
69 | * 页面相关事件处理函数--监听用户下拉动作
70 | */
71 | onPullDownRefresh: function () {
72 |
73 | },
74 |
75 | /**
76 | * 页面上拉触底事件的处理函数
77 | */
78 | onReachBottom: function () {
79 |
80 | },
81 |
82 | /**
83 | * 用户点击右上角分享
84 | */
85 | onShareAppMessage: function () {
86 |
87 | },
88 | bindGetUserInfo: function (e) {
89 | const session = qcloud.Session.get()
90 |
91 | if (session) {
92 | // 第二次登录
93 | // 或者本地已经有登录态
94 | // 可使用本函数更新登录态
95 | qcloud.loginWithCode({
96 | success: res => {
97 | this.setData({ userInfo: res, logged: true })
98 | showSuccess('授权成功')
99 | },
100 | fail: err => {
101 | console.error(err)
102 | showModel('授权错误', err.message)
103 | }
104 | })
105 | } else {
106 | // 首次登录
107 | qcloud.login({
108 | success: res => {
109 | this.setData({ userInfo: res, logged: true })
110 | showSuccess('授权成功')
111 | setTimeout(function(){
112 | wx.navigateBack({
113 |
114 | })
115 | },500)
116 | },
117 | fail: err => {
118 | console.error(err)
119 | showModel('授权错误', err.message)
120 | }
121 | })
122 | }
123 | },
124 | })
--------------------------------------------------------------------------------
/client/pages/test/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 登录接口测试
5 |
6 |
7 |
8 |
9 |
10 | 清除登录会话
11 |
12 |
13 |
14 | 带会话请求测试
15 |
16 |
17 | 请求
18 |
19 |
20 |
21 | 上传图片测试
22 |
23 |
24 | 上传图片
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | 客服消息测试
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | WebSocket 信道服务测试
42 |
43 |
44 |
45 | 信道
46 |
47 | {{tunnelStatusText[tunnelStatus]}}
48 |
49 |
50 |
51 |
52 | 发送消息
53 | 测试重连
54 |
55 |
56 |
--------------------------------------------------------------------------------
/server/README.md:
--------------------------------------------------------------------------------
1 | # 腾讯云小程序解决方案 Demo - Node.js
2 |
3 | Node.js 版本 Wafer SDK 的服务端 Demo
4 |
5 | ## 下载源码
6 |
7 | 你可以直接通过 git 将代码 clone 到本地,也可以点击[这里](https://github.com/tencentyun/wafer-node-server-demo/releases)下载。
8 |
9 | ```bash
10 | git clone https://github.com/tencentyun/wafer-node-server-demo.git
11 | ```
12 |
13 | ## 开始使用
14 |
15 | #### 安装依赖
16 |
17 | ```bash
18 | # 安装全局依赖
19 | npm i pm2 nodemon -g
20 |
21 | # 安装项目依赖
22 | npm i
23 | ```
24 |
25 | #### 启动项目
26 |
27 | ```bash
28 | # 开发环境,监听文件变化自动重启,并会输出 debug 信息
29 | tnpm run dev
30 |
31 | # 线上部署环境
32 | tnpm start
33 | ```
34 |
35 | 按照[小程序创建资源配置指引](https://github.com/tencentyun/weapp-doc)进行操作,可以得到运行本示例所需的资源和服务,其中包括已部署好的示例代码及自动下发的 SDK 配置文件 `/etc/qcloud/sdk.config`。
36 |
37 | - 示例代码部署目录:`/data/release/node-weapp-demo`
38 | - 运行示例的 Node 版本:`v8.1.0`
39 | - Node 进程管理工具:`pm2`
40 |
41 | ## 项目结构
42 |
43 | ```
44 | koa-weapp-demo
45 | ├── README.md
46 | ├── app.js
47 | ├── controllers
48 | │ ├── index.js
49 | │ ├── login.js
50 | │ ├── message.js
51 | │ ├── tunnel.js
52 | │ ├── upload.js
53 | │ └── user.js
54 | ├── middlewares
55 | │ └── response.js
56 | ├── config.js
57 | ├── package.json
58 | ├── process.json
59 | ├── nodemon.json
60 | ├── qcloud.js
61 | └── routes
62 | └── index.js
63 | ```
64 | `app.js` 是 Demo 的主入口文件,Demo 使用 Koa 框架,在 `app.js` 创建一个 Koa 实例并响应请求。
65 |
66 | `routes/index.js` 是 Demo 的路由定义文件
67 |
68 | `controllers` 存放 Demo 所有业务逻辑的目录,`index.js` 不需要修改,他会动态的将 `controllers` 文件夹下的目录结构映射成 modules 的 Object,例如 Demo 中的目录将会被映射成如下的结构:
69 |
70 | ```javascript
71 | // index.js 输出
72 | {
73 | login: require('login'),
74 | message: require('message'),
75 | tunnel: require('tunnel'),
76 | upload: require('upload'),
77 | user: require('user')
78 | }
79 | ```
80 |
81 | `qcloud.js` 导出了一个 SDK 的单例,包含了所有的 SDK 接口,之后使用的时候只需要 `require` 这个文件就行,无需重复初始化 SDK。
82 |
83 | `config.js` 主要的配置如下:
84 |
85 | ```javascript
86 | {
87 | port: '5757', // 项目启动的端口
88 |
89 | appId: 'wx00dd00dd00dd00dd', // 微信小程序 App ID
90 | appSecret: 'abcdefg', // 微信小程序 App Secret
91 | wxLoginExpires: 7200, // 微信登录态有效期
92 | useQcloudLogin: false, // 是否使用腾讯云代理登录
93 |
94 | /**
95 | * MySQL 配置,用来存储用户登录态和用户信息
96 | * 如果不提供 MySQL 配置,模式会使用自动配置好的本地镜像中的 MySQL 储存信息
97 | * 具体查看文档-登录态储存和校验
98 | **/
99 | mysql: {
100 | host: 'localhost',
101 | port: 3306,
102 | user: 'root',
103 | db: 'cAuth',
104 | pass: '',
105 | char: 'utf8'
106 | },
107 |
108 | // COS 配置,用于上传模块使用
109 | cos: {
110 | /**
111 | * 区域
112 | * 华北:cn-north
113 | * 华东:cn-east
114 | * 华南:cn-south
115 | * 西南:cn-southwest
116 | */
117 | region: 'cn-south',
118 | fileBucket: 'test', // Bucket 名称
119 | uploadFolder: '' // 文件夹
120 | }
121 | }
122 | ```
123 |
124 | 除了 `config.js` ,腾讯云还会在你初始化小程序解决方案的时候,向你的机器下发 `sdk.config`,里面包含了你的腾讯云 AppId、SecretId、SecretKey 和服务器等信息,无需修改,`qcloud.js` 会自动引入。如果你想要在自己的机器上部署 SDK 的 Demo,请查看[自行部署 Demo 说明]()。
125 |
126 | 除此以外,关于 SDK 的详细配置信息,还可以查看 [SDK 的 API 文档]()。
--------------------------------------------------------------------------------
/client/pages/test/index.wxss:
--------------------------------------------------------------------------------
1 | .root {
2 | background: #efeff4;
3 | position: absolute;
4 | top: 0;
5 | left: 0;
6 | right: 0;
7 | bottom:0;
8 | }
9 | .line {
10 | padding-top: 30rpx;
11 | }
12 | .line text {
13 | color: #6D6D72;
14 | font-size: 28rpx;
15 | margin-left: 40rpx;
16 | }
17 | .line-control {
18 | border-bottom: #d9d9d9 1px solid;
19 | border-top: #d9d9d9 1px solid;
20 | background-color: #fff;
21 | margin-top: 10rpx;
22 | }
23 | .line-control .item {
24 | box-sizing: border-box;
25 | text-align: left;
26 | color: #007AFF;
27 | font-size: 32rpx;
28 | padding-left: 40rpx;
29 | position: relative;
30 | }
31 | .line-control .item:active {
32 | background: #d9d9d9;
33 | }
34 | .line-control .item.flag {
35 | color: #333;
36 | }
37 | .line-control .item.flag:active {
38 | background: #fff;
39 | }
40 | .line-control .item-inner {
41 | border-bottom: #d9d9d9 1px solid;
42 | height: 90rpx;
43 | line-height: 90rpx;
44 | }
45 | .line-control .item-inner::after {
46 | border: none;
47 | }
48 |
49 | .line-control .login-button {
50 | background-color: white;
51 | border-radius: 0;
52 | color: #007AFF;
53 | font-size: 38rpx;
54 | text-align: left;
55 | padding-left: 0;
56 | }
57 |
58 | .line-control .item-image {
59 | text-align: center;
60 | }
61 | .line-control .item.button {
62 | padding: 10px 20px;
63 | }
64 | .line-control .item.button:active {
65 | background-color: #fff;
66 | }
67 | .line-control .item-image .image {
68 | width: 380rpx;
69 | height: 380rpx;
70 | text-align: center;
71 | margin: 10rpx;
72 | }
73 | .line-control .item:last-child .item-inner {
74 | border:none;
75 | }
76 | .line-control .switch {
77 | vertical-align: middle;
78 | line-height: normal;
79 | }
80 | .line-control text {
81 | display: inline-block;
82 | vertical-align: middle;
83 | margin-right: 10rpx;
84 | color: #8E8E93;
85 | margin-left: 0;
86 | }
87 | .line-control .switch-status {
88 | color: #999;
89 | position: absolute;
90 | right: 40rpx;
91 | top: 0;
92 | }
93 | .line-control .item.disabled {
94 | color: #999
95 | }
96 | .line-control .item.disabled:active {
97 | background: none;
98 | }
99 | .line .demo {
100 | height: 90rpx;
101 | line-height: 90rpx;
102 | box-sizing: border-box;
103 | text-align: left;
104 | color: #333;
105 | background-color: #fff;
106 | position: relative;
107 | font-size: 32rpx;
108 | padding-left: 40rpx;
109 | }
110 | .line .demo .link {
111 | position: absolute;
112 | right: 40rpx;
113 | top: 0rpx;
114 | color: #8E8E93;
115 | }
116 | .hide {
117 | display: none
118 | }
119 |
120 | @media (max-width : 360px) {
121 | .line text {
122 | font-size: 36rpx;
123 | }
124 | .line-control .item-inner {
125 | border-bottom: #d9d9d9 1px solid;
126 | height: 110rpx;
127 | line-height: 110rpx;
128 | }
129 | .line-control .item {
130 | height: 110rpx;
131 | line-height: 110rpx;
132 | box-sizing: border-box;
133 | text-align: left;
134 | color: #007AFF;
135 | font-size: 38rpx;
136 | padding-left: 40rpx;
137 | position: relative
138 | }
139 | .line .demo {
140 | height: 110rpx;
141 | line-height: 110rpx;
142 | font-size: 38rpx;
143 | padding-left: 40rpx;
144 | }
145 | }
--------------------------------------------------------------------------------
/client/vendor/wafer2-client-sdk/lib/request.js:
--------------------------------------------------------------------------------
1 | var constants = require('./constants');
2 | var utils = require('./utils');
3 | var Session = require('./session');
4 | var loginLib = require('./login');
5 |
6 | var noop = function noop() {};
7 |
8 | var buildAuthHeader = function buildAuthHeader(session) {
9 | var header = {};
10 |
11 | if (session) {
12 | header[constants.WX_HEADER_SKEY] = session;
13 | }
14 |
15 | return header;
16 | };
17 |
18 | /***
19 | * @class
20 | * 表示请求过程中发生的异常
21 | */
22 | var RequestError = (function () {
23 | function RequestError(type, message) {
24 | Error.call(this, message);
25 | this.type = type;
26 | this.message = message;
27 | }
28 |
29 | RequestError.prototype = new Error();
30 | RequestError.prototype.constructor = RequestError;
31 |
32 | return RequestError;
33 | })();
34 |
35 | function request(options) {
36 | if (typeof options !== 'object') {
37 | var message = '请求传参应为 object 类型,但实际传了 ' + (typeof options) + ' 类型';
38 | throw new RequestError(constants.ERR_INVALID_PARAMS, message);
39 | }
40 |
41 | var requireLogin = options.login;
42 | var success = options.success || noop;
43 | var fail = options.fail || noop;
44 | var complete = options.complete || noop;
45 | var originHeader = options.header || {};
46 |
47 | // 成功回调
48 | var callSuccess = function () {
49 | success.apply(null, arguments);
50 | complete.apply(null, arguments);
51 | };
52 |
53 | // 失败回调
54 | var callFail = function (error) {
55 | fail.call(null, error);
56 | complete.call(null, error);
57 | };
58 |
59 | // 是否已经进行过重试
60 | var hasRetried = false;
61 |
62 | if (requireLogin) {
63 | doRequestWithLogin();
64 | } else {
65 | doRequest();
66 | }
67 |
68 | // 登录后再请求
69 | function doRequestWithLogin() {
70 | loginLib.loginWithCode({ success: doRequest, fail: callFail });
71 | }
72 |
73 | // 实际进行请求的方法
74 | function doRequest() {
75 | var authHeader = {}
76 |
77 | var session = Session.get();
78 |
79 | if (session) {
80 | authHeader = buildAuthHeader(session.skey);
81 | }
82 |
83 | wx.request(utils.extend({}, options, {
84 | header: utils.extend({}, originHeader, authHeader),
85 |
86 | success: function (response) {
87 | var data = response.data;
88 |
89 | var error, message;
90 | if ((data && data.code === -1) || response.statusCode === 401) {
91 | Session.clear();
92 | // 如果是登录态无效,并且还没重试过,会尝试登录后刷新凭据重新请求
93 | if (!hasRetried) {
94 | hasRetried = true;
95 | doRequestWithLogin();
96 | return;
97 | }
98 |
99 | message = '登录态已过期';
100 | error = new RequestError(data.error, message);
101 |
102 | callFail(error);
103 | return;
104 | } else {
105 | callSuccess.apply(null, arguments);
106 | }
107 | },
108 |
109 | fail: callFail,
110 | complete: noop,
111 | }));
112 | };
113 |
114 | };
115 |
116 | module.exports = {
117 | RequestError: RequestError,
118 | request: request,
119 | };
--------------------------------------------------------------------------------
/client/pages/yaoqiu/yaoqiu.js:
--------------------------------------------------------------------------------
1 | // pages/yaoqiu/yaoqiu.js
2 | Page({
3 |
4 | /**
5 | * 页面的初始数据
6 | */
7 | data: {
8 |
9 | grids: [{
10 | id:0,
11 | flag:0,
12 | image: "/images/icon/eat.png",
13 | name: "餐饮"
14 | },
15 | {
16 | id: 1,
17 | flag: 0,
18 | image:'/images/icon/file.png',
19 | name: "文件"
20 | },
21 |
22 | {
23 | id: 2,
24 | flag: 0,
25 | image:'/images/icon/yaopin.png',
26 | name: "药品"
27 | },
28 |
29 | {
30 | id: 3,
31 | flag: 0,
32 | image:'/images/icon/cake.png',
33 | name: "蛋糕"
34 | },
35 | {
36 | id: 4,
37 | flag: 0,
38 | image: '/images/icon/flower.png',
39 | name: "鲜花"
40 | },
41 | {
42 | id: 5,
43 | flag: 0,
44 | image:'/images/icon/key.png',
45 | name: "钥匙"
46 | },
47 | {
48 | id:6,
49 | flag: 0,
50 | image:'/images/icon/shuma.png',
51 | name: "数码"
52 | },
53 | {
54 | id: 7,
55 | flag: 0,
56 | image:'/images/icon/clothes.png',
57 | name: "服饰"
58 | },
59 | {
60 | id: 8,
61 | flag: 0,
62 | image:'/images/icon/other.png',
63 | name: "其他"
64 | }
65 | ],
66 | weight: '小于5'
67 | },
68 |
69 | /**
70 | * 生命周期函数--监听页面加载
71 | */
72 | onLoad: function(options) {
73 |
74 | },
75 |
76 | /**
77 | * 生命周期函数--监听页面初次渲染完成
78 | */
79 | onReady: function() {
80 |
81 | },
82 |
83 | /**
84 | * 生命周期函数--监听页面显示
85 | */
86 | onShow: function() {
87 |
88 | },
89 |
90 | /**
91 | * 生命周期函数--监听页面隐藏
92 | */
93 | onHide: function() {
94 |
95 | },
96 |
97 | /**
98 | * 生命周期函数--监听页面卸载
99 | */
100 | onUnload: function() {
101 |
102 | },
103 |
104 | /**
105 | * 页面相关事件处理函数--监听用户下拉动作
106 | */
107 | onPullDownRefresh: function() {
108 |
109 | },
110 |
111 | /**
112 | * 页面上拉触底事件的处理函数
113 | */
114 | onReachBottom: function() {
115 |
116 | },
117 |
118 | /**
119 | * 用户点击右上角分享
120 | */
121 | onShareAppMessage: function() {
122 |
123 | },
124 | slider: function(e) {
125 | var that = this;
126 | if (e.detail.value == 4) {
127 | that.setData({
128 | weight: "小于5"
129 | })
130 | } else {
131 | that.setData({
132 | weight: e.detail.value
133 | })
134 | }
135 | },
136 | slider2: function(e) {
137 | var that = this;
138 | if (e.detail.value == 4) {
139 | that.setData({
140 | weight: "小于5"
141 | })
142 | } else {
143 | that.setData({
144 | weight: e.detail.value
145 | })
146 | }
147 | },
148 |
149 | select:function(event){
150 | var item = event.currentTarget.dataset.item;
151 | item.flag = 1;
152 | var id = parseInt(item.id);
153 | let grids = this.data.grids;
154 | grids[id].flag = item.flag;
155 | this.setData({
156 | grids:grids
157 | })
158 | console.log(this.data.grids);
159 |
160 | },
161 | submit:function(){
162 | let grids = this.data.grids;
163 | var detail ;
164 | for( var i = 0; i < grids.length; i++) {
165 | if(grids[i].flag == 1) {
166 | detail = grids[i].name;
167 | }
168 | }
169 | console.log(detail);
170 | wx.reLaunch({
171 |
172 | url: '/pages/index/index?thingType=' + detail + "&weight=" + this.data.weight,
173 | })
174 | }
175 | })
--------------------------------------------------------------------------------
/server/controllers/tunnel.js:
--------------------------------------------------------------------------------
1 | const { tunnel } = require('../qcloud')
2 | const debug = require('debug')('koa-weapp-demo')
3 |
4 | /**
5 | * 这里实现一个简单的聊天室
6 | * userMap 为 tunnelId 和 用户信息的映射
7 | * 实际使用请使用数据库存储
8 | */
9 | const userMap = {}
10 |
11 | // 保存 当前已连接的 WebSocket 信道ID列表
12 | const connectedTunnelIds = []
13 |
14 | /**
15 | * 调用 tunnel.broadcast() 进行广播
16 | * @param {String} type 消息类型
17 | * @param {String} content 消息内容
18 | */
19 | const $broadcast = (type, content) => {
20 | tunnel.broadcast(connectedTunnelIds, type, content)
21 | .then(result => {
22 | const invalidTunnelIds = result.data && result.data.invalidTunnelIds || []
23 |
24 | if (invalidTunnelIds.length) {
25 | console.log('检测到无效的信道 IDs =>', invalidTunnelIds)
26 |
27 | // 从 userMap 和 connectedTunnelIds 中将无效的信道记录移除
28 | invalidTunnelIds.forEach(tunnelId => {
29 | delete userMap[tunnelId]
30 |
31 | const index = connectedTunnelIds.indexOf(tunnelId)
32 | if (~index) {
33 | connectedTunnelIds.splice(index, 1)
34 | }
35 | })
36 | }
37 | })
38 | }
39 |
40 | /**
41 | * 调用 TunnelService.closeTunnel() 关闭信道
42 | * @param {String} tunnelId 信道ID
43 | */
44 | const $close = (tunnelId) => {
45 | tunnel.closeTunnel(tunnelId)
46 | }
47 |
48 | /**
49 | * 实现 onConnect 方法
50 | * 在客户端成功连接 WebSocket 信道服务之后会调用该方法,
51 | * 此时通知所有其它在线的用户当前总人数以及刚加入的用户是谁
52 | */
53 | function onConnect (tunnelId) {
54 | console.log(`[onConnect] =>`, { tunnelId })
55 |
56 | if (tunnelId in userMap) {
57 | connectedTunnelIds.push(tunnelId)
58 |
59 | $broadcast('people', {
60 | 'total': connectedTunnelIds.length,
61 | 'enter': userMap[tunnelId]
62 | })
63 | } else {
64 | console.log(`Unknown tunnelId(${tunnelId}) was connectd, close it`)
65 | $close(tunnelId)
66 | }
67 | }
68 |
69 | /**
70 | * 实现 onMessage 方法
71 | * 客户端推送消息到 WebSocket 信道服务器上后,会调用该方法,此时可以处理信道的消息。
72 | * 在本示例,我们处理 `speak` 类型的消息,该消息表示有用户发言。
73 | * 我们把这个发言的信息广播到所有在线的 WebSocket 信道上
74 | */
75 | function onMessage (tunnelId, type, content) {
76 | console.log(`[onMessage] =>`, { tunnelId, type, content })
77 |
78 | switch (type) {
79 | case 'speak':
80 | if (tunnelId in userMap) {
81 | $broadcast('speak', {
82 | 'who': userMap[tunnelId],
83 | 'word': content.word
84 | })
85 | } else {
86 | $close(tunnelId)
87 | }
88 | break
89 |
90 | default:
91 | break
92 | }
93 | }
94 |
95 | /**
96 | * 实现 onClose 方法
97 | * 客户端关闭 WebSocket 信道或者被信道服务器判断为已断开后,
98 | * 会调用该方法,此时可以进行清理及通知操作
99 | */
100 | function onClose (tunnelId) {
101 | console.log(`[onClose] =>`, { tunnelId })
102 |
103 | if (!(tunnelId in userMap)) {
104 | console.log(`[onClose][Invalid TunnelId]=>`, tunnelId)
105 | $close(tunnelId)
106 | return
107 | }
108 |
109 | const leaveUser = userMap[tunnelId]
110 | delete userMap[tunnelId]
111 |
112 | const index = connectedTunnelIds.indexOf(tunnelId)
113 | if (~index) {
114 | connectedTunnelIds.splice(index, 1)
115 | }
116 |
117 | // 聊天室没有人了(即无信道ID)不再需要广播消息
118 | if (connectedTunnelIds.length > 0) {
119 | $broadcast('people', {
120 | 'total': connectedTunnelIds.length,
121 | 'leave': leaveUser
122 | })
123 | }
124 | }
125 |
126 | module.exports = {
127 | // 小程序请求 websocket 地址
128 | get: async ctx => {
129 | const data = await tunnel.getTunnelUrl(ctx.req)
130 | const tunnelInfo = data.tunnel
131 |
132 | userMap[tunnelInfo.tunnelId] = data.userinfo
133 |
134 | ctx.state.data = tunnelInfo
135 | },
136 |
137 | // 信道将信息传输过来的时候
138 | post: async ctx => {
139 | const packet = await tunnel.onTunnelMessage(ctx.request.body)
140 |
141 | debug('Tunnel recive a package: %o', packet)
142 |
143 | switch (packet.type) {
144 | case 'connect':
145 | onConnect(packet.tunnelId)
146 | break
147 | case 'message':
148 | onMessage(packet.tunnelId, packet.content.messageType, packet.content.messageContent)
149 | break
150 | case 'close':
151 | onClose(packet.tunnelId)
152 | break
153 | }
154 | }
155 |
156 | }
157 |
--------------------------------------------------------------------------------
/client/pages/libs/qqmap-wx-jssdk.min.js:
--------------------------------------------------------------------------------
1 | var _createClass=function(){function a(e,c){for(var b=0;b
2 |
3 |
4 |
5 | 用户信息
6 |
7 |
8 |
9 |
10 |
11 |
12 | {{User.nickName}}
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | 我的订单
29 |
30 |
31 |
32 |
33 |
34 |
35 | 我的红包
36 |
37 |
38 |
39 |
40 |
41 |
42 | 邀请好友送红包
43 |
44 |
45 |
46 |
47 |
48 |
49 | 意见反馈
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | 设置
65 |
66 |
67 |
68 |
69 |
70 |
71 | 跑腿员招募
72 |
73 |
74 |
75 |
76 |
77 |
78 | 联系客服
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
--------------------------------------------------------------------------------
/client/vendor/wafer2-client-sdk/lib/login.js:
--------------------------------------------------------------------------------
1 | /**
2 | * README!!!
3 | * 为了兼容微信修改的登录逻辑
4 | * 这里对登录的 SDK 进行重构
5 | * 微信公告:https://developers.weixin.qq.com/blogdetail?action=get_post_info&lang=zh_CN&token=&docid=0000a26e1aca6012e896a517556c01
6 | */
7 | var constants = require('./constants');
8 | var Session = require('./session');
9 |
10 | /**
11 | * 微信登录,获取 code 和 encryptData
12 | */
13 | function getWxLoginResult (cb) {
14 | wx.login({
15 | success (loginResult) {
16 | wx.getUserInfo({
17 | success (userResult) {
18 | cb(null, {
19 | code: loginResult.code,
20 | encryptedData: userResult.encryptedData,
21 | iv: userResult.iv,
22 | userInfo: userResult.userInfo
23 | })
24 | },
25 | fail (userError) {
26 | cb(new Error('获取微信用户信息失败,请检查网络状态'), null)
27 | }
28 | });
29 | },
30 | fail (loginError) {
31 | cb(new Error('微信登录失败,请检查网络状态'), null)
32 | }
33 | })
34 | }
35 |
36 | const noop = function noop() {}
37 | const defaultOptions = {
38 | method: 'GET',
39 | success: noop,
40 | fail: noop,
41 | loginUrl: null,
42 | }
43 |
44 | /**
45 | * @method
46 | * 进行服务器登录,以获得登录会话
47 | * 受限于微信的限制,本函数需要在 的回调函数中调用
48 | * 需要先使用