Skip to content
On this page

wx公众号开发实战(JD/PDD系统):nodejs + mysql + koa2 + 阿里云部署

本课程通过开发wx公众号PDD系统。nodejs环境下使用koa-router开发后台接口、koa-view服务端渲染页面、mysql2开发mysql数据库最后部署到阿里云服务器。

课程中使用到的技术栈有: nodejs + koa2 + nginx服务器https后台部署 + mysql数据库等

第一课 课程介绍

一、课程背景

1、公众号实战开发系列课程中没有涉及到mysql的内容,对服务端渲染只是简单介绍没有开发比较完整的前端页面(如果大家对公众的基本开发还不熟悉的话可以先去学习前面的课程)

2、大家有学习的需求:

  • 大部分同学没有都是用的个人号申请,没有认证公众号

  • 新增JD/PDD的功能

  • 支持不能用户查询自己的订单

3、有部分童鞋只想要公众号源码部署使用。

我们后面会出一个开箱即用的源码部署的视频

二、项目演示

三、课程能学到什么?

1、获得一套可以直接上线运营的公众号找券系统

2、nodejs对接mysql数据库(用户数据入库、定时任务订单数据入库)

3、koa中间件使用:koa-static静态资源管理、koa-view和ejs实现服务端渲染、koa-router开发后台接口

4、使用weui开发前端页面(订单页面)

5、PDD/JD推广的相关知识

四、如何获取课程资料

1、wx公众号波波科技网络工作室 回复 学习

2、wx小程序波波科技网络工作室客服小哥哥索取学习资料

3、VX:bobokeji521

第二课 安装mysql

mysql数据库、MySQL Workbench安装,数据库的建库建表基本操作

一、进入mysql官网下载对应系统的mysql版本

1、进入官网地址MySQL :: Download MySQL Community Server,选择自己电脑对于的系统和架构安装包

2、如果不知道自己电脑系统架构的话可以在终端输入uname -a查看

3、如果安装是报如下的错误,需要配置一下安装校验规则

系统偏好设置->安全性与隐私->通用->点击通用页面左下角锁的图标->点击通用页面下方的被拒绝的安装应用后的“仍要打开”即可

4、安装过程中的数据库验证配置一定要选择use legacy password encryption

5、给root用户设置密码,这个密码一定要记住后面我们需要用到

6、打开系统偏好设置点击mysql图标,显示链接打开正常说明安装成功

二、下载mysql官方的数据库可视化操作工具MySQL Workbench

进入官网下载地址选择自己的操作系统版本,下载安装即可

三、链接数据库

1、打开第一步下载好的mysql

2、打开第二步下载的MySQL Workbench->点击新增数据库链接按钮填好对应的配置

3、点击新建好的链接,输入安装数据库时的root用户的密码,点击ok按钮后进入mysql可视化操作界面

四、数据库的基本操作

1、按照以下步骤新建数据库

2、按照以下步骤新一个数据库表

第三课 nodejs操作mysql数据库

使用nodejs的第三方库mysql2操作数据库,实现数据库的增删改查

一、安装mysql2模块

javascript
npm install mysql2 -S

二、代码中引入mysql2模块,使用mysql2的链接池连接数据库

点击这里查看index.js源码
javascript
// get the client
const mysql = require('mysql2');

// Create the connection pool. The pool-specific settings are the defaults
const pool = mysql.createPool({
  host: 'localhost',
  port: '3306',
  user: 'root',
  password: "ShenXiaoBo@520",
  database: 'bobokeji01'
});

const poolPromise = pool.promise()

// 查询/删除数据库
const queryData = async(sql)=>{
  let res = await poolPromise.execute(sql)
  return res[0]
}
exports.queryData = queryData

let sql = "delete from user where user_id = '2'" // 删除数据
let sqlquery = "select * from user " // 删除数据

// 新增数据
const insertData = async (tableName, keys, values)=>{
  let sql = `insert into ${tableName} (${keys.join(',')}) values ${values.join(',')}`
  let res = await poolPromise.execute(sql)
  return res[0]
}
exports.insertData = insertData

// 更新数据
const updateData = async(tableName, keys, values, wheresql) => {
  let tempArray = []
  keys.forEach(element => {
    tempArray.push(`${element}=?`)
  });
  let sql = `update ${tableName} set ${tempArray.join(',')} where ${wheresql}`
  let res = await poolPromise.execute(sql, values)
  return res[0]
}
exports.updateData = updateData

// queryData(sqlquery)
// let keys = ['user_name', "user_age"]
// let values = ["('bobokeji03', 20)", "('bobokeji04', 21)"]
// insertData('user', keys, values)
// updateData('user', ['user_name', 'user_age'], ['bobokeji004', 16], 'user_id=5')

第四/五/六课 mysql数据库记录wx用户的openId

使用封装的mysql数据库的操作方法,记录wx公众号用户的openId

一、JD操作设计逻辑

二、user表中记录用户wxopenId

1、数据库新建user表结构

2、调用查询和新增数据库的方法保存数据用户的openId

javascript
// createUser.js
const { queryData, insertData } = require("../../dataBase/index")

const createUser = async (wechatOpenId) => {
  if(!wechatOpenId) return
  // 查询user表中用户是否存在
  let querySql = `select * from users where wechat_uid='${wechatOpenId}'`
  let res = await queryData(querySql)
  // 如果不存在则新增用户
  if(res.length === 0){
    let result = await insertData("users", ["wechat_uid"], [`('${wechatOpenId}')`])
    console.log('result===>', result)
  }
}

exports.createUser = createUser

第七课 调用JD接口实现JD

注册JD联盟账号配置JD接口权限,调用大淘客接口实现JD的功能

一、JD接口权限配置

1、注册JD联盟账号,进入JD联盟官网,使用JD账号登录;

2、进入页面,如果有引导注册,按页面提示完成;

3、点击页面右上角账户管理;

4、找到左上角联盟ID,即为JD联盟账户ID

5、新增JD推广位,进入我的推广--推广位管理--创建推广位--选择导购媒体推广

6、新增好推广位后可以就可以查看自己推广为的PID了

7、进入授权管理中心 - 大淘客联盟dataoke.com,进入JD联盟授权,点击新增授权,填写第4步获取的JD联盟的ID

8、新增JD授权后,点击新增PID, 填入第六步获取到的PID, PID备注可以随便填写

二、调用JD解析接口获取JD商品信息

大淘客api开发平台 ---> 进入JD接口文档

第八/九/十/十一课 调用JD解析接口获取JD商品信息

一、获取JD商品信息和转链接步骤

mysqljs操作mysql数据库获取JD商品转链、promise.all并发请求多个接口拼装JD商品详情消息

1、调用JD链接解析接口获取商品的ID

2、调用JD联盟搜索接口获取商品详细信息

3、调用JD商品转链接口将商品转换成自己的推广链接

二、JD商品源码

点击这里查看index.js源码
javascript
// 代码
const dtkSdk = require('dtk-nodejs-api-sdk');
const { commconfig } = require('../../utils/commconfig');
const { queryData } = require('../../dataBase')
/*
 *  @checkSign: 1 默认老版本验签  2 新版验签
 *  @appKey: 用户填写 appkey
 *  @appSecret: 用户填写 appSecret
 */ 

const sdk = new dtkSdk({appKey:commconfig.appKey,appSecret:commconfig.appSecret,checkSign:2});
const goodInformation = {
  goodName: '',
  coupon: '',
  afterPrice: 0,
  returnMoney: 0,
  goodUrl: ''
}

// 1、调用`JD链接解析`接口获取商品的ID
const getGoodID = async(url)=>{
  let goodID = '' 
  let res = await sdk.request('https://openapi.dataoke.com/api/dels/jd/kit/parseUrl',{
    method:"GET",
    form:{url, version:"v1.0.0"}
  })
  if(res.code === 0 && res.data){
    goodID = res.data.skuId
  }
  return goodID
}

// 2、调用`JD联盟搜索`接口获取商品详细信息
const getGoodInfor = async(url) => {
  let skuIds = await getGoodID(url)
  console.log('skuIds==>', skuIds)
  let res = await sdk.request('https://openapi.dataoke.com/api/dels/jd/goods/search',{
    method:"GET",
    form:{skuIds, version:"v1.0.0"}
  })
  if(res.code === 0 && res.data){
    const temp = res.data.list[0]
    goodInformation.goodName = temp.skuName;
    goodInformation.afterPrice = temp.lowestCouponPrice;
    goodInformation.returnMoney = temp.couponCommission;
    goodInformation.coupon = Math.ceil(temp.lowestPrice - temp.lowestCouponPrice)
  }
}

// 3、调用`JD商品转链`接口将商品转换成自己的推广链接
const getSelfUrl = async (materialId, positionId)=>{
  let sql = `select * from user where wechat_uid = '${positionId}'`
  let result = await queryData(sql)
  let userId = 0
  if(result.length > 0){
    userId = result[0].user_id
  }
  let res = await sdk.request('https://openapi.dataoke.com/api/dels/jd/kit/promotion-union-convert',{
    method:"GET",
    form:{ unionId:commconfig.unionId, materialId, positionId:userId, version:"v1.0.0"}
  })
  if(res.code === 0 && res.data){
    goodInformation.goodUrl = res.data.shortUrl
  }
}

const getGoodInorAndUrl = async (url, wechatId) => {
  await Promise.all([getGoodInfor(url), getSelfUrl(url, wechatId)])
  console.log('goodInformation===>', goodInformation)
}

exports.getGoodInorAndUrl = getGoodInorAndUrl




let url = `【JD】【京喜】树花晓秀口腔清洁牙膏
🌻牙膏中含有进口的蜂胶成分🌟能够有效的去除牙齿上的牙菌斑🌙让你的口腔更加的健康🌹它的质地非常的温和✨即使是敏感肌也可以放心使用🍀
———————
拼购价: ¥159.60
券后拼购价: ¥79.60

领券抢购: https://u.jd.com/5CjYUvE 73.00%`

// getGoodInfor(url)
// getSelfUrl(url, 'oF-RA6fbdaY0mXnMW5lzgWVlpOXM')

getGoodInorAndUrl(url, 'oF-RA6fbdaY0mXnMW5lzgWVlpOXM')

第十二/三/四课 正则表达式解析公众号文本消息区分JD消息

一、正则表达式解析公众号文本消息区分JD消息

二、sendMsg源码

点击这里查看index.js源码
javascript
const { getGoodsInforandUrl } = require('../controller/JDpromotion/getJDgoodsUrl')
const { getTaoBaoPro } = require('../utils/getTaoBaoProduct')

const sendMsg = async (xmlJson)=>{
  // 调用JD接口查询
  let JDrepx = /(\bjd\.com\b)/g
  let isJDtest = JDrepx.test(xmlJson.Content)
  console.log('isJDtest==>', isJDtest)
  if(isJDtest){
    // 提取字符串中的网址
    const reg = /(https?|http):\/\/[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]/g;
    const strValue = xmlJson.Content.match(reg)[0];
    let JdRes = await getGoodsInforandUrl(strValue, xmlJson.FromUserName)
    let JdformateProductInfo = ''
    if(JdRes.returnMoney !== 0){
      let tempName = JdRes.goodName.slice(0, 11) + '...'
      JdformateProductInfo = `商品名称:${tempName}\n优惠券:${JdRes.coupon}\n券后价格:${JdRes.afterPrice}\n额外:${JdRes.returnMoney}\n----------------\n<a href="${JdRes.goodUrl}">点击领券下单</a>`
    }else{
      JdformateProductInfo = '亲,该商家无活动哦!'
    }
    xmlJson.type = 'text'
    xmlJson.content = JdformateProductInfo
  }else{
    // 查询TB官方接口,返回商品和优惠券详情逻辑
    let taobaoPro = await getTaoBaoPro(xmlJson.Content)
    let formateProductInfo = ''
    if(taobaoPro.couponInfo !== 0 || taobaoPro.returnMoney){
      formateProductInfo = `优惠券:${taobaoPro.couponInfo}\n券后价格:${taobaoPro.price}\n额外:${taobaoPro.returnMoney}\n----------------\n${taobaoPro.longTpwd}`
    }else{
      formateProductInfo = '亲,该商家无活动哦!'
    }
    xmlJson.type = 'text'
    xmlJson.content = formateProductInfo
  }
  return xmlJson
}

exports.sendMsg = sendMsg

第十五/六课 weui实现订单页面的开发

weui实现订单页面的开发,页面引入weui的库,使用koa-static实现,js/css代码的动静分离, 使用weui的preview组件,编写代码逻辑

一、页面引入weui的库

weui展示官网weui代码仓库giteeweui代码仓库github

https://res.wx.qq.com/open/libs/weui/2.0.1/weui.min.css

二、使用koa-static实现,js/css代码的动静分离

三、使用weui的preview组件,编写代码逻辑

  • html代码
点击这里查看html源码
javascript
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>JD订单列表</title>
  <link rel="stylesheet" href="https://res.wx.qq.com/open/libs/weui/2.0.1/weui.min.css">
  <link rel="stylesheet" href="/style/jdlist.css">
</head>
<body>
  <div class="page">
    <div class="page__hd">
      <h1 class="page__title">我的JD订单列表</h1>
      <p class="page__desc">订单预览</p>
    </div>
    <div id="nodata" style="display:block" class="weui-loadmore weui-loadmore_line">
      <span class="weui-loadmore__tips">暂无订单数据</span>
    </div>
    <div id="listWrap" class="page__bd">
    </div>
  </div>
  <div class="viewMore" style="visibility: visible;" onclick="viewMore()">查看更多订单...</div>
  <script src="/script/jdlist.js"></script>
</body>
</html>
  • css样式代码
点击这里查看css源码
javascript
// css
.weui-form-preview__hd .weui-form-preview__value{
  font-size: 1rem!important;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
#p4 .weui-form-preview__value{
  color: #c54841
}
#p3 .weui-form-preview__value{
  color: #bd3c34
}
.viewMore{
  display: flex;
  justify-content: center;
  align-items: center;
}
.page{
  overflow: auto;
  max-height: 96vh;
}
#mask{
  position:absolute;
  height: 100vh;
  width: 100vw;
  z-index: 1;
  background: rgba(0, 0, 0, .5);
  display: flex;
  justify-content: center;
  align-items: center;
  color: aliceblue;
}
#syncOrder{
  background: wheat;
  border: 1px solid #cccc;
}
  • js脚本代码
点击这里查看js源码
javascript
function viewMore() {
  // 第一步,请求后台接口,获取订单列表
  var jdlist = [
    {
      goodName: "菜鸟课程",
      orderPrice: 1,
      returnPercent: 70,
      getMoney: 20,
      orderStatus: "有效",
      orderDesc: "完成"
    },
    {
      goodName: "000波波科技课程121212121212121121sdfsfdsfdsfsfdsfsdf",
      orderPrice: 100,
      returnPercent: 80,
      getMoney: 90,
      orderStatus: "有效",
      orderDesc: "完成"
    }
  ]
  if(jdlist.length > 0){
    let nodataDom = document.getElementById("nodata")
    nodataDom.style.display = "none"

    // 第二步构造订单列表,并且渲染到页面中
    let pageDom = document.getElementById("listWrap")

    jdlist.forEach((item)=>{
      let divWrap = document.createElement("div")
      divWrap.innerHTML = `
        <div class="weui-form-preview">
          <div role="option" class="weui-form-preview__hd">
            <div class="weui-form-preview__item">
              <label class="weui-form-preview__label">商品名称:</label>
              <em class="weui-form-preview__value">${item.goodName}</em>
            </div>
          </div>
          <div role="option" aria-labelledby="p1 js_a11y_comma p2 js_a11y_comma p3" class="weui-form-preview__bd">
            <div id="p1" class="weui-form-preview__item">
              <label class="weui-form-preview__label">订单金额</label>
              <span class="weui-form-preview__value">¥${item.orderPrice}</span>
            </div>
            <div id="p2" class="weui-form-preview__item">
              <label class="weui-form-preview__label">比率</label>
              <span class="weui-form-preview__value">${item.returnPercent}%</span>
            </div>
            <div id="p3" class="weui-form-preview__item">
              <label class="weui-form-preview__label">预估收益</label>
              <span class="weui-form-preview__value">¥${item.getMoney}</span>
            </div>
            <div id="p3" class="weui-form-preview__item">
              <label class="weui-form-preview__label">订单状态(${item.orderStatus})</label>
              <span class="weui-form-preview__value">${item.orderDesc}</span>
            </div>
          </div>
        </div>
      `
      pageDom.appendChild(divWrap)
    })
  }else{
    let viewMoreDom = document.getElementsByClassName("viewMore")
    viewMoreDom[0].style.display = "none"
  }
}
viewMore()

第十七/八课 node-schedule模块实现定时任务拉取JD商品订单信息

使用node-schedule、moment中间件实现定时拉去订单列表

一、新建订单列表jd_goods_list 、同步时间表sync_flag

二、查询订单数据并且更新到mysql数据库

  • syncJdOrderList.js源码
点击这里查看源码
javascript
/**
 * 同步JD订单到数据库
 */ 
const { apiRequest } = require("../../utils/dataokeSdkRequest")
const { commconfig } = require("../../utils/commconfig")
const { insertData, updateData, queryData } = require("../../dataBase/index.js")

// 获取JD订单数据
const getJdOrderList = async(startTime, endTime) => {
  let orderlistUrl = 'https://openapi.dataoke.com/api/dels/jd/order/get-official-order-list'
  let params = {
    type: 3, // 订单时间查询类型 1:下单时间,2:完成时间(购买用户确认收货时间),3:更新时间
    key: commconfig.JDKEY, // JD联盟授权key
    startTime: startTime, // 开始时间 格式yyyy-MM-dd HH:mm:ss,与endTime间隔不超过1小时
    endTime: endTime // 结束时间 格式yyyy-MM-dd HH:mm:ss,与startTime间隔不超过1小时
  }
  let goodListRes = await apiRequest(orderlistUrl, params)
  let jdGoodList = []
  let orderIds = []
  let orderIdMap = {}
  if(goodListRes.code === 0 && goodListRes.data.length>0){
    jdGoodList = goodListRes.data.map((item) => {
      orderIds.push(item.orderId)
      orderIdMap[item.orderId] = item
      return {
        price: item.price,
        skuName: item.skuName,
        skuNum: item.skuNum,
        finalRate: item.finalRate,
        commissionRate: item.commissionRate,
        actualFee: item.actualFee,
        actualCosPrice: item.actualCosPrice,
        estimateFee: item.estimateFee,
        orderId: item.orderId,
        validCode: item.validCode,
        orderTime: item.orderTime,
        finishTime: item.finishTime,
        positionId: item.positionId,
        subUnionId: item.subUnionId,
        estimateCosPrice: item.estimateCosPrice
      }
    })
  }
  return { jdGoodList, orderIds, orderIdMap }
}

// 将最新的订单数据插入表中jd_goods_list
const insertJDlist = async(startTime, endTime) => {
  // 获取最近5分钟订单数据
  let { jdGoodList, orderIds, orderIdMap } = await getJdOrderList(startTime, endTime)
  console.log('jdGoodList==>', jdGoodList)
  let insertRes = ''
  if(orderIds.length > 0){
    // 1、根据订单id查询表中已存在的订单数据
    let querySql = `select orderId,estimateCosPrice,actualCosPrice,actualFee,estimateFee,validCode,finishTime from jd_goods_list where orderId in (${orderIds.join(",")})`
    let queryDataRes = await queryData(querySql)

    // 2、更新表中已有的订单数据
    let filterOrderIds = [] //需要过滤的订单id
    let updateKeys = ["finishTime", "validCode", "estimateFee", "actualFee", "actualCosPrice", "estimateCosPrice"]
    queryDataRes.forEach( async element => {
      let uadateWhereSql = `orderId='${element.orderId}'`
      let upadateValues = [ 
        orderIdMap[element.orderId].finishTime, 
        orderIdMap[element.orderId].validCode, 
        orderIdMap[element.orderId].estimateFee, 
        orderIdMap[element.orderId].actualFee, 
        orderIdMap[element.orderId].actualCosPrice, 
        orderIdMap[element.orderId].estimateCosPrice
      ]
      filterOrderIds.push(element.orderId)
      let updateTableRes = await updateData('jd_goods_list', updateKeys, upadateValues, uadateWhereSql)
    });

    // 3、过滤掉已经更新的数据
    let afterFileterData = jdGoodList.filter(item => {
      return !filterOrderIds.includes(item.orderId)
    })

    console.log('afterFileterData==>', afterFileterData)
    if(afterFileterData.length > 0){
      // 4、将数据插入表中
      let tableKeys = [
        "price",'skuName','skuNum','finalRate','commissionRate','estimateFee','actualFee',
        'actualCosPrice','orderId','validCode','orderTime','finishTime','subUnionId', 'positionId','estimateCosPrice'
      ]
      insertRes = await insertData('jd_goods_list', tableKeys, afterFileterData)
    }
  }
  return insertRes
}

exports.insertJDlist = insertJDlist

// insertJDlist('2022-11-22 13:02:00', '2022-11-22 13:04:00')
  • dataokeSdkRequest.js源码
点击这里查看源码
javascript
const dtkSdk = require('dtk-nodejs-api-sdk');
const { commconfig } = require('./commconfig');
const sdk = new dtkSdk({appKey:commconfig.appKey, appSecret:commconfig.appSecret, checkSign:2});

const apiRequest = async (url, parms) => {
  let selUrlDetail = await sdk.request(url,{
    method:"GET",
    form:{ version: 'v1.0.0', ...parms }
  })
  return selUrlDetail
}

exports.apiRequest = apiRequest
  • index.js源码
点击这里查看源码
javascript
// get the client
const mysql = require('mysql2');

// Create the connection pool. The pool-specific settings are the defaults
const pool = mysql.createPool({
  host: 'localhost',
  port: '3306',
  user: 'root',
  password: "ShenXiaoBo@520",
  database: 'bobokeji01'
});

const poolPromise = pool.promise()

// 查询/删除数据库
const queryData = async(sql)=>{
  let res = await poolPromise.execute(sql)
  return res[0]
}
exports.queryData = queryData


const insertTable = async (tableName, fieds, Values) => {
  let fiedsString = ''
  let valuestrings = []

  Values.forEach(re => {
    let tempArray = []
    fieds.forEach(item => {
      tempArray.push(`'${re[item]}'`)
    })
    valuestrings.push(`(${tempArray.join(',')})`)
  });
  let sql = `insert into ${tableName}(${fieds.join(',')}) values${valuestrings.join(',')}`
  try{
    const res = await poolPromise.execute(sql)
    return 'insert success'
  }catch(err){
    throw new Error(err)
  }
}
exports.insertData = insertTable

// 更新数据
const updateData = async(tableName, keys, values, wheresql) => {
  let tempArray = []
  keys.forEach(element => {
    tempArray.push(`${element}=?`)
  });
  let sql = `update ${tableName} set ${tempArray.join(',')} where ${wheresql}`
  let res = await poolPromise.execute(sql, values)
  return res[0]
}
exports.updateData = updateData
// let sql = "delete from jd_goods_list where price = 2099" // 删除数据
// let sqlquery = "select * from user " // 查询数据
// queryData(sql)
// let keys = ['wechat_uid', "user_nickname"]
// let values = ["('bobokeji012345', 20456)", "('bobokeji0467890', 200)"]
// insertData('user', keys, values)
// updateData('user', ['wechat_uid', 'user_nickname'], ['test', 16], 'user_id=1')

第十九/二十课 开发JD订单查询接口

使用koa-router开发订单查询接口、使用redis缓存用户数据提高查询效率

一、使用redis缓存用户数据提高查询效率

redis官网、[redis的nodejs库](redis - npm (npmjs.com))

  • 安装redis模块

  • 封装redis新增和查询脚本redis.js

点击这里查看源码
javascript
// redis.js脚本

const { createClient } = require('redis');

const client = createClient();
client.on('error', err => console.log('Redis Client Error', err));

const getRedisValue = async (key)=>{
  await client.connect();
  let value = await client.get(key);
  await client.disconnect();
  return value
}
exports.getRedisValue = getRedisValue

const setRedisValues = async (keyValues) => {
  await client.connect();
  keyValues.forEach(async item => {
    await client.set(Object.keys(item)[0], Object.values(item)[0]);
  })
  await client.disconnect();
}
exports.setRedisValues = setRedisValues

const setRedisValue = async (key, value) => {
  await client.connect();
  await client.set(key, value);
  await client.disconnect();
}
exports.setRedisValue = setRedisValue

二、jd_goods_list表新增俩个字段user_id、account_name

  • 新增用户时同步把用户的数据存到redis

  • 定时任务jd订单入库时查询redis对应的用户信息存入订单表

点击这里查看源码
javascript
// createUser.js 脚本源码

const {queryData, insertData} = require('../../dataBase/index')
const { setRedisValue } = require("../../dataBase/redis")

const createUser = async (openId, accountName) =>{
  if(!openId) return;
  // 查询user表中是否保存用户的openId
  let querySql = `select * from user where wechat_uid='${openId}'`
  let result = await queryData(querySql)
  console.log('result===>', result)
  // 新增用户
  if(result.length === 0){
    let insertRes = await insertData('user',['wechat_uid','account_name'],[{ wechat_uid:openId, account_name:accountName }])
    await setRedisValue(`${insertRes}`, `${openId},${accountName}`)
  }
}
exports.createUser = createUser
点击这里查看源码
javascript
// syncJdOrderList.js 脚本源码
/**
 * 同步JD订单到数据库
 */ 
const { apiRequest } = require("../../utils/dataokeSdkRequest")
const { commconfig } = require("../../utils/commconfig")
const { insertData, updateData, queryData } = require("../../dataBase/index.js")
const { getRedisValue, setRedisValue } = require("../../dataBase/redis")

// 获取JD订单数据
const getJdOrderList = async(startTime, endTime) => {
  let orderlistUrl = 'https://openapi.dataoke.com/api/dels/jd/order/get-official-order-list'
  let params = {
    type: 3, // 订单时间查询类型 1:下单时间,2:完成时间(购买用户确认收货时间),3:更新时间
    key: commconfig.JDKEY, // JD联盟授权key
    startTime: startTime, // 开始时间 格式yyyy-MM-dd HH:mm:ss,与endTime间隔不超过1小时
    endTime: endTime // 结束时间 格式yyyy-MM-dd HH:mm:ss,与startTime间隔不超过1小时
  }
  let goodListRes = await apiRequest(orderlistUrl, params)
  let jdGoodList = []
  let orderIds = []
  let orderIdMap = {}
  if(goodListRes.code === 0 && goodListRes.data.length>0){
    jdGoodList = await Promise.all(goodListRes.data.map(async(item) => {
      orderIds.push(item.orderId)
      orderIdMap[item.orderId] = item
      let personMap = await getPersonFromRedis(item.positionId)
      return {
        price: item.price,
        skuName: item.skuName,
        skuNum: item.skuNum,
        finalRate: item.finalRate,
        commissionRate: item.commissionRate,
        actualFee: item.actualFee,
        actualCosPrice: item.actualCosPrice,
        estimateFee: item.estimateFee,
        orderId: item.orderId,
        validCode: item.validCode,
        orderTime: item.orderTime,
        finishTime: item.finishTime,
        positionId: item.positionId,
        subUnionId: item.subUnionId,
        estimateCosPrice: item.estimateCosPrice,
        wechat_uid: personMap.wechat_uid,
        account_name: personMap.account_name
      }
    }))
  }
  return { jdGoodList, orderIds, orderIdMap }
}

// 将最新的订单数据插入表中jd_goods_list
const insertJDlist = async(startTime, endTime) => {
  // 获取最近5分钟订单数据
  let { jdGoodList, orderIds, orderIdMap } = await getJdOrderList(startTime, endTime)
  console.log('jdGoodList==>', jdGoodList)
  let insertRes = ''
  if(orderIds.length > 0){
    // 1、根据订单id查询表中已存在的订单数据
    let querySql = `select orderId,estimateCosPrice,actualCosPrice,actualFee,estimateFee,validCode,finishTime from jd_goods_list where orderId in (${orderIds.join(",")})`
    let queryDataRes = await queryData(querySql)

    // 2、更新表中已有的订单数据
    let filterOrderIds = [] //需要过滤的订单id
    let updateKeys = ["finishTime", "validCode", "estimateFee", "actualFee", "actualCosPrice", "estimateCosPrice"]
    queryDataRes.forEach( async element => {
      let uadateWhereSql = `orderId='${element.orderId}'`
      let upadateValues = [ 
        orderIdMap[element.orderId].finishTime, 
        orderIdMap[element.orderId].validCode, 
        orderIdMap[element.orderId].estimateFee, 
        orderIdMap[element.orderId].actualFee, 
        orderIdMap[element.orderId].actualCosPrice, 
        orderIdMap[element.orderId].estimateCosPrice
      ]
      filterOrderIds.push(element.orderId)
      let updateTableRes = await updateData('jd_goods_list', updateKeys, upadateValues, uadateWhereSql)
    });

    // 3、过滤掉已经更新的数据
    let afterFileterData = jdGoodList.filter(item => {
      let ordId = item.orderId.toString()
      return !filterOrderIds.includes(ordId)
    })
    console.log('afterFileterData==>', afterFileterData)
    if(afterFileterData.length > 0){
      // 4、将数据插入表中
      let tableKeys = [
        "price",'skuName','skuNum','finalRate','commissionRate','estimateFee','actualFee',
        'actualCosPrice','orderId','validCode','orderTime','finishTime','subUnionId', 'positionId',
        'estimateCosPrice','wechat_uid','account_name'
      ]
      insertRes = await insertData('jd_goods_list', tableKeys, afterFileterData)
    }
  }
  return insertRes
}
exports.insertJDlist = insertJDlist

const getPersonFromRedis = async(key)=>{
  let userMap = {
    wechat_uid: "",
    account_name: ""
  }
  let keyString = key.toString()
  let userInfo = await getRedisValue(keyString)
  if(userInfo){ // 从redis里取用户的信息
    userMap.wechat_uid = userInfo.split(',')[0]
    userMap.account_name = userInfo.split(',')[1]
  }else{ // 如果redis里没有,则从mysql里获取用户信息,并存入redis下次便可以直接从redis获取数据
    let querySql = `select * from user where user_id='${key}'`
    let result = await queryData(querySql)
    if(result.length > 0){
      let userRes = [result[0].wechat_uid,result[0].account_name]
      userMap.wechat_uid = result[0].wechat_uid
      userMap.account_name = result[0].account_name
      setRedisValue(keyString, userRes.join(',')) // 这里用异步处理,提高效率
    }
  }
  console.log('userMap===>', userMap)
  return userMap
}

// insertJDlist("2023-02-26 19:04:00","2023-02-26 19:06:00")

三、接口设计

  • 需要的入参,pageNum、pageSize、weUid(用户不同用户查询自己的订单)

四、使用koa-router开发jd订单列表查询接口

点击这里查看源码
javascript
// getJdOrderList.js 源码

const Router = require('koa-router')
const router = new Router()
const { commconfig } = require('../../utils/commconfig')
const { queryData } = require('../../dataBase/index')

router.post('/get', async (ctx, next) => {
  let requestParam = ctx.request.body
  let weuid = requestParam.weichatUid || ''
  console.log("requestParam===>", requestParam.weichatUid)
  let jDlistRes = []
  let responseCode = 0
  // 根据userId获取JD订单数据
  let whereSql = `where wechat_uid='${weuid}'`
  let jdSql = `select * from jd_goods_list ${whereSql} order by record_id desc limit ${requestParam.pageNum},${requestParam.pageSize} `
  // 判断是否为超级管理员,超级管理员可以查看所有订单
  let isSuperManager = commconfig.superManagerIds[weuid]
  if(isSuperManager){
    jdSql = `select * from jd_goods_list where account_name='${isSuperManager}' order by record_id desc limit ${requestParam.pageNum},${requestParam.pageSize}`
  }
  console.log("jdSql===>", jdSql)
  jDlistRes = await queryData(jdSql)
  ctx.body = {
    code: responseCode,
    jdList: jDlistRes
  }
  next()
})
module.exports = router

五、订单查询页面调用订单订单查询接口展示用户订单

  • 页面引入了第三方请求库axios.js

  • 获取链接中的weuid、发送用户消息时查看订单链接拼接好用户的weuid

  • 实现页面翻页、loading、无数据等样式逻辑

点击这里查看源码
javascript
// axiox.js 源码

/* axios v0.27.2 | (c) 2022 by Matt Zabriskie */
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.axios=t():e.axios=t()}(this,(function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=13)}([function(e,t,n){"use strict";var r,o=n(4),i=Object.prototype.toString,s=(r=Object.create(null),function(e){var t=i.call(e);return r[t]||(r[t]=t.slice(8,-1).toLowerCase())});function a(e){return e=e.toLowerCase(),function(t){return s(t)===e}}function u(e){return Array.isArray(e)}function c(e){return void 0===e}var f=a("ArrayBuffer");function l(e){return null!==e&&"object"==typeof e}function p(e){if("object"!==s(e))return!1;var t=Object.getPrototypeOf(e);return null===t||t===Object.prototype}var d=a("Date"),h=a("File"),m=a("Blob"),v=a("FileList");function y(e){return"[object Function]"===i.call(e)}var g=a("URLSearchParams");function E(e,t){if(null!=e)if("object"!=typeof e&&(e=[e]),u(e))for(var n=0,r=e.length;n<r;n++)t.call(null,e[n],n,e);else for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&t.call(null,e[o],o,e)}var b,O=(b="undefined"!=typeof Uint8Array&&Object.getPrototypeOf(Uint8Array),function(e){return b&&e instanceof b});e.exports={isArray:u,isArrayBuffer:f,isBuffer:function(e){return null!==e&&!c(e)&&null!==e.constructor&&!c(e.constructor)&&"function"==typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)},isFormData:function(e){return e&&("function"==typeof FormData&&e instanceof FormData||"[object FormData]"===i.call(e)||y(e.toString)&&"[object FormData]"===e.toString())},isArrayBufferView:function(e){return"undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&f(e.buffer)},isString:function(e){return"string"==typeof e},isNumber:function(e){return"number"==typeof e},isObject:l,isPlainObject:p,isUndefined:c,isDate:d,isFile:h,isBlob:m,isFunction:y,isStream:function(e){return l(e)&&y(e.pipe)},isURLSearchParams:g,isStandardBrowserEnv:function(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product&&"NativeScript"!==navigator.product&&"NS"!==navigator.product)&&("undefined"!=typeof window&&"undefined"!=typeof document)},forEach:E,merge:function e(){var t={};function n(n,r){p(t[r])&&p(n)?t[r]=e(t[r],n):p(n)?t[r]=e({},n):u(n)?t[r]=n.slice():t[r]=n}for(var r=0,o=arguments.length;r<o;r++)E(arguments[r],n);return t},extend:function(e,t,n){return E(t,(function(t,r){e[r]=n&&"function"==typeof t?o(t,n):t})),e},trim:function(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")},stripBOM:function(e){return 65279===e.charCodeAt(0)&&(e=e.slice(1)),e},inherits:function(e,t,n,r){e.prototype=Object.create(t.prototype,r),e.prototype.constructor=e,n&&Object.assign(e.prototype,n)},toFlatObject:function(e,t,n){var r,o,i,s={};t=t||{};do{for(o=(r=Object.getOwnPropertyNames(e)).length;o-- >0;)s[i=r[o]]||(t[i]=e[i],s[i]=!0);e=Object.getPrototypeOf(e)}while(e&&(!n||n(e,t))&&e!==Object.prototype);return t},kindOf:s,kindOfTest:a,endsWith:function(e,t,n){e=String(e),(void 0===n||n>e.length)&&(n=e.length),n-=t.length;var r=e.indexOf(t,n);return-1!==r&&r===n},toArray:function(e){if(!e)return null;var t=e.length;if(c(t))return null;for(var n=new Array(t);t-- >0;)n[t]=e[t];return n},isTypedArray:O,isFileList:v}},function(e,t,n){"use strict";var r=n(0);function o(e,t,n,r,o){Error.call(this),this.message=e,this.name="AxiosError",t&&(this.code=t),n&&(this.config=n),r&&(this.request=r),o&&(this.response=o)}r.inherits(o,Error,{toJSON:function(){return{message:this.message,name:this.name,description:this.description,number:this.number,fileName:this.fileName,lineNumber:this.lineNumber,columnNumber:this.columnNumber,stack:this.stack,config:this.config,code:this.code,status:this.response&&this.response.status?this.response.status:null}}});var i=o.prototype,s={};["ERR_BAD_OPTION_VALUE","ERR_BAD_OPTION","ECONNABORTED","ETIMEDOUT","ERR_NETWORK","ERR_FR_TOO_MANY_REDIRECTS","ERR_DEPRECATED","ERR_BAD_RESPONSE","ERR_BAD_REQUEST","ERR_CANCELED"].forEach((function(e){s[e]={value:e}})),Object.defineProperties(o,s),Object.defineProperty(i,"isAxiosError",{value:!0}),o.from=function(e,t,n,s,a,u){var c=Object.create(i);return r.toFlatObject(e,c,(function(e){return e!==Error.prototype})),o.call(c,e.message,t,n,s,a),c.name=e.name,u&&Object.assign(c,u),c},e.exports=o},function(e,t,n){"use strict";var r=n(1);function o(e){r.call(this,null==e?"canceled":e,r.ERR_CANCELED),this.name="CanceledError"}n(0).inherits(o,r,{__CANCEL__:!0}),e.exports=o},function(e,t,n){"use strict";var r=n(0),o=n(19),i=n(1),s=n(6),a=n(7),u={"Content-Type":"application/x-www-form-urlencoded"};function c(e,t){!r.isUndefined(e)&&r.isUndefined(e["Content-Type"])&&(e["Content-Type"]=t)}var f,l={transitional:s,adapter:(("undefined"!=typeof XMLHttpRequest||"undefined"!=typeof process&&"[object process]"===Object.prototype.toString.call(process))&&(f=n(8)),f),transformRequest:[function(e,t){if(o(t,"Accept"),o(t,"Content-Type"),r.isFormData(e)||r.isArrayBuffer(e)||r.isBuffer(e)||r.isStream(e)||r.isFile(e)||r.isBlob(e))return e;if(r.isArrayBufferView(e))return e.buffer;if(r.isURLSearchParams(e))return c(t,"application/x-www-form-urlencoded;charset=utf-8"),e.toString();var n,i=r.isObject(e),s=t&&t["Content-Type"];if((n=r.isFileList(e))||i&&"multipart/form-data"===s){var u=this.env&&this.env.FormData;return a(n?{"files[]":e}:e,u&&new u)}return i||"application/json"===s?(c(t,"application/json"),function(e,t,n){if(r.isString(e))try{return(t||JSON.parse)(e),r.trim(e)}catch(e){if("SyntaxError"!==e.name)throw e}return(n||JSON.stringify)(e)}(e)):e}],transformResponse:[function(e){var t=this.transitional||l.transitional,n=t&&t.silentJSONParsing,o=t&&t.forcedJSONParsing,s=!n&&"json"===this.responseType;if(s||o&&r.isString(e)&&e.length)try{return JSON.parse(e)}catch(e){if(s){if("SyntaxError"===e.name)throw i.from(e,i.ERR_BAD_RESPONSE,this,null,this.response);throw e}}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,maxBodyLength:-1,env:{FormData:n(27)},validateStatus:function(e){return e>=200&&e<300},headers:{common:{Accept:"application/json, text/plain, */*"}}};r.forEach(["delete","get","head"],(function(e){l.headers[e]={}})),r.forEach(["post","put","patch"],(function(e){l.headers[e]=r.merge(u)})),e.exports=l},function(e,t,n){"use strict";e.exports=function(e,t){return function(){for(var n=new Array(arguments.length),r=0;r<n.length;r++)n[r]=arguments[r];return e.apply(t,n)}}},function(e,t,n){"use strict";var r=n(0);function o(e){return encodeURIComponent(e).replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}e.exports=function(e,t,n){if(!t)return e;var i;if(n)i=n(t);else if(r.isURLSearchParams(t))i=t.toString();else{var s=[];r.forEach(t,(function(e,t){null!=e&&(r.isArray(e)?t+="[]":e=[e],r.forEach(e,(function(e){r.isDate(e)?e=e.toISOString():r.isObject(e)&&(e=JSON.stringify(e)),s.push(o(t)+"="+o(e))})))})),i=s.join("&")}if(i){var a=e.indexOf("#");-1!==a&&(e=e.slice(0,a)),e+=(-1===e.indexOf("?")?"?":"&")+i}return e}},function(e,t,n){"use strict";e.exports={silentJSONParsing:!0,forcedJSONParsing:!0,clarifyTimeoutError:!1}},function(e,t,n){"use strict";var r=n(0);e.exports=function(e,t){t=t||new FormData;var n=[];function o(e){return null===e?"":r.isDate(e)?e.toISOString():r.isArrayBuffer(e)||r.isTypedArray(e)?"function"==typeof Blob?new Blob([e]):Buffer.from(e):e}return function e(i,s){if(r.isPlainObject(i)||r.isArray(i)){if(-1!==n.indexOf(i))throw Error("Circular reference detected in "+s);n.push(i),r.forEach(i,(function(n,i){if(!r.isUndefined(n)){var a,u=s?s+"."+i:i;if(n&&!s&&"object"==typeof n)if(r.endsWith(i,"{}"))n=JSON.stringify(n);else if(r.endsWith(i,"[]")&&(a=r.toArray(n)))return void a.forEach((function(e){!r.isUndefined(e)&&t.append(u,o(e))}));e(n,u)}})),n.pop()}else t.append(s,o(i))}(e),t}},function(e,t,n){"use strict";var r=n(0),o=n(20),i=n(21),s=n(5),a=n(9),u=n(24),c=n(25),f=n(6),l=n(1),p=n(2),d=n(26);e.exports=function(e){return new Promise((function(t,n){var h,m=e.data,v=e.headers,y=e.responseType;function g(){e.cancelToken&&e.cancelToken.unsubscribe(h),e.signal&&e.signal.removeEventListener("abort",h)}r.isFormData(m)&&r.isStandardBrowserEnv()&&delete v["Content-Type"];var E=new XMLHttpRequest;if(e.auth){var b=e.auth.username||"",O=e.auth.password?unescape(encodeURIComponent(e.auth.password)):"";v.Authorization="Basic "+btoa(b+":"+O)}var x=a(e.baseURL,e.url);function w(){if(E){var r="getAllResponseHeaders"in E?u(E.getAllResponseHeaders()):null,i={data:y&&"text"!==y&&"json"!==y?E.response:E.responseText,status:E.status,statusText:E.statusText,headers:r,config:e,request:E};o((function(e){t(e),g()}),(function(e){n(e),g()}),i),E=null}}if(E.open(e.method.toUpperCase(),s(x,e.params,e.paramsSerializer),!0),E.timeout=e.timeout,"onloadend"in E?E.onloadend=w:E.onreadystatechange=function(){E&&4===E.readyState&&(0!==E.status||E.responseURL&&0===E.responseURL.indexOf("file:"))&&setTimeout(w)},E.onabort=function(){E&&(n(new l("Request aborted",l.ECONNABORTED,e,E)),E=null)},E.onerror=function(){n(new l("Network Error",l.ERR_NETWORK,e,E,E)),E=null},E.ontimeout=function(){var t=e.timeout?"timeout of "+e.timeout+"ms exceeded":"timeout exceeded",r=e.transitional||f;e.timeoutErrorMessage&&(t=e.timeoutErrorMessage),n(new l(t,r.clarifyTimeoutError?l.ETIMEDOUT:l.ECONNABORTED,e,E)),E=null},r.isStandardBrowserEnv()){var R=(e.withCredentials||c(x))&&e.xsrfCookieName?i.read(e.xsrfCookieName):void 0;R&&(v[e.xsrfHeaderName]=R)}"setRequestHeader"in E&&r.forEach(v,(function(e,t){void 0===m&&"content-type"===t.toLowerCase()?delete v[t]:E.setRequestHeader(t,e)})),r.isUndefined(e.withCredentials)||(E.withCredentials=!!e.withCredentials),y&&"json"!==y&&(E.responseType=e.responseType),"function"==typeof e.onDownloadProgress&&E.addEventListener("progress",e.onDownloadProgress),"function"==typeof e.onUploadProgress&&E.upload&&E.upload.addEventListener("progress",e.onUploadProgress),(e.cancelToken||e.signal)&&(h=function(e){E&&(n(!e||e&&e.type?new p:e),E.abort(),E=null)},e.cancelToken&&e.cancelToken.subscribe(h),e.signal&&(e.signal.aborted?h():e.signal.addEventListener("abort",h))),m||(m=null);var S=d(x);S&&-1===["http","https","file"].indexOf(S)?n(new l("Unsupported protocol "+S+":",l.ERR_BAD_REQUEST,e)):E.send(m)}))}},function(e,t,n){"use strict";var r=n(22),o=n(23);e.exports=function(e,t){return e&&!r(t)?o(e,t):t}},function(e,t,n){"use strict";e.exports=function(e){return!(!e||!e.__CANCEL__)}},function(e,t,n){"use strict";var r=n(0);e.exports=function(e,t){t=t||{};var n={};function o(e,t){return r.isPlainObject(e)&&r.isPlainObject(t)?r.merge(e,t):r.isPlainObject(t)?r.merge({},t):r.isArray(t)?t.slice():t}function i(n){return r.isUndefined(t[n])?r.isUndefined(e[n])?void 0:o(void 0,e[n]):o(e[n],t[n])}function s(e){if(!r.isUndefined(t[e]))return o(void 0,t[e])}function a(n){return r.isUndefined(t[n])?r.isUndefined(e[n])?void 0:o(void 0,e[n]):o(void 0,t[n])}function u(n){return n in t?o(e[n],t[n]):n in e?o(void 0,e[n]):void 0}var c={url:s,method:s,data:s,baseURL:a,transformRequest:a,transformResponse:a,paramsSerializer:a,timeout:a,timeoutMessage:a,withCredentials:a,adapter:a,responseType:a,xsrfCookieName:a,xsrfHeaderName:a,onUploadProgress:a,onDownloadProgress:a,decompress:a,maxContentLength:a,maxBodyLength:a,beforeRedirect:a,transport:a,httpAgent:a,httpsAgent:a,cancelToken:a,socketPath:a,responseEncoding:a,validateStatus:u};return r.forEach(Object.keys(e).concat(Object.keys(t)),(function(e){var t=c[e]||i,o=t(e);r.isUndefined(o)&&t!==u||(n[e]=o)})),n}},function(e,t){e.exports={version:"0.27.2"}},function(e,t,n){e.exports=n(14)},function(e,t,n){"use strict";var r=n(0),o=n(4),i=n(15),s=n(11);var a=function e(t){var n=new i(t),a=o(i.prototype.request,n);return r.extend(a,i.prototype,n),r.extend(a,n),a.create=function(n){return e(s(t,n))},a}(n(3));a.Axios=i,a.CanceledError=n(2),a.CancelToken=n(29),a.isCancel=n(10),a.VERSION=n(12).version,a.toFormData=n(7),a.AxiosError=n(1),a.Cancel=a.CanceledError,a.all=function(e){return Promise.all(e)},a.spread=n(30),a.isAxiosError=n(31),e.exports=a,e.exports.default=a},function(e,t,n){"use strict";var r=n(0),o=n(5),i=n(16),s=n(17),a=n(11),u=n(9),c=n(28),f=c.validators;function l(e){this.defaults=e,this.interceptors={request:new i,response:new i}}l.prototype.request=function(e,t){"string"==typeof e?(t=t||{}).url=e:t=e||{},(t=a(this.defaults,t)).method?t.method=t.method.toLowerCase():this.defaults.method?t.method=this.defaults.method.toLowerCase():t.method="get";var n=t.transitional;void 0!==n&&c.assertOptions(n,{silentJSONParsing:f.transitional(f.boolean),forcedJSONParsing:f.transitional(f.boolean),clarifyTimeoutError:f.transitional(f.boolean)},!1);var r=[],o=!0;this.interceptors.request.forEach((function(e){"function"==typeof e.runWhen&&!1===e.runWhen(t)||(o=o&&e.synchronous,r.unshift(e.fulfilled,e.rejected))}));var i,u=[];if(this.interceptors.response.forEach((function(e){u.push(e.fulfilled,e.rejected)})),!o){var l=[s,void 0];for(Array.prototype.unshift.apply(l,r),l=l.concat(u),i=Promise.resolve(t);l.length;)i=i.then(l.shift(),l.shift());return i}for(var p=t;r.length;){var d=r.shift(),h=r.shift();try{p=d(p)}catch(e){h(e);break}}try{i=s(p)}catch(e){return Promise.reject(e)}for(;u.length;)i=i.then(u.shift(),u.shift());return i},l.prototype.getUri=function(e){e=a(this.defaults,e);var t=u(e.baseURL,e.url);return o(t,e.params,e.paramsSerializer)},r.forEach(["delete","get","head","options"],(function(e){l.prototype[e]=function(t,n){return this.request(a(n||{},{method:e,url:t,data:(n||{}).data}))}})),r.forEach(["post","put","patch"],(function(e){function t(t){return function(n,r,o){return this.request(a(o||{},{method:e,headers:t?{"Content-Type":"multipart/form-data"}:{},url:n,data:r}))}}l.prototype[e]=t(),l.prototype[e+"Form"]=t(!0)})),e.exports=l},function(e,t,n){"use strict";var r=n(0);function o(){this.handlers=[]}o.prototype.use=function(e,t,n){return this.handlers.push({fulfilled:e,rejected:t,synchronous:!!n&&n.synchronous,runWhen:n?n.runWhen:null}),this.handlers.length-1},o.prototype.eject=function(e){this.handlers[e]&&(this.handlers[e]=null)},o.prototype.forEach=function(e){r.forEach(this.handlers,(function(t){null!==t&&e(t)}))},e.exports=o},function(e,t,n){"use strict";var r=n(0),o=n(18),i=n(10),s=n(3),a=n(2);function u(e){if(e.cancelToken&&e.cancelToken.throwIfRequested(),e.signal&&e.signal.aborted)throw new a}e.exports=function(e){return u(e),e.headers=e.headers||{},e.data=o.call(e,e.data,e.headers,e.transformRequest),e.headers=r.merge(e.headers.common||{},e.headers[e.method]||{},e.headers),r.forEach(["delete","get","head","post","put","patch","common"],(function(t){delete e.headers[t]})),(e.adapter||s.adapter)(e).then((function(t){return u(e),t.data=o.call(e,t.data,t.headers,e.transformResponse),t}),(function(t){return i(t)||(u(e),t&&t.response&&(t.response.data=o.call(e,t.response.data,t.response.headers,e.transformResponse))),Promise.reject(t)}))}},function(e,t,n){"use strict";var r=n(0),o=n(3);e.exports=function(e,t,n){var i=this||o;return r.forEach(n,(function(n){e=n.call(i,e,t)})),e}},function(e,t,n){"use strict";var r=n(0);e.exports=function(e,t){r.forEach(e,(function(n,r){r!==t&&r.toUpperCase()===t.toUpperCase()&&(e[t]=n,delete e[r])}))}},function(e,t,n){"use strict";var r=n(1);e.exports=function(e,t,n){var o=n.config.validateStatus;n.status&&o&&!o(n.status)?t(new r("Request failed with status code "+n.status,[r.ERR_BAD_REQUEST,r.ERR_BAD_RESPONSE][Math.floor(n.status/100)-4],n.config,n.request,n)):e(n)}},function(e,t,n){"use strict";var r=n(0);e.exports=r.isStandardBrowserEnv()?{write:function(e,t,n,o,i,s){var a=[];a.push(e+"="+encodeURIComponent(t)),r.isNumber(n)&&a.push("expires="+new Date(n).toGMTString()),r.isString(o)&&a.push("path="+o),r.isString(i)&&a.push("domain="+i),!0===s&&a.push("secure"),document.cookie=a.join("; ")},read:function(e){var t=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return t?decodeURIComponent(t[3]):null},remove:function(e){this.write(e,"",Date.now()-864e5)}}:{write:function(){},read:function(){return null},remove:function(){}}},function(e,t,n){"use strict";e.exports=function(e){return/^([a-z][a-z\d+\-.]*:)?\/\//i.test(e)}},function(e,t,n){"use strict";e.exports=function(e,t){return t?e.replace(/\/+$/,"")+"/"+t.replace(/^\/+/,""):e}},function(e,t,n){"use strict";var r=n(0),o=["age","authorization","content-length","content-type","etag","expires","from","host","if-modified-since","if-unmodified-since","last-modified","location","max-forwards","proxy-authorization","referer","retry-after","user-agent"];e.exports=function(e){var t,n,i,s={};return e?(r.forEach(e.split("\n"),(function(e){if(i=e.indexOf(":"),t=r.trim(e.substr(0,i)).toLowerCase(),n=r.trim(e.substr(i+1)),t){if(s[t]&&o.indexOf(t)>=0)return;s[t]="set-cookie"===t?(s[t]?s[t]:[]).concat([n]):s[t]?s[t]+", "+n:n}})),s):s}},function(e,t,n){"use strict";var r=n(0);e.exports=r.isStandardBrowserEnv()?function(){var e,t=/(msie|trident)/i.test(navigator.userAgent),n=document.createElement("a");function o(e){var r=e;return t&&(n.setAttribute("href",r),r=n.href),n.setAttribute("href",r),{href:n.href,protocol:n.protocol?n.protocol.replace(/:$/,""):"",host:n.host,search:n.search?n.search.replace(/^\?/,""):"",hash:n.hash?n.hash.replace(/^#/,""):"",hostname:n.hostname,port:n.port,pathname:"/"===n.pathname.charAt(0)?n.pathname:"/"+n.pathname}}return e=o(window.location.href),function(t){var n=r.isString(t)?o(t):t;return n.protocol===e.protocol&&n.host===e.host}}():function(){return!0}},function(e,t,n){"use strict";e.exports=function(e){var t=/^([-+\w]{1,25})(:?\/\/|:)/.exec(e);return t&&t[1]||""}},function(e,t){e.exports=null},function(e,t,n){"use strict";var r=n(12).version,o=n(1),i={};["object","boolean","number","function","string","symbol"].forEach((function(e,t){i[e]=function(n){return typeof n===e||"a"+(t<1?"n ":" ")+e}}));var s={};i.transitional=function(e,t,n){function i(e,t){return"[Axios v"+r+"] Transitional option '"+e+"'"+t+(n?". "+n:"")}return function(n,r,a){if(!1===e)throw new o(i(r," has been removed"+(t?" in "+t:"")),o.ERR_DEPRECATED);return t&&!s[r]&&(s[r]=!0,console.warn(i(r," has been deprecated since v"+t+" and will be removed in the near future"))),!e||e(n,r,a)}},e.exports={assertOptions:function(e,t,n){if("object"!=typeof e)throw new o("options must be an object",o.ERR_BAD_OPTION_VALUE);for(var r=Object.keys(e),i=r.length;i-- >0;){var s=r[i],a=t[s];if(a){var u=e[s],c=void 0===u||a(u,s,e);if(!0!==c)throw new o("option "+s+" must be "+c,o.ERR_BAD_OPTION_VALUE)}else if(!0!==n)throw new o("Unknown option "+s,o.ERR_BAD_OPTION)}},validators:i}},function(e,t,n){"use strict";var r=n(2);function o(e){if("function"!=typeof e)throw new TypeError("executor must be a function.");var t;this.promise=new Promise((function(e){t=e}));var n=this;this.promise.then((function(e){if(n._listeners){var t,r=n._listeners.length;for(t=0;t<r;t++)n._listeners[t](e);n._listeners=null}})),this.promise.then=function(e){var t,r=new Promise((function(e){n.subscribe(e),t=e})).then(e);return r.cancel=function(){n.unsubscribe(t)},r},e((function(e){n.reason||(n.reason=new r(e),t(n.reason))}))}o.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},o.prototype.subscribe=function(e){this.reason?e(this.reason):this._listeners?this._listeners.push(e):this._listeners=[e]},o.prototype.unsubscribe=function(e){if(this._listeners){var t=this._listeners.indexOf(e);-1!==t&&this._listeners.splice(t,1)}},o.source=function(){var e;return{token:new o((function(t){e=t})),cancel:e}},e.exports=o},function(e,t,n){"use strict";e.exports=function(e){return function(t){return e.apply(null,t)}}},function(e,t,n){"use strict";var r=n(0);e.exports=function(e){return r.isObject(e)&&!0===e.isAxiosError}}])}));
//# sourceMappingURL=axios.min.map
点击这里查看源码
javascript
// jdList.js 源码


// 获取用户的openId
let searchParam = window.location.search
let wechatUid = searchParam.split('=')[1]

let pageNum = 0
let pageSize = 1
let loadingDom = document.getElementById('mask')
let nodataDom = document.getElementById('nodata')
let viewMoreDom = document.getElementById('viewMore')
function getJdlist(){
  loadingDom.style.display = " "
  // 请求用户JD订单数据
  let parmas = {
    pageNum,
    pageSize,
    weichatUid: wechatUid
  }
  // sku维度的有效码(-1:未知,2.无效-拆单,3.无效-取消,4.无效-JD帮帮主订单,5.无效-账号异常,6.无效-赠品类目不返佣,
  // 7.无效-校园订单,8.无效-企业订单,
  // 9.无效-团购订单,11.无效-乡村推广员下单,13.无效-违规订单,14.无效-来源与备案网址不符,15.待付款,16.已付款,17.已完成(购买用户确认收货),
  // 20.无效-此复购订单对应的首购订单无效,21.无效-云店订单
  const statusMap = {
    2:{
      status: "无效",
      desc: "拆单"
    },
    3:{
      status: "无效",
      desc: "取消"
    },
    4:{
      status: "无效",
      desc: "JD帮帮主订单"
    },
    5:{
      status: "无效",
      desc: "账号异常"
    },
    6:{
      status: "无效",
      desc: "赠品类目不返佣"
    },
    7:{
      status: "无效",
      desc: "校园订单"
    },
    8:{
      status: "无效",
      desc: "企业订单"
    },
    9:{
      status: "无效",
      desc: "团购订单"
    },
    11:{
      status: "无效",
      desc: "乡村推广员下单"
    },
    13:{
      status: "无效",
      desc: "违规订单"
    },
    14:{
      status: "无效",
      desc: "来源与备案网址不符"
    },
    15:{
      status: "有效",
      desc: "待付款"
    },
    16:{
      status: "有效",
      desc: "已付款"
    },
    17:{
      status: "有效",
      desc: "已完成"
    },
    20:{
      status: "无效",
      desc: "此复购订单对应的首购订单无效"
    },
    21:{
      status: "无效",
      desc: "云店订单"
    },
  }
  var jdlist = []
  axios.post('/jdOrderList/get', parmas).then(res => {
    if(res.data.code === 0){
      jdlist = res.data.jdList
      if(jdlist.length === 0){
        if(pageNum === 0){ // 页面第一次加载如果没有数据的话就显示无数据,隐藏加载更多按钮
          nodataDom.style.display = '';
        }
        alert("没有更多订单数据了")
        viewMoreDom.style.display = 'none'
      }
      // 拼装订单列表并且渲染到页面
      let JdlistWrapDom = document.getElementById("JdlistWrap")
      jdlist.forEach((item)=>{
        let divDom = document.createElement("div")
        divDom.innerHTML = `
          <div role="option" class="weui-form-preview__hd">
                  <div class="weui-form-preview__item">
                      <label class="weui-form-preview__label">商品名称</label>
                      <em class="weui-form-preview__value">${item.skuName}</em>
                  </div>
              </div>
              <div role="option" aria-labelledby="p1 js_a11y_comma p2 js_a11y_comma p3" class="weui-form-preview__bd">
                  <div id="p1" class="weui-form-preview__item">
                      <label class="weui-form-preview__label">订单金额</label>
                      <span class="weui-form-preview__value">¥${item.estimateCosPrice}</span>
                  </div>
                  <div id="p1" class="weui-form-preview__item">
                      <label class="weui-form-preview__label">比率</label>
                      <span class="weui-form-preview__value">${item.commissionRate}%</span>
                  </div>
                  <div id="p2" class="weui-form-preview__item">
                      <label class="weui-form-preview__label">预估收益</label>
                      <span class="weui-form-preview__value">¥${item.estimateFee}</span>
                  </div>
                  <div id="p3" class="weui-form-preview__item">
                      <label class="weui-form-preview__label">订单状态(${statusMap[item.validCode].status})</label>
                      <span class="weui-form-preview__value">${statusMap[item.validCode].desc}</span>
                  </div>
              </div>
        `
        JdlistWrapDom.appendChild(divDom)
      })
    }else if(res.data.code === 1){
      viewMoreDom.style.display = 'none'
      nodataDom.style.display = '';
      alert("当前用户不存在")
    }
    loadingDom.style.display = "none"
  })
  pageNum += pageSize
}
getJdlist()
点击这里查看源码
javascript
// jdList.html 源码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>JD订单</title>
  <link rel="stylesheet" href="https://res.wx.qq.com/open/libs/weui/2.0.1/weui.min.css"><link>
  <link rel="stylesheet" href="/style/jdlist.css">
</head>
<body>
  <div id="mask" style="display: none"><div>数据加载中...</div></div>
  <div class="page">
    <div class="page__hd">
      <h1 class="page__title">我的JD订单列表</h1>
      <p class="page__desc">订单预览</p>
      <div id="nodata" style="display: none" class="weui-loadmore weui-loadmore_line">
        <span class="weui-loadmore__tips">暂无订单数据</span>
      </div>
    </div>
    <div id="JdlistWrap" class="page__bd">
    </div>
    <div id='viewMore' class="viewMore" onclick="getJdlist()">查看更多订单...</div>
  </div>
  <script src="/javascript/axios.js"></script>
  <script src="/javascript/jdList.js"> </script>
</body>
</html>

第二十一课 源码部署到腾讯云上线运行

课程录制中....