├── README.md ├── taro-demo ├── .gitignore ├── README.md ├── client │ ├── .editorconfig │ ├── .eslintignore │ ├── .eslintrc │ ├── .gitignore │ ├── .prettierrc │ ├── README.md │ ├── config │ │ ├── dev.js │ │ ├── index.js │ │ └── prod.js │ ├── package-lock.json │ ├── package.json │ └── src │ │ ├── actions │ │ ├── balance.js │ │ ├── cart.js │ │ ├── detail.js │ │ ├── home.js │ │ ├── order.js │ │ ├── search.js │ │ └── shop.js │ │ ├── app.js │ │ ├── app.scss │ │ ├── asset │ │ ├── add_icon.png │ │ ├── add_icon_off.png │ │ ├── area_icon.png │ │ ├── area_icon_white.png │ │ ├── arrow_icon.png │ │ ├── avatar.png │ │ ├── brand.png │ │ ├── brand_active.png │ │ ├── close_icon.png │ │ ├── emptycart_icon.png │ │ ├── gift_bag.png │ │ ├── gift_cover_hand.png │ │ ├── gift_cover_line.png │ │ ├── history_icon_off.png │ │ ├── history_icon_on.png │ │ ├── home.png │ │ ├── home_active.png │ │ ├── ic_del.png │ │ ├── ic_search.png │ │ ├── ic_search_leftarrow.png │ │ ├── ic_search_tips.png │ │ ├── like_icon_off.png │ │ ├── like_icon_on.png │ │ ├── mine.png │ │ ├── mine_active.png │ │ ├── minus_icon.png │ │ ├── minus_icon_off.png │ │ ├── new_icon.png │ │ ├── offsale_icon.png │ │ ├── order_loading.gif │ │ ├── presents │ │ │ └── qrcode.png │ │ ├── radio_off.png │ │ ├── radio_on.png │ │ ├── select_icon_off.png │ │ ├── select_icon_on.png │ │ ├── selected.png │ │ ├── service_help_icon.png │ │ ├── service_right_icon.png │ │ ├── shopping_cart.png │ │ ├── shoppingbag.png │ │ ├── shoppingbag_active.png │ │ └── tclass │ │ │ └── presents.gif │ │ ├── components │ │ ├── balance │ │ │ ├── express.js │ │ │ ├── express.scss │ │ │ ├── good_list.js │ │ │ └── good_list.scss │ │ ├── cart │ │ │ ├── _mixin.scss │ │ │ ├── bottom_bar │ │ │ │ ├── bottom_bar.js │ │ │ │ └── bottom_bar.scss │ │ │ ├── commodity │ │ │ │ ├── commodity.js │ │ │ │ ├── commodity.scss │ │ │ │ └── commodity_container.js │ │ │ ├── edit_box │ │ │ │ ├── edit_box.js │ │ │ │ └── edit_box.scss │ │ │ └── goods │ │ │ │ ├── goods.js │ │ │ │ └── goods.scss │ │ ├── gb │ │ │ ├── coupon │ │ │ │ ├── coupon.js │ │ │ │ └── coupon.scss │ │ │ ├── modal │ │ │ │ ├── modal.js │ │ │ │ └── modal.scss │ │ │ └── select_panel │ │ │ │ ├── select_panel.js │ │ │ │ └── select_panel.scss │ │ └── search │ │ │ ├── _mixin.scss │ │ │ ├── searchBar.js │ │ │ ├── searchBar.scss │ │ │ ├── searchFilter │ │ │ ├── filterMask.js │ │ │ ├── filterMask.scss │ │ │ ├── searchFilter.js │ │ │ └── searchFilter.scss │ │ │ ├── searchHistory.js │ │ │ ├── searchHistory.scss │ │ │ ├── searchHot.js │ │ │ ├── searchHot.scss │ │ │ ├── searchInto.js │ │ │ ├── searchInto.scss │ │ │ └── searchResult │ │ │ ├── resultList.js │ │ │ ├── resultList.scss │ │ │ ├── searchError.js │ │ │ └── searchError.scss │ │ ├── constants │ │ ├── balance.js │ │ ├── cart.js │ │ ├── detail.js │ │ ├── globalData.js │ │ ├── home.js │ │ ├── images.js │ │ ├── order │ │ │ ├── detail.js │ │ │ └── list.js │ │ ├── search.js │ │ ├── shop.js │ │ └── weapp.js │ │ ├── index.html │ │ ├── leancloud │ │ ├── cart │ │ │ ├── editCart.js │ │ │ ├── getCart.js │ │ │ └── utils.js │ │ ├── dbData.js │ │ ├── index.js │ │ ├── order │ │ │ ├── addOrder.js │ │ │ ├── cancelOrder.js │ │ │ ├── getBalance.js │ │ │ ├── getOrder.js │ │ │ └── getOrderDetail.js │ │ ├── search │ │ │ └── getList.js │ │ ├── shop │ │ │ ├── getInformation.js │ │ │ ├── getShop.js │ │ │ └── getSku.js │ │ └── user │ │ │ ├── addUser.js │ │ │ └── getUser.js │ │ ├── pages │ │ ├── balance │ │ │ ├── balance.js │ │ │ └── balance.scss │ │ ├── cart │ │ │ ├── cart.js │ │ │ ├── cart.scss │ │ │ └── cart_sub.js │ │ ├── detail │ │ │ ├── bag.png │ │ │ ├── detail.js │ │ │ └── detail.scss │ │ ├── index │ │ │ ├── index.js │ │ │ └── index.scss │ │ ├── list │ │ │ ├── list.js │ │ │ └── list.scss │ │ ├── shop │ │ │ ├── shop.js │ │ │ └── shop.scss │ │ └── user │ │ │ └── order │ │ │ ├── detail │ │ │ ├── detail.js │ │ │ └── detail.scss │ │ │ └── list │ │ │ ├── list.js │ │ │ └── list.scss │ │ ├── reducers │ │ ├── balance.js │ │ ├── cart.js │ │ ├── detail.js │ │ ├── home.js │ │ ├── index.js │ │ ├── order │ │ │ ├── detail.js │ │ │ └── list.js │ │ ├── search.js │ │ └── shop.js │ │ ├── store │ │ └── index.js │ │ └── utils │ │ ├── index.js │ │ ├── util.js │ │ └── wx.js ├── cloud │ ├── doc │ │ ├── cart.json │ │ ├── commodity.json │ │ ├── commodity_into.json │ │ ├── information.json │ │ ├── order.json │ │ ├── shop.json │ │ ├── shop_into.json │ │ └── user.json │ └── functions │ │ ├── cart │ │ ├── editCart.js │ │ ├── getCart.js │ │ ├── index.js │ │ ├── package.json │ │ ├── utils.js │ │ └── yarn.lock │ │ ├── order │ │ ├── addOrder.js │ │ ├── cancelOrder.js │ │ ├── getBalance.js │ │ ├── getOrder.js │ │ ├── getOrderDetail.js │ │ ├── index.js │ │ ├── package.json │ │ └── yarn.lock │ │ ├── search │ │ ├── getList.js │ │ ├── index.js │ │ ├── package-lock.json │ │ └── package.json │ │ ├── shop │ │ ├── getInformation.js │ │ ├── getShop.js │ │ ├── getSku.js │ │ ├── index.js │ │ ├── package-lock.json │ │ ├── package.json │ │ └── yarn.lock │ │ └── user │ │ ├── addUser.js │ │ ├── getUser.js │ │ ├── index.js │ │ ├── package.json │ │ └── yarn.lock ├── project.config.json └── tcb.json ├── todoList-Redux ├── .editorconfig ├── .eslintrc ├── .gitignore ├── config │ ├── dev.js │ ├── index.js │ └── prod.js ├── package.json ├── project.config.json ├── src │ ├── actions │ │ └── index.js │ ├── app.js │ ├── app.scss │ ├── constants │ │ └── todos.js │ ├── index.html │ ├── pages │ │ └── index │ │ │ ├── index.js │ │ │ └── index.scss │ ├── reducers │ │ └── index.js │ └── store │ │ └── index.js └── yarn.lock └── todoList ├── .editorconfig ├── .eslintrc ├── .gitignore ├── .npmrc ├── config ├── dev.js ├── index.js └── prod.js ├── package.json ├── project.config.json └── src ├── app.js ├── app.scss ├── index.html └── pages └── index ├── index.js └── index.scss /README.md: -------------------------------------------------------------------------------- 1 | # 《Taro 多端开发实现原理与项目实战》源码 2 | 3 | [《Taro 多端开发实现原理与项目实战》](https://juejin.im/book/5b73a131f265da28065fb1cd) 示例代码包含: 4 | 5 | - [《用 Taro 实现一个简单的 Todo 项目》的示例](https://github.com/o2team/taro-ebook-source/tree/master/todoList) 6 | - [《在 Taro 中使用 Redux》的示例](https://github.com/o2team/taro-ebook-source/tree/master/todoList-Redux) 7 | - [实战篇电商平台的示例](https://github.com/o2team/taro-ebook-source/tree/master/taro-demo) 8 | -------------------------------------------------------------------------------- /taro-demo/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | .temp/ 3 | .rn_temp/ 4 | node_modules/ 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /taro-demo/README.md: -------------------------------------------------------------------------------- 1 | # Taro商城demo 2 | 3 | 本demo的多端适配状态如下: 4 | 5 | - 微信小程序端 --- 后台使用小程序云,已适配 6 | - H5端 --- 后台使用leancloud,已适配 7 | - RN端 --- 后台使用leancloud,适配进行中 8 | - 支付宝小程序端 --- 适配进行中 9 | - 百度小程序端 --- 适配进行中 10 | 11 | 12 | 13 | ### 关于云开发 14 | 15 | 文章中的几个数据集的模拟数据,已上传至`cloud/doc`中,可根据需要自行导入。不过购物车,订单类的数据与openId相关联,所以更多的是可以参考其数据结构。 16 | 17 | 云函数的代码存放在`cloud/functions`中,小册并没有针对此部分进行过多的解读。代码是按模块进行分割,每个模块有一个入口文件和一些执行具体逻辑的文件。各位读者可自行阅读源码进行参考。 18 | 19 | 20 | 21 | ### 关于云函数 22 | 23 | 在使用你自己的云函数环境时,需要将云函数初始化换成你小程序的云环境。有以下几个地方需要注意: 24 | 25 | - `src/app.js` 26 | - `cloud/functions` 下**每个云函数**里的 `index.js` 27 | - `project.config.json` 里的appid需要换成你的小程序的appid 28 | 29 | ```javascript 30 | // src/app.js 31 | 32 | async componentWillMount () { 33 | if (process.env.TARO_ENV === 'weapp') { 34 | wx.cloud.init({ 35 | env: 'taro-ebook-23bbcb', // 换成你的云函数环境 36 | traceUser: true // 是否要捕捉每个用户的访问记录。设置为true,用户可在管理端看到用户访问记录 37 | }) 38 | const userData = await getWxUserData() 39 | setGlobalData('userData', userData) 40 | } 41 | } 42 | 43 | ``` 44 | 45 | ```javascript 46 | // 例: cloud/functions/cart/index.js 47 | 48 | const app = require('tcb-admin-node') 49 | 50 | const { getCart } = require('./getCart.js') 51 | const { editCart } = require('./editCart.js') 52 | 53 | app.init({ 54 | envName: 'taro-ebook-23bbcb', // 换成你的云函数环境 55 | mpAppId: 'wx9504f077bdc24ea2' // 换成你的小程序id 56 | }) 57 | ``` 58 | 59 | 另外,还有值得注意的,本demo在开发的时候,云函数的依赖包是 `tcb-admin-node` ,现在官方文档已改为 `wx-server-sdk`。不过亲测使用 `tcb-admin-node` 依旧能跑通,每个云函数都需要安装依赖后全量上传。 -------------------------------------------------------------------------------- /taro-demo/client/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /taro-demo/client/.eslintignore: -------------------------------------------------------------------------------- 1 | dist/* 2 | lib 3 | node_modules 4 | -------------------------------------------------------------------------------- /taro-demo/client/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "taro" 4 | ], 5 | "rules": { 6 | "no-unused-vars": [ 7 | "error", 8 | { 9 | "varsIgnorePattern": "Taro" 10 | } 11 | ] 12 | }, 13 | "parser": "babel-eslint" 14 | } 15 | -------------------------------------------------------------------------------- /taro-demo/client/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | .temp/ 3 | .rn_temp/ 4 | node_modules/ 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /taro-demo/client/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /taro-demo/client/README.md: -------------------------------------------------------------------------------- 1 | # Taro商城demo 2 | -------------------------------------------------------------------------------- /taro-demo/client/config/dev.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | NODE_ENV: '"development"' 4 | }, 5 | defineConstants: { 6 | }, 7 | weapp: {}, 8 | h5: {} 9 | } 10 | -------------------------------------------------------------------------------- /taro-demo/client/config/index.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | projectName: 'toplife-weapp', 3 | date: '2018-4-18', 4 | designWidth: 750, 5 | sourceRoot: 'src', 6 | outputRoot: 'dist', 7 | plugins: { 8 | babel: { 9 | sourceMap: true, 10 | presets: [ 11 | 'env' 12 | ], 13 | plugins: [ 14 | 'transform-class-properties', 15 | 'transform-decorators-legacy', 16 | 'transform-object-rest-spread' 17 | ] 18 | }, 19 | csso: { 20 | enable: true, 21 | config: { 22 | restructure: false 23 | } 24 | } 25 | }, 26 | defineConstants: { 27 | }, 28 | weapp: { 29 | }, 30 | h5: { 31 | publicPath: '/', 32 | staticDirectory: 'static', 33 | module: { 34 | postcss: { 35 | autoprefixer: { 36 | enable: true 37 | } 38 | } 39 | } 40 | } 41 | } 42 | 43 | module.exports = function (merge) { 44 | if (process.env.NODE_ENV === 'development') { 45 | return merge({}, config, require('./dev')) 46 | } 47 | return merge({}, config, require('./prod')) 48 | } 49 | -------------------------------------------------------------------------------- /taro-demo/client/config/prod.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | NODE_ENV: '"production"' 4 | }, 5 | defineConstants: { 6 | }, 7 | weapp: {}, 8 | h5: { 9 | publicPath: '//labs.qiang.it/toplife_xcx/', 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /taro-demo/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "taro-demo", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "Taro商场", 6 | "main": "index.js", 7 | "scripts": { 8 | "commitmsg": "validate-commit-msg", 9 | "commit": "git-cz", 10 | "dev:weapp": "taro build --type weapp --watch", 11 | "dev:h5": "taro build --type h5 --watch", 12 | "dev:rn": "taro build --type rn --watch", 13 | "dev:alipay": "taro build --type alipay --watch", 14 | "dev:swan": "taro build --type swan --watch", 15 | "build": "cross-env NODE_ENV=production taro build", 16 | "test": "echo \"Error: no test specified\" && exit 1" 17 | }, 18 | "config": { 19 | "validate-commit-msg": { 20 | "types": [ 21 | "feat", 22 | "fix", 23 | "docs", 24 | "style", 25 | "refactor", 26 | "perf", 27 | "test", 28 | "chore", 29 | "revert", 30 | "ci" 31 | ], 32 | "warnOnFail": false, 33 | "maxSubjectLength": 100, 34 | "helpMessage": "" 35 | } 36 | }, 37 | "author": "O2TEAM", 38 | "license": "MIT", 39 | "dependencies": { 40 | "@tarojs/async-await": "1.2.21", 41 | "@tarojs/components": "1.2.21", 42 | "@tarojs/redux": "1.2.21", 43 | "@tarojs/redux-h5": "1.2.21", 44 | "@tarojs/rn-runner": "1.2.21", 45 | "@tarojs/router": "1.2.21", 46 | "@tarojs/taro": "1.2.21", 47 | "@tarojs/taro-alipay": "1.2.21", 48 | "@tarojs/taro-h5": "1.2.21", 49 | "@tarojs/taro-weapp": "1.2.21", 50 | "classnames": "^2.2.5", 51 | "global": "^4.3.2", 52 | "leancloud-realtime": "^4.2.0", 53 | "leancloud-storage": "^3.10.0", 54 | "nerv-redux": "^1.2.18", 55 | "nervjs": "^1.2.17", 56 | "redux": "^4.0.0", 57 | "redux-actions": "^2.3.0", 58 | "redux-logger": "^3.0.6", 59 | "redux-thunk": "^2.2.0", 60 | "tcb-admin-node": "^1.0.21" 61 | }, 62 | "devDependencies": { 63 | "@tarojs/plugin-babel": "1.2.21", 64 | "@tarojs/plugin-csso": "1.2.21", 65 | "@tarojs/plugin-sass": "1.2.21", 66 | "@tarojs/plugin-uglifyjs": "1.2.21", 67 | "@tarojs/webpack-runner": "1.2.21", 68 | "babel-eslint": "^10.0.1", 69 | "babel-plugin-transform-class-properties": "^6.24.1", 70 | "babel-plugin-transform-decorators-legacy": "^1.3.4", 71 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 72 | "babel-preset-env": "^1.6.1", 73 | "commitizen": "^2.9.6", 74 | "cross-env": "^5.1.4", 75 | "cz-conventional-changelog": "^2.1.0", 76 | "eslint": "^4.19.1", 77 | "eslint-config-standard": "^11.0.0", 78 | "eslint-config-taro": "1.2.21", 79 | "eslint-plugin-flowtype": "^2.46.1", 80 | "eslint-plugin-import": "^2.9.0", 81 | "eslint-plugin-jest": "^21.15.0", 82 | "eslint-plugin-node": "^6.0.1", 83 | "eslint-plugin-promise": "^3.7.0", 84 | "eslint-plugin-react": "^7.7.0", 85 | "eslint-plugin-standard": "^3.0.1", 86 | "husky": "^0.14.3", 87 | "lint-staged": "^7.0.4", 88 | "validate-commit-msg": "^2.14.0" 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /taro-demo/client/src/actions/detail.js: -------------------------------------------------------------------------------- 1 | import Taro from '@tarojs/taro' 2 | import { operate } from '../constants/cart' 3 | import { createAction } from 'redux-actions' 4 | import { getOpenId, getH5UniqueId } from '../utils/index' 5 | import { 6 | REQUEST_DETAIL_CART, 7 | RECEIVE_DETAIL_CART, 8 | REQUEST_DETAIL_SKU, 9 | RECEIVE_DETAIL_SKU, 10 | REQUEST_DETAIL_ADD_CART, 11 | RECEIVE_DETAIL_ADD_CART 12 | } from '../constants/detail' 13 | 14 | const aMap = { 15 | REQUEST_DETAIL_CART: createAction(REQUEST_DETAIL_CART, data => data), 16 | RECEIVE_DETAIL_CART: createAction(RECEIVE_DETAIL_CART, data => data), 17 | REQUEST_DETAIL_SKU: createAction(REQUEST_DETAIL_SKU, data => data), 18 | RECEIVE_DETAIL_SKU: createAction(RECEIVE_DETAIL_SKU, data => data), 19 | REQUEST_DETAIL_ADD_CART: createAction(REQUEST_DETAIL_ADD_CART, data => data), 20 | RECEIVE_DETAIL_ADD_CART: createAction(RECEIVE_DETAIL_ADD_CART, data => data) 21 | } 22 | 23 | export function fetchCart () { 24 | return async (dispatch, getState) => { 25 | dispatch(aMap[REQUEST_DETAIL_CART]()) 26 | let res 27 | if (process.env.TARO_ENV === 'weapp') { 28 | const _openId = await getOpenId() 29 | res = await wx.cloud.callFunction({ 30 | name: 'cart', 31 | data: { 32 | func: 'getCart', 33 | data: { 34 | _id: _openId 35 | } 36 | } 37 | }).catch(err => { 38 | console.log(err) 39 | dispatch(aMap[RECEIVE_DETAIL_CART](getState().detail)) 40 | }) 41 | } else if (process.env.TARO_ENV === 'h5' || 'rn') { 42 | const h5Id = await getH5UniqueId() 43 | const getCart = require('../leancloud/cart/getCart').getCart 44 | res = await getCart(h5Id) 45 | } 46 | const data = res.result.data 47 | if (data.length !== 0) { 48 | dispatch(aMap[RECEIVE_DETAIL_CART](data)) 49 | } else { 50 | dispatch(aMap[RECEIVE_DETAIL_CART](getState().detail)) 51 | data.code !== 3 && Taro.showToast({ 52 | icon: 'none', 53 | title: '服务器繁忙' 54 | }) 55 | } 56 | } 57 | } 58 | 59 | export function fetchSkuData (skuId) { 60 | return async dispatch => { 61 | try { 62 | dispatch(aMap[REQUEST_DETAIL_SKU]()) 63 | let res 64 | if (process.env.TARO_ENV === 'weapp') { 65 | res = await wx.cloud.callFunction({ 66 | name: 'shop', 67 | data: { 68 | func: 'getSku', 69 | data: skuId 70 | } 71 | }) 72 | } else if (process.env.TARO_ENV === 'h5' || 'rn') { 73 | const getSku = require('../leancloud/shop/getSku').getSku 74 | res = await getSku(skuId) 75 | } 76 | if (res.result) { 77 | let skuData = res.result.data 78 | dispatch(aMap[RECEIVE_DETAIL_SKU](skuData)) 79 | } else { 80 | Taro.redirectTo({url: '/pages/404/404'}) 81 | } 82 | } catch (err) { 83 | console.log(err) 84 | Taro.redirectTo({url: '/pages/404/404'}) 85 | } 86 | } 87 | } 88 | 89 | export function fetchAddCart (skus) { 90 | return async (dispatch, getState) => { 91 | dispatch(aMap[REQUEST_DETAIL_ADD_CART]()) 92 | let res 93 | if (process.env.TARO_ENV === 'weapp') { 94 | const _openId = await getOpenId() 95 | res = await wx.cloud.callFunction({ 96 | name: 'cart', 97 | data: { 98 | func: 'editCart', 99 | data: { 100 | _id: _openId, 101 | type: operate['ADD'], 102 | skus 103 | } 104 | } 105 | }).catch(err => { 106 | console.log(err) 107 | dispatch(aMap[RECEIVE_DETAIL_ADD_CART](getState().detail)) 108 | }) 109 | } else if (process.env.TARO_ENV === 'h5' || 'rn') { 110 | const h5Id = await getH5UniqueId() 111 | const editCart = require('../leancloud/cart/editCart').editCart 112 | const editData = { 113 | h5Id, 114 | type: operate['ADD'], 115 | skus 116 | } 117 | res = await editCart(editData) 118 | } 119 | const data = res.result.data 120 | if (data.length !== 0) { 121 | dispatch(aMap[RECEIVE_DETAIL_ADD_CART](data)) 122 | Taro.showToast({ 123 | title: '添加购物车成功' 124 | }) 125 | } else { 126 | dispatch(aMap[RECEIVE_DETAIL_CART](getState().detail)) 127 | data.code !== 3 && Taro.showToast({ 128 | icon: 'none', 129 | title: '服务器繁忙' 130 | }) 131 | } 132 | } 133 | } 134 | 135 | -------------------------------------------------------------------------------- /taro-demo/client/src/actions/search.js: -------------------------------------------------------------------------------- 1 | import Taro from '@tarojs/taro' 2 | import { createAction } from 'redux-actions' 3 | import { 4 | SHOW_SEARCH_BAR, 5 | REQUEST_SEARCH_RESULT, 6 | RECEIVE_SEARCH_RESULT, 7 | RECEIVE_SEARCH_ERROR, 8 | SHOW_RESULT, 9 | CHANGE_HISTORY, 10 | SHOW_NOT_FIND, 11 | RESET_STATE 12 | } from '../constants/search' 13 | 14 | export const triggerShowSearchBar = createAction(SHOW_SEARCH_BAR) 15 | export const showResult = createAction(SHOW_RESULT, data => data) 16 | export const changeHistory = createAction(CHANGE_HISTORY, data => data) 17 | export const restState = createAction(RESET_STATE) 18 | 19 | const actionMap = { 20 | requestSearch: createAction(REQUEST_SEARCH_RESULT, (data) => data), 21 | receiveSearch: createAction(RECEIVE_SEARCH_RESULT, (data) => data), 22 | receiveSearchError: createAction(RECEIVE_SEARCH_ERROR, (data) => data), 23 | receiveShowNotFind: createAction(SHOW_NOT_FIND) 24 | } 25 | 26 | export function setSearchHistory (data = {}) { 27 | 28 | return async dispatch => { 29 | try { 30 | const res = await Taro.getStorage({key: 'search_history'}) 31 | let history = res.data 32 | if (data.value && data.type && data.type === 'add' && history.indexOf(data.value) === -1) { 33 | history.unshift(data.value) 34 | 35 | } else if (data.value && data.type && data.type === 'add' && history.indexOf(data.value) > -1) { 36 | history.splice(history.indexOf(data.value), 1) 37 | history.unshift(data.value) 38 | 39 | } else if (history && data.value && data.type && data.type === 'delete' && history.indexOf(data.value) > -1) { 40 | history.splice(data.value, 1) 41 | } 42 | if (history.length > 50) { 43 | history = history.splice(0, 50) 44 | } 45 | 46 | Taro.setStorage({ 47 | key: 'search_history', 48 | data: history, 49 | success: () => { 50 | dispatch(changeHistory(history)) 51 | } 52 | }) 53 | } catch (e) { 54 | console.log('操作历史搜索失败') 55 | } 56 | } 57 | } 58 | 59 | export function fetchSearchData (data) { 60 | Taro.showLoading({title: '加载中...'}) 61 | data.page = data.page || 1 62 | data['pageSize'] = 10 63 | console.log(data) 64 | return async dispatch => { 65 | try { 66 | dispatch(actionMap['requestSearch']()) 67 | let res 68 | if (process.env.TARO_ENV === 'weapp') { 69 | res = await wx.cloud.callFunction({ 70 | name: 'search', 71 | data: { 72 | func: 'getList', 73 | data 74 | } 75 | }) 76 | } else if (process.env.TARO_ENV === 'h5' || 'rn') { 77 | const getList = require('../leancloud/search/getList').getList 78 | res = await getList(data) 79 | } 80 | if (res.result.data && res.result.data.count) { 81 | dispatch(actionMap['receiveSearch'](res.result.data)) 82 | } else { 83 | dispatch(actionMap['receiveShowNotFind']()) 84 | } 85 | Taro.hideLoading() 86 | } catch (err) { 87 | console.log(err) 88 | dispatch(actionMap['receiveSearchError']()) 89 | Taro.hideLoading() 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /taro-demo/client/src/actions/shop.js: -------------------------------------------------------------------------------- 1 | import Taro from '@tarojs/taro' 2 | import { createAction } from 'redux-actions' 3 | 4 | import { 5 | REQUEST_SHOP, 6 | RECEIVE_SHOP 7 | } from '../constants/shop' 8 | 9 | export const actionMap = { 10 | shopRequest: createAction(REQUEST_SHOP), 11 | shop: createAction(RECEIVE_SHOP, (data) => data) 12 | } 13 | 14 | export function fetchShopData (data) { 15 | const venderId = data.venderId 16 | return async dispatch => { 17 | try { 18 | dispatch(actionMap['shopRequest']()) 19 | let res 20 | if (process.env.TARO_ENV === 'weapp') { 21 | res = await wx.cloud.callFunction({ 22 | name: 'shop', 23 | data: { 24 | func: 'getShop', 25 | data: venderId 26 | } 27 | }) 28 | } else if (process.env.TARO_ENV === 'h5' || 'rn') { 29 | const getShop = require('../leancloud/shop/getShop').getShop 30 | res = await getShop(venderId) 31 | } 32 | if (res.result) { 33 | let shopData = res.result.data 34 | dispatch(actionMap['shop'](shopData)) 35 | } else { 36 | Taro.redirectTo({url: '/pages/404/404'}) 37 | } 38 | } catch (err) { 39 | console.log(err) 40 | Taro.redirectTo({url: '/pages/404/404'}) 41 | } 42 | } 43 | } 44 | 45 | // async function getShop (params) { 46 | // const db = wx.cloud.database() 47 | // const _ = db.command 48 | // const shopColl = db.collection('shop') 49 | // const res = await shopColl.get() 50 | // console.log(JSON.stringify(res.data, 4)) 51 | // } 52 | 53 | // getShop() 54 | -------------------------------------------------------------------------------- /taro-demo/client/src/app.js: -------------------------------------------------------------------------------- 1 | import Taro, { Component } from '@tarojs/taro' 2 | import { Provider } from '@tarojs/redux' 3 | import '@tarojs/async-await' 4 | import configStore from './store' 5 | import Index from './pages/index' 6 | 7 | import { setGlobalData } from './constants/globalData' 8 | import { getWxUserData } from './utils/wx' 9 | 10 | import './app.scss' 11 | 12 | const store = configStore() 13 | 14 | class App extends Component { 15 | config = { 16 | pages: [ 17 | 'pages/index/index', 18 | 'pages/shop/shop', 19 | 'pages/user/order/list/list', 20 | 'pages/user/order/detail/detail', 21 | 'pages/cart/cart', 22 | 'pages/cart/cart_sub', 23 | 'pages/detail/detail', 24 | 'pages/list/list', 25 | 'pages/balance/balance' 26 | ], 27 | window: { 28 | backgroundTextStyle: 'light', 29 | navigationBarBackgroundColor: '#ffffff', 30 | navigationBarTitleText: 'TARO商城', 31 | navigationBarTextStyle: 'black' 32 | }, 33 | tabBar: { 34 | color: '#7b7b7a', 35 | selectedColor: '#c0a369', 36 | backgroundColor: '#222222', 37 | list: [ 38 | { 39 | pagePath: 'pages/index/index', 40 | text: '首页', 41 | iconPath: 'asset/home.png', 42 | selectedIconPath: 'asset/home_active.png' 43 | },{ 44 | pagePath: 'pages/cart/cart', 45 | text: '购物车', 46 | iconPath: 'asset/shoppingbag.png', 47 | selectedIconPath: 'asset/shoppingbag_active.png' 48 | }, { 49 | pagePath: 'pages/user/order/list/list', 50 | text: '订单', 51 | iconPath: 'asset/mine.png', 52 | selectedIconPath: 'asset/mine_active.png' 53 | }] 54 | }, 55 | cloud: true, 56 | networkTimeout: { 57 | request: 6000, 58 | connectSocket: 10000, 59 | uploadFile: 10000, 60 | downloadFile: 10000 61 | } 62 | } 63 | 64 | constructor () { 65 | super(...arguments) 66 | } 67 | 68 | async componentWillMount () { 69 | if (process.env.TARO_ENV === 'weapp') { 70 | wx.cloud.init({ 71 | env: 'taro-ebook-23bbcb', // 前往云控制台获取环境id 72 | traceUser: true // 是否要捕捉每个用户的访问记录。设置为true,用户可在管理端看到用户访问记录 73 | }) 74 | const userData = await getWxUserData() 75 | setGlobalData('userData', userData) 76 | } 77 | } 78 | 79 | render() { 80 | return ( 81 | 82 | 83 | 84 | ) 85 | } 86 | } 87 | 88 | Taro.render(, document.getElementById('app')) 89 | -------------------------------------------------------------------------------- /taro-demo/client/src/asset/add_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/add_icon.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/add_icon_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/add_icon_off.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/area_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/area_icon.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/area_icon_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/area_icon_white.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/arrow_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/arrow_icon.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/avatar.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/brand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/brand.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/brand_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/brand_active.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/close_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/close_icon.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/emptycart_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/emptycart_icon.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/gift_bag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/gift_bag.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/gift_cover_hand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/gift_cover_hand.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/gift_cover_line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/gift_cover_line.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/history_icon_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/history_icon_off.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/history_icon_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/history_icon_on.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/home.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/home_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/home_active.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/ic_del.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/ic_del.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/ic_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/ic_search.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/ic_search_leftarrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/ic_search_leftarrow.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/ic_search_tips.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/ic_search_tips.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/like_icon_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/like_icon_off.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/like_icon_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/like_icon_on.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/mine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/mine.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/mine_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/mine_active.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/minus_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/minus_icon.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/minus_icon_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/minus_icon_off.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/new_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/new_icon.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/offsale_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/offsale_icon.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/order_loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/order_loading.gif -------------------------------------------------------------------------------- /taro-demo/client/src/asset/presents/qrcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/presents/qrcode.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/radio_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/radio_off.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/radio_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/radio_on.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/select_icon_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/select_icon_off.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/select_icon_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/select_icon_on.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/selected.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/service_help_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/service_help_icon.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/service_right_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/service_right_icon.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/shopping_cart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/shopping_cart.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/shoppingbag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/shoppingbag.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/shoppingbag_active.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/shoppingbag_active.png -------------------------------------------------------------------------------- /taro-demo/client/src/asset/tclass/presents.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/asset/tclass/presents.gif -------------------------------------------------------------------------------- /taro-demo/client/src/components/balance/express.js: -------------------------------------------------------------------------------- 1 | import Taro, { Component } from '@tarojs/taro' 2 | import { View, Text, Image } from '@tarojs/components' 3 | import './express.scss' 4 | 5 | export default class Express extends Component { 6 | render () { 7 | return ( 8 | 9 | 10 | {/**/} 11 | 12 | 13 | 14 | 收货人A 15 |  123456789  16 |  默认 17 | 18 | 广东省深圳市宝安区龙光世纪大厦 19 | 20 | 21 | 22 | 23 | 24 | 配送 25 | 26 | 27 | TARO商城配送 28 | 29 | ¥ 30 | {this.props.freightPrice} 31 | 32 | 33 | TARO商城配送默认时间 34 | 35 | 36 | 37 | 38 | ) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/balance/express.scss: -------------------------------------------------------------------------------- 1 | /*postcss-pxtransform rn eject enable*/ 2 | 3 | .balance_box { 4 | overflow: hidden; 5 | box-sizing: border-box; 6 | box-shadow: 2px 0 30px rgba(0, 0, 0, 0.06); 7 | } 8 | 9 | .balance_good .total { 10 | color: #232321; 11 | font-family: "toplifeCustomEn"; 12 | } 13 | 14 | .balance_good .addr_detail .addr_text { 15 | word-break: break-all; 16 | word-wrap: break-word; 17 | overflow: hidden; 18 | -o-text-overflow: ellipsis; 19 | text-overflow: ellipsis; 20 | display: -webkit-box; 21 | -webkit-box-orient: vertical; 22 | -webkit-line-clamp: 2; 23 | } 24 | 25 | .balance_good_express .express_fee { 26 | font-family: "toplifeCustomEn"; 27 | } 28 | 29 | .balance_good_express .val_time { 30 | font-family: "toplifeCustomEn"; 31 | } 32 | 33 | /*postcss-pxtransform rn eject disable*/ 34 | 35 | .balance_box { 36 | font-size: 24px; 37 | font-weight: 300; 38 | background-color: #fff; 39 | margin: 0 20px 20px; 40 | padding: 40px; 41 | } 42 | 43 | .balance_box:last-child { 44 | margin-bottom: 0; 45 | } 46 | 47 | .addr_default { 48 | color: #fff; 49 | background-color: #232321; 50 | margin-left: 10px; 51 | padding: 0 5px; 52 | } 53 | 54 | .addr_detail { 55 | flex: 1; 56 | } 57 | 58 | .addr_detail_header { 59 | display: flex; 60 | flex-direction: row; 61 | } 62 | 63 | .addr_detail_grey { 64 | color: #999; 65 | } 66 | 67 | .addr_text { 68 | color: #999; 69 | margin-top: 20px; 70 | font-size: 24px; 71 | width: 100%; 72 | } 73 | 74 | .balance_good_addr { 75 | display: flex; 76 | flex-direction: row; 77 | } 78 | 79 | .balance_good_addr_icon { 80 | width: 46px; 81 | height: 60px; 82 | position: relative; 83 | top: 30px; 84 | margin-right: 65px; 85 | } 86 | 87 | .balance_good_addr, .balance_good_express { 88 | padding: 0 30px; 89 | height: 125px; 90 | } 91 | 92 | .balance_box_arrow { 93 | width: 48px; 94 | height: 48px; 95 | } 96 | 97 | .balance_good_express { 98 | display: flex; 99 | flex-direction: row; 100 | align-items: center; 101 | background-color: #f8f8f8; 102 | margin-top: 40px; 103 | } 104 | 105 | .balance_good_label { 106 | width: 110px; 107 | color: #999; 108 | } 109 | 110 | .val_wrap { 111 | display: flex; 112 | flex-direction: column; 113 | flex: 1; 114 | } 115 | 116 | .expredd_grey { 117 | color: #999; 118 | } 119 | 120 | .val_express { 121 | display: flex; 122 | flex-direction: row; 123 | } 124 | 125 | .express_fee { 126 | color: #999; 127 | margin-left: 20px; 128 | } 129 | 130 | .val_time { 131 | margin-top: 10px; 132 | color: #999; 133 | } 134 | 135 | .balance_good .count, 136 | .balance_good .total { 137 | margin-top: 40px; 138 | } 139 | 140 | .balance_good .count { 141 | color: #999; 142 | } 143 | 144 | .balance_good .count text { 145 | margin-right: 10px; 146 | } 147 | 148 | .balance_good .total { 149 | color: #232321; 150 | font-family: "toplifeCustomEn"; 151 | } 152 | 153 | .balance_good .good_tip { 154 | background-color: rgba(35, 35, 33, 0.8); 155 | color: #fff; 156 | padding-left: 30px; 157 | height: 50px; 158 | line-height: 50px; 159 | margin-top: -10px; 160 | } 161 | 162 | .balance_slice { 163 | margin-top: 30px; 164 | height: 2px; 165 | background-color: #ddd; 166 | width: 100%; 167 | } 168 | 169 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/balance/good_list.js: -------------------------------------------------------------------------------- 1 | import Taro, { Component } from '@tarojs/taro' 2 | import { View, Text, Image } from '@tarojs/components' 3 | import { parseMoney } from '../../utils/util' 4 | import './good_list.scss' 5 | 6 | export default class GoodList extends Component { 7 | navigateTo (id) { 8 | let url = `/pages/shop/shop?venderId=${id}` 9 | jumpUrl(url) 10 | } 11 | 12 | render () { 13 | let {payCommodities = []} = this.props 14 | 15 | payCommodities = payCommodities.map(item => { 16 | let totalNum = 0 17 | let totalPrice = 0 18 | const newSkus = item.skus.map(skuItem => { 19 | totalNum += parseInt(skuItem.num) 20 | totalPrice += totalNum * parseInt(skuItem.main.price) 21 | if (!/http:\/\/|https:\/\//.test(skuItem.main.images[0])) { 22 | skuItem.imgUrl = `https://${skuItem.main.images[0]}` 23 | } else { 24 | skuItem.imgUrl = skuItem.main.images[0] 25 | } 26 | return skuItem 27 | }) 28 | item.skus = newSkus 29 | item.totalNum = totalNum 30 | item.totalPrice = parseMoney(totalPrice) 31 | return item 32 | }) 33 | 34 | return ( 35 | 36 | { 37 | payCommodities.map(item => { 38 | return ( 39 | 40 | 41 | 42 | 43 | 44 | {item.skus.map((sku) => { 45 | console.log(1) 46 | return 47 | 48 | 49 | 50 | 51 | 52 | 53 | {sku.main.skuName} 54 | {sku.sizeInfo.name}: {sku.sizeInfo.value} 55 | {sku.colorInfo.name}: {sku.colorInfo.value} 56 | 支持7天无理由退换 57 | 58 | 59 | ¥{sku.main.price} 60 | X{sku.num} 61 | 62 | 63 | 64 | 65 | })} 66 | 67 | 68 | 共 {item.totalNum} 件商品 69 | 小计:¥{item.totalPrice} 70 | 71 | 72 | ) 73 | }) 74 | } 75 | 76 | ) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/balance/good_list.scss: -------------------------------------------------------------------------------- 1 | /*postcss-pxtransform rn eject enable*/ 2 | .balance_good_items .info_support::before { 3 | display: inline-block; 4 | content: ""; 5 | width: 20px; 6 | height: 20px; 7 | background: url("https://static.360buyimg.com/tp-statics/2018-4-20/m/img/ic_7days@2x.png") no-repeat; 8 | background-size: 100% 100%; 9 | position: relative; 10 | top: 2px; 11 | margin-right: 8px; 12 | } 13 | 14 | .balance_good_items .info_support.nosupport::before { 15 | background: url("https://static.360buyimg.com/tp-statics/2018-4-20/m/img/ic_no7days@2x.png") no-repeat; 16 | background-size: 100% 100%; 17 | } 18 | 19 | /*postcss-pxtransform rn eject disable*/ 20 | 21 | .balance_box { 22 | font-size: 24px; 23 | font-weight: 300; 24 | background-color: #fff; 25 | margin: 0 20px 20px; 26 | padding: 40px; 27 | } 28 | 29 | .balance_good_shop { 30 | display: flex; 31 | flex-direction: row; 32 | justify-content: center; 33 | height: 60px; 34 | } 35 | 36 | .balance_good_shop_image { 37 | width: 180px; 38 | height: 60px; 39 | } 40 | 41 | .balance_slice { 42 | margin-top: 30px; 43 | height: 2px; 44 | background-color: #ddd; 45 | width: 100%; 46 | } 47 | 48 | .balance_good_items { 49 | overflow: hidden; 50 | margin-bottom: 40px; 51 | } 52 | 53 | .balance_good_item { 54 | display: flex; 55 | flex-direction: row; 56 | margin-top: 60px; 57 | overflow: hidden; 58 | } 59 | 60 | .balance_good_items_pic { 61 | width: 200px; 62 | margin-right: 40px; 63 | position: relative; 64 | } 65 | 66 | .balance_good_items_pic_image { 67 | width: 200px; 68 | height: 200px; 69 | } 70 | 71 | .balance_good_items .pic_count { 72 | width: 200px; 73 | height: 50px; 74 | background-color: rgba(35, 35, 33, 0.8); 75 | position: absolute; 76 | bottom: 0; 77 | left: 0; 78 | text-align: center; 79 | line-height: 50px; 80 | color: #fff; 81 | } 82 | 83 | .balance_good_items .item_count { 84 | line-height: 200px; 85 | color: #999; 86 | } 87 | 88 | .balance_good_items .item_count text { 89 | color: #232321; 90 | margin-right: 10px; 91 | } 92 | 93 | .balance_good_items .arrow { 94 | top: 75px; 95 | } 96 | 97 | .info_wrap { 98 | flex: 1; 99 | } 100 | 101 | .info { 102 | display: flex; 103 | flex-direction: column; 104 | } 105 | 106 | .info_name { 107 | color: #232321; 108 | margin-bottom: 30px; 109 | } 110 | 111 | .balance_good_items .price_val { 112 | font-weight: 400; 113 | font-family: "toplifeCustomEn"; 114 | } 115 | 116 | .price { 117 | display: flex; 118 | flex-direction: row; 119 | align-items: baseline; 120 | margin-top: 40px; 121 | } 122 | 123 | .balance_good_items .price_val text { 124 | font-size: 32px; 125 | } 126 | 127 | .price_num { 128 | flex: 1; 129 | text-align: right; 130 | } 131 | 132 | .balance_grey { 133 | color: #999; 134 | } 135 | 136 | .balance_good_count { 137 | margin-top: 20px; 138 | display: flex; 139 | flex-direction: row; 140 | } 141 | 142 | .count_text, .count_total_text { 143 | color: #999; 144 | } 145 | 146 | .count_total_text{ 147 | flex: 1; 148 | text-align: right; 149 | } 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/cart/_mixin.scss: -------------------------------------------------------------------------------- 1 | @mixin image-background($url) { 2 | background: url($url) no-repeat center center; 3 | background-size: 100% 100%; 4 | width: width($url, 3); 5 | height: height($url, 3); 6 | } 7 | 8 | @mixin img-bg ($url, $width, $height) { 9 | display: inline-block; 10 | background-image: url($url); 11 | background-size: 100% 100%; 12 | width: ($width); 13 | height: ($height); 14 | } -------------------------------------------------------------------------------- /taro-demo/client/src/components/cart/bottom_bar/bottom_bar.scss: -------------------------------------------------------------------------------- 1 | /*postcss-pxtransform rn eject enable*/ 2 | .del_popup { 3 | position: fixed; 4 | width: 100%; 5 | height: 100%; 6 | left: 0; 7 | top: 0; 8 | background-color: rgba(0, 0, 0, 0.8); 9 | z-index: 10; 10 | } 11 | 12 | .del_popup_content { 13 | position: absolute; 14 | left: 50%; 15 | top: 50%; 16 | width: 600px; 17 | height: 320px; 18 | transform: translate(-50%, -50%); 19 | background-color: #fff; 20 | color: #232321; 21 | text-align: center; 22 | border-radius: 30px; 23 | } 24 | 25 | .del_popup_title { 26 | margin-top: 40px; 27 | font-size: 32px; 28 | } 29 | 30 | .del_popup_text { 31 | margin-top: 40px; 32 | font-size: 24px; 33 | } 34 | 35 | .del_popup_btn { 36 | position: absolute; 37 | bottom: 0; 38 | left: 0; 39 | width: 100%; 40 | height: 88px; 41 | border-top: 2px solid #eee; 42 | } 43 | 44 | .del_popup_btn_cancel { 45 | color: #8c8c8c; 46 | border-right: 2px solid #eee; 47 | } 48 | 49 | .del_popup_btn_confirm { 50 | color: #666; 51 | } 52 | 53 | .del_popup_btn text { 54 | display: block; 55 | float: left; 56 | width: 50%; 57 | height: 88px; 58 | text-align: center; 59 | line-height: 88px; 60 | font-size: 32px; 61 | box-sizing: border-box; 62 | } 63 | 64 | /*postcss-pxtransform rn eject disable*/ 65 | 66 | 67 | .bottom_bar_wp { 68 | flex-direction: row; 69 | flex-shrink: 0; 70 | width: 100%; 71 | height: 100px; 72 | position: relative; 73 | background-color: #232321; 74 | // position: fixed; 75 | // left: 0; 76 | // bottom: 0; 77 | // margin-bottom: 100px; 78 | } 79 | 80 | .bottom_bar{ 81 | display: flex; 82 | flex-direction: row; 83 | width: 100%; 84 | } 85 | 86 | .bottom_bar_select_wp{ 87 | display: flex; 88 | flex-direction: row; 89 | align-items: center; 90 | } 91 | 92 | .bottom_bar_select { 93 | display: flex; 94 | justify-content: center; 95 | align-items: center; 96 | width: 170px; 97 | height: 100px; 98 | } 99 | 100 | .select_radio_img{ 101 | width: 24px; 102 | height: 24px; 103 | } 104 | 105 | .select_radio_text { 106 | font-size: 24px; 107 | color: #fff; 108 | } 109 | 110 | .bottom_bar_select .select_radio_real { 111 | position: absolute; 112 | left: 58px; 113 | visibility: hidden; 114 | } 115 | 116 | .bottom_bar_total { 117 | display: flex; 118 | flex-direction: column; 119 | justify-content: center; 120 | height: 100px; 121 | color: #fff; 122 | } 123 | 124 | .bottom_bar_total_text { 125 | display: flex; 126 | flex-direction: row; 127 | align-items: baseline; 128 | color: white; 129 | font-size: 24px; 130 | } 131 | 132 | .bottom_bar_total_small { 133 | color: white; 134 | font-size: 16px; 135 | } 136 | 137 | .bottom_bar_total_big { 138 | color: white; 139 | font-size: 32px; 140 | } 141 | 142 | .bottom_bar_total_desc { 143 | color: white; 144 | font-size: 18px; 145 | } 146 | 147 | .bottom_bar_btn { 148 | position: absolute; 149 | display: flex; 150 | height: 100px; 151 | width: 228px; 152 | right: 0; 153 | top: 0; 154 | align-items: center; 155 | justify-content: center; 156 | color: #232321; 157 | background-color: #bfa36c; 158 | font-size: 32px; 159 | } 160 | 161 | .bottom_bar_btn.del { 162 | background-color: #000000; 163 | color: #fff; 164 | } 165 | 166 | .bottom_bar_btn_none { 167 | background-color: #999999; 168 | } 169 | 170 | .bottom_bar_wp.hide { 171 | display: none; 172 | } 173 | 174 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/cart/commodity/commodity_container.js: -------------------------------------------------------------------------------- 1 | import Taro, { Component } from '@tarojs/taro' 2 | import { connect } from '@tarojs/redux' 3 | import { View } from '@tarojs/components' 4 | 5 | import Commondity from './commodity' 6 | import { 7 | fetchCheckCart, 8 | fetchInvertCheckCart, 9 | checkDelCart, 10 | inverseCheckDelCart, 11 | showEditBox, 12 | fetchCart, 13 | fetchChangeCartNum, 14 | fetchDelCart, 15 | changeCouponStatus, 16 | changeEditStatus 17 | } from '../../../actions/cart' 18 | 19 | class CommondityContainer extends Component { 20 | constructor (...args) { 21 | super(...args) 22 | } 23 | 24 | render () { 25 | const { 26 | isFixedBar, 27 | commoditys, 28 | editSkuData, 29 | isEditStatus, 30 | isFetching, 31 | fetchCheckCart, 32 | fetchInvertCheckCart, 33 | checkDelCart, 34 | inverseCheckDelCart, 35 | showEditBox, 36 | fetchCart, 37 | fetchChangeCartNum, 38 | fetchDelCart, 39 | changeEditStatus 40 | } = this.props 41 | return ( 42 | 43 | 59 | 60 | ) 61 | } 62 | } 63 | 64 | export default connect(({ 65 | cart 66 | }) => { 67 | return { 68 | editSkuData: cart.editSkuData, 69 | commoditys: cart.commoditys, 70 | isEditStatus: cart.isEditStatus, 71 | isFetching: cart.isFetching 72 | } 73 | }, (dispatch) => ({ 74 | fetchCart (...args) { 75 | dispatch(fetchCart(...args)) 76 | }, 77 | fetchCheckCart (...args) { 78 | dispatch(fetchCheckCart(...args)) 79 | }, 80 | fetchInvertCheckCart (...args) { 81 | dispatch(fetchInvertCheckCart(...args)) 82 | }, 83 | checkDelCart (...args) { 84 | dispatch(checkDelCart(...args)) 85 | }, 86 | inverseCheckDelCart (...args) { 87 | dispatch(inverseCheckDelCart(...args)) 88 | }, 89 | showEditBox (...args) { 90 | dispatch(showEditBox(...args)) 91 | }, 92 | fetchChangeCartNum (...args) { 93 | dispatch(fetchChangeCartNum(...args)) 94 | }, 95 | fetchDelCart (...args) { 96 | dispatch(fetchDelCart(...args)) 97 | }, 98 | changeCouponStatus (...args) { 99 | dispatch(changeCouponStatus(...args)) 100 | }, 101 | changeEditStatus (...args) { 102 | dispatch(changeEditStatus(...args)) 103 | } 104 | }))(CommondityContainer) 105 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/cart/edit_box/edit_box.js: -------------------------------------------------------------------------------- 1 | import Taro, { Component } from '@tarojs/taro' 2 | import { View, Image, Text } from '@tarojs/components' 3 | import { connect } from '@tarojs/redux' 4 | import classnames from 'classnames' 5 | 6 | import { 7 | hideEditBox, 8 | fetchChangeAttr 9 | } from '../../../actions/cart' 10 | 11 | import './edit_box.scss' 12 | 13 | class EditBox extends Component { 14 | constructor () { 15 | super(...arguments) 16 | this.state = { 17 | showColorValue: '', 18 | showSizeValue: '', 19 | isClose: false 20 | } 21 | } 22 | 23 | onAnimationEnd = () => { 24 | const {isClose} = this.state 25 | if (isClose) { 26 | this.setState({isClose: false}) 27 | this.props.hideEditBox() 28 | } 29 | } 30 | 31 | runCloseAni = () => { 32 | this.setState({isClose: true}) 33 | } 34 | 35 | selectAttr = (type, value) => { 36 | if (type === 'color') { 37 | this.setState({showColorValue: value}) 38 | } else if (type === 'size') { 39 | this.setState({showSizeValue: value}) 40 | } 41 | } 42 | 43 | changeCartAttr = () => { 44 | const { editSkuData, onFetchChangeAttr } = this.props 45 | const {showColorValue, showSizeValue} = this.state 46 | const {sku} = editSkuData 47 | const newSku = [ 48 | { 49 | skuId: sku.skuId, 50 | color: showColorValue || sku.colorInfo.value, 51 | size: showSizeValue || sku.sizeInfo.value 52 | }] 53 | 54 | this.runCloseAni() 55 | if (showColorValue || showSizeValue) { 56 | onFetchChangeAttr(newSku) 57 | } 58 | } 59 | 60 | render () { 61 | const {isClose, showColorValue, showSizeValue} = this.state 62 | const {editSkuData} = this.props 63 | const {showEidtBox, sku} = editSkuData 64 | const {colorInfo, sizeInfo} = sku || {} 65 | 66 | const colorValue = showColorValue || colorInfo.value 67 | const sizeValue = showSizeValue || sizeInfo.value 68 | 69 | const wpClass = classnames('editbox bg_shade', {'show': showEidtBox}, {'fade': isClose}) 70 | const aniClass = classnames('editbox_content', {'show_wp': !isClose && showEidtBox}, {'hide_wp': isClose}) 71 | return ( 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | {sku.main.price} 80 | 商品编号:{sku.skuId} 81 | 82 | 83 | 84 | 85 | {colorInfo.name}: 86 | 87 | {colorInfo.all.map((value, idx) => { 88 | return {value} 93 | })} 94 | 95 | 96 | 97 | {colorInfo.name}: 98 | 99 | {sizeInfo.all.map((value, idx) => { 100 | return {value} 105 | })} 106 | 107 | 108 | {sku.isOutOfStock ? 该商品补货中 : 确定} 109 | 110 | 111 | ) 112 | } 113 | } 114 | 115 | export default connect(({ 116 | cart 117 | }) => ({ 118 | editSkuData: cart.editSkuData 119 | }), (dispatch) => ({ 120 | hideEditBox (...args) { 121 | dispatch(hideEditBox(...args)) 122 | }, 123 | onFetchChangeAttr (...args) { 124 | dispatch(fetchChangeAttr(...args)) 125 | } 126 | }))(EditBox) 127 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/cart/edit_box/edit_box.scss: -------------------------------------------------------------------------------- 1 | /*postcss-pxtransform rn eject enable*/ 2 | 3 | @import '../_mixin.scss'; 4 | 5 | .editbox { 6 | display: none; 7 | font-family: '-apple-system-font,Helvetica Neue,Helvetica,sans-serif'; 8 | z-index: 10; 9 | &_content { 10 | position: absolute; 11 | bottom: 0; 12 | padding-bottom: 150px; 13 | width: 100%; 14 | background-color: #fff; 15 | } 16 | &_header { 17 | position: relative; 18 | height: 180px; 19 | &_img { 20 | position: absolute; 21 | left: 40px; 22 | top: -60px; 23 | width: 200px; 24 | height: 200px; 25 | border: 2px solid #ddd; 26 | .taro-img, 27 | image { 28 | width: 100%; 29 | height: 100%; 30 | } 31 | } 32 | &_text { 33 | position: absolute; 34 | top: 60px; 35 | left: 270px; 36 | &_price { 37 | font-family: 'toplifeCustomEn'; 38 | font-size: 32px; 39 | color: #232321; 40 | } 41 | &_desc { 42 | display: block; 43 | font-size: 24px; 44 | line-height: 1.5; 45 | color: #999999; 46 | } 47 | .small { 48 | font-size: 16px; 49 | } 50 | } 51 | &_close { 52 | position: absolute; 53 | right: 35px; 54 | top: 30px; 55 | @include img-bg('http://storage.jd.com/o2images/close_icon.png', 40px, 40px); 56 | } 57 | } 58 | &_option { 59 | margin-bottom: 40px; 60 | padding: 0 40px; 61 | color: #232321; 62 | &_title { 63 | font-size: 28px; 64 | } 65 | &_wp { 66 | margin-top: 20px; 67 | } 68 | &_item { 69 | display: inline-block; 70 | margin-right: 34px; 71 | margin-bottom: 30px; 72 | padding: 30px 40px; 73 | font-size: 24px; 74 | text-align: center; 75 | border: 2px solid #ddd; 76 | &.on { 77 | color: #fff; 78 | background-color: #000; 79 | } 80 | } 81 | &.size { 82 | .editbox_option_item { 83 | padding-left: 20px; 84 | padding-right: 20px; 85 | font-size: 32px; 86 | box-sizing: border-box; 87 | } 88 | } 89 | } 90 | &_btn { 91 | position: absolute; 92 | bottom: 0; 93 | width: 100%; 94 | height: 100px; 95 | line-height: 100px; 96 | color: #fff; 97 | background-color: #222; 98 | text-align: center; 99 | font-size: 32px; 100 | } 101 | &_offsale { 102 | position: absolute; 103 | bottom: 0; 104 | width: 100%; 105 | height: 76px; 106 | line-height: 76px; 107 | color: #fff; 108 | background-color: rgba(0,0,0,.7); 109 | text-align: center; 110 | font-size: 32px; 111 | } 112 | } 113 | 114 | .bg_shade { 115 | position: fixed; 116 | left: 0; 117 | right: 0; 118 | top: 0; 119 | bottom: 0; 120 | background-color: rgba($color: #232321, $alpha: 0.8); 121 | z-index: 999; 122 | } 123 | 124 | 125 | .show { 126 | display: block!important; 127 | } 128 | 129 | .show_wp { 130 | animation: slide_in .3s ease-out forwards; 131 | } 132 | 133 | .hide_wp { 134 | animation: slide_out .3s ease-in forwards; 135 | } 136 | 137 | .fade { 138 | animation: fade_out .3s ease-in-out forwards; 139 | } 140 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/cart/goods/goods.js: -------------------------------------------------------------------------------- 1 | import Taro, { Component } from '@tarojs/taro' 2 | import { View, Text, Image } from '@tarojs/components' 3 | import { connect } from '@tarojs/redux' 4 | 5 | import { 6 | fetchDiviner 7 | } from '../../../actions/cart' 8 | 9 | import { jumpUrl, log } from '../../../utils/util' 10 | import './goods.scss' 11 | 12 | class Goods extends Component { 13 | constructor () { 14 | super(...arguments) 15 | this.state = { 16 | showDiviner: true 17 | } 18 | } 19 | 20 | tabHandle = (type) => { 21 | if (type === 'diviner') { 22 | if (!this.state.showDiviner) this.setState({showDiviner: true}) 23 | } else { 24 | if (this.state.showDiviner) this.setState({showDiviner: false}) 25 | } 26 | } 27 | 28 | componentWillMount () {} 29 | 30 | gotoDetail = (skuId, e) => { 31 | jumpUrl(`../detail/detail?skuId=${skuId}`) 32 | log.autoClick(e) 33 | } 34 | 35 | render () { 36 | const { footmark, isSub } = this.props 37 | const hasNofootmark = !footmark || footmark.length === 0 38 | return ( 39 | 40 | 41 | 42 | 43 | 44 | 最近浏览 45 | 46 | 47 | {hasNofootmark 48 | ? 49 | 暂无最近浏览商品 50 | 51 | : 52 | {footmark.map((good, index) => { 53 | return ( 54 | 62 | 63 | 64 | {good.stockState === 34 || good.stockState === 0 || good.price === '-1' 65 | ? 66 | 补货中 67 | : null} 68 | 69 | 70 | {good.brandName} 71 | {good.shortName} 72 | {good.price === '-1' 73 | ? 暂无报价 74 | : {good.price}} 75 | {/* 32,700 */} 76 | 77 | 78 | ) 79 | })} 80 | } 81 | 82 | 83 | ) 84 | } 85 | } 86 | 87 | export default connect(({ 88 | cart 89 | }) => ({ 90 | diviner: cart.diviner, 91 | footmark: cart.footmark 92 | }), (dispatch) => ({ 93 | fetchDiviner (...args) { 94 | dispatch(fetchDiviner(...args)) 95 | } 96 | }))(Goods) 97 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/cart/goods/goods.scss: -------------------------------------------------------------------------------- 1 | /*postcss-pxtransform rn eject enable*/ 2 | 3 | /*postcss-pxtransform rn eject disable*/ 4 | .goods { 5 | margin: 20px auto 0 auto; 6 | width: 710px; 7 | background-color: #fff; 8 | } 9 | 10 | .goods_wp { 11 | padding-bottom: 20px; 12 | } 13 | 14 | .goods_tab { 15 | height: 100px; 16 | display: flex; 17 | align-items: center; 18 | justify-content: center; 19 | //border-bottom: 2px solid #ddd; 20 | } 21 | 22 | .goods_tab_item { 23 | display: flex; 24 | flex-direction: row; 25 | align-items: center; 26 | justify-content: center; 27 | width: 270px; 28 | font-size: 28px; 29 | color: #999; 30 | } 31 | 32 | .goods_tab_item .like { 33 | display: inline-block; 34 | background-image: url("//storage.jd.com/o2images/like_icon_off.png"); 35 | background-size: 100% 100%; 36 | width: 37px; 37 | height: 32px; 38 | } 39 | 40 | //.goods_tab_item .history { 41 | // display: inline-block; 42 | // background-image: url("//storage.jd.com/o2images/history_icon_off.png"); 43 | // background-size: 100% 100%; 44 | // width: 28px; 45 | // height: 32px; 46 | //} 47 | 48 | .goods_tab_item.on { 49 | color: #232321; 50 | } 51 | 52 | .goods_tab_item.on .like { 53 | background-image: url("//storage.jd.com/o2images/like_icon_on.png"); 54 | } 55 | 56 | //.goods_tab_item.on .history { 57 | // background-image: url("//storage.jd.com/o2images/history_icon_on.png"); 58 | //} 59 | 60 | .goods_tab_icon { 61 | width: 28px; 62 | height: 32px; 63 | margin-right: 10px; 64 | } 65 | 66 | .goods_content { 67 | display: flex; 68 | flex-wrap: wrap; 69 | } 70 | 71 | .goods_content_item { 72 | width: 50%; 73 | height: 700px; 74 | padding-top: 35px; 75 | } 76 | 77 | .goods_content_item_img { 78 | position: relative; 79 | display: flex; 80 | align-items: center; 81 | justify-content: center; 82 | width: 355px; 83 | height: 455px; 84 | } 85 | 86 | .goods_content_item_img image { 87 | width: 355px; 88 | height: 455px; 89 | } 90 | 91 | .goods_content_item_img .item_img_none { 92 | position: absolute; 93 | display: flex; 94 | align-items: center; 95 | justify-content: center; 96 | left: 0; 97 | top: 0; 98 | width: 100%; 99 | height: 100%; 100 | background-color: rgba(255, 255, 255, 0.5); 101 | } 102 | 103 | .goods_content_item_img .item_img_none_text { 104 | display: block; 105 | width: 50%; 106 | height: 42px; 107 | line-height: 42px; 108 | text-align: center; 109 | font-size: 22px; 110 | color: #fff; 111 | background-color: rgba(0, 0, 0, 0.5); 112 | } 113 | 114 | .goods_content_item .gciw { 115 | padding: 0 40px; 116 | color: #232321; 117 | line-height: 1.5; 118 | } 119 | 120 | .goods_content_item .gciw_brand { 121 | display: block; 122 | margin-top: 20px; 123 | font-size: 26px; 124 | overflow: hidden; 125 | text-overflow: ellipsis; 126 | white-space: nowrap; 127 | } 128 | 129 | .goods_content_item .gciw_name { 130 | display: block; 131 | font-size: 24px; 132 | height: 72px; 133 | overflow: hidden; 134 | text-overflow: ellipsis; 135 | display: -webkit-box; 136 | } 137 | 138 | .goods_content_item .gciw_none { 139 | display: block; 140 | height: 48px; 141 | line-height: 48px; 142 | font-size: 24px; 143 | } 144 | 145 | .goods_content_item .gciw_price { 146 | display: block; 147 | font-size: 32px; 148 | } 149 | 150 | .goods_content_item .gciw_overdue { 151 | display: block; 152 | font-size: 24px; 153 | color: #999; 154 | text-decoration: line-through; 155 | } 156 | 157 | .goods_content_item .gciw .small { 158 | font-size: 16px; 159 | } 160 | 161 | .goods_content_item .gciw .new_icon { 162 | margin-right: 10px; 163 | display: inline-block; 164 | background-image: url("//storage.jd.com/o2images/new_icon.png"); 165 | background-size: 100% 100%; 166 | width: 60px; 167 | height: 26px; 168 | } 169 | 170 | .goods_none { 171 | display: flex; 172 | justify-content: center; 173 | align-items: center; 174 | width: 100%; 175 | height: 500px; 176 | background-color: #ffffff; 177 | font-size: 24px; 178 | color: #999; 179 | } 180 | 181 | .goods .hide { 182 | display: none; 183 | } 184 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/gb/coupon/coupon.js: -------------------------------------------------------------------------------- 1 | import Taro, {Component} from '@tarojs/taro' 2 | import {View, Text, Image} from '@tarojs/components' 3 | import {getUuid, getLoginStatus, getAreas, jumpUrl, log} from '../../../utils/util' 4 | 5 | export class CouponItem extends Component { 6 | state = {} 7 | constructor () { 8 | super(...arguments) 9 | } 10 | 11 | toUseCoupon (coupon, cantUse, e) { 12 | let parseCantUse = typeof cantUse === 'boolean' && cantUse 13 | if (parseCantUse) return 14 | let couponBatch = coupon.batchId 15 | let couponInfo = `${coupon.quota}-${coupon.discount}` 16 | jumpUrl(`../list/list?couponBatch=${couponBatch}&couponInfo=${couponInfo}`) 17 | log.autoClick(e) 18 | } 19 | 20 | async selectCoupon (coupon, isBalance, cantUse) { 21 | let parseCantUse = typeof cantUse === 'boolean' && cantUse 22 | if (!isBalance || parseCantUse) return 23 | let cantSelect = coupon.showDesc 24 | if (cantSelect) { 25 | Taro.showToast({ 26 | icon: 'none', 27 | title: '请先取消选中的优惠券' 28 | }) 29 | return 30 | } 31 | let balanceCoupon = this.$parent 32 | let {fetchCouponInfo, balanceInfo} = balanceCoupon.props 33 | let {cachedCoupons} = balanceCoupon.state 34 | let newCachedCoupons = {} 35 | 36 | if (coupon.selected) { 37 | for (let i in cachedCoupons) { 38 | if (coupon.id !== i) { 39 | newCachedCoupons[i] = coupon.discount 40 | } 41 | } 42 | } else { 43 | newCachedCoupons = cachedCoupons || {} 44 | newCachedCoupons[coupon.id] = coupon.discount 45 | } 46 | 47 | balanceCoupon.setState({ 48 | cachedCoupons: newCachedCoupons 49 | }, async () => { 50 | let body = JSON.stringify({"cachedCoupons": newCachedCoupons}) 51 | let uuid = await getUuid() 52 | let ptKey = await getLoginStatus() 53 | let areas = await getAreas() 54 | areas = areas ? areas.areas : null 55 | let address = balanceInfo.address 56 | areas = areas 57 | ? areas 58 | : (address ? `${address.provinceId}-${address.cityId}-${address.countyId}-${address.townId}`: null) 59 | 60 | fetchCouponInfo({ 61 | uuid, 62 | areas, 63 | body 64 | }, { 65 | 'cookie': `pt_key=${ptKey}` 66 | }) 67 | }) 68 | log.autoClick(e) 69 | } 70 | 71 | render () { 72 | const {coupon, cantSelect, isBalance, elevel, eid, eparam} = this.props 73 | let curCantSelect = cantSelect || (isBalance && coupon && coupon.showDesc) 74 | let useText = '立即使用' 75 | if (coupon && cantSelect) { 76 | switch (coupon.state) { 77 | case 3: 78 | useText = '已使用' 79 | break 80 | case 1000: 81 | useText = '已过期' 82 | break 83 | } 84 | } 85 | return ( 86 | 87 | 88 | {isBalance && !cantSelect && } 89 | ¥ 90 | {coupon && coupon.discount} 91 | 92 | 93 | 满{coupon && coupon.quota}元使用 94 | 95 | {coupon && coupon.limitStr} 96 | {coupon && coupon.timeStr} 97 | {!isBalance && {useText}} 98 | {isBalance && curCantSelect && *{coupon && coupon.showDesc}} 99 | 100 | ) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/gb/coupon/coupon.scss: -------------------------------------------------------------------------------- 1 | /*postcss-pxtransform rn eject enable*/ 2 | 3 | .coupon { 4 | &_item { 5 | width: 670px; 6 | height: 360px; 7 | padding-top: 36px; 8 | background-color: #fff; 9 | background-repeat: no-repeat; 10 | background-image: url('https://static.360buyimg.com/tp-statics/2018-4-17/m/img/coupon_bg.png'); 11 | background-size: 100% 100%; 12 | margin: 0 auto 20px; 13 | text-align: center; 14 | 15 | &.cantSelect { 16 | background-color: #fff; 17 | background-repeat: no-repeat; 18 | background-image: url('https://static.360buyimg.com/tp-statics/2018-4-17/m/img/gray_coupon_bg.png'); 19 | background-size: 100% 100%; 20 | 21 | view { 22 | color: #ccc; 23 | } 24 | .coupon_tit { 25 | background-repeat: no-repeat; 26 | background-image: url('https://static.360buyimg.com/tp-statics/2018-4-17/m/img/uncoupon_toplife.png'); 27 | background-size: 100% 100%; 28 | } 29 | .coupon_need_money { 30 | &::before, 31 | &::after {background-color: #ccc;} 32 | } 33 | .coupon_btn_use {background-color: #999;color: #fff;} 34 | } 35 | } 36 | &_tit { 37 | width: 129px; 38 | height: 10px; 39 | margin: 0 auto; 40 | background: url('https://static.360buyimg.com/tp-statics/2018-4-17/m/img/coupon_toplife.png') no-repeat; 41 | background-size: 100% 100%; 42 | } 43 | &_value { 44 | color: #c4a66a; 45 | font-size: 30px; 46 | font-style: italic; 47 | font-weight: 300; 48 | margin-top: 35px; 49 | 50 | text {font-size: 70px;font-weight: 400;} 51 | } 52 | &_need_money, 53 | &_limit, 54 | &_time, 55 | &_btn_use { 56 | font-size: 24px; 57 | font-weight: 300; 58 | } 59 | &_need_money { 60 | color: #c4a66a; 61 | text { 62 | padding: 0 16px; 63 | } 64 | &::before, 65 | &::after { 66 | width: 7px; 67 | height: 7px; 68 | background-color: #c4a66a; 69 | display: inline-block; 70 | content: ""; 71 | vertical-align: middle; 72 | transform: rotate(45deg); 73 | } 74 | } 75 | &_limit, 76 | &_time { 77 | transform: scale(0.8); 78 | } 79 | &_limit { 80 | margin-top: 30px; 81 | } 82 | &_btn_use { 83 | width: 200px; 84 | height: 50px; 85 | line-height: 50px; 86 | margin: 0 auto; 87 | background-color: #232321; 88 | color: #fff; 89 | position: relative; 90 | top: 36px; 91 | } 92 | &_btn_check { 93 | text-align: center; 94 | font-size: 26px; 95 | font-weight: 300; 96 | color: #232321; 97 | margin: 60px 0 30px; 98 | &::after { 99 | width: 26px; 100 | height: 16px; 101 | display: inline-block; 102 | content: ''; 103 | background-repeat: no-repeat; 104 | background-image: url('https://static.360buyimg.com/tp-statics/2018-4-17/m/img/ic_coupon_downarrow_black@2x.png'); 105 | background-size: 100% 100%; 106 | margin-left: 10px; 107 | } 108 | 109 | &.open { 110 | &::after { 111 | background-repeat: no-repeat; 112 | background-image: url('https://static.360buyimg.com/tp-statics/2018-4-17/m/img/ic_coupon_uparrow_black@2x.png'); 113 | background-size: 100% 100%; 114 | } 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/gb/modal/modal.js: -------------------------------------------------------------------------------- 1 | import Taro, { Component } from '@tarojs/taro' 2 | import { View, Button } from '@tarojs/components' 3 | 4 | import './modal.scss' 5 | 6 | class Modal extends Component { 7 | constructor() { 8 | super(...arguments) 9 | this.state = {} 10 | } 11 | 12 | onConfirmClick = () => { 13 | this.props.onConfirmCallback() 14 | } 15 | 16 | onCancelClick = () => { 17 | this.props.onCancelCallback() 18 | } 19 | 20 | onAuthConfirmClick = (e) => { 21 | this.props.onConfirmCallback(e.detail) 22 | } 23 | 24 | preventTouchMove = (e) => { 25 | e.stopPropagation() 26 | } 27 | 28 | render() { 29 | const { title, contentText, cancelText, confirmText, isAuth } = this.props 30 | return ( 31 | 32 | 33 | {title} 34 | {contentText} 35 | 36 | 37 | {!isAuth ? 38 | : 39 | } 40 | 41 | 42 | 43 | ) 44 | } 45 | } 46 | 47 | Modal.defaultProps = { 48 | title: '', 49 | contentText: '', 50 | cancelText: '取消', 51 | confirmText: '确定', 52 | isAuth: false, 53 | onCancelCallback: () => {}, 54 | onConfirmCallback: () => {} 55 | } 56 | 57 | export default Modal 58 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/gb/modal/modal.scss: -------------------------------------------------------------------------------- 1 | /*postcss-pxtransform rn eject enable*/ 2 | 3 | .toplife_modal { 4 | position: fixed; 5 | width: 100%; 6 | height: 100%; 7 | left: 0; 8 | top: 0; 9 | background-color: rgba(0,0,0,.8); 10 | z-index: 100; 11 | &_content { 12 | position: absolute; 13 | left: 50%; 14 | top: 50%; 15 | width: 600px; 16 | height: 320px; 17 | transform: translate(-50%, -50%); 18 | background-color: #fff; 19 | color: #232321; 20 | text-align: center; 21 | border-radius: 30px; 22 | } 23 | &_title { 24 | margin-top: 40px; 25 | font-size: 32px; 26 | } 27 | &_text{ 28 | margin-top: 40px; 29 | font-size: 24px; 30 | } 31 | &_btn { 32 | position: absolute; 33 | bottom: 0; 34 | left: 0; 35 | width: 100%; 36 | height: 88px; 37 | border-top: 2px solid #eee; 38 | &_cancel { 39 | color: #8c8c8c; 40 | border-radius: 0; 41 | border: 0; 42 | border-right: 2px solid #eee; 43 | border-bottom-left-radius: 30px; 44 | } 45 | &_confirm { 46 | color: #666; 47 | border-radius: 0; 48 | border: 0; 49 | border-bottom-right-radius: 30px; 50 | } 51 | button { 52 | display: block; 53 | float: left; 54 | width: 50%; 55 | height: 88px; 56 | text-align: center; 57 | line-height: 88px; 58 | font-size: 32px; 59 | box-sizing: border-box; 60 | background-color: #fff; 61 | &::after { 62 | border: 0; 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/gb/select_panel/select_panel.js: -------------------------------------------------------------------------------- 1 | import Taro, { Component } from '@tarojs/taro' 2 | import { View, Text, Button } from '@tarojs/components' 3 | import classnames from 'classnames' 4 | 5 | import './select_panel.scss' 6 | 7 | export default class SelectPanel extends Component { 8 | constructor () { 9 | super(...arguments) 10 | this.state = { 11 | isShow: true, 12 | selectedIndex: -1, 13 | selectedDetail: null 14 | } 15 | } 16 | 17 | closePanel = () => { 18 | this.setState({ 19 | isShow: false 20 | }) 21 | } 22 | 23 | confirmSelect = () => { 24 | if (this.state.selectedIndex !== -1) { 25 | this.setState({ 26 | isShow: false 27 | }, () => { 28 | this.props.onSelected && this.props.onSelected(this.state.selectedDetail) 29 | }) 30 | } 31 | } 32 | 33 | seleted (index, item) { 34 | this.setState({ 35 | selectedIndex: index, 36 | selectedDetail: item 37 | }) 38 | } 39 | 40 | onAnimationEnd = () => { 41 | if (!this.state.isShow) { 42 | this.setState({ 43 | isShow: true, 44 | selectedIndex: -1, 45 | selectedDetail: null 46 | }) 47 | this.props.onClose && this.props.onClose() 48 | } 49 | } 50 | 51 | touchMove = (e) => { 52 | e && e.stopPropagation() 53 | } 54 | 55 | render () { 56 | const { detail = [], title, tips, subTitle, cancelBtnText, confirmBtnText } = this.props 57 | const selectPanelClassName = classnames('select_panel', !this.state.isShow && 'hide') 58 | const confirmDisable = this.state.selectedIndex === -1 59 | 60 | return ( 61 | 62 | 63 | 64 | 65 | {title} 66 | 67 | 68 | 69 | 70 | {tips.map(item => { 71 | return {item} 72 | })} 73 | 74 | 75 | 76 | {subTitle} 77 | 78 | 79 | {detail.map((item, index) => { 80 | return ( 81 | 82 | 83 | {item.desc} 84 | 85 | 86 | ) 87 | })} 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | ) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/gb/select_panel/select_panel.scss: -------------------------------------------------------------------------------- 1 | /*postcss-pxtransform rn eject enable*/ 2 | 3 | .select_panel { 4 | position: fixed; 5 | top: 0; 6 | left: 0; 7 | z-index: 10; 8 | width: 100%; 9 | height: 100%; 10 | &.hide { 11 | .select_panel_mask { 12 | animation-name: hidePanelMask; 13 | } 14 | .select_panel_wrapper { 15 | animation-name: hideDetailWrapper; 16 | } 17 | } 18 | &_mask { 19 | position: fixed; 20 | top: 0; 21 | left: 0; 22 | width: 100%; 23 | height: 100%; 24 | background-color: rgba(0,0,0,.6); 25 | z-index: 11; 26 | opacity: 0; 27 | animation-name: showPanelMask; 28 | animation-duration: .3s; 29 | animation-timing-function: ease-in-out; 30 | animation-fill-mode: forwards; 31 | } 32 | &_wrapper { 33 | position: fixed; 34 | bottom: 0; 35 | left: 0; 36 | width: 100%; 37 | background-color: #FFFFFF; 38 | padding-bottom: 100px; 39 | z-index: 12; 40 | box-sizing: border-box; 41 | transform: translateY(100%); 42 | opacity: 0; 43 | animation-name: showDetailWrapper; 44 | animation-duration: .3s; 45 | animation-timing-function: ease-in-out; 46 | animation-fill-mode: forwards; 47 | } 48 | &_hd { 49 | line-height: 112px; 50 | text-align: center; 51 | font-size: 32px; 52 | color: #666; 53 | } 54 | &_tip { 55 | padding: 14px 35px; 56 | background-color: #ddd3b3; 57 | color: #fff; 58 | line-height: 42px; 59 | font-size: 24px; 60 | margin: 0 40px; 61 | } 62 | &_sub { 63 | height: 106px; 64 | border-bottom: 2px solid #ddd; 65 | font-size: 28px; 66 | margin: 0 40px; 67 | &_tit { 68 | display: inline-block; 69 | border-bottom: 4px solid #232321; 70 | line-height: 102px; 71 | } 72 | } 73 | &_detail { 74 | max-height: 546px; 75 | overflow-y: auto; 76 | padding-bottom: 20px; 77 | &_item { 78 | font-size: 24px; 79 | line-height: 74px; 80 | &.selected { 81 | background-color: #232321; 82 | color: #FFFFFF 83 | } 84 | } 85 | &_inner { 86 | padding: 0 40px; 87 | } 88 | } 89 | &_ft { 90 | display: flex; 91 | background: #232321; 92 | position: absolute; 93 | left: 0; 94 | bottom: 0; 95 | width: 100%; 96 | &_btn { 97 | width: 100%; 98 | flex: 1; 99 | line-height: 100px; 100 | font-size: 28px; 101 | color: #FFFFFF; 102 | background: #232321; 103 | border: 0; 104 | border-radius: 0; 105 | &.disabled { 106 | color: rgba(255, 255, 255, .4); 107 | } 108 | } 109 | &_split { 110 | width: 1px; 111 | height: 30px; 112 | background: #3b3b3b; 113 | margin-top: 35px; 114 | } 115 | } 116 | } 117 | 118 | @keyframes showPanelMask { 119 | 0% { opacity: 0; } 120 | 100% { opacity: 1; } 121 | } 122 | 123 | @keyframes showDetailWrapper { 124 | 0% { opacity: 0; transform: translateY(100%) } 125 | 100% { opacity: 1; transform: translateY(0) } 126 | } 127 | 128 | @keyframes hidePanelMask { 129 | 0% { opacity: 1; } 130 | 100% { opacity: 0; } 131 | } 132 | 133 | @keyframes hideDetailWrapper { 134 | 0% { opacity: 1; transform: translateY(0) } 135 | 100% { opacity: 0; transform: translateY(100%) } 136 | } 137 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/search/_mixin.scss: -------------------------------------------------------------------------------- 1 | .search_not_see{ 2 | display: none; 3 | } 4 | .search_not_see_ani{ 5 | opacity: 0; 6 | } -------------------------------------------------------------------------------- /taro-demo/client/src/components/search/searchBar.js: -------------------------------------------------------------------------------- 1 | import Taro, { Component } from '@tarojs/taro' 2 | import { View, Input, Text, Image } from '@tarojs/components' 3 | 4 | import searchIcon from '../../asset/ic_search.png' 5 | import cartIcon from '../../asset/shopping_cart.png' 6 | import searchDel from '../../asset/ic_del.png' 7 | import './searchBar.scss' 8 | import { jumpUrl } from '../../utils/util' 9 | 10 | export default class SearchBar extends Component { 11 | 12 | state = { 13 | words: '', 14 | focusSearch: false 15 | } 16 | 17 | componentWillReceiveProps (nextProps) { 18 | if (this.props.keyWords !== nextProps.keyWords || this.state.words === '') { 19 | this.setState({ 20 | words: nextProps.keyWords 21 | }) 22 | } 23 | } 24 | 25 | onSearchInput = ({detail = {}}) => { 26 | if (!detail.value) { 27 | return 28 | } 29 | this.setState({ 30 | words: detail.value 31 | }) 32 | } 33 | 34 | onH5Enter = (e) => { 35 | const key = e.key 36 | const value = e.target.value 37 | if (key === 'Enter') { 38 | this.props.onAddHistory({value: value, type: 'add'}) 39 | this.props.onSearchWords({keyWords: value}) 40 | } 41 | } 42 | 43 | onFocusSearch = () => { 44 | this.props.onShowSearchResult({type: 'result', isShow: false}) 45 | } 46 | 47 | deleteHandler = () => { 48 | this.setState({ 49 | words: '' 50 | }) 51 | } 52 | cancelSearch = () => { 53 | this.props.onShowSearchResult({type: 'result', isShow: true}) 54 | } 55 | goSearch = ({detail}) => { 56 | if (detail.value !== '') { 57 | this.props.onAddHistory({value: detail.value, type: 'add'}) 58 | this.props.onSearchWords({keyWords: detail.value}) 59 | } 60 | } 61 | 62 | goCart () { 63 | jumpUrl('../cart/cart_sub') 64 | } 65 | 66 | render () { 67 | const {showSearchResult = false} = this.props 68 | const {words} = this.state 69 | const carNumber = 99 70 | return ( 71 | 72 | 73 | 74 | 75 | 76 | 77 | 88 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | {carNumber} 99 | 100 | 101 | 105 | 取消 106 | 107 | 108 | 109 | ) 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/search/searchBar.scss: -------------------------------------------------------------------------------- 1 | /*postcss-pxtransform rn eject enable*/ 2 | /*postcss-pxtransform rn eject disable*/ 3 | @import './_mixin.scss'; 4 | 5 | .search_container { 6 | display: flex; 7 | flex-shrink: 0; 8 | background-color: #fff; 9 | height: 80px; 10 | overflow: hidden; 11 | width: 100%; 12 | } 13 | 14 | .search_container_box { 15 | display: flex; 16 | flex: 1; 17 | flex-direction: row; 18 | padding: 0 40px; 19 | background-color: #fff; 20 | height: 80px; 21 | align-items: center; 22 | z-index: 100; 23 | } 24 | 25 | .search_container_box-search_box { 26 | display: flex; 27 | flex: 1; 28 | flex-direction: row; 29 | position: relative; 30 | height: 60px; 31 | align-items: center; 32 | background-color: #eee; 33 | opacity: 0.5; 34 | } 35 | 36 | .search_container_box-search_icon-wrap { 37 | display: flex; 38 | margin: 0 16px; 39 | } 40 | 41 | .search_container_box-search_icon { 42 | width: 30px; 43 | height: 30px; 44 | } 45 | 46 | .search_container_box-search_input { 47 | display: flex; 48 | flex: 1; 49 | height: 60px; 50 | border: 0; 51 | font-size: 24px; 52 | z-index: 20; 53 | background-color: #eee; 54 | } 55 | 56 | .search_container_box-search_del { 57 | position: absolute; 58 | right: 0; 59 | top: 0; 60 | z-index: 101; 61 | display: flex; 62 | align-items: center; 63 | background-color: #eee; 64 | justify-content: center; 65 | width: 100px; 66 | height: 60px; 67 | } 68 | 69 | .search_container_box-search_del_icon { 70 | display: flex; 71 | width: 30px; 72 | height: 30px; 73 | } 74 | 75 | .search_container_box-search_show_cancel { 76 | //font-size: 32px; 77 | //color: #232321; 78 | padding-left: 20px; 79 | } 80 | 81 | .search_container_box-search_show_cart { 82 | position: relative; 83 | margin-left: 20px; 84 | } 85 | 86 | .search_container_box-cart_icon { 87 | width: 48px; 88 | height: 48px; 89 | display: flex; 90 | } 91 | 92 | .search_container_box-cart_num_wrap { 93 | display: flex; 94 | position: absolute; 95 | top: -10px; 96 | right: -10px; 97 | width: 34px; 98 | height: 30px; 99 | background-color: #c0a369; 100 | border-radius: 50px; 101 | align-items: center; 102 | justify-content: center; 103 | } 104 | 105 | .search_container_box-cart_num { 106 | line-height: 30px; 107 | font-size: 18px; 108 | color: #fff; 109 | } 110 | 111 | 112 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/search/searchFilter/searchFilter.js: -------------------------------------------------------------------------------- 1 | import Taro, { Component } from '@tarojs/taro' 2 | import { View, Text } from '@tarojs/components' 3 | 4 | import FilterMask from './filterMask' 5 | import './searchFilter.scss' 6 | 7 | export default class SearchFilter extends Component { 8 | 9 | constructor () { 10 | super(...arguments) 11 | this.state = { 12 | isClick: true, 13 | sortContent: [ 14 | { 15 | label: '综合', 16 | value: 1, 17 | cName: 'result_filter_btn' 18 | }, 19 | { 20 | label: '最新', 21 | value: 4, 22 | cName: 'result_filter_btn' 23 | }, 24 | { 25 | label: '价格', 26 | value: 2, 27 | cName: 'result_filter_btn price_btn' 28 | } 29 | ], 30 | sortType: 1, 31 | showFilterMask: false, 32 | currentIndex: 0, 33 | filterObj: {} 34 | } 35 | this.allListData = [] 36 | } 37 | 38 | selectFilter = async (index, value) => { 39 | 40 | Taro.pageScrollTo({ 41 | scrollTop: 0 42 | }) 43 | let {sortContent, isClick, currentIndex} = this.state 44 | let currentValue = parseInt(value, 10) 45 | if (currentValue === 2 || currentValue === 3) { 46 | currentIndex = 2 47 | if (isClick) { 48 | this.setState({ 49 | isClick: false 50 | }) 51 | } else { 52 | currentValue = currentValue === 2 ? 3 : 2 53 | sortContent[2].value = currentValue 54 | } 55 | } else { 56 | currentIndex = parseInt(index, 10) 57 | sortContent[2].value = 2 58 | this.setState({ 59 | isClick: true, 60 | sortContent 61 | }) 62 | } 63 | this.setState({ 64 | sortType: currentValue, 65 | currentIndex, 66 | sortContent 67 | }) 68 | this.goSearchContent() 69 | } 70 | 71 | confirmSelect = (data = {}) => { 72 | this.setState({ 73 | filterObj: data 74 | }) 75 | this.goSearchContent() 76 | } 77 | 78 | goSearchContent = () => { 79 | const {filterObj, sortType} = this.state 80 | this.props.onGoSearchContent({sortType, ...filterObj}) 81 | } 82 | 83 | showFilterMask = () => { 84 | console.log('showFilterMask') 85 | this.setState({ 86 | showFilterMask: !this.state.showFilterMask 87 | }) 88 | } 89 | 90 | render () { 91 | const { 92 | sortContent, 93 | sortType, 94 | currentIndex, 95 | showFilterMask 96 | } = this.state 97 | const list = sortContent.map((item) => { 98 | const cNameItem = sortType === 2 ? (item.cName + ' top') : (sortType === 3 ? (item.cName + ' bottom') : item.cName) 99 | return { 100 | ...item, 101 | cName: cNameItem 102 | } 103 | }) 104 | return ( 105 | 106 | 107 | { 108 | list.map((item, index) => { 109 | return ( 110 | 115 | {item.label} 116 | 117 | ) 118 | }) 119 | } 120 | 筛选 121 | 122 | { 123 | 128 | } 129 | 130 | ) 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/search/searchFilter/searchFilter.scss: -------------------------------------------------------------------------------- 1 | /*postcss-pxtransform rn eject enable*/ 2 | 3 | .search_filter_content .price_btn::after { 4 | content: ""; 5 | display: block; 6 | width: 0; 7 | height: 0; 8 | background: rgba(0, 0, 0, 0); 9 | border-left: 8px solid transparent; 10 | border-right: 8px solid transparent; 11 | border-bottom: 8px solid #bbb; 12 | position: absolute; 13 | right: 32px; 14 | top: 26px; 15 | } 16 | 17 | .search_filter_content .price_btn::before { 18 | content: ""; 19 | display: block; 20 | width: 0; 21 | height: 0; 22 | background: rgba(0, 0, 0, 0); 23 | border-left: 8px solid transparent; 24 | border-right: 8px solid transparent; 25 | border-top: 8px solid #bbb; 26 | position: absolute; 27 | right: 32px; 28 | top: 40px; 29 | } 30 | 31 | .search_filter_content .top::after { 32 | border-bottom: 8px solid #c0a369; 33 | } 34 | 35 | /*postcss-pxtransform rn eject disable*/ 36 | 37 | .search_filter { 38 | border-width: 0 0 2px 0; 39 | border-bottom-color: #eee; 40 | border-style: solid; 41 | } 42 | 43 | .search_filter_content { 44 | height: 80px; 45 | display: flex; 46 | align-items: center; 47 | background-color: #fff; 48 | flex-direction: row; 49 | justify-content: center; 50 | } 51 | 52 | .search_filter { 53 | height: 80px; 54 | } 55 | 56 | .result_filter_btn { 57 | height: 80px; 58 | line-height: 80px; 59 | background-color: #fff; 60 | font-size: 24px; 61 | flex: 1; 62 | text-align: center; 63 | position: relative; 64 | } 65 | 66 | .search_filter_content_active { 67 | color: #c0a369; 68 | } 69 | 70 | .search_filter_content .bottom::before { 71 | border-top: 8px solid #c0a369; 72 | } 73 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/search/searchHistory.js: -------------------------------------------------------------------------------- 1 | import Taro, { Component } from '@tarojs/taro' 2 | import { View, Image, Text } from '@tarojs/components' 3 | 4 | import delIcon from '../../asset/ic_del.png' 5 | import './searchHistory.scss' 6 | 7 | export default class SearchHistory extends Component { 8 | 9 | componentDidMount () { 10 | 11 | } 12 | 13 | goSearch (value = '') { 14 | if (value) { 15 | this.props.onChangeHistory({value, type: 'add'}) 16 | this.props.onSearchWords({keyWords: value}) 17 | } 18 | // let url = `../list/list?words=${value}` 19 | // jumpUrl(url, {method: 'redirectTo'}) 20 | 21 | } 22 | 23 | deleteSearch (value) { 24 | this.props.onChangeHistory({value, type: 'delete'}) 25 | } 26 | 27 | render () { 28 | const {historyWords = []} = this.props 29 | return ( 30 | historyWords.length > 0 && 31 | 32 | 33 | 历史搜索 34 | 35 | 36 | { 37 | historyWords.map((item, index) => { 38 | return ( 39 | 40 | 44 | {item} 45 | 46 | 53 | 54 | 55 | ) 56 | }) 57 | } 58 | 59 | 60 | ) 61 | } 62 | } 63 | 64 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/search/searchHistory.scss: -------------------------------------------------------------------------------- 1 | .history { 2 | margin-top: 20px; 3 | background-color: #fff; 4 | } 5 | 6 | .history_title { 7 | padding: 40px; 8 | border-width: 0 0 1px 0; 9 | border-style: solid; 10 | border-bottom-color: #ddd; 11 | } 12 | 13 | .history_title_content { 14 | color: #232321; 15 | font-size: 28px; 16 | font-weight: 600; 17 | display: flex; 18 | } 19 | 20 | .history_word { 21 | display: flex; 22 | flex-direction: row; 23 | border-style: solid; 24 | border-bottom-color: #ddd; 25 | border-width: 0 0 1px 0; 26 | } 27 | 28 | .history_word_info { 29 | font-size: 28px; 30 | padding: 40px; 31 | flex: 1; 32 | } 33 | 34 | .history_word_del { 35 | margin: 48px 40px 0; 36 | width: 26px; 37 | height: 26px; 38 | display: flex; 39 | } 40 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/search/searchHot.js: -------------------------------------------------------------------------------- 1 | import Taro, { Component } from '@tarojs/taro' 2 | import { View, Text } from '@tarojs/components' 3 | 4 | import './searchHot.scss' 5 | 6 | const DEFAULT_TITLE = '热门搜索' 7 | export default class SearchHot extends Component { 8 | 9 | goSearch = (value = '') => { 10 | if (value) { 11 | this.props.onAddHistory({value, type: 'add'}) 12 | this.props.onSearchWords({keyWords: value}) 13 | } 14 | } 15 | 16 | render () { 17 | const {hotWords, titleName} = this.props 18 | return ( 19 | hotWords.length > 0 && 20 | 21 | {titleName} 22 | 23 | { 24 | hotWords.map((item, index) => { 25 | return ( 26 | 31 | {item} 32 | 33 | ) 34 | }) 35 | } 36 | 37 | 38 | ) 39 | } 40 | } 41 | SearchHot.defaultProps = { 42 | hotWords: [], 43 | titleName: DEFAULT_TITLE 44 | } 45 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/search/searchHot.scss: -------------------------------------------------------------------------------- 1 | /*postcss-pxtransform rn eject enable*/ 2 | .hot_word-keyword { 3 | text-overflow: ellipsis; 4 | white-space: nowrap; 5 | } 6 | 7 | /*postcss-pxtransform rn eject disable*/ 8 | 9 | .hot_word { 10 | margin-top: 20px; 11 | background-color: #fff; 12 | } 13 | 14 | .hot_word-title { 15 | padding: 40px 40px 30px; 16 | color: #232321; 17 | font-size: 28px; 18 | font-weight: 600; 19 | display: flex; 20 | } 21 | 22 | .hot_word-list { 23 | padding: 0 40px 40px; 24 | display: flex; 25 | flex-direction: row; 26 | } 27 | 28 | .hot_word-keyword { 29 | color: #191919; 30 | font-size: 28px; 31 | border: 1px solid #ddd; 32 | height: 52px; 33 | line-height: 52px; 34 | padding: 0 30px; 35 | margin: 0 16px 16px 0; 36 | display: flex; 37 | max-width: 100%; 38 | overflow: hidden; 39 | } 40 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/search/searchInto.js: -------------------------------------------------------------------------------- 1 | import Taro, { Component } from '@tarojs/taro' 2 | import { View, Text, Image } from '@tarojs/components' 3 | import searchIcon from '../../asset/ic_search.png' 4 | import './searchInto.scss' 5 | import { jumpUrl } from '../../utils/util' 6 | 7 | const DEFAULT_PLACEHOLDER = '探索你的精致生活' 8 | 9 | export default class SearchInto extends Component { 10 | handler = () => { 11 | console.log('类型:' + this.props.type) 12 | } 13 | goSearch = () => { 14 | console.log('goSearch') 15 | jumpUrl(`/pages/list/list`) 16 | } 17 | 18 | render () { 19 | const {placeholder} = this.props 20 | return ( 21 | 22 | 23 | {placeholder} 24 | 25 | ) 26 | } 27 | } 28 | 29 | SearchInto.defaultProps = { 30 | placeholder: DEFAULT_PLACEHOLDER 31 | } 32 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/search/searchInto.scss: -------------------------------------------------------------------------------- 1 | .search_into { 2 | display: flex; 3 | flex-direction: row; 4 | height: 60px; 5 | background-color: #f6f6f6; 6 | width: 610px; 7 | justify-content: center; 8 | align-items: center; 9 | } 10 | 11 | .search_box { 12 | height: 60px; 13 | background-color: #f6f6f6; 14 | display: flex; 15 | flex: 1; 16 | flex-direction: row; 17 | justify-content: center; 18 | align-items: center; 19 | } 20 | 21 | .search_icon { 22 | width: 30px; 23 | height: 30px; 24 | } 25 | 26 | .search_text { 27 | height: 60px; 28 | line-height: 60px; 29 | color: #999; 30 | font-size: 28px; 31 | } 32 | 33 | .search_not_show { 34 | display: none; 35 | } 36 | 37 | .small.search_into { 38 | padding: 0 0 0 40px; 39 | width: 600px; 40 | } 41 | 42 | .small.search_into .search_box { 43 | text-align: left; 44 | } 45 | 46 | .small.search_into .search_icon { 47 | margin: 0 23px 0 28px; 48 | } 49 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/search/searchResult/resultList.js: -------------------------------------------------------------------------------- 1 | import Taro, { Component } from '@tarojs/taro' 2 | import { View, Image, Text, ScrollView } from '@tarojs/components' 3 | 4 | import { jumpUrl } from '../../../utils/util' 5 | import './resultList.scss' 6 | 7 | export default class ResultList extends Component { 8 | 9 | constructor () { 10 | super(...arguments) 11 | 12 | this.state = { 13 | list: [] 14 | } 15 | this.allListData = [] 16 | this.currentMaxPage = 1 //当前大分页 17 | } 18 | 19 | componentDidMount () { 20 | Taro.getSystemInfo({ 21 | success: (res) => { 22 | console.log(res) 23 | } 24 | }) 25 | } 26 | 27 | componentWillReceiveProps (nextProps) { 28 | const {searchResult, scrollTop} = nextProps 29 | if (searchResult.page < 10) { 30 | this.allListData = searchResult.wares 31 | this.setState({ 32 | list: searchResult.wares 33 | }) 34 | } else if (searchResult.page > 9 && nextProps.searchResult.page !== searchResult.page) { 35 | this.allListData = this.allListData.concat(searchResult.wares) 36 | let list = this.allListData 37 | if (searchResult.page % 10 === 0) { 38 | this.currentMaxPage = page 39 | } 40 | if (searchResult.page > 9) { 41 | list = this.allListData.slice((this.currentMaxPage - 2) * 10, (searchResult.page + 8) * 10) 42 | } 43 | this.setState({ 44 | list 45 | }) 46 | } else if (scrollTop < 1000 && searchResult.page > 9) { 47 | this.setState({ 48 | list: this.allListData.slice((this.currentMaxPage - 9) * 10, (searchResult.page) * 10) 49 | }) 50 | } else if (scrollTop > 1500 * 10 && searchResult.page > 9) { 51 | this.setState({ 52 | list: this.allListData.slice((this.currentMaxPage - 2) * 10, (searchResult.page + 10) * 10) 53 | }) 54 | } 55 | } 56 | 57 | doJump (skuid) { 58 | jumpUrl(`/pages/detail/detail?skuid=${skuid}`) 59 | } 60 | 61 | srollToTop () { 62 | Taro.pageScrollTo({ 63 | scrollTop: 0, 64 | duration: 400 65 | }) 66 | } 67 | 68 | showFilter = () => { 69 | this.props.onShowFilter({type: 'filter', isShow: true}) 70 | } 71 | 72 | render () { 73 | const { 74 | list 75 | } = this.state 76 | const {searchResult = {}, showGoTop = false} = this.props 77 | const resultList = list.map((item, index) => { 78 | return ( 79 | 84 | 85 | 91 | 92 | {item.skuName || ''} 93 | {item.name} 94 | 95 | { 96 | item.price && item.price !== '-1' && 97 | ¥ 98 | } 99 | {item.price && item.price !== '-1' ? item.price : '暂无报价'} 100 | 101 | 102 | ) 103 | }) 104 | 105 | return list.length > 0 && ( 106 | 107 | 108 | 109 | {resultList} 110 | 111 | 112 | 113 | 114 | 没有更多商品了~ 115 | searchResult.page * 10 ? 'has_not_more' : 'search_not_see'}>正在加载中... 116 | 117 | 118 | ) 119 | } 120 | } 121 | 122 | ResultList.defaultProps = { 123 | searchResult: { 124 | wares: [], 125 | page: 1 126 | }, 127 | showGoTop: false 128 | } 129 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/search/searchResult/resultList.scss: -------------------------------------------------------------------------------- 1 | /*postcss-pxtransform rn eject enable*/ 2 | 3 | .result_content-item_subtitle { 4 | overflow: hidden; 5 | text-overflow: ellipsis; 6 | display: -webkit-box; 7 | word-break: break-all; 8 | } 9 | 10 | .search_result-go_top { 11 | background: #232321; 12 | opacity: 0.8; 13 | width: 86px; 14 | height: 86px; 15 | position: fixed; 16 | z-index: 100; 17 | right: 30px; 18 | bottom: 150px; 19 | border-radius: 50%; 20 | transition: opacity 0.3s ease-in-out; 21 | display: flex; 22 | align-items: center; 23 | justify-content: center; 24 | } 25 | 26 | .search_result-go_to_arrow { 27 | width: 20px; 28 | height: 20px; 29 | border-right: 2px solid #fff; 30 | border-bottom: 2px solid #fff; 31 | transform: rotate(-135deg); 32 | margin-top: 11px; 33 | } 34 | 35 | /*postcss-pxtransform rn eject disable*/ 36 | 37 | @import '../_mixin.scss'; 38 | 39 | .search_result-scroll { 40 | flex-grow: 1; 41 | } 42 | 43 | .search_result-result_content { 44 | background-color: #fff; 45 | } 46 | 47 | .result_content_list { 48 | display: flex; 49 | flex-direction: row; 50 | flex-wrap: wrap; 51 | } 52 | 53 | .result_content-item { 54 | display: flex; 55 | flex: 1; 56 | flex-basis: 50%; 57 | flex-direction: column; 58 | margin: 30px 0; 59 | height: 610px; 60 | position: relative; 61 | } 62 | 63 | .result_content-item_img { 64 | width: 310px; 65 | height: 390px; 66 | overflow: hidden; 67 | position: relative; 68 | margin: 0 30px; 69 | } 70 | 71 | .item_img_info { 72 | width: 310px; 73 | height: 390px; 74 | } 75 | 76 | .search_result .result_content .result_content_item .item_img .item_sold_out { 77 | position: absolute; 78 | top: 0; 79 | left: 0; 80 | width: 100%; 81 | height: 100%; 82 | z-index: 5; 83 | background-color: #fff; 84 | opacity: 0.75; 85 | display: flex; 86 | justify-content: center; 87 | align-items: center; 88 | } 89 | 90 | .search_result .result_content .result_content_item .item_img .item_sold_out .sold_out_text { 91 | background-color: #000; 92 | opacity: 0.75; 93 | color: #fff; 94 | text-align: center; 95 | width: 35%; 96 | font-size: 24px; 97 | height: 40px; 98 | line-height: 40px; 99 | } 100 | 101 | .result_content-item_title { 102 | padding: 0 30px; 103 | font-size: 26px; 104 | height: 80px; 105 | line-height: 80px; 106 | overflow: hidden; 107 | } 108 | 109 | .result_content-item_subtitle { 110 | padding: 0 30px; 111 | height: 84px; 112 | line-height: 42px; 113 | font-size: 24px; 114 | color: #322d2d; 115 | } 116 | 117 | .result_content-item_price { 118 | font-size: 32px; 119 | padding: 0 30px; 120 | height: 50px; 121 | line-height: 50px; 122 | color: #222; 123 | overflow: hidden; 124 | } 125 | 126 | .result_content-item_price_unit { 127 | font-size: 16px; 128 | } 129 | 130 | .search_result .result_content .result_content_item .item_price_old { 131 | color: #aaa; 132 | } 133 | 134 | .search_result .result_content .result_content_item .item_price_old .price_old_num { 135 | text-decoration: line-through; 136 | } 137 | 138 | .search_result .show_current_page { 139 | position: fixed; 140 | bottom: 170px; 141 | text-align: center; 142 | z-index: 100; 143 | width: 100%; 144 | animation: slide_in 0.3s ease-in-out; 145 | } 146 | 147 | .search_result .show_current_page .current_page_text { 148 | font-size: 28px; 149 | background: #232321; 150 | opacity: 0.8; 151 | color: #fff; 152 | display: block; 153 | height: 44px; 154 | line-height: 44px; 155 | width: 104px; 156 | margin: 0 auto; 157 | } 158 | 159 | .search_result .slide_out { 160 | display: none; 161 | } 162 | 163 | .not_see_go { 164 | opacity: 0; 165 | } 166 | 167 | .has_not_more { 168 | background-color: #fff; 169 | text-align: center; 170 | display: flex; 171 | justify-content: center; 172 | width: 100%; 173 | padding-bottom: 40px; 174 | font-size: 24px; 175 | color: #322d2d; 176 | } 177 | 178 | @keyframes slide_in { 179 | 0% { 180 | opacity: 0; 181 | } 182 | 100% { 183 | opacity: 1; 184 | } 185 | } 186 | 187 | @keyframes slide_out { 188 | 0% { 189 | opacity: 1; 190 | } 191 | 100% { 192 | opacity: 0; 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/search/searchResult/searchError.js: -------------------------------------------------------------------------------- 1 | import Taro, { Component } from '@tarojs/taro' 2 | import { View, Image, Text } from '@tarojs/components' 3 | 4 | import './searchError.scss' 5 | import errIcon from '../../../asset/ic_search_tips.png' 6 | 7 | export default class SearchError extends Component { 8 | 9 | async refresh () { 10 | this.props.onGoSearchContent() 11 | } 12 | 13 | render () { 14 | const {showNotFind, keyWords, showErrorProblem} = this.props 15 | const words = /^.*[,].*$/.test(keyWords) ? '' : keyWords 16 | const showWordsTips = `没有找到与“${words} 相关的商品` 17 | 18 | return ( 19 | 20 | 21 | 很抱歉 22 | { 23 | !showErrorProblem && showNotFind && 24 | {showWordsTips} 25 | } 26 | { 27 | showErrorProblem && 28 | 29 | 程序员可能送货去了 30 | 刷新试试 31 | 32 | } 33 | 34 | ) 35 | } 36 | } 37 | SearchError.defaultProps = { 38 | showNotFind: false, 39 | keyWords: '', 40 | showErrorProblem: false 41 | } 42 | -------------------------------------------------------------------------------- /taro-demo/client/src/components/search/searchResult/searchError.scss: -------------------------------------------------------------------------------- 1 | .search_not_found { 2 | display: flex; 3 | flex: 1; 4 | flex-direction: column; 5 | align-items: center; 6 | justify-content: center; 7 | width: 100%; 8 | background-color: #f4f1f1; 9 | } 10 | 11 | .not_found_img { 12 | width: 160px; 13 | height: 160px; 14 | margin-top: -40%; 15 | } 16 | 17 | .not_found_text { 18 | font-size: 28px; 19 | margin-top: 20px; 20 | color: #666; 21 | } 22 | 23 | .not_found_word { 24 | font-size: 24px; 25 | margin-top: 10px; 26 | color: #999; 27 | } 28 | 29 | .not_found_btn { 30 | font-size: 24px; 31 | color: #232321; 32 | width: 204px; 33 | height: 48px; 34 | line-height: 48px; 35 | text-align: center; 36 | margin: 30px auto 0; 37 | border: 1px solid #232321; 38 | } 39 | -------------------------------------------------------------------------------- /taro-demo/client/src/constants/balance.js: -------------------------------------------------------------------------------- 1 | export const REQUEST_BALANCE_INFO = 'REQUEST_BALANCE_INFO' 2 | export const RECEIVE_BALANCE_INFO = 'RECEIVE_BALANCE_INFO' 3 | 4 | export const REQUEST_BALANCE_ORDER = 'REQUEST_BALANCE_ORDER' 5 | export const RECEIVE_BALANCE_ORDER = 'RECEIVE_BALANCE_ORDER' 6 | -------------------------------------------------------------------------------- /taro-demo/client/src/constants/cart.js: -------------------------------------------------------------------------------- 1 | export const REQUEST_CART = 'REQUEST_CART' 2 | export const RECEIVE_CART = 'RECEIVE_CART' 3 | 4 | export const REQUEST_DEL_CART = 'REQUEST_DEL_CART' 5 | export const RECEIVE_DEL_CART = 'RECEIVE_DEL_CART' 6 | 7 | export const REQUEST_CHANGE_NUM = 'REQUEST_CHANGE_NUM' 8 | export const RECEIVE_CHANGE_NUM = 'RECEIVE_CHANGE_NUM' 9 | 10 | export const REQUEST_CHECK_CART = 'REQUEST_CHECK_CART' 11 | export const RECEIVE_CHECK_CART = 'RECEIVE_CHECK_CART' 12 | 13 | export const REQUEST_INVERSE_CHECK = 'REQUEST_INVERSE_CHECK' 14 | export const RECEIVE_INVERSE_CHECK = 'RECEIVE_INVERSE_CHECK' 15 | 16 | export const REQUEST_SKU_ATTR = 'REQUEST_SKU_ATTR' 17 | export const RECEIVE_SKU_ATTR = 'RECEIVE_SKU_ATTR' 18 | 19 | export const REQUEST_CHANGE_ATTR = 'REQUEST_CHANGE_ATTR' 20 | export const RECEIVE_CHANGE_ATTR = 'RECEIVE_CHANGE_ATTR' 21 | 22 | export const CHECK_DEL = 'CHECK_DEL' 23 | export const INVERSE_CHECK_DEL = 'INVERSE_CHECK_DEL' 24 | 25 | export const SHOW_ATTR_BOX = 'SHOW_ATTR_BOX' 26 | export const HIDE_ATTR_BOX = 'HIDE_ATTR_BOX' 27 | 28 | export const CHANGE_EDIT_STATUS = 'CHANGE_EDIT_STATUS' 29 | 30 | export const operate = { 31 | QUERY: '1', 32 | ADD: '2', 33 | CHANGE_NUM: '3', 34 | DEL: '4', 35 | CHECK: '5', 36 | INVERT_CHECK: '6', 37 | CHANGE_ATTR: '8', 38 | GET_NUM: '9' 39 | } 40 | -------------------------------------------------------------------------------- /taro-demo/client/src/constants/detail.js: -------------------------------------------------------------------------------- 1 | export const REQUEST_DETAIL_CART = 'REQUEST_DETAIL_CART' 2 | export const RECEIVE_DETAIL_CART = 'RECEIVE_DETAIL_CART' 3 | 4 | export const REQUEST_DETAIL_SKU = 'REQUEST_DETAIL_SKU' 5 | export const RECEIVE_DETAIL_SKU = 'RECEIVE_DETAIL_SKU' 6 | 7 | export const REQUEST_DETAIL_ADD_CART = 'REQUEST_DETAIL_ADD_CART' 8 | export const RECEIVE_DETAIL_ADD_CART = 'RECEIVE_DETAIL_ADD_CART' 9 | 10 | // export const REQUEST_CART = 'REQUEST_CART' 11 | // export const RECEIVE_CART = 'RECEIVE_CART' 12 | 13 | // export const REQUEST_CART = 'REQUEST_CART' 14 | // export const RECEIVE_CART = 'RECEIVE_CART' 15 | -------------------------------------------------------------------------------- /taro-demo/client/src/constants/globalData.js: -------------------------------------------------------------------------------- 1 | const globalData = {} 2 | 3 | export function setGlobalData (key, val) { 4 | globalData[key] = val 5 | } 6 | 7 | export function getGlobalData (key) { 8 | return globalData[key] 9 | } -------------------------------------------------------------------------------- /taro-demo/client/src/constants/home.js: -------------------------------------------------------------------------------- 1 | export const REQUEST_HOME = 'REQUEST_HOME' 2 | export const RECEIVE_HOME = 'RECEIVE_HOME' 3 | export const RECEIVE_HOME_ERROR = 'RECEIVE_HOME_ERROR' 4 | -------------------------------------------------------------------------------- /taro-demo/client/src/constants/images.js: -------------------------------------------------------------------------------- 1 | export const SEARCH_BAR_LIST_IMAGE = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAYCAYAAACbU/80AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAaElEQVRIx2NUVlb0ZGBgmMsAAcl3797fzkBHwAK1XBLKn8vAwCAFk1RWVvxPawcwofEZ6el7WAikQH3+l4GBIQ1Z8u7d+3R30CgYBSMPMI6WhOghQk/fw0JgtCQcBaNgQMFoSThaEgIAiY8mmPwztG0AAAAASUVORK5CYII=' 2 | export const SEARCH_BAR_MORE_IMAGE = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAGCAYAAADUtS5UAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAABmJLR0QAAAAAAAD5Q7t/AAAACXBIWXMAAAsSAAALEgHS3X78AAAAlklEQVQoz8WRsQ6CMBRFD5X4S4Z/kTK5QjARWJyJ8gtO8jGELyJhAAeeSdOUIpNnvD19vekLouh0BBpAAxPQAkXX9SMODP8MBOLfNvwnEJt+KGFquJkUuOLmYfmp+PmKX8tM0x+UNLHRrKN3+okjuyj+hGL5c5vWc+f9Y+Y7e4VAwbJ0DczyaOkZVErh74q2/Ao4WP79A14CJJ7qixoSAAAAAElFTkSuQmCC' 3 | -------------------------------------------------------------------------------- /taro-demo/client/src/constants/order/detail.js: -------------------------------------------------------------------------------- 1 | export const REQUEST_ORDER_DETAIL = 'REQUEST_ORDER_DETAIL' 2 | export const RECEIVE_ORDER_DETAIL = 'RECEIVE_ORDER_DETAIL' 3 | export const RESET_ORDER_DETAIL = 'RESET_ORDER_DETAIL' 4 | 5 | export const REQUEST_ORDER_CANCEL = 'REQUEST_ORDER_CANCEL' 6 | export const RECEIVE_ORDER_CANCEL = 'RECEIVE_ORDER_CANCEL' 7 | -------------------------------------------------------------------------------- /taro-demo/client/src/constants/order/list.js: -------------------------------------------------------------------------------- 1 | export const REQUEST_ORDER_LIST = 'REQUEST_ORDER_LIST' 2 | export const RECEIVE_ORDER_LIST = 'RECEIVE_ORDER_LIST' 3 | -------------------------------------------------------------------------------- /taro-demo/client/src/constants/search.js: -------------------------------------------------------------------------------- 1 | 2 | export const SHOW_SEARCH_BAR = 'SHOW_SEARCH_BAR' 3 | export const REQUEST_SEARCH_RESULT = 'REQUEST_SEARCH_RESULT' 4 | export const RECEIVE_SEARCH_RESULT = 'RECEIVE_SEARCH_RESULT' 5 | export const RECEIVE_SEARCH_ERROR = 'RECEIVE_SEARCH_ERROR' 6 | export const SHOW_RESULT = 'SHOW_RESULT' 7 | export const CHANGE_HISTORY = 'CHANGE_HISTORY' 8 | export const SHOW_NOT_FIND = 'SHOW_NOT_FIND' 9 | export const RESET_STATE = 'RESET_STATE' 10 | -------------------------------------------------------------------------------- /taro-demo/client/src/constants/shop.js: -------------------------------------------------------------------------------- 1 | export const REQUEST_SHOP = 'REQUEST_SHOP' 2 | export const RECEIVE_SHOP = 'RECEIVE_SHOP' 3 | export const RESET_SHOP = 'RESET_SHOP' 4 | export const REQUEST_SUB_SHOP = 'REQUEST_SUB_SHOP' 5 | export const RECEIVE_SUB_SHOP = 'RECEIVE_SUB_SHOP' 6 | export const RESET_SUB_SHOP = 'RESET_SUB_SHOP' 7 | export const REQUEST_ACT = 'REQUEST_ACT' 8 | export const RECEIVE_ACT = 'RECEIVE_ACT' 9 | export const RESET_ACT = 'RESET_ACT' 10 | export const REQUEST_SHOP_CATE = 'REQUEST_SHOP_CATE' 11 | export const RECEIVE_SHOP_CATE = 'RECEIVE_SHOP_CATE ' 12 | export const RESET_SHOP_CATE = 'RESET_SHOP_CATE ' 13 | -------------------------------------------------------------------------------- /taro-demo/client/src/constants/weapp.js: -------------------------------------------------------------------------------- 1 | export const APP_ID = 'wx5c394ae0cf4d8e32' 2 | -------------------------------------------------------------------------------- /taro-demo/client/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | TARO商城 12 | 15 | 16 | 17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /taro-demo/client/src/leancloud/cart/editCart.js: -------------------------------------------------------------------------------- 1 | const AV = require('../index').default 2 | const { typeMap, getNewCartData } = require('./utils') 3 | 4 | function changCartNum (oldCartInfo, skus) { 5 | // 更新购物车中的商品数据 6 | const newCartInfo = oldCartInfo.map((item) => { 7 | const temp = skus.filter(sku => item.skuId === sku.skuId)[0] 8 | if (temp) { 9 | item.num = temp.num 10 | item.isCheck = true 11 | } 12 | return item 13 | }) 14 | 15 | return newCartInfo 16 | } 17 | 18 | function addCart (oldCartInfo, skus) { 19 | skus.forEach((sku) => { sku.isCheck = true }) 20 | let spliceIdx 21 | // 更新购物车中的商品数据 22 | let newCartInfo = oldCartInfo.map((item) => { 23 | const temp = skus.filter((sku, idx) => { 24 | if (item.skuId === sku.skuId) { 25 | spliceIdx = idx 26 | return true 27 | } 28 | })[0] 29 | if (temp) { 30 | skus.splice(spliceIdx, 1) 31 | item.num += temp.num 32 | item.isCheck = temp.isCheck 33 | item.size = temp.size 34 | item.color = temp.color 35 | } 36 | 37 | return item 38 | }) 39 | 40 | return newCartInfo.concat(skus) 41 | } 42 | 43 | function delCart (oldCartInfo, skus) { 44 | const newCartInfo = oldCartInfo.filter((item) => { 45 | const temp = skus.filter(sku => { return item.skuId === sku.skuId })[0] 46 | return !temp 47 | }) 48 | 49 | return newCartInfo 50 | } 51 | 52 | function checkCart (oldCartInfo, skus) { 53 | // 更新购物车中的商品数据 54 | const newCartInfo = oldCartInfo.map((item) => { 55 | const temp = skus.filter(sku => item.skuId === sku.skuId)[0] 56 | if (temp) { 57 | item.isCheck = true 58 | } 59 | return item 60 | }) 61 | 62 | return newCartInfo 63 | } 64 | 65 | function inverseCheckCart (oldCartInfo, skus) { 66 | // 更新购物车中的商品数据 67 | const newCartInfo = oldCartInfo.map((item) => { 68 | const temp = skus.filter(sku => item.skuId === sku.skuId)[0] 69 | if (temp) { 70 | item.isCheck = false 71 | } 72 | return item 73 | }) 74 | 75 | return newCartInfo 76 | } 77 | 78 | function changeAttr (oldCartInfo, skus) { 79 | // 更新购物车中的商品数据 80 | const newCartInfo = oldCartInfo.map((item) => { 81 | const temp = skus.filter(sku => item.skuId === sku.skuId)[0] 82 | if (temp) { 83 | item.info.colorInfo.value = temp.color 84 | item.info.sizeInfo.value = temp.size 85 | } 86 | return item 87 | }) 88 | 89 | return newCartInfo 90 | } 91 | 92 | async function editCart (data) { 93 | const { h5Id, skus, type } = data 94 | const CartQuery = new AV.Query('Cart') 95 | 96 | // 补存num字段 97 | skus.forEach((sku) => { 98 | sku.skuId = sku.skuId + '' 99 | if(!sku.num) { sku.num = 1 } 100 | }) 101 | 102 | // 获取当前购物车 103 | CartQuery.equalTo('h5Id', h5Id) 104 | CartQuery.select(['cartInfo', 'shopMap']) 105 | const findRes = await CartQuery.find() 106 | const cartRes = findRes[0].toJSON() 107 | const shopMap = cartRes.shopMap[0] 108 | const oldCartInfo = cartRes.cartInfo 109 | const cartObjectId = cartRes.objectId 110 | let newCartInfo 111 | 112 | // 根据type进行相应的购物车操作 113 | switch (type) { 114 | case typeMap['CHANGE_NUM']: 115 | newCartInfo = changCartNum(oldCartInfo, skus) 116 | break 117 | case typeMap['ADD']: 118 | newCartInfo = addCart(oldCartInfo, skus) 119 | break 120 | case typeMap['DEL']: 121 | newCartInfo = delCart(oldCartInfo, skus) 122 | break 123 | case typeMap['CHECK']: 124 | newCartInfo = checkCart(oldCartInfo, skus) 125 | break 126 | case typeMap['INVERT_CHECK']: 127 | newCartInfo = inverseCheckCart(oldCartInfo, skus) 128 | break 129 | case typeMap['CHANGE_ATTR']: 130 | newCartInfo = changeAttr(oldCartInfo, skus) 131 | break 132 | default: 133 | break 134 | } 135 | 136 | // 得到新的购物车数据 137 | const cartData = await getNewCartData({cartInfo: newCartInfo, shopMap}) 138 | // 更新数据 139 | const newCart = AV.Object.createWithoutData('Cart', cartObjectId) 140 | for (let key in cartData) { 141 | newCart.set(key, cartData[key]) 142 | } 143 | await newCart.save() 144 | 145 | return { result: { data: cartData }} 146 | } 147 | 148 | exports.editCart = editCart 149 | -------------------------------------------------------------------------------- /taro-demo/client/src/leancloud/cart/getCart.js: -------------------------------------------------------------------------------- 1 | import AV from '../index' 2 | 3 | export async function getCart (h5Id) { 4 | const Cart = AV.Object.extend('Cart') 5 | const CartQuery = new AV.Query('Cart') 6 | let cartData = { 7 | h5Id, 8 | cartNum: 0, 9 | totalPrice: 0, 10 | cartInfo: [], 11 | shopMap: [{}] 12 | } 13 | CartQuery.equalTo('h5Id', h5Id) 14 | const res = await CartQuery.find() 15 | if (res.length === 0) { 16 | const cartItem = new Cart() 17 | for(let key in cartData) { 18 | cartItem.set(key, cartData[key]) 19 | } 20 | await cartItem.save() 21 | } else { 22 | cartData = res[0].toJSON() 23 | } 24 | return { result: { data: cartData } } 25 | } 26 | 27 | export default getCart 28 | -------------------------------------------------------------------------------- /taro-demo/client/src/leancloud/cart/utils.js: -------------------------------------------------------------------------------- 1 | const AV = require('../index').default 2 | 3 | const typeMap = { 4 | ADD: '2', 5 | CHANGE_NUM: '3', 6 | DEL: '4', 7 | CHECK: '5', 8 | INVERT_CHECK: '6', 9 | CHANGE_ATTR: '8' 10 | } 11 | 12 | async function getNewCartData ({cartInfo, shopMap}) { 13 | const ComQuery = new AV.Query('commodity') 14 | const ShopQuery = new AV.Query('shop') 15 | 16 | const newShopMap = {} 17 | const allCartInfoData = await Promise.all(cartInfo.map(async (item) => { 18 | let newItem = item 19 | 20 | // 如果没有商品的具体信息 21 | if (!item.info) { 22 | // 获得商品的具体信息 23 | ComQuery.equalTo('skuId', parseInt(item.skuId)) 24 | let allItemData = await ComQuery.find() 25 | allItemData = allItemData[0].toJSON() 26 | 27 | // 加上venderId 28 | if (!item.venderId) { item.venderId = allItemData.venderId } 29 | item.venderId += '' 30 | 31 | // 更改尺寸 32 | if (item.size) { 33 | allItemData.sizeInfo.value = item.size 34 | } 35 | 36 | // 更改颜色 37 | if (item.color) { 38 | allItemData.colorInfo.value = item.color 39 | } 40 | 41 | // 判定是否被选中 42 | if (!item.isCheck) { item.isCheck = false } 43 | 44 | newItem = Object.assign({}, item, { info: allItemData }) 45 | } 46 | 47 | // 获得商店的具体信息 48 | if (!newShopMap[newItem.venderId]) { 49 | // 先找下有没有缓存,不用再查数据库 50 | if (!shopMap[newItem.venderId]) { 51 | ShopQuery.equalTo('venderId', parseInt(newItem.venderId)) 52 | ShopQuery.select(['thumbnail', 'title', 'venderId']) 53 | let shopInfo = await ShopQuery.find() 54 | shopInfo = shopInfo[0].toJSON() 55 | newShopMap[newItem.venderId] = shopInfo 56 | } else { 57 | newShopMap[newItem.venderId] = shopMap[newItem.venderId] 58 | } 59 | } 60 | 61 | return newItem 62 | })) 63 | 64 | const cartData = { 65 | cartNum: 0, 66 | totalPrice: 0, 67 | cartInfo: allCartInfoData, 68 | shopMap: [newShopMap] 69 | } 70 | 71 | allCartInfoData.forEach((item) => { 72 | cartData.cartNum += item.num 73 | if (item.isCheck) { 74 | cartData.totalPrice += item.num * parseInt(item.info.price) 75 | } 76 | }) 77 | 78 | return cartData 79 | } 80 | 81 | module.exports = { 82 | typeMap, 83 | getNewCartData 84 | } 85 | -------------------------------------------------------------------------------- /taro-demo/client/src/leancloud/index.js: -------------------------------------------------------------------------------- 1 | import AV from 'leancloud-storage/dist/av-min' 2 | 3 | AV.init('YqcEnvTSXLpEiFq3JNwgBzhL-gzGzoHsz', 'Sl7Ylgav79ETm65WRCXB6d0a') 4 | 5 | export default AV 6 | -------------------------------------------------------------------------------- /taro-demo/client/src/leancloud/order/addOrder.js: -------------------------------------------------------------------------------- 1 | import AV from '../index' 2 | 3 | async function addOrder (data) { 4 | const { h5Id, freightPrice = 14, payType = 4 } = data 5 | let returnData 6 | const CartQuery = new AV.Query('Cart') 7 | 8 | const Order = AV.Object.extend('Order') 9 | 10 | CartQuery.equalTo('h5Id', h5Id) 11 | const res = await CartQuery.find() 12 | const cartData = res[0].toJSON() 13 | const cartObjectId = cartData.objectId 14 | 15 | // 获取购物车中被选中的数据 16 | const payInfo = cartData.cartInfo.filter((item) => { 17 | return item.isCheck 18 | }) 19 | 20 | // 使用新的商品map 21 | const oldShopMap = cartData.shopMap[0] 22 | const newShop = {} 23 | payInfo.forEach(item => { 24 | newShop[item.venderId] = oldShopMap[item.venderId] 25 | }) 26 | 27 | if (payInfo.length === 0) { 28 | returnData = { 29 | code: -1, 30 | msg: '购物车中没有勾选物品' 31 | } 32 | } 33 | 34 | const orderId = Math.random().toString(36).substr(2) 35 | 36 | const orderData = { 37 | dateSubmit: new Date().toString(), 38 | orderId, 39 | orderState: 1, 40 | ownerId: h5Id, 41 | payType, 42 | shopInfo: newShop, 43 | shouldPayPrice: cartData.totalPrice + freightPrice, 44 | skuInfoList: payInfo, 45 | cancelReasonText: '提交申请' 46 | } 47 | 48 | // 新插入订单 49 | const orderItem = new Order() 50 | for (let key in orderData) { 51 | orderItem.set(key, orderData[key]) 52 | } 53 | await orderItem.save().catch(err => console.log(err)) 54 | 55 | // 购物车中除移生成了订单的商品 56 | let newCartNum = 0 57 | let newCartShopMap = {} 58 | const newCartInfo = cartData.cartInfo.filter((item) => { 59 | if (!item.isCheck) { 60 | newCartShopMap[item.venderId] = oldShopMap[item.venderId] 61 | newCartNum += item.num 62 | return true 63 | } 64 | return false 65 | }) 66 | 67 | // 更新数据 68 | const newCart = AV.Object.createWithoutData('Cart', cartObjectId) 69 | newCart.set('cartInfo', newCartInfo) 70 | newCart.set('cartNum', newCartNum) 71 | newCart.set('shopMap', [newCartShopMap]) 72 | newCart.set('totalPrice', 0) 73 | await newCart.save() 74 | 75 | returnData = { 76 | code: 0, 77 | msg: '成功生成订单', 78 | data: orderData 79 | } 80 | 81 | return { result: { data: returnData } } 82 | } 83 | 84 | exports.addOrder = addOrder 85 | -------------------------------------------------------------------------------- /taro-demo/client/src/leancloud/order/cancelOrder.js: -------------------------------------------------------------------------------- 1 | import AV from '../index' 2 | 3 | async function cancelOrder (data) { 4 | const { orderId, cancelReasonText } = data 5 | const OrderQuery = new AV.Query('Order') 6 | 7 | OrderQuery.equalTo('orderId', orderId) 8 | const res = await OrderQuery.find() 9 | const orderData = res[0].toJSON() 10 | const orderObjectId = orderData.objectId 11 | 12 | const newOrder = AV.Object.createWithoutData('Order', orderObjectId) 13 | newOrder.set('orderState', -1) 14 | newOrder.set('cancelReasonText', cancelReasonText) 15 | await newOrder.save() 16 | 17 | const returnData = { 18 | code: 0, 19 | msg: '成功取消订单' 20 | } 21 | 22 | return { result: { data: returnData } } 23 | } 24 | 25 | exports.cancelOrder = cancelOrder 26 | -------------------------------------------------------------------------------- /taro-demo/client/src/leancloud/order/getBalance.js: -------------------------------------------------------------------------------- 1 | import AV from '../index' 2 | 3 | async function getBalance (data) { 4 | const { h5Id } = data 5 | const CartQuery = new AV.Query('Cart') 6 | CartQuery.equalTo('h5Id', h5Id) 7 | const res = await CartQuery.find() 8 | const cartData = res[0].toJSON() 9 | const payInfo = cartData.cartInfo.filter((item) => { 10 | return item.isCheck 11 | }) 12 | 13 | const balanceData = { 14 | isNeedBanlance: payInfo.length !== 0, 15 | payInfo, 16 | shopMap: cartData.shopMap, 17 | totalPrice: cartData.totalPrice 18 | } 19 | 20 | return { result: { data: balanceData } } 21 | } 22 | 23 | exports.getBalance = getBalance 24 | -------------------------------------------------------------------------------- /taro-demo/client/src/leancloud/order/getOrder.js: -------------------------------------------------------------------------------- 1 | import AV from '../index' 2 | 3 | async function getOrder (data) { 4 | const { h5Id } = data 5 | const OrderQuery = new AV.Query('Order') 6 | 7 | OrderQuery.equalTo('ownerId', h5Id) 8 | OrderQuery.descending('createdAt') 9 | const res = await OrderQuery.find() 10 | const orderData = res.map(item => { 11 | return item.toJSON() 12 | }) 13 | 14 | return { result: { data: orderData } } 15 | } 16 | 17 | exports.getOrder = getOrder 18 | -------------------------------------------------------------------------------- /taro-demo/client/src/leancloud/order/getOrderDetail.js: -------------------------------------------------------------------------------- 1 | import AV from '../index' 2 | 3 | async function getOrderDetail (data) { 4 | const { h5Id, orderId } = data 5 | const OrderQuery = new AV.Query('Order') 6 | 7 | OrderQuery.equalTo('ownerId', h5Id) 8 | OrderQuery.equalTo('orderId', orderId) 9 | const res = await OrderQuery.find() 10 | 11 | const orderData = res[0].toJSON() 12 | 13 | return { result: { data: orderData } } 14 | } 15 | 16 | exports.getOrderDetail = getOrderDetail 17 | -------------------------------------------------------------------------------- /taro-demo/client/src/leancloud/search/getList.js: -------------------------------------------------------------------------------- 1 | import AV from '../index' 2 | 3 | async function getList (data) { 4 | const CommodityQuery = new AV.Query('commodity') 5 | 6 | let allGoods = await CommodityQuery.find() 7 | allGoods = allGoods.map(item => { 8 | return item.toJSON() 9 | }) 10 | let res = {} 11 | let searchGoods = allGoods.filter(item => { 12 | return item.skuName.indexOf(data.keyWords) > -1 13 | }) 14 | 15 | res.wares = searchGoods 16 | res.count = searchGoods.length 17 | res.page = data.page 18 | return { result: { data: res } } 19 | } 20 | 21 | exports.getList = getList 22 | -------------------------------------------------------------------------------- /taro-demo/client/src/leancloud/shop/getInformation.js: -------------------------------------------------------------------------------- 1 | import AV from '../index' 2 | 3 | export async function getInformation () { 4 | const InfomationQuery = new AV.Query('Infomation') 5 | const findRes = await InfomationQuery.find() 6 | const result = findRes.map(item => { 7 | return item.toJSON() 8 | }) 9 | return { result: { data: result } } 10 | } 11 | -------------------------------------------------------------------------------- /taro-demo/client/src/leancloud/shop/getShop.js: -------------------------------------------------------------------------------- 1 | import AV from '../index' 2 | 3 | async function getShop (venderId) { 4 | const shopQuery = new AV.Query('shop') 5 | shopQuery.equalTo('venderId', Number(venderId)) 6 | const findRes = await shopQuery.find() 7 | let result = findRes[0].toJSON() 8 | const floors = await Promise.all(result.floors.map(async (floor) => { 9 | const objectIds = floor.commodities.map((item) => { 10 | const comObject = AV.Object.createWithoutData('commodity', item.objectId) 11 | return comObject 12 | }) 13 | const commodities = await AV.Object.fetchAll(objectIds) 14 | floor.commodities = commodities.map(com => com.toJSON()) 15 | return floor 16 | })) 17 | result.floors = floors 18 | return { result: { data: result } } 19 | } 20 | 21 | exports.getShop = getShop 22 | -------------------------------------------------------------------------------- /taro-demo/client/src/leancloud/shop/getSku.js: -------------------------------------------------------------------------------- 1 | import AV from '../index' 2 | 3 | export async function getSku (skuId) { 4 | const CommodityQuery = new AV.Query('commodity') 5 | CommodityQuery.equalTo('skuId', Number(skuId)) 6 | const findRes = await CommodityQuery.find() 7 | const result = findRes[0].toJSON() 8 | return { result: { data: [result] } } 9 | } 10 | 11 | -------------------------------------------------------------------------------- /taro-demo/client/src/leancloud/user/addUser.js: -------------------------------------------------------------------------------- 1 | import AV from '../index' 2 | 3 | export async function addUser (h5Id) { 4 | const Man = AV.Object.extend('Man') 5 | const man = new Man() 6 | man.set('h5Id', h5Id) 7 | const res = await man.save() 8 | return res 9 | } 10 | 11 | -------------------------------------------------------------------------------- /taro-demo/client/src/leancloud/user/getUser.js: -------------------------------------------------------------------------------- 1 | async function getUser (db, _openid) { 2 | const _ = db.command 3 | const collection = db.collection('user') 4 | const user = await collection.where({ 5 | _openid: _.eq(_openid) 6 | }) 7 | 8 | return user 9 | } 10 | 11 | exports.getUser = getUser 12 | -------------------------------------------------------------------------------- /taro-demo/client/src/pages/cart/cart.js: -------------------------------------------------------------------------------- 1 | import Taro, { Component } from '@tarojs/taro' 2 | import { View, ScrollView } from '@tarojs/components' 3 | import { connect } from '@tarojs/redux' 4 | import classnames from 'classnames' 5 | 6 | import CommondityContainer from '../../components/cart/commodity/commodity_container' 7 | import Goods from '../../components/cart/goods/goods' 8 | import BottomBar from '../../components/cart/bottom_bar/bottom_bar' 9 | import EditBox from '../../components/cart/edit_box/edit_box' 10 | 11 | import { fetchCart } from '../../actions/cart' 12 | 13 | import { throttle, getSystemInfo } from '../../utils/util' 14 | 15 | import './cart.scss' 16 | 17 | class Cart extends Component { 18 | config = { 19 | navigationBarTitleText: '购物车', 20 | backgroundColor: '#f2efef', 21 | disableScroll: true 22 | } 23 | 24 | constructor () { 25 | super(...arguments) 26 | this.state = { 27 | isLogin: true, 28 | isFixedBar: false, 29 | systemInfo: {} 30 | } 31 | 32 | this.scrollTop = 0 33 | this.pageScrollFn = throttle(this.isNeedFixedBar, 200, this) 34 | } 35 | 36 | componentDidShow () { 37 | const isLogin = true 38 | this.props.onFetchCart() 39 | this.setState({ 40 | isLogin, 41 | systemInfo: getSystemInfo() 42 | }) 43 | } 44 | 45 | onViewScroll = (e) => { 46 | this.pageScrollFn(e.detail.scrollTop) 47 | } 48 | 49 | isNeedFixedBar (top) { 50 | const {isFixedBar} = this.state 51 | this.scrollTop = top 52 | let needTop = 45 53 | if (top > needTop) { 54 | !isFixedBar && this.setState({isFixedBar: true}) 55 | } else { 56 | isFixedBar && this.setState({isFixedBar: false}) 57 | } 58 | } 59 | 60 | render () { 61 | const {isLogin, isFixedBar, systemInfo} = this.state 62 | const {commoditys, editSkuData, isFetching} = this.props 63 | 64 | const showEidtBox = editSkuData.showEidtBox 65 | 66 | const hasCommodity = commoditys.length !== 0 67 | 68 | const cartClass = classnames('cart-scroll', {'no_bottom': !hasCommodity && !isLogin}) 69 | 70 | const newSystemInfo = getSystemInfo() 71 | 72 | let windowHeight = systemInfo.windowHeight 73 | if (newSystemInfo.windowHeight > windowHeight && windowHeight) { 74 | windowHeight = newSystemInfo.windowHeight 75 | } 76 | 77 | if (isFetching) { 78 | Taro.showLoading({title: '请求加载中...'}) 79 | } else { 80 | Taro.hideLoading() 81 | } 82 | 83 | return ( 84 | 85 | 91 | 92 | 93 | {/* */} 94 | 95 | {showEidtBox && } 96 | 97 | 98 | ) 99 | } 100 | } 101 | 102 | export default connect( 103 | ({cart, home}) => ({ 104 | floorData: home.floorData || {}, 105 | commoditys: cart.commoditys, 106 | editSkuData: cart.editSkuData, 107 | isFetching: cart.isFetching 108 | }), (dispatch) => ({ 109 | onFetchCart (...args) { 110 | dispatch(fetchCart(...args)) 111 | } 112 | }))(Cart) 113 | -------------------------------------------------------------------------------- /taro-demo/client/src/pages/cart/cart.scss: -------------------------------------------------------------------------------- 1 | /*postcss-pxtransform rn eject enable*/ 2 | 3 | page { 4 | overflow-y: hidden; 5 | } 6 | 7 | @keyframes slide_in { 8 | 0% { 9 | opacity: 0; 10 | transform: translateY(130%); 11 | } 12 | 100% { 13 | opacity: 1; 14 | transform: translateY(0); 15 | } 16 | } 17 | 18 | @keyframes slide_out { 19 | 0% { 20 | opacity: 1; 21 | transform: translateY(0); 22 | } 23 | 100% { 24 | opacity: 0; 25 | transform: translateY(130%); 26 | } 27 | } 28 | 29 | @keyframes fade_out { 30 | 0% { 31 | opacity: 1; 32 | } 33 | 100% { 34 | opacity: 0; 35 | } 36 | } 37 | 38 | .show { 39 | display: block !important; 40 | } 41 | 42 | .show_wp { 43 | animation: slide_in 0.3s ease-out forwards; 44 | } 45 | 46 | .hide_wp { 47 | animation: slide_out 0.3s ease-in forwards; 48 | } 49 | 50 | .fade { 51 | animation: fade_out 0.3s ease-in-out forwards; 52 | } 53 | 54 | /*postcss-pxtransform rn eject disable*/ 55 | 56 | .cart { 57 | height: 100%; 58 | display: flex; 59 | flex-direction: column; 60 | background-color: #f2efef; 61 | overflow: hidden; 62 | } 63 | 64 | .cart-scroll { 65 | flex-grow: 1; 66 | -webkit-overflow-scrolling: touch; 67 | } 68 | 69 | .cart.no_bottom { 70 | padding-bottom: 0; 71 | } 72 | -------------------------------------------------------------------------------- /taro-demo/client/src/pages/cart/cart_sub.js: -------------------------------------------------------------------------------- 1 | import Taro, { Component } from '@tarojs/taro' 2 | import { View, ScrollView } from '@tarojs/components' 3 | import { connect } from '@tarojs/redux' 4 | import classnames from 'classnames' 5 | 6 | import CommondityContainer from '../../components/cart/commodity/commodity_container' 7 | import Goods from '../../components/cart/goods/goods' 8 | import BottomBar from '../../components/cart/bottom_bar/bottom_bar' 9 | import EditBox from '../../components/cart/edit_box/edit_box' 10 | 11 | import { 12 | fetchCart 13 | } from '../../actions/cart' 14 | 15 | import { getLoginStatus, throttle, getSystemInfo } from '../../utils/util' 16 | 17 | import './cart.scss' 18 | 19 | class CartSub extends Component { 20 | config = { 21 | navigationBarTitleText: '购物车', 22 | backgroundColor: '#f2efef', 23 | disableScroll: true 24 | } 25 | 26 | constructor () { 27 | super(...arguments) 28 | this.state = { 29 | isLogin: Boolean(getLoginStatus()), 30 | isFixedBar: false, 31 | systemInfo: {} 32 | } 33 | 34 | this.scrollTop = 0 35 | this.pageScrollFn = throttle(this.isNeedFixedBar, 200, this) 36 | } 37 | 38 | componentDidShow () { 39 | const isLogin = Boolean(getLoginStatus()) 40 | this.props.fetchCart() 41 | this.setState({ 42 | isLogin, 43 | systemInfo: getSystemInfo() 44 | }) 45 | } 46 | 47 | onViewScroll = (e) => { 48 | this.pageScrollFn && this.pageScrollFn(e.detail.scrollTop) 49 | } 50 | 51 | isNeedFixedBar (top) { 52 | const {isFixedBar} = this.state 53 | this.scrollTop = top 54 | let needTop = 45 55 | if (top > needTop) { 56 | !isFixedBar && this.setState({isFixedBar: true}) 57 | } else { 58 | isFixedBar && this.setState({isFixedBar: false}) 59 | } 60 | } 61 | 62 | render () { 63 | const {isLogin, isFixedBar, systemInfo} = this.state 64 | const {commoditys, editSkuData, isFetching} = this.props 65 | 66 | const showEidtBox = editSkuData.showEidtBox 67 | 68 | const hasCommodity = commoditys.length !== 0 69 | 70 | const cartClass = classnames('cart-scroll', {'no_bottom': !hasCommodity && !isLogin}) 71 | 72 | const newSystemInfo = getSystemInfo() 73 | 74 | let windowHeight = systemInfo.windowHeight 75 | if (newSystemInfo.windowHeight > windowHeight && windowHeight) { 76 | windowHeight = newSystemInfo.windowHeight 77 | } 78 | 79 | if (isFetching) { 80 | Taro.showLoading({title: '请求加载中...'}) 81 | } else { 82 | Taro.hideLoading() 83 | } 84 | 85 | return ( 86 | 87 | 94 | 95 | 96 | {/* */} 97 | 98 | {showEidtBox ? : null} 99 | 100 | 101 | ) 102 | } 103 | } 104 | 105 | export default connect(( 106 | { 107 | cart, 108 | home 109 | }) => ({ 110 | floorData: home.floorData || {}, 111 | commoditys: cart.commoditys, 112 | editSkuData: cart.editSkuData, 113 | isFetching: cart.isFetching 114 | }), (dispatch) => ({ 115 | fetchCart (...args) { 116 | dispatch(fetchCart(...args)) 117 | } 118 | }))(CartSub) 119 | -------------------------------------------------------------------------------- /taro-demo/client/src/pages/detail/bag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/taro-demo/client/src/pages/detail/bag.png -------------------------------------------------------------------------------- /taro-demo/client/src/pages/index/index.scss: -------------------------------------------------------------------------------- 1 | page, body { 2 | height: 100%; 3 | } 4 | 5 | .index { 6 | background-color: #ffffff; 7 | height: 100%; 8 | display: flex; 9 | flex-direction: column; 10 | overflow: hidden; 11 | } 12 | 13 | .index-search_into { 14 | padding: 30px 40px; 15 | position: relative; 16 | display: flex; 17 | height: 120px; 18 | background: #ffffff; 19 | } 20 | 21 | .index-search_box { 22 | width: 88%; 23 | margin: 0 auto; 24 | } 25 | 26 | .index_list.hidden { 27 | height: 100%; 28 | overflow: hidden; 29 | } 30 | 31 | .index_list { 32 | //flex: 1; 33 | flex-grow: 1; 34 | overflow: scroll; 35 | -webkit-overflow-scrolling: touch; 36 | } 37 | 38 | .index_item { 39 | position: relative; 40 | display: flex; 41 | flex-direction: column; 42 | align-items: center; 43 | width: 100%; 44 | margin: -1px 0 0; 45 | overflow: hidden; 46 | } 47 | 48 | .index_item_in { 49 | width: 100%; 50 | height: 100%; 51 | } 52 | 53 | .index_item_img { 54 | width: 100%; 55 | } 56 | 57 | .index_item_brand { 58 | position: absolute; 59 | top: 300px; 60 | left: 0; 61 | width: 100%; 62 | font-size: 38px; 63 | font-weight: bold; 64 | text-align: center; 65 | color: #fff; 66 | letter-spacing: 4px; 67 | //transition: top 2s ease-in; 68 | } 69 | 70 | .index_item_desc { 71 | position: absolute; 72 | top: 358px; 73 | left: 0; 74 | width: 100%; 75 | font-size: 24px; 76 | font-weight: bold; 77 | text-align: center; 78 | letter-spacing: 8px; 79 | color: #fff; 80 | //transition: top 2s ease-in; 81 | } 82 | 83 | .index_item_type { 84 | position: absolute; 85 | top: 40px; 86 | right: 30px; 87 | text-align: right; 88 | color: #fff; 89 | font-size: 18px; 90 | } 91 | 92 | .index_item_title { 93 | position: absolute; 94 | top: 300px; 95 | left: 0; 96 | width: 100%; 97 | font-size: 42px; 98 | font-weight: bold; 99 | text-align: center; 100 | color: #fff; 101 | letter-spacing: 4px; 102 | //transition: top 2s ease-in; 103 | } 104 | 105 | .index_item_more { 106 | position: absolute; 107 | top: 406px; 108 | left: 50%; 109 | width: 228px; 110 | height: 42px; 111 | margin-left: -114px; 112 | border: 1px solid #fff; 113 | text-align: center; 114 | line-height: 42px; 115 | font-size: 24px; 116 | color: #fff; 117 | //transition: top 2s ease-in; 118 | } 119 | 120 | .index_item_avatar { 121 | position: absolute; 122 | bottom: 128px; 123 | left: 50%; 124 | margin-left: -25px; 125 | width: 50px; 126 | height: 50px; 127 | overflow: hidden; 128 | border-radius: 100px; 129 | //transition: bottom 2s ease-in; 130 | } 131 | 132 | .index_item_athor { 133 | position: absolute; 134 | bottom: 74px; 135 | left: 0; 136 | width: 100%; 137 | text-align: center; 138 | font-size: 20px; 139 | color: #fff; 140 | //transition: bottom 2s ease-in; 141 | } 142 | 143 | .animation .index_item { 144 | animation: home_move 0.5s ease-in forwards; 145 | } 146 | 147 | @keyframes home_move { 148 | 0% { 149 | transform: translateY(50px); 150 | } 151 | 100% { 152 | transform: translateY(0px); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /taro-demo/client/src/pages/list/list.scss: -------------------------------------------------------------------------------- 1 | .list { 2 | position: relative; 3 | height: 100%; 4 | overflow: hidden; 5 | background-color: white; 6 | display: flex; 7 | flex-direction: column; 8 | } 9 | -------------------------------------------------------------------------------- /taro-demo/client/src/reducers/balance.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions' 2 | import { 3 | REQUEST_BALANCE_INFO, 4 | RECEIVE_BALANCE_INFO, 5 | RECEIVE_BALANCE_ORDER, 6 | REQUEST_BALANCE_ORDER 7 | } from '../constants/balance' 8 | 9 | import { parseMoney } from '../utils/util' 10 | 11 | const balanceData = { 12 | isNeedBanlance: true, 13 | payCommodities: [], 14 | freightPrice: 14, 15 | totalPrice: 0, 16 | allPrice: 0, 17 | payNum: 0, 18 | isFetching: false 19 | } 20 | 21 | export default handleActions({ 22 | [REQUEST_BALANCE_INFO] (state) { 23 | return { 24 | ...state, 25 | isFetching: true 26 | } 27 | }, 28 | [RECEIVE_BALANCE_INFO] (state, action) { 29 | const { payCommodities, isNeedBanlance, payNum } = action.payload 30 | let totalPrice = action.payload.totalPrice 31 | const allPrice = parseMoney(totalPrice + state.freightPrice) 32 | totalPrice = parseMoney(totalPrice) 33 | return { 34 | ...state, 35 | isNeedBanlance, 36 | payCommodities, 37 | totalPrice, 38 | allPrice, 39 | payNum, 40 | isFetching: false 41 | } 42 | }, 43 | [REQUEST_BALANCE_ORDER](state) { 44 | return Object.assign({}, state, { 45 | isFetching: true 46 | }) 47 | }, 48 | 49 | [RECEIVE_BALANCE_ORDER](state) { 50 | return Object.assign({}, state, { 51 | isFetching: false 52 | }) 53 | } 54 | }, {...balanceData}) 55 | -------------------------------------------------------------------------------- /taro-demo/client/src/reducers/cart.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions' 2 | import { 3 | REQUEST_CART, 4 | RECEIVE_CART, 5 | REQUEST_DEL_CART, 6 | RECEIVE_DEL_CART, 7 | REQUEST_CHANGE_NUM, 8 | RECEIVE_CHANGE_NUM, 9 | REQUEST_ADD_CART, 10 | RECEIVE_ADD_CART, 11 | REQUEST_CHECK_CART, 12 | RECEIVE_CHECK_CART, 13 | REQUEST_INVERSE_CHECK, 14 | RECEIVE_INVERSE_CHECK, 15 | REQUEST_CHANGE_ATTR, 16 | RECEIVE_CHANGE_ATTR, 17 | REQUEST_SKU_ATTR, 18 | RECEIVE_SKU_ATTR, 19 | CHECK_DEL, 20 | INVERSE_CHECK_DEL, 21 | SHOW_ATTR_BOX, 22 | HIDE_ATTR_BOX, 23 | CHANGE_EDIT_STATUS 24 | } from '../constants/cart' 25 | 26 | const INITIAL_STATE = { 27 | commoditys: [], 28 | offSales: [], 29 | editSkuData: { 30 | showEidtBox: false 31 | }, 32 | diviner: [], 33 | footmark: [], 34 | couponData: { 35 | showCouponList: false 36 | }, 37 | checkCartNum: 0, 38 | totalPrice: 0, 39 | checkAll: false, 40 | checkDelAll: false, 41 | isEditStatus: false, 42 | isFetching: false 43 | } 44 | 45 | function genarateFetchActions () { 46 | const actionsMap = {} 47 | 48 | const fetchActionType = [ 49 | REQUEST_CART, 50 | REQUEST_DEL_CART, 51 | REQUEST_CHANGE_NUM, 52 | REQUEST_ADD_CART, 53 | REQUEST_CHECK_CART, 54 | REQUEST_INVERSE_CHECK, 55 | REQUEST_CHANGE_ATTR, 56 | REQUEST_SKU_ATTR, 57 | ] 58 | 59 | const receiveActionType = [ 60 | RECEIVE_CART, 61 | RECEIVE_DEL_CART, 62 | RECEIVE_CHANGE_NUM, 63 | RECEIVE_ADD_CART, 64 | RECEIVE_CHECK_CART, 65 | RECEIVE_INVERSE_CHECK, 66 | RECEIVE_CHANGE_ATTR 67 | ] 68 | 69 | fetchActionType.forEach((type) => { 70 | actionsMap[type] = function(state){ 71 | return { 72 | ...state, 73 | isFetching: true 74 | } 75 | } 76 | }) 77 | receiveActionType.forEach((type) => { 78 | actionsMap[type] = function (state, action) { 79 | const { 80 | commoditys = [], 81 | offSales = [], 82 | checkCartNum = 0, 83 | totalPrice = 0, 84 | checkAll = false 85 | } = action.payload 86 | 87 | return { 88 | ...state, 89 | commoditys, 90 | offSales, 91 | checkCartNum, 92 | totalPrice, 93 | checkAll, 94 | isFetching: false 95 | } 96 | } 97 | }) 98 | 99 | return actionsMap 100 | } 101 | 102 | export default handleActions({ 103 | ...genarateFetchActions(), 104 | [CHECK_DEL](state, action) { 105 | const { commoditys, checkDelAll } = action.payload 106 | return { 107 | ...state, 108 | commoditys, 109 | checkDelAll 110 | } 111 | }, 112 | [INVERSE_CHECK_DEL](state, action) { 113 | const { commoditys, checkDelAll } = action.payload 114 | return { 115 | ...state, 116 | commoditys, 117 | checkDelAll 118 | } 119 | }, 120 | [RECEIVE_SKU_ATTR](state, action) { 121 | const { editSkuData } = action.payload 122 | return { 123 | ...state, 124 | editSkuData, 125 | isFetching: false 126 | } 127 | }, 128 | [SHOW_ATTR_BOX](state, action) { 129 | const { editSkuData } = action.payload 130 | return { 131 | ...state, 132 | editSkuData 133 | } 134 | }, 135 | [HIDE_ATTR_BOX](state, action) { 136 | const { editSkuData } = action.payload 137 | return { 138 | ...state, 139 | editSkuData 140 | } 141 | }, 142 | [CHANGE_EDIT_STATUS](state, action) { 143 | const { isEditStatus } = action.payload 144 | return { 145 | ...state, 146 | isEditStatus 147 | } 148 | } 149 | }, { ...INITIAL_STATE }) 150 | -------------------------------------------------------------------------------- /taro-demo/client/src/reducers/detail.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions' 2 | import { 3 | REQUEST_DETAIL_CART, 4 | RECEIVE_DETAIL_CART, 5 | REQUEST_DETAIL_SKU, 6 | RECEIVE_DETAIL_SKU, 7 | REQUEST_DETAIL_ADD_CART, 8 | RECEIVE_DETAIL_ADD_CART 9 | } from '../constants/detail' 10 | 11 | const detailData = { 12 | sku: {}, 13 | cartInfo: [], 14 | cartNum: 0, 15 | isFetching: false 16 | } 17 | 18 | export default handleActions({ 19 | [REQUEST_DETAIL_CART](state) { 20 | return { 21 | ...state, 22 | isFetching: true 23 | } 24 | }, 25 | [RECEIVE_DETAIL_CART](state, action) { 26 | const { cartNum } = action.payload 27 | return { 28 | ...state, 29 | cartNum, 30 | isFetching: false 31 | } 32 | }, 33 | [REQUEST_DETAIL_SKU](state) { 34 | return { 35 | ...state, 36 | isFetching: true 37 | } 38 | }, 39 | [RECEIVE_DETAIL_SKU](state, action) { 40 | const sku = action.payload 41 | return { 42 | ...state, 43 | sku, 44 | isFetching: false 45 | } 46 | }, 47 | [REQUEST_DETAIL_ADD_CART](state) { 48 | return { 49 | ...state, 50 | isFetching: true 51 | } 52 | }, 53 | [RECEIVE_DETAIL_ADD_CART](state, action) { 54 | const { cartNum } = action.payload 55 | return { 56 | ...state, 57 | cartNum, 58 | isFetching: false 59 | } 60 | }, 61 | }, {...detailData}) 62 | -------------------------------------------------------------------------------- /taro-demo/client/src/reducers/home.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions' 2 | import { 3 | REQUEST_HOME, 4 | RECEIVE_HOME, 5 | RECEIVE_HOME_ERROR 6 | } from '../constants/home' 7 | 8 | const homeData = { 9 | loading: false, 10 | floorData: [] 11 | } 12 | 13 | export default handleActions({ 14 | [REQUEST_HOME] (state) { 15 | return { 16 | ...state, 17 | loading: true 18 | } 19 | }, 20 | [RECEIVE_HOME] (state, action) { 21 | const { data } = action.payload 22 | return { 23 | ...state, 24 | loading: false, 25 | floorData: data 26 | } 27 | }, 28 | [RECEIVE_HOME_ERROR] (state) { 29 | return { 30 | ...state 31 | } 32 | } 33 | }, {...homeData}) 34 | -------------------------------------------------------------------------------- /taro-demo/client/src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux' 2 | import detail from './detail' 3 | import home from './home' 4 | import shop from './shop' 5 | import search from './search' 6 | import cart from './cart' 7 | import balance from './balance' 8 | 9 | import orderDetail from './order/detail' 10 | import orderList from './order/list' 11 | 12 | export default combineReducers({ 13 | detail, 14 | home, 15 | shop, 16 | search, 17 | orderDetail, 18 | orderList, 19 | cart, 20 | balance 21 | }) 22 | -------------------------------------------------------------------------------- /taro-demo/client/src/reducers/order/detail.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions' 2 | import { 3 | REQUEST_ORDER_DETAIL, 4 | RECEIVE_ORDER_DETAIL, 5 | RECEIVE_ORDER_CANCEL, 6 | REQUEST_ORDER_CANCEL 7 | } from '../../constants/order/detail' 8 | 9 | const detail = { 10 | isFetchingDetail: false, 11 | all: {} 12 | } 13 | 14 | export default handleActions({ 15 | [REQUEST_ORDER_DETAIL] (state) { 16 | return Object.assign({ 17 | isFetchingDetail: true 18 | }, state) 19 | }, 20 | 21 | [RECEIVE_ORDER_DETAIL] (state, action) { 22 | const res = action.payload 23 | return { 24 | ...state, 25 | isFetchingDetail: false, 26 | all: res 27 | } 28 | }, 29 | 30 | [REQUEST_ORDER_CANCEL] (state) { 31 | return { 32 | ...state, 33 | isFetchingDetail: true 34 | } 35 | }, 36 | 37 | [RECEIVE_ORDER_CANCEL] (state) { 38 | return { 39 | ...state, 40 | isFetchingDetail: false 41 | } 42 | }, 43 | }, { 44 | ...detail 45 | }) 46 | -------------------------------------------------------------------------------- /taro-demo/client/src/reducers/order/list.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions' 2 | import { 3 | REQUEST_ORDER_LIST, 4 | RECEIVE_ORDER_LIST 5 | } from '../../constants/order/list' 6 | 7 | const list = { 8 | isFetchingList: false, 9 | orderList: [] 10 | } 11 | 12 | export default handleActions({ 13 | [REQUEST_ORDER_LIST] (state) { 14 | return Object.assign({}, state, { 15 | isFetchingList: true 16 | }) 17 | }, 18 | 19 | [RECEIVE_ORDER_LIST] (state, action) { 20 | const data = action.payload 21 | return Object.assign({}, state, { 22 | isFetchingList: false, 23 | orderList: data 24 | }) 25 | }, 26 | }, { ...list }) 27 | -------------------------------------------------------------------------------- /taro-demo/client/src/reducers/search.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions' 2 | 3 | import { 4 | SHOW_SEARCH_BAR, 5 | REQUEST_SEARCH_RESULT, 6 | RECEIVE_SEARCH_RESULT, 7 | RECEIVE_SEARCH_ERROR, 8 | SHOW_RESULT, 9 | CHANGE_HISTORY, 10 | SHOW_NOT_FIND, 11 | RESET_STATE 12 | } from '../constants/search' 13 | const searchData = { 14 | historyWords: ['品牌', '衣服'], 15 | hotWords: ['品牌', '衣服'], 16 | searchResult: { 17 | wares: [] 18 | }, 19 | loading: false, 20 | cart: null, 21 | showSearchBar: true, 22 | showSearchResult: false, 23 | showSearchHot: true, 24 | showSearchHistory: true, 25 | showErrorProblem: false, 26 | showNotFind: false 27 | } 28 | export default handleActions({ 29 | [SHOW_SEARCH_BAR] (state) { 30 | return { 31 | ...state, 32 | showSearchBar: !state.showSearchBar 33 | } 34 | }, 35 | [REQUEST_SEARCH_RESULT] (state, action) { 36 | if (state.searchResult.page && state.searchResult.page === 1) { 37 | state.searchResult = { 38 | wares: [] 39 | } 40 | } 41 | return { 42 | ...state, 43 | loading: true, 44 | showSearchBar: true, 45 | showSearchResult: true, 46 | showSearchHot: false, 47 | showSearchHistory: false, 48 | showErrorProblem: false, 49 | showNotFind: false 50 | } 51 | }, 52 | [RECEIVE_SEARCH_RESULT] (state, action) { 53 | return { 54 | ...state, 55 | searchResult: action.payload 56 | } 57 | }, 58 | [RECEIVE_SEARCH_ERROR] (state) { 59 | return { 60 | ...state, 61 | showErrorProblem: true 62 | } 63 | }, 64 | [CHANGE_HISTORY] (state, action) { 65 | return { 66 | ...state, 67 | historyWords: action.payload 68 | } 69 | }, 70 | [SHOW_RESULT] (state, action) { 71 | let isShow = action.payload 72 | return { 73 | ...state, 74 | showSearchResult: isShow, 75 | showSearchHot: !isShow, 76 | showSearchHistory: !isShow 77 | } 78 | }, 79 | [SHOW_NOT_FIND] (state) { 80 | return { 81 | ...state, 82 | showNotFind: true 83 | } 84 | }, 85 | [RESET_STATE] () { 86 | return searchData 87 | } 88 | }, { ...searchData }) 89 | -------------------------------------------------------------------------------- /taro-demo/client/src/reducers/shop.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions' 2 | import { 3 | REQUEST_SHOP, 4 | RECEIVE_SHOP, 5 | RESET_SHOP 6 | } from '../constants/shop' 7 | 8 | const INITIAL_STATE = { 9 | title: '', 10 | floors: [] 11 | } 12 | 13 | export default handleActions({ 14 | [REQUEST_SHOP](state) { 15 | return { ...state } 16 | }, 17 | [RECEIVE_SHOP](state, action) { 18 | const data = action.payload 19 | return { 20 | ...state, 21 | ...data 22 | } 23 | }, 24 | [RESET_SHOP](state) { 25 | return { 26 | title: '', 27 | floors: [] 28 | } 29 | } 30 | }, { ...INITIAL_STATE }) 31 | -------------------------------------------------------------------------------- /taro-demo/client/src/store/index.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from 'redux' 2 | import thunkMiddleware from 'redux-thunk' 3 | import { createLogger } from 'redux-logger' 4 | import rootReducer from '../reducers' 5 | 6 | const middlewares = [ 7 | thunkMiddleware, 8 | createLogger() 9 | ] 10 | 11 | export default function configStore () { 12 | const store = createStore(rootReducer, applyMiddleware(...middlewares)) 13 | return store 14 | } 15 | -------------------------------------------------------------------------------- /taro-demo/client/src/utils/index.js: -------------------------------------------------------------------------------- 1 | import Taro from '@tarojs/taro' 2 | import { getGlobalData } from '../constants/globalData' 3 | 4 | const appid = 'wx9504f077bdc24ea2' 5 | const secret = 'a98c03055579cfd517a45fb4771377e9' 6 | 7 | async function getUserInfo () { 8 | const userData = getGlobalData('userData') 9 | if (userData) { 10 | return userData 11 | } 12 | try { 13 | const userData = await Taro.getUserInfo() 14 | return userData 15 | } catch (err) { 16 | console.log(err) 17 | console.log('微信登录或用户接口故障') 18 | return {} 19 | } 20 | } 21 | 22 | async function getOpenId () { 23 | let openId 24 | try { 25 | openId = Taro.getStorageSync('taro_demo_openid') 26 | } catch (error) { 27 | console.log(error) 28 | } 29 | if (openId) { 30 | return openId 31 | } else { 32 | const res = await Taro.cloud.callFunction({ 33 | name: 'user', 34 | data: { 35 | func: 'getOpenId' 36 | } 37 | }) 38 | const openId = res.result.data.openId 39 | Taro.setStorage({key: 'taro_demo_openid', data: openId}) 40 | return openId 41 | } 42 | } 43 | 44 | async function getIsAuth () { 45 | const openid = await getOpenId() 46 | let {userInfo} = await getUserInfo() 47 | let isAuth = false 48 | if (userInfo) { 49 | userInfo.isAuth = true 50 | userInfo._id = openid 51 | isAuth = true 52 | } else { 53 | userInfo = { 54 | _id: openid, 55 | isAuth: false 56 | } 57 | } 58 | await wx.cloud.callFunction({ 59 | name: 'user', 60 | data: { 61 | func: 'addUser', 62 | data: userInfo 63 | }, 64 | success: (res) => { 65 | // console.log(res) 66 | }, 67 | fail: (res) => { 68 | // console.log(res) 69 | } 70 | }) 71 | 72 | return isAuth 73 | } 74 | 75 | function getH5UniqueId () { 76 | if (process.env.TARO_ENV !== 'weapp') { 77 | return new Promise((resolve, reject) => { 78 | Taro.getStorage({ 79 | key: 'Taro_h5_demo_uid', 80 | success({ data }) { 81 | if (!data) { 82 | const h5Id = `user_${Math.random().toString(36).substr(2)}` 83 | Taro.setStorage({ key: 'Taro_h5_demo_uid', data: h5Id }) 84 | const addUser = require('../leancloud/user/addUser').addUser 85 | addUser(h5Id).then((res) => { 86 | Taro.setStorage({ key: 'Taro_h5_demo_objectId', data: res.id }) 87 | resolve(h5Id) 88 | }).catch(reject) 89 | } else { 90 | resolve(data) 91 | } 92 | }, 93 | fail() { 94 | const h5Id = `user_${Math.random().toString(36).substr(2)}` 95 | Taro.setStorage({ key: 'Taro_h5_demo_uid', data: h5Id }) 96 | const addUser = require('../leancloud/user/addUser').addUser 97 | addUser(h5Id).then((res) => { 98 | Taro.setStorage({ key: 'Taro_h5_demo_objectId', data: res.id }) 99 | resolve(h5Id) 100 | }).catch(reject) 101 | } 102 | }) 103 | }) 104 | } else { 105 | return null 106 | } 107 | } 108 | 109 | export { 110 | getUserInfo, 111 | getOpenId, 112 | getIsAuth, 113 | getH5UniqueId 114 | } 115 | -------------------------------------------------------------------------------- /taro-demo/client/src/utils/wx.js: -------------------------------------------------------------------------------- 1 | import Taro from '@tarojs/taro' 2 | 3 | import { getGlobalData } from '../constants/globalData' 4 | import { isEmptyObject } from './util' 5 | 6 | export async function getWxUserData () { 7 | const userData = getGlobalData('userData') 8 | if (userData) { 9 | return userData 10 | } 11 | try { 12 | const userData = await Taro.getUserInfo() 13 | return userData 14 | } catch (err) { 15 | console.log(err) 16 | console.log('微信登录或用户接口故障') 17 | return null 18 | } 19 | } 20 | 21 | export async function checkSettingStatus (scope, { title, content }) { 22 | const setting = await Taro.getSetting() 23 | const authSetting = setting.authSetting 24 | if (!isEmptyObject(authSetting)) { 25 | if (authSetting[scope] === false) { 26 | const res = await Taro.showModal({ 27 | title: title, 28 | content: content, 29 | showCancel: true 30 | }) 31 | if (res.confirm) { 32 | const setting = await Taro.openSetting() 33 | const authSetting = setting.authSetting 34 | if (!isEmptyObject(authSetting)) { 35 | if (authSetting[scope] === true) { 36 | return await getWxUserData() 37 | } 38 | } 39 | } 40 | } 41 | } 42 | return null 43 | } 44 | -------------------------------------------------------------------------------- /taro-demo/cloud/doc/information.json: -------------------------------------------------------------------------------- 1 | {"_id":"W2pgbeqC-opZcR0z","desc":"店铺1","venderId":{"$numberLong":"1"},"image":"http://img20.360buyimg.com/ling/jfs/t1/1161/40/5220/256660/5b9f125cE063f3457/6e4dcd832773a0e2.jpg"} 2 | {"_id":"W3DpRxp0j_S6QBTN","venderId":{"$numberLong":"2"},"desc":"店铺2","image":"http://img12.360buyimg.com/ling/jfs/t1/1550/16/5171/266341/5b9f1b09E428298ba/d586bfc13f02a332.jpg"} 3 | {"_id":"W3DqDOqC-opZc_xv","venderId":{"$numberLong":"3"},"desc":"店铺3","image":"http://img14.360buyimg.com/ling/jfs/t1/2576/31/5323/251933/5b9f1b20E11657686/c2f74978d2db0300.jpg"} 4 | {"_id":"W3DqZ-qC-opZc_yv","desc":"店铺4","image":"http://img14.360buyimg.com/ling/jfs/t1/5916/27/5150/265659/5b9f1b36E270b1d18/c3f5c638e3bef241.jpg","venderId":{"$numberLong":"4"}} 5 | -------------------------------------------------------------------------------- /taro-demo/cloud/doc/shop.json: -------------------------------------------------------------------------------- 1 | {"_id":"1","floors":[{"commodities":[{"$numberLong":"1"},{"$numberLong":"2"},{"$numberLong":"3"},{"$numberLong":"4"}],"desc":"http://img13.360buyimg.com/ling/jfs/t1/351/8/5598/360623/5b9f2d78E2ae9ff61/716a483125913fd9.jpg","title":"//img12.360buyimg.com/tuangou/s750x170_jfs/t15316/209/1136705664/8030/71099545/5a4626ebN8fea2205.png"},{"commodities":[{"$numberLong":"1"},{"$numberLong":"3"},{"$numberLong":"4"},{"$numberLong":"5"}],"desc":"http://img10.360buyimg.com/ling/jfs/t1/1657/27/5346/245880/5b9f2d78E85f0c8c7/1dc51ecf4e25b6d0.jpg","title":"//img10.360buyimg.com/tuangou/s750x170_jfs/t15328/270/809894122/7669/cc12bee5/5a38bbd7Nd9f338f0.png"}],"thumbnail":"//img10.360buyimg.com/popshop/s190x80_jfs/t16390/270/1887231446/24253/18756a28/5a72d454N18b1efc6.jpg","title":"店铺1","venderId":{"$numberLong":"1"},"banner":["http://img14.360buyimg.com/ling/jfs/t1/460/5/5518/747242/5b9f1eb2Ed89cd28b/7787f2a49186610f.jpg","http://img30.360buyimg.com/ling/jfs/t1/268/31/5534/1729274/5b9f1f14Eee5b2adf/8e74d65c03f3f9fd.jpg!q60","http://img12.360buyimg.com/ling/jfs/t1/1501/21/5274/925976/5b9f2021E25bcf9e1/9850163290842937.jpg!q60","http://img14.360buyimg.com/ling/jfs/t1/1826/38/5279/1690440/5b9f1f90Eecfa2c50/10051d297b94c29b.jpg!q60"],"desc":"店铺1页面","_openid":"oFQSH5MekinNSc_yqH9dNlmKh6vI"} 2 | {"_id":"2","desc":"店铺2页面","floors":[{"desc":"http://img10.360buyimg.com/ling/jfs/t1/1657/27/5346/245880/5b9f2d78E85f0c8c7/1dc51ecf4e25b6d0.jpg","title":"//img12.360buyimg.com/tuangou/s750x170_jfs/t15316/209/1136705664/8030/71099545/5a4626ebN8fea2205.png","commodities":[{"$numberLong":"3"},{"$numberLong":"1"},{"$numberLong":"2"},{"$numberLong":"5"}]},{"commodities":[{"$numberLong":"1"},{"$numberLong":"3"},{"$numberLong":"2"},{"$numberLong":"7"}],"desc":"http://img30.360buyimg.com/ling/jfs/t1/5083/21/5232/267378/5b9f2d78E8bcd381b/ff27135de4d8cf8c.jpg","title":"//img10.360buyimg.com/tuangou/s750x170_jfs/t15328/270/809894122/7669/cc12bee5/5a38bbd7Nd9f338f0.png"}],"thumbnail":"//img10.360buyimg.com/popshop/s190x80_jfs/t17935/53/2369573223/24376/e2dd64/5af1b116N558ae2db.jpg","title":"店铺2","venderId":{"$numberLong":"2"},"banner":["http://img30.360buyimg.com/ling/jfs/t1/268/31/5534/1729274/5b9f1f14Eee5b2adf/8e74d65c03f3f9fd.jpg!q60","http://img12.360buyimg.com/ling/jfs/t1/1501/21/5274/925976/5b9f2021E25bcf9e1/9850163290842937.jpg!q60","http://img14.360buyimg.com/ling/jfs/t1/1826/38/5279/1690440/5b9f1f90Eecfa2c50/10051d297b94c29b.jpg!q60","http://img20.360buyimg.com/ling/jfs/t1/5373/22/5202/707257/5b9f1e8aE219cdf19/bb17192e448bade7.jpg"],"_openid":"oFQSH5MekinNSc_yqH9dNlmKh6vI"} 3 | {"_id":"3","desc":"店铺3页面","floors":[{"commodities":[{"$numberLong":"2"},{"$numberLong":"3"},{"$numberLong":"6"},{"$numberLong":"4"}],"desc":"http://img30.360buyimg.com/ling/jfs/t1/5083/21/5232/267378/5b9f2d78E8bcd381b/ff27135de4d8cf8c.jpg","title":"//img12.360buyimg.com/tuangou/s750x170_jfs/t15316/209/1136705664/8030/71099545/5a4626ebN8fea2205.png"},{"title":"//img10.360buyimg.com/tuangou/s750x170_jfs/t15328/270/809894122/7669/cc12bee5/5a38bbd7Nd9f338f0.png","commodities":[{"$numberLong":"1"},{"$numberLong":"5"},{"$numberLong":"3"},{"$numberLong":"6"}],"desc":"http://img10.360buyimg.com/ling/jfs/t1/1657/27/5346/245880/5b9f2d78E85f0c8c7/1dc51ecf4e25b6d0.jpg"}],"thumbnail":"//img12.360buyimg.com/n1/s190x80_jfs/t22429/300/1109626640/5017/d77c7252/5b50350aNb53dba6c.png","title":"店铺3","venderId":{"$numberLong":"3"},"banner":["http://img20.360buyimg.com/ling/jfs/t1/5373/22/5202/707257/5b9f1e8aE219cdf19/bb17192e448bade7.jpg","http://img14.360buyimg.com/ling/jfs/t1/460/5/5518/747242/5b9f1eb2Ed89cd28b/7787f2a49186610f.jpg","http://img30.360buyimg.com/ling/jfs/t1/268/31/5534/1729274/5b9f1f14Eee5b2adf/8e74d65c03f3f9fd.jpg!q60","http://img12.360buyimg.com/ling/jfs/t1/1501/21/5274/925976/5b9f2021E25bcf9e1/9850163290842937.jpg!q60"],"_openid":"oFQSH5MekinNSc_yqH9dNlmKh6vI"} 4 | {"_id":"4","venderId":{"$numberLong":"4"},"banner":["http://img20.360buyimg.com/ling/jfs/t1/5373/22/5202/707257/5b9f1e8aE219cdf19/bb17192e448bade7.jpg","http://img14.360buyimg.com/ling/jfs/t1/460/5/5518/747242/5b9f1eb2Ed89cd28b/7787f2a49186610f.jpg","http://img30.360buyimg.com/ling/jfs/t1/268/31/5534/1729274/5b9f1f14Eee5b2adf/8e74d65c03f3f9fd.jpg!q60","http://img11.360buyimg.com/ling/jfs/t1/4629/4/5095/1714340/5b9f1f72E997695e5/4f56ca1a12642971.jpg!q60"],"desc":"店铺4页面","floors":[{"commodities":[{"$numberLong":"4"},{"$numberLong":"6"},{"$numberLong":"1"},{"$numberLong":"2"}],"desc":"http://img30.360buyimg.com/ling/jfs/t1/5083/21/5232/267378/5b9f2d78E8bcd381b/ff27135de4d8cf8c.jpg","title":"//img12.360buyimg.com/tuangou/s750x170_jfs/t15316/209/1136705664/8030/71099545/5a4626ebN8fea2205.png"},{"commodities":[{"$numberLong":"1"},{"$numberLong":"2"},{"$numberLong":"5"},{"$numberLong":"3"}],"desc":"http://img13.360buyimg.com/ling/jfs/t1/351/8/5598/360623/5b9f2d78E2ae9ff61/716a483125913fd9.jpg","title":"//img10.360buyimg.com/tuangou/s750x170_jfs/t15328/270/809894122/7669/cc12bee5/5a38bbd7Nd9f338f0.png"}],"thumbnail":"//img14.360buyimg.com/popshop/s190x80_jfs/t11023/223/1027006619/7985/c520a46c/5a379a4aN9d105368.png","title":"店铺4","_openid":"oFQSH5MekinNSc_yqH9dNlmKh6vI"} 5 | -------------------------------------------------------------------------------- /taro-demo/cloud/doc/user.json: -------------------------------------------------------------------------------- 1 | {"_id":"oFQSH5DTPL_1z8GvsBX3eug7B0YI","country":"China","nickName":"Mr_Prune","province":"Chongqing","city":"","gender":{"$numberLong":"1"},"isAuth":true,"language":"zh_CN","avatarUrl":"https://wx.qlogo.cn/mmopen/vi_32/2JXQXmeRCKLKicw8SACyqYXicibDVreHhCjJW17tuQcSL0ibaQgJeBsZyhgzZYXTs0ucTpqLiaTRw1SKBcia2lEEJk7g/132"} 2 | {"_id":"oFQSH5Hy28tDuKGyI2qHHjLw5fRY","gender":{"$numberLong":"1"},"isAuth":true,"language":"zh_CN","nickName":"江锡忠","province":"Guangdong","avatarUrl":"https://wx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTLHGZgQJjatG9aEe85aSVdicvfePpS5UKFzPD2DS12LiaZc0LPhfXhIITE6DCJJBbnT0UIrTbr3zZIw/132","city":"Zhanjiang","country":"China"} 3 | {"_id":"oFQSH5MekinNSc_yqH9dNlmKh6vI","country":"China","gender":{"$numberLong":"1"},"language":"zh_CN","nickName":"- 爽。。","province":"Guangdong","city":"Shenzhen","avatarUrl":"https://wx.qlogo.cn/mmopen/vi_32/NzY4FlYl7m50Hib0VZfkjaQsVkZ0YtpK0ceWx7AQnMeQu0DetkS0ecp2oQwFrS41TSNw5xa7yib2mmOKms5Fup1Q/132","isAuth":true} 4 | {"_id":{"$oid":"5b6d6d16524ec2d3211e5933"},"province":"Guangdong","avatarUrl":"https://wx.qlogo.cn/mmopen/vi_32/NzY4FlYl7m50Hib0VZfkjaQsVkZ0YtpK0ceWx7AQnMeQu0DetkS0ecp2oQwFrS41TSNw5xa7yib2mmOKms5Fup1Q/132","city":"Shenzhen","country":"China","gender":{"$numberLong":"1"},"isAuth":true,"language":"zh_CN","nickName":"- 爽。。"} 5 | -------------------------------------------------------------------------------- /taro-demo/cloud/functions/cart/editCart.js: -------------------------------------------------------------------------------- 1 | const { typeMap, getNewCartData } = require('./utils') 2 | 3 | function changCartNum (oldCartInfo, skus) { 4 | // 更新购物车中的商品数据 5 | const newCartInfo = oldCartInfo.map((item) => { 6 | const temp = skus.filter(sku => item.skuId === sku.skuId)[0] 7 | if (temp) { 8 | item.num = temp.num 9 | item.isCheck = true 10 | } 11 | return item 12 | }) 13 | 14 | return newCartInfo 15 | } 16 | 17 | function addCart (oldCartInfo, skus) { 18 | skus.forEach((sku) => { sku.isCheck = true }) 19 | let spliceIdx 20 | // 更新购物车中的商品数据 21 | let newCartInfo = oldCartInfo.map((item) => { 22 | const temp = skus.filter((sku, idx) => { 23 | if (item.skuId === sku.skuId) { 24 | spliceIdx = idx 25 | return true 26 | } 27 | })[0] 28 | if (temp) { 29 | skus.splice(spliceIdx, 1) 30 | item.num += temp.num 31 | item.isCheck = temp.isCheck 32 | item.size = temp.size 33 | item.color = temp.color 34 | } 35 | 36 | return item 37 | }) 38 | 39 | return newCartInfo.concat(skus) 40 | } 41 | 42 | function delCart (oldCartInfo, skus) { 43 | const newCartInfo = oldCartInfo.filter((item) => { 44 | const temp = skus.filter(sku => { return item.skuId === sku.skuId })[0] 45 | return !temp 46 | }) 47 | 48 | return newCartInfo 49 | } 50 | 51 | function checkCart (oldCartInfo, skus) { 52 | // 更新购物车中的商品数据 53 | const newCartInfo = oldCartInfo.map((item) => { 54 | const temp = skus.filter(sku => item.skuId === sku.skuId)[0] 55 | if (temp) { 56 | item.isCheck = true 57 | } 58 | return item 59 | }) 60 | 61 | return newCartInfo 62 | } 63 | 64 | function inverseCheckCart (oldCartInfo, skus) { 65 | // 更新购物车中的商品数据 66 | const newCartInfo = oldCartInfo.map((item) => { 67 | const temp = skus.filter(sku => item.skuId === sku.skuId)[0] 68 | if (temp) { 69 | item.isCheck = false 70 | } 71 | return item 72 | }) 73 | 74 | return newCartInfo 75 | } 76 | 77 | function changeAttr (oldCartInfo, skus) { 78 | // 更新购物车中的商品数据 79 | const newCartInfo = oldCartInfo.map((item) => { 80 | const temp = skus.filter(sku => item.skuId === sku.skuId)[0] 81 | if (temp) { 82 | item.info.colorInfo.value = temp.color 83 | item.info.sizeInfo.value = temp.size 84 | } 85 | return item 86 | }) 87 | 88 | return newCartInfo 89 | } 90 | 91 | async function editCart (db, data) { 92 | const { _id, skus, type } = data 93 | const cartColl = db.collection('cart') 94 | 95 | // 补存num字段 96 | skus.forEach((sku) => { 97 | sku.skuId = sku.skuId + '' 98 | if(!sku.num) { sku.num = 1 } 99 | }) 100 | 101 | // 获取当前购物车 102 | const res = await cartColl.doc(_id).field({ 103 | cartInfo: true, 104 | shopMap: true 105 | }).get() 106 | const shopMap = res.data[0].shopMap 107 | const oldCartInfo = res.data[0].cartInfo 108 | let newCartInfo 109 | 110 | // 根据type进行相应的购物车操作 111 | switch (type) { 112 | case typeMap['CHANGE_NUM']: 113 | newCartInfo = changCartNum(oldCartInfo, skus) 114 | break 115 | case typeMap['ADD']: 116 | newCartInfo = addCart(oldCartInfo, skus) 117 | break 118 | case typeMap['DEL']: 119 | newCartInfo = delCart(oldCartInfo, skus) 120 | break 121 | case typeMap['CHECK']: 122 | newCartInfo = checkCart(oldCartInfo, skus) 123 | break 124 | case typeMap['INVERT_CHECK']: 125 | newCartInfo = inverseCheckCart(oldCartInfo, skus) 126 | break 127 | case typeMap['CHANGE_ATTR']: 128 | newCartInfo = changeAttr(oldCartInfo, skus) 129 | break 130 | default: 131 | break 132 | } 133 | 134 | // 得到新的购物车数据 135 | const cartData = await getNewCartData({cartInfo: newCartInfo, shopMap}) 136 | 137 | // 更新数据 138 | await cartColl.doc(_id).update(cartData) 139 | 140 | return cartData 141 | } 142 | 143 | exports.editCart = editCart 144 | -------------------------------------------------------------------------------- /taro-demo/cloud/functions/cart/getCart.js: -------------------------------------------------------------------------------- 1 | async function getCart (db, data) { 2 | const { _id } = data 3 | const cartColl = db.collection('cart') 4 | let cartData = { 5 | _id, 6 | cartNum: 0, 7 | totalPrice: 0, 8 | cartInfo: [], 9 | shopMap: {} 10 | } 11 | 12 | const res = await cartColl.doc(_id).get() 13 | if (res.data.length === 0) { 14 | await cartColl.add(cartData) 15 | } else { 16 | cartData = res.data[0] 17 | } 18 | return cartData 19 | } 20 | 21 | exports.getCart = getCart 22 | -------------------------------------------------------------------------------- /taro-demo/cloud/functions/cart/index.js: -------------------------------------------------------------------------------- 1 | const app = require('wx-server-sdk') 2 | 3 | const { getCart } = require('./getCart.js') 4 | const { editCart } = require('./editCart.js') 5 | 6 | app.init({ 7 | envName: 'taro-ebook-23bbcb', 8 | mpAppId: 'wx9504f077bdc24ea2' 9 | }) 10 | 11 | async function main (event, context) { 12 | const db = app.database() 13 | const { func, data } = event 14 | let res 15 | if (func === 'getCart') { 16 | res = await getCart(db, data).catch(err => console.log(err)) 17 | } else if (func === 'editCart') { 18 | res = await editCart(db, data).catch(err => console.log(err)) 19 | } 20 | 21 | return { 22 | context, 23 | data: res 24 | } 25 | } 26 | 27 | exports.main = main 28 | -------------------------------------------------------------------------------- /taro-demo/cloud/functions/cart/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "wx-server-sdk": "^0.2.1" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /taro-demo/cloud/functions/cart/utils.js: -------------------------------------------------------------------------------- 1 | const app = require('tcb-admin-node') 2 | 3 | app.init({ 4 | envName: 'taro-ebook-23bbcb', 5 | mpAppId: 'wx9504f077bdc24ea2', 6 | }) 7 | 8 | const typeMap = { 9 | ADD: '2', 10 | CHANGE_NUM: '3', 11 | DEL: '4', 12 | CHECK: '5', 13 | INVERT_CHECK: '6', 14 | CHANGE_ATTR: '8' 15 | } 16 | 17 | async function getNewCartData ({cartInfo, shopMap}) { 18 | const db = app.database() 19 | const comColl = db.collection('commodity') 20 | const shopColl = db.collection('shop') 21 | 22 | const newShopMap = {} 23 | const allCartInfoData = await Promise.all(cartInfo.map(async (item) => { 24 | let newItem = item 25 | 26 | // 如果没有商品的具体信息 27 | if (!item.info) { 28 | // 获得商品的具体信息 29 | let allItemData = await comColl.doc(item.skuId).get() 30 | allItemData = allItemData.data[0] 31 | 32 | // 加上venderId 33 | if (!item.venderId) { item.venderId = allItemData.venderId } 34 | item.venderId += '' 35 | 36 | // 更改尺寸 37 | if (item.size) { 38 | allItemData.sizeInfo.value = item.size 39 | } 40 | 41 | // 更改颜色 42 | if (item.color) { 43 | allItemData.colorInfo.value = item.color 44 | } 45 | 46 | // 判定是否被选中 47 | if (!item.isCheck) { item.isCheck = false } 48 | 49 | newItem = Object.assign({}, item, { info: allItemData }) 50 | } 51 | 52 | // 获得商店的具体信息 53 | if (!newShopMap[newItem.venderId]) { 54 | // 先找下有没有缓存,不用再查数据库 55 | if (!shopMap[newItem.venderId]) { 56 | let shopInfo = await shopColl.doc(newItem.venderId).field({ 57 | thumbnail: true, 58 | title: true, 59 | venderId: true 60 | }).get() 61 | shopInfo = shopInfo.data[0] 62 | newShopMap[newItem.venderId] = shopInfo 63 | } else { 64 | newShopMap[newItem.venderId] = shopMap[newItem.venderId] 65 | } 66 | } 67 | 68 | return newItem 69 | })) 70 | 71 | const cartData = { 72 | cartNum: 0, 73 | totalPrice: 0, 74 | cartInfo: allCartInfoData, 75 | shopMap: [newShopMap] 76 | } 77 | 78 | allCartInfoData.forEach((item) => { 79 | cartData.cartNum += item.num 80 | if (item.isCheck) { 81 | cartData.totalPrice += item.num * parseInt(item.info.price) 82 | } 83 | }) 84 | 85 | return cartData 86 | } 87 | 88 | module.exports = { 89 | typeMap, 90 | getNewCartData 91 | } 92 | -------------------------------------------------------------------------------- /taro-demo/cloud/functions/order/addOrder.js: -------------------------------------------------------------------------------- 1 | async function addOrder (db, data) { 2 | const { _id, freightPrice = 14, payType = 4 } = data 3 | const _ = db.command 4 | const orderColl = db.collection('order') 5 | const cartColl = db.collection('cart') 6 | 7 | let cartData = await cartColl.doc(_id).get() 8 | cartData = cartData.data[0] 9 | 10 | // 获取购物车中被选中的数据 11 | const payInfo = cartData.cartInfo.filter((item) => { 12 | return item.isCheck 13 | }) 14 | 15 | // 使用新的商品map 16 | const oldShopMap = cartData.shopMap[0] 17 | const newShop = {} 18 | payInfo.forEach(item => { 19 | newShop[item.venderId] = oldShopMap[item.venderId] 20 | }) 21 | 22 | if (payInfo.length === 0) { 23 | return { 24 | code: -1, 25 | msg: '购物车中没有勾选物品' 26 | } 27 | } 28 | 29 | const orderId = Math.random().toString(36).substr(2) 30 | 31 | const orderData = { 32 | _id: orderId, 33 | dateSubmit: db.serverDate(), 34 | orderId, 35 | orderState: 1, 36 | ownerId: _id, 37 | payType, 38 | shopInfo: newShop, 39 | shouldPayPrice: cartData.totalPrice + freightPrice, 40 | skuInfoList: payInfo, 41 | cancelReasonText: '提交申请' 42 | } 43 | 44 | // 新插入订单 45 | await orderColl.add(orderData).catch(err => console.log(err)) 46 | 47 | // 购物车中除移生成了订单的商品 48 | let newCartNum = 0 49 | let newCartShopMap = {} 50 | const newCartInfo = cartData.cartInfo.filter((item) => { 51 | if (!item.isCheck) { 52 | newCartShopMap[item.venderId] = oldShopMap[item.venderId] 53 | newCartNum += item.num 54 | return true 55 | } 56 | return false 57 | }) 58 | 59 | await cartColl.doc(_id).update({ 60 | cartInfo: newCartInfo, 61 | cartNum: newCartNum, 62 | shopMap: [newCartShopMap], 63 | totalPrice: 0 64 | }) 65 | 66 | return { 67 | code: 0, 68 | msg: '成功生成订单', 69 | data: orderData 70 | } 71 | } 72 | 73 | exports.addOrder = addOrder 74 | -------------------------------------------------------------------------------- /taro-demo/cloud/functions/order/cancelOrder.js: -------------------------------------------------------------------------------- 1 | async function cancelOrder ( db, data) { 2 | const { orderId, cancelReasonText } = data 3 | const orderColl = db.collection('order') 4 | const _ = db.command 5 | 6 | await orderColl.doc(orderId).update({ 7 | orderState: -1, 8 | cancelReasonText 9 | }) 10 | 11 | return { 12 | code: 0, 13 | msg: '成功取消订单' 14 | } 15 | } 16 | 17 | exports.cancelOrder = cancelOrder 18 | -------------------------------------------------------------------------------- /taro-demo/cloud/functions/order/getBalance.js: -------------------------------------------------------------------------------- 1 | async function getBalance (app, data) { 2 | const { _id } = data 3 | const res = await app.callFunction({ 4 | name: 'cart', 5 | data: { 6 | func: 'getCart', 7 | data: { 8 | _id 9 | } 10 | } 11 | }) 12 | const cartData = res.result.data 13 | const payInfo = cartData.cartInfo.filter((item) => { 14 | return item.isCheck 15 | }) 16 | 17 | const balanceData = { 18 | isNeedBanlance: payInfo.length !== 0, 19 | payInfo, 20 | shopMap: cartData.shopMap, 21 | totalPrice: cartData.totalPrice 22 | } 23 | 24 | return balanceData 25 | } 26 | 27 | exports.getBalance = getBalance 28 | -------------------------------------------------------------------------------- /taro-demo/cloud/functions/order/getOrder.js: -------------------------------------------------------------------------------- 1 | async function getOrder (db, data) { 2 | const { _id } = data 3 | const orderColl = db.collection('order') 4 | const _ = db.command 5 | 6 | const res = await orderColl.where({ 7 | ownerId: _.eq(_id) 8 | }).orderBy('dateSubmit', 'desc').get() 9 | 10 | const orderData = res.data 11 | 12 | return orderData 13 | } 14 | 15 | exports.getOrder = getOrder 16 | -------------------------------------------------------------------------------- /taro-demo/cloud/functions/order/getOrderDetail.js: -------------------------------------------------------------------------------- 1 | async function getOrderDetail (db, data) { 2 | const { _id, orderId } = data 3 | const orderColl = db.collection('order') 4 | const _ = db.command 5 | 6 | const res = await orderColl.where({ 7 | ownerId: _.eq(_id), 8 | orderId: _.eq(orderId) 9 | }).get() 10 | 11 | const orderData = res.data[0] 12 | 13 | return orderData 14 | } 15 | 16 | exports.getOrderDetail = getOrderDetail 17 | -------------------------------------------------------------------------------- /taro-demo/cloud/functions/order/index.js: -------------------------------------------------------------------------------- 1 | const app = require('wx-server-sdk') 2 | 3 | const { getBalance } = require('./getBalance.js') 4 | const { addOrder } = require('./addOrder.js') 5 | const { getOrder } = require('./getOrder.js') 6 | const { cancelOrder } = require('./cancelOrder.js') 7 | const { getOrderDetail } = require('./getOrderDetail.js') 8 | 9 | app.init({ 10 | envName: 'taro-ebook-23bbcb', 11 | mpAppId: 'wx9504f077bdc24ea2', 12 | // secretId: 'AKIDuA6QxlhN9619IeT2y45S8tmCvRtnubjs', 13 | // secretKey: 'qXW08RurtFSb6YYZs73DvEQ1qmEFSDIJ', 14 | // sessionToken: '4431b3f2da2e54cdce7c85a8714b8abb63ca397340001' 15 | }) 16 | 17 | async function main (event, context) { 18 | const db = app.database() 19 | const { func, data } = event 20 | let res 21 | if (func === 'getBalance') { 22 | res = await getBalance(app, data) 23 | } else if (func === 'addOrder') { 24 | res = await addOrder(db, data) 25 | } else if (func === 'getOrder') { 26 | res = await getOrder(db, data) 27 | } else if (func === 'getOrderDetail') { 28 | res = await getOrderDetail(db, data) 29 | } else if (func === 'cancelOrder') { 30 | res = await cancelOrder(db, data) 31 | } 32 | 33 | return { 34 | data: res 35 | } 36 | } 37 | 38 | exports.main = main 39 | 40 | // // 测试的函数 41 | // async function test (params) { 42 | // const res = await main({ 43 | // func: 'getOrder', 44 | // data: { 45 | // _id: 'oFQSH5MekinNSc_yqH9dNlmKh6vI' 46 | // } 47 | // }) 48 | 49 | // console.log(res) 50 | // } 51 | 52 | // test() 53 | -------------------------------------------------------------------------------- /taro-demo/cloud/functions/order/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "wx-server-sdk": "^0.2.1" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /taro-demo/cloud/functions/search/getList.js: -------------------------------------------------------------------------------- 1 | async function getList (db, data) { 2 | const commColl = db.collection('commodity') 3 | const _ = db.command 4 | 5 | const allGoods = await commColl.get() 6 | let res = {} 7 | let searchGoods = allGoods.data.filter(item => { 8 | return item.skuName.indexOf(data.keyWords) > -1 9 | }) 10 | res.wares = searchGoods 11 | res.count = searchGoods.length 12 | res.page = data.page 13 | return res 14 | } 15 | 16 | exports.getList = getList 17 | -------------------------------------------------------------------------------- /taro-demo/cloud/functions/search/index.js: -------------------------------------------------------------------------------- 1 | const app = require('wx-server-sdk') 2 | 3 | const { getList } = require('./getList.js') 4 | 5 | app.init({ 6 | envName: 'taro-ebook-23bbcb', 7 | mpAppId: 'wx9504f077bdc24ea2', 8 | }) 9 | 10 | exports.main = async (event, context) => { 11 | const db = app.database() 12 | const { func, data } = event 13 | let res 14 | if (func === 'getList') { 15 | res = await getList(db, data) 16 | } 17 | return { 18 | context, 19 | data: res 20 | } 21 | } -------------------------------------------------------------------------------- /taro-demo/cloud/functions/search/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "wx-server-sdk": "^0.2.1" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /taro-demo/cloud/functions/shop/getInformation.js: -------------------------------------------------------------------------------- 1 | async function getInformation (db) { 2 | const collection = db.collection('information') 3 | const res = await collection.get() 4 | return res.data 5 | } 6 | 7 | exports.getInformation = getInformation -------------------------------------------------------------------------------- /taro-demo/cloud/functions/shop/getShop.js: -------------------------------------------------------------------------------- 1 | async function getShop (db, venderId) { 2 | const shopColl = db.collection('shop') 3 | const commColl = db.collection('commodity') 4 | const _ = db.command 5 | 6 | const res = await shopColl.where({ 7 | venderId: _.eq(Number(venderId)) 8 | }).get() 9 | 10 | const shopData = res.data[0] 11 | const floors = await Promise.all(shopData.floors.map(async (floor) => { 12 | let res = await commColl.where({ 13 | skuId: _.in(floor.commodities) 14 | }).get() 15 | floor.commodities = res.data 16 | return floor 17 | })) 18 | shopData.floors = floors 19 | 20 | return shopData 21 | } 22 | 23 | exports.getShop = getShop 24 | -------------------------------------------------------------------------------- /taro-demo/cloud/functions/shop/getSku.js: -------------------------------------------------------------------------------- 1 | async function getSku (db, skuId) { 2 | const commColl = db.collection('commodity') 3 | const res = await commColl.doc(skuId).get() 4 | console.log(res) 5 | return res.data 6 | } 7 | 8 | exports.getSku = getSku 9 | -------------------------------------------------------------------------------- /taro-demo/cloud/functions/shop/index.js: -------------------------------------------------------------------------------- 1 | const app = require('wx-server-sdk') 2 | 3 | const { getInformation } = require('./getInformation.js') 4 | const { getShop } = require('./getShop.js') 5 | const { getSku } = require('./getSku.js') 6 | 7 | app.init({ 8 | envName: 'taro-ebook-23bbcb', 9 | mpAppId: 'wx9504f077bdc24ea2' 10 | }) 11 | 12 | async function main (event, context) { 13 | const db = app.database() 14 | const { func, data } = event 15 | let res 16 | if (func === 'getInformation') { 17 | res = await getInformation(db) 18 | } else if (func === 'getShop') { 19 | res = await getShop(db, data) 20 | } else if (func === 'getSku'){ 21 | res = await getSku(db, data) 22 | } 23 | 24 | return { 25 | context, 26 | data: res 27 | } 28 | } 29 | 30 | exports.main = main 31 | -------------------------------------------------------------------------------- /taro-demo/cloud/functions/shop/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "wx-server-sdk": "^0.2.1" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /taro-demo/cloud/functions/user/addUser.js: -------------------------------------------------------------------------------- 1 | async function addUser (db, userInfo) { 2 | const collection = db.collection('user') 3 | await collection.doc(userInfo._id).set(userInfo) 4 | return userInfo 5 | } 6 | 7 | exports.addUser = addUser 8 | -------------------------------------------------------------------------------- /taro-demo/cloud/functions/user/getUser.js: -------------------------------------------------------------------------------- 1 | async function getUser (db, _openid) { 2 | const _ = db.command 3 | const collection = db.collection('user') 4 | const user = await collection.where({ 5 | _openid: _.eq(_openid) 6 | }) 7 | 8 | return user 9 | } 10 | 11 | exports.getUser = getUser 12 | -------------------------------------------------------------------------------- /taro-demo/cloud/functions/user/index.js: -------------------------------------------------------------------------------- 1 | const app = require('wx-server-sdk') 2 | 3 | const { addUser } = require('./addUser.js') 4 | const { getUser } = require('./getUser.js') 5 | 6 | app.init({ 7 | envName: 'taro-ebook-23bbcb', 8 | mpAppId: 'wx9504f077bdc24ea2' 9 | }) 10 | 11 | exports.main = async (event, context) => { 12 | const db = app.database() 13 | const { func, data } = event 14 | let res 15 | if (func === 'addUser') { 16 | res = await addUser(db, data) 17 | } else if (func === 'getUser') { 18 | res = await getUser(db, data) 19 | } else if (func === 'getOpenId') { 20 | res = event.userInfo 21 | } 22 | 23 | return { 24 | data: res 25 | } 26 | } -------------------------------------------------------------------------------- /taro-demo/cloud/functions/user/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "wx-server-sdk": "^0.2.1" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /taro-demo/project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "description", 3 | "packOptions": { 4 | "ignore": [ 5 | "server", 6 | "cloud" 7 | ] 8 | }, 9 | "setting": { 10 | "urlCheck": false, 11 | "es6": false, 12 | "postcss": false, 13 | "minified": false, 14 | "newFeature": true 15 | }, 16 | "compileType": "miniprogram", 17 | "libVersion": "2.6.2", 18 | "appid": "wx9504f077bdc24ea2", 19 | "projectname": "%E6%8E%98%E9%87%91%E5%B0%8F%E5%86%8Cdemo", 20 | "isGameTourist": false, 21 | "miniprogramRoot": "client/dist/", 22 | "cloudfunctionRoot": "cloud/functions/", 23 | "condition": { 24 | "search": { 25 | "current": -1, 26 | "list": [] 27 | }, 28 | "conversation": { 29 | "current": -1, 30 | "list": [] 31 | }, 32 | "plugin": { 33 | "current": -1, 34 | "list": [] 35 | }, 36 | "game": { 37 | "currentL": -1, 38 | "list": [] 39 | }, 40 | "miniprogram": { 41 | "current": 7, 42 | "list": [ 43 | { 44 | "id": -1, 45 | "name": "shop", 46 | "pathName": "pages/shop/shop", 47 | "query": "venderId=1" 48 | }, 49 | { 50 | "id": 1, 51 | "name": "cart", 52 | "pathName": "pages/cart/cart", 53 | "query": "" 54 | }, 55 | { 56 | "id": -1, 57 | "name": "cloud", 58 | "pathName": "pages/cloud/cloud", 59 | "query": "" 60 | }, 61 | { 62 | "id": 3, 63 | "name": "detail", 64 | "pathName": "pages/detail/detail", 65 | "query": "skuId=1" 66 | }, 67 | { 68 | "id": -1, 69 | "name": "cart_sub", 70 | "pathName": "pages/cart/cart_sub", 71 | "query": "2" 72 | }, 73 | { 74 | "id": 5, 75 | "name": "结算页", 76 | "pathName": "pages/balance/balance", 77 | "query": "" 78 | }, 79 | { 80 | "id": 6, 81 | "name": "order", 82 | "pathName": "pages/user/order/list/list", 83 | "query": "", 84 | "scene": null 85 | }, 86 | { 87 | "id": 7, 88 | "name": "orderDetail", 89 | "pathName": "pages/user/order/detail/detail", 90 | "query": "orderId=o6zt3qslcj&__key_=15535015457221", 91 | "scene": null 92 | } 93 | ] 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /taro-demo/tcb.json: -------------------------------------------------------------------------------- 1 | { 2 | "mpappid": "wx9504f077bdc24ea2", 3 | "env": "taro-ebook-23bbcb", 4 | "secretid": "AKIDhIyd705LQxzJBN1lYYVQzhbmLrMy7Btf", 5 | "secretkey": "7wfqvN7OLXRZihYgrUNabufu178hWvLX", 6 | "path": { 7 | "storage": "./cloud/storage", 8 | "database": "./cloud/database", 9 | "functions": "./cloud/functions" 10 | } 11 | } -------------------------------------------------------------------------------- /todoList-Redux/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /todoList-Redux/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["taro"], 3 | "rules": { 4 | "no-unused-vars": ["error", { "varsIgnorePattern": "Taro" }], 5 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx", ".tsx"] }] 6 | }, 7 | "parser": "babel-eslint" 8 | } 9 | -------------------------------------------------------------------------------- /todoList-Redux/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | .temp/ 3 | .rn_temp/ 4 | node_modules/ 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /todoList-Redux/config/dev.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | NODE_ENV: '"development"' 4 | }, 5 | defineConstants: { 6 | }, 7 | weapp: {}, 8 | h5: {} 9 | } 10 | -------------------------------------------------------------------------------- /todoList-Redux/config/index.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | projectName: 'todos', 3 | date: '2018-6-12', 4 | designWidth: 750, 5 | sourceRoot: 'src', 6 | outputRoot: 'dist', 7 | plugins: { 8 | babel: { 9 | sourceMap: true, 10 | presets: [ 11 | 'env' 12 | ], 13 | plugins: [ 14 | 'transform-class-properties', 15 | 'transform-decorators-legacy', 16 | 'transform-object-rest-spread' 17 | ] 18 | }, 19 | }, 20 | defineConstants: { 21 | }, 22 | weapp: { 23 | 24 | }, 25 | h5: { 26 | publicPath: '/', 27 | staticDirectory: 'static', 28 | module: { 29 | postcss: { 30 | autoprefixer: { 31 | enable: true 32 | } 33 | } 34 | } 35 | } 36 | } 37 | 38 | module.exports = function (merge) { 39 | if (process.env.NODE_ENV === 'development') { 40 | return merge({}, config, require('./dev')) 41 | } 42 | return merge({}, config, require('./prod')) 43 | } 44 | -------------------------------------------------------------------------------- /todoList-Redux/config/prod.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | NODE_ENV: '"production"' 4 | }, 5 | defineConstants: { 6 | }, 7 | weapp: {}, 8 | h5: {} 9 | } 10 | -------------------------------------------------------------------------------- /todoList-Redux/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "todos", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "taro 集成 redux 例子", 6 | "main": "index.js", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "", 11 | "license": "MIT", 12 | "dependencies": { 13 | "@tarojs/components": "1.1.4", 14 | "@tarojs/redux": "1.1.4", 15 | "@tarojs/router": "1.1.4", 16 | "@tarojs/taro": "1.1.4", 17 | "@tarojs/taro-h5": "1.1.4", 18 | "@tarojs/taro-weapp": "1.1.4", 19 | "nervjs": "^1.2.18", 20 | "redux": "^4.0.0", 21 | "redux-action": "^1.2.2", 22 | "redux-logger": "^3.0.6", 23 | "redux-thunk": "^2.3.0" 24 | }, 25 | "devDependencies": { 26 | "@tarojs/plugin-babel": "1.1.4", 27 | "@tarojs/plugin-csso": "1.1.4", 28 | "@tarojs/plugin-sass": "1.1.4", 29 | "@tarojs/plugin-uglifyjs": "1.1.4", 30 | "@tarojs/webpack-runner": "1.1.4", 31 | "babel-plugin-transform-class-properties": "^6.24.1", 32 | "babel-plugin-transform-decorators-legacy": "^1.3.4", 33 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 34 | "babel-preset-env": "^1.6.1" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /todoList-Redux/project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "miniprogramRoot": "./dist", 3 | "projectname": "todoList", 4 | "description": "todo List", 5 | "appid": "touristappid", 6 | "setting": { 7 | "urlCheck": true, 8 | "es6": false, 9 | "postcss": false, 10 | "minified": false 11 | }, 12 | "compileType": "miniprogram" 13 | } 14 | -------------------------------------------------------------------------------- /todoList-Redux/src/actions/index.js: -------------------------------------------------------------------------------- 1 | import { ADD, DELETE } from '../constants/todos' 2 | 3 | export const add = (data) => { 4 | return { 5 | data, 6 | type: ADD 7 | } 8 | } 9 | 10 | export const del = (data) => { 11 | return { 12 | data, 13 | type: DELETE 14 | } 15 | } -------------------------------------------------------------------------------- /todoList-Redux/src/app.js: -------------------------------------------------------------------------------- 1 | import Taro, { Component } from '@tarojs/taro' 2 | import { Provider } from '@tarojs/redux' 3 | 4 | import configStore from './store' 5 | import Index from './pages/index' 6 | 7 | import './app.scss' 8 | 9 | const store = configStore() 10 | 11 | class App extends Component { 12 | config = { 13 | pages: [ 14 | 'pages/index/index' 15 | ], 16 | window: { 17 | backgroundTextStyle: 'light', 18 | navigationBarBackgroundColor: '#fff', 19 | navigationBarTitleText: 'WeChat', 20 | navigationBarTextStyle: 'black' 21 | } 22 | } 23 | 24 | componentDidMount () {} 25 | 26 | componentDidShow () {} 27 | 28 | componentDidHide () {} 29 | 30 | componentCatchError () {} 31 | 32 | render () { 33 | return ( 34 | 35 | 36 | 37 | ) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /todoList-Redux/src/app.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/todoList-Redux/src/app.scss -------------------------------------------------------------------------------- /todoList-Redux/src/constants/todos.js: -------------------------------------------------------------------------------- 1 | export const ADD = 'ADD' 2 | export const DELETE = 'DELETE' -------------------------------------------------------------------------------- /todoList-Redux/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Taro 8 | 11 | 12 | 13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /todoList-Redux/src/pages/index/index.js: -------------------------------------------------------------------------------- 1 | import Taro, { Component } from '@tarojs/taro' 2 | import { View, Input, Text } from '@tarojs/components' 3 | import { connect } from '@tarojs/redux' 4 | import './index.scss' 5 | 6 | import { add, del } from '../../actions/index' 7 | 8 | class Index extends Component { 9 | config = { 10 | navigationBarTitleText: '首页' 11 | } 12 | 13 | constructor () { 14 | super () 15 | 16 | this.state = { 17 | newTodo: '' 18 | } 19 | } 20 | 21 | componentDidMount () { 22 | 23 | } 24 | 25 | saveNewTodo (e) { 26 | let { newTodo } = this.state 27 | if (!e.detail.value || e.detail.value === newTodo) return 28 | 29 | this.setState({ 30 | newTodo: e.detail.value 31 | }) 32 | } 33 | 34 | addTodo () { 35 | let { newTodo } = this.state 36 | let { add } = this.props 37 | 38 | if (!newTodo) return 39 | 40 | add(newTodo) 41 | this.setState({ 42 | newTodo: '' 43 | }) 44 | } 45 | 46 | delTodo (id) { 47 | let { del } = this.props 48 | del(id) 49 | } 50 | 51 | render () { 52 | // 获取未经处理的todos并展示 53 | let { newTodo } = this.state 54 | let { todos, add, del } = this.props 55 | 56 | const todosJsx = todos.map(todo => { 57 | return ( 58 | {todo.text}- 59 | ) 60 | }) 61 | 62 | return ( 63 | 64 | 65 | 66 | + 67 | 68 | { todosJsx } 69 | 70 | ) 71 | } 72 | } 73 | 74 | export default connect (({ todos }) => ({ 75 | todos: todos.todos 76 | }), (dispatch) => ({ 77 | add (data) { 78 | dispatch(add(data)) 79 | }, 80 | del (id) { 81 | dispatch(del(id)) 82 | } 83 | }))(Index) 84 | 85 | -------------------------------------------------------------------------------- /todoList-Redux/src/pages/index/index.scss: -------------------------------------------------------------------------------- 1 | .todos { 2 | padding: 20px 40px; 3 | font-size: 30px; 4 | line-height: 36px; 5 | 6 | &_item { 7 | margin-top: 20px; 8 | } 9 | 10 | .add_wrap { 11 | margin-bottom: 40px; 12 | overflow: hidden; 13 | } 14 | 15 | input { 16 | width: 576px; 17 | float: left; 18 | border: 1px solid #999; 19 | border-right: none; 20 | padding-left: 20px; 21 | } 22 | 23 | .del, 24 | .add { 25 | float: right; 26 | border: 1px solid #999; 27 | padding: 0 25px; 28 | background: #999; 29 | color: #fff; 30 | } 31 | 32 | .add { 33 | float: left; 34 | line-height: 52px; 35 | } 36 | } -------------------------------------------------------------------------------- /todoList-Redux/src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux' 2 | import { ADD, DELETE } from '../constants/todos' 3 | 4 | const INITIAL_STATE = { 5 | todos: [ 6 | {id: 0, text: '第一条todo'} 7 | ] 8 | } 9 | 10 | function todos (state = INITIAL_STATE, action) { 11 | // 获取当前todos条数,用以id自增 12 | let todoNum = state.todos.length 13 | 14 | switch (action.type) { 15 | case ADD: 16 | return { 17 | ...state, 18 | todos: state.todos.concat({ 19 | id: todoNum, 20 | text: action.data 21 | }) 22 | } 23 | case DELETE: 24 | let newTodos = state.todos.filter(item => { 25 | return item.id !== action.data 26 | }) 27 | 28 | return { 29 | ...state, 30 | todos: newTodos 31 | } 32 | default: 33 | return state 34 | } 35 | } 36 | 37 | export default combineReducers({ 38 | todos 39 | }) -------------------------------------------------------------------------------- /todoList-Redux/src/store/index.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from 'redux' 2 | 3 | // 引入需要的中间件 4 | import thunkMiddleware from 'redux-thunk' 5 | import { createLogger } from 'redux-logger' 6 | 7 | // 引入根reducers 8 | import rootReducer from '../reducers' 9 | 10 | const middlewares = [ 11 | thunkMiddleware, 12 | createLogger() 13 | ] 14 | 15 | // 创建store 16 | export default function configStore () { 17 | const store = createStore(rootReducer, applyMiddleware(...middlewares)) 18 | return store 19 | } 20 | -------------------------------------------------------------------------------- /todoList/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /todoList/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["taro"], 3 | "rules": { 4 | "no-unused-vars": ["error", { "varsIgnorePattern": "Taro" }], 5 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx", ".tsx"] }] 6 | }, 7 | "parser": "babel-eslint" 8 | } 9 | -------------------------------------------------------------------------------- /todoList/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | .temp/ 3 | .rn_temp/ 4 | node_modules/ 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /todoList/.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://r.cnpmjs.org 2 | disturl=https://r.cnpmjs.org/node 3 | sass_binary_site=https://r.cnpmjs.org/node-sass/ 4 | fse_binary_host_mirror=https://r.cnpmjs.org/fsevents 5 | -------------------------------------------------------------------------------- /todoList/config/dev.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | NODE_ENV: '"development"' 4 | }, 5 | defineConstants: { 6 | }, 7 | weapp: {}, 8 | h5: {} 9 | } 10 | -------------------------------------------------------------------------------- /todoList/config/index.js: -------------------------------------------------------------------------------- 1 | const config = { 2 | projectName: 'todoList', 3 | date: '2018-11-12', 4 | designWidth: 750, 5 | deviceRatio: { 6 | '640': 2.34 / 2, 7 | '750': 1, 8 | '828': 1.81 / 2 9 | }, 10 | sourceRoot: 'src', 11 | outputRoot: 'dist', 12 | plugins: { 13 | babel: { 14 | sourceMap: true, 15 | presets: [ 16 | 'env' 17 | ], 18 | plugins: [ 19 | 'transform-class-properties', 20 | 'transform-decorators-legacy', 21 | 'transform-object-rest-spread' 22 | ] 23 | } 24 | }, 25 | defineConstants: { 26 | }, 27 | copy: { 28 | patterns: [ 29 | ], 30 | options: { 31 | } 32 | }, 33 | weapp: { 34 | module: { 35 | postcss: { 36 | autoprefixer: { 37 | enable: true 38 | }, 39 | url: { 40 | enable: true, 41 | limit: 10240 42 | } 43 | } 44 | } 45 | }, 46 | h5: { 47 | publicPath: '/', 48 | staticDirectory: 'static', 49 | module: { 50 | postcss: { 51 | autoprefixer: { 52 | enable: true 53 | } 54 | } 55 | } 56 | } 57 | } 58 | 59 | module.exports = function (merge) { 60 | if (process.env.NODE_ENV === 'development') { 61 | return merge({}, config, require('./dev')) 62 | } 63 | return merge({}, config, require('./prod')) 64 | } 65 | -------------------------------------------------------------------------------- /todoList/config/prod.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | NODE_ENV: '"production"' 4 | }, 5 | defineConstants: { 6 | }, 7 | weapp: {}, 8 | h5: {} 9 | } 10 | -------------------------------------------------------------------------------- /todoList/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "todoList", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "todo List", 6 | "scripts": { 7 | "build:weapp": "taro build --type weapp", 8 | "build:swan": "taro build --type swan", 9 | "build:alipay": "taro build --type alipay", 10 | "build:h5": "taro build --type h5", 11 | "build:rn": "taro build --type rn", 12 | "dev:weapp": "npm run build:weapp -- --watch", 13 | "dev:swan": "npm run build:swan -- --watch", 14 | "dev:alipay": "npm run build:alipay -- --watch", 15 | "dev:h5": "npm run build:h5 -- --watch", 16 | "dev:rn": "npm run build:rn -- --watch" 17 | }, 18 | "author": "", 19 | "license": "MIT", 20 | "dependencies": { 21 | "@tarojs/components": "^1.1.4", 22 | "@tarojs/router": "^1.1.4", 23 | "@tarojs/taro": "^1.1.4", 24 | "@tarojs/taro-alipay": "^1.1.4", 25 | "@tarojs/taro-h5": "^1.1.4", 26 | "@tarojs/taro-swan": "^1.1.4", 27 | "@tarojs/taro-weapp": "^1.1.4", 28 | "nervjs": "^1.3.5" 29 | }, 30 | "devDependencies": { 31 | "@types/react": "^16.4.6", 32 | "@types/webpack-env": "^1.13.6", 33 | "@tarojs/plugin-babel": "^1.1.4", 34 | "@tarojs/plugin-csso": "^1.1.4", 35 | "@tarojs/plugin-sass": "^1.1.4", 36 | "@tarojs/plugin-uglifyjs": "^1.1.4", 37 | "@tarojs/webpack-runner": "^1.1.4", 38 | "babel-plugin-transform-class-properties": "^6.24.1", 39 | "babel-plugin-transform-decorators-legacy": "^1.3.4", 40 | "babel-plugin-transform-jsx-stylesheet": "^0.6.5", 41 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 42 | "babel-preset-env": "^1.6.1", 43 | "babel-eslint": "^8.2.3", 44 | "eslint": "^4.19.1", 45 | "eslint-config-taro": "^1.1.4", 46 | "eslint-plugin-react": "^7.8.2", 47 | "eslint-plugin-import": "^2.12.0", 48 | "eslint-plugin-taro": "^1.1.4" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /todoList/project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "miniprogramRoot": "dist/", 3 | "projectname": "todoList_simple", 4 | "description": "todo List", 5 | "appid": "touristappid", 6 | "setting": { 7 | "urlCheck": true, 8 | "es6": false, 9 | "postcss": false, 10 | "minified": false, 11 | "newFeature": true 12 | }, 13 | "compileType": "miniprogram", 14 | "condition": {} 15 | } -------------------------------------------------------------------------------- /todoList/src/app.js: -------------------------------------------------------------------------------- 1 | import Taro, { Component } from '@tarojs/taro' 2 | import Index from './pages/index' 3 | 4 | import './app.scss' 5 | 6 | class App extends Component { 7 | 8 | config = { 9 | pages: [ 10 | 'pages/index/index' 11 | ], 12 | window: { 13 | backgroundTextStyle: 'light', 14 | navigationBarBackgroundColor: '#fff', 15 | navigationBarTitleText: 'WeChat', 16 | navigationBarTextStyle: 'black' 17 | } 18 | } 19 | 20 | componentDidMount () {} 21 | 22 | componentDidShow () {} 23 | 24 | componentDidHide () {} 25 | 26 | componentDidCatchError () {} 27 | 28 | // 在 App 类中的 render() 函数没有实际作用 29 | // 请勿修改此函数 30 | render () { 31 | return ( 32 | 33 | ) 34 | } 35 | } 36 | 37 | Taro.render(, document.getElementById('app')) 38 | -------------------------------------------------------------------------------- /todoList/src/app.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/o2team/taro-ebook-source/ed7772e1921de9e01865d250761bcd302cede18d/todoList/src/app.scss -------------------------------------------------------------------------------- /todoList/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Taro 12 | 15 | 16 | 17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /todoList/src/pages/index/index.js: -------------------------------------------------------------------------------- 1 | import Taro, { Component } from '@tarojs/taro' 2 | import { View, Text, Input } from '@tarojs/components' 3 | import './index.scss' 4 | 5 | export default class Index extends Component { 6 | config = { 7 | navigationBarTitleText: '首页' 8 | } 9 | 10 | constructor (props) { 11 | super (props) 12 | this.state = { 13 | // 创建一个初始的 Todolist 14 | list: [ 15 | 'get up', 16 | 'coding', 17 | 'sleep', 18 | ], 19 | inputVal: '' 20 | } 21 | } 22 | 23 | // ... 生命周期函数,暂时不需要关注 24 | 25 | addItem () { 26 | let { list, inputVal } = this.state 27 | if (inputVal == '') return 28 | list.push(inputVal) 29 | this.setState({ 30 | list, 31 | inputVal: '' 32 | }) 33 | } 34 | 35 | delItem (index) { 36 | let { list } = this.state 37 | list.splice(index, 1) 38 | this.setState({ 39 | list 40 | }) 41 | } 42 | 43 | inputHandler (e) { 44 | this.setState({ inputVal: e.target.value }) 45 | } 46 | 47 | render () { 48 | let { list, inputVal } = this.state 49 | 50 | return ( 51 | 52 | 53 | 添加 54 | 55 | Todo list 56 | { 57 | list.map((item, index) => { 58 | return 59 | {index + 1}.{item} 60 | 删除 61 | 62 | }) 63 | } 64 | 65 | 66 | ) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /todoList/src/pages/index/index.scss: -------------------------------------------------------------------------------- 1 | .input { 2 | display: inline-block; 3 | margin: 20px; 4 | border: 1px solid #666; 5 | width: 500px; 6 | vertical-align: middle; 7 | } 8 | .list_wrap { 9 | padding: 50px 20px; 10 | } 11 | .list { 12 | margin: 20px 0; 13 | } 14 | .add, 15 | .del { 16 | display: inline-block; 17 | width: 120px; 18 | height: 60px; 19 | margin: 0 10px; 20 | padding: 0 10px; 21 | color: #333; 22 | font-size: 22px; 23 | line-height: 60px; 24 | text-align: center; 25 | border-radius: 10px; 26 | border: 1px solid #C5D9E8; 27 | box-sizing: border-box; 28 | overflow: hidden; 29 | text-overflow: ellipsis; 30 | white-space: nowrap; 31 | justify-content: center; 32 | vertical-align: middle; 33 | } 34 | .add { 35 | background-color: #5c89e4; 36 | color: #fff; 37 | border: 1PX solid #5c89e4; 38 | } 39 | .del { 40 | background-color: #fff; 41 | color: #5c89e4; 42 | border: 1PX solid #5c89e4; 43 | margin-left: 100px; 44 | } 45 | --------------------------------------------------------------------------------