├── .gitignore ├── README.md ├── cloudfunctions ├── addComment │ ├── index.js │ └── package.json ├── addOrder │ ├── index.js │ └── package.json ├── addTrolley │ ├── index.js │ └── package.json ├── getOrderList │ ├── index.js │ └── package.json ├── getTrolleyList │ ├── index.js │ └── package.json ├── productDetail │ ├── index.js │ └── package.json └── updateTrolley │ ├── index.js │ └── package.json ├── data ├── products.json ├── products │ ├── product1.jpg │ ├── product10.jpg │ ├── product11.jpg │ ├── product12.jpg │ ├── product13.jpg │ ├── product14.jpg │ ├── product15.jpg │ ├── product2.jpg │ ├── product3.jpg │ ├── product4.jpg │ ├── product5.jpg │ ├── product6.jpg │ ├── product7.jpg │ ├── product8.jpg │ └── product9.jpg └── screenshot │ ├── screenshot1.png │ ├── screenshot2.png │ ├── screenshot3.png │ ├── screenshot4.png │ ├── screenshot5.png │ ├── screenshot6.png │ ├── screenshot7.png │ └── screenshot8.png ├── miniprogram ├── app.js ├── app.json ├── app.wxss ├── components │ ├── login.js │ ├── login.json │ ├── login.wxml │ ├── login.wxss │ ├── product.js │ ├── product.json │ ├── product.wxml │ └── product.wxss ├── images │ ├── bg.png │ ├── check-yellow.png │ ├── check.png │ ├── discount.png │ ├── grey-arrow.png │ ├── home-sel.png │ ├── home.png │ ├── image.png │ ├── line-black.png │ ├── line-red.png │ ├── order-sel.png │ ├── order.png │ ├── trolley-sel.png │ ├── trolley.png │ ├── user-sel.png │ └── user.png ├── pages │ ├── add-comment │ │ ├── add-comment.js │ │ ├── add-comment.json │ │ ├── add-comment.wxml │ │ └── add-comment.wxss │ ├── comment │ │ ├── comment.js │ │ ├── comment.json │ │ ├── comment.wxml │ │ └── comment.wxss │ ├── detail │ │ ├── detail.js │ │ ├── detail.json │ │ ├── detail.wxml │ │ └── detail.wxss │ ├── home │ │ ├── home.js │ │ ├── home.json │ │ ├── home.wxml │ │ └── home.wxss │ ├── order │ │ ├── order.js │ │ ├── order.json │ │ ├── order.wxml │ │ └── order.wxss │ ├── trolley │ │ ├── trolley.js │ │ ├── trolley.json │ │ ├── trolley.wxml │ │ └── trolley.wxss │ └── user │ │ ├── user.js │ │ ├── user.json │ │ ├── user.wxml │ │ └── user.wxss ├── sitemap.json └── utils │ ├── db.js │ └── util.js └── project.config.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows 2 | [Dd]esktop.ini 3 | Thumbs.db 4 | $RECYCLE.BIN/ 5 | 6 | # macOS 7 | .DS_Store 8 | .fseventsd 9 | .Spotlight-V100 10 | .TemporaryItems 11 | .Trashes 12 | 13 | # Node.js 14 | node_modules/ 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 闲商城 2 | 3 | 优达学城商城类小程序项目。本项目使用的是云开发进行后端搭建,是一个比较综合的项目,需要具备一定的 **JavaScript、CSS** 知识。 4 | 5 | [tencent-cloud分支](https://github.com/fujianlian/mall/tree/tencent-cloud)是基于**腾讯云服务**进行后端开发的,相对比来说比较复杂,建议选择**云开发**模式开发 6 | 7 | ## 小程序截图 8 | 9 | ![1](./data/screenshot/screenshot1.png) | ![2](./data/screenshot/screenshot2.png) | ![3](./data/screenshot/screenshot3.png) | ![4](./data/screenshot/screenshot4.png) | 10 | | :--: | :--: | :--: | :--: | 11 | | 首页 | 订单 | 购物车 | 个人中心 | 12 | 13 | ![1](./data/screenshot/screenshot5.png) | ![2](./data/screenshot/screenshot6.png) | ![3](./data/screenshot/screenshot7.png) | ![4](./data/screenshot/screenshot8.png) | 14 | | :--: | :--: | :--: | :--: | 15 | | 商品详情 | 添加评论 | 用户评论 | 未登录 | 16 | 17 | # 云开发 quickstart 18 | 19 | 这是云开发的快速启动指引,其中演示了如何上手使用云开发的三大基础能力: 20 | 21 | - 数据库:一个既可在小程序前端操作,也能在云函数中读写的 JSON 文档型数据库 22 | - 文件存储:在小程序前端直接上传/下载云端文件,在云开发控制台可视化管理 23 | - 云函数:在云端运行的代码,微信私有协议天然鉴权,开发者只需编写业务逻辑代码 24 | 25 | ## 参考文档 26 | 27 | - [云开发文档](https://developers.weixin.qq.com/miniprogram/dev/wxcloud/basis/getting-started.html) 28 | 29 | # 运行准备 30 | 31 | 注册[小程序开发帐号](https://mp.weixin.qq.com/cgi-bin/registermidpage?action=index),完成注册之后,登录[微信公众平台官网](https://mp.weixin.qq.com/) ,点击 **“设置 -> 开发设置”**,获取你的 **AppID 帐号**,后面初始化项目需要用到。 32 | 33 | ## 运行项目 34 | 35 | 1. 安装[微信开发者工具](https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html) 36 | 37 | 2. 下载源码,打开微信开发者,选择小程序导入源码,**AppID改为自己申请的** 38 | 39 | 3. 接下来申请云开发功能,进入云开发页面 40 | 41 | * 在存储里创建 **products** 文件夹,将data/products里的所有图片上传到products文件夹中 42 | 43 | * 在数据库里创建 **order/product/review/trolley** 四个集合,将data/products.json导入到product集合中,注意修改image的地址前缀 44 | 45 | * env修改,可参考[这篇文章](https://blog.csdn.net/Sprintf_HelloWorld/article/details/86746684) 46 | 47 | * 上传云函数,运行即可 48 | 49 | ## 贡献 50 | 51 | * 如果你在使用过程中遇到问题,欢迎给我提Issue 52 | 53 | * 如果你有好的想法,欢迎pull request 54 | 55 | * 觉得不错的话,顺手 **点个Star**,笔者需要您的支持 56 | 57 | -------------------------------------------------------------------------------- /cloudfunctions/addComment/index.js: -------------------------------------------------------------------------------- 1 | // 云函数入口文件 2 | const cloud = require('wx-server-sdk') 3 | 4 | cloud.init({ 5 | traceUser: true, 6 | env: 'mall-7vt8m', 7 | }) 8 | 9 | const db = cloud.database() 10 | 11 | exports.main = async (event, context) => { 12 | const wxContext = cloud.getWXContext() 13 | const user = wxContext.OPENID 14 | 15 | await db.collection('review').add({ 16 | data: { 17 | user, 18 | username: event.username, 19 | avatar: event.avatar, 20 | content: event.content, 21 | productId: event.productId, 22 | createTime: +new Date(), 23 | images: (event.images || []).join(';'), 24 | }, 25 | }) 26 | 27 | return {} 28 | } -------------------------------------------------------------------------------- /cloudfunctions/addComment/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "addComment", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "wx-server-sdk": "latest" 13 | } 14 | } -------------------------------------------------------------------------------- /cloudfunctions/addOrder/index.js: -------------------------------------------------------------------------------- 1 | // 云函数入口文件 2 | const cloud = require('wx-server-sdk') 3 | 4 | cloud.init({ 5 | traceUser: true, 6 | env: 'mall-7vt8m', 7 | }) 8 | 9 | const db = cloud.database() 10 | 11 | // 云函数入口函数 12 | exports.main = async (event, context) => { 13 | const wxContext = cloud.getWXContext() 14 | const user = wxContext.OPENID 15 | 16 | const productList = event.list || [] 17 | const isCheckout = !!event.isCheckout 18 | 19 | await db.collection('order').add({ 20 | data: { 21 | user, 22 | createTime: +new Date(), 23 | productList, 24 | }, 25 | }) 26 | 27 | if (isCheckout) { 28 | await db.collection('trolley').where({ 29 | productId: db.command.in(productList.map(product => product.productId)) 30 | }).remove() 31 | } 32 | 33 | return {} 34 | } -------------------------------------------------------------------------------- /cloudfunctions/addOrder/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "addOrder", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "wx-server-sdk": "latest" 13 | } 14 | } -------------------------------------------------------------------------------- /cloudfunctions/addTrolley/index.js: -------------------------------------------------------------------------------- 1 | // 云函数入口文件 2 | const cloud = require('wx-server-sdk') 3 | 4 | cloud.init({ 5 | traceUser: true, 6 | env: 'mall-7vt8m', 7 | }) 8 | 9 | const db = cloud.database() 10 | 11 | // 云函数入口函数 12 | exports.main = async (event, context) => { 13 | const wxContext = cloud.getWXContext() 14 | const user = wxContext.OPENID 15 | const productId = event._id 16 | 17 | const cartRes = await db.collection('trolley').where({ 18 | productId, 19 | user, 20 | }).get() 21 | const cartList = cartRes.data 22 | 23 | if (!cartList.length) { 24 | await db.collection('trolley').add({ 25 | data: { 26 | productId, 27 | count: 1, 28 | user, 29 | image: event.image, 30 | name: event.name, 31 | price: event.price, 32 | }, 33 | }) 34 | } else { 35 | const count = cartList[0].count + 1 36 | await db.collection('trolley').doc(cartList[0]._id).update({ 37 | data: { 38 | count, 39 | }, 40 | }) 41 | } 42 | 43 | return {} 44 | } -------------------------------------------------------------------------------- /cloudfunctions/addTrolley/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "addTrolley", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "wx-server-sdk": "latest" 13 | } 14 | } -------------------------------------------------------------------------------- /cloudfunctions/getOrderList/index.js: -------------------------------------------------------------------------------- 1 | // 云函数入口文件 2 | const cloud = require('wx-server-sdk') 3 | 4 | cloud.init({ 5 | traceUser: true, 6 | env: 'mall-7vt8m', 7 | }) 8 | 9 | const db = cloud.database() 10 | 11 | // 云函数入口函数 12 | exports.main = async (event, context) => { 13 | const wxContext = cloud.getWXContext() 14 | const user = wxContext.OPENID 15 | 16 | // Order List 17 | const orderRes = await db.collection('order').where({ 18 | user, 19 | }).get() 20 | const orderList = orderRes.data 21 | 22 | return orderList 23 | } -------------------------------------------------------------------------------- /cloudfunctions/getOrderList/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "getOrderList", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "wx-server-sdk": "latest" 13 | } 14 | } -------------------------------------------------------------------------------- /cloudfunctions/getTrolleyList/index.js: -------------------------------------------------------------------------------- 1 | // 云函数入口文件 2 | const cloud = require('wx-server-sdk') 3 | 4 | cloud.init({ 5 | traceUser: true, 6 | env: 'mall-7vt8m', 7 | }) 8 | 9 | const db = cloud.database() 10 | 11 | // 云函数入口函数 12 | exports.main = async (event, context) => { 13 | const wxContext = cloud.getWXContext() 14 | const user = wxContext.OPENID 15 | 16 | // trolley list 17 | const trolleyRes = await db.collection('trolley').where({ 18 | user, 19 | }).get() 20 | const trolleyList = trolleyRes.data 21 | 22 | return trolleyList 23 | } -------------------------------------------------------------------------------- /cloudfunctions/getTrolleyList/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "getTrolleyList", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "wx-server-sdk": "latest" 13 | } 14 | } -------------------------------------------------------------------------------- /cloudfunctions/productDetail/index.js: -------------------------------------------------------------------------------- 1 | // 云函数入口文件 2 | const cloud = require('wx-server-sdk') 3 | 4 | cloud.init({ 5 | traceUser: true, 6 | env: 'mall-7vt8m', 7 | }) 8 | 9 | const db = cloud.database() 10 | 11 | // 云函数入口函数 12 | exports.main = async (event, context) => { 13 | const id = event.id 14 | 15 | // product detail 16 | const productRes = await db.collection('product').doc(id).get() 17 | const product = productRes.data 18 | 19 | return product 20 | } -------------------------------------------------------------------------------- /cloudfunctions/productDetail/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "productDetail", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "wx-server-sdk": "latest" 13 | } 14 | } -------------------------------------------------------------------------------- /cloudfunctions/updateTrolley/index.js: -------------------------------------------------------------------------------- 1 | // 云函数入口文件 2 | const cloud = require('wx-server-sdk') 3 | 4 | cloud.init({ 5 | traceUser: true, 6 | env: 'mall-7vt8m', 7 | }) 8 | 9 | const db = cloud.database() 10 | 11 | // 云函数入口函数 12 | exports.main = async (event, context) => { 13 | const wxContext = cloud.getWXContext() 14 | const user = wxContext.OPENID 15 | const productList = event.list 16 | 17 | // delete all the data from cart 18 | await db.collection('trolley').where({ 19 | user, 20 | }).remove() 21 | 22 | // fill cart with updated data 23 | for (const product of productList) { 24 | await db.collection('trolley').add({ 25 | data: { 26 | productId: product.productId, 27 | count: product.count, 28 | user, 29 | image: product.image, 30 | name: product.name, 31 | price: product.price, 32 | }, 33 | }) 34 | } 35 | 36 | return {} 37 | } -------------------------------------------------------------------------------- /cloudfunctions/updateTrolley/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "updateTrolley", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "wx-server-sdk": "latest" 13 | } 14 | } -------------------------------------------------------------------------------- /data/products.json: -------------------------------------------------------------------------------- 1 | { 2 | "image": "xxx/products/product1.jpg", 3 | "name": "Toy Holster", 4 | "price": 132.00, 5 | "source": "CHINA" 6 | } 7 | { 8 | "image": "xxx/products/product2.jpg", 9 | "name": "Golden Acoustic Guitar", 10 | "price": 480.50, 11 | "source": "CHINA" 12 | } 13 | { 14 | "image": "xxx/products/product3.jpg", 15 | "name": "Red Iron Stapler", 16 | "price": 28.00, 17 | "source": "CHINA" 18 | } 19 | { 20 | "image": "xxx/products/product4.jpg", 21 | "name": "Fresh Organic Vegetables", 22 | "price": 30.90, 23 | "source": "CHINA" 24 | } 25 | { 26 | "image": "xxx/products/product5.jpg", 27 | "name": "Imitation Iron Plate Clock", 28 | "price": 45.00, 29 | "source": "SWEDEN" 30 | } 31 | { 32 | "image": "xxx/products/product6.jpg", 33 | "name": "Fresh Grapes", 34 | "price": 24.80, 35 | "source": "CHINA" 36 | } 37 | { 38 | "image": "xxx/products/product7.jpg", 39 | "name": "Fruit and Vegetable Spree", 40 | "price": 158.00, 41 | "source": "NEW ZEALAND" 42 | } 43 | { 44 | "image": "xxx/products/product8.jpg", 45 | "name": "Red Retro Car Model", 46 | "price": 35.00, 47 | "source": "GERMANY" 48 | } 49 | { 50 | "image": "xxx/products/product9.jpg", 51 | "name": "Winding Electric Motorcycle", 52 | "price": 249.00, 53 | "source": "CHINA" 54 | } 55 | { 56 | "image": "xxx/products/product10.jpg", 57 | "name": "Red Apples", 58 | "price": 29.80, 59 | "source": "CHINA" 60 | } 61 | { 62 | "image": "xxx/products/product11.jpg", 63 | "name": "Durable Men's Shoes", 64 | "price": 335.00, 65 | "source": "CHINA" 66 | } 67 | { 68 | "image": "xxx/products/product12.jpg", 69 | "name": "Religious Place Tourism Memorial", 70 | "price": 1668.00, 71 | "source": "INDIA" 72 | } 73 | { 74 | "image": "xxx/products/product13.jpg", 75 | "name": "High Quality Pump", 76 | "price": 2000.80, 77 | "source": "CHINA" 78 | } 79 | { 80 | "image": "xxx/products/product14.jpg", 81 | "name": "King Kong Rings", 82 | "price": 34.00, 83 | "source": "CHINA" 84 | } 85 | { 86 | "image": "xxx/products/product15.jpg", 87 | "name": "Halloween Pumpkin", 88 | "price": 29.90, 89 | "source": "USA" 90 | } -------------------------------------------------------------------------------- /data/products/product1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/products/product1.jpg -------------------------------------------------------------------------------- /data/products/product10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/products/product10.jpg -------------------------------------------------------------------------------- /data/products/product11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/products/product11.jpg -------------------------------------------------------------------------------- /data/products/product12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/products/product12.jpg -------------------------------------------------------------------------------- /data/products/product13.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/products/product13.jpg -------------------------------------------------------------------------------- /data/products/product14.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/products/product14.jpg -------------------------------------------------------------------------------- /data/products/product15.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/products/product15.jpg -------------------------------------------------------------------------------- /data/products/product2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/products/product2.jpg -------------------------------------------------------------------------------- /data/products/product3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/products/product3.jpg -------------------------------------------------------------------------------- /data/products/product4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/products/product4.jpg -------------------------------------------------------------------------------- /data/products/product5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/products/product5.jpg -------------------------------------------------------------------------------- /data/products/product6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/products/product6.jpg -------------------------------------------------------------------------------- /data/products/product7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/products/product7.jpg -------------------------------------------------------------------------------- /data/products/product8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/products/product8.jpg -------------------------------------------------------------------------------- /data/products/product9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/products/product9.jpg -------------------------------------------------------------------------------- /data/screenshot/screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/screenshot/screenshot1.png -------------------------------------------------------------------------------- /data/screenshot/screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/screenshot/screenshot2.png -------------------------------------------------------------------------------- /data/screenshot/screenshot3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/screenshot/screenshot3.png -------------------------------------------------------------------------------- /data/screenshot/screenshot4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/screenshot/screenshot4.png -------------------------------------------------------------------------------- /data/screenshot/screenshot5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/screenshot/screenshot5.png -------------------------------------------------------------------------------- /data/screenshot/screenshot6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/screenshot/screenshot6.png -------------------------------------------------------------------------------- /data/screenshot/screenshot7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/screenshot/screenshot7.png -------------------------------------------------------------------------------- /data/screenshot/screenshot8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/data/screenshot/screenshot8.png -------------------------------------------------------------------------------- /miniprogram/app.js: -------------------------------------------------------------------------------- 1 | //app.js 2 | 3 | App({ 4 | 5 | onLaunch: function () { 6 | 7 | if (!wx.cloud) { 8 | console.error('请使用 2.2.3 或以上的基础库以使用云能力') 9 | } else { 10 | wx.cloud.init({ 11 | traceUser: true, 12 | env: 'mall-7vt8m', 13 | }) 14 | } 15 | 16 | this.globalData = {} 17 | }, 18 | 19 | checkSession({ 20 | success, 21 | error 22 | }) { 23 | wx.checkSession({ 24 | success: () => { 25 | this.getUserInfo({ 26 | success, 27 | error 28 | }) 29 | }, 30 | fail: () => { 31 | error && error() 32 | } 33 | }) 34 | }, 35 | }) 36 | -------------------------------------------------------------------------------- /miniprogram/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ 3 | "pages/home/home", 4 | "pages/order/order", 5 | "pages/trolley/trolley", 6 | "pages/user/user", 7 | "pages/detail/detail", 8 | "pages/add-comment/add-comment", 9 | "pages/comment/comment" 10 | ], 11 | "tabBar": { 12 | "color": "#5d5f64", 13 | "selectedColor": "#5d5f64", 14 | "backgroundColor": "#fff", 15 | "position": "bottom", 16 | "borderStyle": "white", 17 | "list": [ 18 | { 19 | "pagePath": "pages/home/home", 20 | "iconPath": "images/home.png", 21 | "selectedIconPath": "images/home-sel.png", 22 | "text": "首页" 23 | }, 24 | { 25 | "pagePath": "pages/order/order", 26 | "iconPath": "images/order.png", 27 | "selectedIconPath": "images/order-sel.png", 28 | "text": "订单" 29 | }, 30 | { 31 | "pagePath": "pages/trolley/trolley", 32 | "iconPath": "images/trolley.png", 33 | "selectedIconPath": "images/trolley-sel.png", 34 | "text": "购物车" 35 | }, 36 | { 37 | "pagePath": "pages/user/user", 38 | "iconPath": "images/user.png", 39 | "selectedIconPath": "images/user-sel.png", 40 | "text": "个人中心" 41 | } 42 | ] 43 | }, 44 | "window": { 45 | "backgroundColor": "#F6F6F6", 46 | "backgroundTextStyle": "light", 47 | "navigationBarBackgroundColor": "#fff", 48 | "navigationBarTitleText": "商城小程序", 49 | "navigationBarTextStyle": "black" 50 | }, 51 | "sitemapLocation": "sitemap.json" 52 | } -------------------------------------------------------------------------------- /miniprogram/app.wxss: -------------------------------------------------------------------------------- 1 | /**app.wxss**/ 2 | 3 | page { 4 | background: #f9f9f9; 5 | } 6 | 7 | .bg { 8 | position: absolute; 9 | left: 0; 10 | top: 0; 11 | width: 100%; 12 | height: 144rpx; 13 | z-index: -1 14 | } 15 | 16 | .empty-list { 17 | display: flex; 18 | flex-direction: column; 19 | margin: 40rpx 30rpx; 20 | background: white; 21 | border-radius: 15rpx; 22 | box-shadow: 0 2rpx 13rpx 5rpx rgba(0, 0, 0, 0.05); 23 | height: 420rpx; 24 | justify-content: center; 25 | align-items: center; 26 | } 27 | 28 | .empty-image { 29 | margin-bottom: 29rpx; 30 | width: 90rpx; 31 | height: 90rpx; 32 | opacity: 0.4; 33 | } 34 | 35 | .empty-text { 36 | font-size: 28rpx; 37 | line-height: 42rpx; 38 | color: rgba(139, 139, 139, 0.8); 39 | } 40 | -------------------------------------------------------------------------------- /miniprogram/components/login.js: -------------------------------------------------------------------------------- 1 | // components/login.js 2 | Component({ 3 | /** 4 | * 组件的属性列表 5 | */ 6 | properties: { 7 | 8 | }, 9 | 10 | /** 11 | * 组件的初始数据 12 | */ 13 | data: { 14 | 15 | }, 16 | 17 | /** 18 | * 组件的方法列表 19 | */ 20 | methods: { 21 | onTapLogin(event) { 22 | const loginDetail = { 23 | userInfo: event.detail.userInfo 24 | } // detail object, Provided to the event listener function 25 | 26 | this.triggerEvent('onLogin', loginDetail) 27 | }, 28 | } 29 | }) -------------------------------------------------------------------------------- /miniprogram/components/login.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /miniprogram/components/login.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /miniprogram/components/login.wxss: -------------------------------------------------------------------------------- 1 | /* components/login.wxss */ 2 | .login-card { 3 | display: flex; 4 | align-items: center; 5 | margin: 50rpx 27rpx 0; 6 | height: 200rpx; 7 | background: #FFFFFF; 8 | box-shadow: 0 2rpx 13rpx 5rpx rgba(0, 0, 0, 0.02); 9 | border-radius: 13rpx; 10 | } 11 | 12 | .login-head { 13 | flex-shrink: 0; 14 | margin-left: 53rpx; 15 | height: 100rpx; 16 | width: 100rpx; 17 | background: #F5E069; 18 | border-radius: 50%; 19 | } 20 | 21 | .login-info { 22 | flex: 1; 23 | margin-left: 31rpx; 24 | } 25 | 26 | .login-text { 27 | line-height: 48rpx; 28 | font-size: 34rpx; 29 | color: rgba(29, 29, 38, 0.8); 30 | font-weight: bold; 31 | } 32 | 33 | .login-tips { 34 | margin-top: 6rpx; 35 | line-height: 33rpx; 36 | font-size: 24rpx; 37 | color: #8B8B8B; 38 | } 39 | 40 | .login-btn { 41 | margin: 34rpx auto 0; 42 | width: 250rpx; 43 | height: 80rpx; 44 | line-height: 80rpx; 45 | background: #F5E069; 46 | outline: none; 47 | border: none; 48 | border-radius: 10rpx; 49 | font-size: 30rpx; 50 | text-align: center; 51 | color: #34373D; 52 | font-weight: bold; 53 | } 54 | 55 | .login-btn::after { 56 | border: none; 57 | } -------------------------------------------------------------------------------- /miniprogram/components/product.js: -------------------------------------------------------------------------------- 1 | // components/product.js 2 | Component({ 3 | /** 4 | * 组件的属性列表 5 | */ 6 | properties: { 7 | productImage: String, 8 | productName: String, 9 | productPrice: String 10 | }, 11 | 12 | /** 13 | * 组件的初始数据 14 | */ 15 | data: { 16 | 17 | }, 18 | 19 | /** 20 | * 组件的方法列表 21 | */ 22 | methods: { 23 | 24 | } 25 | }) 26 | -------------------------------------------------------------------------------- /miniprogram/components/product.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /miniprogram/components/product.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{productName}} 6 | ¥ {{productPrice}} 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /miniprogram/components/product.wxss: -------------------------------------------------------------------------------- 1 | /* components/product.wxss */ 2 | .product-card { 3 | display: flex; 4 | align-items: center; 5 | padding-left: 26rpx; 6 | height: 200rpx; 7 | background: #FFFFFF; 8 | } 9 | 10 | .product-image { 11 | flex-shrink: 0; 12 | width: 160rpx; 13 | height: 160rpx; 14 | } 15 | 16 | .product-info { 17 | flex: 1; 18 | padding: 27rpx; 19 | height: 100%; 20 | box-sizing: border-box; 21 | font-size: 28rpx; 22 | line-height: 40rpx; 23 | } 24 | 25 | .product-name { 26 | color: rgba(29, 29, 38, 0.8); 27 | } 28 | 29 | .product-price { 30 | margin-top: 12rpx; 31 | font-weight: bold; 32 | } -------------------------------------------------------------------------------- /miniprogram/images/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/miniprogram/images/bg.png -------------------------------------------------------------------------------- /miniprogram/images/check-yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/miniprogram/images/check-yellow.png -------------------------------------------------------------------------------- /miniprogram/images/check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/miniprogram/images/check.png -------------------------------------------------------------------------------- /miniprogram/images/discount.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/miniprogram/images/discount.png -------------------------------------------------------------------------------- /miniprogram/images/grey-arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/miniprogram/images/grey-arrow.png -------------------------------------------------------------------------------- /miniprogram/images/home-sel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/miniprogram/images/home-sel.png -------------------------------------------------------------------------------- /miniprogram/images/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/miniprogram/images/home.png -------------------------------------------------------------------------------- /miniprogram/images/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/miniprogram/images/image.png -------------------------------------------------------------------------------- /miniprogram/images/line-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/miniprogram/images/line-black.png -------------------------------------------------------------------------------- /miniprogram/images/line-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/miniprogram/images/line-red.png -------------------------------------------------------------------------------- /miniprogram/images/order-sel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/miniprogram/images/order-sel.png -------------------------------------------------------------------------------- /miniprogram/images/order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/miniprogram/images/order.png -------------------------------------------------------------------------------- /miniprogram/images/trolley-sel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/miniprogram/images/trolley-sel.png -------------------------------------------------------------------------------- /miniprogram/images/trolley.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/miniprogram/images/trolley.png -------------------------------------------------------------------------------- /miniprogram/images/user-sel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/miniprogram/images/user-sel.png -------------------------------------------------------------------------------- /miniprogram/images/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fujianlian/mall/f212147e3b9753d6315ba7d485974b40970f852e/miniprogram/images/user.png -------------------------------------------------------------------------------- /miniprogram/pages/add-comment/add-comment.js: -------------------------------------------------------------------------------- 1 | // pages/add-comment/add-comment.js 2 | 3 | const db = require('../../utils/db.js') 4 | const util = require('../../utils/util') 5 | 6 | Page({ 7 | 8 | /** 9 | * 页面的初始数据 10 | */ 11 | data: { 12 | userInfo: null, 13 | product: null, 14 | commentValue: '', 15 | commentImages: [], 16 | }, 17 | 18 | /** 19 | * 生命周期函数--监听页面加载 20 | */ 21 | onLoad: function (options) { 22 | util.getUserInfo().then(userInfo => { 23 | this.setData({ 24 | userInfo 25 | }) 26 | this.setProduct(options) 27 | }).catch(err => { 28 | console.log('尚未通过身份验证') 29 | }) 30 | }, 31 | 32 | setProduct(options) { 33 | let product = this.data.product 34 | product = JSON.parse(options.data) 35 | this.setData({ 36 | product 37 | }) 38 | }, 39 | 40 | onInput(event) { 41 | this.setData({ 42 | commentValue: event.detail.value.trim() 43 | }) 44 | }, 45 | 46 | addComment(event) { 47 | let content = this.data.commentValue; 48 | if (!content) return 49 | 50 | wx.showLoading({ 51 | title: '正在发表评论' 52 | }) 53 | 54 | this.uploadImage(images => { 55 | db.addComment({ 56 | username: this.data.userInfo.nickName, 57 | avatar: this.data.userInfo.avatarUrl, 58 | content, 59 | productId: this.data.product.productId, 60 | images, 61 | }).then(result => { 62 | wx.hideLoading() 63 | 64 | const data = result.result 65 | 66 | if (data) { 67 | wx.showToast({ 68 | title: '发表评论成功' 69 | }) 70 | 71 | setTimeout(() => { 72 | wx.navigateBack() 73 | }, 1500) 74 | } else { 75 | wx.showToast({ 76 | icon: 'none', 77 | title: '发表评论失败' 78 | }) 79 | } 80 | }).catch(err => { 81 | console.error(err) 82 | wx.hideLoading() 83 | 84 | wx.showToast({ 85 | icon: 'none', 86 | title: '发表评论失败' 87 | }) 88 | }) 89 | }) 90 | }, 91 | 92 | chooseImage() { 93 | let currentImages = this.data.commentImages 94 | wx.chooseImage({ 95 | count: 3, 96 | sizeType: ['compressed'], 97 | sourceType: ['album', 'camera'], 98 | success: res => { 99 | currentImages = currentImages.concat(res.tempFilePaths) 100 | let end = currentImages.length 101 | let begin = Math.max(end - 3, 0) 102 | currentImages = currentImages.slice(begin, end) 103 | this.setData({ 104 | commentImages: currentImages 105 | }); 106 | }, 107 | }) 108 | }, 109 | 110 | previewImg(event) { 111 | let target = event.currentTarget 112 | let src = target.dataset.src 113 | 114 | wx.previewImage({ 115 | current: src, 116 | urls: this.data.commentImages 117 | }) 118 | }, 119 | 120 | uploadImage(callback) { 121 | const commentImages = this.data.commentImages 122 | const images = [] 123 | 124 | if (commentImages.length) { 125 | let imageCount = commentImages.length 126 | for (let i = 0; i < imageCount; i++) { 127 | db.uploadImage(commentImages[i]).then(result => { 128 | images.push(result.fileID) 129 | if (i === imageCount - 1) { 130 | callback && callback(images) 131 | } 132 | }).catch(err => { 133 | console.log('err', err) 134 | }) 135 | } 136 | } else { 137 | callback && callback(images) 138 | } 139 | } 140 | }) -------------------------------------------------------------------------------- /miniprogram/pages/add-comment/add-comment.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "添加评论", 3 | "usingComponents": { 4 | "product": "/components/product" 5 | } 6 | } -------------------------------------------------------------------------------- /miniprogram/pages/add-comment/add-comment.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 提交评价 -------------------------------------------------------------------------------- /miniprogram/pages/add-comment/add-comment.wxss: -------------------------------------------------------------------------------- 1 | /* pages/add-comment/add-comment.wxss */ 2 | 3 | .comment-cnt { 4 | margin: 29rpx 27rpx 0; 5 | padding-bottom: 26rpx; 6 | background: #fff; 7 | box-shadow: 0 2rpx 13rpx 5rpx rgba(0, 0, 0, 0.02); 8 | border-radius: 10rpx; 9 | } 10 | 11 | .comment-ipt { 12 | width: 100%; 13 | height: 207rpx; 14 | padding: 29rpx 34rpx; 15 | box-sizing: border-box; 16 | font-size: 28rpx; 17 | line-height: 40rpx; 18 | } 19 | 20 | .comment-placeholder { 21 | color: rgba(29, 29, 38, 0.4); 22 | } 23 | 24 | .preview-cnt { 25 | display: flex; 26 | margin-top: 29rpx; 27 | margin-left: 29rpx; 28 | } 29 | 30 | .preview-image { 31 | margin-right: 10rpx; 32 | width: 180rpx; 33 | height: 180rpx; 34 | border-radius: 5rpx; 35 | } 36 | 37 | .opr-upload { 38 | display: block; 39 | margin-top: 29rpx; 40 | margin-left: 29rpx; 41 | width: 43rpx; 42 | height: 43rpx; 43 | } 44 | 45 | .comment-btn { 46 | margin: 34rpx auto; 47 | width: 250rpx; 48 | height: 80rpx; 49 | line-height: 80rpx; 50 | text-align: center; 51 | background: #f5e069; 52 | border-radius: 10rpx; 53 | font-size: 30rpx; 54 | color: #34373d; 55 | } 56 | 57 | .comment-btn.dis { 58 | color: rgba(52, 55, 61, 0.5); 59 | } 60 | -------------------------------------------------------------------------------- /miniprogram/pages/comment/comment.js: -------------------------------------------------------------------------------- 1 | // pages/comment/comment.js 2 | 3 | const db = require('../../utils/db') 4 | const util = require('../../utils/util') 5 | 6 | Page({ 7 | 8 | /** 9 | * 页面的初始数据 10 | */ 11 | data: { 12 | commentList: [], // 评论列表 13 | product: null 14 | }, 15 | 16 | /** 17 | * 生命周期函数--监听页面加载 18 | */ 19 | onLoad: function (options) { 20 | let product = this.data.product 21 | product = JSON.parse(options.data) 22 | this.setData({ 23 | product 24 | }) 25 | this.getCommentList(product._id) 26 | }, 27 | 28 | getCommentList(productId) { 29 | db.getComments(productId).then(result => { 30 | const data = result.data 31 | console.log(result) 32 | if (data.length) { 33 | this.setData({ 34 | commentList: data.map(review => { 35 | review.createTime = util.formatTime(review.createTime, 'yyyy/MM/dd') 36 | review.images = review.images ? review.images.split(';') : [] 37 | return review 38 | }) 39 | }) 40 | } 41 | }).catch(err => { 42 | console.error(err) 43 | }) 44 | }, 45 | 46 | previewImg(event) { 47 | let target = event.currentTarget 48 | let current = target.dataset.current 49 | let urls = target.dataset.urls 50 | wx.previewImage({ 51 | current: current, 52 | urls: urls 53 | }) 54 | } 55 | }) -------------------------------------------------------------------------------- /miniprogram/pages/comment/comment.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "用户评论", 3 | "usingComponents": { 4 | "product": "/components/product" 5 | } 6 | } -------------------------------------------------------------------------------- /miniprogram/pages/comment/comment.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{commentList.length}}条评价 6 | 7 | 8 | 9 | 10 | {{item.username}} 11 | {{item.createTime}} 12 | 13 | {{item.content}} 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /miniprogram/pages/comment/comment.wxss: -------------------------------------------------------------------------------- 1 | /* pages/comment/comment.wxss */ 2 | 3 | .comment-list { 4 | margin-top: 16rpx; 5 | background: #fff; 6 | box-shadow: 0 2rpx 13rpx 5rpx rgba(0, 0, 0, 0.02); 7 | } 8 | 9 | .comment-title { 10 | padding: 25rpx 26rpx 14rpx; 11 | font-size: 30rpx; 12 | line-height: 42rpx; 13 | color: rgba(29, 29, 38, 0.8); 14 | font-weight: bold; 15 | } 16 | 17 | .comment-card { 18 | display: flex; 19 | padding: 30rpx 23rpx 0 26rpx; 20 | } 21 | 22 | .comment-card:last-child .comment-cnt { 23 | border-bottom: none; 24 | } 25 | 26 | .comment-avatar { 27 | flex-shrink: 0; 28 | width: 60rpx; 29 | height: 60rpx; 30 | border-radius: 50%; 31 | } 32 | 33 | .comment-cnt { 34 | flex: 1; 35 | margin-left: 24rpx; 36 | padding-bottom: 30rpx; 37 | border-bottom: 1px solid rgba(151, 151, 151, 0.2); 38 | } 39 | 40 | .comment-top { 41 | display: flex; 42 | font-size: 25rpx; 43 | line-height: 36rpx; 44 | color: rgba(29, 29, 38, 0.5); 45 | } 46 | 47 | .comment-username { 48 | flex: 1; 49 | } 50 | 51 | .comment-content { 52 | font-size: 28rpx; 53 | line-height: 40rpx; 54 | color: #1d1d26; 55 | } 56 | 57 | .preview-list { 58 | display: flex; 59 | margin-top: 16rpx; 60 | } 61 | 62 | .preview-item { 63 | margin-right: 10rpx; 64 | width: 180rpx; 65 | height: 180rpx; 66 | border-radius: 10rpx; 67 | } 68 | 69 | .preview-cnt { 70 | display: flex; 71 | margin-top: 20rpx; 72 | } 73 | 74 | .preview-image { 75 | margin-right: 10rpx; 76 | width: 180rpx; 77 | height: 180rpx; 78 | border-radius: 5rpx; 79 | } 80 | -------------------------------------------------------------------------------- /miniprogram/pages/detail/detail.js: -------------------------------------------------------------------------------- 1 | // pages/detail/detail.js 2 | 3 | const db = require('../../utils/db.js') 4 | const util = require('../../utils/util.js') 5 | 6 | Page({ 7 | 8 | /** 9 | * 页面的初始数据 10 | */ 11 | data: { 12 | product: {}, 13 | }, 14 | 15 | /** 16 | * 生命周期函数--监听页面加载 17 | */ 18 | onLoad: function (options) { 19 | let id = options.id 20 | this.getProduct(id) 21 | }, 22 | 23 | getProduct(id) { 24 | let self = this 25 | wx.showLoading({ 26 | title: '正在加载中...', 27 | }) 28 | 29 | db.getProductDetail(id).then(result => { 30 | wx.hideLoading() 31 | const data = result.result 32 | // get 2 digits price 33 | data.price = util.formatPrice(data.price) 34 | self.setData({ 35 | product: data 36 | }) 37 | }).catch(err => { 38 | console.error(err) 39 | wx.hideLoading() 40 | wx.showToast({ 41 | title: '加载数据失败', 42 | }) 43 | }) 44 | }, 45 | 46 | buy() { 47 | wx.showLoading({ 48 | title: '商品购买中...', 49 | }) 50 | 51 | const productToBuy = Object.assign({ 52 | count: 1 53 | }, this.data.product) 54 | productToBuy.productId = productToBuy._id 55 | console.log(productToBuy) 56 | db.addOrder({ 57 | list: [productToBuy] 58 | }).then(result => { 59 | wx.hideLoading() 60 | 61 | const data = result.result 62 | 63 | console.log(data) 64 | if (data) { 65 | wx.showToast({ 66 | title: '商品购买成功' 67 | }) 68 | } else { 69 | wx.showToast({ 70 | icon: 'none', 71 | title: '商品购买失败', 72 | }) 73 | } 74 | }).catch(err => { 75 | console.error(err) 76 | wx.hideLoading() 77 | wx.showToast({ 78 | icon: 'none', 79 | title: '商品购买失败', 80 | }) 81 | }) 82 | }, 83 | 84 | addToTrolley() { 85 | 86 | wx.showLoading({ 87 | title: '正在添加到购物车...', 88 | }) 89 | 90 | db.addTrolley(this.data.product).then(result => { 91 | wx.hideLoading() 92 | 93 | const data = result.result 94 | 95 | if (data) { 96 | wx.showToast({ 97 | title: '已添加到购物车' 98 | }) 99 | } else { 100 | wx.showToast({ 101 | icon: 'none', 102 | title: '添加到购物车失败', 103 | }) 104 | } 105 | }).catch(err => { 106 | console.error(err) 107 | wx.hideLoading() 108 | 109 | wx.showToast({ 110 | icon: 'none', 111 | title: '加入购物车' 112 | }) 113 | }) 114 | }, 115 | 116 | onTapCommentEntry() { 117 | let product = this.data.product 118 | if (product.reviewCount) { 119 | wx.navigateTo({ 120 | url: `/pages/comment/comment?data=${JSON.stringify(this.data.product)}` 121 | }) 122 | } 123 | } 124 | }) -------------------------------------------------------------------------------- /miniprogram/pages/detail/detail.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "商品详情" 3 | } -------------------------------------------------------------------------------- /miniprogram/pages/detail/detail.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{product.name}} 5 | {{product.source}} 6 | 7 | {{product.price}} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 7天免费退换 15 | 16 | 17 | 18 | 24小时内发货并赠送运费险 19 | 20 | 21 | 22 | 23 | 已买评价 24 | {{product.reviewCount}} 条 25 | 26 | 27 | {{product.firstComment.content}} 28 | 29 | 30 | 31 | 加入购物车 32 | 立即购买 33 | 34 | -------------------------------------------------------------------------------- /miniprogram/pages/detail/detail.wxss: -------------------------------------------------------------------------------- 1 | /* pages/detail/detail.wxss */ 2 | .top { 3 | background: white; 4 | padding: 30rpx 30rpx 20rpx; 5 | } 6 | 7 | .top-image { 8 | height: 300rpx; 9 | width: 300rpx; 10 | margin-left: 195rpx; 11 | } 12 | 13 | .top-name { 14 | font-size: 36rpx; 15 | line-height: 50rpx; 16 | margin-top: 20rpx; 17 | } 18 | 19 | .top-source { 20 | font-size: 26rpx; 21 | line-clamp: 35rpx; 22 | opacity: 0.5; 23 | margin-top: 5rpx; 24 | } 25 | 26 | .top-price-item { 27 | align-items: center; 28 | margin-top: 15rpx; 29 | display: flex; 30 | flex-flow: row-reverse; 31 | } 32 | 33 | .top-money { 34 | width: 36rpx; 35 | height: 36rpx; 36 | line-height: 36rpx; 37 | text-align: center; 38 | border-radius: 50%; 39 | color: #34373d; 40 | font-weight: 900; 41 | background: #f7e687; 42 | font-size: 24rpx; 43 | } 44 | 45 | .top-price { 46 | margin-left: 5rpx; 47 | font-size: 30rpx; 48 | line-height: 36rpx; 49 | } 50 | 51 | .service { 52 | padding: 25rpx 20rpx 0; 53 | margin: 30rpx; 54 | background: white; 55 | border-radius: 15rpx; 56 | box-shadow: 0 2rpx 13rpx 5rpx rgba(0, 0, 0, 0.05); 57 | } 58 | 59 | .service-promise { 60 | display: flex; 61 | margin-top: 15rpx; 62 | align-items: center; 63 | } 64 | 65 | .service-check { 66 | margin-right: 10rpx; 67 | width: 22rpx; 68 | height: 16rpx; 69 | } 70 | 71 | .service-promise-text { 72 | align-items: 15rpx; 73 | font-size: 26rpx; 74 | opacity: 0.7; 75 | } 76 | 77 | .line { 78 | background: #e6e6e6; 79 | height: 1rpx; 80 | margin-top: 36rpx; 81 | } 82 | 83 | .evaluation-wrapper { 84 | display: flex; 85 | flex-flow: column; 86 | padding-bottom: 10rpx; 87 | } 88 | 89 | .evaluation { 90 | display: flex; 91 | align-items: center; 92 | padding: 30rpx 0 20rpx; 93 | } 94 | 95 | .evaluation-title { 96 | flex: 1; 97 | font-size: 28rpx; 98 | line-height: 28rpx; 99 | } 100 | 101 | .evaluation-right { 102 | width: 11rpx; 103 | height: 18rpx; 104 | } 105 | 106 | .evaluation-num { 107 | font-size: 20rpx; 108 | line-height: 25rpx; 109 | margin-right: 9rpx; 110 | opacity: 0.4; 111 | } 112 | 113 | .evaluation-text { 114 | font-size: 24rpx; 115 | line-height: 34rpx; 116 | margin-bottom: 15rpx; 117 | opacity: 0.9; 118 | } 119 | 120 | .opr { 121 | position: fixed; 122 | bottom: 0; 123 | left: 0; 124 | right: 0; 125 | display: flex; 126 | align-items: center; 127 | } 128 | 129 | .opr-trolley, .opr-buy { 130 | flex: 1; 131 | height: 100rpx; 132 | line-height: 100rpx; 133 | text-align: center; 134 | font-size: 30rpx; 135 | color: #34373d; 136 | font-weight: bold; 137 | } 138 | 139 | .opr-trolley { 140 | background: rgba(245, 224, 105, 0.6); 141 | } 142 | 143 | .opr-buy { 144 | background: #f5e069; 145 | } 146 | -------------------------------------------------------------------------------- /miniprogram/pages/home/home.js: -------------------------------------------------------------------------------- 1 | // pages/home/home.js 2 | 3 | const db = require('../../utils/db.js') 4 | const util = require('../../utils/util.js') 5 | 6 | Page({ 7 | 8 | /** 9 | * 页面的初始数据 10 | */ 11 | data: { 12 | // 商品列表 13 | productList: [] 14 | }, 15 | 16 | /** 17 | * 生命周期函数--监听页面加载 18 | */ 19 | onLoad: function(options) { 20 | this.getList() 21 | }, 22 | 23 | /** 24 | * 获取商品列表 25 | */ 26 | getList() { 27 | let self = this 28 | wx.showLoading({ 29 | title: '正在加载中...', 30 | }) 31 | 32 | db.getProductList().then(result => { 33 | wx.hideLoading() 34 | 35 | const productList = result.data 36 | // get 2 digits price 37 | productList.forEach(product => product.price = util.formatPrice(product.price)) 38 | if (productList.length) { 39 | this.setData({ 40 | productList 41 | }) 42 | } 43 | }).catch(err => { 44 | console.error(err) 45 | wx.hideLoading() 46 | wx.showToast({ 47 | title: '加载数据失败', 48 | }) 49 | 50 | }) 51 | }, 52 | 53 | addToTrolley(event) { 54 | let index = event.currentTarget.dataset.index 55 | let d = this.data.productList[index] 56 | 57 | wx.showLoading({ 58 | title: '正在添加到购物车...', 59 | }) 60 | 61 | db.addTrolley(d).then(result => { 62 | wx.hideLoading() 63 | 64 | const data = result.result 65 | 66 | if (data) { 67 | wx.showToast({ 68 | title: '已添加到购物车' 69 | }) 70 | } else { 71 | wx.showToast({ 72 | icon: 'none', 73 | title: '添加到购物车失败', 74 | }) 75 | } 76 | }).catch(err => { 77 | console.error(err) 78 | wx.hideLoading() 79 | 80 | wx.showToast({ 81 | icon: 'none', 82 | title: '加入购物车' 83 | }) 84 | }) 85 | }, 86 | }) -------------------------------------------------------------------------------- /miniprogram/pages/home/home.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "首页" 3 | } -------------------------------------------------------------------------------- /miniprogram/pages/home/home.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{productList[0].name}} 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 春季推荐 15 | 16 | 17 | 18 | 19 | 20 | {{pitem.name}} 21 | 22 | 23 | {{pitem.price}} 24 | + 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /miniprogram/pages/home/home.wxss: -------------------------------------------------------------------------------- 1 | /* pages/home/home.wxss */ 2 | .hot-card { 3 | position: relative; 4 | margin: 32rpx 52rpx; 5 | background: white; 6 | border-radius: 15rpx; 7 | box-shadow: 0 2rpx 13rpx 5rpx rgba(0, 0, 0, 0.05); 8 | height: 320rpx; 9 | } 10 | 11 | .hot-name { 12 | position: absolute; 13 | top: 36rpx; 14 | left: 36rpx; 15 | display: flex; 16 | align-items: center; 17 | } 18 | 19 | .hot-name-line { 20 | width: 24rpx; 21 | height: 39rpx; 22 | } 23 | 24 | .hot-name-text { 25 | margin: 0 20rpx; 26 | font-size: 28rpx; 27 | color: #333; 28 | font-weight: bold; 29 | } 30 | 31 | .hot-image-discount { 32 | position: absolute; 33 | width: 259rpx; 34 | height: 188rpx; 35 | bottom: 0; 36 | left: 42rpx; 37 | } 38 | 39 | .hot-image { 40 | position: absolute; 41 | width: 240rpx; 42 | height: 240rpx; 43 | right: 36rpx; 44 | top: 40rpx; 45 | } 46 | 47 | .separator { 48 | display: flex; 49 | align-items: center; 50 | justify-content: center; 51 | margin: 70rpx 0 30rpx; 52 | } 53 | 54 | .separator-line { 55 | width: 21rpx; 56 | height: 34rpx; 57 | } 58 | 59 | .separator-text { 60 | margin: 0 20rpx; 61 | font-size: 28rpx; 62 | font-weight: bold; 63 | } 64 | 65 | .list { 66 | display: flex; 67 | margin: 0 27rpx 0 52rpx; 68 | justify-content: space-around; 69 | } 70 | 71 | .list-item { 72 | background: white; 73 | border-radius: 15rpx; 74 | box-shadow: 0 2rpx 13rpx 5rpx rgba(0, 0, 0, 0.05); 75 | width: 100%; 76 | margin-bottom: 25rpx; 77 | margin-right: 25rpx; 78 | } 79 | 80 | .list-item-image { 81 | height: 260rpx; 82 | width: 260rpx; 83 | margin: 10rpx 20rpx 15rpx; 84 | } 85 | 86 | .list-item-title { 87 | margin-left: 20rpx; 88 | font-size: 28rpx; 89 | font-weight: bold; 90 | opacity: 0.5; 91 | } 92 | 93 | .list-item-bottom { 94 | margin: 15rpx 20rpx; 95 | display: flex; 96 | } 97 | 98 | .list-item-bottom-icon { 99 | width: 36rpx; 100 | height: 36rpx; 101 | line-height: 36rpx; 102 | text-align: center; 103 | border-radius: 50%; 104 | color: #34373d; 105 | font-weight: 900; 106 | background: #f7e687; 107 | font-size: 24rpx; 108 | } 109 | 110 | .list-item-bottom-price { 111 | flex: 1; 112 | margin: 0 10rpx; 113 | font-size: 28rpx; 114 | } 115 | -------------------------------------------------------------------------------- /miniprogram/pages/order/order.js: -------------------------------------------------------------------------------- 1 | // pages/order/order.js 2 | 3 | const db = require('../../utils/db.js') 4 | const util = require('../../utils/util') 5 | 6 | Page({ 7 | 8 | /** 9 | * 页面的初始数据 10 | */ 11 | data: { 12 | userInfo: null, 13 | orderList: [], // 订单列表 14 | }, 15 | 16 | onShow() { 17 | util.getUserInfo().then(userInfo => { 18 | this.setData({ 19 | userInfo 20 | }) 21 | this.getOrder() 22 | }).catch(err => { 23 | console.log('尚未通过身份验证'); 24 | }) 25 | }, 26 | 27 | onTapLogin(event) { 28 | this.setData({ 29 | userInfo: event.detail.userInfo 30 | }) 31 | }, 32 | 33 | getOrder() { 34 | let that = this 35 | if (this.data.orderList.length == 0) 36 | wx.showLoading({ 37 | title: '刷新订单数据...', 38 | }) 39 | db.getOrderList().then(result => { 40 | wx.hideLoading() 41 | that.setData({ 42 | orderList: result.result 43 | }) 44 | }).catch(err => { 45 | console.error(err) 46 | wx.hideLoading() 47 | wx.showToast({ 48 | title: '刷新订单数据失败', 49 | }) 50 | }) 51 | }, 52 | 53 | goComment(event) { 54 | let product = event.currentTarget.dataset.item 55 | wx.navigateTo({ 56 | url: '/pages/add-comment/add-comment?data=' + JSON.stringify(product), 57 | }) 58 | } 59 | 60 | }) -------------------------------------------------------------------------------- /miniprogram/pages/order/order.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "订单", 3 | "usingComponents": { 4 | "login": "/components/login" 5 | } 6 | } -------------------------------------------------------------------------------- /miniprogram/pages/order/order.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 暂时还没有订单 9 | 10 | 11 | 12 | 13 | 已完成 14 | 15 | 16 | 17 | 18 | 19 | {{item.name}} 20 | ¥ {{item.price}} 21 | 22 | 23 | 评价 24 | x{{item.count}} 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /miniprogram/pages/order/order.wxss: -------------------------------------------------------------------------------- 1 | /* pages/order/order.wxss */ 2 | .order-head { 3 | margin: 40rpx 30rpx 15rpx; 4 | display: flex; 5 | align-items: center; 6 | } 7 | 8 | .order-head-line { 9 | width: 21rpx; 10 | height: 34rpx; 11 | } 12 | 13 | .order-head-text { 14 | margin-left: 10rpx; 15 | font-size: 24rpx; 16 | line-height: 33rpx; 17 | color: rgba(52, 55, 61, 0.8); 18 | } 19 | 20 | .order-block { 21 | margin: 0 26rpx 26rpx; 22 | background: #fff; 23 | box-shadow: 0 2rpx 13rpx 5rpx rgba(0, 0, 0, 0.02); 24 | border-radius: 13rpx; 25 | } 26 | 27 | .order-card { 28 | display: flex; 29 | align-items: center; 30 | margin-left: 19rpx; 31 | margin-right: 23rpx; 32 | height: 200rpx; 33 | border-bottom: 1px solid rgba(151, 151, 151, 0.2); 34 | } 35 | 36 | .order-card:last-child { 37 | border-bottom: none; 38 | } 39 | 40 | .order-image { 41 | flex-shrink: 0; 42 | width: 160rpx; 43 | height: 160rpx; 44 | } 45 | 46 | .order-info { 47 | flex: 1; 48 | padding: 27rpx; 49 | height: 100%; 50 | box-sizing: border-box; 51 | font-size: 28rpx; 52 | line-height: 40rpx; 53 | } 54 | 55 | .order-name { 56 | color: rgba(29, 29, 38, 0.8); 57 | } 58 | 59 | .order-price { 60 | margin-top: 12rpx; 61 | font-weight: bold; 62 | } 63 | 64 | .order-opr { 65 | flex-shrink: 0; 66 | margin-left: 59rpx; 67 | padding-top: 34rpx; 68 | height: 100%; 69 | box-sizing: border-box; 70 | font-size: 28rpx; 71 | } 72 | 73 | .order-btn { 74 | width: 100rpx; 75 | height: 52rpx; 76 | line-height: 52rpx; 77 | background: #F5E069; 78 | border-radius: 8rpx; 79 | text-align: center; 80 | } 81 | 82 | .order-count { 83 | margin-top: 49rpx; 84 | line-height: 40rpx; 85 | font-weight: bold; 86 | text-align: right; 87 | } 88 | -------------------------------------------------------------------------------- /miniprogram/pages/trolley/trolley.js: -------------------------------------------------------------------------------- 1 | // pages/trolley/trolley.js 2 | 3 | const db = require('../../utils/db.js') 4 | const util = require('../../utils/util') 5 | 6 | Page({ 7 | 8 | /** 9 | * 页面的初始数据 10 | */ 11 | data: { 12 | userInfo: null, 13 | trolleyList: [], // 购物车商品列表 14 | trolleyCheckMap: {}, // 购物车中选中的id哈希表 15 | trolleyAccount: 0, // 购物车结算总价 16 | isTrolleyEdit: false, // 购物车是否处于编辑状态 17 | isTrolleyTotalCheck: false, // 购物车中商品是否全选 18 | }, 19 | 20 | onShow() { 21 | util.getUserInfo().then(userInfo => { 22 | this.setData({ 23 | userInfo 24 | }) 25 | this.getList() 26 | }).catch(err => { 27 | console.log('尚未通过身份验证'); 28 | }) 29 | }, 30 | 31 | onTapLogin(event) { 32 | this.setData({ 33 | userInfo: event.detail.userInfo 34 | }) 35 | }, 36 | 37 | /** 38 | * 获取购物车列表 39 | */ 40 | getList() { 41 | let self = this 42 | if (this.data.trolleyList.length == 0) 43 | wx.showLoading({ 44 | title: '刷新购物车数据...', 45 | }) 46 | 47 | db.getTrolleyList().then(result => { 48 | wx.hideLoading(); 49 | const data = result.result; 50 | if (data.length) { 51 | // update the total price for cart 52 | this.setData({ 53 | trolleyAccount: util.formatPrice(0), 54 | trolleyList: data 55 | }) 56 | } 57 | }).catch(err => { 58 | console.error(err) 59 | wx.hideLoading() 60 | wx.showToast({ 61 | icon: 'none', 62 | title: '刷新数据失败' 63 | }) 64 | }) 65 | }, 66 | 67 | onTapCheckSingle(event) { 68 | let checkId = event.currentTarget.dataset.id 69 | let trolleyCheckMap = this.data.trolleyCheckMap 70 | let trolleyList = this.data.trolleyList 71 | let isTrolleyTotalCheck = this.data.isTrolleyTotalCheck 72 | let trolleyAccount = this.data.trolleyAccount 73 | // 单项商品被选中/取消 74 | trolleyCheckMap[checkId] = !trolleyCheckMap[checkId]; 75 | isTrolleyTotalCheck = true 76 | trolleyList.forEach(product => { 77 | if (!trolleyCheckMap[product.productId]) { 78 | // not all product selected 79 | isTrolleyTotalCheck = false 80 | } 81 | }); 82 | trolleyAccount = this.calcAccount(trolleyList, trolleyCheckMap); 83 | this.setData({ 84 | trolleyCheckMap, 85 | isTrolleyTotalCheck, 86 | trolleyAccount 87 | }) 88 | }, 89 | 90 | onTapCheckTotal() { 91 | let trolleyCheckMap = this.data.trolleyCheckMap 92 | let trolleyList = this.data.trolleyList 93 | let isTrolleyTotalCheck = this.data.isTrolleyTotalCheck 94 | let trolleyAccount = this.data.trolleyAccount 95 | 96 | // 全选按钮被选中/取消 97 | isTrolleyTotalCheck = !isTrolleyTotalCheck 98 | 99 | // 遍历并修改所有商品的状态 100 | trolleyList.forEach(product => { 101 | trolleyCheckMap[product.productId] = isTrolleyTotalCheck 102 | }) 103 | trolleyAccount = this.calcAccount(trolleyList, trolleyCheckMap) 104 | this.setData({ 105 | isTrolleyTotalCheck, 106 | trolleyCheckMap, 107 | trolleyAccount 108 | }) 109 | 110 | }, 111 | 112 | calcAccount(trolleyList, trolleyCheckMap) { 113 | let account = 0 114 | trolleyList.forEach(product => { 115 | account = trolleyCheckMap[product.productId] ? account + product.price * product.count : account 116 | }) 117 | 118 | return util.formatPrice(account) 119 | }, 120 | 121 | onTapEdit() { 122 | let isTrolleyEdit = this.data.isTrolleyEdit 123 | 124 | if (isTrolleyEdit) { 125 | this.updateTrolley() 126 | } else { 127 | this.setData({ 128 | isTrolleyEdit: !isTrolleyEdit 129 | }) 130 | } 131 | }, 132 | 133 | adjustTrolleyCount(event) { 134 | let trolleyCheckMap = this.data.trolleyCheckMap 135 | let trolleyList = this.data.trolleyList 136 | let dataset = event.currentTarget.dataset 137 | let adjustType = dataset.type 138 | let productId = dataset.id 139 | let product 140 | let index 141 | 142 | for (index = 0; index < trolleyList.length; index++) { 143 | if (productId === trolleyList[index].productId) { 144 | product = trolleyList[index] 145 | break 146 | } 147 | } 148 | 149 | if (product) { 150 | if (adjustType === "add") { 151 | product.count++ 152 | } else { 153 | if (product.count <= 1) { 154 | // 商品数量不超过1,点击减号相当于删除 155 | delete trolleyCheckMap[productId] 156 | trolleyList.splice(index, 1) 157 | } else { 158 | // 商品数量大于1 159 | product.count-- 160 | } 161 | } 162 | } 163 | 164 | // 调整结算总价 165 | let trolleyAccount = this.calcAccount(trolleyList, trolleyCheckMap) 166 | 167 | this.setData({ 168 | trolleyAccount, 169 | trolleyList, 170 | trolleyCheckMap 171 | }) 172 | 173 | }, 174 | 175 | updateTrolley() { 176 | wx.showLoading({ 177 | title: '更新购物车数据...', 178 | }) 179 | let trolleyList = 180 | db.updateTrolley(this.data.trolleyList).then(result => { 181 | wx.hideLoading(); 182 | this.setData({ 183 | isTrolleyEdit: false 184 | }) 185 | }).catch(err => { 186 | console.error(err) 187 | wx.hideLoading(); 188 | wx.showToast({ 189 | icon: 'none', 190 | title: '更新购物车失败' 191 | }) 192 | }) 193 | }, 194 | 195 | onTapPay() { 196 | 197 | if (!this.data.trolleyAccount) return 198 | 199 | wx.showLoading({ 200 | title: '结算中...', 201 | }) 202 | 203 | let self = this 204 | let trolleyCheckMap = this.data.trolleyCheckMap 205 | let trolleyList = this.data.trolleyList 206 | 207 | let needToPayProductList = trolleyList.filter(product => { 208 | return !!trolleyCheckMap[product.productId] 209 | }) 210 | 211 | db.addOrder({ 212 | list: needToPayProductList, 213 | isCheckout: true 214 | }).then(result => { 215 | wx.hideLoading() 216 | const data = result.result 217 | if (data) { 218 | wx.showToast({ 219 | title: '结算成功', 220 | }) 221 | self.getList() 222 | } 223 | }).catch(err => { 224 | console.error(err) 225 | wx.hideLoading() 226 | 227 | wx.showToast({ 228 | icon: 'none', 229 | title: '结算失败', 230 | }) 231 | }) 232 | }, 233 | }) -------------------------------------------------------------------------------- /miniprogram/pages/trolley/trolley.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "购物车", 3 | "usingComponents": { 4 | "login": "/components/login" 5 | } 6 | } -------------------------------------------------------------------------------- /miniprogram/pages/trolley/trolley.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 购物车是空的 9 | 快添加物品进来吧 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 全选 18 | 19 | {{isTrolleyEdit ? '完成' : '编辑'}} 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | {{item.name}} 29 | ¥{{item.price}} 30 | 31 | - 32 | {{item.count}} 33 | + 34 | 35 | x {{item.count}} 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 全选 45 | 46 | 总价 47 | ¥{{ trolleyAccount }} 48 | 结算 49 | 50 | -------------------------------------------------------------------------------- /miniprogram/pages/trolley/trolley.wxss: -------------------------------------------------------------------------------- 1 | /* pages/trolley/trolley.wxss */ 2 | 3 | .trolley-top { 4 | display: flex; 5 | align-items: center; 6 | justify-content: space-between; 7 | padding-left: 24rpx; 8 | } 9 | 10 | .trolley-total { 11 | display: flex; 12 | align-items: center; 13 | padding-left: 35rpx; 14 | font-size: 32rpx; 15 | } 16 | 17 | .trolley-check-wrapper { 18 | flex-shrink: 0; 19 | display: flex; 20 | align-items: center; 21 | justify-content: center; 22 | width: 36rpx; 23 | height: 36rpx; 24 | border-radius: 50%; 25 | background: #ececee; 26 | } 27 | 28 | .trolley-check-wrapper.white { 29 | background: #fff; 30 | } 31 | 32 | .trolley-check-wrapper.check { 33 | background: #f5e069; 34 | } 35 | 36 | .trolley-check { 37 | width: 22rpx; 38 | height: 16rpx; 39 | } 40 | 41 | .trolley-total-text, .trolley-edit, .bottom-text { 42 | margin-left: 18rpx; 43 | margin-right: 33rpx; 44 | color: rgb(52, 55, 61, 0.8); 45 | font-size: 24rpx; 46 | line-height: 33rpx; 47 | } 48 | 49 | .product-list { 50 | position: absolute; 51 | left: 0; 52 | right: 0; 53 | top: 54rpx; 54 | bottom: 100rpx; 55 | padding-bottom: 30rpx; 56 | } 57 | 58 | .product-card { 59 | display: flex; 60 | align-items: center; 61 | margin: 0 26rpx 26rpx; 62 | padding-left: 32rpx; 63 | height: 200rpx; 64 | background: #fff; 65 | box-shadow: 0 2rpx 13rpx 5rpx rgba(0, 0, 0, 0.02); 66 | border-radius: 13rpx; 67 | } 68 | 69 | .product-info { 70 | flex: 1; 71 | padding: 38rpx 28rpx 0 36rpx; 72 | height: 100%; 73 | box-sizing: border-box; 74 | font-size: 28rpx; 75 | line-height: 40rpx; 76 | } 77 | 78 | .product-img { 79 | flex-shrink: 0; 80 | margin-left: 31rpx; 81 | width: 160rpx; 82 | height: 160rpx; 83 | } 84 | 85 | .product-name { 86 | color: rgba(29, 29, 38, 0.8); 87 | } 88 | 89 | .product-price { 90 | margin-top: 3rpx; 91 | } 92 | 93 | .product-count { 94 | text-align: right; 95 | } 96 | 97 | .product-count-edit { 98 | display: flex; 99 | align-items: center; 100 | justify-content: flex-end; 101 | } 102 | 103 | .count-minus, .count-add { 104 | width: 36rpx; 105 | height: 36rpx; 106 | line-height: 36rpx; 107 | border-radius: 50%; 108 | border: 3rpx solid #f6e474; 109 | text-align: center; 110 | font-size: 28rpx; 111 | font-weight: 900; 112 | } 113 | 114 | .count-now { 115 | margin: 0 18rpx; 116 | } 117 | 118 | .bottom { 119 | position: fixed; 120 | bottom: 0; 121 | left: 0; 122 | right: 0; 123 | display: flex; 124 | align-items: center; 125 | background: white; 126 | padding-left: 24rpx; 127 | } 128 | 129 | .bottom-pay { 130 | height: 100rpx; 131 | width: 200rpx; 132 | line-height: 100rpx; 133 | text-align: center; 134 | font-size: 30rpx; 135 | background: #f5e069; 136 | color: rgba(52, 55, 61, 0.5); 137 | font-weight: bold; 138 | } 139 | 140 | .bottom-pay.canpay { 141 | color: #34373d 142 | } 143 | 144 | .bottom-text { 145 | flex: 1; 146 | text-align: right; 147 | opacity: 0.5; 148 | margin-right: 5rpx; 149 | } 150 | 151 | .bottom-price { 152 | font-size: 30rpx; 153 | line-height: 42rpx; 154 | margin-right: 20rpx; 155 | } 156 | -------------------------------------------------------------------------------- /miniprogram/pages/user/user.js: -------------------------------------------------------------------------------- 1 | // pages/user/user.js 2 | const util = require('../../utils/util') 3 | 4 | Page({ 5 | 6 | /** 7 | * 页面的初始数据 8 | */ 9 | data: { 10 | userInfo: null, 11 | }, 12 | 13 | onShow() { 14 | util.getUserInfo().then(userInfo => { 15 | this.setData({ 16 | userInfo 17 | }) 18 | }).catch(err => { 19 | console.log('尚未通过身份验证'); 20 | }) 21 | }, 22 | 23 | onTapLogin(event) { 24 | this.setData({ 25 | userInfo: event.detail.userInfo 26 | }) 27 | }, 28 | 29 | onTapAddress() { 30 | wx.showToast({ 31 | icon: 'none', 32 | title: '此功能暂未开放' 33 | }) 34 | }, 35 | 36 | onTapService() { 37 | wx.showToast({ 38 | icon: 'none', 39 | title: '此功能暂未开放' 40 | }) 41 | } 42 | }) -------------------------------------------------------------------------------- /miniprogram/pages/user/user.json: -------------------------------------------------------------------------------- 1 | { 2 | "navigationBarTitleText": "个人中心", 3 | "usingComponents": { 4 | "login": "/components/login" 5 | } 6 | } -------------------------------------------------------------------------------- /miniprogram/pages/user/user.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | {{userInfo.nickName}} 12 | 13 | 14 | 15 | 16 | 收货地址 17 | 18 | 19 | 20 | 联系客服 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /miniprogram/pages/user/user.wxss: -------------------------------------------------------------------------------- 1 | /* pages/user/user.wxss */ 2 | .user-card { 3 | margin: 50rpx 27rpx 0; 4 | background: #FFFFFF; 5 | box-shadow: 0 2rpx 13rpx 5rpx rgba(0, 0, 0, 0.02); 6 | border-radius: 13rpx; 7 | } 8 | 9 | .user-info { 10 | display: flex; 11 | align-items: center; 12 | height: 200rpx; 13 | } 14 | 15 | .user-head { 16 | flex-shrink: 0; 17 | margin-left: 53rpx; 18 | height: 100rpx; 19 | width: 100rpx; 20 | background: #F5E069; 21 | border-radius: 50%; 22 | } 23 | 24 | .user-name { 25 | flex: 1; 26 | margin: 0 31rpx; 27 | font-weight: bold; 28 | white-space: nowrap; 29 | overflow: hidden; 30 | text-overflow: ellipsis; 31 | } 32 | 33 | .user-split { 34 | height: 8rpx; 35 | background: #F9F9F9; 36 | } 37 | 38 | .user-options .option { 39 | display: flex; 40 | align-items: center; 41 | margin-left: 46rpx; 42 | margin-right: 27rpx; 43 | height: 128rpx; 44 | border-bottom: 1px solid rgba(151, 151, 151, 0.2); 45 | } 46 | 47 | .user-options .option:last-child { 48 | border-bottom: none; 49 | } 50 | 51 | .user-options .option-title { 52 | flex: 1; 53 | font-size: 30rpx; 54 | color: rgba(29, 29, 38, 0.8); 55 | } 56 | 57 | .user-options .option-arrow { 58 | width: 11rpx; 59 | height: 18rpx; 60 | } -------------------------------------------------------------------------------- /miniprogram/sitemap.json: -------------------------------------------------------------------------------- 1 | { 2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", 3 | "rules": [{ 4 | "action": "allow", 5 | "page": "*" 6 | }] 7 | } -------------------------------------------------------------------------------- /miniprogram/utils/db.js: -------------------------------------------------------------------------------- 1 | const util = require('./util') 2 | 3 | const db = wx.cloud.database({ 4 | env: 'mall-7vt8m' 5 | }) 6 | 7 | module.exports = { 8 | getProductList() { 9 | return db.collection('product').get() 10 | }, 11 | 12 | getProductDetail(id) { 13 | return wx.cloud.callFunction({ 14 | name: 'productDetail', 15 | data: { 16 | id 17 | }, 18 | }) 19 | }, 20 | 21 | getOrderList() { 22 | return wx.cloud.callFunction({ 23 | name: 'getOrderList' 24 | }) 25 | }, 26 | 27 | addOrder(data) { 28 | return util.isAuthenticated() 29 | .then(() => { 30 | return wx.cloud.callFunction({ 31 | name: 'addOrder', 32 | data, 33 | }) 34 | }) 35 | .catch(() => { 36 | wx.showToast({ 37 | icon: 'none', 38 | title: '请先登录' 39 | }) 40 | return {} 41 | }) 42 | }, 43 | 44 | getTrolleyList() { 45 | return wx.cloud.callFunction({ 46 | name: 'getTrolleyList' 47 | }) 48 | }, 49 | 50 | addTrolley(data) { 51 | return util.isAuthenticated() 52 | .then(() => { 53 | return wx.cloud.callFunction({ 54 | name: 'addTrolley', 55 | data, 56 | }) 57 | }) 58 | .catch(() => { 59 | wx.showToast({ 60 | icon: 'none', 61 | title: '请先登录' 62 | }) 63 | return {} 64 | }) 65 | }, 66 | 67 | updateTrolley(list) { 68 | return util.isAuthenticated() 69 | .then(() => { 70 | return wx.cloud.callFunction({ 71 | name: 'updateTrolley', 72 | data: { 73 | list, 74 | }, 75 | }) 76 | }).catch(() => { 77 | wx.showToast({ 78 | icon: 'none', 79 | title: '请先登录' 80 | }) 81 | return {} 82 | }) 83 | }, 84 | 85 | addComment(data) { 86 | return util.isAuthenticated() 87 | .then(() => { 88 | return wx.cloud.callFunction({ 89 | name: 'addComment', 90 | data, 91 | }) 92 | }).catch(() => { 93 | wx.showToast({ 94 | icon: 'none', 95 | title: 'Please Login First' 96 | }) 97 | return {} 98 | }) 99 | }, 100 | 101 | getComments(productId) { 102 | return db.collection('review').where({ 103 | productId, 104 | }).get() 105 | }, 106 | 107 | uploadImage(imgPath) { 108 | return wx.cloud.uploadFile({ 109 | cloudPath: `review/${util.getId()}`, 110 | filePath: imgPath, 111 | }) 112 | } 113 | 114 | } -------------------------------------------------------------------------------- /miniprogram/utils/util.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // make price with 2 digits 3 | formatPrice(price) { 4 | return parseFloat(Math.round(price * 100) / 100).toFixed(2) 5 | }, 6 | 7 | getUserInfo() { 8 | return new Promise((resolve, reject) => { 9 | this.isAuthenticated().then(() => { 10 | wx.getUserInfo({ 11 | success(res) { 12 | resolve(res.userInfo) 13 | } 14 | }) 15 | }).catch(() => { 16 | reject() 17 | }) 18 | }) 19 | }, 20 | 21 | isAuthenticated() { 22 | return new Promise((resolve, reject) => { 23 | wx.getSetting({ 24 | success(res) { 25 | if (res.authSetting['scope.userInfo'] === true) { 26 | resolve() 27 | } else { 28 | reject() 29 | } 30 | } 31 | }) 32 | }) 33 | }, 34 | 35 | formatTime(time, reg) { 36 | const date = typeof time === 'string' || typeof time === 'number' ? new Date(time) : time; 37 | const map = {}; 38 | map.yyyy = date.getFullYear(); 39 | map.yy = ('' + map.yyyy).substr(2); 40 | map.M = date.getMonth() + 1 41 | map.MM = (map.M < 10 ? '0' : '') + map.M; 42 | map.d = date.getDate(); 43 | map.dd = (map.d < 10 ? '0' : '') + map.d; 44 | map.H = date.getHours(); 45 | map.HH = (map.H < 10 ? '0' : '') + map.H; 46 | map.m = date.getMinutes(); 47 | map.mm = (map.m < 10 ? '0' : '') + map.m; 48 | map.s = date.getSeconds(); 49 | map.ss = (map.s < 10 ? '0' : '') + map.s; 50 | 51 | return reg.replace(/\byyyy|yy|MM|M|dd|d|HH|H|mm|m|ss|s\b/g, $1 => { 52 | return map[$1]; 53 | }); 54 | }, 55 | 56 | getId() { 57 | return Math.floor((1 + Math.random()) * 0x100000000).toString(16).slice(1) 58 | }, 59 | } -------------------------------------------------------------------------------- /project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "miniprogramRoot": "miniprogram/", 3 | "cloudfunctionRoot": "cloudfunctions/", 4 | "setting": { 5 | "urlCheck": true, 6 | "es6": true, 7 | "postcss": true, 8 | "minified": true, 9 | "newFeature": true 10 | }, 11 | "appid": "wx168c62fb8d672fc7", 12 | "projectname": "mall", 13 | "libVersion": "2.2.5", 14 | "simulatorType": "wechat", 15 | "simulatorPluginLibVersion": {}, 16 | "condition": { 17 | "search": { 18 | "current": -1, 19 | "list": [] 20 | }, 21 | "conversation": { 22 | "current": -1, 23 | "list": [] 24 | }, 25 | "plugin": { 26 | "current": -1, 27 | "list": [] 28 | }, 29 | "game": { 30 | "list": [] 31 | }, 32 | "miniprogram": { 33 | "current": 0, 34 | "list": [ 35 | { 36 | "id": -1, 37 | "name": "db guide", 38 | "pathName": "pages/databaseGuide/databaseGuide" 39 | } 40 | ] 41 | } 42 | } 43 | } --------------------------------------------------------------------------------