项目介绍
基于Vue的校园二手物品交易平台是一款专门为用户设计的在线交易系统,旨在提供一个简洁高效、安全可靠的二手商品买卖环境。利用Vue框架的响应式数据绑定和组件化特点,该平台实现了一个用户友好的界面,使得商品浏览、发布和管理变得异常轻松。这个基于Vue的校园二手物品交易平台不仅方便了校园内的物品循环使用,降低了用户的开销,而且促进了环保意识的提升,为构建绿色校园文化贡献了一份力量。
该系统利用Nodejs语言、MySQL数据库,结合目前流行的 B/S架构,将用户管理的各个方面都集中到数据库中,以便于用户的需要。该系统在确保系统稳定的前提下,能够实现多功能模块的设计和应用。该系统由管理员功能模块和用户功能模块组成。不同角色的准入制度是有严格区别的。各功能模块的设计也便于以后的系统升级和维护。该系统采用了软件组件化、精化体系结构、分离逻辑和数据等方法。
开发环境
编程语言:nodejs
数据库 :mysql
系统架构:b/s
前端技术:vue
运行工具:vs code
支持定做:java/php/python/android/小程序vue/爬虫/c#/asp.net
系统截图
核心代码
import { version } from '../../package.json'
import { Router } from 'express'
import { Sequelize, Op,literal, QueryTypes } from 'sequelize'
import sequelize from '../models/sequelize'
import toRes from '../lib/toRes'
import CartModel from '../models/CartModel'
import util from '../lib/util'
import jwt from 'jsonwebtoken'
import moment from 'moment'
import ConfigModel from '../models/ConfigModel'
import https from 'https'
import request from 'request'
import qs from 'querystring'
import path from 'path'
import fs from 'fs'
import config from '../config.json'
const redis = require('redis')
export default ({ config, db }) => {
let api = Router()
// 分页接口(后端)
api.get('/page', async (req, res) => {
try {
let page = parseInt(req.query.page) || 1
let limit = parseInt(req.query.limit) || 10
let sort = req.query.sort || 'id'
let order = req.query.order || 'asc'
let where = {}
let tablename = req.query.tablename
if (tablename) {
if (tablename.indexOf('%') != -1) {
where.tablename = {
[Op.like]: tablename
}
} else {
where.tablename = {
[Op.eq]: tablename
}
}
}
let userid = req.query.userid
if (userid) {
if (userid.indexOf('%') != -1) {
where.userid = {
[Op.like]: userid
}
} else {
where.userid = {
[Op.eq]: userid
}
}
}
let goodid = req.query.goodid
if (goodid) {
if (goodid.indexOf('%') != -1) {
where.goodid = {
[Op.like]: goodid
}
} else {
where.goodid = {
[Op.eq]: goodid
}
}
}
let goodname = req.query.goodname
if (goodname) {
if (goodname.indexOf('%') != -1) {
where.goodname = {
[Op.like]: goodname
}
} else {
where.goodname = {
[Op.eq]: goodname
}
}
}
let picture = req.query.picture
if (picture) {
if (picture.indexOf('%') != -1) {
where.picture = {
[Op.like]: picture
}
} else {
where.picture = {
[Op.eq]: picture
}
}
}
let buynumber = req.query.buynumber
if (buynumber) {
if (buynumber.indexOf('%') != -1) {
where.buynumber = {
[Op.like]: buynumber
}
} else {
where.buynumber = {
[Op.eq]: buynumber
}
}
}
let price = req.query.price
if (price) {
if (price.indexOf('%') != -1) {
where.price = {
[Op.like]: price
}
} else {
where.price = {
[Op.eq]: price
}
}
}
let zhanghao = req.query.zhanghao
if (zhanghao) {
if (zhanghao.indexOf('%') != -1) {
where.zhanghao = {
[Op.like]: zhanghao
}
} else {
where.zhanghao = {
[Op.eq]: zhanghao
}
}
}
if (jwt.decode(req.headers.token).role != '管理员') {
where.userid = {
[Op.eq]: req.session.userinfo === undefined ? jwt.decode(req.headers.token).id : req.session.userinfo.id
}
}
let orders =[]
const sortList = sort.split(",")
const orderList = order.split(",")
sortList.forEach((item, index) => {
orders.push([item,orderList[index]])
});
let result = await CartModel.findAndCountAll({
order: [orders],
where,
offset: (page - 1) * limit,
limit
})
result.currPage = page
result.pageSize = limit
toRes.page(res, 0, result)
} catch(err) {
res.status(500).render(err)
//toRes.session(res, 500, '服务器错误!', '', 500)
}
})
// 分页接口(前端)
api.get('/lists', async (req, res) => {
try {
let result = await CartModel.findAll()
toRes.record(res, 0, result)
} catch(err) {
toRes.session(res, 401, '您的权限不够!', '', 200)
}
})
// 分页接口(前端)
api.get('/list', async (req, res) => {
try {
let page = parseInt(req.query.page) || 1
let limit = parseInt(req.query.limit) || 10
let sort = req.query.sort || 'id'
let order = req.query.order || 'asc'
let where = {}
let userid = req.query.userid
let goodid = req.query.goodid
if (userid) {
where.userid = {
[Op.eq]: userid
}
}
if (goodid) {
where.goodid = {
[Op.eq]: goodid
}
}
let orders =[]
const sortList = sort.split(",")
const orderList = order.split(",")
sortList.forEach((item, index) => {
orders.push([item,orderList[index]])
});
let result = await CartModel.findAndCountAll({
order: [orders],
where,
offset: (page - 1) * limit,
limit
})
result.currPage = page
result.pageSize = limit
toRes.page(res, 0, result)
} catch(err) {
toRes.session(res, 401, '您的权限不够!', '', 200)
}
})
// 保存接口(后端)
api.post('/save', async (req, res) => {
try {
Object.keys(req.body).forEach(item=>{
if(req.body[item] == '') delete req.body[item]
if(req.body[item] == '' && item == 'sfsh') req.body[item] = '待审核'
})
if (!req.body.userid) {
req.body.userid = req.session.userinfo === undefined ? jwt.decode(req.headers.token).id : req.session.userinfo.id
}
const userinfo = await CartModel.create(req.body)
if (userinfo === null) {
toRes.session(res, -1, '添加失败!')
} else {
toRes.session(res, 0, '添加成功!')
}
} catch(err) {
toRes.session(res, 500, '服务器错误!', '', 500)
}
})
// 保存接口(前端)
api.post('/add', async (req, res) => {
try {
Object.keys(req.body).forEach(item=>{
if(req.body[item] == '') delete req.body[item]
if(req.body[item] == '' && item == 'sfsh') req.body[item] = '待审核'
})
if (jwt.decode(req.headers.token) == null) {
toRes.session(res, 401, '请登录后再操作', '', 401)
}
req.body.userid = req.session.userinfo === undefined ? jwt.decode(req.headers.token).id : req.session.userinfo.id
const userinfo = await CartModel.create(req.body)
if (userinfo === null) {
toRes.session(res, -1, '添加失败!')
} else {
toRes.session(res, 0, '添加成功!')
}
} catch(err) {
toRes.session(res, 500, '服务器错误!', '', 500)
}
})
// 更新接口
api.post('/update', async (req, res) => {
try {
await CartModel.update(req.body, {
where: {
id: req.body.id || 0
}
})
toRes.session(res, 0, '编辑成功!')
} catch(err) {
toRes.session(res, 500, '服务器错误!', '', 500)
}
})
// 删除接口
api.post('/delete', async (req, res) => {
try {
await CartModel.destroy({
where: {
id: {
[Op.in]: req.body
}
}
})
toRes.session(res, 0, '删除成功!')
} catch(err) {
toRes.session(res, 500, '服务器错误!', '', 500)
}
})
// 详情接口(后端)
api.all('/info/:id', async (req, res) => {
try {
toRes.record(res, 0, await CartModel.findOne({ where: { id: req.params.id } }))
} catch(err) {
toRes.session(res, 500, '服务器错误!', '', 500)
}
})
// 详情接口(前端)
api.all('/detail/:id', async (req, res) => {
try {
toRes.record(res, 0, await CartModel.findOne({ where: { id: req.params.id } }))
} catch(err) {
toRes.session(res, 500, '服务器错误!', '', 500)
}
})
// 获取需要提醒的记录数接口
api.get('/remind/:columnName/:type', async (req, res) => {
let where = ' 1=1 '
try {
let sql = 'SELECT 0 AS count'
if (req.params.type == 1) {
if (req.query.remindstart) sql = "SELECT COUNT(*) AS count FROM cart WHERE " + where + " AND " + req.params.columnName + " >= '" + req.query.remindstart + "'"
if (req.query.remindend) sql = "SELECT COUNT(*) AS count FROM cart WHERE " + where + " AND " + req.params.columnName + " <= '" + req.query.remindend + "'"
if (req.query.remindstart && req.query.remindend) {
sql = "SELECT COUNT(*) AS count FROM cart WHERE " + where + " AND " + req.params.columnName + " >= '" + req.query.remindstart + "' AND " + req.params.columnName + " <= '" + req.query.remindend + "'"
}
}
if (req.params.type == 2) {
if (req.query.remindstart) {
let remindStart = util.getDateTimeFormat(0 + Number(req.query.remindstart), "yyyy-MM-dd")
sql = "SELECT COUNT(*) AS count FROM cart WHERE " + where + " AND " + req.params.columnName + " >= '" + remindStart + "'"
}
if (req.query.remindend) {
let remindEnd = util.getDateTimeFormat(req.query.remindend, "yyyy-MM-dd")
sql = "SELECT COUNT(*) AS count FROM cart WHERE " + where + " AND " + req.params.columnName + " <= '" + remindEnd + "'"
}
if (req.query.remindstart && req.query.remindend) {
let remindStart = util.getDateTimeFormat(0 + Number(req.query.remindstart), "yyyy-MM-dd")
let remindEnd = util.getDateTimeFormat(req.query.remindend, "yyyy-MM-dd")
sql = "SELECT COUNT(*) AS count FROM cart WHERE " + where + " AND " + req.params.columnName + " >= '" + remindStart + "' AND " + req.params.columnName + " <= '" + remindEnd + "'"
}
}
const results = await sequelize.query(sql, {
plain: true,
raw: true,
type: QueryTypes.SELECT
})
toRes.count(res, 0, results.count)
} catch(err) {
toRes.session(res, 500, '服务器错误!', '', 500)
}
})
// 分组统计接口
api.get('/group/:columnName', async (req, res) => {
try {
let sql = ""
let columnName = req.params.columnName
// let tableName = "cart"
let where = " WHERE 1 = 1 "
sql = "SELECT COUNT(*) AS total, " + columnName + " FROM cart " + where + " GROUP BY " + columnName
toRes.record(res, 0, await sequelize.query(sql, {
plain: false,
raw: true,
type: QueryTypes.SELECT
}))
} catch(err) {
toRes.session(res, 500, '服务器错误!', '', 500)
}
})
// 统计指定字段
api.get('/value/:xColumnName/:yColumnName', async (req, res) => {
try {
let sql = ""
let xColumnName = req.params.xColumnName
let yColumnName = req.params.yColumnName
let where = " WHERE 1 = 1 "
if ("cart" == "orders") {
where += " AND status IN ('已支付', '已发货', '已完成') ";
}
sql = "SELECT " + xColumnName + ", SUM(" + yColumnName + ") AS total FROM cart " + where + " GROUP BY " + xColumnName + " DESC"
toRes.record(res, 0, await sequelize.query(sql, {
plain: false,
raw: true,
type: QueryTypes.SELECT
}))
} catch(err) {
toRes.session(res, 500, '服务器错误!', '', 500)
}
})
// (按值统计)时间统计类型(多)
api.get('/valueMul/:xColumnName', async (req, res) => {
try {
let sql = ""
let xColumnName = req.params.xColumnName
let yColumnName = req.query.yColumnNameMul
let tableName = "cart"
let where = " WHERE 1 = 1 "
const promises = yColumnName.split(',').map(async(item)=>{
sql = "SELECT " + xColumnName + ", sum(" + item + ") total FROM " + tableName + where + " GROUP BY " + xColumnName;
const results = await sequelize.query(sql, {
plain: false,
raw: true,
type: QueryTypes.SELECT
});
return results;
})
toRes.record(res, 0, await Promise.all(promises))
} catch(err) {
toRes.session(res, 500, '服务器错误!', '', 500)
}
})
// (按值统计)时间统计类型(多)
api.get('/valueMul/:xColumnName/:timeStatType', async (req, res) => {
try {
let sql = ""
let xColumnName = req.params.xColumnName
let yColumnName = req.query.yColumnNameMul
let timeStatType = req.params.timeStatType
let tableName = "cart"
let where = " WHERE 1 = 1 "
const promises = yColumnName.split(',').map(async(item)=>{
sql = "SELECT " + xColumnName + ", sum(" + item + ") total FROM " + tableName + where + " GROUP BY " + xColumnName;
if (config.dbConnection.dbtype.toLowerCase() == "mysql") {
if (timeStatType == "日")
sql = "SELECT DATE_FORMAT(" + xColumnName + ", '%Y-%m-%d') " + xColumnName + ", sum(" + item + ") total FROM " + tableName + where + " GROUP BY DATE_FORMAT(" + xColumnName + ", '%Y-%m-%d')";
if (timeStatType == "月")
sql = "SELECT DATE_FORMAT(" + xColumnName + ", '%Y-%m') " + xColumnName + ", sum(" + item + ") total FROM " + tableName + where + " GROUP BY DATE_FORMAT(" + xColumnName + ", '%Y-%m')";
if (timeStatType == "年")
sql = "SELECT DATE_FORMAT(" + xColumnName + ", '%Y') " + xColumnName + ", sum(" + item + ") total FROM " + tableName + where + " GROUP BY DATE_FORMAT(" + xColumnName + ", '%Y')";
} else {
if (timeStatType == "日")
sql = "SELECT DATE_FORMAT(VARCHAR(10)," + xColumnName + ", 120) " + xColumnName + ", sum(" + item + ") total FROM " + tableName + where + " GROUP BY DATE_FORMAT(VARCHAR(10)," + xColumnName + ", 120)";
if (timeStatType == "月")
sql = "SELECT DATE_FORMAT(VARCHAR(7)," + xColumnName + ", 120) " + xColumnName + ", sum(" + item + ") total FROM " + tableName + where + " GROUP BY DATE_FORMAT(VARCHAR(7)," + xColumnName + ", 120)";
if (timeStatType == "年")
sql = "SELECT DATE_FORMAT(VARCHAR(4)," + xColumnName + ", 120) " + xColumnName + ", sum(" + item + ") total FROM " + tableName + where + " GROUP BY DATE_FORMAT(VARCHAR(4)," + xColumnName + ", 120)";
}
const results = await sequelize.query(sql, {
plain: false,
raw: true,
type: QueryTypes.SELECT
});
return results;
})
toRes.record(res, 0, await Promise.all(promises))
} catch(err) {
toRes.session(res, 500, '服务器错误!', '', 500)
}
})
// 按日期统计
api.get('/value/:xColumnName/:yColumnName/:timeStatType', async (req, res) => {
try {
let sql = ""
let xColumnName = req.params.xColumnName
let yColumnName = req.params.yColumnName
let timeStatType = req.params.timeStatType
let tableName = "cart"
let where = " WHERE 1 = 1 "
if ("cart" == "orders") {
where += " AND status IN ('已支付', '已发货', '已完成') ";
}
if (config.dbConnection.dbtype.toLowerCase() == "mysql") {
if (timeStatType == "日")
sql = "SELECT DATE_FORMAT(" + xColumnName + ", '%Y-%m-%d') " + xColumnName + ", sum(" + yColumnName + ") total FROM " + tableName + where + " GROUP BY DATE_FORMAT(" + xColumnName + ", '%Y-%m-%d')";
if (timeStatType == "月")
sql = "SELECT DATE_FORMAT(" + xColumnName + ", '%Y-%m') " + xColumnName + ", sum(" + yColumnName + ") total FROM " + tableName + where + " GROUP BY DATE_FORMAT(" + xColumnName + ", '%Y-%m')";
if (timeStatType == "年")
sql = "SELECT DATE_FORMAT(" + xColumnName + ", '%Y') " + xColumnName + ", sum(" + yColumnName + ") total FROM " + tableName + where + " GROUP BY DATE_FORMAT(" + xColumnName + ", '%Y')";
} else {
if (timeStatType == "日")
sql = "SELECT DATE_FORMAT(VARCHAR(10)," + xColumnName + ", 120) " + xColumnName + ", sum(" + yColumnName + ") total FROM " + tableName + where + " GROUP BY DATE_FORMAT(VARCHAR(10)," + xColumnName + ", 120)";
if (timeStatType == "月")
sql = "SELECT DATE_FORMAT(VARCHAR(7)," + xColumnName + ", 120) " + xColumnName + ", sum(" + yColumnName + ") total FROM " + tableName + where + " GROUP BY DATE_FORMAT(VARCHAR(7)," + xColumnName + ", 120)";
if (timeStatType == "年")
sql = "SELECT DATE_FORMAT(VARCHAR(4)," + xColumnName + ", 120) " + xColumnName + ", sum(" + yColumnName + ") total FROM " + tableName + where + " GROUP BY DATE_FORMAT(VARCHAR(4)," + xColumnName + ", 120)";
}
toRes.record(res, 0, await sequelize.query(sql, {
plain: false,
raw: true,
type: QueryTypes.SELECT
}))
} catch(err) {
toRes.session(res, 500, '服务器错误!', '', 500)
}
})
return api
}
论文参考
目 录
目 录 II
1绪 论 1
1.1研究背景与意义 1
1.2国内外研究现状 1
1.3本文研究内容 2
2开发技术 3
2.1 Nodejs介绍 3
2.2 MySql简介 3
2.3 Vue框架 4
2.4 B/S架构 4
3系统分析 5
3.1系统可行性分析 5
3.1.1技术可行性分析 5
3.1.2经济可行性分析 5
3.1.3法律可行性分析 5
3.2系统性能分析 5
3.3功能需求分析 6
3.3.1管理员需求分析 6
3.3.2用户需求分析 6
3.4系统流程分析 7
4系统设计 9
4.1功能模块设计 9
4.2数据库设计 9
4.2.1数据库设计原则 9
4.2.2系统E-R图 10
4.2.3数据库表设计 10
5系统实现 19
5.1前台功能实现 19
5.1.1系统首页页面 19
5.1.2个人中心 21
5.2后台模块实现 21
6系统测试 26
6.1系统测试内容 26
6.1.1 登录测试 26
6.1.2 角色测试 26
6.1.3性能测试 27
6.2测试用例执行结果 27
结 论 28
参考文献 29