// /app/model/product.js
module.exports = app => {
const { INTEGER, STRING, DATE, TEXT, DECIMAL, UUIT, UUIDV4 } = app.Sequelize;
const ProductModel = app.model.define('product', {
id: {//数据id
type: UUID,
defaultValue: UUIDV4,
allowNull: false,
primaryKey: true,
// autoIncrement:true,
},
// 关联id 分类
categoryId: {
type: UUID,
allowNull: false,
},
name: {
type: STIRNG(50),
allowNull: false,
},
subImages: {//json 格式扩展用
type: TEXT,
allowNull: true,
},
price: { // 价格,保留两位小数
type: DECIMAL(20, 2),
allowNull: false,
},
status: {
type: INTEGER(6),
allowNull: true,
defaultValue: 1,
},
createTime: {
type: DATE,
allowNull: false,
defaultValue: new Date(),
},
updateTime: {
type: DATE,
allowNull: false,
defaultValue: new Date(),
}
}, {
// 配置
timestamp: false,//不使用默认的 创建更新时间
tableName: 'product',
}, {
indexes: [
{ field: ['categoryId'] }
]
}, {
classMethods: {
associate() {
ProductModel.hasOne(app.model.CartModel, { foreignKey: 'id' })
}
}
})
// ProductModel.belongsTo(app.model.categoryModel)
ProductModel.beforeBulkUpdate(product => {
product.attributes.updateTime = new Date();
return product;
});
return ProductModel;
}
// service.js
const productRow = await this.ProductModel.findOne({ where: { id } });
// undefined 没有返回
productRow.get('status') !== 1;//返回属性值
// asc 正序
async productSearch({ productName, pageNum=1, pageSize=10, sortBy: 'asc' }){
const { count, rows } = await this.ProductModel.findAndCount({
where: { name: { $like: `%${productName}%` }, status: 1 },
order: [['price', sortBy]],
limit: Number(pageSize | 0),
offset: Number(pageNum - 1 | 0) * Number(pageSize | 0),
})
if (rows.length < 1) //无产品数据;
rows.forEach(row => row && row.toJSON())//数组数据
ctx.body = rows
}
// /app/service/UserService
/**
* 返回 undefined
* 或者 是数据行
*/
const question = await this.UserModel.findOne({
attributes: ['question'],//筛选需要的字段
where: { username },
})
/**
* 设置redis
* 根据问题 回答 正确 返回有效期的token 比较用户 还有他的 缓存 判断缓存失效 相同
* 校验这个token 来做密码修改 超时关闭
*/
await this.app.redis.set(TOKEN + username, forgetToken);
await this.app.redis.expire(TOKEN + username, 12 * 60 * 60);
// lodash 函数库 eq 判断相等 可以判断对象 全等的
_.eq(token, forgetToken)
// 密码的设置
const [rowCount] = await this.UserModel.update({
password: md5(passwordNew + salt)
}, { where: { username }, individualHooks: true })
/**
* 返回数组 rowCount 收影响的行数
* 更新 返回 数组
* 密码保密加盐
*/
if (rowCount > 0) { } //修改成功
// 判断密码
/**
* 根据查找到结果,如果存在就是密码正确,不存在就是错误
*/
const result = await this.UserModel.findOne({
attributes: ['username'],
where: { id: currentUser.id, password: md5(passwordOld + salt) }
})
// 唯一字段 修改前判断是否存在 排除当前用户
const result = await this.UserModel.findOne({
attributes: ['email'],
where: {
email: userInfo.email,
id: { $not: currentUser.id }
}
})
if (result) '邮箱已存在,不能改成这个邮箱了'
// 更新数据 会返回数据结果 这个结果包含全部字段 只有一条数据的情况
const [updateCount, [updateRow]] = await this.UserModel.update(userInfo, {
where: { id: currentUser.id },
individualHooks: true,
})
// pickBy 返回指定key字段的 组成的对象
// 参数1:对象 参数2:回调函数 类似数组
// 回调函数 参数1:对象value 参数2 :对象key
const user = _.pickBy(updateRow.toJSON(), (value, key) => {
return ['id', 'useranme', 'email', 'phone'].find(item => key === item);
})
// 鉴权
async checkAdminRole(user){
if (user && user.role === 1) return '成功'
return '失败'
}
async checkAdminAndLogin(){
const user = this.session.currentUser;
if (!user) return '用户未登录'
const response = await this.checkAdminRole(user);
// 返回是否有权限
}
// /app/service/shippingservice.js
/**
* 新建内容
* create
* 返回 新建的row
*/
async add(shipping){
if (!Object.keys(shipping).every(k ==> !!shipping)) return '存在参数为空'
const { id: userId } = this.session.currentUser
shipping = { ...shipping, userId }
const shippingRow = await this.ShippingModel.create(shipping)
if (!shippingRow) return '创建失败'
ctx.body = shippingRow.toJSON()
}
/**
* 根据分类信息搜索产品
* 数组 分页 findAndCount
*
*/
async getProductListByCategoryId({ categoryName, categoryId, pageNum=1, pageSize=10, sortBy='asc' }){
const { data: categoryIdArr } = await this.ctx.service.categoryManageService.getCategoryAndDeepChildCategory(categoryId);
const { count, rows } = await this.ProductModel.findAndCount({
where: { categoryId: { $in: categoryIdArr }, status: ON_SALE.CODE },
order: [['price', sortBy]],
limit: Number(pageSize | 0),
offset: Number(pageNum - 1 | 0) * Number(pageSize | 0),
});
if (rows.length < 1) this.ServerResponse.createBySuccessMsg('无产品数据');
rows.forEach(row => row && row.toJSON());
}
// 多张图片处理
const subImgArr = product.subImages.split(',');
if (subImgArr.length > 0) product.mainImage = subImgArr[0];
// 如果有id就更新 没有就添加
// 先findOne 再 create 或者 update
// resultRow undefinde 表示没有 如果有返回数据内容
const resultRow = await this.ProductModel.findOne({
where: { id: product.id }
})
if (!resultRow) {
// todo 添加
productRow = await this.ProductModel.create(product);
addOrUpdate = '添加'
if (!productRow) return '添加失败'
} else {
// 更新
const [updateCount, [updateRow]] = await this.ProductModel.update(product, {
where: { id: product.id },
individualHooks: true
})
addOrUpdate = '更新'
if (updateCount < 1) '更新'
}
// 属性排除
async getProductList({ pageNum=1, pageSize=10 }){
const { count, rows } = await this.ProductModel.findAndCount({
// attributes:{exclude:['createTime','updateTime']}
order: [['id', 'ASC']],
limit: Number(pageSize | 0),
offset: Number(pageNum - 1 | 0) * Number(pageSize | 0),
})
rows.forEach(row => row && row.toJSON());
}
// 订单服务
// 支付宝 common/alipayConfig.js
module.exports = {
/* 更多参数请翻源码 */
/* 应用AppID */
appid: 2016091200492877,
/* 通知URL */
notifyUrl: 'http://9bqaiq.natappfree.cc/order/alipaycallback',
/* 应用RSA私钥 请勿忘记 -----BEGIN RSA PRIVATE KEY----- 与 -----END RSA PRIVATE KEY----- */
merchantPrivateKey: '-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEApsBXKCC0pZmKAAosGCgPfrWKpmyCG32LzZO3XJhuROpgfLYBCPF2t1k3i3o7E6ViCT7nlhZu8/vDszdCyIJhD2fLZEKy0knPTykzpGtp4S7H4wiDuPsQRsJ2qktd8knNzEthN/CXQu+AUj3ggrnkiqDxQ5EbdXQ4sK1VlgJ6t+gWLfepXC4KwtkVwJVIt3s67xghRiOpl2Y+AZL1HIfZvLQJUWzP92Ts/pNnvgotaywKM535kK8CcFrehmXObvYQ7zSauZTcWNcWI1qaKkjG1LGvCU2J4VQU43B2NY9blTpyuL9qxJ9hexP/fAAXToslf2aPAmdeSvvB5xoDZf2X6QIDAQABAoIBAEPoNlY4I3kA8wsbGWPpBI5kXgdyTvXlBcb9bgG+bcGQ9SQ0dm1u8BqwsYcSivZwNmFvhZ5AmoSvtb3JNmAzgFVmvpSg+PPcbRlevRIrUB4NEAfsEsCFNdarIOou8R5XYgDdfcTrLJ5srIRRgJmcHG88JaSPdnA5mVCR9jW14sX7jKrF+mE9zuVlxzEQFBEIKu9pGsqdutsvhfPwZH2kp1ji6Ltd1OxPgymFu3MQW+I7agZB8lqvOQql3/EbOaw6vy1uaqR4qSD6la2ckVlLxdyeDjBZZOKsR0R8SOkzJi9BBDnmx12aDatW4DwZI4uwOBJL4lhJN5ys/+D34wCI5oUCgYEA0InpKu3eoo6h+ghMeGRJ5buKbWjfmI8yUl39eOQ/ip3rO75N/TAFDKSCo3TtaA3ftfhn13MU6EEjDhoyix3NhLGndLHfrrtMM7umYq5P8AafEDjHiHqqo12Wvtg2pw943AFGg8V1EV+luB1m/qbWnA4tRQk1INbQ+A+ulyudrqsCgYEAzLPFi6WCmRoSGMlHX60E7B2nmVXrEVb80qg2qh34ZgLXLOqLt9pQgWkCw0LersKWIwIrFkhd9CTZk7ccpbAYfKlPuIxo4L+zxzqq1g9Z90A3yoVxCQG+RKdl2eGoUwuIj1TnubCy8DPxTyOm3TwJo50i4D/HNEtixXyujqZJA7sCgYBxoeRjFxDMpUoP03vP0l4OB74rVg0YtVanWT3oJP+WyexHNrCKeSMXO4FQDkPbAkxXfM8gsD3BPNUcNxw5f/jgCGoGBXKsZLTmL6c/eFpooUMFdNsNPEJFGJcu0OQe7iheQXeqD+t1lxfXFnZr5n9ks7jpOFYx2bwun2T0TLj0VwKBgC2tb8dZh2rihmdBgsu2sAKAG4X7xhh4cLIRFyGezm70807yh3rfHFfENvmbUlVs1lO5iCPQwiZYkrSDh8DxKoWmwkNMEZsVK+ipDrX1dv3VNp3aaP65hNuM/w0/bXAagr55E7w70bIH5TDjo7h6TSxVRBMGKE1jBQdMaycps+FBAoGAKe7TNAohYjde+Hc6DMad7FPX1vZnMad8khWmw2vE+KAJe2I5VflBMPk6OekUa3l8GLbecIl9+dICbyqpVo9u3c4JI9MkwJGzx6qdEmqT6cumgBay6CE7eX/wIkZQ+/VZVEt2zgrReMNx1NtbHxp8ushGpblQcUKdwqn063gmnOg=\n-----END RSA PRIVATE KEY-----',
/* 支付宝公钥 如果为空会使用默认值 请勿忘记 -----BEGIN PUBLIC KEY----- 与 -----END PUBLIC KEY----- */
alipayPublicKey: '-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs1qN9Jc9Sf+wnRxVHcHruXQq/YjWIe47Ay1e0ujNb8Ga+GS5Vlvg9UoISI1J8GUbNQR7gK2j81h6icbBVbMc4s5ZvPJTIOD0xODxdRH3daY04mkfYnshbu+ri5GhwrlGS9wAFKa57Ksb8P+EUZumNQL7rIJwFlW1UEiF/x252xG+1zplTnLnKkf1ERcPb4fo/kdtBD53bW5TFsY7IJ4NPqj9AnnfDdpFTZsXZ3ixPVz8uY8J5qganVXEieKpH1OSR9us9Egsh2OfR8AvLl1u2Py/qBecvXbggqPEzbNWLbNyJY0iK/KPXiDYiOV+MN/HHgCRXAEqR3g7Whh6ARswZwIDAQAB\n-----END PUBLIC KEY-----',
/* 支付宝支付网关 如果为空会使用沙盒网关 */
gatewayUrl: 'https://openapi.alipaydev.com/gateway.do',
};
const alipayftof = require('alipay-ftof');
const alipayf2f = new alipayftof(alipayf2fConfig);
const Alipay = require('alipay-mobile');
const alipayService = new Alipay(options);
this.ProductModel.hasOne(this.CartModel, { foreignKey: 'id' })
this.ProductModel.belongsTo(this.ProductModel, { foreignKey: 'productId' })
this.OrderItemModel.hasMany(this.OrderModel, { foreignKey: 'orderNum', targetKey: 'orderNum' })
this.OrderModel.belongsTo(this.OrderItemModel, { foreignKey: 'orderNum', targetKey: 'orderNum' })
this.ShippingModel.hasOne(this.OrderModel, { foreginKey: 'id' })
this.OrderModel.belongsTo(this.ShippingModel, { foreginKey: 'shippingId' })
module.exports = {
CANCELED: { CODE: 0, VALUE: '已取消' },
NO_PAY: { CODE: 10, VALUE: '未支付' },
PAID: { CODE: 20, VALUE: '已支付' },
SHIPPED: { CODE: 40, VALUE: '已发货' },
ORDER_SUCCESS: { CODE: 50, VALUE: '订单已完成' },
ORDER_CLOSE: { CODE: 60, VALUE: '订单关闭' },
};
// 生产支付二维码
async pay(orderNum){
const { id: userId } = this.session.currentUser;
const order = await this.OrderModel.findOne({ where: { userId, orderNum } })
.then(row => row && row.toJSON())
if (order.status >= OrderStus.PAID.CODE) '该订单不可支付'
const result = await alipayf2f.createQRPay(this.alipayData(order))
const { filename, url } = this.saveQrcode(result)
}
/**
* 返回对象 第一个匹配的 key
* 可以回调函数判断 类似数组
*/
_getEnumValueByCode(mapper, code){
return mapper[_.findKey(mapper, item => item.CODE === code)].VALUE
}
// 连表查询 例子:https://www.jb51.net/article/106782.htm
/* 'use strict' https://blog.csdn.net/huwei2003/article/details/77646054
const Sequelize = require('sequelize');
// 创建 sequelize 实例
const sequelize = new Sequelize('db1', 'root', '111111', { logging: console.log });
// 定义User模型
var User = sequelize.define('user', {
id: { type: Sequelize.BIGINT(11), autoIncrement: true, primaryKey: true, unique: true },
name: { type: Sequelize.STRING, comment: '姓名' },
sex: { type: Sequelize.INTEGER, allowNull: false, defaultValue: 0, comment: '性别' },
companyId: { type: Sequelize.BIGINT(11), field: 'company_id', allowNull: false, comment: '所属公司' },
isManager: { type: Sequelize.BOOLEAN, field: 'is_manager', allowNull: false, defaultValue: false, comment: '是否管理员' }
},
{
charset: 'utf8',
collate: 'utf8_general_ci'
});
// 定义Company模型
var Company = sequelize.define('company', {
id: { type: Sequelize.BIGINT(11), autoIncrement: true, primaryKey: true, unique: true },
name: { type: Sequelize.STRING, comment: '公司名称' }
},
{
charset: 'utf8',
collate: 'utf8_general_ci'
});
// 定义User-Company关联关系
User.belongsTo(Company, { foreignKey: 'companyId' });
// sequelize.sync({force:true}).then(() => {
// process.exit();
// });
Company.create({ name: '某公司' }).then((result) => {
return Promise.all([
User.create({ name: '何民三', sex: 1, companyId: result.id, isManager: true }),
User.create({ name: '张老二', sex: 1, companyId: result.id })
])
}).then((result) => {
console.log('done');
}).catch((err) => {
console.error(err);
});
var include = [{
model: Company,
as: 'company'
}];
User.findOne({ include: include }).then((result) => {
console.log(result.name + ' 是 ' + result.company.name + ' 的员工');
}).catch((err) => {
console.error(err);
});
何民三 是 某公司 的员工
var include = [{
association: Company.hasOne(User, { foreignKey: 'companyId', as: 'manager' }),
where: { isManager: true }
}]
Company.findOne({ include: include }).then((result) => {
console.log(result.name + ' 的管理员是 ' + result.manager.name);
}).catch((err) => {
console.error(err);
});
某公司 的管理员是 何民三 */
async _getCartListWithProduct(userId){
const arr = await this.CartModel.findAll({
where: { userId, checked: CHECKED },
include: [{ model: this.ProductModel, where: { id: app.Sequelize.col('productId'), status: ON_SALE.CODE } }]
// 返回处理好的数组?
}).then(rows => rows && rows.map(r => r.toJSON()))
/*
估计返回
商品,
数量,
用户,
选择,
product:商品表具体内容
*/
if(arr.length === 0) '购无车为空'
// 检测是否有货
if(!this._ckeckStock(arr).hasStock) '库存不足'
}
// 检查库存
/*
存在无库存的情况就push到数组里面
*/
_checkStock(list) {
let arr = []
list.forEach(item => {
// 商品库存 小于 购物车下单量
if (item.product.stock < item.quantity) {
arr.push(item.product.name)
}
})
return { hasStock : arr.length === 0, noStockList: arr }
}
const orderNum = Date.now() + _.random(100)
// 整数 获取整数100 内随机 创建订单号
// 创建订单
// 1.拿到收货地址
const shipping= await this.ShippingModel.findOne({where:{id:shippingId,userId}}).then(r=>r&&r.toJSON())
if(!shipping) reutn '用户无收货地址'
// 2.购物车获取数据 判断有没有货
_getCartListWithProduct
// 3. 创建支付订单 用户,收货地址 支付总价
// 4. 更新库存
await this.ProductModel.update({ stock: app.Sequelize.literal(`stock - ${item.quantity}`) }, { where: { id: item.productId }})
await this.ProductModel.update({stock:app.Sequelize.literal(`stock-${item.quantity}`)},{where:{id:item.productId}})
// 清空购物车 这个逻辑不好 不能做在下一单
// 清空购物车
async _cleanCart(cartList) {
cartList.forEach(async item => {
await this.CartModel.destroy({ where: { id: item.id } })
})
}
/model/CategoryModel.js
// 父类别id 为0时为根节点,一级类别
parentId: {
type: UUID,
allowNull: true,
},
// 类别状态1-正常,2-废弃
status: {
type: INTEGER(1),
allowNull: true,
defaultValue: 1,
},
// 排序编号,同类展示顺序,相等则自然排序
sortOrder: {
type: INTEGER(4),
allowNull: true,
},
// 返回去重后的数组
const categoryUniqList = _.uniqWith(categoryList, _.isEqual);
// /router.js
module.exports=app=>{
const {router,controller}=app;
router.get('/',controller.home.index)
require('./router/portal/cartRouter')(app)//路由分文件夹
}
// /router/portal/cartRouter.js
module.exports=app=>{
const checkLogin=app.middleware.checkLogin();//登录中间件
}
// 购物车更新 需要权限 使用中间件
app.router.post('/cart/update',checkLogin,app.controller.portal.cartController.addOrUpdate)
// /server.js
cosnt egg=require('egg');
const workers =Number(process.argv[2]||require('os').cpus().length)
egg.startCluster({
workers,
baseDir:__dirname,
})
// app.js
module.exports = app => {
app.beforeStart(async function() {
// 应用会等待这个函数执行完成才启动
// await app.model.sync({ force: true }); // 开发环境使用
/* egg-sequelize
We strongly recommend you to use migrations to create or migrate database.
This code should only be used in development.
if (app.config.env === 'local') {
app.beforeStart(function* () {
yield app.model.sync({force: true});
});
}
同步数据 迁移
*/
await app.model.sync({});
});
};
exports.relativeTime = time => moment(new Date(time * 1000)).fromNow();//a minute ago
// 返回日期距离当前的一个 描述
// 封装响应
const ServerResponse = require('../common/serverResponse');
const ResponseCode = require('../common/responseCode');
// 定义返回错误标志
module.exports = {
SUCCESS: 0,
ERROR: 1,
NEED_LOGIN: 10,
NO_AUTH: 20,
ILLEGAL_ARGUMENT: 2,
};
// server 返回一个对象 调用serverResponse类 返回 对象
module.exports = class ServerResponse {
constructor(status, msg, data) {
this.status = status;
this.msg = msg;
this.data = data;
}
// 这个返回结果类可以拿到 数据 提示 和code 统一定义返回
}
if (!productId || !count)
return this.ServerResponse
.createByErrorMsg(this.ResponseCode.ILLEGAL_ARGUMENT, 'ILLEGAL_ARGUMENT');
static createByErrorCodeMsg(errorCode, errorMsg) {
return new ServerResponse(errorCode, errorMsg, null);
}
egg源码记录,
最新推荐文章于 2023-01-16 15:44:40 发布