UNIAPP实战项目笔记72 提交订单到选择支付方式的前后端交互
思路
- 购物车确认订单,跳转到订单确认界面
- 确认支付后清除购物车对应id的数据
实例截图
清空购物车数据后
代码
前端代码 order.js
export default{
state:{
// 订单号
orderNumber:''
},
getters:{
},
mutations:{
initOrder( state,order ){
state.orderNumber = order;
}
},
actions:{
}
}
前端代码 index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
// 购物车
import cart from './modules/cart.js'
// 地址管理
import path from './modules/path.js'
// 用户
import user from './modules/user.js'
// 订单
import order from './modules/order.js'
export default new Vuex.Store({
modules:{
cart,
path,
user,
order
}
})
nodejs 后端代码 index.js
var express = require('express');
var router = express.Router();
var connection = require('../db/sql.js');
var user = require('../db/UserSql.js');
const jwt = require('jsonwebtoken');// 生成token秘钥
// 验证码
let code = '';
// 接入短信的sdk
// var QcloudSms = require('qcloudsms_js');
//设置跨域访问(设置在所有的请求前面即可)
router.all("*", function (req, res, next) {
//设置允许跨域的域名,*代表允许任意域名跨域
res.header("Access-Control-Allow-Origin", "*");
//允许的header类型,X-Requested-With
res.header("Access-Control-Allow-Headers", "Appid,Secret,Access-Token,token,Content-Type,Origin,User-Agent,DNT,Cache-Control,X-Requested-With");
//跨域允许的请求方式
res.header("Access-Control-Allow-Methods", "DELETE,PUT,POST,GET,OPTIONS");
// res.header("Access-Control-Allow-Methods", "*");
res.header("Content-Type", "application/json;chartset=utf-8");
// if (req.method == 'OPTIONS')
// res.sendStatus(200); //让options尝试请求快速结束
// else
next();
});
/* GET home page. */
router.get('/', function(req, res, next) {
res.send({
data:{
aaa:'1111'
}
});
// res.render('index', { title: 'Express' });
});
/* 测试token数据. */
router.post('/api/ceshi', function(req, res, next) {
console.log(111);
res.send({
data:{
aaa:'1111'
}
});
});
/* 修改订单 */
router.post('/api/submitOrder', function(req, res, next) {
let token = req.headers.token;
let phone = jwt.decode(token);
// 订单号
let orderId = req.body.orderId;
// 购物车中选中的商品
let shopArr = req.body.shopArr;
// 查询用户id
connection.query( `select * from user where phone = ${
phone.name}`,function(error,results, fields){
let userId = results[0].id;
// 查询订单id
connection.query( `select * from store_order where uid = ${
userId} and order_id = ${
orderId}`,function(error1,results1, fields1){
let id = results1[0].id;
// 修改订单status
connection.query( `update store_order set order_status = replace(order_status,'1','2') where id = ${
id}`,function(error2,results2, fields2){
// 清购物车
connection.query( `delete from goods_cart where id in (${
shopArr.join(',')})`,function(error3,results3, fields3){
res.json({
data:{
success:true
}
})
})
})
})
})
});
/* 生成订单 */
router.post('/api/addOrder', function(req, res, next) {
let token = req.headers.token;
let phone = jwt.decode(token);
// 前端传过来的数据
let goodsArr = req.body.arr;
// 生成订单号
function setTimeDateFmt(s){
return s < 10 ? '0'+s : s;
}
function orderNumber(){
const now = new Date();
let fullYear = now.getFullYear();
let month = setTimeDateFmt(now.getMonth() + 1);
let day = setTimeDateFmt(now.getDate());
let hour = setTimeDateFmt(now.getHours());
let minutes = setTimeDateFmt(now.getMinutes());
let seconds = setTimeDateFmt(now.getSeconds());
let orderCode = fullYear + month + day + hour + minutes + seconds + ( Math.round( Math.random() * 1000000 ) );
return orderCode;
}
// 商品名称
let goodsName = [];
// 订单总价
let goodsPrice = 0;
// 订单商品总数量
let goodsNum = 0;
// 订单号
let orderId = orderNumber();
goodsArr.forEach(v=>{
goodsName.push( v.name );
goodsNum += parseInt(v.num);
goodsPrice += v.num * v.pprice;
})
// 查询用户id
connection.query( `select * from user where phone = ${
phone.name}`,function(error,results, fields){
let userId = results[0].id;
// 订单写入数据库
connection.query(
`insert into store_order (uid,order_id,goods_name,goods_price,goods_num,order_status ) values ('${
userId}','${
orderId}','${
goodsName}','${
goodsPrice}','${
goodsNum}','1')`,
function(error1,results1, fields1){
// console.log(error);
// 查询刚生成的订单详情
connection.query( `select * from store_order where uid = ${
userId} and order_id = ${
orderId}`,function(error2,results2, fields2){
res.json({
data:{
success:true,
data:results2
}
})
});
});
})
})
/* 修改当前用户购物车商品数量 */
router.post('/api/deleteCart', function(req, res, next) {
let goodsId = req.body.goods_id;//商品id
// console.log(`delete from goods_cart where id in (${goodsId.join(',')})`);
connection.query( `delete from goods_cart where id in (${
goodsId.join(',')})`,function(error,results, fields){
res.json({
data:{
success:true
}
})
})
})
/* 修改当前用户购物车商品数量 */
router.post('/api/addCart', function(req, res, next) {
let token = req.headers.token;
let phone = jwt.decode(token);
let goodsId = req.body.goods_id;//商品id
let num = req.body.num;//前端传过来用户输入的产品数量
connection.query( `select * from user where phone = ${
phone.name}`,function(error,results, fields){
let userId = results[0].id;
connection.query( `select * from goods_search where id = ${
goodsId}`,function(error1,results1, fields1){
console.log(error1,results1);
let name = results1[0].name;
let imgUrl = results1[0].imgUrl;
let pprice = results1[0].pprice;
// 查询当前用户之前是否添加过这个商品
connection.query( `select * from goods_cart where uid = ${
userId} and goods_id = ${
goodsId}`,function(error2,results2, fields12){
console.log(error2,results2);
if(results2.length > 0){
// 如果当前用户之前加入过本商品,就直接增加数量
connection.query(`update goods_cart set num = replace(num,${
results2[0].num},${
parseInt(num) + parseInt(results2[0].num)}) where id = ${
results2[0].id}`,function(error4,results4){
console.log(error4,results4);
res.json({
data:{
success:"加入成功"
}
})
})
}else{
// 如果当前用户之前没有加入过本商品需要添加进入
connection.query(
`insert into goods_cart (uid,goods_id,name,imgUrl,pprice,num) values ("${
userId}","${
goodsId}","${
name}","${
imgUrl}","${
pprice}","${
num}")`,
function(error3,results3){
res.json({
data:{
success:"加入成功"
}
})
});
}
});
});
});
});
/* 修改当前用户购物车商品数量 */
router.post('/api/updateCart', function(req, res, next) {
let token = req.headers.token;
let phone = jwt.decode(token);
let goodsId = req.body.goodsId;//商品id
let num = req.body.num;//前端传过来用户输入的产品数量
connection.query( `select * from user where phone = ${
phone.name}`,function(error,results, fields){
let userId = results[0].id;
connection.query( `select * from goods_cart where uid = ${
userId} and goods_id = ${
goodsId}`,function(error1,results1, fields1){
// console.log(results1);
let goods_num = results1[0].num;//数据库中当前的数量
let id = results1[0].id;//当前id号
// 修改替换
connection.query(`update goods_cart set num = replace(num,${
goods_num},${
num}) where id = ${
id}`,function(error2,results2){
res.json({
data:{
success:true
}
})
})
});
});
});
/* 获取当前用户购物车列表 */
router.post('/api/selectCart', function(req, res, next) {
let token = req.headers.token;
let phone = jwt.decode(token);
connection.query( `select * from user where phone = ${
phone.name}`,function(error,results, fields){
let userId = results[0].id;
connection.query( `select * from goods_cart where uid = ${
userId}`,function(error1,results1, fields1){
res.json({
data:results1
});
});
});
});
/* 当前用户修改收货地址 */
router.post('/api/updateAddress', function(req, res, next) {
let token = req.headers.token;
let phone = jwt.decode(token);
let name = req.body.name;
let tel = req.body.tel;
let province = req.body.province;
let city = req.body.city;
let district = req.body.district;
let address = req.body.address;
let isDefault = req.body.isDefault;
let id = req.body.id;
connection.query( `select * from user where phone = ${
phone.name}`,function(error,results, fields){
let userId = results[0].id;
// 默认地址处理,当前用户只能有一个默认地址
connection.query(`select * from address where userid=${
userId} and isDefault = ${
isDefault}`,function(err2,res2,fields2){
let childId = results[0].id;
connection.query(`update address set isDefault = replace(isDefault,"1","0") where userid=${
childId}`,function(err3,res3){
// console.log(err3,res3);
//
let sqlupdate = "update address set name=?,tel=?,province=?,city=?,district=?,address=?,isDefault=?,userid=? where id = '"+id+"'";
connection.query(sqlupdate,[name,tel,province,city,district,address,isDefault,userId],function(err1,res1,field1){
// console.log(err1,res1,field1);
res.send({
data:{
success:"成功"
}
})
});
});
});
});
});
/* 当前用户新增收货地址 */
router.post('/api/addAddress', function(req, res, next) {
let token = req.headers.token;
let phone = jwt.decode(token);
let name = req.body.name;
let tel = req.body.tel;
let province = req.body.province;
let city = req.body.city;
let district = req.body.district;
let address = req.body.address;
let isDefault = req.body.isDefault;
connection.query( `select * from user where phone = ${
phone.name}`,function(error,results, fields){
let id = results[0].id;
let sqlInsert = "insert into address (name,tel,province,city,district,address,isDefault,userId) values ('"+name+"','"+tel+"','"+province+"','"+city+"','"+district+"','"+address+"','"+isDefault+"','"+id+"')";
connection.query(sqlInsert,function(err1,res1,field1){
res.send({
data:{
success:"成功"
}
})
});
});
});
/* 当前用户查询收货地址 */
router.post('/api/selectAddress', function(req, res, next) {
let token = req.headers.token;
let phone = jwt.decode(token);
console.log( token );
console.log( phone );
connection.query( `select * from user where phone = ${
phone.name}`,function(error,results, fields){
let id = results[0].id;
connection.query( `select * from address where userId = ${
id}`,function(error2,results2, fields2){
// console.log( results2 );
res.send({
data:results2
})
});
});
});
/* 第三方登录 */
router.post('/api/loginother', function(req, res, next) {
// 前端给后端的数据
let params = {
provider:req.body.provider,//登录方式
openid:req.body.openid,//用户身份id
nickName:req.body.nickName,//用户昵称
avataUrl:req.body.avataUrl//用户头像
};
console.log(params);
// 查询数据库中用户是否存在
connection.query(user.queryUserName(params),function(error,results,fields){
if(results.length > 0){
// 数据库中存在 直接读取
connection.query( user.queryUserName( params ), function(err2, res2) {
res.send({
data:res2[0]
});
});
}else{
// 数据库中不存在 存储 -> 读取
connection.query( user.insertData( params ), function(err1,res1) {
connection.query( user.queryUserName( params ), function(err2, res2) {
res.send({
data:res2[0]
});
});
});
}
})
});
/* 注册->增加一条数据. */
router.post('/api/addUser', function(req, res, next) {
// 前端给后端的数据
let params = {
userName:req.body.userName,
userCode:req.body.code
};
if( params.userCode == code ){
connection.query( user.insertData( params ),function(error,results, fields){
// 再去查询手机号是否存在,用于注册成功后直接登录
connection.query(user.queryUserName(params),function(er,result){
if(results.length > 0){
res.send({
data:{
success:true,
msg:'注册成功',
data:result[0]
}
});
}
});
// res.send({
// data:{
// success:true,
// msg:'注册成功'
// }
// });
});
}
});
/* 发送验证码 */
router.post('/api/code', function(req, res, next) {
// 前端给后端的数据
let params = {
userName : req.body.userName
}
// 短信SDK 可以使用阿里云或腾讯云的,具体接入方式以官方NodeJS代码案例
// ....
// 阿里云 官方代码 https://help.aliyun.com/document_detail/112185.html
// 腾讯云 官方代码 https://cloud.tencent.com/developer/article/1987501
// ....
// ....
var paramss = [ Math.floor( Math.random()*(9999-1000)+1000 ) ] // 要发送的验证码
// 模拟以获取到验证码
code = paramss[0];
console.log(code);
// 模拟成功返回验证码
res.send({
data:{
success:true,
code : paramss[0]
}
})
})
/* 注册验证手机号是否存在 */
router.post('/api/registered', function(req, res, next) {
// 前端给后端的数据
let params = {
userName : req.body.phone
}
// 查询手机号是否存在
connection.query(user.queryUserName(params),function(error,results,fields){
if(results.length > 0){
res.send({
data:{
success:false,
msg:"手机号已经存在!"
}
});
}else{
res.send({
data:{
success:true
}
});
}
})
});
/* 用户登录 */
router.post('/api/login', function(req, res, next) {
// 前端给后端的数据
let params = {
userName : req.body.userName,
userPwd : req.body.userPwd
}
// 查询用户名或手机号是否存在
connection.query(user.queryUserName(params),function(error,results,fields){
if(results.length > 0){
connection.query(user.queryUserPwd(params),function(erro,result){
if(result.length > 0){
res.send({
data:{
success:true,
msg:"登录成功!",
data:result[0]
}
});
}else{
res.send({
data:{
success:false,
msg:"密码不正确!"
}
});
}
})
}else{
res.send({
data:{
success:false,
msg:"用户名或手机号不存在!"
}
});
}
})
});
/* GET databases goods Detail. */
router.get('/api/goods/id', function(req, res, next) {
let id = req.query.id;
connection.query("select * from goods_search where id='"+id+"'",function(error,result,fields){
if(error) throw error;
res.send({
code:"0",
data:result
})
})
});
/* GET List Page */
router.get('/api/goods/list', function(req, res, next) {
res.send({
code:0,
name:"家居家纺",
data:[
{
id:1,
name:"家纺",
data:[
{
name:"家纺",
list:[
{
id:1,
name:"毛巾/浴巾",
imgUrl:"/static/logo.png"
},
{
id:2,
name:"枕头",
imgUrl:"/static/logo.png"
}
]
},
{
name:"生活用品",
list:[
{
id:1,
name:"浴室用品",
imgUrl:"/static/logo.png"
},
{
id:2,
name:"洗晒",
imgUrl:"/static/logo.png"
}
]
}
]
},
{
id:2,
name:"女装",
data:[
{
name:"裙装",
list:[
{
id:1,
name:"连衣裙",
imgUrl:"/static/logo.png"
},
{
id:2,
name:"半身裙",
imgUrl:"/static/logo.png"
}
]
},
{
name:"上衣",
list:[
{
id:1,
name:"T恤",
imgUrl:"/static/logo.png"
},
{
id:2,
name:"衬衫",
imgUrl:"/static/logo.png"
}
]
}
]
}
]
});
});
/* GET databases goods. */
router.get('/api/goods/search', function(req, res, next) {
/*
desc 降序 asc 升序
*/
// 获取对象的key
let [goodsName,orderName] = Object.keys(req.query);
// name参数的值
let name = req.query.name;
// orderName的key值
let order = req.query[orderName];
let sql = "select * from goods_search";
if(!(name == undefined || orderName == undefined || order == undefined)){
sql = "select * from goods_search where name like '%"+name+"%' order by "+orderName+" "+order;
}
connection.query(sql,function(error,results,fields){
res.send({
code:"0",
data:results
});
})
});
/* 首页第一次触底的数据 */
router.get('/api/index_list/1/data/2', function(req, res, next) {
res.send({
code:"0",
data:[
{
type:"commodityList",
data:[
{
id:1,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
{
id:2,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},{
id:3,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
{
id:4,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
]
},
]
});
});
/* 运动户外第二次触底的数据 */
router.get('/api/index_list/2/data/3', function(req, res, next) {
res.send({
code:"0",
data:[
{
type:"commodityList",
data:[
{
id:1,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
{
id:2,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},{
id:3,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
{
id:4,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
]
},
]
});
});
/* 运动户外第一次触底的数据 */
router.get('/api/index_list/2/data/2', function(req, res, next) {
res.send({
code:"0",
data:[
{
type:"commodityList",
data:[
{
id:1,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
{
id:2,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},{
id:3,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
{
id:4,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
]
},
]
});
});
/* 运动户外第一次加载的数据 */
router.get('/api/index_list/2/data/1', function(req, res, next) {
res.send({
code:"0",
data:[
{
type:"bannerList",
imgUrl:"../../static/img/b3.jpg",
},
{
type:"iconsList",
data:[
{
imgUrl:"../../static/logo.png",name:"运动户外"},
{
imgUrl:"../../static/logo.png",name:"运动户外"},
{
imgUrl:"../../static/logo.png",name:"运动户外"},
{
imgUrl:"../../static/logo.png",name:"运动户外"},
{
imgUrl:"../../static/logo.png",name:"运动户外"},
{
imgUrl:"../../static/logo.png",name:"运动户外"},
{
imgUrl:"../../static/logo.png",name:"运动户外"},
{
imgUrl:"../../static/logo.png",name:"运动户外"}
]
},
{
type:"hotList",
data:[
{
id:1,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
{
id:2,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},{
id:3,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
}
]
},
{
type:"shopList",
data:[
{
bigUrl:"../../static/img/b3.jpg",
data:[
{
id:1,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
{
id:2,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},{
id:3,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
{
id:4,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
}
]
}
],
},
{
type:"commodityList",
data:[
{
id:1,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
{
id:2,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},{
id:3,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
{
id:4,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
]
},
]
});
});
/* 服饰内衣第一次加载的数据 */
router.get('/api/index_list/3/data/1', function(req, res, next) {
res.send({
code:"0",
data:[
{
type:"bannerList",
imgUrl:"../../static/img/b3.jpg",
},
{
type:"iconsList",
data:[
{
imgUrl:"../../static/logo.png",name:"服饰内衣"},
{
imgUrl:"../../static/logo.png",name:"服饰内衣"},
{
imgUrl:"../../static/logo.png",name:"服饰内衣"},
{
imgUrl:"../../static/logo.png",name:"服饰内衣"},
{
imgUrl:"../../static/logo.png",name:"服饰内衣"},
{
imgUrl:"../../static/logo.png",name:"服饰内衣"},
{
imgUrl:"../../static/logo.png",name:"服饰内衣"},
{
imgUrl:"../../static/logo.png",name:"服饰内衣"}
]
},
{
type:"hotList",
data:[
{
id:1,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
{
id:2,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},{
id:3,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
}
]
},
{
type:"shopList",
data:[
{
bigUrl:"../../static/img/b3.jpg",
data:[
{
id:1,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
{
id:2,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},{
id:3,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
{
id:4,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
}
]
}
],
},
{
type:"commodityList",
data:[
{
id:1,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
{
id:2,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},{
id:3,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
{
id:4,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
]
},
]
});
});
/* 首页推荐数据 */
router.get('/api/index_list/data', function(req, res, next) {
res.send({
"code":0,
"data":{
topBar:[
{
id:1,name:'推荐'},
{
id:2,name:'运动户外'},
{
id:3,name:'服饰内衣'},
{
id:4,name:'鞋靴箱包'},
{
id:5,name:'美妆个护'},
{
id:6,name:'家居数码'},
{
id:7,name:'食品母婴'}
],
data:[
{
type:"swiperList",
data:[
{
imgUrl:'/static/img/b3.jpg'},
{
imgUrl:'/static/img/b3.jpg'},
{
imgUrl:'/static/img/b3.jpg'}
]
},{
type:"recommendList",
data:[
{
bigUrl:"../../static/img/b3.jpg",
data:[
{
imgUrl:'../../static/logo.png'},
{
imgUrl:'../../static/logo.png'},
{
imgUrl:'../../static/logo.png'}
]
},{
bigUrl:"../../static/img/b3.jpg",
data:[
{
imgUrl:'../../static/logo.png'},
{
imgUrl:'../../static/logo.png'},
{
imgUrl:'../../static/logo.png'}
]
}
]
},{
type:"commodityList",
data:[
{
id:1,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
{
id:2,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},{
id:3,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
{
id:4,
imgUrl:"../../static/logo.png",
name:"迪奥绒毛大衣,今年必抢,错过瞬时不爽了,爆款疯狂销售",
pprice:"299",
oprice:"659",
discount:"5.2"
},
]
},
]
}
})
});
module.exports = router;
前端购物车页面 shopcart.vue
<template>
<view class="shop-cart">
<template v-if=" list.length > 0 ">
<!-- 自定义导航栏 -->
<uniNavBar
title="购物车"
:rightText=" isNavBar ? '完成' : '编辑'"
fixed="true"
statusBar="true"
@clickRight=" isNavBar = !isNavBar"
></uniNavBar>
<!-- 商品内容 -->
<view class="shop-item" v-for="(item,index) in list" :key="index">
<label for="" class="radio" @tap="selectedItem(index)">
<radio value="" color="#FF3333" :checked="item.checked" /> <text></text>
</label>
<image class="shop-img" :src="item.imgUrl" mode=""></image>
<view class="shop-text">
<view class="shop-name">
{
{
item.name}}
</view>
<view class="shop-color f-color">
{
{
item.color}}
</view>
<view class="shop-price">
<view class="">
¥{
{
item.pprice}}
</view>
<template v-if="!isNavBar">
<view>x {
{
item.num}}</view>
</template>
<template v-else>
<uniNumberBox
:value="item.num"
:min=1
@change="changeNumber($event,index,item)"
></uniNumberBox>
</template>
</view>
</view>
</view>
<!-- 底部 -->
<view class="shop-foot">
<label for="" class="radio foot-radio" @tap='checkedAllFn'>
<radio value="" color="#FF3333" :checked="checkedAll"></radio><text>全选</text>
</label>
<template v-if="!isNavBar">
<view class="foot-total">
<view class="foot-count">
合计:
<text class="f-active-color">
¥{
{
totalCount.pprice}}
</text>
</view>
<view class="foot-num" @tap="goConfirmOrder">
结算({
{
totalCount.num}})
</view>
</view>
</template>
<template v-else>
<view class="foot-total">
<view class="foot-num" style="background-color: black;">
移入收藏夹
</view>
<view class="foot-num" @tap="delGoodsFn">
删除
</view>
</view>
</template>
</view>
</template>
<template v-else>
<uniNavBar
title="购物车"
fixed="true"
statusBar="true"
></uniNavBar>
<view class="shop-else-list">
<text>囧~ 购物车还是空的~</text>
</view>
</template>
<Tabbar currentPage='shopcart'></Tabbar>
</view>
</template>
<script>
import $http from '@/common/api/request.js'
import uniNavBar from '@/components/uni/uni-nav-bar/uni-nav-bar.vue'
import uniNumberBox from '@/components/uni/uni-number-box/uni-number-box.vue'
import Tabbar from '@/components/common/Tabbar.vue';//引入
// 状态机引入
import {
mapState,mapActions,mapGetters,mapMutations} from 'vuex'
export default {
data() {
return {
isNavBar:false,
}
},
computed:{
// 状态机数据处理
...mapState({
list:state=>state.cart.list,
selectedList:state=>state.cart.selectedList,
}),
...mapGetters(['checkedAll','totalCount'])
},
components:{
uniNavBar,uniNumberBox,Tabbar
},
onShow() {
this.getData();
},
methods: {
...mapActions(['checkedAllFn','delGoodsFn']),
...mapMutations(['selectedItem','initGetData','initOrder']),
getData(){
$http.request({
url:'/selectCart',
method:"POST",
header:{
token:true
}
}).then((res)=>{
this.initGetData(res)
}).catch(()=>{
uni.showToast({
title:'请求失败',
icon:'none'
})
})
},
changeNumber(value,index,item){
if ( value == item.num ) return;
$http.request({
url:'/updateCart',
method:"POST",
header:{
token:true
},
data:{
goodsId:item.goods_id,
num:value
}
}).then((res)=>{
this.list[index].num = value;
}).catch(()=>{
uni.showToast({
title:'请求失败',
icon:'none'
})
})
},
// 进入确认订单
goConfirmOrder(){
if(this.selectedList.length === 0){
return uni.showToast({
title:"至少选择一件商品",
icon:"none"
})
}
let newList = [];
this.list.forEach(item=>{
this.selectedList.filter(v=>{
if( item.id == v ){
newList.push( item );
}
})
})
$http.request({
url:'/addOrder',
method:"POST",
header:{
token:true
},
data:{
arr:newList
}
}).then((res)=>{
console.log(res);
if( res.success ){
// 存储订单号
this.initOrder( res.data[0].order_id);
// 跳转页面
uni.navigateTo({
url:`/pages/confirm-order/confirm-order?details=${
JSON.stringify(this.selectedList)}`
})
}
}).catch(()=>{
uni.showToast({
title:'请求失败',
icon:'none'
})
})
}
}
}
</script>
<style lang="scss">
.shop-list{
padding-bottom: 100rpx;
}
.shop-else-list{
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: #f7f7f7;
display: flex;
align-items: center;
justify-content: center;
}
.shop-item{
display: flex;
padding: 20rpx;
align-items: center;
background-color: #f7f7f7;
margin-bottom: 10rpx;
}
.shop-img{
width: 200rpx;
height: 200rpx;
}
.shop-text{
flex: 1;
padding-left: 20rpx;
}
.shop-color{
font-size: 24rpx;
}
.shop-price{
display: flex;
justify-content: space-between;
}
.shop-foot{
border-top: 2rpx solid #f7f7f7;
background-color: #FFFFFF;
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 100rpx;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 120rpx;
}
.foot-radio{
padding-left: 20rpx;
}
.foot-total{
display: flex;
}
.foot-count{
line-height: 100rpx;
padding: 0 20rpx;
font-size: 32rpx;
}
.foot-num{
background-color: #49bdfb;
color: #FFFFFF;
padding: 0 60rpx;
line-height: 100rpx;
}
</style>
前端订单确认界面 confirm-order.vue
<template>
<view class="shop-cart">
<template v-if=" list.length > 0 ">
<!-- 自定义导航栏 -->
<uniNavBar
title="购物车"
:rightText=" isNavBar ? '完成' : '编辑'"
fixed="true"
statusBar="true"
@clickRight=" isNavBar = !isNavBar"
></uniNavBar>
<!-- 商品内容 -->
<view class="shop-item" v-for="(item,index) in list" :key="index">
<label for="" class="radio" @tap="selectedItem(index)">
<radio value="" color="#FF3333" :checked="item.checked" /> <text></text>
</label>
<image class="shop-img" :src="item.imgUrl" mode=""></image>
<view class="shop-text">
<view class="shop-name">
{
{
item.name}}
</view>
<view class="shop-color f-color">
{
{
item.color}}
</view>
<view class="shop-price">
<view class="">
¥{
{
item.pprice}}
</view>
<template v-if="!isNavBar">
<view>x {
{
item.num}}</view>
</template>
<template v-else>
<uniNumberBox
:value="item.num"
:min=1
@change="changeNumber($event,index,item)"
></uniNumberBox>
</template>
</view>
</view>
</view>
<!-- 底部 -->
<view class="shop-foot">
<label for="" class="radio foot-radio" @tap='checkedAllFn'>
<radio value="" color="#FF3333" :checked="checkedAll"></radio><text>全选</text>
</label>
<template v-if="!isNavBar">
<view class="foot-total">
<view class="foot-count">
合计:
<text class="f-active-color">
¥{
{
totalCount.pprice}}
</text>
</view>
<view class="foot-num" @tap="goConfirmOrder">
结算({
{
totalCount.num}})
</view>
</view>
</template>
<template v-else>
<view class="foot-total">
<view class="foot-num" style="background-color: black;">
移入收藏夹
</view>
<view class="foot-num" @tap="delGoodsFn">
删除
</view>
</view>
</template>
</view>
</template>
<template v-else>
<uniNavBar
title="购物车"
fixed="true"
statusBar="true"
></uniNavBar>
<view class="shop-else-list">
<text>囧~ 购物车还是空的~</text>
</view>
</template>
<Tabbar currentPage='shopcart'></Tabbar>
</view>
</template>
<script>
import $http from '@/common/api/request.js'
import uniNavBar from '@/components/uni/uni-nav-bar/uni-nav-bar.vue'
import uniNumberBox from '@/components/uni/uni-number-box/uni-number-box.vue'
import Tabbar from '@/components/common/Tabbar.vue';//引入
// 状态机引入
import {
mapState,mapActions,mapGetters,mapMutations} from 'vuex'
export default {
data() {
return {
isNavBar:false,
}
},
computed:{
// 状态机数据处理
...mapState({
list:state=>state.cart.list,
selectedList:state=>state.cart.selectedList,
}),
...mapGetters(['checkedAll','totalCount'])
},
components:{
uniNavBar,uniNumberBox,Tabbar
},
onShow() {
this.getData();
},
methods: {
...mapActions(['checkedAllFn','delGoodsFn']),
...mapMutations(['selectedItem','initGetData','initOrder']),
getData(){
$http.request({
url:'/selectCart',
method:"POST",
header:{
token:true
}
}).then((res)=>{
this.initGetData(res)
}).catch(()=>{
uni.showToast({
title:'请求失败',
icon:'none'
})
})
},
changeNumber(value,index,item){
if ( value == item.num ) return;
$http.request({
url:'/updateCart',
method:"POST",
header:{
token:true
},
data:{
goodsId:item.goods_id,
num:value
}
}).then((res)=>{
this.list[index].num = value;
}).catch(()=>{
uni.showToast({
title:'请求失败',
icon:'none'
})
})
},
// 进入确认订单
goConfirmOrder(){
if(this.selectedList.length === 0){
return uni.showToast({
title:"至少选择一件商品",
icon:"none"
})
}
let newList = [];
this.list.forEach(item=>{
this.selectedList.filter(v=>{
if( item.id == v ){
newList.push( item );
}
})
})
$http.request({
url:'/addOrder',
method:"POST",
header:{
token:true
},
data:{
arr:newList
}
}).then((res)=>{
console.log(res);
if( res.success ){
// 存储订单号
this.initOrder( res.data[0].order_id);
// 跳转页面
uni.navigateTo({
url:`/pages/confirm-order/confirm-order?details=${
JSON.stringify(this.selectedList)}`
})
}
}).catch(()=>{
uni.showToast({
title:'请求失败',
icon:'none'
})
})
}
}
}
</script>
<style lang="scss">
.shop-list{
padding-bottom: 100rpx;
}
.shop-else-list{
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: #f7f7f7;
display: flex;
align-items: center;
justify-content: center;
}
.shop-item{
display: flex;
padding: 20rpx;
align-items: center;
background-color: #f7f7f7;
margin-bottom: 10rpx;
}
.shop-img{
width: 200rpx;
height: 200rpx;
}
.shop-text{
flex: 1;
padding-left: 20rpx;
}
.shop-color{
font-size: 24rpx;
}
.shop-price{
display: flex;
justify-content: space-between;
}
.shop-foot{
border-top: 2rpx solid #f7f7f7;
background-color: #FFFFFF;
position: fixed;
bottom: 0;
left: 0;
width: 100%;
height: 100rpx;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 120rpx;
}
.foot-radio{
padding-left: 20rpx;
}
.foot-total{
display: flex;
}
.foot-count{
line-height: 100rpx;
padding: 0 20rpx;
font-size: 32rpx;
}
.foot-num{
background-color: #49bdfb;
color: #FFFFFF;
padding: 0 60rpx;
line-height: 100rpx;
}
</style>
前端 选择支付方式界面 payment.vue
<template>
<view>
<view class="">
<!-- 自定义导航栏 -->
<!-- #ifndef MP-WEIXIN -->
<uniNavBar
title='确认支付'
left-text='关闭'
fixed='true'
@clickLeft='goBack'
></uniNavBar>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<uniNavBar
title='确认支付'
left-text='关闭'
fixed='true'
@clickLeft='goBack'
></uniNavBar>
<!-- #endif -->
</view>
<view class="pay-main">
<radio-group>
<label for="">
<view class="pay-item">
<image class="pay-img" src="../../static/img/zfbzf.png" mode=""></image>
<view class="">
<view class="">支付宝支付</view>
<view class="pay-txt">推荐支付宝用户使用</view>
</view>
<label class="radio">
<radio value="" color="#ff3333"/><text></text>
</label>
</view>
</label>
<label for="">
<view class="pay-item">
<image class="pay-img" src="../../static/img/wxzf.jpg" mode=""></image>
<view class="">
<view class="">微信支付</view>
<view class="pay-txt">推荐微信的用户使用</view>
</view>
<label class="radio">
<radio value="" color="#ff3333"/><text></text>
</label>
</view>
</label>
</radio-group>
</view>
<view class="pay-foot">
<view class="total">
<text class="f-color">合计:</text>
<text class="total-price">¥{
{
details.price}}</text>
</view>
<view class="go-pay" @tap="goPayment">
去支付
</view>
</view>
</view>
</template>
<script>
import uniNavBar from '@/components/uni/uni-nav-bar/uni-nav-bar.vue'
export default {
data() {
return {
details:{
price:0
}
};
},
components:{
uniNavBar
},
onLoad(e) {
console.log(e);
this.detail = JSON.parse( e.details );
},
methods:{
// 点击关闭返回上一页
goBack(){
uni.navigateBack();
},
// 跳转到支付成功
goPayment(){
uni.navigateTo({
url:'/pages/payment-success/payment-success'
})
}
}
}
</script>
<style lang="scss">
.pay-item{
display:flex;
justify-content: space-between;
align-items: center;
padding: 20rpx;
border-bottom: 2rpx solid #ccc;
}
.pay-txt{
color: #bbb;
}
.pay-img{
width: 100rpx;
height: 100rpx;
}
.pay-foot{
width: 100%;
position: fixed;
left: 0;
bottom: 0;
height: 100rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
.total-price{
color: #fff;
}
.total{
padding-left: 100rpx;
flex: 1;
background-color: #000;
line-height: 100rpx;
}
.go-pay{
color: #fff;
background-color: #49bdfb;
line-height: 100rpx;
text-align: center;
width: 220rpx;
}
.f-color{
color: #ccc;
}
</style>
目录结构
前端目录结构
-
manifest.json 配置文件: appid、logo…
-
pages.json 配置文件: 导航、 tabbar、 路由
-
main.js vue初始化入口文件
-
App.vue 全局配置:样式、全局监视
-
static 静态资源:图片、字体图标
-
page 页面
- index
- index.vue
- list
- list.vue
- my
- my.vue
- my-config
- my-config.vue
- my-config
- my-config.vue
- my-add-path
- my-add-path.vue
- my-path-list
- my-path-list.vue
- search
- search.vue
- search-list
- search-list.vue
- shopcart
- shopcart.vue
- details
- details.vue
- my-order
- my-order.vue
- confirm-order
- confirm-order.vue
- payment
- payment.vue
- payment-success
- payment-success.vue
- login
- login.vue
- login-tel
login-tel.vue
- login-code
login-code.vue
- index
-
components 组件
- index
- Banner.vue
- Hot.vue
- Icons.vue
- indexSwiper.vue
- Recommend.vue
- Shop.vue
Tabbar.vue
- common
- Card.vue
- Commondity.vue
- CommondityList.vue
- Line.vue
- ShopList.vue
- order
- order-list.vue
- uni
- uni-number-box
- uni-number-box.vue
- uni-icons
- uni-icons.vue
- uni-nav-bar
- uni-nav-bar.vue
- mpvue-citypicker
- mpvueCityPicker.vue
- uni-number-box
- index
-
common 公共文件:全局css文件 || 全局js文件
- api
- request.js
- common.css
- uni.css
- api
-
store vuex状态机文件
- modules
- cart.js
- path.js
- user.js
order.js
- index.js
- modules