提示:文章寫完後,目錄可以自動生成,如何生成可參考右邊的幫助文檔
基于node vue的電商系統 mongodb express架構
- 前言
-
- 技術棧
- 基本功能
-
- 普通使用者
- 管理者
- 一、運作截圖?
- 二、使用步驟
-
- 1.前端main.js
- 2.後端admin路由
前言
技術棧
- 本項目采用前後端分離的開發方式,使用的技術棧是:Vue+Node+MongoDB
- 前端:用vue-cli搭建,使用vue全家桶+element-ui
- 後端:express架構
- 資料庫:mongodb
基本功能
普通使用者
- 注冊、登入
- 根據關鍵詞對商品模糊搜尋
- 根據分類查詢商品
- 商品詳情展示
- 加入購物車及建立訂單
- 商品評論
- 使用者個人中心(修改個人資訊及檢視訂單)
管理者
- 登入
- 使用者管理
- 權限管理
- 商品管理
- 訂單管理
- 資料統計
提示:以下是本篇文章正文内容,下面案例可供參考
一、運作截圖?
二、使用步驟
1.前端main.js
代碼如下(示例):
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'
Vue.config.productionTip = false
//圖檔懶加載
import LazyLoad from 'vue-lazyload'
Vue.use(LazyLoad, {
error:require('./assets/img/error.png'),
// 占位圖
loading:require('./assets/img/loading.png')
})
//引入ElementUI庫
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
Vue.use(ElementUI);
//省市區關聯
import VueAreaLinkage from 'vue-area-linkage';
import 'vue-area-linkage/dist/index.css';
Vue.use(VueAreaLinkage);
//引入圖示庫
import 'assets/fonts/iconfont.css'
//引入全局樣式
import 'assets/css/base.css'
//事件總線
Vue.prototype.$bus = new Vue();
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
//通過methods裡的代碼跳轉路由需要寫下面代碼: (不然重複點選會報錯)
import Router from 'vue-router'
const routerPush = Router.prototype.replace
Router.prototype.replace = function replace(location) {
return routerPush.call(this, location).catch(error => error)
}
2.後端admin路由
代碼如下(示例):
import express from 'express'
import mongoose from 'mongoose'
import path from 'path'
import md5 from 'blueimp-md5'
import formidable from 'formidable'
import config from '../src/config.js'
import {
Administrator,
User,
Category,
Goods,
Comment,
Order
} from '../db/db'
const router = express.Router();
const S_KEY = '[email protected]' //鹽
//管理者登入
router.post('/login', async (req, res) => {
let adminName = req.body.adminName;
let adminPsw = md5(md5(req.body.adminPsw) + S_KEY);
let result = await Administrator.findOne({
adminName
})
if (result) {
if (adminPsw === result.password) {
req.session.admin = adminName;
res.json({
status_code: 200,
message: '登入成功',
})
} else {
res.json({
status_code: 400,
message: '密碼錯誤'
})
}
} else {
res.json({
status_code: 400,
message: '使用者名不存在'
})
}
})
//設定背景通路權限
router.use((req, res, next) => {
if (!req.session.admin) {
res.json({
status_code: 400,
message: '無權通路'
})
}
next();
})
// 驗證登入狀态,若未被中間件攔截則為登入狀态
router.get('/isadmin', async (req, res) => {
console.log(req.session.admin)
if(req.session.admin){
let result = await Administrator.findOne({
adminName: req.session.admin
})
console.log(result)
res.json({
status_code: 200,
message: '進入管理者界面',
adminName: req.session.admin,
role: result.role
})
}
})
//登出
router.get('/logout', (req, res) => {
req.session.admin = '';
res.json({
status_code: 200,
message: '已登出'
})
})
/**************************************** 使用者管理 *******************************************/
//擷取使用者清單
router.get('/userlist', async (req, res) => {
let result;
if (req.query.userName) {
result = await User.find({
userName: {
$regex: req.query.userName,
$options: 'gi'
}
});
} else {
result = await User.find({});
}
res.json({
status_code: 200,
message: '擷取使用者清單成功',
total: result.length,
users: result
})
})
//添加使用者
router.post('/adduser', (req, res) => {
const form = new formidable.IncomingForm();
form.uploadDir = config.uploadsAvatarPath; // 上傳圖檔放置的檔案夾
form.keepExtensions = true; // 保持檔案的原始擴充名
form.parse(req, (err, fields, files) => {
let avatar;
if (fields.userSex == '男') {
avatar = 'http://localhost:' + config.port + '/boy_avatar.svg'
} else {
avatar = 'http://localhost:' + config.port + '/girl_avatar.svg'
}
if (files.userAvatar) {
avatar = 'http://localhost:' + config.port + '/avatar_uploads/' + path.basename(files.userAvatar.path);
}
let userInfo = {
userName: fields.userName,
password: md5(md5(fields.userPsw) + S_KEY), //加密密碼
userEmail: fields.userEmail,
userPhone: fields.userPhone,
userSex: fields.userSex,
userSign: fields.userSign,
userAdress: fields.userAdress,
nickName: fields.nickName,
// userAdress:fields.userAdress.replace(/,/g,''),
userAvatar: avatar
}
User.create(userInfo, (err, doc) => {
console.log(err, doc)
if (!err) {
res.json({
status_code: 200,
message: '添加使用者成功',
})
} else {
res.json({
status_code: 400,
message: '内部錯誤,添加使用者失敗',
})
}
})
})
})
//編輯使用者
router.post('/edituser', (req, res) => {
const form = new formidable.IncomingForm();
form.uploadDir = config.uploadsAvatarPath; // 上傳圖檔放置的檔案夾
form.keepExtensions = true; // 保持檔案的原始擴充名
form.parse(req, (err, fields, files) => {
let avatar;
let userInfo = {
userName: fields.userName,
userEmail: fields.userEmail,
userPhone: fields.userPhone,
userSex: fields.userSex,
userSign: fields.userSign,
userAdress: fields.userAdress,
nickName: fields.nickName
}
if (files.userAvatar) {
avatar = 'http://localhost:' + config.port + '/avatar_uploads/' + path.basename(files.userAvatar.path);
userInfo.userAvatar = avatar
}
if (fields.userPsw) {
userInfo.password = md5(md5(fields.userPsw) + S_KEY); //加密密碼
}
User.updateOne({
userName: fields.userName
}, userInfo).then((doc) => {
res.json({
status_code: 200,
message: '修改使用者成功',
})
}).catch((err) => {
res.json({
status_code: 400,
message: '内部錯誤,修改使用者資訊失敗',
})
})
})
})
//删除使用者
router.get('/deleteuser', (req, res) => {
let userName = req.query.userName;
User.findOneAndDelete({
userName
}).then((doc) => {
res.json({
status_code: 200,
message: '删除使用者成功',
})
}).catch((err) => {
res.json({
status_code: 400,
message: '内部錯誤,删除使用者失敗',
})
})
})
/**************************************** 權限管理 *******************************************/
//擷取管理者清單
router.get('/adminlist', async (req, res) => {
let result;
if (req.query.adminName) {
result = await Administrator.find({
adminName: {
$regex: req.query.adminName,
$options: 'gi'
}
});
} else {
result = await Administrator.find({});
}
res.json({
status_code: 200,
message: '擷取管理者清單成功',
total: result.length,
administrators: result
})
})
//添加管理者
router.post('/addadmin', (req, res) => {
let regFrom = req.body;
console.log(regFrom)
let adminInfo = {
adminName: regFrom.adminName,
password: md5(md5(regFrom.adminPsw) + S_KEY), //加密密碼
role: regFrom.adminRole
}
Administrator.create(adminInfo, (err, doc) => {
console.log(err, doc)
if (!err) {
res.json({
status_code: 200,
message: '添加管理者成功',
})
} else {
res.json({
status_code: 400,
message: '内部錯誤,添加管理者失敗',
})
}
})
})
//檢查管理者名是否已注冊
router.get('/checkname', async (req, res) => {
let adminName = req.query.adminName;
let isNameReg = await Administrator.findOne({
adminName
})
if (isNameReg) {
res.json({
status_code: 400,
message: '該名稱已注冊'
})
} else {
res.json({
status_code: 200,
message: '該名稱可以使用'
})
}
})
//編輯管理者
router.post('/editadmin', async (req, res) => {
let regFrom = req.body;
console.log(regFrom);
let adminInfo = {
adminName: regFrom.adminName,
role: regFrom.adminRole
}
if (regFrom.adminPsw) {
adminInfo.password = md5(md5(regFrom.adminPsw) + S_KEY); //加密密碼
}
Administrator.updateOne({
adminName: regFrom.adminName
}, adminInfo).then((doc) => {
res.json({
status_code: 200,
message: '修改管理者資訊成功',
})
}).catch((err) => {
res.json({
status_code: 400,
message: '内部錯誤,修改管理者資訊失敗',
})
})
})
//删除管理者
router.get('/deleteadmin', (req, res) => {
let adminName = req.query.adminName;
Administrator.findOneAndDelete({
adminName
}).then((doc) => {
res.json({
status_code: 200,
message: '删除管理者成功',
})
}).catch((err) => {
res.json({
status_code: 400,
message: '内部錯誤,删除管理者失敗',
})
})
})
/**************************************** 商品管理 *******************************************/
//擷取分類清單
router.get('/catelist', async (req, res) => {
let result;
if (req.query.cateId) {
result = await Category.find({
cateId: req.query.cateId
}).sort('cateId');
} else {
result = await Category.find({}).sort('cateId');
}
res.json({
status_code: 200,
message: '擷取分類清單成功',
total: result.length,
categories: result
})
})
//檢查分類ID是否已存在
router.get('/checkcateid', async (req, res) => {
let cateId = req.query.cateId;
let isIdReg = await Category.findOne({
cateId
})
if (isIdReg) {
res.json({
status_code: 400,
message: '此ID已被使用'
})
} else {
res.json({
status_code: 200,
message: '此ID可以使用'
})
}
})
//檢查分類名稱是否已存在
router.get('/checkcatename', async (req, res) => {
let cateName = req.query.cateName;
let isIdReg = await Category.findOne({
cateName
})
if (isIdReg) {
res.json({
status_code: 400,
message: '此名稱已被使用'
})
} else {
res.json({
status_code: 200,
message: '此名稱可以使用'
})
}
})
//添加分類
router.post('/addcate', (req, res) => {
let regFrom = req.body;
console.log(regFrom)
let cateInfo = {
cateId: regFrom.cateId,
cateName: regFrom.cateName,
cateCounts: 0,
cateSales: 0
}
Category.create(cateInfo, (err, doc) => {
console.log(err, doc)
if (!err) {
res.json({
status_code: 200,
message: '添加分類成功',
})
} else {
res.json({
status_code: 400,
message: '内部錯誤,添加分類失敗',
})
}
})
})
//編輯分類
router.post('/editcate', async (req, res) => {
let editFrom = req.body;
Category.updateOne({cateId: editFrom.cateId}, editFrom).then((doc) => {
res.json({status_code: 200,message: '修改分類資訊成功',})
}).catch((err) => {
res.json({status_code: 400,message: '内部錯誤,修改分類資訊失敗',})
})
})
//删除分類
router.get('/deletecate', (req, res) => {
let cateId = req.query.cateId;
Category.findOneAndDelete({
cateId
}).then(async (doc) => {
//删除商品下評論
let result = await Goods.find({
goodsCategory: cateId
})
console.log('result', result)
for (let i = 0; i < result.length; i++) {
await Comment.deleteMany({
goodsId: result[i].goodsId
})
}
//删除分類下所有商品
await Goods.deleteMany({
goodsCategory: cateId
})
res.json({
status_code: 200,
message: '删除分類成功',
})
}).catch((err) => {
res.json({
status_code: 400,
message: '内部錯誤,删除分類失敗',
})
})
})
//擷取商品清單
router.get('/goodslist', async (req, res) => {
let result;
if (req.query.goodsCategory) {
if (req.query.goodsId) {
let resultId = await Goods.find({
goodsId: req.query.goodsId,
goodsCategory: req.query.goodsCategory
}).sort('goodsCategory');
let resultName = await Goods.find({
goodsName: {
$regex: req.query.goodsId,
$options: 'gi'
},
goodsCategory: req.query.goodsCategory
}).sort('goodsCategory');
if (resultId.length != 0) {
result = resultId
} else {
result = resultName
}
} else {
result = await Goods.find({
goodsCategory: req.query.goodsCategory
}).sort('goodsCategory');
}
} else {
if (req.query.goodsId) {
let resultId = await Goods.find({
goodsId: req.query.goodsId
}).sort('goodsCategory');
let resultName = await Goods.find({
goodsName: {
$regex: req.query.goodsId,
$options: 'gi'
}
}).sort('goodsCategory');
if (resultId.length != 0) {
result = resultId
} else {
result = resultName
}
} else {
result = await Goods.find({}).sort('goodsCategory');
}
}
res.json({
status_code: 200,
message: '擷取分類清單成功',
total: result.length,
goods: result
})
})
//擷取商品的分類
router.get('/goodscate', async (req, res) => {
let result = await Category.findOne({cateId: req.query.cateId});
res.json({
status_code: 200,
message: '擷取分類資訊成功',
goodsCate: result.cateName
})
})
//檢查商品ID是否已存在
router.get('/checkgoodsid', async (req, res) => {
let goodsId = req.query.goodsId;
let isIdReg = await Goods.findOne({
goodsId
})
console.log(isIdReg)
if (isIdReg) {
res.json({
status_code: 400,
message: '此ID已被使用'
})
} else {
res.json({
status_code: 200,
message: '此ID可以使用'
})
}
})
//添加商品
router.post('/addgoods', (req, res) => {
const form = new formidable.IncomingForm();
form.uploadDir = config.uploadsGoodsPath; // 上傳圖檔放置的檔案夾
form.keepExtensions = true; // 保持檔案的原始擴充名
form.parse(req, (err, fields, files) => {
let goodsInfo = {
goodsId: fields.goodsId,
shortName: fields.shortName,
goodsName: fields.goodsName,
goodsPrice: fields.goodsPrice,
normalPrice: fields.normalPrice,
salesTips: fields.salesTips,
goodsCategory: fields.goodsCategory,
goodsCounts: Number(fields.goodsCounts),
goodsImg: 'http://localhost:' + config.port + '/uploads/' + path.basename(files.goodsImg.path),
goodsComments: 0
}
Goods.create(goodsInfo, async (err, doc) => {
//更新商品分類裡的商品數量
let result = await Goods.find({
goodsCategory: fields.goodsCategory
});
Category.updateOne({
cateId: fields.goodsCategory
}, {
cateCounts: result.length
}).then(doc => console.log('doc', doc)).catch(err => console.log('err', err))
if (!err) {
res.json({
status_code: 200,
message: '添加商品成功',
})
} else {
res.json({
status_code: 400,
message: '内部錯誤,添加商品失敗',
})
}
})
})
})
//編輯商品
router.post('/editgoods', (req, res) => {
const form = new formidable.IncomingForm();
form.uploadDir = config.uploadsGoodsPath; // 上傳圖檔放置的檔案夾
form.keepExtensions = true; // 保持檔案的原始擴充名
form.parse(req, (err, fields, files) => {
console.log(fields, files)
let goodsInfo = {
goodsId: fields.goodsId,
shortName: fields.shortName,
goodsName: fields.goodsName,
goodsPrice: fields.goodsPrice,
normalPrice: fields.normalPrice,
salesTips: fields.salesTips,
goodsCategory: fields.goodsCategory,
goodsCounts: Number(fields.goodsCounts),
}
if (files.goodsImg) {
goodsInfo.userAvatar = 'http://localhost:' + config.port + '/uploads/' + path.basename(files.goodsImg.path);
}
Goods.updateOne({
goodsId: fields.goodsId
}, goodsInfo).then(async (doc) => {
//更新編輯前商品分類裡的商品數量
let resultOld = await Goods.find({
goodsCategory: fields.goodsOldCate
});
Category.updateOne({
cateId: fields.goodsOldCate
}, {
cateCounts: resultOld.length
}).then(doc => console.log('doc', doc)).catch(err => console.log('err', err));
//更新編輯後商品分類裡的商品數量
let result = await Goods.find({
goodsCategory: fields.goodsCategory
});
Category.updateOne({
cateId: fields.goodsCategory
}, {
cateCounts: result.length
}).then(doc => console.log('doc', doc)).catch(err => console.log('err', err));
res.json({
status_code: 200,
message: '修改商品成功',
})
}).catch((err) => {
console.log(err)
res.json({
status_code: 400,
message: '内部錯誤,修改商品資訊失敗',
})
})
})
})
//删除商品
router.get('/deletegoods', (req, res) => {
let goodsId = req.query.goodsId;
let goodsCategory = req.query.goodsCategory;
Goods.findOneAndDelete({
goodsId
}).then(async (doc) => {
//删除該商品下所有評論
Comment.deleteMany({
goodsId
}).then(doc => console.log(doc))
//更新删除後商品分類裡的商品數量
let result = await Goods.find({
goodsCategory
});
Category.updateOne({
cateId: goodsCategory
}, {
cateCounts: result.length
}).then(doc => console.log('doc', doc)).catch(err => console.log('err', err));
res.json({
status_code: 200,
message: '删除商品成功',
})
}).catch((err) => {
res.json({
status_code: 400,
message: '内部錯誤,删除商品失敗',
})
})
})
/**************************************** 訂單管理 *******************************************/
//擷取訂單清單
router.get('/orderlist', async (req, res) => {
let result;
if (req.query.userName) {
let resultId = [];
if (req.query.userName.length == 24) {
resultId = await Order.find({
_id: mongoose.Types.ObjectId(req.query.userName)
}).sort('-orderTime');
}
let resultName = await Order.find({
userName: {
$regex: req.query.userName,
$options: 'gi'
}
}).sort('-orderTime');
if (resultId.length != 0) {
result = resultId
} else {
result = resultName
}
} else {
result = await Order.find({}).sort('-orderTime');
}
res.json({
status_code: 200,
message: '擷取訂單清單成功',
total: result.length,
orders: result
})
})
//編輯訂單資訊
router.post('/editorder', async (req, res) => {
let editFrom = req.body;
console.log(editFrom);
Order.updateOne({
_id: mongoose.Types.ObjectId(editFrom._id)
}, editFrom).then((doc) => {
res.json({
status_code: 200,
message: '修改訂單資訊成功',
})
}).catch((err) => {
console.log(err)
res.json({
status_code: 400,
message: '内部錯誤,修改訂單資訊失敗',
})
})
})
//删除訂單
router.get('/deleteorder', (req, res) => {
Order.findOneAndDelete({
_id: mongoose.Types.ObjectId(req.query._id)
}).then((doc) => {
res.json({
status_code: 200,
message: '删除訂單成功',
})
}).catch((err) => {
res.json({
status_code: 400,
message: '内部錯誤,删除訂單失敗',
})
})
})
/**************************************** 資料統計 *******************************************/
//擷取資料統計資料
router.get('/datalist', async (req, res) => {
let result = await Category.find({}).sort('cateId');
let xAxisData =[];
let seriesData = [];
for (let i = 0; i < result.length; i++) {
xAxisData.push(result[i].cateName);
seriesData.push(result[i].cateSales);
}
let option = {
title: {
text: '各分類月銷量'
},
tooltip: {},
legend: {
data: ['銷量']
},
xAxis: {
data: xAxisData
},
yAxis: {},
series: [{
name: '銷量',
type: 'bar',
data: seriesData
}]
};
console.log(xAxisData,seriesData,option)
res.json({
status_code: 200,
message: '擷取資料統計資訊成功',
option: option
})
})
export default router;
---
# 源碼
https://pan.baidu.com/s/1ADfDdHbOYui8vwOTzwCbUA?pwd=8767