资讯专栏INFORMATION COLUMN

写一个小程序菜鸟裹裹吧

dinfer / 2510人阅读

摘要:最近双十一过后,每天不是拿快递就是去拿快递的路上,翻开手机应用里的菜鸟裹裹查看快递是很方便的,当我在微信端搜索菜鸟裹裹小程序时,却没有发现,于是便想自己动手仿版写一个菜鸟裹裹的小程序,对其中的快递查询物流跟踪很有兴趣。

新手写小程序并不简单,这是我的第一次尝试学习到了很多。最近双十一过后,每天不是拿快递就是去拿快递的路上,翻开手机应用里的菜鸟裹裹查看快递是很方便的,当我在微信端搜索菜鸟裹裹小程序时,却没有发现,于是便想自己动手仿app版写一个菜鸟裹裹的小程序,对其中的快递查询物流跟踪很有兴趣。 项目预览图

项目效果预览

项目目录结构


使用的开发工具 VScode和微信开发者工具

平台提供:微信公众品台|小程序,在该品台注册账号获取AppId,使用AppId登入微信开发者工具,开启项目

使用的API文档: 微信小程序开发文档,

微信小程序开发教程手册文档_w3c详细介绍了微信各种工具的使用
Vant Weapp,提供了好多实用性的组件,我项目中搜索框使用了该组件库的搜索组件
weUI微信团队的基础样式库,

使用的接口: 快递鸟 接口 提供快递单号和公司编码可以查询快递的物流信息。

腾讯地图开放品台提供了关于使用地图,地图显示,标注/多边形绘制,路线显示这些功能的实现。

## 页面解构

如下图,总共四个页面

第一个主要页面



  
   
  
  
    
      
        
      
      扫一扫
    
    
      
        
      
      快递员上门
    
    
      
        
      
      精灵书屋
    
    
      
        
      
      领裹酱
    
  
  
    
      
    
  
  
    进行中
    
  
  


    
      

      {{item.text1}}
      
      
        {{item.text2}}
        {{item.text3}}
        {{item.text4}}
      
      
    
//最后一个广告项
    

     有一个神秘包裹想你飞来
      
      
        已放入裹裹自提柜
        菜鸟裹裹
        神秘包裹已送至裹裹自提柜
      
    
    
    
     

查看全部
  
  

第二个页面写起来很简单


  
    
      取消
    
    
      
      {{company}}
    
    
      
    
    
      保存到包裹列表
      
    
    
      查询
    
  
  
    
      {{historyOrder}}
      
        {{item.code}}
        {{item.company}}
        
      
      {{delectHistory}}
      
    
  

第三个主要页面


  
    
    
  
  
    
      
        {{item}}
      
    
    
      {{item.number}}
      
        
        {{item.text}}
        
          
        
      
    
  

第四个主要页面


  
    
      
        
        
        已签收
      
      
        
          
          物流客服
        
        
          
          物流投诉
        
        
          
        
      
    
  
  
    
      
      
        评价驿站 东华理工大学南区七栋菜鸟驿站
        
          
          
            
            
            
            
            
          
        
        
          {{company}}  {{code}}
          
        
      
      
        
          
          
            
          
          
            
            【收货地址】江西省南昌市青山湖区 蛟桥镇 东华理工大学广兰大道广兰校区
          
        
        
          {{time1}}
          
            
          
          
            已签收
            您已在东华理工大学南区七栋菜鸟驿站完成取件,感谢使用菜鸟驿站,期待再次为您服务。
            我要退货
            联系卖家
            查看订单
          
        
        
          {{time2}}
          
            
          
          
            待取件
            您已在东华理工大学南区七栋菜鸟驿站完成取件,感谢使用菜鸟驿站,期待再次为您服务。
          
        
        
          {{time3}}
          
            
          
          
            派送中
            {{text3}}
          
        
        
          {{time3}}
          
            
          
          
            运输中
            {{text3}}
          
        
        
          {{item.AcceptTime}}
          
            
          
          
            
            {{item.AcceptStation}}
          
        
        
          {{time3}}
          
            
          
          
            已揽件
            
          
        
      
    
  



这个页面的功能是实现查询已签收的快递的物流状态,而且签收地固定了一下还有其他状态比如运输中,未发货,快递单号过期。为了把这个效果展现出来。这里没有写其他的页面。
第一个数据detail-data 收 需要获取用户的收货地址
第二个数据 detail-data 已签收可以送请求的数据中获取使用

数据来源

easy-mock+小程序云开发数据库使用

easy-mock可以实现高效伪造数据 easy-mock
在上面注册后可以创建一个接口,编辑接口可以添加数据, 可以获取接口的url,然后通过小程序的wx.request(url)获取在easy-mock里的数据,本例使用easy-mock构建了首页中expressLists的数据

{
"data": {
 expressList: [{
     image: "https://636c-cloud-912718-1257892962.tcb.qcloud.la/images2/yy.jpg?sign=b28732bd498113a8c88cfa634121a363&t=1542776282",
     text1: "【送历年真题】,朱伟老师推荐!新东方201...",
     text2: "签收时间:10-29 21:01",
     text3: "百世快递:71220099817129",
     text4: "北京北京市--江西南昌",
     contentId: "001",
   },
   {
     image: "https://636c-cloud-912718-1257892962.tcb.qcloud.la/images2/lq.jpg?sign=82cc4a8eca681accf06dd4737f2422cc&t=1542776323",
     text1: "淘宝|运动护具篮球护指套艾弗森库...",
     text2: "签收时间:11-10 12:20",
     text3: "圆通快递:802511355217367857",
     text4: "广州广州市--江西南昌",
     contentId: "002",
   },
   {
     image: "https://636c-cloud-912718-1257892962.tcb.qcloud.la/images2/css.jpg?sign=324ebd7e4e3203b2071cb7e0f24a0d2e&t=1542776355",
     text1: "天猫|CSS世界web前端开发CSS3+...",
     text2: "签收时间:10-17 17:11",
     text3: "圆通快递:802022497906214489",
     text4: "河南省新乡市--江西南昌",
     contentId: "003",
   },
   {
     image: "https://636c-cloud-912718-1257892962.tcb.qcloud.la/images2/js.jpg?sign=d07ef9708724b5d20595923a16964fa8&t=1542776376",
     text1: "淘宝|二手包邮 你不知道的javaScri...",
     text2: "签收时间:09-21 17:13",
     text3: "韵达快递:3956570250807",
     text4: "河南洛阳--江西南昌",
     contentId: "004",
   }
 ]
}
}

小程序云开发数据库使用

companyes:选择快递公司页面对应的快递公司图片标志,快递公司名字,和喜欢收藏icon图片

expresses:每一个快递单号对应的信息,这里通过接口获取数据后添加到数据库中,同时把快递单号作为每一个记录的一个字段,后面可以通过单号直接查询,重复单号不添加,无效单号也不添加进云数据库。

getExpresses:这是代取件里面的数据集合,

云数据库存储
这里把项目的图片资源存储在了小程序的云数据库上,新建文件将名字为images点击上传可以把本地图片上传到存储中


利用云数据库提供的图片地址可以实现本地图片url书写。

使用小程序云开发品台里的数据库,存储管理,既不用占用本地资源,也方便请求和修改。

云开发为开发者提供完整的云端支持,不用操心后端的管理,同时也不需要很麻去构建服务器,直接使用小程序提供的云函数的API文档和对小程序数据库操作的相关API即可实现数据的增删改操作,比mysql数据库操作更简单方便,这样就可以可实现快速上线和迭代,同时这一能力,同开发者已经使用的云服务相互兼容,并不互斥。

接口使用

整个查询快递的流程预览

快递鸟接口

首先注册一个快递鸟账号,选择订购物流查询免费版应用,期间需要上传身份证,还需要填写技术人员信息,通通写自己就好了,申请成功后,可以得到自己的API key和用户ID



查询快递的js代码
这里需要先选择快递公司,在selectCompany页面选择,选择完成返回到查询订单号sarch页面


*
选择后在selectCompany页面的js代码里保存选择的快递公司代码。即companyname在搜索框中填入要搜索的快递单号信息,用exp保存
即可获得使用接口的两个参数。这样就得到了使用接口的两个参数,详情看快递鸟即时查询api接口的使用

下面是具体的请求参数

需要对请求的数据中的Datasign部分做以下处理

使用工具包util里的MD5函数进行加密运算
(util.md5(RequestData + "eb016c6c-ab32-47b2-be8c-8fddf3f59c1e"))

需要把请求的数据进行encodeURI()编码,该函数可把字符串作为 URl 进行编码。

使用util工具包中的Base64编码算法对请求数据编码成base64格式

Base64是当今比较流行的编码方法,因为它编起来速度快而且简单

好处: base64特别适合在http,协议下快速传输数据。

最后把数据内容签名进行encodeURI编码,请求数据准备好了

请求的地址,数据,请求头的格式都在下面代码里给出,这里不需要多说

var util = require("../../utils/util.js")
const db = wx.cloud.database()
const expresses = db.collection("expresses")
const app = getApp()
getExpressInfo:function(nu,cb){
    //查物流
    //快递公司和,快递单号
   let companyname=wx.getStorageSync("codename")||"YTO";
    let company = wx.getStorageSync("company") || "圆通快递";
   console.log(companyname);
     let exp=nu.currentTarget.dataset.name
    var logistics = [companyname,exp];//保存在一个数组中
    this.setData({
      ShipperCode:logistics[0],
      LogisticCode:logistics[1]

    })
    //数据内容
    var RequestData = "{"OrderCode":"","ShipperCode":"" + logistics[0] + "","LogisticCode":"" + logistics[1] + ""}"
    //utf-8编码的数据内容
    // OrderCode    String    订单编号    O
    // ShipperCode    String    快递公司编码    R
    // LogisticCode    String    物流单号
    console.log(RequestData)
    var RequestDatautf = encodeURI(RequestData)
    console.log("RequestDatautf:" + RequestDatautf) //签名
    console.log(RequestData + "eb016c6c-ab32-47b2-be8c-8fddf3f59c1e")
    var DataSign = encodeURI(util.Base64((util.md5(RequestData + "eb016c6c-ab32-47b2-be8c-8fddf3f59c1e"))))
    console.log("DataSign:" + DataSign)
    if (logistics != null&&exp>999) {
      wx.request({
        url: "https://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspx",
        data: {
          //数据内容(进行过url编码)
          "RequestData": RequestDatautf,
          //电商ID
          "EBusinessID": "1399017",
          //请求指令类型:1002
          "RequestType": "1002",
          //数据内容签名把(请求内容(未编码)+ApiKey)进行MD5加密,然后Base64编码,最后进行URL(utf-8)编码
          "DataSign": DataSign,
          //请求、返回数据类型: 2-json;
          "DataType": "2",
        },
        header: {
          "content-type": "application/json"
        },
        success:(res)=> {
          console.log(res)
          let list = wx.getStorageSync("historys")||[];
          var item = {
            company: company,
            code: logistics[1]
          }
          if (list==null||list.length=== 0||list.every(res => {  return res.code!==logistics[1] })) {
           list.push(item);
          }
          wx.setStorage({
            key: "historys",
            data: list,
          })
          this.setData({
            historyList: list
          })
          this.setData({
            delectHistory: "清楚历史记录",
            historyOrder: "历史记录"
          })
          // this.setData({ mydata: res.data})
          expresses.where({
            code:exp
          }).count().then(res3=>{
            if (res3.total == 0){
              expresses.add({
                data: {
                  message: res.data,
                  code: exp
                }
              })
            } else {
              // wx.showToast({
              //   // title: "不能重复加"
              // })
            }
          })
         .then(res2 => {
           if(res.data.State>1) {
             wx.navigateTo({
               url: "../Todetail/index",
             })
           }
           wx.setStorage({
             key: "code",
             data: exp,
           }),
             wx.setStorage({
               key: "nowcompany",
               data: logistics[0],
             })
            
          })
        }
      })
    }
  },

数据请求成功以后打印出res.data

成功后做以下操作
全是小程序MVVM的思想的体现

M -Model数据 模型

V -view 页面 视图

VM -ViewModel数据绑定到界面上 视图模型层->模板{{}}

显示在历史记录中.为了防止第一次从storage中取不到键为historys的历史记录,这样子写比较好let list = wx.getStorageSync("historys")||[];,如果数组list为空或者已经不存在正在查询的快递单号,则添加 ,反之则不添加,存储this.setData({historyList: list})页面重新渲染显示

把当前快递单号对应的快递信息存储到云数据库上

跳转到物流详情页面,显示。

腾讯地图接口使用

最终效果见下图


Todetil页面

但是在手机端确总有个bug,样式里写了z-index表示元素的堆叠顺序,在手机端只出现地图,不过这只是一个效果。腾讯地图的接口需要在腾讯地图开放品台注册申请,使用API获取当前地址经纬度信息,利用逆地址查询获取当前 位置,这里只是获取地图作为背景图片。可以看下我的源码在github上面

这个页面的逻辑就是获取快递单号和公司代码,这里有四种情况两种界面效果,未查询到显示一种界面效果,这个很简单效果都一样,从首页查询到,搜索查询到,历史记录点击查询到显示另外一个界面状态,这种属于殊途同归,都是在onLoad函数中获取.

 onLoad(options) {
    let company = wx.getStorageSync("company");
    this.setData({
      company
    })
    let codeExpress=options.contentId
    // console.log(codeExpress);
    this.getLocation()
    if(!codeExpress){
      let code = wx.getStorageSync("code")
      console.log(code);
      this.setData({
        code,
      })
    }else{
      var  Navcode = codeExpress.substr(5);
      let company=codeExpress.substr(0,4);
      console.log(company);
      this.setData({
        code:Navcode,
        company:company
      })
      console.log(Navcode);
    }
    let code=this.data.code;
   
    expresses.where({
      code:code
    }).get().then(res=>{
      this.setData({
      tracesList:res.data,
      Traces:res.data[0].message.Traces
      })
      console.log(res.data);
      let Traces=this.data.Traces;
       this.showdetail();
       this.packageData(Traces);
    })
  
  },
组件使用

这里使用来对话框组件, 点击清楚历史记录,触发对话框。

点击对话框确定,全部清楚历史记录

点击对话框取消,隐藏对话框,不清楚历史记录

组件Components使用首先在index.json中引入

{
     "wxc-dialog": "/components/dialog/dialog"
}

对应search.wxml中使用的代码

在search.wxml中引入components中的dialog组件 dialog

{{delectHistory}}
     
 

组建的js是这样写的

onGotUserInfo(e) {
      this.triggerEvent("confirm", e)
      //向外传递
    }

组件中的确定按钮调用组件自身的onGotUserInfo方法

点击确定,触发search.js页面的bindconfirm="delectHistory"事件,清除历史记录并回显页面

页面可以向组件传递props数据,让组件在页面显示

组件可以负责与页面调用部分的通信。
请求封装的优化

在util包中封装 ,使用promise 返回promise对象,可以then操作
通用性的对wx.request封装

const $get = (url, data = {}) => {
  //发送请求
  return new Promise((resolve, reject) => {
    wx.request({
      url: url,
      data: data,
      method: "GET", // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
      // header: {}, // 设置请求的 header
      success: function (res) {
        resolve(res)
      },
      fail: function () {
        reject()
      },
      complete: function () {
      }
    })
  })
}
module.exports = {
  $get,
}

首页中请求easy-mock中的数据就是使用了util类中对request的封装,可以实现多次调用,重复调用,实现了代码的复用性。 getList()函数用于获取数据

getList(type) {
    this.setData({
    isLoading: true,
      hasMore: true
    })
    type === "down" ? this.setData({ page: 0 }) : null;
    util.$get("https://www.easy-mock.com/mock/5bca919de6742c1bf8220b50/example/express#!method=get", ).then(res => {
      if (res.statusCode == 200) {
        this.processData(type, res.data.data.expressList)
      }
    }).catch(e => {
      this.setData({
        isLoading: true,
        hasMore: false
      })
      wx.stopPullDownRefresh()
      wx.showToast({ title: `网络错误!`, duration: 1000, icon: "none" })
    })
 
  },

当页面请求数据到两页后,出现查看全部点击跳转到另外一个页面


查看全部这个text的 出现

是onReachBottom()这个函数在起作用,每次到达页面底部,检查此时page的值,小于3,上拉刷新,负责停止刷新,把样式改为bottomshow 在模型层就是把bottomshow的值改为true

查看全部
onReachBottom() {
    if (!this.data.isLoading) { // 防止数据还没回来再次触发加载
      return;
    }
    if(this.data.page<=3){
      this.getList("up")

    }else{
      wx.stopPullDownRefresh()
      this.setData({
        bottomshow:true

      })
    }
样式hide对用代码
    .hide{
    display: none;
   }
toView巧妙使用

效果预览

selectCompany.wxml,这里外层循环了companyList列表,先输出右边的侧边栏A-Z,再输出列表项的大写字母A,B,C...,和该项的内层循环,内层循环了每一个大写字母对应了以该大写字母开头的公司列表,scroll-view 每一项动态设置id="{{item.number}}" 设置scroll-into-view="{{toView}}"

当点击侧边栏的A,B,C,D...Z时,触发bindtap="switchTab"设置相对应的toView

这里有比较奇怪的一点,就是I字母没有以该字母出现的公司列表,原版菜鸟裹裹点击后回到A,我想用户要么不会去点击 ,要么点击邻近的不小心点错了。可以点击I时 ,scroll-into-view到附近的去 给switchTab新增一个判断条件 搞定。

switchTab(e){
 if (e.currentTarget.dataset.id=="I"){
      this.setData({
        curIndex: e.currentTarget.dataset.index,
        toView: "F",
      })

    }
    console.log(e);
    this.setData({
      curIndex:e.currentTarget.dataset.index,
      toView: e.currentTarget.dataset.id,
    })
  },

整个scroll-view代码

 
    
      
        {{item}}
      
    
    
      {{item.number}}
      
        
        {{item.text}}
        
          
        
      
    
  

回显到上个页面 选择某一行时点击触发 bindtap="backwithData"

wx.navigatBack()改变上个页面中的数据,存储公司标志,公司文本,公司代码Storage,上个页面获取数据显示。代码如下

var pages = getCurrentPages();
    var Page = pages[pages.length - 1];//当前页
    var prevPage = pages[pages.length - 2];  //上一个页面
    var info = prevPage.data //取上页data里的数据也可以修改
    prevPage.setData({ src,company })//设置数据
    wx.navigateBack({
      
    })

云函数使用,
这里使用了云函数,查询数据库集合的符合条件的列表项并删除,云函数确实较高的权限,直接对云数据库进行修改,云控制台的权限同管理端,拥有所有权限,
但是数云函数有点不太好的就是每次修改都要上传部署。后面项目更新会继续使用云函数解决问题。

这里只写了主要的常用的快递物流查询,如下图,
对于后面获取的数据的处理,因为获取的是倒叙的数据,我先用packageData()处理一下,把页面需要的单个数据或者列表整理出来,存储显示。

结语

总结一下就是用快递公司名字查找对应的编码,快递单号从用户输入或首页点击事件获得,然后请求查询,最后一个页面是显示的结果,还有路径标注任务没有完成,由于项目工程较大,只做了主要的一部分吧,关于组件封装,方法调用还有,效果展示应该会有更多激动人心的效果,项目就玩到这吧,再慢慢学习,慢慢补充。

感谢各位读者的阅读,文章中如有错误或不妥之处,请不吝赐教。

你的赞与肯定将会成为我代码之路上的一缕阳光,使我更加勇敢坚定的往前走。


项目地址奉上

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/53379.html

相关文章

  • 一个程序菜鸟裹吧

    摘要:最近双十一过后,每天不是拿快递就是去拿快递的路上,翻开手机应用里的菜鸟裹裹查看快递是很方便的,当我在微信端搜索菜鸟裹裹小程序时,却没有发现,于是便想自己动手仿版写一个菜鸟裹裹的小程序,对其中的快递查询物流跟踪很有兴趣。 新手写小程序并不简单,这是我的第一次尝试学习到了很多。最近双十一过后,每天不是拿快递就是去拿快递的路上,翻开手机应用里的菜鸟裹裹查看快递是很方便的,当我在微信端搜索菜鸟...

    NikoManiac 评论0 收藏0
  • 一个程序菜鸟裹吧

    摘要:最近双十一过后,每天不是拿快递就是去拿快递的路上,翻开手机应用里的菜鸟裹裹查看快递是很方便的,当我在微信端搜索菜鸟裹裹小程序时,却没有发现,于是便想自己动手仿版写一个菜鸟裹裹的小程序,对其中的快递查询物流跟踪很有兴趣。 新手写小程序并不简单,这是我的第一次尝试学习到了很多。最近双十一过后,每天不是拿快递就是去拿快递的路上,翻开手机应用里的菜鸟裹裹查看快递是很方便的,当我在微信端搜索菜鸟...

    Michael_Lin 评论0 收藏0
  • 一个菜鸟裹裹程序

    摘要:最近双十一过后,每天不是拿快递就是去拿快递的路上,翻开手机应用里的菜鸟裹裹查看快递是很方便的,当我在微信端搜索菜鸟裹裹小程序时,却没有发现,于是便想自己动手仿版写一个菜鸟裹裹的小程序,对其中的快递查询物流跟踪很有兴趣。 showImg(https://segmentfault.com/img/bVbkk77); 新手写小程序并不简单,这是我的第一次尝试学习到了很多。最近双十一过后,每天...

    dreamans 评论0 收藏0
  • 一个菜鸟裹裹程序

    摘要:最近双十一过后,每天不是拿快递就是去拿快递的路上,翻开手机应用里的菜鸟裹裹查看快递是很方便的,当我在微信端搜索菜鸟裹裹小程序时,却没有发现,于是便想自己动手仿版写一个菜鸟裹裹的小程序,对其中的快递查询物流跟踪很有兴趣。 新手写小程序并不简单,这是我的第一次尝试学习到了很多。最近双十一过后,每天不是拿快递就是去拿快递的路上,翻开手机应用里的菜鸟裹裹查看快递是很方便的,当我在微信端搜索菜鸟...

    evin2016 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<