├── .gitignore
├── pages
├── my
│ ├── index.wxss
│ ├── index.json
│ ├── index.wxml
│ └── index.js
├── detail
│ ├── index.wxss
│ ├── index.json
│ ├── index.wxml
│ └── index.js
├── recycle-list
│ ├── index.wxss
│ ├── index.json
│ ├── index.wxml
│ └── index.js
├── map
│ ├── index.json
│ ├── index.wxml
│ ├── index.wxss
│ └── index.js
├── index
│ ├── index.json
│ ├── index.wxss
│ ├── index.js
│ └── index.wxml
├── address-detail_1
│ ├── index.json
│ ├── index.wxml
│ ├── index.wxss
│ └── index.js
├── address-detail_2
│ ├── index.json
│ ├── index.wxss
│ ├── index.wxml
│ └── index.js
└── address-detail_3
│ ├── index.json
│ ├── index.wxss
│ ├── index.wxml
│ └── index.js
├── components
├── area-select
│ ├── index.wxss
│ ├── index.json
│ ├── index.wxml
│ └── index.js
├── authorize
│ ├── mixin.js
│ ├── index.json
│ ├── index.wxss
│ ├── index.wxml
│ └── index.js
└── navbar
│ ├── index.json
│ ├── index.wxml
│ ├── index.wxss
│ └── index.js
├── images
└── marker.png
├── common
├── behavior.js
├── emun.js
└── globalMixin.js
├── custom-tab-bar
├── index.wxss
├── index.json
├── index.wxml
└── index.js
├── sitemap.json
├── api
└── user.js
├── utils
├── app.js
├── request.js
├── mixin.js
├── smartWeChat
│ ├── README.md
│ └── js
│ │ └── address_parse.js
├── authLogin.js
├── utils.js
└── qqmap-wx-jssdk.min.js
├── gulpfile.js
├── package.json
├── config.js
├── LICENSE
├── app.json
├── app.js
├── project.private.config.json
├── css
└── variables.wxss
├── fonts
└── iconfont.wxss
├── project.config.json
├── app.wxss
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 | /miniprogram_npm/
--------------------------------------------------------------------------------
/pages/my/index.wxss:
--------------------------------------------------------------------------------
1 | /* pages/page1/index.wxss */
--------------------------------------------------------------------------------
/pages/detail/index.wxss:
--------------------------------------------------------------------------------
1 | /* pages/detail/index.wxss */
--------------------------------------------------------------------------------
/pages/detail/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {}
3 | }
--------------------------------------------------------------------------------
/pages/my/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {}
3 | }
--------------------------------------------------------------------------------
/pages/detail/index.wxml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/components/area-select/index.wxss:
--------------------------------------------------------------------------------
1 | /* components/area-select.wxss */
--------------------------------------------------------------------------------
/pages/recycle-list/index.wxss:
--------------------------------------------------------------------------------
1 | /* pages/recycle-list/index.wxss */
--------------------------------------------------------------------------------
/images/marker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KiteWorld/wx_template/HEAD/images/marker.png
--------------------------------------------------------------------------------
/pages/my/index.wxml:
--------------------------------------------------------------------------------
1 |
2 | pages/page1/index.wxml
--------------------------------------------------------------------------------
/components/authorize/mixin.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | data: {
3 | isShowAuth: false,
4 | authType: "UserInfo",
5 | }
6 | }
--------------------------------------------------------------------------------
/common/behavior.js:
--------------------------------------------------------------------------------
1 | export const commomProp = Behavior({
2 | data: {
3 | activeColor: "#d70039",
4 | mainColor: "#707070",
5 | }
6 | })
--------------------------------------------------------------------------------
/components/authorize/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "van-dialog": "@vant/weapp/dialog/index"
5 | }
6 | }
--------------------------------------------------------------------------------
/pages/map/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "navbar": "/components/navbar/index",
4 | "van-search": "@vant/weapp/search/index"
5 | }
6 | }
--------------------------------------------------------------------------------
/pages/index/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "van-icon": "@vant/weapp/icon/index",
4 | "authorize": "/components/authorize/index"
5 | }
6 | }
--------------------------------------------------------------------------------
/components/area-select/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "van-area": "@vant/weapp/area/index",
5 | "van-popup": "@vant/weapp/popup/index"
6 | }
7 | }
--------------------------------------------------------------------------------
/components/navbar/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "van-nav-bar": "@vant/weapp/nav-bar/index",
5 | "van-icon": "@vant/weapp/icon/index"
6 | }
7 | }
--------------------------------------------------------------------------------
/custom-tab-bar/index.wxss:
--------------------------------------------------------------------------------
1 | .my-tabbar {
2 | --tabbar-height: 100rpx;
3 | --tabbar-item-font-size: 26rpx;
4 | --tabbar-item-icon-size: 44rpx;
5 | --tabbar-item-margin-bottom: 8rpx
6 | }
--------------------------------------------------------------------------------
/sitemap.json:
--------------------------------------------------------------------------------
1 | {
2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
3 | "rules": [{
4 | "action": "allow",
5 | "page": "*"
6 | }]
7 | }
--------------------------------------------------------------------------------
/custom-tab-bar/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {
4 | "van-tabbar": "@vant/weapp/tabbar/index",
5 | "van-tabbar-item": "@vant/weapp/tabbar-item/index"
6 | }
7 | }
--------------------------------------------------------------------------------
/pages/recycle-list/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "recycle-view": "miniprogram-recycle-view/recycle-view",
4 | "recycle-item": "miniprogram-recycle-view/recycle-item"
5 | }
6 | }
--------------------------------------------------------------------------------
/common/emun.js:
--------------------------------------------------------------------------------
1 | /*
2 | * 枚举值都可以在这里维护。最保险的方式,其实是请求后端的字典接口来获取对应的映射,
3 | * 这样后端改动时,前端就不需要手动维护了。
4 | */
5 | export const STATUS = {
6 | "1": "待处理",
7 | "2": "处理中",
8 | "3": "已完成",
9 | "4": "已取消",
10 | }
--------------------------------------------------------------------------------
/pages/address-detail_1/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "van-field": "@vant/weapp/field/index",
4 | "van-cell": "@vant/weapp/cell/index",
5 | "van-cell-group": "@vant/weapp/cell-group/index",
6 | "area-select": "/components/area-select/index"
7 | }
8 | }
--------------------------------------------------------------------------------
/pages/address-detail_2/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "van-field": "@vant/weapp/field/index",
4 | "van-cell": "@vant/weapp/cell/index",
5 | "van-cell-group": "@vant/weapp/cell-group/index",
6 | "area-select": "/components/area-select/index"
7 | }
8 | }
--------------------------------------------------------------------------------
/pages/address-detail_3/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "van-field": "@vant/weapp/field/index",
4 | "van-cell": "@vant/weapp/cell/index",
5 | "van-cell-group": "@vant/weapp/cell-group/index",
6 | "area-select": "/components/area-select/index"
7 | }
8 | }
--------------------------------------------------------------------------------
/components/area-select/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/pages/my/index.js:
--------------------------------------------------------------------------------
1 | Page({
2 | data: {
3 | navConfig: {
4 | title: "page2",
5 | isLeftArrow: false
6 | },
7 | },
8 | onLoad: function (options) {},
9 | onReady: function () {},
10 | onShow: function () {
11 | //初始化tabbar
12 | this.getTabBar().init()
13 | },
14 | })
--------------------------------------------------------------------------------
/custom-tab-bar/index.wxml:
--------------------------------------------------------------------------------
1 |
3 | {{
4 | item.text
5 | }}
6 |
--------------------------------------------------------------------------------
/components/authorize/index.wxss:
--------------------------------------------------------------------------------
1 | @import "../../app.wxss";
2 |
3 | .tips-content {
4 | color: #444444;
5 | padding: 40rpx 10rpx 40rpx 20rpx;
6 | }
7 |
8 | .auth-btn {
9 | width: 500rpx !important;
10 | margin-top: 10rpx;
11 | }
12 |
13 | .tips {
14 | text-align: center;
15 | font-size: 28rpx;
16 | margin-bottom: 20rpx;
17 | color: var(--text-color);
18 | }
--------------------------------------------------------------------------------
/pages/index/index.wxss:
--------------------------------------------------------------------------------
1 | /* pages/page1/index.wxss */
2 | .btn {
3 | display: inline-block;
4 | width: 250rpx;
5 | height: 100rpx;
6 | text-align: center;
7 | line-height: 100rpx;
8 | /* CSS变量的使用 */
9 | border: 1rpx solid var(--border-color);
10 | color: var(--text-color);
11 | border-radius: 10rpx;
12 | padding: 0 20rpx;
13 | box-sizing: border-box;
14 | }
--------------------------------------------------------------------------------
/common/globalMixin.js:
--------------------------------------------------------------------------------
1 | export const mixin1 = {
2 | data: {
3 | title1: "mixin1",
4 | activeColor: "#d70039",
5 | mainColor: "#707070",
6 | },
7 | getTitle1() {
8 | console.log("getTitle1", this.data.title1)
9 | }
10 | }
11 | export const mixin2 = {
12 | data: {
13 | title2: "mixin2"
14 | },
15 | getTitle2() {
16 | console.log("getTitle2", this.data.title2)
17 | }
18 | }
--------------------------------------------------------------------------------
/api/user.js:
--------------------------------------------------------------------------------
1 | import request from "../utils/request"
2 |
3 | //这些接口都不是真实的,只是演示怎么使用
4 | //小程序用户登录
5 | export function login(code, data) {
6 | return request.post(`login?code=${code}`, data, {
7 | noAuth: true
8 | });
9 | }
10 |
11 | //更新用户信息
12 | export function updateUserInfo(data) {
13 | return request.post("user/profile", data);
14 | }
15 |
16 | //更新用户手机号
17 | export function updatePhone(data) {
18 | return request.post("user/phone", data);
19 | }
--------------------------------------------------------------------------------
/utils/app.js:
--------------------------------------------------------------------------------
1 | /*
2 | type toast 类型
3 | content 提示文本
4 | duration 提示持续时长,默认 1秒
5 | opt 支持 showToast 中所以属性,注意:相同属性名会覆盖,opt 属性的优先级最高,基本只有需要回调的时候用到
6 | */
7 | export function toast(icon, title, duration, opt = {}) {
8 | wx.showToast({
9 | title: title,
10 | icon: icon,
11 | duration: duration || 1000,
12 | ...opt
13 | })
14 | }
15 | ["success", "error", "loading", "none"].forEach(type => toast[type] = (title, duration, opt) => toast(type, title,
16 | duration, opt))
--------------------------------------------------------------------------------
/components/navbar/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | // gulp 配置文件
2 | var gulp = require('gulp');
3 |
4 | var postcss = require('gulp-postcss');
5 |
6 | var pxtorem = require('postcss-pxtransform');
7 |
8 | gulp.task('css', function () {
9 |
10 | var processors = [
11 |
12 | pxtorem({
13 |
14 | platform: 'weapp',
15 |
16 | designWidth: 750,
17 |
18 | })
19 |
20 | ];
21 |
22 |
23 | //根据自己的 vant 构建路径来
24 | return gulp.src(['miniprogram_npm/@vant/weapp/**/*.wxss'])
25 | .pipe(postcss(processors))
26 | .pipe(gulp.dest('miniprogram_npm/@vant/weapp/'));
27 | });
--------------------------------------------------------------------------------
/pages/recycle-list/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 | 长列表前面的内容
7 |
8 |
9 | {{item.title}}
10 |
11 |
12 | 长列表后面的内容
13 |
14 |
15 |
--------------------------------------------------------------------------------
/components/authorize/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 | 微信授权登录
6 |
7 | 获取手机号进行绑定
9 |
10 | 取消
11 |
12 |
13 | 用户信息仅用于XXXXX
14 |
--------------------------------------------------------------------------------
/components/navbar/index.wxss:
--------------------------------------------------------------------------------
1 | /* css 变量用于覆盖 vant组件默认的样式 */
2 | @import "/app.wxss";
3 |
4 | .my-navbar {
5 | /* background: url(https://kite1874.com/nav_bg.jpg) no-repeat center center; */
6 | background: var(--nav-bg-color) no-repeat !important;
7 | background-size: 200% !important;
8 | background-position: 50% 0rpx !important;
9 | --nav-bar-background-color: #fff0;
10 | --nav-bar-icon-color: #fff;
11 | --nav-bar-text-color: #fff;
12 | --nav-bar-arrow-size: 40rpx;
13 | --nav-bar-title-text-color: #fff;
14 | --nav-bar-height: 100rpx;
15 | --nav-bar-title-font-size: 38rpx;
16 | z-index: 9999 !important;
17 | }
18 |
19 | .my-navbar::after {
20 | border: none !important;
21 | }
22 |
23 | /* .my-navbar-title {
24 | color: #fff;
25 | } */
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "wx_template",
3 | "version": "1.0.0",
4 | "description": "wx_template",
5 | "main": "app.js",
6 | "dependencies": {
7 | "@vant/weapp": "^1.6.8",
8 | "miniprogram-recycle-view": "^0.1.5"
9 | },
10 | "devDependencies": {
11 | "gulp": "^4.0.2",
12 | "gulp-postcss": "^9.0.1",
13 | "postcss-pxtransform": "^3.3.5"
14 | },
15 | "scripts": {
16 | "build": "gulp css",
17 | "test": "echo \"Error: no test specified\" && exit 1"
18 | },
19 | "repository": {
20 | "type": "git",
21 | "url": "git+https://github.com/KiteWorld/wx_template.git"
22 | },
23 | "keywords": [
24 | "wx_template"
25 | ],
26 | "author": "kiteWorld",
27 | "license": "ISC",
28 | "bugs": {
29 | "url": "https://github.com/KiteWorld/wx_template/issues"
30 | },
31 | "homepage": "https://github.com/KiteWorld/wx_template#readme"
32 | }
33 |
--------------------------------------------------------------------------------
/custom-tab-bar/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | commomProp
3 | } from "../common/behavior"
4 | Component({
5 | behaviors: [commomProp],
6 | properties: {},
7 | data: {
8 | selected: 0,
9 | "list": [{
10 | "url": "/pages/index/index",
11 | "icon": "wap-home-o",
12 | "text": "首页"
13 | },
14 | {
15 | "url": "/pages/my/index",
16 | "icon": "user-circle-o",
17 | "text": "我的"
18 | }
19 | ],
20 | },
21 | lifetimes: {},
22 | methods: {
23 | onChange(e) {
24 | const url = this.data.list[e.detail].url
25 | wx.switchTab({
26 | url: url
27 | });
28 | this.setData({
29 | selected: e.detail
30 | });
31 | },
32 | init() {
33 | const page = getCurrentPages().pop();
34 | this.setData({
35 | selected: this.data.list.findIndex(item => item.url === `/${page.route}`)
36 | });
37 | }
38 | }
39 | })
--------------------------------------------------------------------------------
/config.js:
--------------------------------------------------------------------------------
1 | // "release" 正式版 "trial" 体验版 "develop" 开发版
2 | const env = wx.getAccountInfoSync().miniProgram.envVersion
3 |
4 | const HTTP_REQUEST_URL = env === "release" ? "https://kite1874.com/api/" : env === "trial" ? "https://kite1874.com/test/api/" : "https://kite1874.com/dev/api/"
5 |
6 | module.exports = {
7 | //请求接口地址,根URL
8 | HTTP_REQUEST_URL,
9 |
10 | // 腾讯位置服务 Key
11 | MAP_KEY: "VP4BZ-MPBCU-LQFVU-BXR22-CFNTS-WLFZN",
12 |
13 | // 请求头
14 | HEADER: {
15 | 'content-type': 'application/json'
16 | },
17 | // 回话密钥名称
18 | TOKENNAME: 'X-Access-Token',
19 | //用户信息缓存名称
20 | CACHE_USERINFO: 'USERINFO',
21 | //code
22 | CACHE_CODE: "CODE",
23 | //code获取时间戳
24 | CACHE_CODE_TIME: "CODETIME",
25 | //微信官方称code有效时间为五分钟,保险起见设置 4.5 分钟
26 | CODE_EFFECTIVE_TIME: 45000,
27 | //token缓存名称
28 | CACHE_TOKEN: 'TOKEN',
29 | //token获取时间戳
30 | CACHE_TOKEN_TIME: 'CACHE_TOKEN_TIME',
31 | //token有效时间
32 | TOKEN_EFFECTIVE_TIME: 82800000,
33 | }
--------------------------------------------------------------------------------
/pages/detail/index.js:
--------------------------------------------------------------------------------
1 | // pages/detail/index.js
2 | Page({
3 |
4 | /**
5 | * 页面的初始数据
6 | */
7 | data: {
8 | navConfig: {
9 | title: "detail",
10 | isLeftArrow: true //返回上一页面
11 | },
12 | },
13 |
14 | /**
15 | * 生命周期函数--监听页面加载
16 | */
17 | onLoad: function (options) {
18 |
19 | },
20 |
21 | /**
22 | * 生命周期函数--监听页面初次渲染完成
23 | */
24 | onReady: function () {
25 |
26 | },
27 |
28 | /**
29 | * 生命周期函数--监听页面显示
30 | */
31 | onShow: function () {
32 |
33 | },
34 |
35 | /**
36 | * 生命周期函数--监听页面隐藏
37 | */
38 | onHide: function () {
39 |
40 | },
41 |
42 | /**
43 | * 生命周期函数--监听页面卸载
44 | */
45 | onUnload: function () {
46 |
47 | },
48 |
49 | /**
50 | * 页面相关事件处理函数--监听用户下拉动作
51 | */
52 | onPullDownRefresh: function () {
53 |
54 | },
55 |
56 | /**
57 | * 页面上拉触底事件的处理函数
58 | */
59 | onReachBottom: function () {
60 |
61 | },
62 |
63 | /**
64 | * 用户点击右上角分享
65 | */
66 | onShareAppMessage: function () {
67 |
68 | }
69 | })
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 KiteWorld
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/pages/index/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | STATUS
3 | } from "../../common/emun"
4 | import {
5 | mixin2
6 | } from "../../common/globalMixin"
7 |
8 | import {
9 | authLogin
10 | } from "../../utils/authLogin.js"
11 |
12 |
13 | Page({
14 | //局部 mixin
15 | mixins: [mixin2],
16 | data: {
17 | navConfig: {
18 | title: "page1",
19 | isLeftArrow: false
20 | },
21 | status: "",
22 | authType: "UserInfo", // 不是 UserInfo 时,显示手机号码授权
23 | showAuth: true,
24 | cWidth: 100, //设置canvas宽高,进行压缩
25 | cHeight: 100,
26 | },
27 |
28 | onLoad: function (options) {
29 | console.log("mixin1.title1", this.data.title1)
30 | console.log("mixin2.title2", this.data.title2)
31 | console.log("mixin2.title2", this.data.activeColor)
32 | this.getTitle1()
33 | this.getTitle2()
34 | const status = 1
35 | this.setData({
36 | status: STATUS[status]
37 | })
38 | authLogin(this)
39 | },
40 | onReady: function () {},
41 | onShow: function () {
42 | //初始化tabbar
43 | this.getTabBar().init()
44 | },
45 |
46 | auth() {
47 | authLogin(this)
48 | },
49 | testToast() {
50 | // 挂在在 wx 全局对象上,方便调用,类似于 vue.propotype 。
51 | wx.$toast.success("toast演示成功")
52 | }
53 |
54 | })
--------------------------------------------------------------------------------
/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages": [
3 | "pages/index/index",
4 | "pages/my/index",
5 | "pages/detail/index",
6 | "pages/map/index",
7 | "pages/address-detail_1/index",
8 | "pages/address-detail_2/index",
9 | "pages/address-detail_3/index",
10 | "pages/recycle-list/index"
11 | ],
12 | "window": {
13 | "backgroundTextStyle": "light",
14 | "navigationBarBackgroundColor": "#fff",
15 | "navigationBarTitleText": "Weixin",
16 | "navigationBarTextStyle": "white",
17 | "navigationStyle": "custom"
18 | },
19 | "tabBar": {
20 | "custom": true,
21 | "color": "#000000",
22 | "selectedColor": "#2c4999",
23 | "borderStyle": "white",
24 | "list": [
25 | {
26 | "pagePath": "pages/index/index",
27 | "text": "首页"
28 | },
29 | {
30 | "pagePath": "pages/my/index",
31 | "text": "我的"
32 | }
33 | ]
34 | },
35 | "usingComponents": {
36 | "navbar": "/components/navbar/index",
37 | "van-button": "@vant/weapp/button/index"
38 | },
39 | "plugins": {
40 | "citySelector": {
41 | "version": "1.0.0",
42 | "provider": "wx63ffb7b7894e99ae"
43 | }
44 | },
45 | "permission": {
46 | "scope.userLocation": {
47 | "desc": "你的位置信息将用于小程序定位"
48 | }
49 | },
50 | "style": "v2",
51 | "sitemapLocation": "sitemap.json"
52 | }
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | //引入 mixin.js,实现 mixin(混入)功能
2 | import "./utils/mixin"
3 | import {
4 | mixin1
5 | } from "./common/globalMixin"
6 | import address_parse from "./utils/smartWeChat/js/address_parse"
7 |
8 | import {
9 | toast
10 | } from "utils/app.js"
11 |
12 | App({
13 | onLaunch() {
14 | wx.$toast = toast
15 | wx.getSystemInfo({
16 | success: (res) => {
17 | this.globalData.statusBarHeight = res.statusBarHeight
18 | }
19 | })
20 | //版本更新提醒
21 | const updateManager = wx.getUpdateManager();
22 |
23 | updateManager.onCheckForUpdate(function (res) {
24 | // 请求完新版本信息的回调
25 | })
26 |
27 | updateManager.onUpdateReady(function () {
28 | wx.showModal({
29 | title: '更新提示',
30 | content: '新版本已经准备好,是否重启应用?',
31 | success: function (res) {
32 | if (res.confirm) {
33 | // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
34 | updateManager.applyUpdate()
35 | }
36 | }
37 | })
38 | });
39 | updateManager.onUpdateFailed(() => {
40 | wx.$toast.error("更新版本失败")
41 | })
42 | },
43 | smart: function (val) {
44 | return address_parse.method(val || '')
45 | },
46 | getAddressData: function () { //手动重新挂载数据
47 | address_parse.getData()
48 | },
49 | globalData: {
50 | userInfo: null,
51 | token: null,
52 | statusBarHeight: 0,
53 | },
54 | })
55 |
56 | // 全局 mixins(混入)
57 | wx.mixin(mixin1)
--------------------------------------------------------------------------------
/project.private.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "setting": {},
3 | "condition": {
4 | "plugin": {
5 | "list": []
6 | },
7 | "game": {
8 | "list": []
9 | },
10 | "gamePlugin": {
11 | "list": []
12 | },
13 | "miniprogram": {
14 | "list": [
15 | {
16 | "name": "pages/map/index",
17 | "pathName": "pages/map/index",
18 | "query": "",
19 | "scene": null
20 | },
21 | {
22 | "name": "pages/index/index",
23 | "pathName": "pages/index/index",
24 | "query": "",
25 | "scene": null
26 | },
27 | {
28 | "name": "pages/address-detail_1/index",
29 | "pathName": "pages/address-detail_1/index",
30 | "query": "",
31 | "scene": null
32 | },
33 | {
34 | "name": "pages/address-detail_2/index",
35 | "pathName": "pages/address-detail_2/index",
36 | "query": "",
37 | "scene": null
38 | },
39 | {
40 | "name": "pages/address-detail_3/index",
41 | "pathName": "pages/address-detail_3/index",
42 | "query": "",
43 | "scene": null
44 | },
45 | {
46 | "name": "pages/recycle-list/index",
47 | "pathName": "pages/recycle-list/index",
48 | "query": "",
49 | "scene": null
50 | }
51 | ]
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/components/navbar/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | //my-navbar 和 my-navbar-title 对应 van-navbar 的 custom-class 和 title-class
3 | // externalClasses: ['my-navbar', 'my-navbar-title'],
4 | properties: {
5 | navConfig: {
6 | type: Object,
7 | observer(newVal) {
8 | if (this.data.navConfig.onClickLeft) {
9 | this.onClickLeft = this.data.navConfig.onClickLeft
10 | }
11 | if (this.data.navConfig.onClickRight) {
12 | this.onClickRight = this.data.navConfig.onClickRight
13 | }
14 |
15 | }
16 | },
17 | addHeight: {
18 | type: Number,
19 | value: 0
20 | }
21 | },
22 | data: {
23 | navH: 0
24 | },
25 | options: {
26 | styleIsolation: 'shared'
27 | },
28 | lifetimes: {
29 | attached: function () {
30 | this.setData({
31 | navH: getApp().globalData.statusBarHeight
32 | })
33 | },
34 | ready: function () {},
35 | },
36 | /**
37 | * 组件的方法列表
38 | */
39 | methods: {
40 | onClickLeft() {
41 | const navParam = {}
42 | if (this.data.navConfig.isNavUrl) {
43 | navParam.url = this.data.navConfig.url
44 | wx.navigateTo(navParam)
45 | } else {
46 | if (getCurrentPages().length <= 1) {
47 | console.log("已经没有上一页")
48 | return
49 | }
50 | navParam.detal = this.data.navConfig.detal || 1
51 | wx.navigateBack(navParam)
52 | }
53 | },
54 | onClickRight() {
55 |
56 | }
57 | }
58 | })
--------------------------------------------------------------------------------
/pages/recycle-list/index.js:
--------------------------------------------------------------------------------
1 | const createRecycleContext = require('miniprogram-recycle-view')
2 | Page({
3 | data: {
4 | navConfig: {
5 | title: "虚拟列表",
6 | isLeftArrow: true
7 | },
8 | recycleList: [],
9 | isLoading: false,
10 | deviceWidth: 320,
11 | itemHeight: 150,
12 | num: 0
13 | },
14 | async onLoad() {
15 | const deviceWidth = (await wx.getSystemInfo()).screenWidth
16 | this.setData({
17 | deviceWidth
18 | })
19 | },
20 | onReady: async function () {
21 | var ctx = createRecycleContext({
22 | id: 'recycleId',
23 | dataKey: 'recycleList',
24 | page: this,
25 | itemSize: { // 这个参数也可以直接传下面定义的this.itemSizeFunc函数
26 | width: this.data.deviceWidth,
27 | height: this.data.itemHeight
28 | }
29 | })
30 | this.ctx = ctx
31 | const list = await this.load()
32 | this.ctx.append(list)
33 | },
34 | itemSizeFunc: function (item, idx) {
35 | return {
36 | width: 162,
37 | height: 182
38 | }
39 | },
40 | async scrollLower() {
41 | const list = await this.load()
42 | this.ctx.append(list)
43 | },
44 | async load() {
45 | return new Promise((resolve, reject) => {
46 | setTimeout(() => {
47 | const list = []
48 | for (let i = 0; i < 20; i++) {
49 | this.data.num++
50 | list.push({
51 | id: this.data.num,
52 | title: 'title' + this.data.num
53 | })
54 | }
55 | resolve(list)
56 | }, 500)
57 | })
58 | }
59 | })
--------------------------------------------------------------------------------
/pages/address-detail_1/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
8 |
11 |
14 |
15 |
16 |
17 |
18 | 保存地址
19 |
20 |
21 | 删除
22 |
23 |
24 |
--------------------------------------------------------------------------------
/pages/index/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 枚举值演示:{{status}}
4 |
5 |
6 | 全局混入:{{title1}}
7 |
8 |
9 | 局部混入:{{title2}}
10 |
11 |
12 |
13 | iconfont使用:
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 | Toast封装演示:
40 | 点击测试
41 |
42 |
43 | recycle-list(长列表性能优化时使用):
44 | 点击查看
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/pages/map/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 | {{cityName}}
9 |
10 |
11 |
12 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | {{item.title}}
30 | {{item.addr}}
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/utils/request.js:
--------------------------------------------------------------------------------
1 | import {
2 | HEADER,
3 | TOKENNAME,
4 | CACHE_TOKEN,
5 | HTTP_REQUEST_URL,
6 | } from './../config.js';
7 |
8 | /*
9 | api:Stirng 接口URL
10 | method :Stirng 请求方法 :get post
11 | data:Object 请求数据
12 | noAuth: Boolean true,不需要携带 token; false,反之
13 | customHeader:自定义请求头(覆盖默认的)
14 | baseURL: 覆盖默认的 baseURL
15 | */
16 | export default function request(api, method, data, {
17 | noAuth = false,
18 | customHeader = null,
19 | baseURL = ''
20 | }) {
21 | let header = customHeader || HEADER;
22 | const token = wx.getStorageSync(CACHE_TOKEN)
23 | if (!noAuth && token) header[TOKENNAME] = token
24 | return new Promise((reslove, reject) => {
25 | wx.request({
26 | url: (baseURL || HTTP_REQUEST_URL) + api,
27 | method: method || 'GET',
28 | header: header,
29 | data: data || {},
30 | success: (res) => {
31 | if (res.statusCode === 401) {
32 | wx.removeStorageSync(CACHE_TOKEN)
33 | wx.showToast({
34 | type: "loading",
35 | title: '超出登录有效期,重新获取中...',
36 | })
37 | wx.switchTab({
38 | url: '/pages/index/index',
39 | })
40 | reject(null);
41 | }
42 | reslove(res.data || null)
43 | },
44 | fail: (msg) => {
45 | wx.hideLoading()
46 | wx.showToast({
47 | icon: "none",
48 | title: "请求失败,服务器异常"
49 | })
50 | reject(null);
51 | }
52 | })
53 | });
54 | }
55 |
56 | ['options', 'get', 'post', 'put', 'head', 'delete', 'trace', 'connect'].forEach((method) => {
57 | request[method] = (api, data, opt) => request(api, method, data, opt || {})
58 | });
--------------------------------------------------------------------------------
/css/variables.wxss:
--------------------------------------------------------------------------------
1 | page {
2 | /*全局通用的CSS变量 */
3 | --text-color: #707070;
4 | --text-secondary-color: #c8c9cc;
5 | --border-color: #eee;
6 | --my-user-info-color: #fff;
7 | --main-color: #54565a;
8 | --nav-bg-color: #54565a;
9 | --custom-active-color: #d70039;
10 | --service-item-color: #d70039;
11 |
12 |
13 | /* vant 通用样式覆盖,根据需要进行调整 */
14 | /* --action-sheet-item-font-size: 36rpx;
15 | --action-sheet-item-line-height: 60rpx;
16 | --font-size-md: 36rpx;
17 | --nav-bar-title-font-size: 38rpx;
18 | --nav-bar-height: 100rpx;
19 | --picker-toolbar-height: 100rpx;
20 | --picker-action-font-size: 38rpx;
21 | --picker-option-font-size: 38rpx;
22 | --picker-confirm-action-color: var(--custom-active-color);
23 | --cell-vertical-padding: 20rpx;
24 | --cell-horizontal-padding: 32rpx;
25 | --cell-font-size: 32rpx;
26 | --cell-line-height: 60rpx;
27 | --cell-icon-size: 40rpx;
28 | --field-icon-size: 40rpx;
29 | --field-clear-icon-size: 40rpx;
30 | --field-error-message-text-font-size: 28rpx;
31 | --padding-base: 10rpx;
32 | --padding-md: 30rpx;
33 | --padding-xs: 18rpx;
34 | --uploader-icon-size: 44rpx;
35 | --tabbar-height: 100rpx;
36 | --tabbar-item-font-size: 26rpx;
37 | --tabbar-item-icon-size: 44rpx;
38 | --tabbar-item-margin-bottom: 8rpx;
39 | --tabbar-height: 100rpx;
40 | --tabbar-item-font-size: 26rpx;
41 | --tabbar-item-icon-size: 44rpx;
42 | --tabbar-item-margin-bottom: 8rpx;
43 | --sidebar-width: 210rpx;
44 | --sidebar-font-size: 32rpx;
45 | --sidebar-padding: 30rpx 20rpx;
46 | --sidebar-selected-border-color: var(--custom-active-color);
47 | --tab-font-size: 30rpx;
48 | --tabs-line-height: 86rpx;
49 | --tabs-bottom-bar-height: 6rpx;
50 | --dialog-width: 80%; */
51 | }
--------------------------------------------------------------------------------
/utils/mixin.js:
--------------------------------------------------------------------------------
1 | //自定义小程序页面 page 的 mixin 功能(不同于 behaviors)
2 | const nativePage = Page
3 | const lifecycle = ['onLoad', 'onReady', 'onShow', 'onHide', 'onUnload', 'onPullDownRefresh', 'onReachBottom', 'onShareAppMessage', 'onPageScroll']
4 | let globalMixin = null
5 |
6 | //全局mixin方法
7 | wx.mixin = function(config){
8 | if(isType(config,'object')){
9 | globalMixin = config
10 | }
11 | }
12 |
13 | //原生Page代理
14 | Page = function (config) {
15 | let mixins = config.mixins
16 | //加入全局mixin
17 | if(globalMixin){
18 | (mixins || (mixins=[])).unshift(globalMixin)
19 | }
20 | if (isType(mixins, 'array') && mixins.length > 0) {
21 | Reflect.deleteProperty(config, 'mixins')
22 | merge(mixins, config)
23 | }
24 | nativePage(config)
25 | }
26 |
27 | function merge(mixins, config) {
28 | mixins.forEach(mixin => {
29 | if (isType(mixin, 'object')) {
30 | //合并data、生命周期以及其他数据
31 | Object.keys(mixin).forEach(key => {
32 | if (key === 'data') {
33 | config[key] = Object.assign({}, mixin[key], config[key])
34 | } else if (lifecycle.includes(key)) {
35 | let nativeLifecycle = config[key]
36 | config[key] = function () {
37 | let arg = Array.prototype.slice.call(arguments)
38 | mixin[key].call(this, arg)
39 | return nativeLifecycle && nativeLifecycle.call(this, arg)
40 | }
41 | } else {
42 | config[key] = mixin[key]
43 | }
44 | })
45 | }
46 | })
47 | }
48 |
49 | //判断类型工具
50 | function isType(target, type) {
51 | let targetType = Object.prototype.toString.call(target).slice(8, -1).toLowerCase()
52 | type = type.toLowerCase()
53 | return targetType === type
54 | }
--------------------------------------------------------------------------------
/fonts/iconfont.wxss:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: "iconfont";
3 | /* Project id 2619442 */
4 | /* 小程序 url 只支持 base64 */
5 | src:
6 | url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAOUAAsAAAAAB5gAAANGAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFQGYACCcAqDCIJKATYCJAMICwYABCAFhG0HMxuPBsieg43jCBZ58nS800P9qHy+vOpXKu0xMiCXzoKNpMGXyQLUDdKxCXJ3v35ZagGWxVEkAXFaAgQEV3b5H/eOf0N8vvMupzk3frDiQApsTxuLrEAC84BTkN2DschzQABa+WoxvWX77vA7etmFKCyzmUCSSY7VrIdaUGIbMgk1QokuTZBPAcxlbgGYG3yePBSmBhiKAjOn825hwrl3sdYIOs47zipPMG68Gmo4A1AAKCB7ZWoymo0d0SiYjdJWGVmJdCWLwLtYr9djrvuHBxAgFWa6DwCIoZjnxHLYp0rNAAAWOgNjAIt7PRKgM5WOPNH1QuOFqLDotdE7s87W7UwjS5eEuZYsCu3da9HixbqZ4X17LA715WRlQ8+taVvL0hbHhj4ueFwi0qHYLfwGPmxNmFq0NHz144b7FYv5P0JclLyoGIeSN6Xf68z3bLV0aRi/ZMmiRaE9uvdx3uq8LXtZNpaFLOP5LhXnqjY4/roHdCATf+3PPXb4x7hKdG36S28bpir6/z9pDg7vyqhC9nVJuqTQM4okvGo5arPfLVX18SqRhg8tj+nalqrCaFn+h+i+v4JFxbCqJ3431uoy/H7puABGmRKUFkWezBhN+oU/5cZlJ181nD4/qF2z7oOS1k+qYKN69trR49ZabxeqP0jJNtv6/+eD6l2oBwDe6UZa91++gy3xUeED/av/qnUsAODJr3AhsHtngZkB9YkbCfwFERCV1VwAk1UsIcoYg94YX2t5AC/TGuRZX2no3UYJtdB7NqvEJkCpJSMsPhsUdIpBSa0OtLK0Wq0TTEKR1ADINJkAEWAvMPycBSrAbYTFPwWFMF9BKSAKWnwEb6mTmlXbTBL0smDiDMM5q9HtEm2NrA0zuwrmwQ69lOYEBF6QmqweriA3Px9pJbgEaYwZTUPMhbIscqLkdnItyWmCw+HmPJLbJhjlXIsseyrz8sSqF+Ua3U5oNSMR6MkEJhyD4ThWRm4uotdapi28vyuB2WAOelJDQ5WWJ5A0sXbPKZArH0BaCV1Qw7Vc0mQIs0IymYgjkrg5cVoSvcBhBd04nupBNgIjWS5LD79HpTwaTUSFufOLnU+3DUDLlDFh5VNotuAyj7C4CgAAAA==') format('woff2'),
7 | url('iconfont.woff?t=1624008421612') format('woff'),
8 | url('iconfont.ttf?t=1624008421612') format('truetype');
9 | }
10 |
11 | .iconfont {
12 | font-family: "iconfont" !important;
13 | font-size: 16px;
14 | font-style: normal;
15 | -webkit-font-smoothing: antialiased;
16 | -moz-osx-font-smoothing: grayscale;
17 | }
18 |
19 | .icon-fengzheng:before {
20 | content: "\e61d";
21 | }
--------------------------------------------------------------------------------
/utils/smartWeChat/README.md:
--------------------------------------------------------------------------------
1 |
7 |
8 | # 建议使用api接口,此方法暂不推荐
9 | ## demo
10 |
11 | 详见```demo```文件夹
12 |
13 | 
14 |
15 | ## 小程序引入
16 | 务必勾选不检验域名等等
17 | 
18 |
19 | 将仓库中的```smartWeChat```文件夹拷贝到项目中```app.js```的同级目录
20 |
21 | 
22 |
23 | > smartWeChat/js/address_parse.js(自建后台)
24 |
25 | 如需要自行构建后台,json文件在demo/后台json/database_export-sw0HKSJkxA1j.json
26 |
27 | 这里需要将demo里的接口替换为后台提供的接口,接口格式返回可以参考https://wangzc.wang/addressJson/1
28 |
29 | 后台json文件···demo/后台json/database_export-sw0HKSJkxA1j.json```
30 |
31 | > app.js
32 | ```
33 | var address_parse = require("./smartWeChat/js/address_parse");
34 |
35 | ...
36 | ...
37 | ...
38 |
39 | App({
40 | ....
41 | smart: function (val){
42 | return address_parse.method(val || '')
43 | },
44 | getAddressData:function(){//手动重新挂载数据
45 | address_parse.getData()
46 | }
47 | })
48 |
49 | ```
50 |
51 | > 调用.js
52 | ```
53 | const app = getApp()
54 | //注意!!省市区文件加载时间可能略长
55 | //需要识别调用
56 | app.smart('新疆阿克苏温宿县博孜墩柯尔克孜族乡吾斯塘博村一组306号 150-3569-6956 马云')
57 |
58 | //ex
59 | //这里改为事件触发即可
60 | onLoad: function() {
61 | setTimeout(function(){
62 | app.getAddressData()//保险起见,手动挂载数据
63 | var address = app.smart('广东省珠海市香洲区盘山路28号幸福茶庄,陈景勇,13593464918')
64 | console.log(address)
65 | },10000)
66 | }
67 |
68 | ```
69 | ### 数据源跟换
70 |
71 | 由于小程序限制文件大小不能超过2MB,所以数据以接口返回,若需要更新请加群联系作者
72 |
73 | ### 注,初次加载会调用接口请求数据,后续会从缓存中读取
74 | ### 接口地址 https://wangzc.wang/addressJson/x
75 |
--------------------------------------------------------------------------------
/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "项目配置文件",
3 | "packOptions": {
4 | "ignore": []
5 | },
6 | "setting": {
7 | "urlCheck": false,
8 | "es6": true,
9 | "enhance": true,
10 | "postcss": true,
11 | "preloadBackgroundData": false,
12 | "minified": true,
13 | "newFeature": false,
14 | "coverView": true,
15 | "nodeModules": true,
16 | "autoAudits": false,
17 | "showShadowRootInWxmlPanel": false,
18 | "scopeDataCheck": false,
19 | "uglifyFileName": false,
20 | "checkInvalidKey": true,
21 | "checkSiteMap": true,
22 | "uploadWithSourceMap": true,
23 | "compileHotReLoad": false,
24 | "useMultiFrameRuntime": true,
25 | "useApiHook": true,
26 | "useApiHostProcess": true,
27 | "babelSetting": {
28 | "ignore": [],
29 | "disablePlugins": [],
30 | "outputPath": ""
31 | },
32 | "enableEngineNative": false,
33 | "useIsolateContext": true,
34 | "userConfirmedBundleSwitch": false,
35 | "packNpmManually": false,
36 | "packNpmRelationList": [],
37 | "minifyWXSS": true,
38 | "showES6CompileOption": false
39 | },
40 | "compileType": "miniprogram",
41 | "libVersion": "2.15.0",
42 | "appid": "wxd1ae1593ac877f86",
43 | "projectname": "wx_template",
44 | "debugOptions": {
45 | "hidedInDevtools": []
46 | },
47 | "scripts": {},
48 | "staticServerOptions": {
49 | "baseURL": "",
50 | "servePath": ""
51 | },
52 | "isGameTourist": false,
53 | "condition": {
54 | "search": {
55 | "list": []
56 | },
57 | "conversation": {
58 | "list": []
59 | },
60 | "game": {
61 | "list": []
62 | },
63 | "plugin": {
64 | "list": []
65 | },
66 | "gamePlugin": {
67 | "list": []
68 | },
69 | "miniprogram": {
70 | "list": []
71 | }
72 | }
73 | }
--------------------------------------------------------------------------------
/pages/address-detail_1/index.wxss:
--------------------------------------------------------------------------------
1 | @import '/app.wxss';
2 |
3 | .smart-address-container {
4 | background: #fff;
5 | }
6 |
7 | .form-container {
8 | --cell-horizontal-padding: 30rpx;
9 | --padding-xs: 18rpx
10 | }
11 |
12 | .smart-address-title {
13 | display: flex;
14 | justify-content: center;
15 | align-items: center;
16 | height: 80rpx;
17 | font-size: 32rpx;
18 | color: #aaaaaa;
19 | }
20 |
21 | .smart-input-root .van-cell__value {
22 | font-size: 32rpx;
23 | background: #eee !important;
24 | border-radius: 10rpx !important;
25 | overflow: hidden !important;
26 | }
27 |
28 | .smart-input {
29 | height: 300rpx !important;
30 | background: #eee !important;
31 | padding: 20rpx !important;
32 | border-radius: 10rpx !important;
33 |
34 | }
35 |
36 | .smart-address {
37 | display: flex;
38 | flex-direction: column;
39 |
40 | /* justify-content: flex-end; */
41 |
42 | }
43 |
44 | .smart-address-btn {
45 | display: flex;
46 | justify-content: flex-end;
47 | margin-bottom: 10rpx;
48 | }
49 |
50 | .smart-address-btn view {
51 | font-size: 32rpx;
52 | padding: 6rpx 10rpx;
53 | width: 100rpx;
54 | text-align: center;
55 | border-radius: 999em;
56 | }
57 |
58 | .smart-address-btn view:nth-child(1) {
59 | border: 1rpx solid #aaaaaa;
60 | color: #aaaaaa;
61 | }
62 |
63 | .smart-address-btn view:nth-child(2) {
64 | width: 150rpx;
65 | margin: 0 20rpx;
66 | background: var(--main-color);
67 | color: #fff;
68 | }
69 |
70 | .save-btn,
71 | .del-btn {
72 | width: 80%;
73 | margin: 40rpx auto 0rpx;
74 | border-radius: 999em;
75 | padding: 16rpx 0;
76 | font-size: 36rpx;
77 | text-align: center;
78 | background: var(--main-color);
79 | color: #fff;
80 | }
81 |
82 | .del-btn {
83 | background: #cfcfcf;
84 | color: #949494;
85 | }
86 |
87 | .btn-contianer {
88 | margin-top: 60rpx;
89 | }
90 |
91 |
--------------------------------------------------------------------------------
/pages/address-detail_2/index.wxss:
--------------------------------------------------------------------------------
1 | @import '/app.wxss';
2 |
3 | .smart-address-container {
4 | background: #fff;
5 | }
6 |
7 | .form-container {
8 | --cell-horizontal-padding: 30rpx;
9 | --padding-xs: 18rpx
10 | }
11 |
12 | .smart-address-title {
13 | display: flex;
14 | justify-content: center;
15 | align-items: center;
16 | height: 80rpx;
17 | font-size: 32rpx;
18 | color: #aaaaaa;
19 | }
20 |
21 | .smart-input-root .van-cell__value {
22 | font-size: 32rpx;
23 | background: #eee !important;
24 | border-radius: 10rpx !important;
25 | overflow: hidden !important;
26 | }
27 |
28 | .smart-input {
29 | height: 300rpx !important;
30 | background: #eee !important;
31 | padding: 20rpx !important;
32 | border-radius: 10rpx !important;
33 |
34 | }
35 |
36 | .smart-address {
37 | display: flex;
38 | flex-direction: column;
39 |
40 | /* justify-content: flex-end; */
41 |
42 | }
43 |
44 | .smart-address-btn {
45 | display: flex;
46 | justify-content: flex-end;
47 | margin-bottom: 10rpx;
48 | }
49 |
50 | .smart-address-btn view {
51 | font-size: 32rpx;
52 | padding: 6rpx 10rpx;
53 | width: 100rpx;
54 | text-align: center;
55 | border-radius: 999em;
56 | }
57 |
58 | .smart-address-btn view:nth-child(1) {
59 | border: 1rpx solid #aaaaaa;
60 | color: #aaaaaa;
61 | }
62 |
63 | .smart-address-btn view:nth-child(2) {
64 | width: 150rpx;
65 | margin: 0 20rpx;
66 | background: var(--main-color);
67 | color: #fff;
68 | }
69 |
70 | .save-btn,
71 | .del-btn {
72 | width: 80%;
73 | margin: 40rpx auto 0rpx;
74 | border-radius: 999em;
75 | padding: 16rpx 0;
76 | font-size: 36rpx;
77 | text-align: center;
78 | background: var(--main-color);
79 | color: #fff;
80 | }
81 |
82 | .del-btn {
83 | background: #cfcfcf;
84 | color: #949494;
85 | }
86 |
87 | .btn-contianer {
88 | margin-top: 60rpx;
89 | }
90 |
91 |
--------------------------------------------------------------------------------
/pages/address-detail_3/index.wxss:
--------------------------------------------------------------------------------
1 | @import '/app.wxss';
2 |
3 | .smart-address-container {
4 | background: #fff;
5 | }
6 |
7 | .form-container {
8 | --cell-horizontal-padding: 30rpx;
9 | --padding-xs: 18rpx
10 | }
11 |
12 | .smart-address-title {
13 | display: flex;
14 | justify-content: center;
15 | align-items: center;
16 | height: 80rpx;
17 | font-size: 32rpx;
18 | color: #aaaaaa;
19 | }
20 |
21 | .smart-input-root .van-cell__value {
22 | font-size: 32rpx;
23 | background: #eee !important;
24 | border-radius: 10rpx !important;
25 | overflow: hidden !important;
26 | }
27 |
28 | .smart-input {
29 | height: 300rpx !important;
30 | background: #eee !important;
31 | padding: 20rpx !important;
32 | border-radius: 10rpx !important;
33 |
34 | }
35 |
36 | .smart-address {
37 | display: flex;
38 | flex-direction: column;
39 |
40 | /* justify-content: flex-end; */
41 |
42 | }
43 |
44 | .smart-address-btn {
45 | display: flex;
46 | justify-content: flex-end;
47 | margin-bottom: 10rpx;
48 | }
49 |
50 | .smart-address-btn view {
51 | font-size: 32rpx;
52 | padding: 6rpx 10rpx;
53 | width: 100rpx;
54 | text-align: center;
55 | border-radius: 999em;
56 | }
57 |
58 | .smart-address-btn view:nth-child(1) {
59 | border: 1rpx solid #aaaaaa;
60 | color: #aaaaaa;
61 | }
62 |
63 | .smart-address-btn view:nth-child(2) {
64 | width: 150rpx;
65 | margin: 0 20rpx;
66 | background: var(--main-color);
67 | color: #fff;
68 | }
69 |
70 | .save-btn,
71 | .del-btn {
72 | width: 80%;
73 | margin: 40rpx auto 0rpx;
74 | border-radius: 999em;
75 | padding: 16rpx 0;
76 | font-size: 36rpx;
77 | text-align: center;
78 | background: var(--main-color);
79 | color: #fff;
80 | }
81 |
82 | .del-btn {
83 | background: #cfcfcf;
84 | color: #949494;
85 | }
86 |
87 | .btn-contianer {
88 | margin-top: 60rpx;
89 | }
90 |
91 |
--------------------------------------------------------------------------------
/pages/address-detail_2/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
8 |
10 |
13 |
16 |
17 |
18 |
19 | 保存地址
20 |
21 |
22 | 删除
23 |
24 |
25 |
26 | 点击「服务地址」跳转地图选点页面, 开发者工具无法显示地图!「点击预览」在手机上查看!
27 |
28 |
--------------------------------------------------------------------------------
/components/area-select/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | MAP_KEY
3 | } from "../../config.js" //腾讯位置服务的 Key
4 | var QQMapWX = require('../../utils/qqmap-wx-jssdk.min'); // 引入 SDK 文件
5 | var qqmapsdk; // SDK实例对象
6 | Component({
7 | properties: {},
8 | data: {
9 | isShowAreaSelect: false,
10 | areaList: {
11 | // 变量名称是 van-area 规定写死的,不能换!不能换!不能换!
12 | province_list: {}, //省
13 | city_list: {}, //市
14 | county_list: {} //区
15 | },
16 | // areaSource: []
17 | },
18 | lifetimes: {
19 | attached() {
20 | //创建SDK实例
21 | qqmapsdk = new QQMapWX({
22 | key: MAP_KEY
23 | });
24 | //调用 getCityList
25 | qqmapsdk.getCityList({
26 | success: (res) => { //成功后的回调
27 | // this.data.areaSource = res.result
28 | this.setData({
29 | "areaList.province_list": this.ArrayToObject(res.result[0]),
30 | "areaList.city_list": this.ArrayToObject(res.result[1]),
31 | "areaList.county_list": this.ArrayToObject(res.result[2]),
32 | })
33 | },
34 | fail: function (error) {
35 | console.error(error);
36 | },
37 | complete: function (res) {
38 | console.log(res);
39 | }
40 | });
41 | }
42 | },
43 | methods: {
44 | //确认选择
45 | confirmArea: function (e) {
46 | const values = e.detail.values
47 | //直辖市,需要处理数据,保持省市一致,例如,省:北京市;市:北京市;区:朝阳区
48 | if (values.some(x => !Boolean(x))) {
49 | [values[1], values[2]] = [values[0], values[1]];
50 | }
51 | const arr = (values.map(x => x.name))
52 | this.triggerEvent("confirm", arr)
53 | this.setData({
54 | isShowAreaSelect: false,
55 | })
56 | },
57 |
58 | //关闭省市区选择组件
59 | closeAreaSelect: function () {
60 | this.setData({
61 | isShowAreaSelect: false
62 | })
63 | },
64 |
65 | //打开省市区选择组件
66 | showAreaSelect: function () {
67 | this.setData({
68 | isShowAreaSelect: true
69 | })
70 | },
71 |
72 | // 格式化省市区数据
73 | ArrayToObject(arr) {
74 | const obj = {}
75 | for (let i = 0; i < arr.length; i++) {
76 | obj[arr[i].id] = arr[i].fullname
77 | }
78 | return obj
79 | }
80 | }
81 | })
--------------------------------------------------------------------------------
/pages/address-detail_3/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
8 |
11 |
13 |
14 |
15 |
16 | 智能识别
17 |
18 |
19 |
20 |
23 |
24 | 取消
25 | 智能识别
26 |
27 |
28 |
29 |
30 |
31 | 保存地址
32 |
33 |
34 | 删除
35 |
36 |
37 |
38 | 开发者工具无法显示地图!「点击预览」在手机上查看!
39 |
40 |
41 |
--------------------------------------------------------------------------------
/pages/map/index.wxss:
--------------------------------------------------------------------------------
1 | @import "../../app.wxss";
2 |
3 | page {
4 | overflow: hidden;
5 | }
6 |
7 | .cityName {
8 | height: 100%;
9 | min-width: 120rpx;
10 | max-width: 160rpx;
11 | font-size: 30rpx;
12 | padding: 0 14rpx;
13 | box-sizing: border-box;
14 | border-right: 1rpx solid var(--border-color);
15 | margin-right: 14rpx;
16 | text-align: center;
17 | }
18 |
19 | .current-site-icon {
20 | width: 50rpx;
21 | height: 50rpx;
22 | position: absolute;
23 | top: 50%;
24 | left: 50%;
25 | transform: translate(-50%, -50%);
26 | }
27 |
28 | .near-item {
29 | display: flex;
30 | line-height: 40rpx;
31 | padding: 20rpx 30rpx;
32 | text-align: left;
33 | border-bottom: 1px solid #eee;
34 | }
35 |
36 | .current-site {
37 | font-size: 40rpx;
38 | margin-right: 30rpx;
39 | }
40 |
41 | .item-main {
42 | flex: 1;
43 | }
44 |
45 | .near-item .title {
46 | color: #282828;
47 | font-size: 32rpx;
48 | white-space: nowrap;
49 | overflow: hidden;
50 | text-overflow: ellipsis;
51 | }
52 |
53 | .near-item .address {
54 | color: #707070;
55 | font-size: 24rpx;
56 | white-space: nowrap;
57 | overflow: hidden;
58 | text-overflow: ellipsis;
59 | }
60 |
61 | .near-item .activeTitle {
62 | color: var(--custom-active-color);
63 | }
64 |
65 | .near-item .activeAddress {
66 | color: var(--custom-active-color);
67 | }
68 |
69 | .map-prompt {
70 | width: 420rpx;
71 | height: 60rpx;
72 | line-height: 60rpx;
73 | font-size: 24rpx;
74 | color: #707070;
75 | text-align: center;
76 | background: #fff;
77 | border-radius: 10rpx;
78 | box-shadow: 0 0 10rpx rgba(0, 0, 0, 0.1);
79 | position: absolute;
80 | bottom: 40rpx;
81 | left: 50%;
82 | transform: translate(-50%, 0);
83 | }
84 |
85 | .reload {
86 | width: 80rpx;
87 | height: 80rpx;
88 | background: #fff;
89 | border-radius: 50%;
90 | box-shadow: 0 0 10rpx rgba(0, 0, 0, 0.1);
91 | position: absolute;
92 | bottom: 30rpx;
93 | right: 30rpx;
94 | }
95 |
96 | .reload .center1 {
97 | width: 30rpx;
98 | height: 30rpx;
99 | border: 1rpx solid var(--custom-active-color);
100 | border-radius: 50%;
101 | margin: 24rpx auto;
102 | }
103 |
104 | .reload .center2 {
105 | width: 25rpx;
106 | height: 25rpx;
107 | background: var(--custom-active-color);
108 | border-radius: 50%;
109 | margin: 3rpx auto;
110 | }
--------------------------------------------------------------------------------
/utils/authLogin.js:
--------------------------------------------------------------------------------
1 | import {
2 | CACHE_USERINFO,
3 | CACHE_TOKEN,
4 | APP_ID,
5 | CACHE_CODE,
6 | CACHE_CODE_TIME,
7 | CACHE_TOKEN_TIME,
8 | CODE_EFFECTIVE_TIME,
9 | TOKEN_EFFECTIVE_TIME,
10 | } from "../config"
11 |
12 | const {
13 | login
14 | } = require("../api/user");
15 |
16 | export async function authLogin(instance) {
17 | const cacheUserInfo = wx.getStorageSync(CACHE_USERINFO)
18 | let userInfo = cacheUserInfo ? JSON.parse(cacheUserInfo) : {}
19 | getApp().globalData.userInfo = userInfo
20 |
21 | //有token时,不需要重新登录
22 | const token = wx.getStorageSync(CACHE_TOKEN)
23 | const tokenTime = wx.getStorageSync(CACHE_TOKEN_TIME)
24 | if (token && (tokenTime + TOKEN_EFFECTIVE_TIME > (new Date()).getTime())) {
25 | return authMain(instance, userInfo)
26 | }
27 | // 防止第一次经入小程序时,反复调用 wx.login,超出频率规范
28 | const code = wx.getStorageSync(CACHE_CODE)
29 | const codeTime = wx.getStorageSync(CACHE_CODE_TIME)
30 | if (code && (codeTime + CODE_EFFECTIVE_TIME > (new Date()).getTime())) {
31 | const loginRes = await loginMain(res.code)
32 | return authMain(instance, loginRes.result)
33 | }
34 | wx.login({
35 | success: async (res) => {
36 | if (res.code) {
37 | const loginRes = await loginMain(res.code)
38 | authMain(instance, loginRes.result)
39 | } else {
40 | console.log('登录失败!' + res.errMsg)
41 | }
42 | }
43 | })
44 | }
45 | //调用 token 和 储存用户token等信息
46 | async function loginMain(code) {
47 | const loginRes = await login(APP_ID, code)
48 | wx.setStorageSync(CACHE_TOKEN, loginRes.result.token)
49 | wx.setStorageSync(CACHE_TOKEN_TIME, (new Date()).getTime())
50 | wx.setStorageSync(CACHE_CODE, code)
51 | wx.setStorageSync(CACHE_CODE_TIME, (new Date()).getTime())
52 | wx.setStorageSync(CACHE_USERINFO, JSON.stringify(loginRes.result))
53 | const globalData = getApp().globalData
54 | globalData.userInfo = loginRes.result || {}
55 | return loginRes
56 | }
57 |
58 | async function authMain(instance, loginRes) {
59 | //判断用户名是否为空,弹出授权窗口
60 | if (!loginRes.wxNickname) {
61 | instance.setData({
62 | authType: "UserInfo",
63 | isShowAuth: true
64 | })
65 | return
66 | }
67 | //判断用户名是否为空,弹出授权窗口
68 | if (!loginRes.wxMobile) {
69 | instance.setData({
70 | authType: "PhoneNumber",
71 | isShowAuth: true,
72 | })
73 | return
74 | }
75 | //用户名和手机号码都不为空证明已经授权过了
76 | //这里可以调用首页需要的 api
77 | }
--------------------------------------------------------------------------------
/components/authorize/index.js:
--------------------------------------------------------------------------------
1 | // components/authorize/index.js
2 | import {
3 | CACHE_USERINFO,
4 | } from "../../config"
5 | import {
6 | updateUserInfo,
7 | updatePhone
8 | } from "../../api/user"
9 | Component({
10 | properties: {
11 | type: {
12 | type: String,
13 | value: "UserInfo"
14 | },
15 | showAuth: {
16 | type: Boolean,
17 | value: false
18 | },
19 | },
20 |
21 | data: {
22 | loading: false,
23 | },
24 | /**
25 | * 组件的方法列表
26 | */
27 | lifetimes: {},
28 | methods: {
29 | getUserProfile() {
30 | wx.getUserProfile({
31 | lang: 'zh_CN',
32 | desc: "微信授权登录",
33 | success: async (res) => {
34 | //传给后端的参数
35 | let param = {
36 | encryptedData: {
37 | encryptedData: res.encryptedData,
38 | iv: res.iv
39 | },
40 | rawData: res.rawData,
41 | signature: res.signature,
42 | userInfo: res.userInfo
43 | }
44 | //调用更新接口
45 | let updateRes = await this.update(updateUserInfo, param)
46 | if (!updateRes) return
47 | // 弹出手机号码授权窗口
48 | this.setData({
49 | showAuth: "PhoneNumber",
50 | type: true,
51 | });
52 | },
53 | fail(res) {
54 | console.log(res)
55 | }
56 | })
57 | },
58 | async getPhoneNumber(e) {
59 | if (e.detail.errMsg === "getPhoneNumber:ok") {
60 | //传给后端的参数
61 | const param = {
62 | encryptedData: {
63 | encryptedData: e.detail.encryptedData,
64 | iv: e.detail.iv
65 | },
66 | }
67 | //调用接口
68 | let updateRes = await this.update(updatePhone, param)
69 | if (!updateRes) return
70 | //关闭隐藏接口
71 | this.hide()
72 | }
73 | },
74 | onCancel() {
75 | this.hide()
76 | },
77 | hide() {
78 | this.setData({
79 | showAuth: false
80 | })
81 | },
82 | //更新用户信息
83 | async update(updateApi, param) {
84 | this.setData({
85 | loading: true
86 | })
87 | let updateRes = await updateApi(param)
88 | this.setData({
89 | loading: false
90 | })
91 | if (updateRes.code !== 200) {
92 | wx.showToast({
93 | icon: "error",
94 | title: "更新失败",
95 | })
96 | return false
97 | }
98 | //更新本地保存 userInfo 数据
99 | getApp().globalData.userInfo = updateRes.result || {}
100 | wx.setStorageSync(CACHE_USERINFO, JSON.stringify(updateRes.result))
101 | return updateRes
102 | }
103 | }
104 | })
--------------------------------------------------------------------------------
/pages/address-detail_1/index.js:
--------------------------------------------------------------------------------
1 | Page({
2 | data: {
3 | //导航栏配置
4 | navConfig: {
5 | title: "地址详细",
6 | isLeftArrow: true
7 | },
8 |
9 | //表单数据
10 | formData: {
11 | contactName: '',
12 | contactTel: "",
13 | county: "",
14 | province: "",
15 | city: "",
16 | addressDetail: "",
17 | },
18 | isShowAreaSelect: false,
19 | phoneNumberError: "",
20 | phoneNumbrRegExp: /^(?:(?:\+|00)86)?1[3-9]\d{9}$/
21 | },
22 |
23 | onLoad: function (options) {
24 | if (options.address) {
25 | this.setData({
26 | formData: JSON.parse(decodeURIComponent(options.address)),
27 | })
28 | }
29 | },
30 |
31 | changeContactName({
32 | detail
33 | }) {
34 | this.setData({
35 | "formData.contactName": detail,
36 | })
37 | },
38 |
39 | changeContactTel({
40 | detail
41 | }) {
42 | const param = {
43 | "formData.contactTel": detail,
44 | }
45 | if (detail.length === 11 && /^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(detail)) {
46 | param.phoneNumberError = ""
47 | }
48 | this.setData(param)
49 | },
50 |
51 | changeHouseMumber({
52 | detail
53 | }) {
54 | this.setData({
55 | "formData.houseNumber": detail,
56 | })
57 | },
58 |
59 | confirmArea: function ({
60 | detail
61 | }) {
62 | this.setData({
63 | "formData.province": detail[0],
64 | "formData.city": detail[1],
65 | "formData.county": detail[2],
66 | })
67 | },
68 |
69 | changeAddressDetail({
70 | detail
71 | }) {
72 | this.setData({
73 | "formData.addressDetail": detail
74 | })
75 | },
76 |
77 | getLocation() {
78 | const {
79 | longitudeLatitude
80 | } = this.data.formData
81 | wx.navigateTo({
82 | url: '../../pages/map/index?longitudeLatitude=' + (longitudeLatitude || ''),
83 | })
84 | },
85 |
86 | changeSmartAddress(e) {
87 | this.setData({
88 | smartAddress: e.detail
89 | })
90 | },
91 |
92 | async saveAddress() {
93 | const formData = this.data.formData
94 | for (const key in formData) {
95 | if (formData.hasOwnProperty(key)) {
96 | if (!formData[key]) {
97 | wx.showToast({
98 | icon: "none",
99 | title: '请填写完整信息',
100 | })
101 | return
102 | }
103 | }
104 | }
105 | if (!(/^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(formData.contactTel))) {
106 | wx.showToast({
107 | icon: "none",
108 | title: '手机号格式错误',
109 | })
110 | this.setData({
111 | "phoneNumberError": "手机号格式错误"
112 | })
113 | }
114 | },
115 |
116 | async delAddress() {
117 | if (res.code === 200) {
118 | wx.navigateBack({
119 | delta: 1,
120 | })
121 | }
122 | },
123 |
124 | showAreaSelect: function () {
125 | this.selectComponent("#area-select").showAreaSelect();
126 | },
127 | })
--------------------------------------------------------------------------------
/app.wxss:
--------------------------------------------------------------------------------
1 | @import "/css/variables.wxss";
2 | @import "/fonts/iconfont.wxss";
3 |
4 | page {
5 | font-size: 32rpx;
6 | /* font-family: sans-serif; */
7 | background: #f5f5f5;
8 | box-sizing: border-box;
9 | /* IOS底部安全距离 */
10 | padding-bottom: constant(safe-area-inset-bottom);
11 | /*兼容 IOS<11.2*/
12 | padding-bottom: env(safe-area-inset-bottom);
13 | /*兼容 IOS>11.2*/
14 | }
15 |
16 | /*共公样式 */
17 | .all_center {
18 | position: absolute;
19 | left: 50%;
20 | top: 50%;
21 | transform: translate(-50%, -50%);
22 | }
23 |
24 | /* 垂直居中 */
25 | .y_center {
26 | position: absolute;
27 | top: 50%;
28 | transform: translateY(-50%);
29 | }
30 |
31 | /* 水平居中 */
32 | .x_center {
33 | position: absolute;
34 | left: 50%;
35 | transform: translateX(-50%);
36 | }
37 |
38 | /* flex 布局 */
39 | /* 横轴 */
40 | .flex_r {
41 | display: flex;
42 | flex-direction: row;
43 | }
44 |
45 | /* 横轴水平居中 */
46 | .flex_r_h {
47 | display: flex;
48 | flex-direction: row;
49 | justify-content: center;
50 | }
51 |
52 | /* 横轴垂直居中 */
53 | .flex_r_v {
54 | display: flex;
55 | flex-direction: row;
56 | align-items: center;
57 | }
58 |
59 | /* 横轴水平垂直居中 */
60 | .flex_r_hv {
61 | display: flex;
62 | flex-direction: row;
63 | justify-content: center;
64 | align-items: center;
65 | }
66 |
67 | /* 纵轴 */
68 | .flex_c {
69 | display: flex;
70 | flex-direction: column;
71 | }
72 |
73 | /* 纵轴水平 */
74 | .flex_c_h {
75 | display: flex;
76 | flex-direction: column;
77 | align-items: center;
78 | }
79 |
80 | /* 纵轴垂直 */
81 | .flex_c_v {
82 | display: flex;
83 | flex-direction: column;
84 | justify-content: center;
85 | }
86 |
87 | /* 纵轴水平垂直 */
88 | .flex_c_hv {
89 | display: flex;
90 | flex-direction: column;
91 | justify-content: center;
92 | align-items: center;
93 | }
94 |
95 |
96 | /* 1px */
97 | .scale-1px {
98 | position: relative;
99 | border: none;
100 | }
101 |
102 | .scale-1px:after {
103 | content: '';
104 | position: absolute;
105 | bottom: 0;
106 | left: 0;
107 | background: var(--border-color);
108 | width: 100%;
109 | height: 1px;
110 | -webkit-transform: scaleY(0.5);
111 | transform: scaleY(0.5);
112 | -webkit-transform-origin: 0 0;
113 | transform-origin: 0 0;
114 | }
115 |
116 | /* 单行超出省略; */
117 | .ellipsis_1 {
118 | overflow: hidden;
119 | text-overflow: ellipsis;
120 | display: -webkit-box;
121 | -webkit-line-clamp: 1;
122 | -webkit-box-orient: vertical;
123 | word-break: break-all;
124 | }
125 |
126 | .ellipsis_2 {
127 | overflow: hidden;
128 | text-overflow: ellipsis;
129 | display: -webkit-box;
130 | -webkit-line-clamp: 2;
131 | -webkit-box-orient: vertical;
132 | word-break: break-all;
133 | }
134 |
135 | .huanhang {
136 | display: block;
137 | word-break: break-all;
138 | overflow-wrap: break-word;
139 | }
140 |
141 | /* 底部占位 */
142 | .tabbar-fit-box {
143 | height: var(--tabbar-height);
144 | }
145 |
146 | /* 客服按钮 */
147 | .contactButton {
148 | position: absolute;
149 | top: 0;
150 | left: 0;
151 | width: 100%;
152 | height: 100%;
153 | opacity: 0;
154 | }
155 |
156 | /* 按钮 */
157 | .custom-btn-container {
158 | width: 80%;
159 | margin: 20rpx auto;
160 | }
161 |
162 | .submit {
163 | --button-normal-font-size: 32rpx;
164 | --button-default-height: 80rpx;
165 | width: 100% !important;
166 | }
167 |
168 | /* 布局通用样式 */
169 | .container {
170 | height: 100vh;
171 | width: 100vw;
172 | display: flex;
173 | flex-direction: column;
174 | overflow: hidden;
175 | box-sizing: border-box;
176 | }
177 |
178 | .scroll {
179 | flex: 1;
180 | overflow: hidden;
181 | }
182 |
183 | /* 弹出选择 样式覆盖 */
184 | .van-action-sheet__cancel,
185 | .van-action-sheet__item {
186 | padding: 20rpx 30rpx !important
187 | }
--------------------------------------------------------------------------------
/pages/address-detail_3/index.js:
--------------------------------------------------------------------------------
1 | const app = getApp()
2 | Page({
3 | data: {
4 | //导航栏配置
5 | navConfig: {
6 | title: "地址详细",
7 | isLeftArrow: true
8 | },
9 | //表单数据
10 | formData: {
11 | contactName: '',
12 | contactTel: "",
13 | county: "",
14 | province: "",
15 | city: "",
16 | addressDetail: "",
17 | houseNumber: "",
18 | },
19 | isShowSmartAddress: true,
20 | isShowAreaSelect: false,
21 | isSelect: false,
22 | phoneNumberError: "",
23 | },
24 |
25 | onLoad: function (options) {
26 | this.setData({
27 | formData: JSON.parse(decodeURIComponent(options.address)),
28 | })
29 | },
30 |
31 | onReady: function () {
32 | this.toast = this.selectComponent('.my-toast');
33 | },
34 |
35 | changeContactName({
36 | detail
37 | }) {
38 | this.setData({
39 | "formData.contactName": detail,
40 | })
41 | },
42 |
43 | changeContactTel({
44 | detail
45 | }) {
46 | const param = {
47 | "formData.contactTel": detail,
48 | }
49 | if (detail.length === 11 && /^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(detail)) {
50 | param.phoneNumberError = ""
51 | }
52 | this.setData(param)
53 | },
54 |
55 | changeHouseMumber({
56 | detail
57 | }) {
58 | this.setData({
59 | "formData.houseNumber": detail,
60 | })
61 | },
62 |
63 | showSmartAddress: function () {
64 | this.setData({
65 | isShowSmartAddress: !this.data.isShowSmartAddress
66 | })
67 | },
68 |
69 | confirmArea: function ({
70 | detail
71 | }) {
72 | this.setData({
73 | "formData.province": detail[0],
74 | "formData.city": detail[1],
75 | "formData.county": detail[2],
76 | })
77 | },
78 |
79 | changeAddressDetail({
80 | detail
81 | }) {
82 | this.setData({
83 | "formData.addressDetail": detail
84 | })
85 | },
86 |
87 | getLocation() {
88 | const {
89 | longitudeLatitude
90 | } = this.data.formData
91 | wx.navigateTo({
92 | url: '../../pages/map/index?longitudeLatitude=' + (longitudeLatitude || ''),
93 | })
94 | },
95 |
96 | insightAddress() {
97 | const addressObj = app.smart(this.data.smartAddress)
98 | let {
99 | name = "",
100 | phone = "",
101 | province = "",
102 | city = "",
103 | county = "",
104 | street = "",
105 | address = ""
106 | } = addressObj
107 | this.setData({
108 | "formData.contactName": name,
109 | "formData.contactTel": phone,
110 | "formData.province": province,
111 | "formData.city": city,
112 | "formData.county": county,
113 | "formData.addressDetail": street + address,
114 | })
115 | },
116 |
117 | changeSmartAddress(e) {
118 | this.setData({
119 | smartAddress: e.detail
120 | })
121 | },
122 |
123 | async saveAddress() {
124 | const formData = this.data.formData
125 | for (const key in formData) {
126 | if (formData.hasOwnProperty(key)) {
127 | if (!formData[key]) {
128 | wx.showToast({
129 | icon: "none",
130 | title: '请填写完整信息',
131 | })
132 | return
133 | }
134 | }
135 | }
136 | if (!(/^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(formData.contactTel))) {
137 | wx.showToast({
138 | icon: "none",
139 | title: '手机号格式错误',
140 | })
141 | this.setData({
142 | "phoneNumberError": "手机号格式错误"
143 | })
144 | return
145 | }
146 | },
147 | async delAddress() {
148 | this.setData({
149 | "toastConfig.type": "success",
150 | "toastConfig.message": "删除成功",
151 | })
152 | this.toast.show()
153 | if (res.code === 200) {
154 | wx.navigateBack({
155 | delta: 1,
156 | })
157 | }
158 | },
159 | showAreaSelect: function () {
160 | this.selectComponent("#area-select").showAreaSelect();
161 | },
162 | })
--------------------------------------------------------------------------------
/pages/address-detail_2/index.js:
--------------------------------------------------------------------------------
1 |
2 | Page({
3 | data: {
4 | //导航栏配置
5 | navConfig: {
6 | title: "地址详细",
7 | isLeftArrow: true
8 | },
9 | //表单数据
10 | formData: {
11 | contactName: '',
12 | contactTel: "",
13 | county: "",
14 | province: "",
15 | city: "",
16 | addressDetail: "",
17 | houseNumber: "",
18 | },
19 | isShowSmartAddress: false,
20 | isShowAreaSelect: false,
21 | isSelect: false,
22 | phoneNumberError: "",
23 | },
24 |
25 | onLoad: function (options) {
26 | this.setData({
27 | formData: JSON.parse(decodeURIComponent(options.address)),
28 | })
29 | },
30 |
31 | onReady: function () {
32 | this.toast = this.selectComponent('.my-toast');
33 | },
34 |
35 | changeContactName({
36 | detail
37 | }) {
38 | this.setData({
39 | "formData.contactName": detail,
40 | })
41 | },
42 |
43 | changeContactTel({
44 | detail
45 | }) {
46 | const param = {
47 | "formData.contactTel": detail,
48 | }
49 | if (detail.length === 11 && /^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(detail)) {
50 | param.phoneNumberError = ""
51 | }
52 | this.setData(param)
53 | },
54 |
55 | changeHouseMumber({
56 | detail
57 | }) {
58 | this.setData({
59 | "formData.houseNumber": detail,
60 | })
61 | },
62 |
63 | showSmartAddress: function () {
64 | this.setData({
65 | isShowSmartAddress: !this.data.isShowSmartAddress
66 | })
67 | },
68 |
69 | confirmArea: function ({
70 | detail
71 | }) {
72 | this.setData({
73 | "formData.province": detail[0],
74 | "formData.city": detail[1],
75 | "formData.county": detail[2],
76 | })
77 | },
78 |
79 | changeAddressDetail({
80 | detail
81 | }) {
82 | this.setData({
83 | "formData.addressDetail": detail
84 | })
85 | },
86 |
87 | getLocation() {
88 | const {
89 | longitudeLatitude
90 | } = this.data.formData
91 | wx.navigateTo({
92 | url: '../../pages/map/index?longitudeLatitude=' + (longitudeLatitude || ''),
93 | })
94 | },
95 |
96 | // insightAddress() {
97 | // const addressObj = app.smart(this.data.smartAddress)
98 | // let {
99 | // name = "",
100 | // phone = "",
101 | // province = "",
102 | // city = "",
103 | // county = "",
104 | // street = "",
105 | // address = ""
106 | // } = addressObj
107 | // this.setData({
108 | // "formData.contactName": name,
109 | // "formData.contactTel": phone,
110 | // "formData.province": province,
111 | // "formData.city": city,
112 | // "formData.county": county,
113 | // "formData.addressDetail": street + address,
114 | // })
115 | // },
116 |
117 | changeSmartAddress(e) {
118 | this.setData({
119 | smartAddress: e.detail
120 | })
121 | },
122 |
123 | async saveAddress() {
124 | const formData = this.data.formData
125 | for (const key in formData) {
126 | if (formData.hasOwnProperty(key)) {
127 | if (!formData[key]) {
128 | wx.showToast({
129 | icon: "none",
130 | title: '请填写完整信息',
131 | })
132 | return
133 | }
134 | }
135 | }
136 | if (!(/^(?:(?:\+|00)86)?1[3-9]\d{9}$/.test(formData.contactTel))) {
137 | wx.showToast({
138 | icon: "none",
139 | title: '手机号格式错误',
140 | })
141 | this.setData({
142 | "phoneNumberError": "手机号格式错误"
143 | })
144 | return
145 | }
146 | },
147 |
148 | async delAddress() {
149 | this.setData({
150 | "toastConfig.type": "success",
151 | "toastConfig.message": "删除成功",
152 | })
153 | this.toast.show()
154 | if (res.code === 200) {
155 | wx.navigateBack({
156 | delta: 1,
157 | })
158 | }
159 | },
160 |
161 | showAreaSelect: function () {
162 | this.selectComponent("#area-select").showAreaSelect();
163 | },
164 | })
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 微信小程序通用项目模板——「提高效率,~~安心摸鱼~~专注于业务逻辑」
2 |
3 | 模板特点:vant-weapp、自定义导航栏、自定 tabbar、自定义mixin混入、全局样式、请求接口二次封装(request.js)、枚举(emun.js)、全局环境变量、添加地址模板三种方式(省市区联动、地图选点、智能识别)、vant 转换像素单位(px 转 rpx , 需自己转换) 等等
4 |
5 | ## 项目启动
6 |
7 | - 安装依赖
8 | ```
9 | //项目根目录,执行命令
10 | npm i
11 | ```
12 | - 构建 npm 包
13 |
14 | 微信开发者工具 --> 工具 --> 构建 npm
15 |
16 |
17 | ## 项目目录:
18 |
19 | ```
20 | wx_template
21 | ├─ api
22 | │ └─ user.js // user 用户相关的 api
23 | ├─ app.js
24 | ├─ app.json // 小程序全局配置
25 | ├─ app.wxss // 全局样式
26 | ├─ common
27 | │ ├─ behavior.js // 组件公用的 behavior
28 | │ ├─ emun.js // 枚举
29 | │ └─ globalMixin.js // 页面公用的 m1312ixin(混入)
30 | ├─ components
31 | │ ├─ area-select // 地区选择组件
32 | │ │ ├─ index.js
33 | │ │ ├─ index.json
34 | │ │ ├─ index.wxml
35 | │ │ └─ index.wxss
36 | │ ├─ authorize // 用户信息和手机号码授权组件
37 | │ │ ├─ index.js
38 | │ │ ├─ index.json
39 | │ │ ├─ index.wxml
40 | │ │ ├─ index.wxss
41 | │ │ └─ mixin.js
42 | │ └─ navbar // 顶部导航栏
43 | │ ├─ index.js
44 | │ ├─ index.json
45 | │ ├─ index.wxml
46 | │ └─ index.wxss
47 | ├─ config.js // 全局配置
48 | ├─ css
49 | │ └─ variables.wxss // css 全局变量
50 | ├─ custom-tab-bar // 自定义 tabbar
51 | │ ├─ index.js
52 | │ ├─ index.json
53 | │ ├─ index.wxml
54 | │ └─ index.wxss
55 | ├─ fonts
56 | │ └─ iconfont.wxss // iconfont 字体样式
57 | ├─ pages // 页面(用于演示)
58 | │ ├─ index
59 | │ ├─ map
60 | │ ├─ index
61 | │ ├─ address-detail_1
62 | │ ├─ address-detail_2
63 | │ ├─ address-detail_3
64 | ├─ project.config.json // 项目配置,对应小程序开发者工具,右侧的勾选项
65 | ├─ sitemap.json
66 | ├─ gulpfile.json // gulpfile gulp的配置文件,用于搭配 postcss-pxtransform 转换 vant 像素单位
67 | └─ utils
68 | ├─ smartWeChat // 智能识别地址
69 | ├─ authLogin.js // 登录校验逻辑
70 | ├─ mixin.js // 使小程序页面也具备类似于 vue 的 mixin(混入) 功能
71 | ├─ request.js // 请求的统一处理,例如:携带token、token校验、异常处理等
72 | ├─ qqmap-wx-jssdk.min.js // 腾讯地图 sdk
73 | ├─ smartWeChat // 地址只能识别插件
74 | └─ utils.js // 一些公用的工具函数、如果时间格式化、图片压缩等
75 | ```
76 |
77 | ## vant-weapp 转换像素单位 (px 转 rpx)
78 | 假设你已经安装了`vant-weapp`, 并且已经 `npm 构建`,如果构建失败可以参考 —— [「微信官网」](https://developers.weixin.qq.com/miniprogram/dev/devtools/npm.html)
79 | ### 安装依赖
80 | ```
81 | npm i gulp gulp-postcss postcss-pxtransform -D
82 | ```
83 | ### 创建 gulp 配置信息
84 | 根目录里面已经创建好了 `gulpfile.js`,不用新建,但是有个地方需要注意,看清楚 `vant-weapp` 构建后的路径是否正确,如果不正确改成自己的就好
85 | ```
86 | //根据自己的 vant 构建路径来
87 | return gulp.src(['miniprogram_npm/@vant/weapp/**/*.wxss'])
88 | .pipe(postcss(processors))
89 | .pipe(gulp.dest('miniprogram_npm/@vant/weapp/'));
90 | ```
91 | ### 修改 node_modules/postcss-pxtransform/index.js
92 | ```
93 | // 默认设置 deviceRatio
94 | // const deviceRatio = {
95 | // 640: 2.34 / 2,
96 | // 750: 1,
97 | // 828: 1.81 / 2
98 | // }
99 |
100 | const deviceRatio = {
101 | 640: 2.34,
102 | 750: 2,
103 | 828: 1.81
104 | }
105 | ```
106 |
107 | ### 添加 npm 脚本,并运行
108 | ```
109 | // package.json(已配置)
110 | scripts": {
111 | "build": "gulp css",
112 | },
113 | ```
114 | ```
115 | // 运行 npm 脚本
116 | npm run build
117 | ```
118 |
119 | ## 项目相关文章:
120 |
121 | 掘金:
122 | - [微信小程序开发那些事 —— 项目前期准备篇](https://juejin.cn/post/6975434044024553503)
123 | - [微信小程序登录功能的实现以及坑点 —— 前端实现](https://juejin.cn/post/6976455315298451470)
124 | - [微信小程序添加地址的三种实现方式 —— 省市区联动选择器、地图选点、智能识别地址](https://juejin.cn/post/6979432031961022478)
125 |
126 | 知乎:
127 | - [微信小程序开发那些事 —— 项目前期准备篇](https://zhuanlan.zhihu.com/p/382180744)
128 | - [微信小程序登录功能的实现以及坑点 —— 前端实现](https://zhuanlan.zhihu.com/p/382588175)
129 | - [微信小程序添加地址的三种实现方式 —— 省市区联动选择器、地图选点、智能识别地址](https://zhuanlan.zhihu.com/p/385354223)
130 |
131 |
--------------------------------------------------------------------------------
/utils/utils.js:
--------------------------------------------------------------------------------
1 | import {
2 | CACHE_TOKEN,
3 | HTTP_OSS_URL
4 | } from "../config"
5 |
6 | /**
7 | * 对Date的扩展,将 Date 转化为指定格式的String
8 | * 月(Y)、月(m)、日(d)、小时(H)、分(M)、秒(S) 可以用 1-2 个占位符,
9 | * 例子:
10 | * dateFormat('YYYY-mm-dd HH:MM:SS', new Date()) ==> 2020-01-01 08:00:00
11 | */
12 |
13 | export const dateFormat = (date = new Date(), fmt = "YYYY-mm-dd") => {
14 | const opt = {
15 | "Y+": date.getFullYear().toString(), // 年
16 | "m+": (date.getMonth() + 1).toString(), // 月
17 | "d+": date.getDate().toString(), // 日
18 | "H+": date.getHours().toString(), // 时
19 | "M+": date.getMinutes().toString(), // 分
20 | "S+": date.getSeconds().toString() // 秒
21 | // 有其他格式化字符需求可以继续添加,必须转化成字符串
22 | };
23 | let ret
24 | for (let k in opt) {
25 | ret = new RegExp("(" + k + ")").exec(fmt)
26 | if (ret) {
27 | fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1].length, "0")))
28 | };
29 | };
30 | return fmt
31 | }
32 |
33 | // 获取年月日 YYYY-MM-DD
34 | const getDate = (time) => {
35 | return time.getFullYear() + "-" +
36 | (time.getMonth() + 1).toString().padStart(2, "0") + "-" +
37 | time.getDate().toString().padStart(2, "0")
38 | }
39 |
40 | // 数组形式返回,今天往后的day后的天
41 | //day 为返回今天往后的天数
42 | const getDateList = (day) => {
43 | let dateList = []
44 | for (let i = 1; i <= day; i++) {
45 | let today = new Date();
46 | let targetday_milliseconds = today.getTime() + 1000 * 60 * 60 * 24 * i;
47 | today.setTime(targetday_milliseconds); //注意,这行是关键代码
48 | dateList.push(today.getDate())
49 | }
50 | return dateList;
51 | }
52 |
53 | // 今天往后的day后的天 ,并格式化 YYYY-MM-DD
54 | const getAfterDate = (day) => {
55 | let today = new Date();
56 | let targetday_milliseconds = today.getTime() + 1000 * 60 * 60 * 24 * day;
57 | today.setTime(targetday_milliseconds); //注意,这行是关键代码
58 | return getDate(today)
59 | }
60 |
61 | // 返回星期几
62 | const getWeekList = (dataList) => {
63 | const weekEum = {
64 | 0: "日",
65 | 1: "一",
66 | 2: "二",
67 | 3: "三",
68 | 4: "四",
69 | 5: "五",
70 | 6: "六",
71 | }
72 | return dataList.map(x => {
73 | let today = new Date()
74 | let targetday_milliseconds = today.getTime() + 1000 * 60 * 60 * 24 * (x - today.getDate());
75 | today.setTime(targetday_milliseconds);
76 | return weekEum[today.getDay()]
77 | })
78 | }
79 |
80 | //压缩图片, 老方法,不建议使用。
81 | /*
82 | instance 为当前实例
83 | canvas canvas DOM元素实例
84 | canvsdId canvas-id="xxx"
85 | url 图片文件本地临时路径
86 | ratio 压缩比例 0 ~ 1,1表示不压缩
87 | suffix 图片后缀
88 | */
89 | const compressImage = async function (instance, canvas, canvasId, url, ratio = 0.8, suffix = 'png') {
90 | return new Promise((resolve, reject) => {
91 | wx.getImageInfo({
92 | src: url,
93 | success: function (res) {
94 | var canvasWidth = res.width //图片原始长宽
95 | var canvasHeight = res.height
96 | canvasWidth = Math.trunc(res.width * ratio)
97 | canvasHeight = Math.trunc(res.height * ratio)
98 | instance.setData({
99 | cWidth: canvasWidth,
100 | cHeight: canvasHeight
101 | })
102 | // const canvas = wx.createCanvasContext(canvasId, instance)
103 | canvas.drawImage(res.path, 0, 0, canvasWidth, canvasHeight)
104 | canvas.draw(false, setTimeout(() => {
105 | wx.canvasToTempFilePath({
106 | canvasId: canvasId,
107 | destWidth: canvasWidth,
108 | destHeight: canvasHeight,
109 | fileType: suffix,
110 | quality: ratio,
111 | success: function (res) {
112 | // 返回压缩后的图片路径
113 | resolve(res.tempFilePath)
114 | },
115 | fail: function (res) {
116 | reject(null)
117 | }
118 | }, instance)
119 | }, 500))
120 | },
121 | fail: function (res) {
122 | console.log(res.errMsg)
123 | },
124 | })
125 | })
126 | }
127 |
128 | // 只接受单张图片上传
129 | const upload = async function (file, canvas, canvasId, fileType, success) {
130 | //只接受 jpg、gif、png 格式的文件,
131 | const acceptFileType = ['jpg', 'gif', 'png']
132 | const index = file.url.lastIndexOf('.') + 1
133 | const suffix = file.url.slice(index)
134 | if (!acceptFileType.includes(suffix)) {
135 | this.setData({
136 | 'toastConfig.type': 'text',
137 | 'toastConfig.message': `仅支持上传,${acceptFileType.join('、')}格式的文件`,
138 | })
139 | return this.toast.show()
140 | }
141 | const fileUrl = await compressImage(this, canvas, canvasId, file.url, 0.8, suffix)
142 | file.url = fileUrl
143 |
144 | // 图片大于 2M 时压缩
145 | // if (file.size > 2 * 1024 * 1024) {
146 | // console.log("压缩")
147 | // console.log(file.url)
148 | // const fileUrl = await compressImage(this, canvas, canvasId, file.url, 0.8)
149 | // file.url = fileUrl
150 | // console.log(file.url)
151 | // }
152 | wx.uploadFile({
153 | url: HTTP_OSS_URL + 'upload',
154 | filePath: file.url,
155 | name: 'file',
156 | formData: {
157 | fileType: fileType
158 | },
159 | header: {
160 | "X-Access-Token": wx.getStorageSync(CACHE_TOKEN)
161 | },
162 | success: (res) => {
163 | success(res)
164 | },
165 | });
166 | }
167 |
168 |
169 | // 防抖
170 | const debounce = (fn, wait, immediate = false) => {
171 | let timer, startTimeStamp = 0;
172 | let context, args;
173 |
174 | let run = (timerInterval) => {
175 | timer = setTimeout(() => {
176 | let now = (new Date()).getTime();
177 | let interval = now - startTimeStamp
178 | if (interval < timerInterval) {
179 | console.log('debounce reset', timerInterval - interval);
180 | startTimeStamp = now;
181 | run(wait - interval);
182 | } else {
183 | if (!immediate) {
184 | fn.apply(context, args);
185 | }
186 | clearTimeout(timer);
187 | timer = null;
188 | }
189 |
190 | }, timerInterval);
191 | }
192 |
193 | return function () {
194 | context = this;
195 | args = arguments;
196 | let now = (new Date()).getTime();
197 | startTimeStamp = now;
198 |
199 | if (!timer) {
200 | console.log('debounce set', wait);
201 | if (immediate) {
202 | fn.apply(context, args);
203 | }
204 | run(wait);
205 | }
206 |
207 | }
208 |
209 | }
210 | module.exports = {
211 | dateFormat,
212 | getDateList,
213 | getWeekList,
214 | getDate,
215 | getAfterDate,
216 | compressImage,
217 | upload,
218 | debounce
219 | }
--------------------------------------------------------------------------------
/pages/map/index.js:
--------------------------------------------------------------------------------
1 | import {
2 | MAP_KEY
3 | } from "../../config"
4 | const citySelector = requirePlugin('citySelector');
5 | import QQMapWX from "../../utils/qqmap-wx-jssdk.min.js"
6 | let qqmapsdk;
7 | Page({
8 | data: {
9 | navConfig: {
10 | title: "地图选点",
11 | isLeftArrow: true
12 | },
13 | cityName: "佛山市",
14 | latitude: '',
15 | longitude: '',
16 | centerData: {},
17 | nearList: [],
18 | selectedId: 0,
19 | defaultKeyword: '房产小区',
20 | keyword: '',
21 | pageIndex: 1,
22 | pageSize: 20,
23 | isDone: false,
24 | MAP_KEY,
25 | },
26 |
27 | onLoad: async function (options) {
28 | //获取地图 map 实例
29 | this.mapCtx = wx.createMapContext('myMap')
30 | // 实例化API核心类
31 | qqmapsdk = new QQMapWX({
32 | key: MAP_KEY
33 | });
34 | //判断是否授权定位
35 | let scopeRes = await wx.getSetting()
36 | if (!scopeRes.authSetting['scope.userLocation']) {
37 | try {
38 | // 没有授权的时候弹出授权窗口
39 | await wx.authorize({
40 | scope: 'scope.userLocation',
41 | })
42 | } catch (error) {
43 | // 用户手动关闭的授权,无法自动调起授权窗口,我们只能提示引导用户授权
44 | wx.showModal({
45 | showCancel: false,
46 | title: '位置授权',
47 | content: '该功能,需要进行「位置授权」才能使用。可点击「右上角」-->「设置」-->「位置消息」-->「仅在使用小程序使用」'
48 | })
49 | return
50 | }
51 | }
52 | wx.showLoading({
53 | title: '加载中'
54 | });
55 |
56 | //判断表单是否传了经纬度,如果有则使用表单的,用于在地图里显示刚才选择的位置
57 | const longitudeLatitude = options ? options.longitudeLatitude : ""
58 | if (longitudeLatitude) {
59 | const longLatArr = longitudeLatitude.split(',')
60 | this.initLocation(longLatArr[1], longLatArr[0])
61 | } else {
62 | //微信作死!新版本 wx.getLocation 存在调用频率限制, 使用 onLocationChange 来代替
63 | wx.startLocationUpdate({
64 | success: (res) => {
65 | wx.onLocationChange((location) => {
66 | if (location) {
67 | const {
68 | latitude,
69 | longitude
70 | } = location
71 | wx.stopLocationUpdate()
72 | this.setData({
73 | latitude,
74 | longitude
75 | })
76 | this.initLocation(latitude, longitude)
77 | }
78 | })
79 | },
80 | })
81 | }
82 | },
83 |
84 | onShow: function () {
85 | //城市选择插件,获取城市信息
86 | const selectedCity = citySelector.getCity();
87 | if (selectedCity) {
88 | const {
89 | fullname,
90 | location
91 | } = selectedCity
92 | this.setData({
93 | longitude: location.longitude,
94 | latitude: location.latitude,
95 | cityName: fullname
96 | })
97 | this.data.pageIndex = 1
98 | this.data.isDone = false
99 | this.nearBySearch()
100 | }
101 |
102 | },
103 | onUnload() {
104 | // 页面卸载时清空插件数据,防止再次进入页面,getCity返回的是上次的结果
105 | citySelector.clearCity();
106 | },
107 |
108 | toSelectCity() {
109 | const key = MAP_KEY; // 使用在腾讯位置服务申请的key
110 | const referer = '微信模板'; // 调用插件的app的名称
111 | wx.navigateTo({
112 | url: `plugin://citySelector/index?key=${key}&referer=${referer}`,
113 | })
114 | },
115 |
116 | //监听拖动地图,拖动结束根据中心点更新页面
117 | mapChange: function (e) {
118 | if (e.type == 'end' && (e.causedBy == 'scale' || e.causedBy == 'drag')) {
119 | this.mapCtx.getCenterLocation({
120 | success: (res) => {
121 | this.setData({
122 | nearList: [],
123 | latitude: res.latitude,
124 | longitude: res.longitude,
125 | })
126 | this.data.pageIndex = 1
127 | this.data.isDone = false
128 | this.nearBySearch.call(this);
129 | }
130 | })
131 | }
132 |
133 | },
134 |
135 | // 重置
136 | reload: function () {
137 | this.setData({
138 | nearList: []
139 | })
140 | this.onLoad();
141 | },
142 |
143 | chooseCenter: function (e) {
144 | let id = e.currentTarget.id;
145 | for (let i = 0; i < this.data.nearList.length; i++) {
146 | if (i == id) {
147 | this.setData({
148 | selectedId: id,
149 | centerData: this.data.nearList[i],
150 | latitude: this.data.nearList[i].latitude,
151 | longitude: this.data.nearList[i].longitude,
152 | });
153 | this.selectedOk()
154 | return;
155 | }
156 | }
157 | },
158 |
159 | nearBySearch: function (e) {
160 | if (e) {
161 | this.setData({
162 | keyword: e.detail,
163 | pageIndex: 1,
164 | nearList: [],
165 | addressInput: e.detail
166 | })
167 | }
168 | wx.hideLoading();
169 | wx.showLoading({
170 | title: '加载中'
171 | });
172 | qqmapsdk.search({
173 | keyword: this.data.keyword,
174 | location: this.data.latitude + ',' + this.data.longitude,
175 | page_size: this.data.pageSize,
176 | page_index: this.data.pageIndex,
177 | success: (res) => {
178 | wx.hideLoading();
179 | let sug = [];
180 | for (let i = 0; i < res.data.length; i++) {
181 | sug.push({
182 | title: res.data[i].title,
183 | id: res.data[i].id,
184 | addr: res.data[i].address,
185 | province: res.data[i].ad_info.province,
186 | city: res.data[i].ad_info.city,
187 | district: res.data[i].ad_info.district,
188 | latitude: res.data[i].location.lat,
189 | longitude: res.data[i].location.lng
190 | });
191 | }
192 | let pageIndex = this.data.pageIndex + 1
193 | if (sug.length < this.data.pageSize) {
194 | this.data.isDone = true
195 | pageIndex = this.data.pageIndex
196 | };
197 | this.setData({
198 | selectedId: 0,
199 | centerData: sug[0],
200 | nearList: this.data.nearList.concat(sug),
201 | pageIndex: pageIndex
202 | })
203 | },
204 | complete: function (res) {
205 | wx.hideLoading();
206 | }
207 | });
208 | },
209 | //确认选择地址
210 | selectedOk: function () {
211 | let pages = getCurrentPages();
212 | //获取上一个页面的实例
213 | let prevPage = pages[pages.length - 2];
214 | const {
215 | title,
216 | city,
217 | district,
218 | province,
219 | latitude,
220 | longitude
221 | } = this.data.centerData
222 | prevPage.setData({
223 | "formData.county": district,
224 | "formData.province": province,
225 | "formData.city": city,
226 | "formData.addressDetail": title,
227 | "formData.longitudeLatitude": longitude + ',' + latitude,
228 | })
229 | wx.navigateBack({
230 | delta: 1
231 | })
232 | },
233 |
234 | //初始化
235 | initLocation: function (latitude, longitude) {
236 | qqmapsdk.reverseGeocoder({
237 | location: {
238 | latitude,
239 | longitude
240 | },
241 | get_poi: 1,
242 | success: (res) => {
243 | this.setData({
244 | latitude: latitude,
245 | longitude: longitude,
246 | keyword: this.data.defaultKeyword,
247 | cityName: res.result.address_component.city,
248 | pageIndex: 1,
249 | addressInput: ""
250 | })
251 | this.nearBySearch();
252 | },
253 | });
254 | },
255 | loadLocation() {
256 | if (!this.data.isDone) this.nearBySearch();
257 | }
258 | })
--------------------------------------------------------------------------------
/utils/smartWeChat/js/address_parse.js:
--------------------------------------------------------------------------------
1 | var addressList = []; //地址列表
2 | var zipCodeList = []; //邮编列表
3 | var zipCode = require("./zipCode.js");
4 |
5 | console.log("正在加载省市区数据...");
6 |
7 | const wx_getaddress = () => {
8 | return new Promise((resolve, reject) => {
9 | let array = [];
10 | let index = 0;
11 | let length = 7;
12 | // console.log('共计' + length + '条数据')
13 | for (let i = 0; i < length; i++) {
14 | if (wx.getStorageSync(i + "")) {
15 | index++;
16 | // console.log('第' + index + '条数据在缓存中读取完毕')
17 | array = [...array, ...JSON.parse(wx.getStorageSync(i + ""))];
18 | if (index == length) {
19 | resolve(array);
20 | }
21 | } else {
22 | setTimeout(() => {
23 | wx.request({
24 | url: "https://wangzc.wang/addressJson/" + i,
25 | method: "GET",
26 | success: function(res) {
27 | index++;
28 | wx.setStorage({
29 | key: i + "",
30 | data: JSON.stringify(res.data)
31 | });
32 | // console.log('第' + index + '条数据加载完毕')
33 | array = [...array, ...res.data];
34 | if (index == length) {
35 | resolve(array);
36 | }
37 | }
38 | });
39 | }, 2000 * i);
40 | }
41 | }
42 | });
43 | };
44 |
45 | function getData() {
46 | wx_getaddress().then(res => {
47 | addressList = res;//地址赋值;这里可以加入自己写的接口进行赋值
48 | addressList.forEach(item => {
49 | formatAddresList(item, 1, "");
50 | });
51 | console.log(addressList);
52 | zipCodeList = zipCodeFormat(zipCode.variable);
53 | console.log("省市区数据挂载完毕!!");
54 | });
55 | }
56 | getData();
57 | /**
58 | * 地址数据处理
59 | * @param addressList-各级数据对象
60 | * @param index-对应的省/市/县区/街道
61 | * @param province-只有直辖市会处理为 北京市北京市
62 | * @returns
63 | */
64 | function formatAddresList(addressList, index, province) {
65 | if (index === 1) {
66 | //省
67 | addressList.province = addressList.name;
68 | }
69 | if (index === 2) {
70 | //市
71 | if (addressList.name == "市辖区") {
72 | addressList.name = province.name;
73 | }
74 | addressList.city = addressList.name;
75 | }
76 | if (index === 3) {
77 | //区或者县
78 | addressList.county = addressList.name;
79 | }
80 | if (index === 4) {
81 | //街道
82 | addressList.street = addressList.name;
83 | }
84 | if (addressList.children) {
85 | index++;
86 | addressList.children.forEach(res => {
87 | formatAddresList(res, index, addressList);
88 | });
89 | }
90 | }
91 | /**
92 | * 解析邮编
93 | * @param
94 | * @returns
95 | */
96 | function zipCodeFormat(zipCode) {
97 | let list = [];
98 | zipCode.forEach(el => {
99 | if (el.child) {
100 | el.child.forEach(event => {
101 | if (event.child) {
102 | event.child.forEach(element => {
103 | list.push(element.zipcode);
104 | });
105 | }
106 | });
107 | }
108 | });
109 | return list;
110 | }
111 |
112 | var smartObj = {};
113 | /**
114 | * 解析邮编
115 | * @param event识别的地址
116 | * @returns
117 | */
118 | function smart(event) {
119 | event = stripscript(event); //过滤特殊字符
120 | let obj = {};
121 | let copyaddress = JSON.parse(JSON.stringify(event));
122 | copyaddress = copyaddress.split(" ");
123 |
124 | copyaddress.forEach((res, index) => {
125 | if (res) {
126 | if (res.length == 1) {
127 | res += "XX"; // 过滤掉一位的名字或者地址
128 | }
129 | let addressObj = smatrAddress(res);
130 | obj = Object.assign(obj, addressObj);
131 | if (JSON.stringify(addressObj) === "{}") {
132 | obj.name = res.replace("XX", "");
133 | }
134 | }
135 | });
136 | return obj;
137 | }
138 | function smatrAddress(event) {
139 | smartObj = {};
140 | let address = event;
141 | //address= event.replace(/\s/g, ''); //去除空格
142 | address = stripscript(address); //过滤特殊字符
143 |
144 | //身份证号匹配
145 | if (IdentityCodeValid(address)) {
146 | smartObj.idCard = address;
147 | address = address.replace(address, "");
148 | }
149 |
150 | //电话匹配
151 | let phone = address.match(
152 | /(86-[1][0-9]{10}) | (86[1][0-9]{10})|([1][0-9]{10})/g
153 | );
154 | if (phone) {
155 | smartObj.phone = phone[0];
156 | address = address.replace(phone[0], "");
157 | }
158 |
159 | //邮编匹配
160 | zipCodeList.forEach(res => {
161 | if (address.indexOf(res) != -1) {
162 | let num = address.indexOf(res);
163 | let code = address.slice(num, num + 6);
164 | smartObj.zipCode = code;
165 | address = address.replace(code, "");
166 | }
167 | });
168 | let matchAddress = "";
169 | //省匹配 比如输入北京市朝阳区,会用北 北京 北京市 北京市朝 以此类推在addressList里的province中做匹配,会得到北京市 河北省 天津市等等;
170 | let matchProvince = []; //粗略匹配上的省份
171 | // for (let begIndex = 0; begIndex < address.length; begIndex++) {
172 | matchAddress = "";
173 | for (let endIndex = 0; endIndex < address.length; endIndex++) {
174 | // if (endIndex > begIndex) {
175 | matchAddress = address.slice(0, endIndex + 2);
176 | addressList.forEach(res => {
177 | if (res["province"].indexOf(matchAddress) != -1) {
178 | matchProvince.push({
179 | province: res.province,
180 | provinceCode: res.code,
181 | matchValue: matchAddress
182 | });
183 | }
184 | });
185 | // }
186 | }
187 | // }
188 |
189 | //统计筛选初略统计出的省份
190 | matchProvince.forEach(res => {
191 | res.index = 0;
192 | matchProvince.forEach(el => {
193 | if (res.province == el.province) {
194 | el.index++;
195 | if (res.matchValue.length > el.matchValue.length) {
196 | el.matchValue = res.matchValue;
197 | }
198 | }
199 | });
200 | });
201 | if (matchProvince.length != 0) {
202 | let province = matchProvince.reduce((p, v) => (p.index < v.index ? v : p));
203 | smartObj.province = province.province;
204 | smartObj.provinceCode = province.provinceCode;
205 | address = address.replace(province.matchValue, "");
206 | }
207 | //市查找
208 | let matchCity = []; //粗略匹配上的市
209 | matchAddress = "";
210 | for (let endIndex = 0; endIndex < address.length; endIndex++) {
211 | matchAddress = address.slice(0, endIndex + 2);
212 | addressList.forEach(el => {
213 | // if (el.name == smartObj.province) {
214 | if (el.code == smartObj.provinceCode || !smartObj.provinceCode) {
215 | if (
216 | smartObj.province == "北京市" ||
217 | smartObj.province == "天津市" ||
218 | smartObj.province == "上海市" ||
219 | smartObj.province == "重庆市"
220 | ) {
221 | el.children.forEach(item => {
222 | item.children.forEach(res => {
223 | if (res["county"].indexOf(matchAddress) != -1) {
224 | matchCity.push({
225 | county: res.county,
226 | countyCode: res.code,
227 | city: item.city,
228 | cityCode: item.code,
229 | matchValue: matchAddress,
230 | province: el.province,
231 | provinceCode: el.code
232 | });
233 | }
234 | });
235 | });
236 | } else {
237 | el.children.forEach(res => {
238 | if (res["city"].indexOf(matchAddress) != -1) {
239 | matchCity.push({
240 | city: res.city,
241 | cityCode: res.code,
242 | matchValue: matchAddress,
243 | province: el.province,
244 | provinceCode: el.code
245 | });
246 | }
247 | });
248 | }
249 | }
250 | // }
251 | });
252 | }
253 |
254 | //统计筛选初略统计出的市
255 | matchCity.forEach(res => {
256 | res.index = 0;
257 | matchCity.forEach(el => {
258 | if (res.city == el.city) {
259 | el.index++;
260 | if (res.matchValue.length > el.matchValue.length) {
261 | el.matchValue = res.matchValue;
262 | }
263 | }
264 | });
265 | });
266 | if (matchCity.length != 0) {
267 | let city = matchCity.reduce((p, v) => (p.index < v.index ? v : p));
268 | smartObj.city = city.city;
269 | smartObj.cityCode = city.cityCode;
270 | smartObj.county = city.county;
271 | smartObj.countyCode = city.countyCode;
272 | if (!smartObj.province) {
273 | smartObj.province = city.province;
274 | smartObj.provinceCode = city.provinceCode;
275 | }
276 | address = address.replace(city.matchValue, "");
277 | }
278 |
279 | //区县查找
280 | let matchCounty = []; //粗略匹配上的区县
281 | matchAddress = "";
282 | for (let endIndex = 0; endIndex < address.length; endIndex++) {
283 | matchAddress = address.slice(0, endIndex + 2);
284 | addressList.forEach(el => {
285 | // if (el.name == smartObj.province) {
286 | if (
287 | smartObj.province == "北京市" ||
288 | smartObj.province == "天津市" ||
289 | smartObj.province == "上海市" ||
290 | smartObj.province == "重庆市"
291 | ) {
292 | //nothing
293 | } else {
294 | el.children.forEach(item => {
295 | // if (item.name == smartObj.city) {
296 | item.children.forEach(res => {
297 | if (res["county"].indexOf(matchAddress) != -1) {
298 | //省/市 || 省
299 | if (smartObj.province) {
300 | if (res.code.slice(0, 2) == smartObj.provinceCode) {
301 | matchCounty.push({
302 | county: res.county,
303 | countyCode: res.code,
304 | city: item.city,
305 | cityCode: item.code,
306 | matchValue: matchAddress,
307 | province: el.province,
308 | provinceCode: el.code
309 | });
310 | }
311 | } else if (!smartObj.province && !smartObj.city) {
312 | matchCounty.push({
313 | county: res.county,
314 | countyCode: res.code,
315 | city: item.city,
316 | cityCode: item.code,
317 | matchValue: matchAddress,
318 | province: el.province,
319 | provinceCode: el.code
320 | });
321 | }
322 | }
323 | });
324 | // }
325 | });
326 | }
327 | // }
328 | });
329 | }
330 | //统计筛选初略统计出的区县
331 | matchCounty.forEach(res => {
332 | res.index = 0;
333 | matchCounty.forEach(el => {
334 | if (res.city == el.city) {
335 | el.index++;
336 | if (res.matchValue.length > el.matchValue.length) {
337 | el.matchValue = res.matchValue;
338 | }
339 | }
340 | });
341 | });
342 | if (matchCounty.length != 0) {
343 | let city = matchCounty.reduce((p, v) => (p.index < v.index ? v : p));
344 | smartObj.county = city.county;
345 | smartObj.countyCode = city.countyCode;
346 | if (!smartObj.province) {
347 | smartObj.province = city.province;
348 | smartObj.provinceCode = city.provinceCode;
349 | }
350 | if (!smartObj.city) {
351 | smartObj.city = city.city;
352 | smartObj.cityCode = city.cityCode;
353 | }
354 | address = address.replace(city.matchValue, "");
355 | }
356 |
357 | //街道查找
358 | let matchStreet = []; //粗略匹配上的街道查
359 | matchAddress = "";
360 | for (let endIndex = 0; endIndex < address.length; endIndex++) {
361 | matchAddress = address.slice(0, endIndex + 3);
362 | addressList.forEach(el => {
363 | if (el.name == smartObj.province) {
364 | if (
365 | smartObj.province == "北京市" ||
366 | smartObj.province == "天津市" ||
367 | smartObj.province == "上海市" ||
368 | smartObj.province == "重庆市"
369 | ) {
370 | //nothing
371 | } else {
372 | el.children.forEach(element => {
373 | if (element.name == smartObj.city) {
374 | element.children.forEach(item => {
375 | if (item.name == smartObj.county) {
376 | item.children.forEach(res => {
377 | if (res["street"].indexOf(matchAddress) != -1) {
378 | matchStreet.push({
379 | street: res.street,
380 | streetCode: res.code,
381 | matchValue: matchAddress
382 | });
383 | }
384 | });
385 | }
386 | });
387 | }
388 | });
389 | }
390 | }
391 | });
392 | }
393 |
394 | //统计筛选初略统计出的区县
395 | matchStreet.forEach(res => {
396 | res.index = 0;
397 | matchStreet.forEach(el => {
398 | if (res.city == el.city) {
399 | el.index++;
400 | if (res.matchValue.length > el.matchValue.length) {
401 | el.matchValue = res.matchValue;
402 | }
403 | }
404 | });
405 | });
406 |
407 | if (matchStreet.length != 0) {
408 | let city = matchStreet.reduce((p, v) => (p.index < v.index ? v : p));
409 | smartObj.street = city.street;
410 | smartObj.streetCode = city.streetCode;
411 | address = address.replace(city.matchValue, "");
412 | }
413 | //姓名查找
414 | if (smartObj.province) {
415 | smartObj.address = address;
416 | }
417 |
418 | return smartObj;
419 | }
420 | ////过滤特殊字符
421 | function stripscript(s) {
422 | s = s.replace(/(\d{3})-(\d{4})-(\d{4})/g, "$1$2$3");
423 | s = s.replace(/(\d{3}) (\d{4}) (\d{4})/g, "$1$2$3");
424 | var pattern = new RegExp(
425 | "[`~!@#$^&*()=|{}':;',\\[\\].<>/?~!@#¥……&*()——|{}【】‘;:”“’。,、?-]"
426 | );
427 | var rs = "";
428 | for (var i = 0; i < s.length; i++) {
429 | rs = rs + s.substr(i, 1).replace(pattern, " ");
430 | }
431 | rs = rs.replace(/[\r\n]/g, "");
432 | return rs;
433 | }
434 |
435 | function IdentityCodeValid(code) {
436 | let pass;
437 | var city = {
438 | 11: "北京",
439 | 12: "天津",
440 | 13: "河北",
441 | 14: "山西",
442 | 15: "内蒙古",
443 | 21: "辽宁",
444 | 22: "吉林",
445 | 23: "黑龙江 ",
446 | 31: "上海",
447 | 32: "江苏",
448 | 33: "浙江",
449 | 34: "安徽",
450 | 35: "福建",
451 | 36: "江西",
452 | 37: "山东",
453 | 41: "河南",
454 | 42: "湖北 ",
455 | 43: "湖南",
456 | 44: "广东",
457 | 45: "广西",
458 | 46: "海南",
459 | 50: "重庆",
460 | 51: "四川",
461 | 52: "贵州",
462 | 53: "云南",
463 | 54: "西藏 ",
464 | 61: "陕西",
465 | 62: "甘肃",
466 | 63: "青海",
467 | 64: "宁夏",
468 | 65: "新疆",
469 | 71: "台湾",
470 | 81: "香港",
471 | 82: "澳门",
472 | 91: "国外 "
473 | };
474 | var tip = "";
475 | pass = true;
476 |
477 | if (!code || !/^\d{17}(\d|X)$/i.test(code)) {
478 | tip = "身份证号格式错误";
479 | pass = false;
480 | } else if (!city[code.substr(0, 2)]) {
481 | tip = "地址编码错误";
482 | pass = false;
483 | } else {
484 | //18位身份证需要验证最后一位校验位
485 | if (code.length == 18) {
486 | code = code.split("");
487 | //∑(ai×Wi)(mod 11)
488 | //加权因子
489 | var factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
490 | //校验位
491 | var parity = [1, 0, "X", 9, 8, 7, 6, 5, 4, 3, 2];
492 | var sum = 0;
493 | var ai = 0;
494 | var wi = 0;
495 | for (var i = 0; i < 17; i++) {
496 | ai = code[i];
497 | wi = factor[i];
498 | sum += ai * wi;
499 | }
500 | var last = parity[sum % 11];
501 | if (parity[sum % 11] != code[17]) {
502 | tip = "校验位错误";
503 | pass = false;
504 | }
505 | }
506 | }
507 | return pass;
508 | }
509 |
510 | module.exports = {
511 | method: smart,
512 | getData: getData
513 | };
514 |
--------------------------------------------------------------------------------
/utils/qqmap-wx-jssdk.min.js:
--------------------------------------------------------------------------------
1 | var ERROR_CONF = { KEY_ERR: 311, KEY_ERR_MSG: 'key格式错误', PARAM_ERR: 310, PARAM_ERR_MSG: '请求参数信息有误', SYSTEM_ERR: 600, SYSTEM_ERR_MSG: '系统错误', WX_ERR_CODE: 1000, WX_OK_CODE: 200 }; var BASE_URL = 'https://apis.map.qq.com/ws/'; var URL_SEARCH = BASE_URL + 'place/v1/search'; var URL_SUGGESTION = BASE_URL + 'place/v1/suggestion'; var URL_GET_GEOCODER = BASE_URL + 'geocoder/v1/'; var URL_CITY_LIST = BASE_URL + 'district/v1/list'; var URL_AREA_LIST = BASE_URL + 'district/v1/getchildren'; var URL_DISTANCE = BASE_URL + 'distance/v1/'; var URL_DIRECTION = BASE_URL + 'direction/v1/'; var MODE = { driving: 'driving', transit: 'transit' }; var EARTH_RADIUS = 6378136.49; var Utils = { safeAdd(x, y) { var lsw = (x & 0xffff) + (y & 0xffff); var msw = (x >> 16) + (y >> 16) + (lsw >> 16); return (msw << 16) | (lsw & 0xffff) }, bitRotateLeft(num, cnt) { return (num << cnt) | (num >>> (32 - cnt)) }, md5cmn(q, a, b, x, s, t) { return this.safeAdd(this.bitRotateLeft(this.safeAdd(this.safeAdd(a, q), this.safeAdd(x, t)), s), b) }, md5ff(a, b, c, d, x, s, t) { return this.md5cmn((b & c) | (~b & d), a, b, x, s, t) }, md5gg(a, b, c, d, x, s, t) { return this.md5cmn((b & d) | (c & ~d), a, b, x, s, t) }, md5hh(a, b, c, d, x, s, t) { return this.md5cmn(b ^ c ^ d, a, b, x, s, t) }, md5ii(a, b, c, d, x, s, t) { return this.md5cmn(c ^ (b | ~d), a, b, x, s, t) }, binlMD5(x, len) { x[len >> 5] |= 0x80 << (len % 32); x[((len + 64) >>> 9 << 4) + 14] = len; var i; var olda; var oldb; var oldc; var oldd; var a = 1732584193; var b = -271733879; var c = -1732584194; var d = 271733878; for (i = 0; i < x.length; i += 16) { olda = a; oldb = b; oldc = c; oldd = d; a = this.md5ff(a, b, c, d, x[i], 7, -680876936); d = this.md5ff(d, a, b, c, x[i + 1], 12, -389564586); c = this.md5ff(c, d, a, b, x[i + 2], 17, 606105819); b = this.md5ff(b, c, d, a, x[i + 3], 22, -1044525330); a = this.md5ff(a, b, c, d, x[i + 4], 7, -176418897); d = this.md5ff(d, a, b, c, x[i + 5], 12, 1200080426); c = this.md5ff(c, d, a, b, x[i + 6], 17, -1473231341); b = this.md5ff(b, c, d, a, x[i + 7], 22, -45705983); a = this.md5ff(a, b, c, d, x[i + 8], 7, 1770035416); d = this.md5ff(d, a, b, c, x[i + 9], 12, -1958414417); c = this.md5ff(c, d, a, b, x[i + 10], 17, -42063); b = this.md5ff(b, c, d, a, x[i + 11], 22, -1990404162); a = this.md5ff(a, b, c, d, x[i + 12], 7, 1804603682); d = this.md5ff(d, a, b, c, x[i + 13], 12, -40341101); c = this.md5ff(c, d, a, b, x[i + 14], 17, -1502002290); b = this.md5ff(b, c, d, a, x[i + 15], 22, 1236535329); a = this.md5gg(a, b, c, d, x[i + 1], 5, -165796510); d = this.md5gg(d, a, b, c, x[i + 6], 9, -1069501632); c = this.md5gg(c, d, a, b, x[i + 11], 14, 643717713); b = this.md5gg(b, c, d, a, x[i], 20, -373897302); a = this.md5gg(a, b, c, d, x[i + 5], 5, -701558691); d = this.md5gg(d, a, b, c, x[i + 10], 9, 38016083); c = this.md5gg(c, d, a, b, x[i + 15], 14, -660478335); b = this.md5gg(b, c, d, a, x[i + 4], 20, -405537848); a = this.md5gg(a, b, c, d, x[i + 9], 5, 568446438); d = this.md5gg(d, a, b, c, x[i + 14], 9, -1019803690); c = this.md5gg(c, d, a, b, x[i + 3], 14, -187363961); b = this.md5gg(b, c, d, a, x[i + 8], 20, 1163531501); a = this.md5gg(a, b, c, d, x[i + 13], 5, -1444681467); d = this.md5gg(d, a, b, c, x[i + 2], 9, -51403784); c = this.md5gg(c, d, a, b, x[i + 7], 14, 1735328473); b = this.md5gg(b, c, d, a, x[i + 12], 20, -1926607734); a = this.md5hh(a, b, c, d, x[i + 5], 4, -378558); d = this.md5hh(d, a, b, c, x[i + 8], 11, -2022574463); c = this.md5hh(c, d, a, b, x[i + 11], 16, 1839030562); b = this.md5hh(b, c, d, a, x[i + 14], 23, -35309556); a = this.md5hh(a, b, c, d, x[i + 1], 4, -1530992060); d = this.md5hh(d, a, b, c, x[i + 4], 11, 1272893353); c = this.md5hh(c, d, a, b, x[i + 7], 16, -155497632); b = this.md5hh(b, c, d, a, x[i + 10], 23, -1094730640); a = this.md5hh(a, b, c, d, x[i + 13], 4, 681279174); d = this.md5hh(d, a, b, c, x[i], 11, -358537222); c = this.md5hh(c, d, a, b, x[i + 3], 16, -722521979); b = this.md5hh(b, c, d, a, x[i + 6], 23, 76029189); a = this.md5hh(a, b, c, d, x[i + 9], 4, -640364487); d = this.md5hh(d, a, b, c, x[i + 12], 11, -421815835); c = this.md5hh(c, d, a, b, x[i + 15], 16, 530742520); b = this.md5hh(b, c, d, a, x[i + 2], 23, -995338651); a = this.md5ii(a, b, c, d, x[i], 6, -198630844); d = this.md5ii(d, a, b, c, x[i + 7], 10, 1126891415); c = this.md5ii(c, d, a, b, x[i + 14], 15, -1416354905); b = this.md5ii(b, c, d, a, x[i + 5], 21, -57434055); a = this.md5ii(a, b, c, d, x[i + 12], 6, 1700485571); d = this.md5ii(d, a, b, c, x[i + 3], 10, -1894986606); c = this.md5ii(c, d, a, b, x[i + 10], 15, -1051523); b = this.md5ii(b, c, d, a, x[i + 1], 21, -2054922799); a = this.md5ii(a, b, c, d, x[i + 8], 6, 1873313359); d = this.md5ii(d, a, b, c, x[i + 15], 10, -30611744); c = this.md5ii(c, d, a, b, x[i + 6], 15, -1560198380); b = this.md5ii(b, c, d, a, x[i + 13], 21, 1309151649); a = this.md5ii(a, b, c, d, x[i + 4], 6, -145523070); d = this.md5ii(d, a, b, c, x[i + 11], 10, -1120210379); c = this.md5ii(c, d, a, b, x[i + 2], 15, 718787259); b = this.md5ii(b, c, d, a, x[i + 9], 21, -343485551); a = this.safeAdd(a, olda); b = this.safeAdd(b, oldb); c = this.safeAdd(c, oldc); d = this.safeAdd(d, oldd) } return [a, b, c, d] }, binl2rstr(input) { var i; var output = ''; var length32 = input.length * 32; for (i = 0; i < length32; i += 8) { output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xff) } return output }, rstr2binl(input) { var i; var output = []; output[(input.length >> 2) - 1] = undefined; for (i = 0; i < output.length; i += 1) { output[i] = 0 } var length8 = input.length * 8; for (i = 0; i < length8; i += 8) { output[i >> 5] |= (input.charCodeAt(i / 8) & 0xff) << (i % 32) } return output }, rstrMD5(s) { return this.binl2rstr(this.binlMD5(this.rstr2binl(s), s.length * 8)) }, rstrHMACMD5(key, data) { var i; var bkey = this.rstr2binl(key); var ipad = []; var opad = []; var hash; ipad[15] = opad[15] = undefined; if (bkey.length > 16) { bkey = this.binlMD5(bkey, key.length * 8) } for (i = 0; i < 16; i += 1) { ipad[i] = bkey[i] ^ 0x36363636; opad[i] = bkey[i] ^ 0x5c5c5c5c } hash = this.binlMD5(ipad.concat(this.rstr2binl(data)), 512 + data.length * 8); return this.binl2rstr(this.binlMD5(opad.concat(hash), 512 + 128)) }, rstr2hex(input) { var hexTab = '0123456789abcdef'; var output = ''; var x; var i; for (i = 0; i < input.length; i += 1) { x = input.charCodeAt(i); output += hexTab.charAt((x >>> 4) & 0x0f) + hexTab.charAt(x & 0x0f) } return output }, str2rstrUTF8(input) { return unescape(encodeURIComponent(input)) }, rawMD5(s) { return this.rstrMD5(this.str2rstrUTF8(s)) }, hexMD5(s) { return this.rstr2hex(this.rawMD5(s)) }, rawHMACMD5(k, d) { return this.rstrHMACMD5(this.str2rstrUTF8(k), str2rstrUTF8(d)) }, hexHMACMD5(k, d) { return this.rstr2hex(this.rawHMACMD5(k, d)) }, md5(string, key, raw) { if (!key) { if (!raw) { return this.hexMD5(string) } return this.rawMD5(string) } if (!raw) { return this.hexHMACMD5(key, string) } return this.rawHMACMD5(key, string) }, getSig(requestParam, sk, feature, mode) { var sig = null; var requestArr = []; Object.keys(requestParam).sort().forEach(function (key) { requestArr.push(key + '=' + requestParam[key]) }); if (feature == 'search') { sig = '/ws/place/v1/search?' + requestArr.join('&') + sk } if (feature == 'suggest') { sig = '/ws/place/v1/suggestion?' + requestArr.join('&') + sk } if (feature == 'reverseGeocoder') { sig = '/ws/geocoder/v1/?' + requestArr.join('&') + sk } if (feature == 'geocoder') { sig = '/ws/geocoder/v1/?' + requestArr.join('&') + sk } if (feature == 'getCityList') { sig = '/ws/district/v1/list?' + requestArr.join('&') + sk } if (feature == 'getDistrictByCityId') { sig = '/ws/district/v1/getchildren?' + requestArr.join('&') + sk } if (feature == 'calculateDistance') { sig = '/ws/distance/v1/?' + requestArr.join('&') + sk } if (feature == 'direction') { sig = '/ws/direction/v1/' + mode + '?' + requestArr.join('&') + sk } sig = this.md5(sig); return sig }, location2query(data) { if (typeof data == 'string') { return data } var query = ''; for (var i = 0; i < data.length; i++) { var d = data[i]; if (!!query) { query += ';' } if (d.location) { query = query + d.location.lat + ',' + d.location.lng } if (d.latitude && d.longitude) { query = query + d.latitude + ',' + d.longitude } } return query }, rad(d) { return d * Math.PI / 180.0 }, getEndLocation(location) { var to = location.split(';'); var endLocation = []; for (var i = 0; i < to.length; i++) { endLocation.push({ lat: parseFloat(to[i].split(',')[0]), lng: parseFloat(to[i].split(',')[1]) }) } return endLocation }, getDistance(latFrom, lngFrom, latTo, lngTo) { var radLatFrom = this.rad(latFrom); var radLatTo = this.rad(latTo); var a = radLatFrom - radLatTo; var b = this.rad(lngFrom) - this.rad(lngTo); var distance = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLatFrom) * Math.cos(radLatTo) * Math.pow(Math.sin(b / 2), 2))); distance = distance * EARTH_RADIUS; distance = Math.round(distance * 10000) / 10000; return parseFloat(distance.toFixed(0)) }, getWXLocation(success, fail, complete) { wx.getLocation({ type: 'gcj02', success: success, fail: fail, complete: complete }) }, getLocationParam(location) { if (typeof location == 'string') { var locationArr = location.split(','); if (locationArr.length === 2) { location = { latitude: location.split(',')[0], longitude: location.split(',')[1] } } else { location = {} } } return location }, polyfillParam(param) { param.success = param.success || function () { }; param.fail = param.fail || function () { }; param.complete = param.complete || function () { } }, checkParamKeyEmpty(param, key) { if (!param[key]) { var errconf = this.buildErrorConfig(ERROR_CONF.PARAM_ERR, ERROR_CONF.PARAM_ERR_MSG + key + '参数格式有误'); param.fail(errconf); param.complete(errconf); return true } return false }, checkKeyword(param) { return !this.checkParamKeyEmpty(param, 'keyword') }, checkLocation(param) { var location = this.getLocationParam(param.location); if (!location || !location.latitude || !location.longitude) { var errconf = this.buildErrorConfig(ERROR_CONF.PARAM_ERR, ERROR_CONF.PARAM_ERR_MSG + ' location参数格式有误'); param.fail(errconf); param.complete(errconf); return false } return true }, buildErrorConfig(errCode, errMsg) { return { status: errCode, message: errMsg } }, handleData(param, data, feature) { if (feature == 'search') { var searchResult = data.data; var searchSimplify = []; for (var i = 0; i < searchResult.length; i++) { searchSimplify.push({ id: searchResult[i].id || null, title: searchResult[i].title || null, latitude: searchResult[i].location && searchResult[i].location.lat || null, longitude: searchResult[i].location && searchResult[i].location.lng || null, address: searchResult[i].address || null, category: searchResult[i].category || null, tel: searchResult[i].tel || null, adcode: searchResult[i].ad_info && searchResult[i].ad_info.adcode || null, city: searchResult[i].ad_info && searchResult[i].ad_info.city || null, district: searchResult[i].ad_info && searchResult[i].ad_info.district || null, province: searchResult[i].ad_info && searchResult[i].ad_info.province || null }) } param.success(data, { searchResult: searchResult, searchSimplify: searchSimplify }) } else if (feature == 'suggest') { var suggestResult = data.data; var suggestSimplify = []; for (var i = 0; i < suggestResult.length; i++) { suggestSimplify.push({ adcode: suggestResult[i].adcode || null, address: suggestResult[i].address || null, category: suggestResult[i].category || null, city: suggestResult[i].city || null, district: suggestResult[i].district || null, id: suggestResult[i].id || null, latitude: suggestResult[i].location && suggestResult[i].location.lat || null, longitude: suggestResult[i].location && suggestResult[i].location.lng || null, province: suggestResult[i].province || null, title: suggestResult[i].title || null, type: suggestResult[i].type || null }) } param.success(data, { suggestResult: suggestResult, suggestSimplify: suggestSimplify }) } else if (feature == 'reverseGeocoder') { var reverseGeocoderResult = data.result; var reverseGeocoderSimplify = { address: reverseGeocoderResult.address || null, latitude: reverseGeocoderResult.location && reverseGeocoderResult.location.lat || null, longitude: reverseGeocoderResult.location && reverseGeocoderResult.location.lng || null, adcode: reverseGeocoderResult.ad_info && reverseGeocoderResult.ad_info.adcode || null, city: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.city || null, district: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.district || null, nation: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.nation || null, province: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.province || null, street: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.street || null, street_number: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.street_number || null, recommend: reverseGeocoderResult.formatted_addresses && reverseGeocoderResult.formatted_addresses.recommend || null, rough: reverseGeocoderResult.formatted_addresses && reverseGeocoderResult.formatted_addresses.rough || null }; if (reverseGeocoderResult.pois) { var pois = reverseGeocoderResult.pois; var poisSimplify = []; for (var i = 0; i < pois.length; i++) { poisSimplify.push({ id: pois[i].id || null, title: pois[i].title || null, latitude: pois[i].location && pois[i].location.lat || null, longitude: pois[i].location && pois[i].location.lng || null, address: pois[i].address || null, category: pois[i].category || null, adcode: pois[i].ad_info && pois[i].ad_info.adcode || null, city: pois[i].ad_info && pois[i].ad_info.city || null, district: pois[i].ad_info && pois[i].ad_info.district || null, province: pois[i].ad_info && pois[i].ad_info.province || null }) } param.success(data, { reverseGeocoderResult: reverseGeocoderResult, reverseGeocoderSimplify: reverseGeocoderSimplify, pois: pois, poisSimplify: poisSimplify }) } else { param.success(data, { reverseGeocoderResult: reverseGeocoderResult, reverseGeocoderSimplify: reverseGeocoderSimplify }) } } else if (feature == 'geocoder') { var geocoderResult = data.result; var geocoderSimplify = { title: geocoderResult.title || null, latitude: geocoderResult.location && geocoderResult.location.lat || null, longitude: geocoderResult.location && geocoderResult.location.lng || null, adcode: geocoderResult.ad_info && geocoderResult.ad_info.adcode || null, province: geocoderResult.address_components && geocoderResult.address_components.province || null, city: geocoderResult.address_components && geocoderResult.address_components.city || null, district: geocoderResult.address_components && geocoderResult.address_components.district || null, street: geocoderResult.address_components && geocoderResult.address_components.street || null, street_number: geocoderResult.address_components && geocoderResult.address_components.street_number || null, level: geocoderResult.level || null }; param.success(data, { geocoderResult: geocoderResult, geocoderSimplify: geocoderSimplify }) } else if (feature == 'getCityList') { var provinceResult = data.result[0]; var cityResult = data.result[1]; var districtResult = data.result[2]; param.success(data, { provinceResult: provinceResult, cityResult: cityResult, districtResult: districtResult }) } else if (feature == 'getDistrictByCityId') { var districtByCity = data.result[0]; param.success(data, districtByCity) } else if (feature == 'calculateDistance') { var calculateDistanceResult = data.result.elements; var distance = []; for (var i = 0; i < calculateDistanceResult.length; i++) { distance.push(calculateDistanceResult[i].distance) } param.success(data, { calculateDistanceResult: calculateDistanceResult, distance: distance }) } else if (feature == 'direction') { var direction = data.result.routes; param.success(data, direction) } else { param.success(data) } }, buildWxRequestConfig(param, options, feature) { var that = this; options.header = { "content-type": "application/json" }; options.method = 'GET'; options.success = function (res) { var data = res.data; if (data.status === 0) { that.handleData(param, data, feature) } else { param.fail(data) } }; options.fail = function (res) { res.statusCode = ERROR_CONF.WX_ERR_CODE; param.fail(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg)) }; options.complete = function (res) { var statusCode = +res.statusCode; switch (statusCode) { case ERROR_CONF.WX_ERR_CODE: { param.complete(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg)); break } case ERROR_CONF.WX_OK_CODE: { var data = res.data; if (data.status === 0) { param.complete(data) } else { param.complete(that.buildErrorConfig(data.status, data.message)) } break } default: { param.complete(that.buildErrorConfig(ERROR_CONF.SYSTEM_ERR, ERROR_CONF.SYSTEM_ERR_MSG)) } } }; return options }, locationProcess(param, locationsuccess, locationfail, locationcomplete) { var that = this; locationfail = locationfail || function (res) { res.statusCode = ERROR_CONF.WX_ERR_CODE; param.fail(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg)) }; locationcomplete = locationcomplete || function (res) { if (res.statusCode == ERROR_CONF.WX_ERR_CODE) { param.complete(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg)) } }; if (!param.location) { that.getWXLocation(locationsuccess, locationfail, locationcomplete) } else if (that.checkLocation(param)) { var location = Utils.getLocationParam(param.location); locationsuccess(location) } } }; class QQMapWX { constructor(options) { if (!options.key) { throw Error('key值不能为空') } this.key = options.key }; search(options) { var that = this; options = options || {}; Utils.polyfillParam(options); if (!Utils.checkKeyword(options)) { return } var requestParam = { keyword: options.keyword, orderby: options.orderby || '_distance', page_size: options.page_size || 10, page_index: options.page_index || 1, output: 'json', key: that.key }; if (options.address_format) { requestParam.address_format = options.address_format } if (options.filter) { requestParam.filter = options.filter } var distance = options.distance || "1000"; var auto_extend = options.auto_extend || 1; var region = null; var rectangle = null; if (options.region) { region = options.region } if (options.rectangle) { rectangle = options.rectangle } var locationsuccess = function (result) { if (region && !rectangle) { requestParam.boundary = "region(" + region + "," + auto_extend + "," + result.latitude + "," + result.longitude + ")"; if (options.sig) { requestParam.sig = Utils.getSig(requestParam, options.sig, 'search') } } else if (rectangle && !region) { requestParam.boundary = "rectangle(" + rectangle + ")"; if (options.sig) { requestParam.sig = Utils.getSig(requestParam, options.sig, 'search') } } else { requestParam.boundary = "nearby(" + result.latitude + "," + result.longitude + "," + distance + "," + auto_extend + ")"; if (options.sig) { requestParam.sig = Utils.getSig(requestParam, options.sig, 'search') } } wx.request(Utils.buildWxRequestConfig(options, { url: URL_SEARCH, data: requestParam }, 'search')) }; Utils.locationProcess(options, locationsuccess) }; getSuggestion(options) { var that = this; options = options || {}; Utils.polyfillParam(options); if (!Utils.checkKeyword(options)) { return } var requestParam = { keyword: options.keyword, region: options.region || '全国', region_fix: options.region_fix || 0, policy: options.policy || 0, page_size: options.page_size || 10, page_index: options.page_index || 1, get_subpois: options.get_subpois || 0, output: 'json', key: that.key }; if (options.address_format) { requestParam.address_format = options.address_format } if (options.filter) { requestParam.filter = options.filter } if (options.location) { var locationsuccess = function (result) { requestParam.location = result.latitude + ',' + result.longitude; if (options.sig) { requestParam.sig = Utils.getSig(requestParam, options.sig, 'suggest') } wx.request(Utils.buildWxRequestConfig(options, { url: URL_SUGGESTION, data: requestParam }, "suggest")) }; Utils.locationProcess(options, locationsuccess) } else { if (options.sig) { requestParam.sig = Utils.getSig(requestParam, options.sig, 'suggest') } wx.request(Utils.buildWxRequestConfig(options, { url: URL_SUGGESTION, data: requestParam }, "suggest")) } }; reverseGeocoder(options) { var that = this; options = options || {}; Utils.polyfillParam(options); var requestParam = { coord_type: options.coord_type || 5, get_poi: options.get_poi || 0, output: 'json', key: that.key }; if (options.poi_options) { requestParam.poi_options = options.poi_options } var locationsuccess = function (result) { requestParam.location = result.latitude + ',' + result.longitude; if (options.sig) { requestParam.sig = Utils.getSig(requestParam, options.sig, 'reverseGeocoder') } wx.request(Utils.buildWxRequestConfig(options, { url: URL_GET_GEOCODER, data: requestParam }, 'reverseGeocoder')) }; Utils.locationProcess(options, locationsuccess) }; geocoder(options) { var that = this; options = options || {}; Utils.polyfillParam(options); if (Utils.checkParamKeyEmpty(options, 'address')) { return } var requestParam = { address: options.address, output: 'json', key: that.key }; if (options.region) { requestParam.region = options.region } if (options.sig) { requestParam.sig = Utils.getSig(requestParam, options.sig, 'geocoder') } wx.request(Utils.buildWxRequestConfig(options, { url: URL_GET_GEOCODER, data: requestParam }, 'geocoder')) }; getCityList(options) { var that = this; options = options || {}; Utils.polyfillParam(options); var requestParam = { output: 'json', key: that.key }; if (options.sig) { requestParam.sig = Utils.getSig(requestParam, options.sig, 'getCityList') } wx.request(Utils.buildWxRequestConfig(options, { url: URL_CITY_LIST, data: requestParam }, 'getCityList')) }; getDistrictByCityId(options) { var that = this; options = options || {}; Utils.polyfillParam(options); if (Utils.checkParamKeyEmpty(options, 'id')) { return } var requestParam = { id: options.id || '', output: 'json', key: that.key }; if (options.sig) { requestParam.sig = Utils.getSig(requestParam, options.sig, 'getDistrictByCityId') } wx.request(Utils.buildWxRequestConfig(options, { url: URL_AREA_LIST, data: requestParam }, 'getDistrictByCityId')) }; calculateDistance(options) { var that = this; options = options || {}; Utils.polyfillParam(options); if (Utils.checkParamKeyEmpty(options, 'to')) { return } var requestParam = { mode: options.mode || 'walking', to: Utils.location2query(options.to), output: 'json', key: that.key }; if (options.from) { options.location = options.from } if (requestParam.mode == 'straight') { var locationsuccess = function (result) { var locationTo = Utils.getEndLocation(requestParam.to); var data = { message: "query ok", result: { elements: [] }, status: 0 }; for (var i = 0; i < locationTo.length; i++) { data.result.elements.push({ distance: Utils.getDistance(result.latitude, result.longitude, locationTo[i].lat, locationTo[i].lng), duration: 0, from: { lat: result.latitude, lng: result.longitude }, to: { lat: locationTo[i].lat, lng: locationTo[i].lng } }) } var calculateResult = data.result.elements; var distanceResult = []; for (var i = 0; i < calculateResult.length; i++) { distanceResult.push(calculateResult[i].distance) } return options.success(data, { calculateResult: calculateResult, distanceResult: distanceResult }) }; Utils.locationProcess(options, locationsuccess) } else { var locationsuccess = function (result) { requestParam.from = result.latitude + ',' + result.longitude; if (options.sig) { requestParam.sig = Utils.getSig(requestParam, options.sig, 'calculateDistance') } wx.request(Utils.buildWxRequestConfig(options, { url: URL_DISTANCE, data: requestParam }, 'calculateDistance')) }; Utils.locationProcess(options, locationsuccess) } }; direction(options) { var that = this; options = options || {}; Utils.polyfillParam(options); if (Utils.checkParamKeyEmpty(options, 'to')) { return } var requestParam = { output: 'json', key: that.key }; if (typeof options.to == 'string') { requestParam.to = options.to } else { requestParam.to = options.to.latitude + ',' + options.to.longitude } var SET_URL_DIRECTION = null; options.mode = options.mode || MODE.driving; SET_URL_DIRECTION = URL_DIRECTION + options.mode; if (options.from) { options.location = options.from } if (options.mode == MODE.driving) { if (options.from_poi) { requestParam.from_poi = options.from_poi } if (options.heading) { requestParam.heading = options.heading } if (options.speed) { requestParam.speed = options.speed } if (options.accuracy) { requestParam.accuracy = options.accuracy } if (options.road_type) { requestParam.road_type = options.road_type } if (options.to_poi) { requestParam.to_poi = options.to_poi } if (options.from_track) { requestParam.from_track = options.from_track } if (options.waypoints) { requestParam.waypoints = options.waypoints } if (options.policy) { requestParam.policy = options.policy } if (options.plate_number) { requestParam.plate_number = options.plate_number } } if (options.mode == MODE.transit) { if (options.departure_time) { requestParam.departure_time = options.departure_time } if (options.policy) { requestParam.policy = options.policy } } var locationsuccess = function (result) { requestParam.from = result.latitude + ',' + result.longitude; if (options.sig) { requestParam.sig = Utils.getSig(requestParam, options.sig, 'direction', options.mode) } wx.request(Utils.buildWxRequestConfig(options, { url: SET_URL_DIRECTION, data: requestParam }, 'direction')) }; Utils.locationProcess(options, locationsuccess) } }; module.exports = QQMapWX;
--------------------------------------------------------------------------------