mpvue小程序:网易严选后端 mpvue-shop-node

后端项目搭建:mpvue-shop-node

目录结构说明
controllers控制层
routes路由分发层
app.js入口文件
config.js项目配置文件
mysql.js数据库基础配置

新建后端项目:server

  • knex 查询构造器是用于构建和执行标准的SQL查询,例如:select, insert, update, delete
  • koa-bodyparser 用于解析前端发起post请求传递的数据对象

文档:https://blog.songxingguo.com/2018/06/30/knex.js-query/

cd server
npm init -y
npm i koa koa-router koa-bodyparser knex mysql -S

后端接收前端传递的数据方式:(重点)

// get请求,接收前端传递的数据:ctx.query.数据字段
const openId = ctx.query.openId

// post请求,接收前端传递的数据(对象):ctx.request.body
const {openId, keyword} = ctx.request.body

查询语句总结:(重点)

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>查询数据>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// 查询表中的所有数据
const channel = await mysql('nideshop_channel').select()

// 根据id查询表中的数据
const banner = await mysql('nideshop_ad').where({
ad_position_id: 1
}).select()

// 查询指定内容(根据id)
const newGoods = await mysql('nideshop_goods').whereIn('id', [1181000, 1135002, 1134030, 1134032]).andWhere('is_new', 1).select()

// 查询表中指定字段
const hotGoods = await mysql('nideshop_goods').column('id', 'name', 'list_pic_url', 'retail_price', 'goods_brief').where({
is_hot: 1
}).limit(5).select()


// 根据id查询表中的数据,升序,只显示4条数据
const brandList = await mysql('nideshop_brand').where({
is_new: 1
}).orderBy('new_sort_order', 'asc').limit(4).select()

// 模糊查询:用于获取用户输入的搜索关键字,显示带有关键字的搜索内容(限制10条)
const keywords = await mysql('nideshop_goods')
.column('id', 'name', 'list_pic_url', 'retail_price')
.where('name', 'like', '%' + keyword + '%').limit(10).select()

>>>>>>>>>>>>>>>>>>>>>>关联查询:表A存储值;表B存储键>>>>>>>>>>>>>>>
const attribute = await mysql('表A').column('表A.value', '表B.name').leftJoin('表B', '表A.attribute_id', '表B.id').where({
'表A.goods_id': 前端传入的查询参数goodsId
}).select()

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>插入数据>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// 向数据库表中,插入指定数据
const data = await mysql('nideshop_search_history').insert({
'user_id': openId,
'keyword': keyword,
'add_time': parseInt(new Date().getTime() / 1000)
})
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>删除数据>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// 根据用户标识 openId ,清除用户搜索历史记录
const data = await mysql('nideshop_search_history').where({
'user_id': openId
}).del()
console.log(data) // 显示删除的数据条数
if (data) {
ctx.body = {
'data': '清除成功'
}
} else {
ctx.body = {
'data': '清除失败'
}
}

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>更新数据>>>>>>>>>>>>>>>>>>>>>>>>>>
const data = await mysql('nideshop_order').where({
   'user_id': openId
 }).update({
   user_id: openId,
   goods_id: goodsId,
   allprice: allPrice
 })    
 

package.json文件

{
  "name": "mpvue-shop-node",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "knex": "^0.20.8",
    "koa": "^2.11.0",
    "koa-bodyparser": "^4.2.1",
    "koa-router": "^8.0.6",
    "mysql": "^2.18.1"
  },
  "devDependencies": {
    "nodemon": "^2.0.2"
  }
}

1. controllers 控制层

1-1:总布局 index.js

controllers / index.js(自动读取本地目录结构,获取文件绝对路径)

const _ = require('lodash')
const fs = require('fs')
const path = require('path')

// 映射 d 文件夹下的文件为模块

const mapDir = d => {
  const tree = {}

  // 获取当前文件夹下的所有文件夹和文件,分成两组,文件夹一组,文件一组
  const [dirs, files] = _(fs.readdirSync(d)).partition(p => fs.statSync(path.join(d, p)).isDirectory())
  // 映射文件夹
  dirs.forEach(dir => {
    tree[dir] = mapDir(path.join(d, dir))
  });
  // 映射文件
  files.forEach(file => {
    // 获取文件后缀名字
    if (path.extname(file) === '.js') {
      tree[path.basename(file, '.js')] = require(path.join(d, file))
    }
  })

  return tree
}

// 默认导出当前文件夹下的映射
module.exports = mapDir(path.join(__dirname))

1-2:收货地址 address/ index.js

收货地址相关的接口:controllers / address/ index.js

const { mysql } = require('../../mysql')

// 获取收货地址列表
async function getListAction(ctx) {

  // 第一步:接收前端传递的数据
  const openId = ctx.query.openId

  // 第二步:根据用户id 查询 `收货地址表`
  const addressList = await mysql('nideshop_address').where({
    'user_id': openId
  }).orderBy('is_default', 'desc').select()

  // 第三步:判断查询状态
  ctx.body = {
    data: addressList
  }
}

// 获取详细地址
async function detailAction(ctx) {
  const id = ctx.query.id
  const detailData = await mysql('nideshop_address').where({
    'id': id
  }).select()
  ctx.body = {
    data: detailData[0]
  }
}

// 添加或更新收货地址
async function saveAction(ctx) {

  // 第一步:获取前端传递的数据
  const addressId = ctx.request.body.addressId
  const { userName, telNumber, address, detailaddress, checked, openId } = ctx.request.body
  console.log(checked)

  // 第二步:如果是默认选中,首先在数据库中查询是否是默认地址(默认收货地址只能有一个)
  if (checked) {

    // 首先:查询数据库中此时默认的收货地址
    const isDefault = await mysql('nideshop_address').where({
      'user_id': openId,
      'is_default': 1
    }).select()

    // 然后:如果找到了这条数据,将其更改为普通收货地址
    if (isDefault.length > 0) {
      await mysql('nideshop_address').where({
        'user_id': openId,
        'is_default': 1
      }).update({
        'is_default': 0
      })
    }
  }

  // 收货地址不存在:说明用户新建收货地址 或者 一键导入收货地址 => 也就是要执行:添加收货地址
  if (!addressId) {
    // 添加地址
    const data = await mysql('nideshop_address').insert({
      name: userName,
      mobile: telNumber,
      address: address,
      address_detail: detailaddress,
      user_id: openId,
      is_default: checked == 'true' || checked ? 1 : 0
    })
    // 数据添加成功-失败
    if (data) {
      ctx.body = {
        data: true
      }
    } else {
      ctx.body = {
        data: false
      }
    }
  } else {
    // 收货地址存在:用户点击的是编辑收货地址
    // 第一步:执行更新收货地址
    const data = await mysql('nideshop_address').where({
      'id': addressId
    }).update({
      name: userName,
      mobile: telNumber,
      address: address,
      address_detail: detailaddress,
      user_id: openId,
      is_default: checked == 'true' || checked ? 1 : 0
    })
    if (data) {
      ctx.body = {
        data: true
      }
    } else {
      ctx.body = {
        data: false
      }
    }
  }
}

module.exports = {
  getListAction,
  detailAction,
  saveAction
}

1-3:购物车 cart / index.js

购物车相关的接口:controllers / cart / index.js

const { mysql } = require('../../mysql')

async function addCart(ctx) {

  // 接收前端传递的数据
  const { openId, goodsId, number } = ctx.request.body

  /**
   * 判断`购物车数据表`是否包含此数据
   * 当前商品是否已加入购物车:如果有只要增加具体的数量就可以了;如果没有执行商品加入购物车的操作
   */
  const haveGoods = await mysql('nideshop_cart').where({
    'user_id': openId,
    'goods_id': goodsId
  }).select()

  if (haveGoods.length === 0) {

    // 根据商品id从`商品信息表`中,查询:商品的价格、商品名称、商品图片 =>然后将商品信息加入`购物车数据表`中
    const goods = await mysql('nideshop_goods').where({
      'id': goodsId
    }).select()
    const { retail_price, name, list_pic_url } = goods[0]
    // 如果不存在,说明该商品没有加入购物车:将该商品加入购物车就可以了
    await mysql('nideshop_cart').insert({
      'user_id': openId,
      'goods_id': goodsId,
      number,
      'goods_name': name,
      retail_price,
      list_pic_url
    })
  } else {
    // 在`购物车表`中,能找到该商品。说明该商品已加入购物车 => 修改商品数量
    // 第一步:查询`购物车数据表`中,该商品的数量
    const oldNumber = await mysql('nideshop_cart').where({
      'user_id': openId,
      'goods_id': goodsId
    }).column('number').select()
    // 第二步:更新`购物车数据表`中的数据
    await mysql('nideshop_cart').where({
      'user_id': openId,
      'goods_id': goodsId
    }).update({
      'number': oldNumber[0].number + number
    })
  }
  // 商品加入购物车成功
  ctx.body = {
    data: 'success'
  }
}

// 获取购物车列表
async function cartList(ctx) {

  // 第一步:接收前端传递的数据
  const { openId } = ctx.query
  // 第二步:查询购物车表中的数据
  const cartList = await mysql('nideshop_cart').where({
    'user_id': openId
  }).select()
  ctx.body = {
    data: cartList
  }
}

module.exports = {
  addCart,
  cartList
}

1-3:商品分类 category / index.js

分类相关的接口:controllers / category / index.js

const { mysql } = require('../../mysql')

// 获取分类列表,导航栏
async function categoryNav(ctx) {

  // 第一步:获取前端传递的商品分类id
  const categoryId = ctx.query.id
  // 第二步:获取分类(这个商品id是由前端上一个页面传递的 => 然后进入商品分类页面)
  const currentNav = await mysql('nideshop_category').where({
    'id': categoryId
  }).select()
  // 第三步:获取它的同类(是指:在首页中点击居家 =>进入商品分类页面:此时商品分类页面也要显示居家的商品分类内容)
  const navData = await mysql('nideshop_category').where({
    'parent_id': currentNav[0].parent_id
  }).select()

  ctx.body = {
    navData,
    currentNav: currentNav[0]
  }
}

// 分类页面
async function indexAction(ctx) {

  // 第一步:
  const { id: categoryId } = ctx.query
  // 第一步:查找 parent_id 为0的数据,作为菜单分类数据(左侧数据)
  const data = await mysql('nideshop_category').where({
    'parent_id': 0
  }).select()
  // 第二步:
  const currentCategory = []
  if (categoryId) {
    currentCategory = await mysql('nideshop_category').where({
      'parent_id': categoryId
    }).select()
  }

  ctx.body = {
    'categoryList': data
  }
}

// 点击左侧菜单获取的分类商品
async function currentAction(ctx) {

  // 第一步:获取商品id
  const { id: categoryId } = ctx.query
  // 第二步:查询`分类表`
  const data =  {}
  const currentOne = await mysql('nideshop_category').where({
    'id': categoryId
  }).select()
  const subList = await mysql('nideshop_category').where({
    'parent_id': currentOne[0].id
  }).select()
  data.currentOne = currentOne[0]
  data.currentOne.subList = subList

  ctx.body = {
    'data': data
  }
}

module.exports = {
  categoryNav,
  indexAction,
  currentAction
}

1-4:收藏 collect / index.js

收藏相关的接口:controllers / collect / index.js

const { mysql } = require('../../mysql')

// 添加收藏
async function addCollect(ctx) {
  const { openId, goodsId } = ctx.request.body
  // 判断是否已经收藏
  const iscollect = await mysql('nideshop_collect').where({
    'user_id': openId,
    'value_id': goodsId
  }).select()
  if (iscollect.length == 0) {
    await mysql('nideshop_collect').insert({
      'user_id': openId,
      'value_id': goodsId
    })
    ctx.body = {
      data: 'collected'
    }
  } else {
    await mysql('nideshop_collect').where({
      'user_id': openId,
      'value_id': goodsId
    }).del()
    ctx.body = {
      data: 'uncollect'
    }
  }
}

module.exports = {
  addCollect
}

1-5:商品 goods / index.js

商品相关的接口:controllers / goods / index.js

const { mysql } = require('../../mysql')

// 商品详情页数据
async function detailAction(ctx) {
  const goodsId = ctx.query.id
  const openId = ctx.query.openId
  // 商品信息
  const info = await mysql('nideshop_goods').where({
    'id': goodsId
  }).select()
  // 获取商品的图片
  const gallery = await mysql('nideshop_goods_gallery').where({
    'goods_id': goodsId
  })
  // 商品参数 关联查询两张表leftJoin
  /**
   * 理解:这两张表都是用来形容一个人的详细信息
   * A表:name id  age
   * B表:sex number tall 
   * 做法:找到A表的age18岁,然后拿着age18去找number也为18的数据
   * 
   * 数据库表划分的非常精细:键和值分别在不同的表中
   * 例如: name 对应 小明
   * 表 nideshop_attribute         存放键
   * 表 nideshop_goods_attribute   存放对应的值
   */
  const attribute = await mysql('nideshop_goods_attribute').column('nideshop_goods_attribute.value', 'nideshop_attribute.name').leftJoin('nideshop_attribute', 'nideshop_goods_attribute.attribute_id', 'nideshop_attribute.id').where({
    'nideshop_goods_attribute.goods_id': goodsId
  }).select()

  // 常见问题
  const issue = await mysql('nideshop_goods_issue').select()

  // 大家都在看
  const productList = await mysql('nideshop_goods').where({
    'category_id': info[0].category_id
  }).select()

  // 判断是否收藏过
  const iscollect = await mysql('nideshop_collect').where({
    'user_id': openId,
    'value_id': goodsId
  }).select()
  let collected = false
  if (iscollect.length > 0) {
    collected = true
  }

  // 判断该用户的购物车里是否含有此商品
  const oldNumber = await mysql('nideshop_cart').where({
    'user_id': openId
  }).column('number').select()
  let allnumber = 0
  if (oldNumber.length > 0) {
    for (let i = 0; i < oldNumber.length; i++) {
      const element = oldNumber[i] // {number: 1}
      allnumber += element.number
    }
  }

  ctx.body = {
    'info': info[0] || [],
    'gallery': gallery,
    'attribute': attribute,
    'issue': issue,
    'productList': productList,
    'collected': collected,
    'allnumber': allnumber
  }
}

// 商品列表
async function goodsList(ctx) {

  // 第一步:获取分类id
  const categoryId = ctx.query.categoryId
  // 第二步:根据分类id,获取该商品分类所属的商品信息列表
  let goodsList = []
  if (categoryId) {

    // 查询商品信息表
    goodsList = await mysql('nideshop_goods').where({
      'category_id': categoryId
    }).select()

    // 查询商品分类表
    const currentNav = await mysql('nideshop_category').where({
      'id': categoryId
    }).select()

    // 如果没有取到商品
    if (goodsList.length == 0) {

      // 找到与之相关的子类,再找到与子类相关的商品
      let subIds = await mysql('nideshop_category').where({
        'parent_id': categoryId
      }).column('id').select()

      // 如果找到了
      if (subIds.length !== 0) {
        subIds = subIds.map((item) => {
          return item.id
        })
      }
      goodsList = await mysql('nideshop_goods').whereIn('category_id', subIds).limit(50).select()
    }

    ctx.body = {
      data: goodsList,
      currentNav: currentNav[0]
    }
  }
}

module.exports = {
  detailAction,
  goodsList
}

1-6:首页 home / index.js

首页相关的接口:controllers / home / index.js

// 因为要查询数据库中的数据,所以引入mysql
const { mysql } = require('../../mysql')

module.exports = async (ctx) => {
  // 轮播图数据
  const banner = await mysql('nideshop_ad').where({
    ad_position_id: 1
  }).select()

  // tab类型
  const channel = await mysql('nideshop_channel').select()

  // 品牌列表
  const brandList = await mysql('nideshop_brand').where({
    is_new: 1
  }).orderBy('new_sort_order', 'asc').limit(4).select()

  // 新品首发
  const newGoods = await mysql('nideshop_goods').whereIn('id', [1181000, 1135002, 1134030, 1134032]).andWhere('is_new', 1).select()

  // 人气推荐
  const hotGoods = await mysql('nideshop_goods').column('id', 'name', 'list_pic_url', 'retail_price', 'goods_brief').where({
    is_hot: 1
  }).limit(5).select()

  // 专题精选
  const topicList = await mysql('nideshop_topic').limit(3).select()

  // 第一步:查询标题:类别列表 **好物:查询出页面标题展示的内容
  const categoryList = await mysql('nideshop_category').where({
    parent_id: 0
  }).select()

  // 第二步:区分标题下面所属的内容:哪些内容属于居家好物一类;哪些内容属于xxx的一类,等等...
  const newCategoryList = []
  for (let i = 0; i < categoryList.length; i++) {
    let item = categoryList[i]
    let childCategoryIds = await mysql('nideshop_category').where({
      parent_id: item.id
    }).column('id').select()
    // 变成数组的形式 [1020000, 1036002]
    childCategoryIds = childCategoryIds.map((item) => {
      return item.id
    })
    // 第三步:在商品中找到在childCategoryIds里的7条数据,whereIn 判断:category_id 是否存在于 childCategoryIds 
    const categoryGoods = await mysql('nideshop_goods').column('id', 'name', 'list_pic_url', 'retail_price').whereIn('category_id', childCategoryIds).limit(7).select()
    newCategoryList.push({
      'id': item.id,
      'name': item.name,
      'goodsList': categoryGoods
    })
  }

  ctx.body = {
    'banner': banner,
    'channel': channel,
    'brandList': brandList,
    'newGoods': newGoods,
    'hotGoods': hotGoods,
    'topicList': topicList,
    'newCategoryList': newCategoryList
  }
}

1-7:订单 order / index.js

订单相关的接口:controllers / order / index.js

const { mysql } = require('../../mysql')

async function submitAction (ctx) {
  // let goodsId = ctx.request.body.goodsId
  // let allPrice = ctx.request.body.allPrice

  // 接口前端传递的参数
  const { openId, goodsId, allPrice } = ctx.request.body
 
  // 是否存在订单
  const isOrder = await mysql('nideshop_order').where({
    'user_id': openId
  }).select()
  // 说明数据库中存在该商品--只是显示`未支付订单`--只需要更改商品信息就可以了,不需要再次插入同样的商品数据信息
  if (isOrder.length > 0) {
    // 
    const data = await mysql('nideshop_order').where({
      'user_id': openId
    }).update({
      user_id: openId,
      goods_id: goodsId,
      allprice: allPrice
    })
    /**
     * 数据更新状态:更新成功--更新失败
     */
    if (data) {
      ctx.body = {
        data: true
      }
    } else {
      ctx.body = {
        data: false
      }
    }
  } else {
    // 说明该商品不在`未支付订单`中,说明用户要添加新的商品--直接将商品信息添加到未支付表中
    const data = await mysql('nideshop_order').insert({
      user_id: openId,
      goods_id: goodsId,
      allprice: allPrice
    })
  /**
   * 数据添加状态:数据添加成功--数据添加失败
   */
    if (data) {
      ctx.body = {
        data: true
      }
    } else {
      ctx.body = {
        data: false
      }
    }
  }
}

/**
 * 获取用户的收货地址
 */
async function detailAction (ctx) {

  // 第一步:获取前端传递的数据:收货地址和用户标识openId
  const openId = ctx.query.openId
  const addressId = ctx.query.addressId || ''

  // 第二步:根据openId查询订单表(未支付订单)
  const orderDetail = await mysql('nideshop_order').where({
    'user_id': openId
  }).select()

  // 第三步:如果有多个商品,就会把商品id用逗号分隔为数组,如:["1001","1002","1003"]
  var goodsIds = orderDetail[0].goods_id.split(',')

  // 第四步:根据用户openId 查询 `购物车表`;判断`购物车表`中的goods_id,是否存在于未支付订单表中
  const list = await mysql('nideshop_cart').andWhere({
    'user_id': openId
  }).whereIn('goods_id', goodsIds).select()

  // 第五步:收货地址
  var addressList;
  if (addressId) {

    // 收货地址存在:查询`收货地址表`中的数据
    addressList = await mysql('nideshop_address').where({
      'user_id': openId,
      'id': addressId
    }).orderBy('is_default', 'desc').select()

  } else {

    // 收货地址不存在(前端没有传递收货地址)
    addressList = await mysql('nideshop_address').where({
      'user_id': openId
    }).orderBy('is_default', 'desc').select()

  }
  ctx.body = {
    price: orderDetail[0].allprice,  // 商品单价
    goodsList: list,  // 商品列表
    address: addressList[0] || {} // 收货地址
  }
}

module.exports = {
  submitAction,
  detailAction
}

1-8:搜索 search / index.js

搜索相关的接口:controllers / search / index.js

const { mysql } = require('../../mysql')

/**
 * 这个接口:负责搜索记录数据和热门搜索的数据
 */
async function indexAction(ctx) {

  /**
   * get请求,接收前端传递的数据:ctx.query.数据字段
   * 传入用户的标识 openId
   */
  const openId = ctx.query.openId

  // 默认关键字:如果 is_default 为1,说明取出的是搜索热门的默认关键字。
  const defaultKeyword = await mysql('nideshop_keywords').where({
    is_default: 1
  }).limit(1).select()

  // 热门关键字:keyword 是指数据库中的字段
  const hotKeywordList = await mysql('nideshop_keywords').distinct('keyword').column('keyword', 'is_hot').limit(10).select()

  // 搜索历史(取10条):传入用户的标识 openId ,你存的数据只有你才能取出来。同理:你也不能看到别人存的数据...
  const historyData = await mysql('nideshop_search_history').where({
    'user_id': openId
  }).limit(10).select()
  ctx.body = {
    'defaultKeyword': defaultKeyword[0],
    'hotKeywordList': hotKeywordList,
    'historyData': historyData
  }
}


// 搜索时匹配搜索相关的内容
async function helperAction(ctx) {

  // 获取用户搜索的内容
  const keyword = ctx.query.keyword
  var order = ctx.query.order
  if (!order) {
    order = ''
    orderBy = 'id'
  } else {
    orderBy = 'retail_price'
  }

  // 查询搜索关键字
  const keywords = await mysql('nideshop_goods').orderBy(orderBy, order)
  .column('id', 'name', 'list_pic_url', 'retail_price')
  .where('name', 'like', '%' + keyword + '%').limit(10).select()
  
  if (keywords) {
    ctx.body = {
      keywords
    }
  } else {
    ctx.body = {
      keywords: []
    }
  }
}


// 添加搜索历史
async function addHistoryAction(ctx) {

  // post请求,接收前端传递的数据(对象):ctx.request.body
  const {openId, keyword} = ctx.request.body

  // 查询历史搜索记录
  const oldData = await mysql('nideshop_search_history').where({
    'user_id': openId,
    'keyword': keyword
  })

  /**
   * 如果用户搜索的内容,已存在数据库中。则不需要重复存储搜索记录。
   * 目的:判断当下搜索字段,是否插入数据库表中,作为历史搜索记录。
   */

  if (oldData.length == 0) {

    // 如果搜索内容,在数据库搜索历史表中找不到。则将用户搜索内容保存在数据库表中
    const data = await mysql('nideshop_search_history').insert({
      'user_id': openId,
      'keyword': keyword,
      'add_time': parseInt(new Date().getTime() / 1000)
    })
    // 如果data值存在,说明数据插入成功;否则数据插入失败。
    if (data) {
      ctx.body = {
        data: 'success'
      }
    } else {
      ctx.body = {
        data: 'fail'
      }
    }
  } else {
    ctx.body = {
      data: '已经有记录了'
    }
  }
}

// 清除历史记录
async function clearHistoryAction(ctx) {

  // 获取前端传递的用户标识 openId
  const openId = ctx.request.body.openId

  const data = await mysql('nideshop_search_history').where({
    'user_id': openId
  }).del()
  if (data) {
    ctx.body = {
      'data': '清除成功'
    }
  } else {
    ctx.body = {
      'data': null
    }
  }
}

module.exports = {
  indexAction,
  addHistoryAction,
  clearHistoryAction,
  helperAction
}

1-9:专题 topic / index.js

专题接口相关的接口:controllers / topic / index.js

const { mysql } = require('../../mysql')

// 获取专题列表数据
async function listAction (ctx) {

  // 第一步:获取请求第几页数据(默认第一页)
  let page = ctx.query.page || 1
  // 第二步:每页显示多少条数据
  const size = 5
  // 第三步:分页处理
  const data = await mysql('nideshop_topic').column('id', 'title', 'price_info', 'scene_pic_url', 'subtitle').limit(size).offset((page - 1) * size)
  const data1 = await mysql('nideshop_topic').column('id', 'title', 'price_info', 'subtitle').select()
  // 计算:总页数
  const total = parseInt(data1.length / 5)

  ctx.body = {
    'page': page,
    'total': total,
    'data': data
  }
}

// 专题详情
async function detailAction (ctx) {

  // 第一步:获取前端传递的商品专题id
  const id = ctx.query.id
  // 第二步:
  let data = []
  if (id) {
    data = await mysql('nideshop_topic').where({
      'id': id
    }).select()
  }
  const recommendList = await mysql('nideshop_topic').column('id', 'title', 'price_info', 'scene_pic_url', 'subtitle').limit(4).select()
  ctx.body = {
    'data': data[0],
    'recommendList': recommendList
  }
}

module.exports = {
  listAction,
  detailAction
}

2. 路由 routes / index.js

// prefix 表示路由前缀

const router = require('koa-router')({
  prefix: '/lm'
})
const controllers = require('../controllers/index')

// 首页相关的接口
router.get('/index/index', controllers.home.index)

// 分类相关的接口
router.get('/category/categoryNav', controllers.category.index.categoryNav)
router.get('/category/indexaction', controllers.category.index.indexAction)
router.get('/category/currentaction', controllers.category.index.currentAction)


// 搜索相关的接口
router.get('/search/indexaction', controllers.search.index.indexAction)
router.post('/search/addhistoryaction', controllers.search.index.addHistoryAction)
router.post('/search/clearhistoryAction', controllers.search.index.clearHistoryAction) // 清除搜索历史
router.get('/search/helperaction', controllers.search.index.helperAction) // 搜索提示

// 商品
router.get('/goods/detailaction', controllers.goods.index.detailAction)
router.get('/goods/goodsList', controllers.goods.index.goodsList)


// 收藏相关的接口
router.post('/collect/addcollect', controllers.collect.index.addCollect)


// 订单相关的接口
router.post('/order/submitAction', controllers.order.index.submitAction)
router.get('/order/detailAction', controllers.order.index.detailAction)


// 购物车相关的接口
router.post('cart/addCart', controllers.cart.index.addCart)
router.get('/cart/cartList', controllers.cart.index.cartList)


// 收货地址相关的接口
router.get('/address/getListAction', controllers.address.index.getListAction)
router.get('/address/detailAction', controllers.address.index.detailAction)
router.post('/address/saveAction', controllers.address.index.saveAction)

// 专题接口
router.get('/topic/listaction', controllers.topic.index.listAction)
router.get('/topic/detailaction', controllers.topic.index.detailAction)

module.exports = router

3. 启动文件 app.js

const Koa = require('koa')
const app = new Koa()
const bodyParser = require('koa-bodyparser')
const config = require('./config')

// 解析请求体
app.use(bodyParser())

const router = require('./routes')
app.use(router.routes())

app.listen(config.port, () => {
  console.log(`server is started at port ${config.port}`)
})

4. 配置文件 config.js

const CONF = {
  port: '5757',
  mysql: {
    host: 'localhost',
    port: 3306,
    user: 'mpvue_shop',
    db: 'nodemysql',
    pass: 'mpvue_shop123',
    char: 'utf8mb4'
  }
}

module.exports = CONF

5. 数据库 mysql.js

// 获取基础配置
const configs = require('./config')

var knex = require('knex') ({
  client: 'mysql',
  connection: {
    host: configs.mysql.host,
    port: configs.mysql.port,
    user: configs.mysql.user,
    password: configs.mysql.pass,
    database: configs.mysql.db,
  }
})
// 将基础配置和sdk.config 合并 导出初始化完成的sdk
module.exports = { mysql: knex }

6. 网易严选 - 数据库表

需要自己手动导入 ,如:PHPstudy软件

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落花流雨

你的鼓励将是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值