商城后台管理系统 04 登录-功能实现-数据持久化-vuex

安装 jsonwebtoken(生成token) jwt-decode(解析token) 依赖
复制代码
code\vue-ego>npm i jsonwebtoken -S

code\vue-ego>npm i jwt-decode -S


<span>退出登录</span>

src/utils/localStoreage.js

复制代码
import store from '@/store/index.js'
// 持久化
let user = localStorage.getItem('user')
if (user) {
	user = JSON.parse(user);
	store.commit('loginModule/setUser', user);
}

src/main.js

复制代码
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import '@/plugins/element.js'
import '@/assets/css/reset.css'
import '@/assets/css/iconfont.css'

// 挂载 api 
import api from './api/index.js'
Vue.prototype.$api = api;

// 导入语言
import i18n from '@/lang/index.js'
import '@/router/permission.js'
import '@/utils/localStorage.js'

Vue.config.productionTip = false

// 持久化
// let user = localStorage.getItem('user')
// if (user) {
// 	user = JSON.parse(user);
// 	store.commit('loginModule/setUser', user);
// }

new Vue({
	router,
	store,
	i18n,
	render: function(h) {
		return h(App)
	}
}).$mount('#app')

src/router/permission.js

复制代码
import router from './index'

// 获取 vuex 数据
import store from '@/store/index.js'

// 路由拦截
router.beforeEach((to, from, next) => {
	// console.log('---to---', to);
	// 1, 判断是否需要登录
	if (to.matched.some(ele => ele.meta.isLogin)) {
		// 2, 判断当前的用户是否已经登录
		let token = store.state.loginModule.userinfo.token;
		if (token) {
			// 判断已登录
			next();
		} else { // 判断未登录
			// 跳转到登录页面
			next('/login');
		}
	} else { // 不需要登录
		next();
	}
})
login接口
复制代码
router.post('/login', (req, res) => {
	let {username,password} = req.body
	// 请求数据库
	let sql = "select * from userinfo where username=? and password=?";
	let arr = [username, password]
	sqlFn(sql, arr, result => {
		if (result.length > 0) {
			let token = jwt.sign({
				username: result[0].username,
				id: result[0].id
			}, config.jwtSecert, {
				expiresIn: 20 * 1
			})
			res.send({
				status: 200,
				data: token
			})
		} else {
			res.send({
				status: 404,
				msg: '信息错误'
			})
		}			
	})
})
登录接口(后端代码)
复制代码
// 登录接口
/**
 * 语法
 * 如 60,'2 day','10h','7d',expiration time 过期时间
 * jwt.sign({},'秘钥','过期时间',{expiresIn: 20*1,'1 day','1h'})
 */

router.post("/login", (req, res) => {
	let {
		username,
		password
	} = req.body
	// 请求数据库
	let sql = "select * from userinfo where username=? and password=?";
	let arr = [username, password]
	sqlFn(sql, arr, result => {
		if (result.length > 0) {
			let token = jwt.sign({
				username: result[0].username,
				id: result[0].id
			}, config.jwtSecert, {
				expiresIn: 20 * 1
			})
			res.send({
				status: 200,
				data: token
			})
		} else {
			res.send({
				status: 404,
				msg: '信息错误'
			})
		}
	})
})
注册接口(后端代码)
复制代码
/**
* 注册接口 /register
*/
router.post("/register", (req, res) => {
	const {
		username,
		password
	} = req.body;
	const sql = "insert into userinfo values(null,?,?)";
	const arr = [username, password];
	sqlFn(sql, arr, (result) => {
		if (result.affectedRows > 0) {
			res.send({
				msg: "注册成功",
				status: 200
			})
		} else {
			res.status(401).json({
				errors: "用户名密码错误"
			})
		}
	})
})
登录-功能实现-数据持久化-vuex 实现代码如下
复制代码
1, src/views/Login/Login.vue
<template>
	<div>
		<div class="login-box">
			<h3 class="title">登录界面</h3>
			<!-- <div>{{info}}</div> -->
			<el-form :model="loginForm" status-icon :rules="rules" ref="ruleForm" label-width="60px"
				class="demo-ruleForm">
				<el-form-item label="账号" prop="username" required>
					<el-input type="text" v-model="loginForm.username" autocomplete="off"></el-input>
				</el-form-item>
				<el-form-item label="密码" prop="password" required>
					<el-input type="password" v-model="loginForm.password" autocomplete="off"></el-input>
				</el-form-item>
				<el-form-item>
					<el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
					<el-button @click="resetForm('ruleForm')">重置</el-button>
				</el-form-item>
			</el-form>
		</div>
	</div>
</template>

<script>
	import jwt from 'jwt-decode'
	import {
		mapMutations
	} from 'vuex';
	export default {
		data() {
			var validateUser = (rule, value, callback) => {
				if (value === '') {
					callback(new Error('请输入账号'));
				} else {
					callback();
				}
			};
			var validatePass = (rule, value, callback) => {
				if (value === '') {
					callback(new Error('请输入密码'));
				} else {
					callback();
				}
			};
			return {
				// info: '',
				loginForm: {
					username: '',
					password: ''
				},
				rules: {
					username: [{
						validator: validateUser,
						trigger: 'blur'
					}],
					password: [{
						validator: validatePass,
						trigger: 'blur'
					}]
				}
			};
		},
		methods: {
			...mapMutations('loginModule', ['setUser']),
			submitForm(formName) {
				this.$refs[formName].validate((valid) => {
					if (valid) {
						console.log('效验通过', this.loginForm);
						let {
							username,
							password
						} = this.loginForm;
						console.log(username, password);
						// 请求登录接口-----
						this.$api.getLogin({
							username,
							password
						}).then(res => {
							console.log('----', res.data);
							if (res.data.status === 200) {
								console.log(jwt(res.data.data));
								// 登录成功后: 
								// 1,存储登录信息 
								let obj = {
									user: jwt(res.data.data).username,
									token: res.data.data
								};
								this.setUser(obj);
								// 2, 存储本地 将数据持久化
								localStorage.setItem('user', JSON.stringify(obj));
								// 3, 跳转
								this.$router.push('/');
								// 3, 顶部区域显示用户信息
								// 4, 跳转网页
								// this.info = ''
							} else {
								this.$message.error('错了哦,这是一条错误消息');
								// 用户名密码错误
								// this.info = '用户名密码错误'
							}
						})
					} else {
						console.log('error submit!!');
						return false;
					}
				});
			},
			resetForm(formName) {
				this.$refs[formName].resetFields();
			}
		}
	}
</script>

<style lang="less" scoped>
	.login-box {
		width: 600px;
		height: 300px;
		// 上下为100px,左右自由,掉在当中
		margin: 150px auto;
		// 添加阴影 10 px
		padding: 20px;
		border-radius: 10px;
		border: 1px solid #eee;
		background: #fff;
	}

	.title {
		margin-bottom: 40px;
		text-align: center;
		color: #666;
	}
</style>





2, src/views/Layout/Content.vue
<template>
	<div>
		<div class="header">
			<i v-if="!isCollapse" @click="changeMenu" class="iconfont icon-right-indent"></i>
			<i v-else @click="changeMenu" class="iconfont icon-left-indent"></i>
			<div class="header-right">
				<el-dropdown @command='clickLang'>
					<span class="el-dropdown-link" style="color: #fff;">
						选择语言<i class="el-icon-arrow-down el-icon--right"></i>
					</span>
					<el-dropdown-menu slot="dropdown">
						<el-dropdown-item command='zh'>中文</el-dropdown-item>
						<el-dropdown-item command='en'>English</el-dropdown-item>
						<!-- <el-dropdown-item>韩文</el-dropdown-item>
						<el-dropdown-item disabled>FR:法语</el-dropdown-item>
						<el-dropdown-item divided>LI:林堡语</el-dropdown-item> -->
					</el-dropdown-menu>
				</el-dropdown>
				<div class="user">
					欢迎: {{ userinfo.user }}
					<i class="iconfont icon-icon-tuichu" @click="loginout"></i>
				</div>
			</div>
		</div>
		<!-- 右侧内容区域 --左侧 路由出口 -->
		<div class="content">
			<!-- 路由出口 -->
			<router-view />
		</div>
	</div>
</template>

<script>
	import {
		mapState,
		mapMutations
	} from 'vuex';
	export default {
		props: ['isCollapse'],
		// 利用 vuex 的计算属性,读取数据
		computed: {
			...mapState('loginModule', ['userinfo'])
		},
		methods: {
			...mapMutations('loginModule', ['clearUser']),
			changeMenu() {
				// 点击切换按钮的时候,修改父组件的数据 isCollapse
				this.$emit('changeCollapse')
			},
			clickLang(command) {
				console.log(command);
				// console.log(this); // 打印参数
				this.$i18n.locale = command; // 切换语言
			},
			loginout() {
				// 退出登录
				// console.log(123);
				// 清空 vuex 数据
				this.clearUser()
				// 清空本地存储
				localStorage.removeItem('user')
				// 返回登录
				this.$router.push('/login')
			}
		},
	};
</script>

<style lang="less" scoped>
	.header {
		height: 50px;
		line-height: 50px;
		color: #fff;
		background: #1e78bf;

		.iconfont {
			font-size: 24px;
		}
	}

	.header-right {
		display: flex;
		float: right;
		padding-right: 20px;

		.user {
			margin-left: 20px;
		}
	}
</style>



3, src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import loginModule from '@/store/modules/loginModules.js'

Vue.use(Vuex)

export default new Vuex.Store({
	state: {},
	getters: {},
	mutations: {},
	actions: {},
	// 注册
	modules: {
		loginModule
	}
})





4, src/store/modules/loginModules.js
export default {
	// 命名空间
	namespaced: true,
	// 数据
	state: {
		userinfo: {
			user: '',
			token: ''
		}
	},
	// 设置
	mutations: {
		// 设置用户信息
		setUser(state, payload) {
			state.userinfo = payload;
		},
		// 清空
		clearUser(state) {
			state.userinfo = {
				user: '',
				token: ''
			}
		}
	},
	// 方法
	actions: {
		//
	}
}





5, src/router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import Layout from '@/views/Layout/index.vue'
import Home from '@/views/Home/index.vue'
import Login from '@/views/Login/Login.vue'

// 异步
const Goods = () => import('../views/Goods/Goods.vue')
const Params = () => import('../views/Params/Params.vue')
const Advert = () => import('../views/Advert/Advert.vue')
const My = () => import('../views/My/My.vue')
const Logistics = () => import('../views/Logistics/Logistics.vue')
const Order = () => import('../views/Order/index.vue')
const OrderList = () => import('../views/Order/OrderList/index.vue')
const OrderBack = () => import('../views/Order/OrderBack/index.vue')

// 子级路由
const AddGoods = () => import('../views/Goods/AddGoods.vue')


Vue.use(VueRouter)

const routes = [{
		path: '',
		component: Layout,
		// 路由的元信息
		meta: {
			isLogin: true
		},
		children: [{
			path: '/',
			name: 'Home',
			component: Home
		}, {
			path: '/goods',
			name: 'Goods',
			component: Goods
		}, {
			path: '/add-goods',
			name: 'AddGoods',
			component: AddGoods
		}, {
			path: '/params',
			name: 'Params',
			component: Params
		}, {
			path: '/advert',
			name: 'Advert',
			component: Advert
		}, {
			path: '/my',
			name: 'My',
			component: My
		}, {
			path: '/logistics',
			name: 'Logistics',
			component: Logistics
		}, {
			path: '/order',
			name: 'Order',
			component: Order,
			redirect: '/order/order-list',
			children: [{
				path: 'order-list',
				component: OrderList
			}, {
				path: 'order-back',
				component: OrderBack
			}]
		}]
	},
	{
		path: '/login',
		name: 'Login',
		component: Login,
	}
]

const router = new VueRouter({
	mode: 'history',
	base: process.env.BASE_URL,
	routes
})



export default router





6, src/router/permission.js
import router from '@/router/index.js';

// 获取 vuex 数据
import store from '@/store/index.js'

// 路由拦截
router.beforeEach((to, from, next) => {
	// console.log('---to---', to);
	// 1, 判断是否需要登录
	if (to.matched.some(ele => ele.meta.isLogin)) {
		// 2, 判断当前的用户是否已经登录
		let token = store.state.loginModule.userinfo.token;
		if (token) {
			// 判断已登录
			next();
		} else { // 判断未登录
			// 跳转到登录页面
			next('/login');
		}
	} else { // 不需要登录
		next();
	}
})





7, src/utils/localStorage.js
import store from '@/store/index.js'
// 持久化
let user = localStorage.getItem('user')
if (user) {
	user = JSON.parse(user);
	store.commit('loginModule/setUser', user);
}





8, src/api/base.js
/**
 * 接口的路径配置:
 * 一般文件目录: base.js index.js
 * 	base.js : 放所有路径的配置
 *  index.js: 放所有请求的方法
 */

const base = {
	host: 'http://localhost:8989', // 基础域名
	goodsList: '/api/api/projectList', // 商品列表
	search: '/api/api/search', // 商品的搜索功能
	selectCategory: '/api/api/backend/itemCategory/selectItemCategoryByParentId', // 类目选择
	uploadUrl: '/api/api/upload', // 图片上传  post请求
	addGoods: '/api/api/backend/item/insertTbItem', // 添加商品 
	deleteGoods: '/api/api/backend/item/deleteItemById', // 删除商品
	updateGoods: '/api/api/backend/item/updateTbItem', // 编辑商品
	login: '/api/api/login', // 登录接口
}

export default base;




9, src/api/index.js
/**
 * 所有请求的方法
 */

import axios from "axios";
import base from "./base";
// node>js
const qs = require('querystring');

const api = {
	/**
	 * 登录接口
	 */
	getLogin(params) { // params={username:'',password:''}
		// console.log('=====', params, qs.stringify(params));
		return axios.post(base.login, qs.stringify(params))
	},
	/**
	 * 商品列表方法
	 */
	getGoodsList(params) { // {page:xx}
		return axios.get(base.goodsList, {
			params
		})
	},
	/**
	 * 搜索商品数据方法
	 * search
	 */
	getSearch(params) { // {search: xx}
		return axios.get(base.search, {
			params
		})
	},
	/**
	 * 获取类目选择
	 * {id: cid}
	 */
	getSelectCategory(params) {
		return axios.get(base.selectCategory, {
			params
		})
	},
	/**
	 * 添加商品
	 * 参数: title cid category sellPoint price num desc paramsInfo image
	 */
	addGoods(params) { // = {}
		return axios.get(base.addGoods, {
			params
		})
	},
	/**
	 * 删除商品 id
	 */
	deleteGoods(params) {
		return axios.get(base.deleteGoods, {
			params
		})
	},
	/**
	 * 编辑商品 id
	 */
	updateGoods(params) {
		return axios.get(base.updateGoods, {
			params
		})
	},
}

export default api;







10, src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import '@/plugins/element.js'
import '@/assets/css/reset.css'
import '@/assets/css/iconfont.css'

// 挂载 api 
import api from './api/index.js'
Vue.prototype.$api = api;

// 导入语言
import i18n from '@/lang/index.js'
import '@/router/permission.js'
import '@/utils/localStorage.js'

Vue.config.productionTip = false

// 持久化
// let user = localStorage.getItem('user')
// if (user) {
// 	user = JSON.parse(user);
// 	store.commit('loginModule/setUser', user);
// }

new Vue({
	router,
	store,
	i18n,
	render: function(h) {
		return h(App)
	}
}).$mount('#app')





11, server/secert.js


module.exports = {
	jwtSecert: 'lalalahahahazhousil'
}






12, server/router.js

// 专门放所有的接口  这里只写一部分大约有二十几个接口

// 导入 express 
const express = require('express')
// 使用里面的 Router() 这个方法
const router = express.Router()


// token  导入模块 jsonwebtoken 秘钥
const jwt = require('jsonwebtoken')

// 秘钥 config.jwtSecert
const config = require('./secert.js')

// 导入数据库 sqlFn('sql',[],res=>{})
const sqlFn = require('./mysql.js')

// 图片上传支持的模块 导入 multer 导入 fs
const multer = require('multer')
const fs = require('fs')


// 测试接口
// router.get('/', (req, res) => {
// 	res.send('hello')
// })

// 路由接口

// 登录接口
/**
 * 语法
 * 如 60,'2 day','10h','7d',expiration time 过期时间
 * jwt.sign({},'秘钥','过期时间',{expiresIn: 20*1,'1 day','1h'})
 */
/**
 * 登录 login
 * 接收的字段: username password
 * postman
 */
router.post('/login', (req, res) => {
	console.log('获取前端传递的参数', username, password);
	let {
		username,
		password
	} = req.body
	// 请求数据库
	let sql = "select * from userinfo where username=? and password=?";
	let arr = [username, password]
	console.log(arr);
	sqlFn(sql, arr, result => {
		if (result.length > 0) {
			let token = jwt.sign({
				username: result[0].username,
				id: result[0].id
			}, config.jwtSecert, {
				expiresIn: 20 * 1
			})
			res.send({
				status: 200,
				data: token
			})
		} else {
			res.send({
				status: 404,
				msg: '信息错误'
			})
		}
	})
})


// router.post("/login", (req, res) => {
// 	let {
// 		username,
// 		password
// 	} = req.body
// 	// 请求数据库
// 	let sql = "select * from userinfo where username=? and password=?";
// 	let arr = [username, password]
// 	sqlFn(sql, arr, result => {
// 		if (result.length > 0) {
// 			let token = jwt.sign({
// 				username: result[0].username,
// 				id: result[0].id
// 			}, config.jwtSecert, {
// 				expiresIn: 20 * 1
// 			})
// 			res.send({
// 				status: 200,
// 				data: token
// 			})
// 		} else {
// 			res.send({
// 				status: 404,
// 				msg: '信息错误'
// 			})
// 		}
// 	})
// })

/**
 * 注册接口 /register
 */
/**
 * 注册接口 /register
 */
router.post("/register", (req, res) => {
	const {
		username,
		password
	} = req.body;
	const sql = "insert into userinfo values(null,?,?)";
	const arr = [username, password];
	sqlFn(sql, arr, (result) => {
		if (result.affectedRows > 0) {
			res.send({
				msg: "注册成功",
				status: 200
			})
		} else {
			res.status(401).json({
				errors: "用户名密码错误"
			})
		}
	})
})

/**
 * 商品列表:获取分页 {total: '',arr:[{},{},{}],pagesize:8,}
 * 参数:page 页码
 */
router.get('/projectList', (req, res) => {
	const page = req.query.page || 1;
	const sqlLen = "select * from project where id";
	sqlFn(sqlLen, null, data => {
		let len = data.length;
		const sql = "select * from project order by id desc limit 8 offset" + (page - 1) * 8;
		sqlFn(sql, null, result => {
			if (result.length > 0) {
				res.send({
					status: 200,
					data: result,
					pageSize: 8,
					total: len
				})
			} else {
				res.send({
					status: 200,
					msg: "暂无数据"
				})
			}
		})
	})
})


// router.get('/projectList', (req, res) => {
// 	// 接收页码 可以不传 默认为1
// 	const page = req.query.page || 1;
// 	// 根据 id 去查 project 表
// 	const sqlLen = "select * from project where id";

// 	sqlFn(sqlLen, null, data => {
// 		let len = data.length;
// 		const sql = "select * from project order by id desc limit 8 offset" + (page - 1) * 8;
// 		sqlFn(sql, null, result => {
// 			if (result.length > 0) {
// 				// 返回数据
// 				res.send({
// 					status: 200,
// 					data: result,
// 					pageSize: 8,
// 					total: len
// 				})
// 			} else {
// 				// 返回数据
// 				res.send({
// 					status: 500,
// 					msg: "暂无数据"
// 				})
// 			}
// 		})
// 	})
// })


/**
 * 商品查询接口 search
 * 参数: search
 */
router.get("/search", (req, res) => {
	var search = req.query.search;
	const sql = "select * from project where concat(`title`,`sellPoint`,`descs`) like '%" + search + "%'";
	sqlFn(sql, null, (result) => {
		if (result.length > 0) {
			res.send({
				status: 200,
				data: result
			})
		} else {
			res.send({
				status: 500,
				msg: '暂无数据'
			})
		}
	})
})


/** 类目选择
 * 接口说明:接口不同的参数 cid 返回不同的类目数据,后台接受变量 id
 */
router.get('/backend/itemCategory/selectItemCategoryByParentId', (req, res) => {
	const id = req.query.id || 1;
	const sql = 'select * from category where id=?'
	var arr = [id];
	sqlFn(sql, arr, result => {
		if (result.length > 0) {
			res.send({
				status: 200,
				result
				// data: result
			})
		} else {
			res.send({
				status: 500,
				msg: '暂无数据'
			})
		}
	})
})


/**
 * 类目结构数据获取
 */
router.get('/category/data', (req, res) => {
	var cid = req.query.cid;
	var sql = "select * from params where itemCatId=?";
	sqlFn(sql, [cid], result => {
		if (result.length > 0) {
			res.send({
				status: 200,
				result
				// data: result
			})
		} else {
			res.send({
				status: 500,
				msg: '暂无数据'
			})
		}
	})
})


/**
 * 上传图片 post 请求 upload
 * 说明:
 * 1, 后台安装 multer 图片模块 同时引入 fs 文件模块  
 * 2,router.js 入口文件导入 模块
 *	const fs = require('fs')	//fs是属于nodejs,只需引入即可
 *	const multer=require('multer') // multer是需要安装的
 * 3, 上传图片 可以跨域 需要配置 cors index.js 导入文件,并配置 cors跨域
 * 4, 在服务端 server 根目录下创建 upload 文件夹,专门装图片的文件
 */
var storage = multer.diskStorage({
	destination: function(req, file, cb) {
		cb(null, './upload/')
	},
	filename: function(req, file, cb) {
		cb(null, Date.now() + "-" + file.originalname)
	}
})

var createFolder = function(folder) {
	try {
		fs.accessSync(folder);
	} catch (e) {
		fs.mkdirSync(folder);
	}
}

var uploadFolder = './upload';
createFolder(uploadFolder);
var upload = multer({
	storage: storage
});

router.post('/upload', upload.single('file'), function(req, res, next) {
	var file = req.file;
	console.log('文件类型,%s', file.mimetype);
	console.log('原始文件名,%s', file.originalname);
	console.log('文件大小,%s', file.size);
	console.log('文件保存路径,%s', file.path);
	res.json({
		res_code: '0',
		name: file.originalname,
		url: file.path
	});
});


/**
 * 商品添加接口
 * 参数: title cid category sellPoint price num descs paramsInfo image
 */
router.get('/backend/item/insertTbItem', (req, res) => {
	// 获取参数
	var title = req.query.title || "";
	var cid = req.query.cid || "";
	var category = req.query.category || "";
	var sellPoint = req.query.sellPoint || "";
	var price = req.query.price || "";
	var num = req.query.num || "";
	var desc = req.query.descs || "";
	var paramsInfo = req.query.paramsInfo || "";
	var image = req.query.image || "";

	const sql = "insert into project values (null,?,?,?,?,?,?,?,'',1,'','',?,?)"
	var arr = [title, image, sellPoint, price, cid, category, num, desc, paramsInfo];
	sqlFn(sql, arr, result => {
		if (result.affectedRows > 0) {
			res.send({
				status: 200,
				msg: "添加成功"
			})
		} else {
			res.send({
				status: 500,
				msg: "添加失败"
			})
		}
	})
})


/**
 * 商品删除 接口 id
 */
router.get("/backend/item/deleteItemById", (req, res) => {
	// 后端接收前端传递的数据
	var id = req.query.id;
	const sql = "delete from project where id=?"
	const arr = [id];
	sqlFn(sql, arr, result => {
		if (result.affectedRows > 0) {
			res.send({
				status: 200,
				msg: "删除成功"
			})
		} else {
			res.send({
				status: 500,
				msg: '删除失败'
			})
		}
	})
})


/**
 * 批量删除: batchDelete idArr id 标识
 * sql = "delete from A where in in (1,2,3)"
 */
router.get("/batchDelete", (req, res) => {
	let arr = req.query.idArr; // []数组格式 需要传递数据是 离散的数字格式
	// const sql = 'delete from project where id in (?)';
	let sql = '';

	function fun(arr) { // sql=`delete from project where id in (101,102,103`;
		sql = `delete from project where id in (`
		for (let i = 0; i < arr.length; i++) {
			sql += arr[i] + ',' // 101,102,
		}
		sql = sql.slice(0, -1)
		sql = sql + ')'
		// console.log(sql);
	}
	fun(arr)
	sqlFn(sql, null, result => {
		if (result.affectedRows > 0) {
			res.send({
				status: 200,
				msg: "删除成功"
			})
		} else {
			res.send({
				status: 500,
				msg: "删除失败"
			})
		}
	})



	/**
	 * 修改商品
	 */
	router.get("/backend/item/updateTbItem", (req, res) => {
		var id = req.query.id;
		var title = req.query.title || "";
		var sellPoint = req.query.sellPoint || "";
		var price = req.query.price || "";
		var cid = req.query.cid || "";
		var category = req.query.category || "";
		var num = req.query.num || "";
		var desc = req.query.descs || "";
		var paramsInfo = req.query.paramsInfo || "";
		var image = req.query.image || "";
		var sql =
			"update project set title=?,sellPoint=?,price=?,cid=?,category=?,num=?,descs=?,paramsInfo=?,image=?"
		var arr = [title, sellPoint, price, cid, category, num, descs, paramsInfo, image, id];
		sqlFn(sql, arr, result => {
			if (result.affectedRows > 0) {
				res.send({
					status: 200,
					msg: "修改成功"
				})
			} else {
				res.send({
					status: 500,
					msg: "修改失败"
				})
			}
		})
	})
})



// =====================


/**
 * 内容分类管理 内容查询
 */
router.get("/content/selectTbContentAllByCategoryId", (req, res) => {
	const pid = req.query.pid;
	const sql = "select * from contentinfo where pid=?"
	sqlFn(sql, [pid], result => {
		if (result.length > 0) {
			res.send({
				status: 200,
				result
			})
		} else {
			res.send({
				status: 500,
				msg: "暂无数据"
			})
		}
	})
})



/**
 * 统计数据--销售信息
 */
router.get('/statistical', (req, res) => {
	res.send(Mock.mock({
		success: true,
		status: 200,
		"list|4": [{
			'id|+1': 100,
			"title|+1": ['总销售额', '访问量', '支付总量', '收藏量'],
			"current|0-2000": 100,
			"total|100-999999": 200
		}]
	}))
})


module.exports = router





13, server/mysql.js

// 连接数据库 1,安装mysql 2, 创建连接
const mysql = require('mysql')

// 创建数据库连接
const client = mysql.createConnection({
	host: 'localhost', // 数据域名 地址
	user: 'longchi18', // 数据库用户名称
	password: 'longchi18', // 数据库密码 xampp 集成
	database: 'vue_ego',
	port: '3306'
})

// 封装数据库操作语句 sql语句 参数数组 arr callback 成功函数结果 老师的
function sqlFn(sql, arr, callback) {
	client.query(sql, arr, function(error, result) {
		if (error) {
			console.log('数据库语句错误');
			return;
		}
		callback(result);
	})
}

module.exports = sqlFn;
相关推荐
毕设源码-朱学姐15 小时前
【开题答辩全过程】以 工厂能耗分析平台的设计与实现为例,包含答辩的问题和答案
java·vue.js
老前端的功夫17 小时前
Vue 3 性能深度解析:从架构革新到运行时的全面优化
javascript·vue.js·架构
前端 贾公子17 小时前
vue移动端适配方案 === postcss-px-to-viewport
前端·javascript·html
GISer_Jing18 小时前
AI营销增长:4大核心能力+前端落地指南
前端·javascript·人工智能
前端小端长19 小时前
Vue 中 keep-alive 组件的原理与实践详解
前端·vue.js·spring
m0_4711996320 小时前
【场景】前端怎么解决离线收银、数据同步异常等场景问题
前端·javascript
小胖霞21 小时前
企业级全栈项目(14) winston记录所有日志
vue.js·前端框架·node.js
栀秋66621 小时前
“无重复字符的最长子串”:从O(n²)哈希优化到滑动窗口封神,再到DP降维打击!
前端·javascript·算法