Compare commits

...

1 Commits

Author SHA1 Message Date
yoga 9b5f269823 add(examples): 增加数据库样例和占位文件 2022-07-31 03:11:51 +08:00
64 changed files with 1840 additions and 8 deletions

0
data/upload/placeholder Normal file
View File

View File

@ -0,0 +1,74 @@
const {
createAddr,
findAllAddr,
updateAddr,
removeAddr,
setDefaultAddr,
} = require('../service/addr.service')
class AddrController {
async create(ctx) {
// 解析user_id, consignee, phone, address
const user_id = ctx.state.user.id
const { consignee, phone, address } = ctx.request.body
const res = await createAddr({ user_id, consignee, phone, address })
ctx.body = {
code: 0,
message: '添加地址成功',
result: res,
}
}
async findAll(ctx) {
const user_id = ctx.state.user.id
const res = await findAllAddr(user_id)
ctx.body = {
code: 0,
message: '获取列表成功',
result: res,
}
}
async update(ctx) {
const id = ctx.request.params.id
const res = await updateAddr(id, ctx.request.body)
ctx.body = {
code: 0,
message: '更新地址成功',
result: res,
}
}
async remove(ctx) {
const id = ctx.request.params.id
const res = await removeAddr(id)
ctx.body = {
code: 0,
message: '删除地址成功',
result: res,
}
}
async setDefault(ctx) {
const user_id = ctx.state.user.id
const id = ctx.request.params.id
const res = await setDefaultAddr(user_id, id)
ctx.body = {
code: 0,
message: '设置默认成功',
result: res,
}
}
}
module.exports = new AddrController()

View File

@ -0,0 +1,96 @@
const {
createOrUpdate,
findCarts,
updateCarts,
removeCarts,
selectAllCarts,
unselectAllCarts,
} = require('../service/cart.service')
const { cartFormatError } = require('../constant/err.type')
class CartController {
async add(ctx) {
// 将商品添加到购物车
// 1. 解析user_id, goods_id
const user_id = ctx.state.user.id
const goods_id = ctx.request.body.goods_id
// console.log(user_id, goods_id)
// 2. 操作数据库
const res = await createOrUpdate(user_id, goods_id)
// 3. 返回结果
ctx.body = {
code: 0,
message: '添加到购物车成功',
result: res,
}
}
async findAll(ctx) {
// 1. 解析请求参数
const { pageNum = 1, pageSize = 10 } = ctx.request.query
// 2. 操作数据库
const res = await findCarts(pageNum, pageSize)
// 3. 返回结果
ctx.body = {
code: 0,
message: '获取购物车列表成功',
result: res,
}
}
async update(ctx) {
// 1. 解析参数
const { id } = ctx.request.params
const { number, selected } = ctx.request.body
if (number === undefined && selected === undefined) {
cartFormatError.message = 'number和selected不能同时为空'
return ctx.app.emit('error', cartFormatError, ctx)
}
// 2. 操作数据库
const res = await updateCarts({ id, number, selected })
// 3. 返回数据
ctx.body = {
code: 0,
message: '更新购物车成功',
result: res,
}
}
async remove(ctx) {
const { ids } = ctx.request.body
const res = await removeCarts(ids)
ctx.body = {
code: 0,
message: '删除购物车成功',
result: res,
}
}
async selectAll(ctx) {
const user_id = ctx.state.user.id
const res = await selectAllCarts(user_id)
ctx.body = {
code: 0,
message: '全部选中',
result: res,
}
}
async unselectAll(ctx) {
const user_id = ctx.state.user.id
const res = await unselectAllCarts(user_id)
ctx.body = {
code: 0,
message: '全部不选中',
result: res,
}
}
}
module.exports = new CartController()

View File

@ -0,0 +1,111 @@
const path = require('path')
const {
fileUploadError,
unSupportedFileType,
publishGoodsError,
invalidGoodsID,
} = require('../constant/err.type')
const {
createGoods,
updateGoods,
removeGoods,
restoreGoods,
findGoods,
} = require('../service/goods.service')
class GoodsController {
async upload(ctx, next) {
// console.log(ctx.request.files)
const { file } = ctx.request.files
// console.log(file)
const fileTypes = ['image/jpeg', 'image/png']
if (file) {
if (!fileTypes.includes(file.type)) {
return ctx.app.emit('error', unSupportedFileType, ctx)
}
ctx.body = {
code: 0,
message: '商品图片上传成功',
result: {
goods_img: path.basename(file.path),
},
}
} else {
return ctx.app.emit('error', fileUploadError, ctx)
}
}
async create(ctx) {
// 直接调用service的createGoods方法
try {
const { createdAt, updatedAt, ...res } = await createGoods(
ctx.request.body
)
ctx.body = {
code: 0,
message: '发布商品成功',
result: res,
}
} catch (err) {
console.error(err)
return ctx.app.emit('error', publishGoodsError, ctx)
}
}
async update(ctx) {
try {
const res = await updateGoods(ctx.params.id, ctx.request.body)
if (res) {
ctx.body = {
code: 0,
message: '修改商品成功',
result: '',
}
} else {
return ctx.app.emit('error', invalidGoodsID, ctx)
}
} catch (err) {
console.error(err)
}
}
async remove(ctx) {
const res = await removeGoods(ctx.params.id)
if (res) {
ctx.body = {
code: 0,
message: '下架商品成功',
result: '',
}
} else {
return ctx.app.emit('error', invalidGoodsID, ctx)
}
}
async restore(ctx) {
const res = await restoreGoods(ctx.params.id)
if (res) {
ctx.body = {
code: 0,
message: '上架商品成功',
result: '',
}
} else {
return ctx.app.emit('error', invalidGoodsID, ctx)
}
}
async findAll(ctx) {
// 1. 解析pageNum和pageSize
const { pageNum = 1, pageSize = 10 } = ctx.request.query
// 2. 调用数据处理的相关方法
const res = await findGoods(pageNum, pageSize)
// 3. 返回结果
ctx.body = {
code: 0,
message: '获取商品列表成功',
result: res,
}
}
}
module.exports = new GoodsController()

View File

@ -0,0 +1,56 @@
const {
createOrder,
findAllOrder,
updateOrder,
} = require('../service/order.service')
class OrderController {
async create(ctx) {
// 准备数据
const user_id = ctx.state.user.id
const { address_id, goods_info, total } = ctx.request.body
const order_number = 'XZD' + Date.now()
const res = await createOrder({
user_id,
address_id,
goods_info,
total,
order_number,
})
ctx.body = {
code: 0,
message: '生成订单成功',
result: res,
}
}
async findAll(ctx) {
const { pageNum = 1, pageSize = 10, status = 0 } = ctx.request.query
const res = await findAllOrder(pageNum, pageSize, status)
ctx.body = {
code: 0,
message: '获取订单列表成功',
result: res,
}
}
async update(ctx) {
const id = ctx.request.params.id
const { status } = ctx.request.body
const res = await updateOrder(id, status)
ctx.body = {
code: 0,
message: '更新订单状态成功',
result: res,
}
}
}
module.exports = new OrderController()

View File

@ -0,0 +1,81 @@
const jwt = require('jsonwebtoken')
const {
createUser,
getUerInfo,
updateById,
} = require('../service/user.service')
const { userRegisterError } = require('../constant/err.type')
const { JWT_SECRET } = require('../config/config.default')
class UserController {
async register(ctx, next) {
// 1. 获取数据
// console.log(ctx.request.body)
const { user_name, password } = ctx.request.body
// 2. 操作数据库
try {
const res = await createUser(user_name, password)
// console.log(res)
// 3. 返回结果
ctx.body = {
code: 0,
message: '用户注册成功',
result: {
id: res.id,
user_name: res.user_name,
},
}
} catch (err) {
console.log(err)
ctx.app.emit('error', userRegisterError, ctx)
}
}
async login(ctx, next) {
const { user_name } = ctx.request.body
// 1. 获取用户信息(在token的payload中, 记录id, user_name, is_admin)
try {
// 从返回结果对象中剔除password属性, 将剩下的属性放到res对象
const { password, ...res } = await getUerInfo({ user_name })
ctx.body = {
code: 0,
message: '用户登录成功',
result: {
token: jwt.sign(res, JWT_SECRET, { expiresIn: '1d' }),
},
}
} catch (err) {
console.error('用户登录失败', err)
}
}
async changePassword(ctx, next) {
// 1. 获取数据
const id = ctx.state.user.id
const password = ctx.request.body.password
// 2. 操作数据库
if (await updateById({ id, password })) {
ctx.body = {
code: 0,
message: '修改密码成功',
result: '',
}
} else {
ctx.body = {
code: '10007',
message: '修改密码失败',
result: '',
}
}
// 3. 返回结果
}
}
module.exports = new UserController()

View File

@ -0,0 +1,12 @@
const { d } = require("../models/user");
class UserController {
async register(ctx, next) {
ctx.json({ code: 0, message: "success" });
}
async getUserList(ctx, next) {
ctx.json({ code: 0, message: "success" });
}
}
module.exports = new UserController();

View File

@ -0,0 +1,27 @@
// connect to third-service of database or other.
const { Sequelize } = require("sequelize");
const {
MARIA_DIALECT,
MARIA_HOST,
MARIA_PORT,
MARIA_DBNAME,
MARIA_USRNAME,
MARIA_PASSWD,
} = process.env;
const seq = new Sequelize(MARIA_DBNAME, MARIA_USRNAME, MARIA_PASSWD, {
host: MARIA_HOST,
port: MARIA_PORT,
dialect: 'mariadb',
});
seq.authenticate()
.then(() => {
console.log('数据库连接成功')
})
.catch(err => {
console.log('数据库连接失败', err)
})
module.exports = seq;

View File

@ -0,0 +1,49 @@
const redis = require("redis");
// require("../config/env.config");
const { REDIS_HOST, REDIS_PORT, REDIS_DBNAME, REDIS_USER, REDIS_PASSWD } =
process.env; // REDIS_USER 和 REDIS_PASSWD需要服务器配置ACL用户名密码
const URL = `redis://${REDIS_USER}:${REDIS_PASSWD}@${REDIS_HOST}:${REDIS_PORT}/${REDIS_DBNAME}`;
// https://github.com/redis/node-redis/tree/master/docs
// module.exports = redis.createClient({URL});
const client = redis.createClient({
// url: URL,
socket: { host: REDIS_HOST, port: REDIS_PORT },
password: REDIS_PASSWD,
// database: REDIS_DBNAME,
// legacyMode: true, // 语法向后(v3)部分兼容
});
client.on("error", (err) => console.log(`redis client ~ Error ${err}`));
client.on("connect", () => console.log("redis client ~ connect"));
client.on("reconnecting", () => console.log("redis client ~ reconnecting"));
client.on("ready", () => console.log("redis client ~ ready"));
client.on("end", () => console.log("redis client ~ end"));
client.connect();
client.ping();
// try {
// } catch (error) {
// console.log(error);
// }
module.exports = client;
//* 方式二redis 连接池
//! unusable
/* var redisPool = require("redis-connection-pool")("myRedisPool", {
host: REDIS_HOST, // default
port: REDIS_PORT, //default
max_clients: 30, // defalut
perform_checks: false, // checks for needed push/pop functionality
database: 0, // database number to use
options: {
auth_pass: REDIS_PASSWD,
}, //options for createClient of node-redis, optional
});
redisPool.set("test-key", "foobar", function (err) {
redisPool.get("test-key", function (err, reply) {
console.log(reply); // 'foobar'
});
}); */

View File

@ -0,0 +1,19 @@
const { addrFormatError } = require('../constant/err.type')
const validator = (rules) => {
return async (ctx, next) => {
try {
ctx.verifyParams(rules)
} catch (err) {
console.error(err)
addrFormatError.result = err
return ctx.app.emit('error', addrFormatError, ctx)
}
await next()
}
}
module.exports = {
validator,
}

View File

@ -0,0 +1,48 @@
const jwt = require('jsonwebtoken')
const { JWT_SECRET } = require('../config/config.default')
const {
tokenExpiredError,
invalidToken,
hasNotAdminPermission,
} = require('../constant/err.type')
const auth = async (ctx, next) => {
const { authorization = '' } = ctx.request.header
const token = authorization.replace('Bearer ', '')
// console.log(token)
try {
// user中包含了payload的信息(id, user_name, is_admin)
const user = jwt.verify(token, JWT_SECRET)
ctx.state.user = user
} catch (err) {
switch (err.name) {
case 'TokenExpiredError':
console.error('token已过期', err)
return ctx.app.emit('error', tokenExpiredError, ctx)
case 'JsonWebTokenError':
console.error('无效的token', err)
return ctx.app.emit('error', invalidToken, ctx)
}
}
await next()
}
const hadAdminPermission = async (ctx, next) => {
const { is_admin } = ctx.state.user
if (!is_admin) {
console.error('该用户没有管理员的权限', ctx.state.user)
return ctx.app.emit('error', hasNotAdminPermission, ctx)
}
await next()
}
module.exports = {
auth,
hadAdminPermission,
}

View File

@ -0,0 +1,18 @@
const { cartFormatError } = require('../constant/err.type')
const validator = (rules) => {
return async (ctx, next) => {
try {
ctx.verifyParams(rules)
} catch (err) {
console.error(err)
cartFormatError.result = err
return ctx.app.emit('error', cartFormatError, ctx)
}
await next()
}
}
module.exports = {
validator,
}

View File

@ -0,0 +1,22 @@
const { goodsFormatError } = require('../constant/err.type')
const validator = async (ctx, next) => {
try {
ctx.verifyParams({
goods_name: { type: 'string', required: true },
goods_price: { type: 'number', required: true },
goods_num: { type: 'number', required: true },
goods_img: { type: 'string', required: true },
})
} catch (err) {
console.error(err)
goodsFormatError.result = err
return ctx.app.emit('error', goodsFormatError, ctx)
}
await next()
}
module.exports = {
validator,
}

View File

@ -0,0 +1,18 @@
const { orderFormatError } = require('../constant/err.type')
const validator = (rules) => {
return async (ctx, next) => {
try {
ctx.verifyParams(rules)
} catch (err) {
console.error(err)
orderFormatError.result = err
return ctx.app.emit('error', orderFormatError, ctx)
}
await next()
}
}
module.exports = {
validator,
}

View File

@ -0,0 +1,92 @@
const bcrypt = require('bcryptjs')
const { getUerInfo } = require('../service/user.service')
const {
userFormateError,
userAlreadyExited,
userRegisterError,
userDoesNotExist,
userLoginError,
invalidPassword,
} = require('../constant/err.type')
const userValidator = async (ctx, next) => {
const { user_name, password } = ctx.request.body
// 合法性
if (!user_name || !password) {
console.error('用户名或密码为空', ctx.request.body)
ctx.app.emit('error', userFormateError, ctx)
return
}
await next()
}
const verifyUser = async (ctx, next) => {
const { user_name } = ctx.request.body
// if (await getUerInfo({ user_name })) {
// ctx.app.emit('error', userAlreadyExited, ctx)
// return
// }
try {
const res = await getUerInfo({ user_name })
if (res) {
console.error('用户名已经存在', { user_name })
ctx.app.emit('error', userAlreadyExited, ctx)
return
}
} catch (err) {
console.error('获取用户信息错误', err)
ctx.app.emit('error', userRegisterError, ctx)
return
}
await next()
}
const crpytPassword = async (ctx, next) => {
const { password } = ctx.request.body
const salt = bcrypt.genSaltSync(10)
// hash保存的是 密文
const hash = bcrypt.hashSync(password, salt)
ctx.request.body.password = hash
await next()
}
const verifyLogin = async (ctx, next) => {
// 1. 判断用户是否存在(不存在:报错)
const { user_name, password } = ctx.request.body
try {
const res = await getUerInfo({ user_name })
if (!res) {
console.error('用户名不存在', { user_name })
ctx.app.emit('error', userDoesNotExist, ctx)
return
}
// 2. 密码是否匹配(不匹配: 报错)
if (!bcrypt.compareSync(password, res.password)) {
ctx.app.emit('error', invalidPassword, ctx)
return
}
} catch (err) {
console.error(err)
return ctx.app.emit('error', userLoginError, ctx)
}
await next()
}
module.exports = {
userValidator,
verifyUser,
crpytPassword,
verifyLogin,
}

View File

@ -0,0 +1,39 @@
// 1. 导入seq的连接
const { DataTypes } = require('sequelize')
const seq = require('../db/seq')
// 2. 定义字段(模型)
const Address = seq.define('zd_addresses', {
user_id: {
type: DataTypes.INTEGER,
allowNull: false,
comment: '用户id',
},
consignee: {
type: DataTypes.STRING,
allowNull: false,
comment: '收货人姓名',
},
phone: {
type: DataTypes.CHAR(11),
allowNull: false,
comment: '收货人的手机号',
},
address: {
type: DataTypes.STRING,
allowNull: false,
comment: '收货人的地址',
},
is_default: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false,
comment: '是否为默认地址, 0:不是(默认值) 1: 是',
},
})
// 3. 同步, sync
// Address.sync({ force: true })
// 4. 导出模型对象
module.exports = Address

View File

@ -0,0 +1,39 @@
// 1. 导入sequelize的连接
const { DataTypes } = require('sequelize')
const seq = require('../db/seq')
const Goods = require('./goods.model')
// 2. 定义Cart模型
const Cart = seq.define('zd_carts', {
goods_id: {
type: DataTypes.INTEGER,
allowNull: false,
comment: '商品的id',
},
user_id: {
type: DataTypes.INTEGER,
allowNull: false,
comment: '用户的id',
},
number: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: 1,
comment: '商品的数量',
},
selected: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: true,
comment: '是否选中',
},
})
// 3. 同步数据(建表)
// Cart.sync({ force: true })
Cart.belongsTo(Goods, {
foreignKey: 'goods_id',
as: 'goods_info',
})
// 4. 导出Cart模型
module.exports = Cart

View File

@ -0,0 +1,36 @@
const { DataTypes } = require('sequelize')
const seq = require('../db/seq')
const Goods = seq.define(
'zd_goods',
{
goods_name: {
type: DataTypes.STRING,
allowNull: false,
comment: '商品名称',
},
goods_price: {
type: DataTypes.DECIMAL(10, 2),
allowNull: false,
comment: '商品价格',
},
goods_num: {
type: DataTypes.INTEGER,
allowNull: false,
comment: '商品库存',
},
goods_img: {
type: DataTypes.STRING,
allowNull: false,
comment: '商品图片的url',
},
},
{
paranoid: true,
}
)
// Goods.sync({ force: true })
module.exports = Goods

View File

@ -0,0 +1,40 @@
const { DataTypes } = require('sequelize')
const seq = require('../db/seq')
const Order = seq.define('zd_orders', {
user_id: {
type: DataTypes.INTEGER,
allowNull: false,
comment: '用户id',
},
address_id: {
type: DataTypes.INTEGER,
allowNull: false,
comment: '地址id',
},
goods_info: {
type: DataTypes.TEXT,
allowNull: false,
comment: '商品信息',
},
total: {
type: DataTypes.DECIMAL(10, 2),
allowNull: false,
comment: '订单总金额',
},
order_number: {
type: DataTypes.CHAR(16),
allowNull: false,
comment: '订单号',
},
status: {
type: DataTypes.TINYINT,
allowNull: false,
defaultValue: 0,
comment: '订单状态(0: 未支付,1: 已支付, 2: 已发货, 3: 已签收, 4: 取消)',
},
})
// Order.sync({ force: true })
module.exports = Order

View File

@ -0,0 +1,30 @@
const { DataTypes } = require('sequelize')
const seq = require('../db/seq')
// 创建模型(Model zd_user -> 表 zd_users)
const User = seq.define('zd_user', {
// id 会被sequelize自动创建, 管理
user_name: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
comment: '用户名, 唯一',
},
password: {
type: DataTypes.CHAR(64),
allowNull: false,
comment: '密码',
},
is_admin: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: 0,
comment: '是否为管理员, 0: 不是管理员(默认); 1: 是管理员',
},
})
// 强制同步数据库(创建数据表)
// User.sync({ force: true })
module.exports = User

View File

@ -0,0 +1,30 @@
const { DataTypes } = require('sequelize')
const seq = require('../db/mariadb')
// 创建模型(Model user -> 数据库表 users)
const User = seq.define('user', {
// id 会被sequelize自动创建, 管理
username: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
comment: '用户名, 唯一',
},
password: {
type: DataTypes.CHAR(64),
allowNull: false,
comment: '密码',
},
is_admin: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: 0,
comment: '是否为管理员: 0 不是管理员(默认); 1 是管理员',
},
})
// 强制同步数据库(创建数据表)
// User.sync({ force: true })
module.exports = User

View File

@ -0,0 +1,54 @@
// 一. 导入koa-router包
const Router = require('koa-router')
// 二. 实例化对象
const router = new Router({ prefix: '/address' })
// 中间件/控制器
const { auth } = require('../middleware/auth.middleware')
const { validator } = require('../middleware/addr.middleware')
const {
create,
findAll,
update,
remove,
setDefault,
} = require('../controller/addr.controller')
// 三. 编写路由规则
// 3.1 添加接口: 登录, 格式
router.post(
'/',
auth,
validator({
consignee: 'string',
phone: { type: 'string', format: /^1\d{10}$/ },
address: 'string',
}),
create
)
// 3.2 获取地址列表
router.get('/', auth, findAll)
// 3.3 更新地址
router.put(
'/:id',
auth,
validator({
consignee: 'string',
phone: { type: 'string', format: /^1\d{10}$/ },
address: 'string',
}),
update
)
// 3.4 删除地址
router.delete('/:id', auth, remove)
// 3.5 设置默认
router.patch('/:id', auth, setDefault)
// 四. 导出router对象
module.exports = router

View File

@ -0,0 +1,48 @@
// 1. 导入koa-router
const Router = require('koa-router')
// 中间件
const { auth } = require('../middleware/auth.middleware')
const { validator } = require('../middleware/cart.middleware')
// 控件器
const {
add,
findAll,
update,
remove,
selectAll,
unselectAll,
} = require('../controller/cart.controller')
// 2. 实例化router对象
const router = new Router({ prefix: '/carts' })
// 3. 编写路由规则
// 3.1 添加到购物车接口: 登录, 格式
router.post('/', auth, validator({ goods_id: 'number' }), add)
// 3.2 获取购物车列表
router.get('/', auth, findAll)
// 3.3 更新购物车
router.patch(
'/:id',
auth,
validator({
number: { type: 'number', required: false },
selected: { type: 'bool', required: false },
}),
update
)
// 3.4 删除购物车
router.delete('/', auth, validator({ ids: 'array' }), remove)
// 3.5 全选与全不选
router.post('/selectAll', auth, selectAll)
router.post('/unselectAll', auth, unselectAll)
// 4. 导出router对象
module.exports = router

View File

@ -0,0 +1,35 @@
const Router = require('koa-router')
const { auth, hadAdminPermission } = require('../middleware/auth.middleware')
const { validator } = require('../middleware/goods.middleware')
const {
upload,
create,
update,
remove,
restore,
findAll,
} = require('../controller/goods.controller')
const router = new Router({ prefix: '/goods' })
// 商品图片上传接口
router.post('/upload', auth, hadAdminPermission, upload)
// 发布商品接口
router.post('/', auth, hadAdminPermission, validator, create)
// 修改商品接口
router.put('/:id', auth, hadAdminPermission, validator, update)
// 硬删除接口
// router.delete('/:id', auth, hadAdminPermission, remove)
router.post('/:id/off', auth, hadAdminPermission, remove)
router.post('/:id/on', auth, hadAdminPermission, restore)
// 获取商品列表
router.get('/', findAll)
module.exports = router

View File

@ -0,0 +1,14 @@
const fs = require('fs')
const Router = require('koa-router')
const router = new Router()
fs.readdirSync(__dirname).forEach(file => {
// console.log(file)
if (file !== 'index.js') {
let r = require('./' + file)
router.use(r.routes())
}
})
module.exports = router

View File

@ -0,0 +1,34 @@
const Router = require('koa-router')
const router = new Router({ prefix: '/orders' })
const { auth } = require('../middleware/auth.middleware')
const { validator } = require('../middleware/order.middleware')
const { create, findAll, update } = require('../controller/order.controller')
// 提交订单
router.post(
'/',
auth,
validator({
address_id: 'int',
goods_info: 'string',
total: 'string',
}),
create
)
// 获取订单列表
router.get('/', auth, findAll)
// 更新订单状态
router.patch(
'/:id',
auth,
validator({
status: 'number',
}),
update
)
module.exports = router

View File

@ -0,0 +1,28 @@
const Router = require('koa-router')
const {
userValidator,
verifyUser,
crpytPassword,
verifyLogin,
} = require('../middleware/user.middleware')
const { auth } = require('../middleware/auth.middleware')
const {
register,
login,
changePassword,
} = require('../controller/user.controller')
const router = new Router({ prefix: '/users' })
// 注册接口
router.post('/register', userValidator, verifyUser, crpytPassword, register)
// 登录接口
router.post('/login', userValidator, verifyLogin, login)
// 修改密码接口
router.patch('/', auth, crpytPassword, changePassword)
module.exports = router

View File

@ -0,0 +1,44 @@
const Address = require('../model/addr.model')
class AddrService {
async createAddr(addr) {
return await Address.create(addr)
}
async findAllAddr(user_id) {
return await Address.findAll({
attributes: ['id', 'consignee', 'phone', 'address', 'is_default'],
where: { user_id },
})
}
async updateAddr(id, addr) {
return await Address.update(addr, { where: { id } })
}
async removeAddr(id) {
return await Address.destroy({ where: { id } })
}
async setDefaultAddr(user_id, id) {
await Address.update(
{ is_default: false },
{
where: {
user_id,
},
}
)
return await Address.update(
{ is_default: true },
{
where: {
id,
},
}
)
}
}
module.exports = new AddrService()

View File

@ -0,0 +1,96 @@
const { Op } = require('sequelize')
const Cart = require('../model/cart.model')
const Goods = require('../model/goods.model')
class CartService {
async createOrUpdate(user_id, goods_id) {
// 根据user_id和goods_id同时查找, 有没有记录
let res = await Cart.findOne({
where: {
[Op.and]: {
user_id,
goods_id,
},
},
})
if (res) {
// 已经存在一条记录, 将number + 1
await res.increment('number')
return await res.reload()
} else {
return await Cart.create({
user_id,
goods_id,
})
}
}
async findCarts(pageNum, pageSize) {
const offset = (pageNum - 1) * pageSize
const { count, rows } = await Cart.findAndCountAll({
attributes: ['id', 'number', 'selected'],
offset: offset,
limit: pageSize * 1,
include: {
model: Goods,
as: 'goods_info',
attributes: ['id', 'goods_name', 'goods_price', 'goods_img'],
},
})
return {
pageNum,
pageSize,
total: count,
list: rows,
}
}
async updateCarts(params) {
const { id, number, selected } = params
const res = await Cart.findByPk(id)
if (!res) return ''
number !== undefined ? (res.number = number) : ''
if (selected !== undefined) {
res.selected = selected
}
return await res.save()
}
async removeCarts(ids) {
return await Cart.destroy({
where: {
id: {
[Op.in]: ids,
},
},
})
}
async selectAllCarts(user_id) {
return await Cart.update(
{ selected: true },
{
where: {
user_id,
},
}
)
}
async unselectAllCarts(user_id) {
return await Cart.update(
{ selected: false },
{
where: {
user_id,
},
}
)
}
}
module.exports = new CartService()

View File

@ -0,0 +1,49 @@
const Goods = require('../model/goods.model')
class GoodsService {
async createGoods(goods) {
const res = await Goods.create(goods)
return res.dataValues
}
async updateGoods(id, goods) {
const res = await Goods.update(goods, { where: { id } })
return res[0] > 0 ? true : false
}
async removeGoods(id) {
const res = await Goods.destroy({ where: { id } })
return res > 0 ? true : false
}
async restoreGoods(id) {
const res = await Goods.restore({ where: { id } })
return res > 0 ? true : false
}
async findGoods(pageNum, pageSize) {
// // 1. 获取总数
// const count = await Goods.count()
// // console.log(count)
// // 2. 获取分页的具体数据
// const offset = (pageNum - 1) * pageSize
// const rows = await Goods.findAll({ offset: offset, limit: pageSize * 1 })
const offset = (pageNum - 1) * pageSize
const { count, rows } = await Goods.findAndCountAll({
offset: offset,
limit: pageSize * 1,
})
return {
pageNum,
pageSize,
total: count,
list: rows,
}
}
}
module.exports = new GoodsService()

View File

@ -0,0 +1,31 @@
const Order = require('../model/order.model')
class OrderService {
async createOrder(order) {
return await Order.create(order)
}
async findAllOrder(pageNum, pageSize, status) {
const { count, rows } = await Order.findAndCountAll({
attributes: ['goods_info', 'total', 'order_number', 'status'],
where: {
status,
},
offset: (pageNum - 1) * pageSize,
limit: pageSize * 1,
})
return {
pageNum,
pageSize,
total: count,
list: rows,
}
}
async updateOrder(id, status) {
return await Order.update({ status }, { where: { id } })
}
}
module.exports = new OrderService()

View File

@ -0,0 +1,42 @@
const User = require('../models/user')
class UserService {
async createUser(user_name, password) {
// 插入数据
// await表达式: promise对象的值
const res = await User.create({ user_name, password })
// console.log(res)
return res.dataValues
}
async getUerInfo({ id, user_name, password, is_admin }) {
const whereOpt = {}
id && Object.assign(whereOpt, { id })
user_name && Object.assign(whereOpt, { user_name })
password && Object.assign(whereOpt, { password })
is_admin && Object.assign(whereOpt, { is_admin })
const res = await User.findOne({
attributes: ['id', 'user_name', 'password', 'is_admin'],
where: whereOpt,
})
return res ? res.dataValues : null
}
async updateById({ id, user_name, password, is_admin }) {
const whereOpt = { id }
const newUser = {}
user_name && Object.assign(newUser, { user_name })
password && Object.assign(newUser, { password })
is_admin && Object.assign(newUser, { is_admin })
const res = await User.update(newUser, { where: whereOpt })
// console.log(res)
return res[0] > 0 ? true : false
}
}
module.exports = new UserService()

View File

@ -0,0 +1,42 @@
const User = require('../model/use.model')
class UserService {
async createUser(user_name, password) {
// 插入数据
// await表达式: promise对象的值
const res = await User.create({ user_name, password })
// console.log(res)
return res.dataValues
}
async getUerInfo({ id, user_name, password, is_admin }) {
const whereOpt = {}
id && Object.assign(whereOpt, { id })
user_name && Object.assign(whereOpt, { user_name })
password && Object.assign(whereOpt, { password })
is_admin && Object.assign(whereOpt, { is_admin })
const res = await User.findOne({
attributes: ['id', 'user_name', 'password', 'is_admin'],
where: whereOpt,
})
return res ? res.dataValues : null
}
async updateById({ id, user_name, password, is_admin }) {
const whereOpt = { id }
const newUser = {}
user_name && Object.assign(newUser, { user_name })
password && Object.assign(newUser, { password })
is_admin && Object.assign(newUser, { is_admin })
const res = await User.update(newUser, { where: whereOpt })
// console.log(res)
return res[0] > 0 ? true : false
}
}
module.exports = new UserService()

View File

@ -0,0 +1,5 @@
const { } = require("../services/service");
class Controller {}
module.exports = new Controller();

View File

@ -0,0 +1,9 @@
const mongoose = require("mongoose");
const { MONGO_HOST, MONGO_PORT, MONGO_DBNAME, MONGO_USER, MONGO_PASSWD } =
process.env;
const URI = `mongodb://${MONGO_USER}:${MONGO_PASSWD}@${MONGO_HOST}:${MONGO_PORT}/${MONGO_DBNAME}`;
mongoose.connect(URI);
module.exports = { mongoose };

View File

@ -0,0 +1,24 @@
const { mongoose } = require("../../db/mgs.mongo");
const BookSchema = mongoose.Schema({
name: {
type: String,
require: true,
},
author: {
type: String,
},
wordCount: {
type: Number,
},
publishTime: {
type: Date,
default: Date.now,
},
});
const Book = mongoose.model("Book", BookSchema);
// let book = new Book({});
module.exports = { Book };

View File

@ -0,0 +1,5 @@
const { client } = require("../db/mongo");
class Service {}
module.exports = new Service();

View File

@ -0,0 +1,12 @@
const { d } = require("../models/user");
class UserController {
async register(ctx, next) {
ctx.json({ code: 0, message: "success" });
}
async getUserList(ctx, next) {
ctx.json({ code: 0, message: "success" });
}
}
module.exports = new UserController();

View File

@ -0,0 +1,27 @@
// connect to third-service of database or other.
const { Sequelize } = require("sequelize");
const {
MARIA_DIALECT,
MARIA_HOST,
MARIA_PORT,
MARIA_DBNAME,
MARIA_USRNAME,
MARIA_PASSWD,
} = process.env;
const seq = new Sequelize(MARIA_DBNAME, MARIA_USRNAME, MARIA_PASSWD, {
host: MARIA_HOST,
port: MARIA_PORT,
dialect: 'mariadb',
});
seq.authenticate()
.then(() => {
console.log('数据库连接成功')
})
.catch(err => {
console.log('数据库连接失败', err)
})
module.exports = seq;

View File

@ -0,0 +1,49 @@
const redis = require("redis");
// require("../config/env.config");
const { REDIS_HOST, REDIS_PORT, REDIS_DBNAME, REDIS_USER, REDIS_PASSWD } =
process.env; // REDIS_USER 和 REDIS_PASSWD需要服务器配置ACL用户名密码
const URL = `redis://${REDIS_USER}:${REDIS_PASSWD}@${REDIS_HOST}:${REDIS_PORT}/${REDIS_DBNAME}`;
// https://github.com/redis/node-redis/tree/master/docs
// module.exports = redis.createClient({URL});
const client = redis.createClient({
// url: URL,
socket: { host: REDIS_HOST, port: REDIS_PORT },
password: REDIS_PASSWD,
// database: REDIS_DBNAME,
// legacyMode: true, // 语法向后(v3)部分兼容
});
client.on("error", (err) => console.log(`redis client ~ Error ${err}`));
client.on("connect", () => console.log("redis client ~ connect"));
client.on("reconnecting", () => console.log("redis client ~ reconnecting"));
client.on("ready", () => console.log("redis client ~ ready"));
client.on("end", () => console.log("redis client ~ end"));
client.connect();
client.ping();
// try {
// } catch (error) {
// console.log(error);
// }
module.exports = client;
//* 方式二redis 连接池
//! unusable
/* var redisPool = require("redis-connection-pool")("myRedisPool", {
host: REDIS_HOST, // default
port: REDIS_PORT, //default
max_clients: 30, // defalut
perform_checks: false, // checks for needed push/pop functionality
database: 0, // database number to use
options: {
auth_pass: REDIS_PASSWD,
}, //options for createClient of node-redis, optional
});
redisPool.set("test-key", "foobar", function (err) {
redisPool.get("test-key", function (err, reply) {
console.log(reply); // 'foobar'
});
}); */

View File

@ -0,0 +1,30 @@
const { DataTypes } = require('sequelize')
const seq = require('../db/mariadb')
// 创建模型(Model user -> 数据库表 users)
const User = seq.define('user', {
// id 会被sequelize自动创建, 管理
username: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
comment: '用户名, 唯一',
},
password: {
type: DataTypes.CHAR(64),
allowNull: false,
comment: '密码',
},
is_admin: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: 0,
comment: '是否为管理员: 0 不是管理员(默认); 1 是管理员',
},
})
// 强制同步数据库(创建数据表)
// User.sync({ force: true })
module.exports = User

View File

@ -0,0 +1,29 @@
const redisClient = require("../../db/redis");
/**
Object.prototype.toString = function () {
return JSON.stringify(this);
};
*/
class RedisService {
client = redisClient;
save2Redis(key, value) {
redisClient.set(key, value);
}
getByKey(key, callback = null) {
if (callback) {
redisClient.get(key, callback);
} else {
redisClient.get(key, (err, value) => {
if (err) return null;
console.log(value);
// return value;
});
}
}
}
module.exports = new RedisService();

View File

@ -0,0 +1,42 @@
const User = require('../models/user')
class UserService {
async createUser(user_name, password) {
// 插入数据
// await表达式: promise对象的值
const res = await User.create({ user_name, password })
// console.log(res)
return res.dataValues
}
async getUerInfo({ id, user_name, password, is_admin }) {
const whereOpt = {}
id && Object.assign(whereOpt, { id })
user_name && Object.assign(whereOpt, { user_name })
password && Object.assign(whereOpt, { password })
is_admin && Object.assign(whereOpt, { is_admin })
const res = await User.findOne({
attributes: ['id', 'user_name', 'password', 'is_admin'],
where: whereOpt,
})
return res ? res.dataValues : null
}
async updateById({ id, user_name, password, is_admin }) {
const whereOpt = { id }
const newUser = {}
user_name && Object.assign(newUser, { user_name })
password && Object.assign(newUser, { password })
is_admin && Object.assign(newUser, { is_admin })
const res = await User.update(newUser, { where: whereOpt })
// console.log(res)
return res[0] > 0 ? true : false
}
}
module.exports = new UserService()

9
examples/dbs/npm.sh Normal file
View File

@ -0,0 +1,9 @@
npm i -S mariadb
npm i -S mongoose
npm i -S mysql2
npm i -S sequelize
npm i -S redis
npm i -S redis-connection-pool
npm i -S
npm i -S

View File

@ -0,0 +1,5 @@
const { } = require("../services/service");
class Controller {}
module.exports = new Controller();

View File

@ -0,0 +1,5 @@
const redis = require("");
const { POSTGRES_HOST, POSTGRES_PORT, POSTGRES_DBNAME, POSTGRES_USER, POSTGRES_PASSWD } = process.env;
module.exports = client;

View File

@ -0,0 +1,3 @@
const { client } = require("../db/");
module.exports = Model;

View File

@ -0,0 +1,5 @@
const { client } = require("../db/postgres");
class Service {}
module.exports = new Service();

View File

@ -0,0 +1,5 @@
const { getByKey, save2Redis } = require("../services/baseOps");
class RedisController {}
module.exports = new RedisController();

View File

@ -0,0 +1,49 @@
const redis = require("redis");
// require("../config/env.config");
const { REDIS_HOST, REDIS_PORT, REDIS_DBNAME, REDIS_USER, REDIS_PASSWD } =
process.env; // REDIS_USER 和 REDIS_PASSWD需要服务器配置ACL用户名密码
const URL = `redis://${REDIS_USER}:${REDIS_PASSWD}@${REDIS_HOST}:${REDIS_PORT}/${REDIS_DBNAME}`;
// https://github.com/redis/node-redis/tree/master/docs
// module.exports = redis.createClient({URL});
const client = redis.createClient({
// url: URL,
socket: { host: REDIS_HOST, port: REDIS_PORT },
password: REDIS_PASSWD,
// database: REDIS_DBNAME,
// legacyMode: true, // 语法向后(v3)部分兼容
});
client.on("error", (err) => console.log(`redis client ~ Error ${err}`));
client.on("connect", () => console.log("redis client ~ connect"));
client.on("reconnecting", () => console.log("redis client ~ reconnecting"));
client.on("ready", () => console.log("redis client ~ ready"));
client.on("end", () => console.log("redis client ~ end"));
client.connect();
client.ping();
// try {
// } catch (error) {
// console.log(error);
// }
module.exports = client;
//* 方式二redis 连接池
//! 报错,不可用
/* var redisPool = require("redis-connection-pool")("myRedisPool", {
host: REDIS_HOST, // default
port: REDIS_PORT, //default
max_clients: 30, // defalut
perform_checks: false, // checks for needed push/pop functionality
database: 0, // database number to use
options: {
auth_pass: REDIS_PASSWD,
}, //options for createClient of node-redis, optional
});
redisPool.set("test-key", "foobar", function (err) {
redisPool.get("test-key", function (err, reply) {
console.log(reply); // 'foobar'
});
}); */

View File

@ -0,0 +1,4 @@
const { client } = require("../db/redis");
module.exports = User

View File

@ -0,0 +1,29 @@
const { client } = require("../db/redis");
/**
Object.prototype.toString = function () {
return JSON.stringify(this);
};
*/
class RedisService {
client = client;
save2Redis(key, value) {
client.set(key, value);
}
getByKey(key, callback = null) {
if (callback) {
client.get(key, callback);
} else {
client.get(key, (err, value) => {
if (err) return null;
console.log(value);
// return value;
});
}
}
}
module.exports = new RedisService();

View File

@ -0,0 +1,18 @@
const {
client,
save2Redis,
getByKey,
} = require("../src/service/redis/base.service");
save2Redis("key1", "i am string value");
// redis 储存时默认调用 Object.toString 而非 JSON.stringify
// save2Redis("key2", { key: "i am string value from Object.toString()" }); // value是object报参数类型错误
getByKey("key2"); // 无console输出
client.rPush("alist", "abc");
// client.rPush("alist", 123); // value是object报参数类型错误
client.lRange("alist", 0, -1, (err, v) => {
console.log(v); // 无console输出
client.disconnect();
});

View File

@ -0,0 +1,5 @@
const { } = require("../services/");
class RedisController {}
module.exports = new RedisController();

View File

@ -0,0 +1,5 @@
const redis = require("");
const { SQLITE3_HOST, SQLITE3_PORT, SQLITE3_DBNAME, SQLITE3_USER, SQLITE3_PASSWD } = process.env;
module.exports = client;

View File

@ -0,0 +1,3 @@
const { client } = require("../db/");
module.exports = Model;

View File

@ -0,0 +1,5 @@
const { client } = require("../db/");
class Service {}
module.exports = new Service();

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "koa2-template",
"version": "1.0.1",
"version": "0.0.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "koa2-template",
"version": "1.0.1",
"version": "0.0.1",
"license": "MIT",
"dependencies": {
"bcryptjs": "^2.4.3",

0
public/js/placeholder.js Normal file
View File

2
scripts/placeholder.ps1 Normal file
View File

@ -0,0 +1,2 @@
nvm
yarn

View File

@ -1,6 +0,0 @@
import { getUserList } from "../controller/user";
import Router from "koa-router";
export const router = new Router({ prefix: "/" });
router.get("/list", getUserList);