├── .swan
└── editor.json
├── src
├── components
│ ├── EIcon
│ │ ├── Eicon.scss
│ │ └── EIcon.tsx
│ ├── ShopList
│ │ ├── ShopList.scss
│ │ └── ShopList.tsx
│ ├── EList
│ │ ├── EList.scss
│ │ ├── index.tsx
│ │ ├── EList.tsx
│ │ ├── EItem.scss
│ │ └── EItem.tsx
│ ├── Test
│ │ └── Test.tsx
│ ├── Card
│ │ ├── Card.scss
│ │ └── Card.tsx
│ ├── EScroll
│ │ ├── EScroll.scss
│ │ └── EScroll.tsx
│ ├── ETransition
│ │ ├── ETransition.scss
│ │ └── ETransition.tsx
│ ├── FooterNav
│ │ ├── images
│ │ │ ├── order_1.svg
│ │ │ ├── profile_1.svg
│ │ │ ├── order_2.svg
│ │ │ ├── profile_2.svg
│ │ │ ├── discover_2.svg
│ │ │ ├── discover_1.svg
│ │ │ ├── msite_2.svg
│ │ │ └── msite_1.svg
│ │ ├── FooterNav.scss
│ │ └── FooterNav.tsx
│ ├── NoDataTip
│ │ ├── NoDataTip.scss
│ │ └── NoDataTip.tsx
│ ├── Star
│ │ ├── Star.scss
│ │ └── Star.tsx
│ ├── ShopButton
│ │ ├── ShopButton.scss
│ │ └── ShopButton.tsx
│ ├── ETabs
│ │ ├── ETabs.scss
│ │ └── ETabs.tsx
│ ├── NavBar
│ │ ├── NavBar.scss
│ │ └── NavBar.tsx
│ ├── EButton
│ │ ├── EButton.tsx
│ │ └── EButton.scss
│ ├── ELoading
│ │ ├── ELoading.tsx
│ │ └── ELoading.scss
│ └── UserAddress
│ │ └── UserAddress.scss
├── pages
│ ├── test
│ │ ├── index.config.ts
│ │ ├── index.scss
│ │ └── index.tsx
│ ├── msite
│ │ ├── components
│ │ │ ├── Tip
│ │ │ │ ├── Tip.scss
│ │ │ │ └── Tip.tsx
│ │ │ ├── MsiteNavBar
│ │ │ │ ├── MsiteNavBar.scss
│ │ │ │ └── MsiteNavBar.tsx
│ │ │ ├── NavSwipe
│ │ │ │ ├── NavSwipe.scss
│ │ │ │ └── NavSwipe.tsx
│ │ │ ├── NavSwipeItem
│ │ │ │ ├── NavSwipeItem.scss
│ │ │ │ └── NavSwipeItem.tsx
│ │ │ ├── Framework
│ │ │ │ ├── Framework.scss
│ │ │ │ └── Framework.tsx
│ │ │ ├── SearchBar
│ │ │ │ ├── SearchBar.scss
│ │ │ │ └── SearchBar.tsx
│ │ │ ├── Svip
│ │ │ │ ├── Svip.tsx
│ │ │ │ └── Svip.scss
│ │ │ └── Advertising
│ │ │ │ ├── Advertising.scss
│ │ │ │ └── Advertising.tsx
│ │ ├── index.config.ts
│ │ └── index.scss
│ ├── profile
│ │ ├── address
│ │ │ ├── add
│ │ │ │ ├── index.scss
│ │ │ │ ├── index.config.ts
│ │ │ │ └── index.tsx
│ │ │ ├── edit
│ │ │ │ ├── index.scss
│ │ │ │ ├── index.config.ts
│ │ │ │ └── index.tsx
│ │ │ ├── index.config.ts
│ │ │ ├── search
│ │ │ │ ├── index.config.ts
│ │ │ │ ├── index.scss
│ │ │ │ └── index.tsx
│ │ │ ├── index.scss
│ │ │ └── components
│ │ │ │ └── AddressRow
│ │ │ │ ├── AddressRow.scss
│ │ │ │ └── AddressRow.tsx
│ │ ├── index.config.ts
│ │ ├── info
│ │ │ ├── index.config.ts
│ │ │ ├── password
│ │ │ │ ├── index.config.ts
│ │ │ │ ├── components
│ │ │ │ │ └── Input
│ │ │ │ │ │ ├── MyInput.scss
│ │ │ │ │ │ └── MyInput.tsx
│ │ │ │ └── index.scss
│ │ │ ├── username
│ │ │ │ ├── index.config.ts
│ │ │ │ ├── index.scss
│ │ │ │ └── index.tsx
│ │ │ └── index.scss
│ │ ├── index.scss
│ │ └── components
│ │ │ ├── Money
│ │ │ ├── Money.scss
│ │ │ └── Money.tsx
│ │ │ └── UserHead
│ │ │ ├── UserHead.tsx
│ │ │ └── UserHead.scss
│ ├── city
│ │ ├── index.config.ts
│ │ ├── index.scss
│ │ └── components
│ │ │ ├── ABC
│ │ │ ├── ABC.scss
│ │ │ └── ABC.tsx
│ │ │ ├── FilterList
│ │ │ ├── FilterList.scss
│ │ │ └── FilterList.tsx
│ │ │ ├── List
│ │ │ ├── List.scss
│ │ │ └── List.tsx
│ │ │ └── Search
│ │ │ ├── Search.scss
│ │ │ └── Search.tsx
│ ├── discover
│ │ ├── index.config.ts
│ │ ├── components
│ │ │ └── Prize
│ │ │ │ ├── Prize.tsx
│ │ │ │ └── Prize.scss
│ │ └── index.scss
│ ├── food
│ │ ├── index.config.ts
│ │ └── index.scss
│ ├── login
│ │ ├── index.config.ts
│ │ └── index.scss
│ ├── order
│ │ ├── index.config.ts
│ │ ├── detail
│ │ │ └── index.config.ts
│ │ ├── index.scss
│ │ ├── components
│ │ │ └── Ordercard
│ │ │ │ ├── Ordercard.scss
│ │ │ │ └── Ordercard.tsx
│ │ └── index.tsx
│ ├── register
│ │ ├── index.config.ts
│ │ └── index.scss
│ ├── search
│ │ ├── index.config.ts
│ │ ├── index.scss
│ │ └── components
│ │ │ ├── Back
│ │ │ ├── Back.scss
│ │ │ └── Back.tsx
│ │ │ ├── SearchBar
│ │ │ ├── SearchBar.scss
│ │ │ └── SearchBar.tsx
│ │ │ └── SearchItem
│ │ │ ├── SearchItem.scss
│ │ │ └── SearchItem.tsx
│ ├── shop
│ │ ├── index.config.ts
│ │ ├── components
│ │ │ ├── LeftBar
│ │ │ │ ├── LeftBar.scss
│ │ │ │ └── LeftBar.tsx
│ │ │ ├── Recommend
│ │ │ │ ├── Recommend.scss
│ │ │ │ └── Recommend.tsx
│ │ │ ├── ActivityModal
│ │ │ │ ├── ActivityModal.scss
│ │ │ │ └── ActivityModal.tsx
│ │ │ ├── ShopItem
│ │ │ │ ├── ShopItem.scss
│ │ │ │ └── ShopItem.tsx
│ │ │ ├── ShopInfo
│ │ │ │ └── ShopInfo.scss
│ │ │ ├── ShopInfoModal
│ │ │ │ ├── ShopInfoModal.scss
│ │ │ │ └── ShopInfoModal.tsx
│ │ │ └── Head
│ │ │ │ ├── Head.tsx
│ │ │ │ └── Head.scss
│ │ └── index.scss
│ ├── address
│ │ ├── index.config.ts
│ │ ├── index.scss
│ │ └── components
│ │ │ ├── Result
│ │ │ ├── Result.scss
│ │ │ └── Result.tsx
│ │ │ ├── ResultItem
│ │ │ ├── ResultItem.scss
│ │ │ └── ResultItem.tsx
│ │ │ ├── AtAddress
│ │ │ ├── AtAddress.scss
│ │ │ └── AtAddress.tsx
│ │ │ ├── Profile
│ │ │ ├── Profile.scss
│ │ │ └── Profile.tsx
│ │ │ └── Search
│ │ │ ├── Search.scss
│ │ │ └── Search.tsx
│ └── clearing
│ │ ├── index.config.ts
│ │ ├── index.scss
│ │ ├── components
│ │ ├── Distribution
│ │ │ ├── Distribution.scss
│ │ │ └── Distribution.tsx
│ │ ├── FooterDic
│ │ │ ├── FooterDic.scss
│ │ │ └── FooterDic.tsx
│ │ ├── CartAddress
│ │ │ ├── CartAddress.scss
│ │ │ └── CartAddress.tsx
│ │ └── CartInfo
│ │ │ ├── CartInfo.scss
│ │ │ └── CartInfo.tsx
│ │ └── index.tsx
├── assets
│ ├── styles
│ │ ├── index.scss
│ │ ├── _mixin.scss
│ │ ├── _variables.scss
│ │ └── normalize.scss
│ ├── iconfont
│ │ ├── iconfont.eot
│ │ ├── iconfont.ttf
│ │ ├── iconfont.woff
│ │ └── iconfont.woff2
│ └── images
│ │ ├── default-head.png
│ │ ├── add.svg
│ │ ├── rec.svg
│ │ ├── red.svg
│ │ ├── gold.svg
│ │ ├── service.svg
│ │ ├── rule.svg
│ │ ├── point.svg
│ │ ├── download.svg
│ │ ├── commend.svg
│ │ ├── address.svg
│ │ ├── xx2.svg
│ │ ├── xx1.svg
│ │ ├── cart2.svg
│ │ ├── cart1.svg
│ │ └── default-shop.svg
├── app.scss
├── redux
│ ├── actions
│ │ ├── cart.ts
│ │ └── user.ts
│ ├── reducers
│ │ ├── index.ts
│ │ ├── cart.ts
│ │ └── user.ts
│ ├── interface.ts
│ ├── action-types
│ │ └── index.ts
│ └── store.ts
├── utils
│ ├── setstylepx.ts
│ ├── distance.ts
│ ├── getDom.ts
│ └── imgUrl.ts
├── config
│ └── base.ts
├── hooks
│ └── useDebounce.tsx
├── app.tsx
├── app.config.ts
├── index.html
└── api
│ └── serve.ts
├── .eslintrc.js
├── .gitignore
├── .editorconfig
├── babel.config.js
├── project.swan.json
├── config
├── prod.js
├── dev.js
└── index.js
├── global.d.ts
├── tsconfig.json
├── project.config.json
├── package.json
└── tatus
/.swan/editor.json:
--------------------------------------------------------------------------------
1 | {}
--------------------------------------------------------------------------------
/src/components/EIcon/Eicon.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/pages/test/index.config.ts:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/pages/msite/components/Tip/Tip.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/pages/profile/address/add/index.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/pages/profile/address/edit/index.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/pages/msite/components/MsiteNavBar/MsiteNavBar.scss:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | 'extends': ['taro/react']
3 | }
4 |
--------------------------------------------------------------------------------
/src/assets/styles/index.scss:
--------------------------------------------------------------------------------
1 | @import 'mixin';
2 | @import 'variables';
3 |
--------------------------------------------------------------------------------
/src/pages/city/index.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | navigationBarTitleText: '选择城市',
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/discover/index.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | navigationBarTitleText: '发现',
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/food/index.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | navigationBarTitleText: '饿了么',
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/login/index.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | navigationBarTitleText: '登录',
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/msite/index.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | navigationBarTitleText: '饿了么',
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/order/index.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | navigationBarTitleText: '订单',
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/profile/index.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | navigationBarTitleText: '我的',
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/register/index.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | navigationBarTitleText: '注册',
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/search/index.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | navigationBarTitleText: '搜索商家',
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/shop/index.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | navigationBarTitleText: '商家详情',
3 | }
4 |
--------------------------------------------------------------------------------
/src/app.scss:
--------------------------------------------------------------------------------
1 | @import './assets/iconfont/iconfont.css';
2 | @import './assets/styles/normalize.scss';
--------------------------------------------------------------------------------
/src/pages/address/index.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | navigationBarTitleText: '选择收货地址',
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/clearing/index.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | navigationBarTitleText: '结算中心',
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/order/detail/index.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | navigationBarTitleText: '订单详情',
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/profile/info/index.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | navigationBarTitleText: '账户信息',
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/profile/address/index.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | navigationBarTitleText: '添加地址',
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
2 | deploy_versions/
3 | .temp/
4 | .rn_temp/
5 | node_modules/
6 | .DS_Store
7 | .history
8 |
--------------------------------------------------------------------------------
/src/components/ShopList/ShopList.scss:
--------------------------------------------------------------------------------
1 | .ele-shoplist-bottom {
2 | @include flex();
3 | height: 80px;
4 | }
5 |
--------------------------------------------------------------------------------
/src/pages/profile/address/add/index.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | navigationBarTitleText: '添加地址',
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/profile/address/edit/index.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | navigationBarTitleText: '编辑地址',
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/profile/address/search/index.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | navigationBarTitleText: '我的地址',
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/profile/info/password/index.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | navigationBarTitleText: '修改密码',
3 | }
4 |
--------------------------------------------------------------------------------
/src/pages/profile/info/username/index.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | navigationBarTitleText: '修改用户名',
3 | }
4 |
--------------------------------------------------------------------------------
/src/assets/iconfont/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qingjuesama/taro-ele/HEAD/src/assets/iconfont/iconfont.eot
--------------------------------------------------------------------------------
/src/assets/iconfont/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qingjuesama/taro-ele/HEAD/src/assets/iconfont/iconfont.ttf
--------------------------------------------------------------------------------
/src/assets/iconfont/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qingjuesama/taro-ele/HEAD/src/assets/iconfont/iconfont.woff
--------------------------------------------------------------------------------
/src/assets/iconfont/iconfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qingjuesama/taro-ele/HEAD/src/assets/iconfont/iconfont.woff2
--------------------------------------------------------------------------------
/src/assets/images/default-head.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qingjuesama/taro-ele/HEAD/src/assets/images/default-head.png
--------------------------------------------------------------------------------
/src/pages/msite/components/NavSwipe/NavSwipe.scss:
--------------------------------------------------------------------------------
1 | .navswiper {
2 | padding-bottom: 20px;
3 | display: flex;
4 | flex-wrap: wrap;
5 | }
6 |
--------------------------------------------------------------------------------
/src/pages/order/index.scss:
--------------------------------------------------------------------------------
1 | .order {
2 | min-height: 100vh;
3 | background: #f5f5f5;
4 | .order-main {
5 | padding-bottom: 150px;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/redux/actions/cart.ts:
--------------------------------------------------------------------------------
1 | import { ADDCART } from '../action-types'
2 |
3 | // 增加商品
4 | export const actionAddCart = food => ({ type: ADDCART, payload: food })
5 |
--------------------------------------------------------------------------------
/src/components/EList/EList.scss:
--------------------------------------------------------------------------------
1 | .ele-elist {
2 | .ele-elist-title {
3 | margin: 25px 0 20px 25px;
4 | font-size: $font-size-24;
5 | color: $color-999;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/pages/search/index.scss:
--------------------------------------------------------------------------------
1 | .search {
2 | padding: 0 20px;
3 | .icon {
4 | padding: 20px 0;
5 | color: $color-999;
6 | font-size: 34px;
7 | font-weight: 600;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/utils/setstylepx.ts:
--------------------------------------------------------------------------------
1 | import Taro from '@tarojs/taro'
2 | import { designWidth } from '../config/base'
3 |
4 | export default (size?: number) => {
5 | return Taro.pxTransform(size, designWidth)
6 | }
7 |
--------------------------------------------------------------------------------
/src/utils/distance.ts:
--------------------------------------------------------------------------------
1 | export default (distance: number): string => {
2 | if (distance > 1000) {
3 | return Math.round(distance / 10) / 100 + 'km'
4 | } else {
5 | return distance + 'm'
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/pages/city/index.scss:
--------------------------------------------------------------------------------
1 | .selectcity {
2 | background: #fff;
3 | -webkit-overflow-scrolling: touch; //ios不流畅问题
4 | }
5 | .city-show {
6 | display: block;
7 | }
8 | .city-hide {
9 | display: none;
10 | }
11 |
--------------------------------------------------------------------------------
/src/redux/reducers/index.ts:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux'
2 | import user from './user'
3 | import cart from './cart'
4 |
5 | export default combineReducers({
6 | ...user,
7 | ...cart,
8 | })
9 |
10 |
--------------------------------------------------------------------------------
/src/components/Test/Test.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { View } from '@tarojs/components'
3 |
4 | const Test = (test) => {
5 | if (test) {
6 | return null
7 | }
8 | return 1
9 | }
10 | export default Test
11 |
--------------------------------------------------------------------------------
/src/components/Card/Card.scss:
--------------------------------------------------------------------------------
1 | .card {
2 | margin-bottom: 20px;
3 | padding: 30px;
4 | background: #fff;
5 | .card-title {
6 | padding-bottom: 20px;
7 | color: #000;
8 | font-size: 30px;
9 | font-weight: 600;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/components/EScroll/EScroll.scss:
--------------------------------------------------------------------------------
1 | .escroll {
2 | flex: 1;
3 | overflow: hidden;
4 | .scroll-box {
5 | height: 100%;
6 | display: flex;
7 | flex-direction: column;
8 | -webkit-overflow-scrolling: touch; //ios不流畅问题
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/config/base.ts:
--------------------------------------------------------------------------------
1 | export const H5 = process.env.TARO_ENV === 'h5'
2 | export const WEAPP = process.env.TARO_ENV === 'weapp'
3 | export const designWidth = '750'
4 | export const defaultImg =
5 | 'https://cube.elemecdn.com/a/7c/a7e9e5aa15b1b8fc6f1bece8ee385jpeg.jpeg'
6 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | // babel-preset-taro 更多选项和默认值:
2 | // https://github.com/NervJS/taro/blob/next/packages/babel-preset-taro/README.md
3 | module.exports = {
4 | presets: [
5 | ['taro', {
6 | framework: 'react',
7 | ts: true
8 | }]
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/src/pages/clearing/index.scss:
--------------------------------------------------------------------------------
1 | .clearing {
2 | min-height: 100vh;
3 | background-image: linear-gradient(
4 | 0deg,
5 | #f5f5f5,
6 | #f5f5f5 65%,
7 | hsla(0, 0%, 96%, .3) 75%,
8 | hsla(0, 0%, 96%, 0)
9 | ),
10 | linear-gradient(270deg, #0085ff, #0af);
11 | }
12 |
--------------------------------------------------------------------------------
/src/pages/city/components/ABC/ABC.scss:
--------------------------------------------------------------------------------
1 | .selectcity-main-content-abc {
2 | position: fixed;
3 | right: 20px;
4 | top: 240px;
5 | .selectcity-main-content-abc-item {
6 | text-align: center;
7 | color: #9d9d9d;
8 | margin: 4px;
9 | font-size: 24px;
10 | }
11 | }
--------------------------------------------------------------------------------
/project.swan.json:
--------------------------------------------------------------------------------
1 | {
2 | "host": "baiduboxapp",
3 | "setting": {
4 | "urlCheck": true
5 | },
6 | "swan": {
7 | "baiduboxapp": {
8 | "swanJsVersion": "3.190.255-rc",
9 | "extensionJsVersion": "100.14.255"
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/src/pages/test/index.scss:
--------------------------------------------------------------------------------
1 | .test {
2 | background: #eeeeee;
3 | margin-top: 20px;
4 | height: 500px;
5 | }
6 | .abc {
7 | position: fixed;
8 | top: 0;
9 | right: 0;
10 | .abc-item {
11 | background: red;
12 | color: #fff;
13 | padding: 10px;
14 | margin: 10px;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/pages/profile/index.scss:
--------------------------------------------------------------------------------
1 | .profile {
2 | background: #f5f5f5;
3 | height: 100vh;
4 |
5 | .profile-block {
6 | margin-top: 20px;
7 | }
8 | .profile-privacy {
9 | color: #4da6f0;
10 | text-align: center;
11 | padding: 30px 0;
12 | }
13 | .profile-list {
14 | padding-top: 25px;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/components/ETransition/ETransition.scss:
--------------------------------------------------------------------------------
1 | @include ele-animation('top', scaleY(0), scaleY(1), center top);
2 | @include ele-animation('left', scale(0.45, 0.45), scale(1, 1), top left);
3 | @include ele-animation('right', scale(0.45, 0.45), scale(1, 1), top right);
4 | @include ele-animation('bottom', scaleY(0), scaleY(1), center bottom);
5 |
--------------------------------------------------------------------------------
/src/pages/address/index.scss:
--------------------------------------------------------------------------------
1 | .selectaddress {
2 | height: 100vh;
3 | background: #f4f4f4;
4 | color: #333;
5 | -webkit-overflow-scrolling: touch; //ios不流畅问题
6 | }
7 | .start {
8 | transform: translateX(100vw);
9 | }
10 | .end {
11 | transform: translateX(0);
12 | }
13 | .add {
14 | position: absolute;
15 | right: 20px;
16 | top: 24px;
17 | }
18 |
--------------------------------------------------------------------------------
/src/components/EList/index.tsx:
--------------------------------------------------------------------------------
1 | import { FC } from 'react'
2 |
3 | import EList, { EListProps } from './EList'
4 | import EItem, { EItemProps } from './EItem'
5 |
6 | type TransListProps = FC & {
7 | EItem: FC
8 | }
9 |
10 | const TransList = EList as TransListProps
11 |
12 | TransList.EItem = EItem
13 |
14 | export default TransList
15 |
--------------------------------------------------------------------------------
/src/pages/food/index.scss:
--------------------------------------------------------------------------------
1 | .food {
2 | height: 100vh;
3 | .food-topbar {
4 | position: sticky;
5 | top: 0;
6 | z-index: 3;
7 | }
8 | .food-shoplist {
9 | height: calc(100vh - 160px);
10 | -webkit-overflow-scrolling: touch; // ios
11 | }
12 | .food-filterbar {
13 | top: 80px;
14 | }
15 | .no-page {
16 | top: 0;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/utils/getDom.ts:
--------------------------------------------------------------------------------
1 | import Taro from '@tarojs/taro'
2 |
3 | export default (nodeName: string) => {
4 | return new Promise((resolve) => {
5 | const query = Taro.createSelectorQuery()
6 | query.selectAll(nodeName).boundingClientRect()
7 | query.selectViewport().scrollOffset()
8 | query.exec((res) => {
9 | resolve(res)
10 | })
11 | })
12 | }
13 |
--------------------------------------------------------------------------------
/src/redux/interface.ts:
--------------------------------------------------------------------------------
1 | export interface Address {
2 | id: string
3 | city: string
4 | address: string
5 | address_detail: string
6 | latitude: string
7 | longitude: string
8 | name: string
9 | phone: string
10 | sex: string
11 | }
12 |
13 | export interface Reducers {
14 | currentAddress: Address
15 | userAddress: Address
16 | userAddressList: Address[]
17 | token: string
18 | }
19 |
--------------------------------------------------------------------------------
/src/components/FooterNav/images/order_1.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/NoDataTip/NoDataTip.scss:
--------------------------------------------------------------------------------
1 | .ele-nodatatipo {
2 | @include flex;
3 | flex-direction: column;
4 | padding-bottom: 20px;
5 | .ele-nodatatipo-img {
6 | width: 420px;
7 | }
8 | .ele-nodatatipo-title {
9 | font-size: $font-size-34;
10 | padding-bottom: 20px;
11 | }
12 | .ele-nodatatipo-info {
13 | font-size: $font-size-24;
14 | color: $color-999;
15 | padding-bottom: 20px;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/components/Star/Star.scss:
--------------------------------------------------------------------------------
1 | .star {
2 | position: relative;
3 | width: 120px;
4 | height: 25px;
5 | .star1 {
6 | position: absolute;
7 | width: 100%;
8 | height: 100%;
9 | background: url('../../assets/images/xx2.svg') no-repeat;
10 | }
11 | .star2 {
12 | position: absolute;
13 | width: 100%;
14 | height: 100%;
15 | background: url('../../assets/images/xx1.svg') no-repeat;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/config/prod.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | NODE_ENV: '"production"'
4 | },
5 | defineConstants: {
6 | },
7 | mini: {},
8 | h5: {
9 | /**
10 | * 如果h5端编译后体积过大,可以使用webpack-bundle-analyzer插件对打包体积进行分析。
11 | * 参考代码如下:
12 | * webpackChain (chain) {
13 | * chain.plugin('analyzer')
14 | * .use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin, [])
15 | * }
16 | */
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/config/dev.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | module.exports = {
4 | env: {
5 | NODE_ENV: '"production"', // production development
6 | },
7 | defineConstants: {},
8 | mini: {},
9 | h5: {
10 | devServer: {
11 | port: 3000,
12 | proxy: {
13 | '/api': {
14 | target: 'http://localhost:4000',
15 | // pathRewrite: { '^/api': '' },
16 | },
17 | },
18 | },
19 | },
20 | }
21 |
--------------------------------------------------------------------------------
/src/pages/profile/info/password/components/Input/MyInput.scss:
--------------------------------------------------------------------------------
1 | .myinput {
2 | .password-input {
3 | background: #f2f2f2;
4 | display: flex;
5 | border: 1px #ececec solid;
6 | height: 80px;
7 | align-items: center;
8 | padding-left: 10px;
9 | }
10 | .password-error {
11 | border: 1px #f0937e solid;
12 | }
13 | .password-tip {
14 | color: #ea3106;
15 | font-size: 24px;
16 | padding-top: 10px;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/components/ShopButton/ShopButton.scss:
--------------------------------------------------------------------------------
1 | .shopbutton {
2 | display: flex;
3 | align-items: center;
4 | .shopbutton-rec {
5 | .icon {
6 | color: #2395ff;
7 | font-size: 42px;
8 | }
9 | }
10 |
11 | .shopbutton-num {
12 | padding: 0 15px;
13 | color: #3f3f3f;
14 | }
15 |
16 | .shopbutton-add {
17 | overflow: hidden;
18 | .icon {
19 | color: #2395ff;
20 | font-size: 42px;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/components/FooterNav/images/profile_1.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/pages/clearing/components/Distribution/Distribution.scss:
--------------------------------------------------------------------------------
1 | .distribution {
2 | margin: 20px;
3 | padding: 10px 20px;
4 | background: #fff;
5 | .distribution-row {
6 | display: flex;
7 | justify-content: space-between;
8 | padding: 20px 0;
9 | &:first-child {
10 | border-bottom: 1px #f8f8f8 solid;
11 | }
12 | .row-left {
13 | color: #333;
14 | }
15 |
16 | .row-right {
17 | color: #2395ff;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/assets/images/add.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/pages/address/components/Result/Result.scss:
--------------------------------------------------------------------------------
1 | // 搜索地址
2 | .search-result {
3 | background: #fff;
4 | .search-main-tip {
5 | color: #999;
6 | padding-top: 50px;
7 | padding-bottom: 150px;
8 | display: flex;
9 | flex-direction: column;
10 | align-items: center;
11 | .tip-title {
12 | font-size: 30px;
13 | padding: 20px 0;
14 | }
15 | }
16 | }
17 | .search-show {
18 | display: block;
19 | }
20 | .search-hide {
21 | display: none;
22 | }
23 |
--------------------------------------------------------------------------------
/src/hooks/useDebounce.tsx:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react'
2 |
3 | const useDebounce = (value: any, delay: number = 300) => {
4 | const [debounceValue, setDebounceValue] = useState(value)
5 |
6 | useEffect(() => {
7 | const handle = setTimeout(() => {
8 | setDebounceValue(value)
9 | })
10 |
11 | return () => {
12 | clearTimeout(handle)
13 | }
14 | }, [value, delay])
15 |
16 | return debounceValue
17 | }
18 |
19 | export default useDebounce
20 |
--------------------------------------------------------------------------------
/src/pages/msite/components/NavSwipeItem/NavSwipeItem.scss:
--------------------------------------------------------------------------------
1 | .navswiper-item {
2 | @include flex;
3 | flex-direction: column;
4 | width: 20%;
5 | padding-top: 20px;
6 | .navswiper-item-image {
7 | display: flex;
8 | justify-content: center;
9 | width: 100%;
10 | .nav-image {
11 | width: 90px;
12 | height: 90px;
13 | }
14 | }
15 | .navswiper-item-title {
16 | color: $color-666;
17 | font-size: 24px;
18 | text-align: center;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/global.d.ts:
--------------------------------------------------------------------------------
1 | declare module "*.png";
2 | declare module "*.gif";
3 | declare module "*.jpg";
4 | declare module "*.jpeg";
5 | declare module "*.svg";
6 | declare module "*.css";
7 | declare module "*.less";
8 | declare module "*.scss";
9 | declare module "*.sass";
10 | declare module "*.styl";
11 |
12 | // @ts-ignore
13 | declare const process: {
14 | env: {
15 | TARO_ENV: 'weapp' | 'swan' | 'alipay' | 'h5' | 'rn' | 'tt' | 'quickapp' | 'qq' | 'jd';
16 | [key: string]: any;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/assets/images/rec.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/pages/msite/index.scss:
--------------------------------------------------------------------------------
1 | .msite {
2 | height: 100%;
3 | flex: 1;
4 | display: flex;
5 | flex-direction: column;
6 |
7 | .msite-navbar {
8 | padding: 20px 20px 0 20px;
9 | height: 69px;
10 | .msite-navbar-title {
11 | padding: 0 10px;
12 | font-size: $font-size-34;
13 | color: $white-color;
14 | font-weight: $font-weight;
15 | max-width: 40vw;
16 | }
17 | }
18 | .nologin {
19 | padding: 50px 0;
20 | }
21 | .msite-filter {
22 | top: 110px;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/FooterNav/images/order_2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/images/red.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/pages/city/components/FilterList/FilterList.scss:
--------------------------------------------------------------------------------
1 | // 城市搜索结果
2 | .result-city {
3 | margin-left: 20px;
4 | height: 100vh;
5 | -webkit-overflow-scrolling: touch; //ios不流畅问题
6 | .result-city-item {
7 | padding: 25px 0;
8 | border-bottom: 1px #eee solid;
9 | color: #666;
10 | font-size: 24px;
11 | &:last-of-type {
12 | border: none;
13 | }
14 | }
15 | .result-city-null {
16 | display: flex;
17 | justify-content: center;
18 | align-items: center;
19 | padding: 100px 0;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/assets/images/gold.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/src/assets/images/service.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/assets/images/rule.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/pages/city/components/List/List.scss:
--------------------------------------------------------------------------------
1 | // 左侧列表
2 | .selectcity-main-content-city {
3 | -webkit-overflow-scrolling: touch; //ios不流畅问题
4 | height: 100vh;
5 | .selectcity-main-content-city-item {
6 | .selectcity-main-content-city-a {
7 | background: #f5f5f5;
8 | padding: 20px;
9 | color: #666;
10 | border-bottom: 1px #eee solid;
11 | }
12 |
13 | .selectcity-main-content-city-name {
14 | color: #333;
15 | margin: 0 20px;
16 | padding: 20px 0;
17 | border-bottom: 1px #f5f5f5 solid;
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/pages/msite/components/Framework/Framework.scss:
--------------------------------------------------------------------------------
1 | .framework {
2 | display: flex;
3 | flex-wrap: wrap;
4 | .framework-item {
5 | @include flex;
6 | flex-direction: column;
7 | width: 20%;
8 | padding-top: 20px;
9 | .framework-item-title {
10 | width: 90px;
11 | height: 90px;
12 | background: $background-f5f5f5;
13 | border-radius: 50%;
14 | }
15 | .framework-item-txt {
16 | width: 80px;
17 | height: 25px;
18 | margin-top: 15px;
19 | background: $background-f5f5f5;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/pages/msite/components/SearchBar/SearchBar.scss:
--------------------------------------------------------------------------------
1 | $main-height: 72px;
2 |
3 | .searchbar {
4 | @include flex;
5 | background-image: $defualt-background-image;
6 | padding: 20px 26px;
7 | position: sticky;
8 | top: -1px;
9 | z-index: 9;
10 | .searchbar-main {
11 | background: $white-color;
12 | width: 100%;
13 | height: $main-height;
14 | line-height: $main-height;
15 | text-align: center;
16 | .searchbar-icon {
17 | padding-right: 10px;
18 | }
19 | .searchbar-title {
20 | color: $color-999;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/redux/reducers/cart.ts:
--------------------------------------------------------------------------------
1 | import { ADDCART } from '../action-types'
2 |
3 | const initCart = {
4 | totalPrice: 0, // (现)总价
5 | originalPrice: 0, // (原)总价
6 | boxPrice: 0, // 餐盒费
7 | foodTotal: 0, // 总数量
8 | foods: [],
9 | }
10 | const cart = (state = initCart, action) => {
11 | const { type, payload } = action
12 | switch (type) {
13 | case ADDCART:
14 | const index = state.foods.findIndex()
15 | state.foods.push(payload)
16 | return { ...state }
17 | default:
18 | return state
19 | }
20 | }
21 |
22 | export default { cart }
23 |
--------------------------------------------------------------------------------
/src/redux/action-types/index.ts:
--------------------------------------------------------------------------------
1 | export const CURRENTADDRESS = 'CURRENTADDRESS' // 定位信息
2 | export const SETTOKEN = 'SETTOKEN' // 设置token
3 | export const REMOVETOKEN = 'REMOVETOKEN' // 删除token
4 | export const USERADDRESS = 'USERADDRESS' // 用户当前编辑地址信息
5 | export const SETUSERADDRESS = 'SETUSERADDRESS' // 更新当前用户地址信息
6 | export const REMOVEUSERADDRESS = 'REMOVEUSERADDRESS' // 清空用户地址信息
7 | export const GETUSERADDRESSLIST = 'GETUSERADDRESSLIST' // 获取用户收货地址列表
8 | export const REMOVEUSERADDRESSLIST = 'REMOVEUSERADDRESSLIST' // 清空用户收货地址列表
9 | export const ADDCART = 'ADDCART' // 增加购物车商品
10 |
--------------------------------------------------------------------------------
/src/components/FooterNav/images/profile_2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/utils/imgUrl.ts:
--------------------------------------------------------------------------------
1 | // 处理图片地址
2 | export default (url: string): string => {
3 | const BASEURL = 'https://cube.elemecdn.com/'
4 | let types = ['jpeg', 'jpg', 'png', 'gif', 'JPEG']
5 | let str = ''
6 | let type = ''
7 |
8 | for (let i = 0; i < url.length; i++) {
9 | if (i === 1) {
10 | str += '/'
11 | } else if (i === 3) {
12 | str += '/'
13 | }
14 | str += url[i]
15 | }
16 |
17 | for (let i = 0; i < types.length; i++) {
18 | if (url.includes(types[i])) {
19 | type = types[i]
20 | }
21 | }
22 |
23 | return BASEURL + str + '.' + type
24 | }
25 |
--------------------------------------------------------------------------------
/src/pages/address/components/ResultItem/ResultItem.scss:
--------------------------------------------------------------------------------
1 | .search-result-item {
2 | padding: 30px 20px;
3 | border-bottom: 1px #eee solid;
4 | &:last-of-type {
5 | border: none;
6 | }
7 | .search-result-item-top {
8 | display: flex;
9 | justify-content: space-between;
10 | .search-result-top-name {
11 | font-weight: 600;
12 | color: #333;
13 | font-size: 30px;
14 | }
15 |
16 | .search-result-item-top-distance {
17 | font-size: 24px;
18 | }
19 | }
20 |
21 | .search-result-item-address {
22 | font-size: 24px;
23 | color: #333;
24 | }
25 | }
--------------------------------------------------------------------------------
/src/assets/images/point.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/components/Star/Star.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View } from '@tarojs/components'
3 |
4 | import './Star.scss'
5 |
6 | interface StarProps {
7 | rating: number
8 | }
9 |
10 | const Star: FC = (props) => {
11 | const { rating } = props
12 |
13 | // 计算评分⭐⭐
14 | const countGrade = (): string => {
15 | return (rating / 5) * 100 + '%'
16 | }
17 |
18 | return (
19 |
20 |
21 |
22 |
23 | )
24 | }
25 |
26 | export default Star
27 |
--------------------------------------------------------------------------------
/src/components/ETabs/ETabs.scss:
--------------------------------------------------------------------------------
1 | .tabs {
2 | .tabs-bar {
3 | position: sticky;
4 | top: 0;
5 | z-index: 1;
6 | background: #fff;
7 | border-bottom: 1px #f5f5f5 solid;
8 | display: flex;
9 | .tabs-bar-item {
10 | width: 33.33%;
11 | text-align: center;
12 | padding: 15px 0;
13 | .tabs-bar-item-title {
14 | color: #666;
15 | font-size: 30px;
16 | }
17 | .tabs-active {
18 | font-weight: 600;
19 | border-bottom: 4px #2291f8 solid;
20 | color: #333 !important;
21 | padding-bottom: 15px;
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/assets/images/download.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/pages/profile/info/password/index.scss:
--------------------------------------------------------------------------------
1 | .password {
2 | height: 100vh;
3 | background: #f5f5f5;
4 | .passowrd-main {
5 | background: #ffffff;
6 | padding: 0 20px 20px 20px;
7 | .passowrd-item {
8 | margin-top: 20px;
9 | }
10 | }
11 | .password-button-main {
12 | margin: 20px;
13 | .password-button {
14 | background: #3199e8;
15 | color: #fff;
16 | font-weight: 600;
17 | &:active {
18 | background: #62bbff;
19 | }
20 | &::after {
21 | border: none;
22 | }
23 | }
24 | .password-button[disabled] {
25 | background: #cccccc;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/pages/search/components/Back/Back.scss:
--------------------------------------------------------------------------------
1 | .back {
2 | margin: 20px 0 30px 0;
3 | .head {
4 | display: flex;
5 | align-items: center;
6 | justify-content: space-between;
7 | .title {
8 | color: $color-666;
9 | font-size: 32px;
10 | font-weight: 600;
11 | padding-bottom: 20px;
12 | }
13 |
14 | .icon {
15 | color: #cecece;
16 | font-size: 24px;
17 | }
18 | }
19 |
20 | .tabs {
21 | display: flex;
22 | flex-wrap: wrap;
23 | .tab {
24 | margin: 10px 20px 10px 0;
25 | padding: 16px 20px;
26 | background: #f7f7f7;
27 | color: $color-666;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/app.tsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react'
2 | import { Provider } from 'react-redux'
3 | import configStore from './redux/store'
4 | import { initCurrentAddress } from './redux/actions/user'
5 |
6 | import './app.scss'
7 |
8 | const store = configStore()
9 |
10 | const App = (props) => {
11 | useEffect(() => {
12 | // 获取ip地址 经纬度
13 | const { currentAddress } = store.getState()
14 | if (!currentAddress.latitude && !currentAddress.longitude) {
15 | store.dispatch(initCurrentAddress())
16 | }
17 | }, [])
18 |
19 | // 请勿修改此函数
20 | return {props.children}
21 | }
22 |
23 | export default App
24 |
--------------------------------------------------------------------------------
/src/components/FooterNav/images/discover_2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/pages/profile/address/index.scss:
--------------------------------------------------------------------------------
1 | .profileaddress {
2 | background: #f5f5f5;
3 | height: 100vh;
4 | .profileaddress-list {
5 | margin-bottom: 100px;
6 | }
7 | .profileaddress-add {
8 | position: fixed;
9 | bottom: 0;
10 | left: 0;
11 | right: 0;
12 | border-top: 1px #ddd solid;
13 | background: #fff;
14 | display: flex;
15 | align-items: center;
16 | justify-content: center;
17 | height: 100px;
18 | color: #3190e8;
19 | .profileaddress-add-text {
20 | font-size: 32px;
21 | padding-left: 10px;
22 | }
23 | .icon {
24 | font-size: 40px;
25 | margin-top: 4px;
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/pages/city/components/Search/Search.scss:
--------------------------------------------------------------------------------
1 | // 搜索
2 | .selectcity-search {
3 | background-image: $defualt-background-image;
4 | overflow: hidden;
5 | .selectcity-search-main {
6 | background: #fff;
7 | border-radius: 50px;
8 | display: flex;
9 | align-items: center;
10 | margin: 20px 50px;
11 | .selectcity-search-icon {
12 | margin: 0 10px 0 20px;
13 | .icon {
14 | font-size: 25px;
15 | }
16 | }
17 | .selectcity-search-input {
18 | width: 500px;
19 | font-size: 24px;
20 | padding: 10px 0;
21 | .selectcity-search-input-content {
22 | width: 500px;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/components/EList/EList.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import classnames from 'classnames'
3 | import { View } from '@tarojs/components'
4 |
5 | import './EList.scss'
6 |
7 | export interface EListProps {
8 | children: React.ReactNode
9 | renderHeader?: () => React.ReactNode
10 | className?: string
11 | }
12 |
13 | const EList: FC = (props) => {
14 | const { renderHeader, children, className } = props
15 | const classes = classnames('ele-elist', className)
16 | return (
17 |
18 | {renderHeader && {renderHeader()}}
19 | {children}
20 |
21 | )
22 | }
23 | export default EList
24 |
--------------------------------------------------------------------------------
/src/components/Card/Card.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View } from '@tarojs/components'
3 | import classnames from 'classnames'
4 |
5 | import './Card.scss'
6 |
7 | interface CardProps {
8 | title?: string
9 | children?: React.ReactNode
10 | className?: string
11 | style?: React.CSSProperties
12 | }
13 |
14 | const Card: FC = (props) => {
15 | const { title, children, className, style } = props
16 | const classes = classnames('card', className)
17 | return (
18 |
19 | {title && {title}}
20 | {children}
21 |
22 | )
23 | }
24 |
25 | export default Card
26 |
--------------------------------------------------------------------------------
/src/pages/msite/components/Framework/Framework.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { View } from '@tarojs/components'
3 |
4 | import './Framework.scss'
5 |
6 | const framework = Array(10).fill(1)
7 |
8 | const Framework = () => {
9 | return (
10 |
11 |
12 | {framework.map((item, i) => {
13 | return (
14 |
15 |
16 |
17 |
18 | )
19 | })}
20 |
21 |
22 | )
23 | }
24 |
25 | export default Framework
26 |
--------------------------------------------------------------------------------
/src/pages/search/components/SearchBar/SearchBar.scss:
--------------------------------------------------------------------------------
1 | .mysearch {
2 | display: flex;
3 | align-items: center;
4 | justify-content: space-between;
5 | position: relative;
6 | padding: 30px 0;
7 | .zoom {
8 | position: absolute;
9 | left: 20px;
10 | color: $color-999;
11 | font-size: 24px;
12 | }
13 | .clear {
14 | position: absolute;
15 | right: 100px;
16 | color: $color-999;
17 | font-size: 24px;
18 | }
19 |
20 | .mysearch-input {
21 | flex: 1;
22 | padding: 8px 0;
23 | padding: 10px 70px;
24 | background: #f8f8f8;
25 | }
26 |
27 | .mysearch-text {
28 | padding-left: 20px;
29 | color: $color-333;
30 | font-size: 32px;
31 | font-weight: 700;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/pages/msite/components/Svip/Svip.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View, Image } from '@tarojs/components'
3 |
4 | import './Svip.scss'
5 |
6 | const Svip: FC = () => {
7 | return (
8 |
9 |
10 |
11 |
15 |
16 | 超级会员
17 | 每月领20元红包
18 |
19 | 限时6元开通
20 |
21 | )
22 | }
23 |
24 | export default Svip
25 |
--------------------------------------------------------------------------------
/src/pages/discover/components/Prize/Prize.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { View, Image } from '@tarojs/components'
3 |
4 | import './Prize.scss'
5 |
6 | const Prize = ({ suggest }) => {
7 | return (
8 |
9 | {suggest.corner_marker}
10 |
11 |
12 | {suggest.title}
13 |
14 | {suggest.points_required}金币
15 | ¥{suggest.original_price}
16 |
17 |
18 |
19 | )
20 | }
21 |
22 | export default Prize
23 |
--------------------------------------------------------------------------------
/src/pages/city/components/ABC/ABC.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View } from '@tarojs/components'
3 |
4 | import './ABC.scss'
5 |
6 | interface ABCProps {
7 | alphabet: string[]
8 | onLinkCity: (alp: string) => void
9 | }
10 |
11 | const ABC: FC = (props) => {
12 | const { alphabet, onLinkCity } = props
13 | return (
14 |
15 | {alphabet.map((alp) => {
16 | return (
17 | onLinkCity(alp)}
21 | >
22 | {alp}
23 |
24 | )
25 | })}
26 |
27 | )
28 | }
29 |
30 | export default ABC
31 |
--------------------------------------------------------------------------------
/src/assets/images/commend.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/pages/msite/components/Advertising/Advertising.scss:
--------------------------------------------------------------------------------
1 | $kf-color: #af8260;
2 |
3 | .advertising {
4 | display: flex;
5 | justify-content: space-between;
6 | margin: 20px 20px 0 20px;
7 | padding: 10px 30px;
8 | background: $background-f5f5f5;
9 | line-height: 1.2;
10 | .advertising-left {
11 | padding-top: 20px;
12 | .title {
13 | font-size: 32px;
14 | font-weight: 600;
15 | }
16 |
17 | .detail {
18 | padding: 10px 0;
19 | color: $color-777;
20 | }
21 |
22 | .href {
23 | padding: 10px 0 0 0;
24 | color: $kf-color;
25 | }
26 | }
27 |
28 | .advertising-right {
29 | width: 282px;
30 | height: 188px;
31 | .image {
32 | width: 100%;
33 | height: 100%;
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/pages/profile/components/Money/Money.scss:
--------------------------------------------------------------------------------
1 | .money {
2 | display: flex;
3 | height: 150px;
4 | background: #fff;
5 | .money-red {
6 | width: 50%;
7 | display: flex;
8 | justify-content: center;
9 | flex-direction: column;
10 | align-items: center;
11 | border-right: 1px #f0f0f0 solid;
12 | &:last-child {
13 | border: none;
14 | }
15 | .money-imgs {
16 | width: 48px;
17 | height: 48px;
18 | .money-image {
19 | width: 100%;
20 | height: 100%;
21 | }
22 | }
23 | }
24 |
25 | .money-gold {
26 | width: 50%;
27 | .money-imgs {
28 | width: 48px;
29 | height: 48px;
30 | .money-image {
31 | width: 100%;
32 | height: 100%;
33 | }
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/assets/images/address.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/pages/clearing/components/FooterDic/FooterDic.scss:
--------------------------------------------------------------------------------
1 | .footerdic {
2 | display: flex;
3 | align-items: center;
4 | position: fixed;
5 | right: 0;
6 | bottom: 0;
7 | left: 0;
8 | height: 80px;
9 | background: #3c3c3c;
10 | .footerdic-price {
11 | padding-left: 10px;
12 | color: #fff;
13 | font-size: 36px;
14 | font-weight: 600;
15 | }
16 |
17 | .footerdic-discounts {
18 | color: #999;
19 | font-size: 24px;
20 | }
21 |
22 | .footerdic-submit {
23 | position: absolute;
24 | right: 0;
25 | bottom: 0;
26 | width: 210px;
27 | height: 100%;
28 | border: none;
29 | background: #00e067;
30 | color: #fff;
31 | font-size: 34px;
32 | line-height: 80px;
33 | text-align: center;
34 | border-radius: 0;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/pages/shop/components/LeftBar/LeftBar.scss:
--------------------------------------------------------------------------------
1 | .leftbar {
2 | display: flex;
3 | align-items: center;
4 | position: relative;
5 | padding: 30px 15px;
6 | background: #f8f8f8;
7 | .leftbar-icon {
8 | width: 26px;
9 | height: 26px;
10 | margin-right: 10px;
11 | }
12 | .leftbar-name {
13 | color: #666;
14 | font-size: 24px;
15 | }
16 |
17 | .leftbar-num {
18 | position: absolute;
19 | top: 5px;
20 | right: 10px;
21 | height: 25px;
22 | padding: 0 7px;
23 | background-image: linear-gradient(-90deg, #ff7416, #ff3c15 98%);
24 | color: #fff;
25 | font-size: 24px;
26 | line-height: 25px;
27 | border-radius: 15px;
28 | }
29 | }
30 | .leftbar-active {
31 | background: #fff;
32 | .leftbar-name {
33 | color: #000;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/components/EScroll/EScroll.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View, ScrollView } from '@tarojs/components'
3 | import { ScrollViewProps } from '@tarojs/components/types/ScrollView'
4 | import classnames from 'classnames'
5 |
6 | import './EScroll.scss'
7 |
8 | interface EScrollProps extends ScrollViewProps {
9 | className?: string
10 | id?: string
11 | children: React.ReactNode
12 | }
13 |
14 | const EScroll: FC = (props) => {
15 | const { className, id, children, ...reset } = props
16 | const classes = classnames('scroll-box', className)
17 | return (
18 |
19 |
20 | {children}
21 |
22 |
23 | )
24 | }
25 |
26 | export default EScroll
27 |
--------------------------------------------------------------------------------
/src/components/FooterNav/images/discover_1.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/pages/clearing/components/FooterDic/FooterDic.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View } from '@tarojs/components'
3 |
4 | import './FooterDic.scss'
5 |
6 | interface FooterDicProps {
7 | totalPrice
8 | discountsPrice
9 | onPay
10 | payLoading
11 | }
12 |
13 | const FooterDic: FC = (props) => {
14 | const { totalPrice, discountsPrice, onPay, payLoading } = props
15 | return (
16 |
17 | ¥{totalPrice}
18 |
19 | |已优惠¥
20 | {discountsPrice}
21 |
22 |
23 | {payLoading ? '正在支付...' : '去支付'}
24 |
25 |
26 | )
27 | }
28 |
29 | export default FooterDic
30 |
--------------------------------------------------------------------------------
/src/pages/shop/components/Recommend/Recommend.scss:
--------------------------------------------------------------------------------
1 | .recommend {
2 | display: inline-block;
3 | width: 250px;
4 | margin-right: 30px;
5 | .recommend-img {
6 | width: 250px;
7 | height: 250px;
8 | border-radius: 10px;
9 | }
10 |
11 | .recommend-main {
12 | .recommend-main-title {
13 | text-overflow: ellipsis;
14 | white-space: nowrap;
15 | overflow: hidden;
16 | }
17 |
18 | .recommend-main-pingjia {
19 | font-size: 24px;
20 | color: #999;
21 | }
22 |
23 | .recommend-main-numpice {
24 | display: flex;
25 | justify-content: space-between;
26 | .recommend-main-numpice-price {
27 | color: #ff5339;
28 | font-size: 36px;
29 | .price-fuhao {
30 | font-size: 24px;
31 | }
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/pages/profile/info/index.scss:
--------------------------------------------------------------------------------
1 | .profileinfo {
2 | color: #333;
3 | background: #f5f5f5;
4 | height: 100vh;
5 | .profileinfo-headimg {
6 | border-radius: 50%;
7 | width: 120px;
8 | height: 120px;
9 | margin: 15px 0;
10 | }
11 | .profileinfo-phone {
12 | color: #0097ff;
13 | font-size: 34px;
14 | margin-right: 10px;
15 | }
16 | .out-login {
17 | margin-top: 20px;
18 | .out-button {
19 | background: #fff;
20 | border: none;
21 | outline: none;
22 | color: #ff5339;
23 | font-weight: 600;
24 | &::after {
25 | border: none;
26 | }
27 | &:active {
28 | color: #ff7c68;
29 | }
30 | }
31 | }
32 | .profileinfo-title {
33 | font-weight: bold;
34 | }
35 | .profileinfo-alter {
36 | color: $blue-color;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/pages/msite/components/SearchBar/SearchBar.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View, Text, Navigator } from '@tarojs/components'
3 |
4 | import EIcon, { EIconProps } from '../../../../components/EIcon/EIcon'
5 |
6 | import './SearchBar.scss'
7 |
8 | interface SearchBarProps extends Omit {
9 | title: string
10 | icon: EIconProps['type']
11 | url: string
12 | }
13 |
14 | const SearchBar: FC = (props) => {
15 | const { title, icon, url } = props
16 | return (
17 |
18 |
19 |
20 | {title}
21 |
22 |
23 | )
24 | }
25 |
26 | export default SearchBar
27 |
--------------------------------------------------------------------------------
/src/components/NavBar/NavBar.scss:
--------------------------------------------------------------------------------
1 | $height: 88px;
2 | $margin-lr: 20px;
3 |
4 | .navbar {
5 | display: flex;
6 | position: relative;
7 | align-items: center;
8 | height: $height;
9 | background: $defualt-background-image;
10 | .navbar-black {
11 | position: absolute;
12 | z-index: 1;
13 | font-size: $font-size-34;
14 | color: $white-color;
15 | left: $margin-lr;
16 | }
17 | .navbar-title {
18 | position: absolute;
19 | left: 0;
20 | right: 0;
21 | top: 0;
22 | bottom: 0;
23 | display: flex;
24 | align-items: center;
25 | justify-content: center;
26 | color: $white-color;
27 | font-size: $font-size-34;
28 | }
29 | .navbar-href {
30 | position: absolute;
31 | z-index: 1;
32 | color: $white-color;
33 | font-size: $font-size-32;
34 | right: $margin-lr;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/pages/clearing/components/CartAddress/CartAddress.scss:
--------------------------------------------------------------------------------
1 | $color: #fff;
2 | $lh: 1.2;
3 |
4 | .cartaddress {
5 | padding: 20px;
6 | .title {
7 | color: #ceedff;
8 | }
9 |
10 | .address-title {
11 | color: $color;
12 | }
13 |
14 | .useinfo {
15 | .useinfo-title {
16 | display: flex;
17 | align-items: center;
18 | justify-content: space-between;
19 | .useinfo-title-text {
20 | overflow: hidden;
21 | padding: 10px 0;
22 | color: $color;
23 | font-size: 44px;
24 | font-weight: 600;
25 | line-height: $lh;
26 | white-space: nowrap;
27 | text-overflow: ellipsis;
28 | }
29 | .icon {
30 | color: #fff;
31 | font-size: 28px;
32 | }
33 | }
34 |
35 | .useinfo-name {
36 | color: $color;
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2017",
4 | "module": "commonjs",
5 | "removeComments": false,
6 | "preserveConstEnums": true,
7 | "moduleResolution": "node",
8 | "experimentalDecorators": true,
9 | "noImplicitAny": false,
10 | "allowSyntheticDefaultImports": true,
11 | "outDir": "lib",
12 | "noUnusedLocals": true,
13 | "noUnusedParameters": true,
14 | "strictNullChecks": true,
15 | "sourceMap": true,
16 | "baseUrl": ".",
17 | "rootDir": ".",
18 | "jsx": "react",
19 | "jsxFactory": "React.createElement",
20 | "allowJs": true,
21 | "resolveJsonModule": true,
22 | "typeRoots": [
23 | "node_modules/@types",
24 | "global.d.ts"
25 | ]
26 | },
27 | "exclude": [
28 | "node_modules",
29 | "dist"
30 | ],
31 | "compileOnSave": false
32 | }
33 |
--------------------------------------------------------------------------------
/src/pages/profile/info/username/index.scss:
--------------------------------------------------------------------------------
1 | .username {
2 | height: 100vh;
3 | background: #f5f5f5;
4 | .username-main {
5 | padding-top: 20px;
6 | margin: 0 20px;
7 | .username-input {
8 | display: flex;
9 | background: #fff;
10 | height: 80px;
11 | align-items: center;
12 | padding-left: 20px;
13 | }
14 |
15 | .username-text {
16 | color: #a9a9a9;
17 | font-size: 24px;
18 | padding: 10px 0;
19 | }
20 |
21 | .username-button {
22 | background: #00d762;
23 | color: #fff;
24 | font-weight: 600;
25 | &:active{
26 | background: #0dec72;
27 | }
28 | }
29 |
30 | .username-button[disabled] {
31 | background: #c7c7c7;
32 | font-weight: 600;
33 | border: none;
34 | &::after {
35 | border: none;
36 | }
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/components/EList/EItem.scss:
--------------------------------------------------------------------------------
1 | .ele-eitem {
2 | background: $white-color;
3 | font-size: $font-size-32;
4 | padding-left: 20px;
5 | &:last-child {
6 | .ele-eitem-main {
7 | border-bottom: none;
8 | }
9 | }
10 | .ele-eitem-main {
11 | border-bottom: 1px solid #f5f5f5;
12 | display: flex;
13 | align-items: center;
14 | .ele-eitem-content-img {
15 | margin-right: 10px;
16 | width: 60px;
17 | height: 60px;
18 | }
19 | .ele-eitem-content {
20 | display: flex;
21 | align-items: center;
22 | flex: 1;
23 | padding-right: 20px;
24 | .ele-eitem-content-title {
25 | flex: 1;
26 | padding: 25px 0;
27 | }
28 | .ele-eitem-content-icon {
29 | margin-left: 10px;
30 | }
31 | .ele-eitem-extra {
32 | color: $color-666;
33 | }
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/pages/msite/components/Advertising/Advertising.tsx:
--------------------------------------------------------------------------------
1 | // 首页广告位
2 | import React, { FC } from 'react'
3 | import { View, Image, Navigator } from '@tarojs/components'
4 |
5 | import './Advertising.scss'
6 |
7 | interface AdvertisingProps {
8 | title: string
9 | detail: string
10 | img: string
11 | url: string
12 | }
13 |
14 | const Advertising: FC = (props) => {
15 | const { title, detail, img, url } = props
16 |
17 | return (
18 |
19 |
20 | {title}
21 | {detail}
22 | 立即抢购>
23 |
24 |
25 |
26 |
27 |
28 | )
29 | }
30 |
31 | export default Advertising
32 |
--------------------------------------------------------------------------------
/src/pages/profile/components/UserHead/UserHead.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { View, Image, Text } from '@tarojs/components'
3 | import './UserHead.scss'
4 |
5 | const UserHead = ({ userInfo, onLink }) => {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 |
13 | {userInfo.userName}
14 |
15 |
16 | {userInfo.phone}
17 |
18 |
19 |
20 |
21 |
22 | )
23 | }
24 |
25 | export default UserHead
26 |
--------------------------------------------------------------------------------
/src/pages/city/components/FilterList/FilterList.tsx:
--------------------------------------------------------------------------------
1 | // 筛选城市
2 | import React from 'react'
3 | import classnames from 'classnames'
4 | import { ScrollView, View } from '@tarojs/components'
5 | import './FilterList.scss'
6 |
7 | const FilterList = ({ cityValue, resultCityList, onSelectCity }) => {
8 | return (
9 |
10 | {resultCityList.map(city => {
11 | return (
12 | onSelectCity(city)}
16 | >
17 | {city.name}
18 |
19 | )
20 | })}
21 | 0 ,
24 | })}
25 | >
26 | 无结果
27 |
28 |
29 | )
30 | }
31 | export default FilterList
32 |
--------------------------------------------------------------------------------
/src/pages/profile/address/search/index.scss:
--------------------------------------------------------------------------------
1 | .search {
2 | .search-main {
3 | height: calc(100vh - 85px);
4 | .search-top {
5 | border: 1px #eaeaea solid;
6 | background: #f5f5f5;
7 | display: flex;
8 | align-items: center;
9 | padding: 5px 0;
10 | margin: 20px 20px 0 20px;
11 | .icon {
12 | font-size: 30px;
13 | padding-left: 10px;
14 | color: #757575;
15 | }
16 |
17 | .input {
18 | flex: 1;
19 | margin-left: 10px;
20 | }
21 | }
22 |
23 | .search-list {
24 | margin: 10px 20px;
25 | .search-item {
26 | border-bottom: 1px #f0f0f0 solid;
27 | padding: 15px 0;
28 | .title {
29 | color: #333;
30 | font-size: 32px;
31 | }
32 |
33 | .detail {
34 | color: #a7a7a7;
35 | font-size: 26px;
36 | }
37 | }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/pages/address/components/AtAddress/AtAddress.scss:
--------------------------------------------------------------------------------
1 | // 当前地址
2 | .ataddress {
3 | .ataddress-title {
4 | padding: 20px;
5 | color: $color-666;
6 | font-size:$font-size-26;
7 | }
8 |
9 | .ataddress-main {
10 | background: #fff;
11 | display: flex;
12 | justify-content: space-between;
13 | align-items: center;
14 | height: 85px;
15 | padding: 0 20px;
16 | > .text {
17 | color: #333;
18 | font-weight: 600;
19 | overflow: hidden;
20 | text-overflow: ellipsis;
21 | white-space: nowrap;
22 | font-size: $font-size-30;
23 | }
24 |
25 | .location {
26 | display: flex;
27 | align-items: center;
28 | .location-icon {
29 | .icon {
30 | color: #008fff;
31 | font-size: 35px;
32 | }
33 | }
34 |
35 | > .text {
36 | color: #008fff;
37 | width: 120px;
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/pages/address/components/AtAddress/AtAddress.tsx:
--------------------------------------------------------------------------------
1 | // 当前地址
2 | import React, { FC } from 'react'
3 | import { View, Text } from '@tarojs/components'
4 |
5 | import './AtAddress.scss'
6 |
7 | interface AtAddressProps {
8 | onLocationCity: () => void
9 | atAddress: string
10 | }
11 | const AtAddress: FC = (props) => {
12 | const { onLocationCity, atAddress } = props
13 | return (
14 |
15 | 当前地址
16 |
17 | {atAddress}
18 |
19 |
20 |
21 |
22 | 重新定位
23 |
24 |
25 |
26 | )
27 | }
28 |
29 | export default AtAddress
30 |
--------------------------------------------------------------------------------
/src/pages/address/components/Profile/Profile.scss:
--------------------------------------------------------------------------------
1 | // 收货地址
2 | .profile {
3 | .profile-title {
4 | padding: 20px;
5 | color: $color-666;
6 | font-size: $font-size-26;
7 | }
8 | .profile-main {
9 | background: #fff;
10 | padding: 0 20px;
11 | .profile-item {
12 | border-bottom: 1px #eeeeee solid;
13 | padding: 20px 0;
14 | .item-top {
15 | display: flex;
16 | align-items: center;
17 | .ming {
18 | color: #333;
19 | font-weight: 600;
20 | font-size: $font-size-30;
21 | }
22 | .sex {
23 | padding: 0 10px;
24 | font-size: 24px;
25 | color: $color-666;
26 | }
27 | .iphone {
28 | font-size: 24px;
29 | color: $color-666;
30 | }
31 | }
32 | .item-address{
33 | padding-top: 10px;
34 | font-size: $font-size-24;
35 | }
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/pages/address/components/ResultItem/ResultItem.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View } from '@tarojs/components'
3 | import { Address } from '../../../../api/interface'
4 |
5 | import './ResultItem.scss'
6 |
7 | interface ResultItemProps {
8 | onSaveAddress: (detail: Address) => void
9 | detail: any
10 | }
11 |
12 | const ResultItem: FC = (props) => {
13 | const { onSaveAddress, detail } = props
14 |
15 | return (
16 | onSaveAddress(detail)}>
17 |
18 | {detail.name}
19 |
20 | {detail.distance}
21 |
22 |
23 | {detail.address}
24 |
25 | )
26 | }
27 |
28 | export default ResultItem
29 |
--------------------------------------------------------------------------------
/src/redux/store.ts:
--------------------------------------------------------------------------------
1 | import { createStore, applyMiddleware, compose } from 'redux'
2 | import thunkMiddleware from 'redux-thunk'
3 | import rootReducer from './reducers'
4 |
5 | const composeEnhancers =
6 | typeof window === 'object' &&
7 | window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
8 | window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
9 | // Specify extension’s options like name, actionsBlacklist, actionsCreators, serialize...
10 | }) : compose
11 |
12 | const middlewares = [
13 | thunkMiddleware
14 | ]
15 |
16 | if (process.env.NODE_ENV === 'development' && process.env.TARO_ENV !== 'quickapp') {
17 | middlewares.push(require('redux-logger').createLogger())
18 | }
19 |
20 | const enhancer = composeEnhancers(
21 | applyMiddleware(...middlewares),
22 | // other store enhancers if any
23 | )
24 |
25 | export default function configStore () {
26 | const store = createStore(rootReducer, enhancer)
27 | return store
28 | }
29 |
--------------------------------------------------------------------------------
/src/app.config.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | pages: [
3 | 'pages/msite/index',
4 | 'pages/login/index',
5 | 'pages/register/index',
6 | 'pages/profile/index',
7 | 'pages/profile/info/index',
8 | 'pages/profile/info/username/index',
9 | 'pages/profile/info/password/index',
10 | 'pages/profile/address/index',
11 | 'pages/profile/address/add/index',
12 | 'pages/profile/address/edit/index',
13 | 'pages/profile/address/search/index',
14 | 'pages/discover/index',
15 | 'pages/order/index',
16 | 'pages/order/detail/index',
17 | 'pages/address/index',
18 | 'pages/city/index',
19 | 'pages/search/index',
20 | 'pages/food/index',
21 | 'pages/shop/index',
22 | 'pages/clearing/index',
23 | 'pages/test/index',
24 | ],
25 | window: {
26 | backgroundTextStyle: 'light',
27 | navigationBarBackgroundColor: '#fff',
28 | navigationBarTitleText: 'WeChat',
29 | navigationBarTextStyle: 'black',
30 | },
31 | }
32 |
--------------------------------------------------------------------------------
/src/components/FooterNav/images/msite_2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/ETransition/ETransition.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View } from '@tarojs/components'
3 | import { CSSTransition } from 'react-transition-group'
4 | import { CSSTransitionProps } from 'react-transition-group/CSSTransition'
5 |
6 | import './ETransition.scss'
7 |
8 | type AnimationName = 'ele-top' | 'ele-bottom' | 'ele-left' | 'ele-right'
9 |
10 | type ETransitionProps = CSSTransitionProps & {
11 | animation?: AnimationName
12 | wrapper?: boolean
13 | }
14 |
15 | const ETransition: FC = (props) => {
16 | const { classNames, animation, wrapper, children, ...restProps } = props
17 |
18 | return (
19 |
23 | {wrapper ? {children} : children}
24 |
25 | )
26 | }
27 | ETransition.defaultProps = {
28 | unmountOnExit: true,
29 | appear: true,
30 | }
31 | export default ETransition
32 |
--------------------------------------------------------------------------------
/src/components/EButton/EButton.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC, Fragment } from 'react'
2 | import { Text, Button } from '@tarojs/components'
3 | import { ButtonProps } from '@tarojs/components/types/Button'
4 | import classnames from 'classnames'
5 |
6 | import './EButton.scss'
7 |
8 | type EButtonType = 'default' | 'green' | 'blue' | 'href'
9 |
10 | interface EButtonProps extends ButtonProps {
11 | className?: string
12 | btnType: EButtonType
13 | children: React.ReactNode
14 | loading?: boolean
15 | href?: string
16 | }
17 |
18 | const EButton: FC = (props) => {
19 | const { className, btnType, loading, children, ...restProps } = props
20 |
21 | const classes = classnames('ele-ebutton', className, {
22 | [`ele-ebutton-${btnType}`]: btnType,
23 | })
24 |
25 | return (
26 |
30 | )
31 | }
32 |
33 | export default EButton
34 |
--------------------------------------------------------------------------------
/src/components/ShopList/ShopList.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC, ReactElement } from 'react'
2 | import { View } from '@tarojs/components'
3 | import ShopItem from '../ShopItem/ShopItem'
4 | import ELoading from '../ELoading/ELoading'
5 |
6 | import { IShopList } from '../../api/interface'
7 | import './ShopList.scss'
8 |
9 | interface ShopListProps {
10 | shopListData: IShopList[]
11 | renderLoading: ReactElement | null
12 | }
13 |
14 | const ShopList: FC = (props) => {
15 | const { shopListData, renderLoading } = props
16 |
17 | if (!shopListData.length) {
18 | return
19 | }
20 |
21 | return (
22 |
23 | {shopListData.map((shopdata) => {
24 | return (
25 |
29 | )
30 | })}
31 | {renderLoading}
32 |
33 | )
34 | }
35 |
36 | export default ShopList
37 |
--------------------------------------------------------------------------------
/src/pages/profile/info/password/components/Input/MyInput.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View, Input } from '@tarojs/components'
3 | import { InputProps } from '@tarojs/components/types/Input'
4 |
5 | import classnames from 'classnames'
6 | import './MyInput.scss'
7 |
8 | interface MyInputProps extends Omit {
9 | tip: string | null
10 | onInput: (value: string) => void
11 | }
12 |
13 | const MyInput: FC = (props) => {
14 | const { placeholder, type, tip, onInput, value } = props
15 | return (
16 |
17 | onInput(e.detail.value)}
26 | />
27 | {tip && {tip}}
28 |
29 | )
30 | }
31 |
32 | export default MyInput
33 |
--------------------------------------------------------------------------------
/src/pages/discover/components/Prize/Prize.scss:
--------------------------------------------------------------------------------
1 | .prize {
2 | display: flex;
3 | flex-direction: column;
4 | position: relative;
5 | width: 220px;
6 | margin: 10px 15px;
7 | text-align: center;
8 | .tab {
9 | position: absolute;
10 | z-index: 1;
11 | padding: 0 8px;
12 | background: #413d3c;
13 | color: #fff;
14 | font-size: 24px;
15 | }
16 |
17 | .prize-img {
18 | width: 220px;
19 | height: 220px;
20 | border: 1px #f8f8f8 solid;
21 | }
22 |
23 | .prize-head {
24 | .title {
25 | overflow: hidden;
26 | font-size: 26px;
27 | white-space: nowrap;
28 | text-overflow: ellipsis;
29 | }
30 |
31 | .price {
32 | display: flex;
33 | align-items: center;
34 | .points {
35 | color: #ff5339;
36 | font-size: 26;
37 | }
38 |
39 | .original {
40 | padding-left: 10px;
41 | color: #aaa;
42 | font-size: 22px;
43 | text-decoration: line-through;
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/pages/msite/components/NavSwipeItem/NavSwipeItem.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View, Navigator, Image } from '@tarojs/components'
3 | import imgUrl from '../../../../utils/imgUrl'
4 | import { INavSwiper } from '../../../../api/interface'
5 | import './NavSwipeItem.scss'
6 |
7 | interface ItemProps {
8 | navItem: INavSwiper
9 | }
10 |
11 | const NavSwipeItem: FC = (props) => {
12 | const { navItem } = props
13 | return (
14 |
15 |
18 |
19 |
24 |
25 | {navItem.name}
26 |
27 |
28 | )
29 | }
30 |
31 | export default NavSwipeItem
32 |
--------------------------------------------------------------------------------
/src/pages/msite/components/MsiteNavBar/MsiteNavBar.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { Navigator } from '@tarojs/components'
3 | import { useSelector } from 'react-redux'
4 | import NavBar from '../../../../components/NavBar/NavBar'
5 | import EIcon from '../../../../components/EIcon/EIcon'
6 | import { Reducers } from '../../../../redux/interface'
7 |
8 | import './MsiteNavBar.scss'
9 |
10 | const MsiteNavBar = () => {
11 | const { currentAddress } = useSelector((state: Reducers) => state)
12 | return (
13 |
14 | {/* 图标 */}
15 |
16 | {/* 地址信息 */}
17 |
22 | {currentAddress.address || '手动选择收货地址'}
23 |
24 | {/* 图标 */}
25 |
26 |
27 | )
28 | }
29 |
30 | export default MsiteNavBar
31 |
--------------------------------------------------------------------------------
/src/pages/profile/address/components/AddressRow/AddressRow.scss:
--------------------------------------------------------------------------------
1 | .addressrow {
2 | display: flex;
3 | align-items: center;
4 | padding: 20px 0;
5 | border-bottom: 1px #f0f0f0 solid;
6 | background: #fff;
7 | color: #6f6f6f;
8 | .addressrow-icon {
9 | padding-left: 20px;
10 | color: #4cd964;
11 | font-size: 60px;
12 | }
13 | .addressrow-left {
14 | flex: 1;
15 | padding-left: 20px;
16 | .myinfo {
17 | display: flex;
18 | align-items: center;
19 | .myname {
20 | color: #333;
21 | font-size: 34px;
22 | font-weight: 600;
23 | }
24 | .mysex {
25 | margin-left: 10px;
26 | }
27 | .myphone {
28 | margin-left: 20px;
29 | font-size: 32px;
30 | }
31 | }
32 | .myaddress {
33 | }
34 | }
35 |
36 | .addressrow-right {
37 | display: flex;
38 | align-items: center;
39 | .addressrow-right-icon {
40 | padding: 0 20px;
41 | .icon {
42 | font-size: 34px;
43 | }
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/pages/clearing/components/Distribution/Distribution.tsx:
--------------------------------------------------------------------------------
1 | import React, { useCallback } from 'react'
2 | import { View } from '@tarojs/components'
3 |
4 | import './Distribution.scss'
5 |
6 | const Distribution = () => {
7 | const getTime = useCallback(() => {
8 | const timeNow = Date.now() + 30 * 60 * 1000
9 | const time = new Date(timeNow)
10 | const hours = time.getHours()
11 | const minutes =
12 | Number(time.getMinutes()) < 10
13 | ? '0' + time.getMinutes()
14 | : time.getMinutes()
15 |
16 | return hours + ':' + minutes
17 | }, [])
18 |
19 | return (
20 |
21 |
22 | 送达时间
23 | 尽快送达({getTime()}送达)
24 |
25 |
26 | 支付方式
27 | 在线支付
28 |
29 |
30 | )
31 | }
32 |
33 | export default Distribution
34 |
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/components/NoDataTip/NoDataTip.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View, Image } from '@tarojs/components'
3 | import classnames from 'classnames'
4 | import EButton from '../EButton/EButton'
5 |
6 | import './NoDataTip.scss'
7 |
8 | export interface NoDataTipProps {
9 | img: string
10 | title: string
11 | info?: string
12 | btnContent?: string
13 | onButtonClick?: () => void
14 | className?: string
15 | }
16 |
17 | const NoDataTip: FC = (props) => {
18 | const { img, title, info, btnContent, onButtonClick, className } = props
19 | const classes = classnames('ele-nodatatipo', className)
20 | return (
21 |
22 |
23 | {title}
24 | {info && {info}}
25 | {btnContent && (
26 |
27 | {btnContent}
28 |
29 | )}
30 |
31 | )
32 | }
33 |
34 | export default NoDataTip
35 |
--------------------------------------------------------------------------------
/src/assets/styles/_mixin.scss:
--------------------------------------------------------------------------------
1 | // @mixin border($direction: 'top', $color, $px: '1px', $solid: 'solid') {
2 | // border-#{$direction}: $px $color $solid;
3 | // }
4 |
5 | @mixin flex() {
6 | display: flex;
7 | align-items: center;
8 | justify-content: center;
9 | }
10 |
11 | @mixin ele-animation(
12 | $direction: 'top',
13 | $scaleStart: scaleY(0),
14 | $scaleEnd: scaleY(1),
15 | $origin: center top
16 | ) {
17 | .ele-#{$direction}-enter {
18 | opacity: 0;
19 | transform: $scaleStart;
20 | }
21 | .ele-#{$direction}-enter-active {
22 | opacity: 1;
23 | transform: $scaleEnd;
24 | transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1) 100ms,
25 | opacity 300ms cubic-bezier(0.23, 1, 0.32, 1) 100ms;
26 | transform-origin: $origin;
27 | }
28 | .ele-#{$direction}-exit {
29 | opacity: 1;
30 | }
31 | .ele-#{$direction}-exit-active {
32 | opacity: 0;
33 | transform: $scaleStart;
34 | transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1) 100ms,
35 | opacity 300ms cubic-bezier(0.23, 1, 0.32, 1) 100ms;
36 | transform-origin: $origin;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/pages/msite/components/Svip/Svip.scss:
--------------------------------------------------------------------------------
1 | .svip {
2 | display: flex;
3 | justify-content: space-between;
4 | padding: 20px;
5 | margin: 10px 20px 0 20px;
6 | background-image: $svip-background-image;
7 | color: #644f1b;
8 | border-radius: 6px;
9 | .svip-left {
10 | display: flex;
11 | align-items: center;
12 | .svip-icon {
13 | margin-right: 10px;
14 | width: 33px;
15 | height: 33px;
16 | .image {
17 | width: 100%;
18 | height: 100%;
19 | }
20 | }
21 | .svip-title {
22 | font-weight: 600;
23 | }
24 | .svip-tip {
25 | font-size: 22px;
26 | &::before {
27 | content: '\B7';
28 | margin: 0 10px;
29 | }
30 | }
31 | }
32 |
33 | .svip-right {
34 | font-size: 22px;
35 | display: flex;
36 | align-items: center;
37 | &::after {
38 | display: block;
39 | content: '';
40 | width: 5px;
41 | height: 5px;
42 | border-right: 2px solid #8c632b;
43 | border-bottom: 2px solid #8c632b;
44 | transform: rotate(-45deg);
45 | margin-left: 10px;
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/components/FooterNav/FooterNav.scss:
--------------------------------------------------------------------------------
1 | .footerbar {
2 | height: 100px;
3 | .footerbar-mian {
4 | display: flex;
5 | align-items: center;
6 | justify-content: space-between;
7 | position: fixed;
8 | z-index: 3;
9 | right: 0;
10 | bottom: 0;
11 | left: 0;
12 | height: 100px;
13 | background: #fff;
14 | color: $color-999;
15 | box-shadow: 0 -0.3px 0.6vw rgba(0, 0, 0, 0.1);
16 | .footer-item {
17 | display: flex;
18 | align-items: center;
19 | flex: 1;
20 | flex-direction: column;
21 | justify-content: center;
22 | .item-icon {
23 | width: 36px;
24 | height: 36px;
25 | .taro-img {
26 | display: block;
27 | width: auto;
28 | height: auto;
29 | }
30 | .item-icon-img {
31 | width: 100%;
32 | height: 100%;
33 | border: none;
34 | }
35 | }
36 |
37 | .item-name {
38 | font-size: 20px;
39 | padding-top: 5px;
40 | }
41 | }
42 | .active {
43 | .item-name {
44 | color: $blue-color;
45 | }
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/pages/city/components/Search/Search.tsx:
--------------------------------------------------------------------------------
1 | // 搜索城市input
2 | import React, { FC } from 'react'
3 | import { View, Input, Text } from '@tarojs/components'
4 | import { InputProps } from '@tarojs/components/types/Input'
5 | import { BaseEventOrig } from '@tarojs/components/types/common'
6 | import './Search.scss'
7 |
8 | interface SearchProps {
9 | cityValue: string
10 | onInput: (e: BaseEventOrig) => void
11 | }
12 |
13 | const Search: FC = (props) => {
14 | const { cityValue, onInput } = props
15 |
16 | return (
17 |
18 |
19 |
20 |
21 |
22 |
23 |
29 |
30 |
31 |
32 | )
33 | }
34 |
35 | export default Search
36 |
--------------------------------------------------------------------------------
/src/components/ShopButton/ShopButton.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC, Fragment } from 'react'
2 | import { View } from '@tarojs/components'
3 |
4 | import './ShopButton.scss'
5 |
6 | interface ShopButtonProps {
7 | onUpdateCart
8 | good
9 | count
10 | }
11 |
12 | const ShopButton: FC = (props) => {
13 | const { onUpdateCart, good, count } = props
14 | return (
15 |
16 | {count > 0 && (
17 |
18 | onUpdateCart(good, 'dec')}
21 | >
22 |
23 |
24 |
25 | {count}
26 |
27 |
28 | )}
29 | onUpdateCart(good, 'add')}
32 | >
33 |
34 |
35 |
36 | )
37 | }
38 |
39 | ShopButton.defaultProps = {
40 | count: 0,
41 | }
42 |
43 | export default ShopButton
44 |
--------------------------------------------------------------------------------
/src/pages/shop/components/LeftBar/LeftBar.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC, useMemo } from 'react'
2 | import { View, Image } from '@tarojs/components'
3 | import classnames from 'classnames'
4 | import imgUrl from '../../../../utils/imgUrl'
5 |
6 | import './LeftBar.scss'
7 |
8 | interface LeftBarProps {
9 | good
10 | isActive
11 | onActive
12 | classCount
13 | }
14 |
15 | const LeftBar: FC = (props) => {
16 | const { good, isActive, onActive, classCount } = props
17 | const icon = useMemo(() => {
18 | if (good.icon_url) {
19 | return (
20 |
24 | )
25 | }
26 | }, [good, isActive])
27 | return (
28 | onActive(good)}
33 | >
34 | {icon}
35 | {good.name}
36 | {classCount > 0 && {classCount}}
37 |
38 | )
39 | }
40 |
41 | export default LeftBar
42 |
--------------------------------------------------------------------------------
/src/pages/profile/components/Money/Money.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View, Image } from '@tarojs/components'
3 |
4 | import './Money.scss'
5 |
6 | type MoneyList = {
7 | id: number
8 | img: string
9 | title: string
10 | }
11 |
12 | interface MoneyProps {
13 | moneyList: MoneyList[]
14 | onClick: () => void
15 | }
16 |
17 | const Money: FC = (props) => {
18 | const { moneyList, onClick } = props
19 | return (
20 |
21 | {/*
22 |
23 |
24 |
25 | 红包
26 | */}
27 | {moneyList.map((item) => {
28 | return (
29 |
30 |
31 |
32 |
33 | 金币
34 |
35 | )
36 | })}
37 |
38 | )
39 | }
40 |
41 | export default Money
42 |
--------------------------------------------------------------------------------
/src/pages/profile/components/UserHead/UserHead.scss:
--------------------------------------------------------------------------------
1 | .user {
2 | background-image: linear-gradient(90deg, #0af, #0085ff);
3 | .user-content {
4 | display: flex;
5 | justify-content: space-between;
6 | align-items: center;
7 | padding: 50px 30px;
8 | .user-left {
9 | width: 120px;
10 | height: 120px;
11 | .user-image {
12 | width: 100%;
13 | height: 100%;
14 | border-radius: 50%;
15 | }
16 | }
17 |
18 | > .icon {
19 | font-size: 30px;
20 | color: #fff;
21 | }
22 |
23 | .user-right {
24 | flex: 1;
25 | display: flex;
26 | height: 100px;
27 | flex-direction: column;
28 | justify-content: space-between;
29 | margin-left: 30px;
30 | .user-title {
31 | font-size: 40px;
32 | font-weight: 600;
33 | color: #fff;
34 | }
35 |
36 | .right-content {
37 | display: flex;
38 | align-items: center;
39 | .icon {
40 | color: #fff;
41 | font-size: 24px;
42 | }
43 | .user-text {
44 | color: #fff;
45 | font-size: 24px;
46 | }
47 | }
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/pages/search/components/SearchBar/SearchBar.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View, Input } from '@tarojs/components'
3 | import { InputProps } from '@tarojs/components/types/Input'
4 | import { BaseEventOrig } from '@tarojs/components/types/common'
5 |
6 | import './SearchBar.scss'
7 |
8 | interface SearcBarProps {
9 | onSearch: (keyword: string) => void
10 | onInput: (e: BaseEventOrig) => void
11 | keyword: string
12 | onClearKeyWord: () => void
13 | }
14 | const SearchBar: FC = (props) => {
15 | const { onSearch, onInput, keyword, onClearKeyWord } = props
16 | return (
17 |
18 |
19 | onInput(e)}
24 | />
25 | {keyword && (
26 |
27 | )}
28 | onSearch(keyword)}>
29 | 搜索
30 |
31 |
32 | )
33 | }
34 |
35 | export default SearchBar
36 |
--------------------------------------------------------------------------------
/src/components/ELoading/ELoading.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View, Text } from '@tarojs/components'
3 | import classnames from 'classnames'
4 | import setstylepx from '../../utils/setstylepx'
5 | import './ELoading.scss'
6 |
7 | interface ELoadingProps {
8 | height?: number | string
9 | className?: string
10 | move?: boolean
11 | title?: string
12 | icon?: boolean
13 | }
14 |
15 | const ELoading: FC = (props) => {
16 | const { height, className, move, title, icon } = props
17 | const classes = classnames('ele-isloading', className)
18 |
19 | const pHeight = () => {
20 | if (typeof height === 'string') {
21 | return height
22 | } else {
23 | return setstylepx(height)
24 | }
25 | }
26 |
27 | if (move) {
28 | return (
29 |
30 | {icon && }
31 | {title}
32 |
33 | )
34 | } else {
35 | return
36 | }
37 | }
38 |
39 | ELoading.defaultProps = {
40 | height: 200,
41 | title: '正在加载...',
42 | icon: true,
43 | }
44 | export default ELoading
45 |
--------------------------------------------------------------------------------
/src/components/ELoading/ELoading.scss:
--------------------------------------------------------------------------------
1 | .ele-isloading {
2 | @include flex;
3 | height: 200px;
4 | &::after {
5 | content: '';
6 | display: block;
7 | width: 40px;
8 | height: 40px;
9 | animation: isloading 0.5s infinite linear;
10 | border-left: 4px solid transparent;
11 | border-right: 4px solid transparent;
12 | border-bottom: 4px solid transparent;
13 | border-top: 4px solid #2395ff;
14 | border-radius: 100%;
15 | z-index: 1;
16 | }
17 | }
18 |
19 | .ele-move {
20 | @include flex;
21 | height: 50px;
22 | .ele-move-icon {
23 | padding-right: 10px;
24 | &::after {
25 | content: '';
26 | display: block;
27 | width: 26px;
28 | height: 26px;
29 | animation: isloading 1s infinite linear;
30 | border-left: 4px #eeeeee solid;
31 | border-right: 4px #eeeeee solid;
32 | border-top: 4px #eeeeee solid;
33 | border-bottom: 4px #2395ff solid;
34 | border-radius: 50%;
35 | }
36 | }
37 | .ele-move-title {
38 | color: $color-666;
39 | font-size: $font-size-24;
40 | }
41 | }
42 |
43 | @keyframes isloading {
44 | 0% {
45 | transform: rotate(0deg);
46 | }
47 | 100% {
48 | transform: rotate(360deg);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/pages/profile/address/add/index.tsx:
--------------------------------------------------------------------------------
1 | // 添加地址
2 | import Taro from '@tarojs/taro'
3 | import React, { FC } from 'react'
4 | import { View } from '@tarojs/components'
5 | import { useSelector } from 'react-redux'
6 | import { H5 } from '../../../../config/base'
7 | import API from '../../../../api'
8 | import { Reducers, Address } from '../../../../redux/interface'
9 | import NavBar from '../../../../components/NavBar/NavBar'
10 | import UserAddress from '../../../../components/UserAddress/UserAddress'
11 |
12 | import './index.scss'
13 |
14 | const AddAddress: FC = () => {
15 | const userAddress = useSelector((state: Reducers) => state.userAddress)
16 | const onForm = async (form: Address) => {
17 | const { err, res } = await API.reqAddUserAddress(form)
18 |
19 | if (err) {
20 | console.log(err)
21 | return
22 | }
23 |
24 | if (res.code === 0) {
25 | Taro.navigateBack({ delta: 1 })
26 | } else {
27 | console.log(res)
28 | Taro.showToast({ title: res.message, icon: 'none' })
29 | }
30 | }
31 | return (
32 |
33 | {H5 && }
34 |
35 |
36 | )
37 | }
38 |
39 | export default AddAddress
40 |
--------------------------------------------------------------------------------
/src/pages/address/components/Profile/Profile.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View } from '@tarojs/components'
3 | import { Address } from 'src/api/interface'
4 |
5 | import './Profile.scss'
6 |
7 | interface ProfileProps {
8 | userAddressList: any[]
9 | onClick: (item: Address) => void
10 | }
11 | const Profile: FC = (props) => {
12 | const { userAddressList, onClick } = props
13 | return (
14 |
15 | 收货地址
16 |
17 | {userAddressList.map((item) => {
18 | return (
19 | onClick(item)}
23 | >
24 |
25 | {item.name}
26 |
27 | {item.sex === '1' ? '先生' : '女士'}
28 |
29 | {item.phone}
30 |
31 | {item.address}
32 |
33 | )
34 | })}
35 |
36 |
37 | )
38 | }
39 |
40 | export default Profile
41 |
--------------------------------------------------------------------------------
/src/pages/address/components/Search/Search.scss:
--------------------------------------------------------------------------------
1 | .selectaddress-search {
2 | background: #fff;
3 | display: flex;
4 | align-items: center;
5 | height: 108px;
6 | .search-left {
7 | width: 128px;
8 | display: flex;
9 | justify-content: center;
10 | align-items: center;
11 | margin-left: 20px;
12 | .search-left-text {
13 | flex: 1;
14 | align-items: center;
15 | text-align: center;
16 | font-size: 24px;
17 | color: #333;
18 | width: 80px;
19 | overflow: hidden;
20 | text-overflow: ellipsis;
21 | white-space: nowrap;
22 | }
23 | .search-left-icon {
24 | >.icon {
25 | color: $color-666 !important;
26 | }
27 | }
28 | }
29 |
30 | .search-right {
31 | flex: 1;
32 | display: flex;
33 | background: #f2f2f2;
34 | margin-right: 20px;
35 | align-items: center;
36 | margin-left: 20px;
37 | .search-right-icon {
38 | margin-left: 20px;
39 | .icon {
40 | font-size: 30px;
41 | }
42 | }
43 | .search-right-input {
44 | flex: 1;
45 | padding: 18px;
46 | }
47 | .search-right-close {
48 | width: 80px;
49 | display: flex;
50 | justify-content: center;
51 | .icon {
52 | font-size: 25px;
53 | }
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/pages/search/components/Back/Back.tsx:
--------------------------------------------------------------------------------
1 | import React, { memo, FC } from 'react'
2 | import { View } from '@tarojs/components'
3 | import ELoading from '../../../../components/ELoading/ELoading'
4 |
5 | import './Back.scss'
6 |
7 | interface BackProps {
8 | title: string
9 | clear?: boolean
10 | dataList: any[]
11 | onTypeaHead: (value: any) => void
12 | onClearHistory?: () => void
13 | }
14 | const Back: FC = (props) => {
15 | const { title, clear, dataList, onTypeaHead, onClearHistory } = props
16 |
17 | if (!dataList.length) {
18 | return
19 | }
20 |
21 | return (
22 |
23 |
24 | {title}
25 | {clear && (
26 |
27 | )}
28 |
29 |
30 | {dataList.map((item, i) => {
31 | return (
32 | onTypeaHead(item.word || item)}
36 | >
37 | {item.word || item}
38 |
39 | )
40 | })}
41 |
42 |
43 | )
44 | }
45 |
46 | export default memo(Back)
47 |
--------------------------------------------------------------------------------
/src/assets/images/xx2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/pages/shop/components/Recommend/Recommend.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View, Image, Text } from '@tarojs/components'
3 | import imgUrl from '../../../../utils/imgUrl'
4 | import ShopButton from '../../../../components/ShopButton/ShopButton'
5 |
6 | import './Recommend.scss'
7 |
8 | interface RecommendProps {
9 | onUpdateCart
10 | recData
11 | count
12 | }
13 | const Recommend: FC = (props) => {
14 | const { onUpdateCart, recData, count } = props
15 | return (
16 |
17 |
18 |
19 | {recData.name}
20 |
21 | 月售{recData.month_sales} 好评率{recData.satisfy_rate}%
22 |
23 |
24 |
25 | ¥
26 | {recData.price}
27 |
28 |
33 |
34 |
35 |
36 | )
37 | }
38 |
39 | export default Recommend
40 |
--------------------------------------------------------------------------------
/src/pages/address/components/Result/Result.tsx:
--------------------------------------------------------------------------------
1 | // 搜索地址
2 | import React, { FC, useMemo, memo } from 'react'
3 | import classnames from 'classnames'
4 | import { View } from '@tarojs/components'
5 | import { Address } from '../../../../api/interface'
6 | import SelectAddressResultItem from '../ResultItem/ResultItem'
7 | import './Result.scss'
8 |
9 | interface ResultProps {
10 | detailList: Address[]
11 | onSaveAddress: (detail: Address) => void
12 | }
13 |
14 | const Result: FC = (props) => {
15 | const { detailList, onSaveAddress } = props
16 |
17 | const flag = useMemo(() => {
18 | if (detailList.length > 0) {
19 | return true
20 | } else {
21 | return false
22 | }
23 | }, [detailList])
24 |
25 | return (
26 |
31 | {detailList.map((detail) => (
32 |
37 | ))}
38 |
39 |
40 | 找不到地址?
41 | 请尝试只输入小区、写字楼或学校名
42 | 详细地址(如门牌号)可稍后输入
43 |
44 |
45 | )
46 | }
47 |
48 | export default memo(Result)
49 |
--------------------------------------------------------------------------------
/src/pages/profile/address/edit/index.tsx:
--------------------------------------------------------------------------------
1 | // 编辑地址
2 | import Taro from '@tarojs/taro'
3 | import React, { FC } from 'react'
4 | import { View } from '@tarojs/components'
5 | import { useSelector } from 'react-redux'
6 | import { H5 } from '../../../../config/base'
7 | import API from '../../../../api'
8 | import { Reducers, Address } from '../../../../redux/interface'
9 | import NavBar from '../../../../components/NavBar/NavBar'
10 | import UserAddress from '../../../../components/UserAddress/UserAddress'
11 |
12 | import './index.scss'
13 |
14 | const ProfileAddressEdit: FC = () => {
15 | const userAddress = useSelector((state: Reducers) => state.userAddress)
16 |
17 | // 获取修改的数据
18 | const onForm = async (myAddress: Address) => {
19 | const { err, res } = await API.reqSetUserAddress(myAddress)
20 |
21 | if (err) {
22 | console.log(err)
23 | return
24 | }
25 |
26 | if (res.code === 0) {
27 | Taro.navigateTo({ url: '/pages/profile/address/index' })
28 | } else {
29 | console.log(res)
30 | Taro.showToast({ title: res.message, icon: 'none' })
31 | }
32 | }
33 |
34 | return (
35 |
36 | {H5 && }
37 |
38 |
39 | )
40 | }
41 |
42 | export default ProfileAddressEdit
43 |
--------------------------------------------------------------------------------
/src/pages/msite/components/Tip/Tip.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Taro from '@tarojs/taro'
3 | import { useSelector } from 'react-redux'
4 | import NoDataTip from '../../../../components/NoDataTip/NoDataTip'
5 | import { Reducers } from '../../../../redux/interface'
6 |
7 | const Tip = () => {
8 | const { token, currentAddress } = useSelector((state: Reducers) => state)
9 | // 跳转到登录
10 | const handleToLogin = () => {
11 | Taro.reLaunch({ url: '/pages/login/index' })
12 | }
13 | // 跳转到选择地址
14 | const handleSelectAddress = () => {
15 | Taro.reLaunch({ url: '/pages/address/index' })
16 | }
17 |
18 | if (!token && currentAddress.latitude) {
19 | return (
20 |
28 | )
29 | }
30 |
31 | if (!currentAddress.latitude) {
32 | return (
33 |
40 | )
41 | }
42 | return null
43 | }
44 |
45 | export default Tip
46 |
--------------------------------------------------------------------------------
/src/pages/login/index.scss:
--------------------------------------------------------------------------------
1 | .login {
2 | margin-top: 30px;
3 | .logo {
4 | display: flex;
5 | justify-content: center;
6 | align-items: center;
7 | padding: 50px 0;
8 | .logo-content {
9 | width: 300px;
10 | height: 120px;
11 | .logo-image {
12 | width: 100%;
13 | height: 100%;
14 | }
15 | }
16 | }
17 | .form {
18 | margin: 0 50px;
19 | display: block;
20 | .input-row {
21 | margin-bottom: 20px;
22 | position: relative;
23 | height: 90px;
24 | display: flex;
25 | align-items: center;
26 | .input {
27 | flex: 1;
28 | border: 1px #eee solid;
29 | outline: none;
30 | padding: 20px 0 20px 20px;
31 | }
32 | .inputactive {
33 | border: 1px #0089dc solid;
34 | }
35 | }
36 |
37 | .tiptext {
38 | padding: 40px 0;
39 | color: #333;
40 | .text {
41 | color: #23a2ff;
42 | }
43 | }
44 |
45 | .submit {
46 | border: 0;
47 | box-shadow: none;
48 | background: #4cd96f;
49 | color: #fff;
50 | outline: none;
51 | &:active {
52 | background: #3cc95f;
53 | }
54 | }
55 |
56 | .register {
57 | display: block;
58 | text-align: center;
59 | color: #ccc;
60 | padding-top: 20px;
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/components/ETabs/ETabs.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import { View, Text } from '@tarojs/components'
3 | import classnames from 'classnames'
4 |
5 | import './ETabs.scss'
6 |
7 | const ETabs = ({ tabs, children }) => {
8 | const [tabIndex, setTabIndex] = useState(0)
9 |
10 | const activeTabs = i => {
11 | setTabIndex(i)
12 | }
13 |
14 | return (
15 |
16 |
17 | {tabs.map((tab, i) => (
18 | activeTabs(i)}
22 | >
23 |
28 | {tab.title}
29 |
30 |
31 | ))}
32 |
33 |
34 | {children.map((item, i) => {
35 | return (
36 |
42 | {item}
43 |
44 | )
45 | })}
46 |
47 |
48 | )
49 | }
50 |
51 | export default ETabs
52 |
--------------------------------------------------------------------------------
/src/pages/search/components/SearchItem/SearchItem.scss:
--------------------------------------------------------------------------------
1 | .searchitem {
2 | display: flex;
3 | align-items: center;
4 | justify-content: space-between;
5 | .searchitem-left {
6 | padding-right: 20px;
7 | .searchitem-img {
8 | width: 48px;
9 | height: 48px;
10 | }
11 | }
12 | .searchitem-right {
13 | display: flex;
14 | align-items: center;
15 | flex: 1;
16 | justify-content: space-between;
17 | padding: 20px 0;
18 | border-bottom: 1px #f8f8f8 solid;
19 | .searchitem-content {
20 | .searchitem-head {
21 | display: flex;
22 | padding: 4px 0;
23 | .title {
24 | font-size: 30px;
25 | }
26 | .searchitem-bold {
27 | color: $color-999;
28 | font-size: 30px;
29 | }
30 |
31 | .tag {
32 | display: table;
33 | margin-left: 20px;
34 | padding: 4px;
35 | color: $white-color;
36 | font-size: 24px;
37 | line-height: 1.2;
38 | }
39 | }
40 |
41 | .searchitem-bus {
42 | display: inline-block;
43 | padding: 0 8px;
44 | border: 1px currentColor solid;
45 | color: #00e066;
46 | font-size: 24px;
47 | border-radius: 20px;
48 | }
49 | }
50 |
51 | .searchitem-rating {
52 | color: #999;
53 | font-size: 24px;
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/components/FooterNav/images/msite_1.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/pages/test/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import { View, ScrollView } from '@tarojs/components'
3 |
4 | import './index.scss'
5 |
6 | const Test = () => {
7 | const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
8 |
9 | const [viewId, setViewId] = useState('')
10 |
11 | const handleViewId = (id) => {
12 | setViewId(`test${id}`)
13 | }
14 |
15 | return (
16 |
17 | handleViewId(1)}
22 | >
23 | 1
24 |
25 | handleViewId(2)}
30 | >
31 | 2
32 |
33 | handleViewId(3)}
38 | >
39 | 3
40 |
41 | handleViewId(4)}
46 | >
47 | 4
48 |
49 | handleViewId(5)}
54 | >
55 | 5
56 |
57 |
58 | )
59 | }
60 |
61 | export default Test
62 |
--------------------------------------------------------------------------------
/src/pages/shop/components/ActivityModal/ActivityModal.scss:
--------------------------------------------------------------------------------
1 | .activitymodal {
2 | position: fixed;
3 | z-index: 8;
4 | top: 0;
5 | right: 0;
6 | bottom: 0;
7 | left: 0;
8 | .activitymodal-main {
9 | position: absolute;
10 | z-index: 2;
11 | bottom: 0;
12 | left: 0;
13 | right: 0;
14 | height: 60vw;
15 | padding: 30px;
16 | background: #fff;
17 | .activitymodal-title {
18 | color: #333;
19 | font-size: 34px;
20 | font-weight: 600;
21 | text-align: center;
22 | }
23 |
24 | .icon.icon-guanbi {
25 | position: absolute;
26 | top: 10px;
27 | right: 10px;
28 | color: #666;
29 | font-size: 50px;
30 | }
31 | .activitymodal-list {
32 | height: 50vw;
33 | .activitymodal-item {
34 | display: flex;
35 | padding: 10px 0;
36 | .activitymodal-item-left {
37 | display: inline-table;
38 | margin-right: 15px;
39 | padding: 0 10px;
40 | font-size: 24px;
41 | line-height: 1.2;
42 | }
43 |
44 | .activitymodal-item-right {
45 | flex: 1;
46 | color: #666;
47 | font-size: 24px;
48 | line-height: 1.2;
49 | }
50 | }
51 | }
52 | }
53 | .activitymodal-bg {
54 | position: absolute;
55 | z-index: 1;
56 | top: 0;
57 | right: 0;
58 | bottom: 0;
59 | left: 0;
60 | background: rgba(0, 0, 0, 0.5);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/assets/images/xx1.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/pages/msite/components/NavSwipe/NavSwipe.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC, useState, useEffect } from 'react'
2 | import { View } from '@tarojs/components'
3 | import { useSelector } from 'react-redux'
4 |
5 | import API from '../../../../api'
6 | import { INavSwiper } from '../../../../api/interface'
7 | import { Reducers } from '../../../../redux/interface'
8 |
9 | import NavSwiperFramework from '../Framework/Framework'
10 | import NavSwiperItem from '../NavSwipeItem/NavSwipeItem'
11 |
12 | import './NavSwipe.scss'
13 |
14 | const NavSwiper: FC = () => {
15 | const { currentAddress } = useSelector((state: Reducers) => state)
16 | const [navSwipeList, setNavSwipeList] = useState([])
17 |
18 | useEffect(() => {
19 | const { latitude, longitude } = currentAddress
20 | // 导航
21 | if (latitude && longitude) {
22 | API.reqNavList({ latitude, longitude }).then((result) => {
23 | const { err, res } = result
24 | if (err) {
25 | console.log(err)
26 | return
27 | }
28 | if (res.code === 0) {
29 | setNavSwipeList(res.data)
30 | }
31 | })
32 | }
33 | }, [currentAddress])
34 |
35 | if (!navSwipeList.length) {
36 | // 骨架
37 | return
38 | }
39 |
40 | // 导航
41 | return (
42 |
43 | {navSwipeList.map((navItem) => {
44 | return
45 | })}
46 |
47 | )
48 | }
49 |
50 | export default NavSwiper
51 |
--------------------------------------------------------------------------------
/src/pages/clearing/components/CartInfo/CartInfo.scss:
--------------------------------------------------------------------------------
1 | .cartinfo {
2 | margin: 0 20px;
3 | padding: 0 30px;
4 | background: #fff;
5 | .cartinfo-title {
6 | padding: 20px 0;
7 | border-bottom: 1px #f5f5f5 solid;
8 | color: #333;
9 | font-size: 34px;
10 | font-weight: 600;
11 | }
12 |
13 | .cartinfo-goods {
14 | .cartinfo-food {
15 | display: flex;
16 | align-items: center;
17 | padding: 20px 0;
18 | border-bottom: 1px #ededed solid;
19 | .cartinfo-img {
20 | width: 72px;
21 | height: 72px;
22 | padding-right: 10px;
23 | }
24 |
25 | .cartinfo-name {
26 | flex: 9;
27 | }
28 |
29 | .cartinfo-count {
30 | flex: 1;
31 | font-size: 24px;
32 | text-align: right;
33 | }
34 |
35 | .origin-price {
36 | min-width: 100px;
37 | color: #999;
38 | text-align: right;
39 | text-decoration: line-through;
40 | }
41 |
42 | .lowest_price {
43 | flex: 3;
44 | color: #ff4a07;
45 | text-align: right;
46 | }
47 | }
48 | .sundry {
49 | display: flex;
50 | align-items: center;
51 | justify-content: space-between;
52 | padding: 20px 0;
53 | border-bottom: 1px #f5f5f5 solid;
54 | .sundry-left {
55 | }
56 | .sundry-right {
57 | }
58 | }
59 | }
60 |
61 | .result {
62 | padding: 20px 0;
63 | text-align: right;
64 | .result-price {
65 | font-size: 44px;
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/assets/images/cart2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/pages/clearing/components/CartAddress/CartAddress.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC, useMemo } from 'react'
2 | import { View, Text } from '@tarojs/components'
3 |
4 | import './CartAddress.scss'
5 |
6 | interface CartAddressProps {
7 | useAddress
8 | onSelectAddress
9 | }
10 |
11 | const CartAddress: FC = (props) => {
12 | const { useAddress, onSelectAddress } = props
13 | // 收货地址
14 | const addressText = useMemo(() => {
15 | if (useAddress.id) {
16 | return useAddress.address
17 | } else {
18 | return '请选择地址'
19 | }
20 | }, [useAddress])
21 |
22 | // 性别
23 | const getSex = useMemo(() => {
24 | const { sex } = useAddress
25 | switch (sex) {
26 | case 0:
27 | return '先生'
28 | case 1:
29 | return '女士'
30 | default:
31 | return null
32 | }
33 | }, [useAddress])
34 |
35 | return (
36 |
37 | 订单配送至
38 |
39 |
40 |
41 | {addressText}
42 |
43 |
44 |
45 | {useAddress.name}
46 | {getSex ? `(${getSex})` : null}
47 | {useAddress.phone}
48 |
49 |
50 |
51 | )
52 | }
53 |
54 | CartAddress.defaultProps = {
55 | useAddress: {},
56 | }
57 |
58 | export default CartAddress
59 |
--------------------------------------------------------------------------------
/src/assets/images/cart1.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/pages/shop/components/ActivityModal/ActivityModal.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View, ScrollView, Text } from '@tarojs/components'
3 |
4 | import './ActivityModal.scss'
5 |
6 | interface ActivityModalProps {
7 | activities
8 | onActivityHide
9 | }
10 |
11 | const ActivityModal: FC = (props) => {
12 | const { activities, onActivityHide } = props
13 | return (
14 |
15 |
16 | 优惠活动
17 |
18 |
19 | {activities.map((activitie) => {
20 | return (
21 |
22 |
29 | {activitie.icon_name}
30 |
31 |
32 | {activitie.description}
33 |
34 |
35 | )
36 | })}
37 |
38 |
39 |
40 |
41 | )
42 | }
43 |
44 | export default ActivityModal
45 |
--------------------------------------------------------------------------------
/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "miniprogramRoot": "dist/",
3 | "projectname": "ele-ts-client",
4 | "description": "仿饿了么H5, 可编译跨端 H5 微信小程序",
5 | "appid": "wxbdfb622485c1051d",
6 | "setting": {
7 | "urlCheck": false,
8 | "es6": false,
9 | "enhance": false,
10 | "postcss": false,
11 | "preloadBackgroundData": false,
12 | "minified": false,
13 | "newFeature": false,
14 | "coverView": true,
15 | "nodeModules": false,
16 | "autoAudits": false,
17 | "showShadowRootInWxmlPanel": true,
18 | "scopeDataCheck": false,
19 | "uglifyFileName": false,
20 | "checkInvalidKey": true,
21 | "checkSiteMap": true,
22 | "uploadWithSourceMap": true,
23 | "compileHotReLoad": false,
24 | "babelSetting": {
25 | "ignore": [],
26 | "disablePlugins": [],
27 | "outputPath": ""
28 | },
29 | "useIsolateContext": true,
30 | "useCompilerModule": false,
31 | "userConfirmedUseCompilerModuleSwitch": false
32 | },
33 | "compileType": "miniprogram",
34 | "simulatorType": "wechat",
35 | "simulatorPluginLibVersion": {},
36 | "condition": {
37 | "search": {
38 | "current": -1,
39 | "list": []
40 | },
41 | "conversation": {
42 | "current": -1,
43 | "list": []
44 | },
45 | "plugin": {
46 | "current": -1,
47 | "list": []
48 | },
49 | "game": {
50 | "current": -1,
51 | "list": []
52 | },
53 | "gamePlugin": {
54 | "current": -1,
55 | "list": []
56 | },
57 | "miniprogram": {
58 | "current": -1,
59 | "list": [
60 | {
61 | "id": -1,
62 | "name": "我的",
63 | "pathName": "pages/profile/index",
64 | "scene": null
65 | }
66 | ]
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/src/pages/register/index.scss:
--------------------------------------------------------------------------------
1 | .register {
2 | margin-top: 30px;
3 | .logo {
4 | display: flex;
5 | justify-content: center;
6 | align-items: center;
7 | padding: 50px 0;
8 | .logo-content {
9 | width: 300px;
10 | height: 120px;
11 | .logo-image {
12 | width: 100%;
13 | height: 100%;
14 | }
15 | }
16 | }
17 | .form {
18 | margin: 0 50px;
19 | display: block;
20 | .input-row {
21 | margin-bottom: 20px;
22 | position: relative;
23 | display: flex;
24 | .input {
25 | flex: 1;
26 | border: 1px #eee solid;
27 | padding: 25px 0;
28 | outline: none;
29 | padding-left: 20px;
30 | &::placeholder {
31 | color: #ccc;
32 | }
33 | }
34 | .inputactive {
35 | border: 1px #ccc solid;
36 | }
37 | .pass {
38 | border: 1px #4cd86f solid;
39 | }
40 | .placeholder {
41 | color: #ccc;
42 | }
43 | .error {
44 | border: 1px #ff7979 solid;
45 | }
46 | }
47 |
48 | .tiptext {
49 | padding: 40px 0;
50 | color: #333;
51 | .text {
52 | color: #23a2ff;
53 | }
54 | }
55 |
56 | .submit {
57 | border: 0;
58 | box-shadow: none;
59 | background: #008cff;
60 | color: #fff;
61 | outline: none;
62 |
63 | &:active {
64 | background: #3ba7ff;
65 | }
66 | }
67 |
68 | .login {
69 | display: block;
70 | text-align: center;
71 | color: #ccc;
72 | padding-top: 20px;
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/components/EIcon/EIcon.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { Text } from '@tarojs/components'
3 | import { StandardProps } from '@tarojs/components/types/common'
4 | import classnames from 'classnames'
5 | import setstylepx from '../../utils/setstylepx'
6 |
7 | import './EIcon.scss'
8 |
9 | type EIconType =
10 | | 'jiazailoading'
11 | | 'daohangshouye'
12 | | 'jianshao'
13 | | 'zengjia'
14 | | 'tianjia'
15 | | 'bianji'
16 | | 'miaozhun'
17 | | 'icon-test'
18 | | 'dianpu1'
19 | | 'jiantou-copy-copy'
20 | | 'jiantou-copy-copy-copy'
21 | | 'shouji'
22 | | 'iconset0143'
23 | | 'jiantou1'
24 | | 'zan'
25 | | 'success_fill'
26 | | 'ai-cart'
27 | | 'lajitong'
28 | | 'guanbi'
29 | | 'close'
30 | | 'huangguan'
31 | | 'jiantou'
32 | | 'jiazai'
33 | | 'shangjiantou'
34 | | 'safetycertificate-f'
35 | | 'xiazai9'
36 | | 'duihao'
37 | | 'funnel'
38 | | 'daohangdizhi'
39 | | 'xiajiantou'
40 | | 'fanhui'
41 | | 'sousuo'
42 | | 'loading'
43 |
44 |
45 | export interface EIconProps extends StandardProps {
46 | black?: boolean
47 | type: EIconType
48 | size?: number
49 | color?: string
50 | }
51 |
52 | const EIcon: FC = (props) => {
53 | const { black, type, size, className, color, ...restProps } = props
54 | const classes = classnames('icon', `icon-${type}`, className)
55 | const styles = {
56 | display: black ? 'block' : '',
57 | fontSize: setstylepx(size),
58 | color,
59 | }
60 | return
61 | }
62 |
63 | EIcon.defaultProps = {
64 | black: false,
65 | size: 38,
66 | }
67 | export default EIcon
68 |
--------------------------------------------------------------------------------
/src/pages/shop/components/ShopItem/ShopItem.scss:
--------------------------------------------------------------------------------
1 | .shopitem {
2 | overflow: hidden;
3 | display: flex;
4 | padding-bottom: 30px;
5 | .shopitem-left {
6 | width: 190px;
7 | height: 190px;
8 | margin-right: 20px;
9 |
10 | .shopitem-left-img {
11 | width: 190px;
12 | height: 190px;
13 | }
14 | }
15 |
16 | .shopitem-right {
17 | overflow: hidden;
18 | display: flex;
19 | flex: 1;
20 | flex-direction: column;
21 | justify-content: space-between;
22 | height: 190px;
23 | .shopitem-title {
24 | overflow: hidden;
25 | color: #333;
26 | font-size: 30px;
27 | font-weight: 600;
28 | white-space: nowrap;
29 | text-overflow: ellipsis;
30 | }
31 |
32 | .shopitem-intro {
33 | color: #999;
34 | font-size: 24px;
35 | }
36 |
37 | .shopitem-pingfen {
38 | color: #999;
39 | font-size: 24px;
40 | }
41 | .shopitem-num {
42 | display: flex;
43 | align-items: center;
44 | justify-content: space-between;
45 | .shopitem-num-price {
46 | color: #ff5339;
47 | font-size: 30px;
48 | display: flex;
49 | align-items: center;
50 | &::before {
51 | content: '\A5';
52 | display: inline-block;
53 | font-size: 24px;
54 | }
55 | .shopitem-num-price-left {
56 | color: #ff5339;
57 | font-size: 30px;
58 | }
59 | .shopitem-num-price-right {
60 | padding-left: 14px;
61 | color: #999;
62 | font-size: 24px;
63 | text-decoration: line-through;
64 | }
65 | }
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/assets/styles/_variables.scss:
--------------------------------------------------------------------------------
1 | // body
2 | $body-line-height: 1.2 !default;
3 | $body-font-size: 28px !default;
4 | $body-font-famify: 'Helvetica Neue', Tahoma, Arial, PingFangSC-Regular,
5 | 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif !default;
6 |
7 | // 字体颜色
8 | $white-color: #ffffff !default;
9 | $black-color: #000000 !default;
10 | $orange-color: #ff4b33 !default;
11 | $blue-color: #2395ff !default;
12 | $green-color: #38ca73 !default;
13 | $color-333: #333333 !default;
14 | $color-666: #666666 !default;
15 | $color-777: #777777 !default;
16 | $color-999: #999999 !default;
17 | $color-ddd:#dddddd !default;
18 |
19 | // 字体大小
20 | $font-size-41: 41px !default;
21 | $font-size-38: 38px !default;
22 | $font-size-36: 36px !default;
23 | $font-size-34: 34px !default;
24 | $font-size-32: 32px !default;
25 | $font-size-30: 30px !default;
26 | $font-size-28: 28px !default;
27 | $font-size-26: 26px !default;
28 | $font-size-24: 24px !default;
29 | $font-size-22: 22px !default;
30 | $font-size-20: 20px !default;
31 |
32 | // 加粗
33 | $font-weight: 700 !default;
34 |
35 | // 渐变背景
36 | $defualt-background-image: linear-gradient(90deg, #0af, #0085ff) !default;
37 | $tag-background-image: linear-gradient(45deg, #0085ff, #0af) !default;
38 | $svip-background-image: linear-gradient(90deg, #ffefc4, #f3dda0) !default;
39 | $brand-background-image: linear-gradient(-139deg, #fff100, #ffe339) !default;
40 | $count-background-image: linear-gradient(-90deg, #ff7416, #ff3c15 98%) !default;
41 | $bg-background-image: linear-gradient(
42 | 0deg,
43 | #f5f5f5,
44 | #f5f5f5 65%,
45 | hsla(0, 0%, 96%, 0.3) 75%,
46 | hsla(0, 0%, 96%, 0)
47 | ),
48 | linear-gradient(270deg, #0085ff, #0af) !default;
49 |
50 | $background-f5f5f5: #f5f5f5;
51 |
--------------------------------------------------------------------------------
/src/pages/order/components/Ordercard/Ordercard.scss:
--------------------------------------------------------------------------------
1 | .ordercard {
2 | margin-bottom: 20px;
3 | padding: 20px;
4 | background: #fff;
5 | .ordercard-top {
6 | display: flex;
7 | .ordercard-top-left {
8 | margin-right: 20px;
9 | .ordercard-top-img {
10 | width: 64px;
11 | height: 64px;
12 | }
13 | }
14 |
15 | .ordercard-top-right {
16 | flex: 1;
17 | .ordercard-head {
18 | padding-bottom: 20px;
19 | border-bottom: 1px #f5f5f5 solid;
20 | .ordercard-head-top {
21 | display: flex;
22 | align-items: center;
23 | justify-content: space-between;
24 | .ordercard-head-top-title {
25 | font-size: 32px;
26 | }
27 |
28 | .ordercard-head-top-tip {
29 | color: #2395ff;
30 | }
31 | }
32 |
33 | .ordercard-head-time {
34 | padding-top: 10px;
35 | color: #999;
36 | font-size: 24px;
37 | line-height: 1.2;
38 | }
39 | }
40 |
41 | .ordercard-text {
42 | display: flex;
43 | justify-content: space-between;
44 | padding: 20px 0;
45 | border-bottom: 1px #f5f5f5 solid;
46 |
47 | .ordercard-text-title {
48 | color: #666;
49 | }
50 |
51 | .ordercard-text-price {
52 | color: #333;
53 | font-weight: 600;
54 | }
55 | }
56 | }
57 | }
58 |
59 | .ordercard-bottom {
60 | display: flex;
61 | justify-content: flex-end;
62 | margin-top: 20px;
63 | .ordercard-bottom-button {
64 | padding: 10px;
65 | border: 1px currentColor solid;
66 | color: #2395ff;
67 | line-height: 1.2;
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/pages/search/components/SearchItem/SearchItem.tsx:
--------------------------------------------------------------------------------
1 | import Taro from '@tarojs/taro'
2 | import React, { useMemo, memo, FC } from 'react'
3 | import { View, Image, Text, RichText } from '@tarojs/components'
4 | import imgUrl from '../../../../utils/imgUrl'
5 |
6 | import './SearchItem.scss'
7 |
8 | interface SearchItemProps {
9 | restaurant: any
10 | keyword: string
11 | }
12 | const SearchItem: FC = (props) => {
13 | const { restaurant, keyword } = props
14 | const shopName = useMemo(() => {
15 | return restaurant.name.replace(
16 | keyword,
17 | `${keyword}`
18 | )
19 | }, [restaurant, keyword])
20 |
21 | const goShop = () => {
22 | Taro.navigateTo({ url: '/pages/myshop/index' })
23 | }
24 |
25 | return (
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
38 | {restaurant.tags[0].name}
39 |
40 |
41 |
42 | 接受预定,{restaurant.next_business_time}开始配送
43 |
44 |
45 | 评价 {restaurant.rating}
46 |
47 |
48 | )
49 | }
50 |
51 | export default memo(SearchItem)
52 |
--------------------------------------------------------------------------------
/src/components/NavBar/NavBar.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Taro from '@tarojs/taro'
3 | import { View, Navigator } from '@tarojs/components'
4 | import classnames from 'classnames'
5 | import EIcon, { EIconProps } from '../EIcon/EIcon'
6 |
7 | import './NavBar.scss'
8 |
9 | type onRightHref = () => void
10 |
11 | interface INavBarProps extends Omit {
12 | icon?: EIconProps['type']
13 | onIconClick?: () => void
14 | title?: string
15 | rightText?: string
16 | rightHref?: string | onRightHref
17 | }
18 |
19 | const NavBar: React.FC = (props) => {
20 | const {
21 | icon,
22 | onIconClick,
23 | title,
24 | rightText,
25 | rightHref,
26 | className,
27 | children,
28 | ...restProps
29 | } = props
30 | const classes = classnames('navbar', className)
31 |
32 | const handleRightHref = () => {
33 | if (rightHref && rightText) {
34 | if (typeof rightHref === 'string') {
35 | return (
36 |
37 | {rightText}
38 |
39 | )
40 | } else {
41 | return (
42 |
43 | {rightText}
44 |
45 | )
46 | }
47 | }
48 | }
49 |
50 | return (
51 |
52 | {icon && (
53 |
54 | )}
55 | {title && {title}}
56 | {handleRightHref()}
57 | {children}
58 |
59 | )
60 | }
61 |
62 | NavBar.defaultProps = {
63 | onIconClick: () => {
64 | Taro.navigateBack({ delta: -1 })
65 | },
66 | }
67 | export default NavBar
68 |
--------------------------------------------------------------------------------
/src/pages/address/components/Search/Search.tsx:
--------------------------------------------------------------------------------
1 | // 选择城市,搜索地址
2 | import React, { FC } from 'react'
3 | import { View, Input, Text, Navigator } from '@tarojs/components'
4 | import { InputProps } from '@tarojs/components/types/Input'
5 | import { BaseEventOrig } from '@tarojs/components/types/common'
6 | import { Address } from '../../../../redux/interface'
7 |
8 | import './Search.scss'
9 |
10 | interface SearchProps {
11 | cityUrl: string
12 | currentAddress: Address
13 | searchValue: string
14 | onInput: (e: BaseEventOrig) => void
15 | onDelSearch: () => void
16 | }
17 |
18 | const Search: FC = (props) => {
19 | const { cityUrl, currentAddress, searchValue, onInput, onDelSearch } = props
20 | return (
21 |
22 | {/* 选择城市 */}
23 |
24 |
25 | {currentAddress.city ? currentAddress.city : '选择城市'}
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | onInput(e)}
40 | />
41 | {searchValue && (
42 |
43 |
44 |
45 | )}
46 |
47 |
48 | )
49 | }
50 |
51 | export default Search
52 |
--------------------------------------------------------------------------------
/src/pages/profile/info/username/index.tsx:
--------------------------------------------------------------------------------
1 | // 修改用户名
2 | import Taro, { FC } from '@tarojs/taro'
3 | import React, { useState } from 'react'
4 | import { View, Input, Button } from '@tarojs/components'
5 | import { InputProps } from '@tarojs/components/types/Input'
6 | import { BaseEventOrig } from '@tarojs/components/types/common'
7 | import API from '../../../../api'
8 |
9 | import './index.scss'
10 |
11 | const UserName: FC = () => {
12 | const [userName, setUserName] = useState('')
13 | const [flag, setFlag] = useState(true)
14 |
15 | // 修改用户名
16 | const handleSetUserName = (e: BaseEventOrig) => {
17 | const { value } = e.detail
18 | if (value.length >= 5 && value.length <= 24) {
19 | setUserName(value)
20 | setFlag(false)
21 | } else {
22 | setFlag(true)
23 | }
24 | }
25 |
26 | // 提交
27 | const handleSubmit = async () => {
28 | if (flag) {
29 | return
30 | }
31 |
32 | const { err, res } = await API.reqSetUserName({ userName })
33 |
34 | if (err) {
35 | console.log(err)
36 | return
37 | }
38 |
39 | if (res.code === 0) {
40 | Taro.navigateBack({ delta: 1 })
41 | }
42 | }
43 |
44 | return (
45 |
46 |
47 |
53 | 修改用户名(5-24个字)
54 |
61 |
62 |
63 | )
64 | }
65 |
66 | export default UserName
67 |
--------------------------------------------------------------------------------
/src/pages/shop/components/ShopInfo/ShopInfo.scss:
--------------------------------------------------------------------------------
1 | .shopinfo {
2 | background: #f5f5f5;
3 | .peisong-img {
4 | width: 100%;
5 | }
6 | .shopinfo-bgcolor {
7 | color: #666;
8 | }
9 | .peisong-content {
10 | .peisong-title {
11 | padding: 10px;
12 | color: #333;
13 | font-weight: 600;
14 | }
15 | .peisong-info {
16 | overflow: hidden;
17 | display: -webkit-box;
18 | -webkit-box-orient: vertical;
19 |
20 | -webkit-line-clamp: 2;
21 | }
22 | }
23 |
24 | .serve {
25 | display: flex;
26 | line-height: 1.2;
27 | .icon-name {
28 | margin-right: 10px;
29 | padding: 0 6px;
30 | }
31 | .serve-descripton {
32 | }
33 | }
34 | .scene {
35 | display: flex;
36 | flex-wrap: wrap;
37 | .scene-item {
38 | position: relative;
39 | width: 150px;
40 | height: 150px;
41 | margin-right: 10px;
42 | .scene-img {
43 | width: 150px;
44 | height: 150px;
45 | }
46 | .scene-name {
47 | position: absolute;
48 | right: 0;
49 | bottom: 0;
50 | left: 0;
51 | background: rgba(0, 0, 0, .5);
52 | color: #fff;
53 | font-size: 24px;
54 | text-align: center;
55 | }
56 | }
57 | }
58 | .description {
59 | padding-bottom: 20px;
60 | border-bottom: 1px #eee solid;
61 | color: #666;
62 | }
63 | .info {
64 | display: flex;
65 | justify-content: space-between;
66 | padding: 20px 0;
67 | border-bottom: 1px #eee solid;
68 | .info-left {
69 | color: #333;
70 | font-weight: 600;
71 | }
72 | .info-right {
73 | color: #666;
74 | }
75 | .tel {
76 | color: #00a6ff;
77 | }
78 | }
79 | .qualification {
80 | color: #333;
81 | font-weight: 600;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/pages/shop/components/ShopItem/ShopItem.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View, Image, Text } from '@tarojs/components'
3 | import imgUrl from '../../../../utils/imgUrl'
4 | import ShopButton from '../../../../components/ShopButton/ShopButton'
5 |
6 | import './ShopItem.scss'
7 |
8 | interface ShopItemProps {
9 | onUpdateCart
10 | food
11 | count
12 | }
13 |
14 | const ShopItem: FC = (props) => {
15 | const { onUpdateCart, food, count } = props
16 | return (
17 |
18 | {food.image_path ? (
19 |
20 |
25 |
26 | ) : null}
27 |
28 | {food.name}
29 | {food.materials}
30 |
31 | 月售{food.month_sales}份 好评率{food.satisfy_rate}%
32 |
33 |
34 |
35 |
36 | {food.price}
37 |
38 |
39 | {food.origin_price !== food.price && (
40 |
41 |
42 | ¥{food.origin_price}
43 |
44 |
45 | )}
46 |
47 |
48 |
49 |
50 |
51 |
52 | )
53 | }
54 |
55 | export default ShopItem
56 |
--------------------------------------------------------------------------------
/src/components/EList/EItem.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View, Image } from '@tarojs/components'
3 | import classnames from 'classnames'
4 | import EIcon from '../EIcon/EIcon'
5 |
6 | import './EItem.scss'
7 |
8 | type Arrow = 'jiantou1' | 'none'
9 | export interface EItemProps {
10 | thumb?: string | React.ReactNode
11 | extra?: string | React.ReactNode
12 | arrow?: Arrow
13 | onClick?: () => void
14 | className?: string
15 | }
16 |
17 | const EItem: FC = (props) => {
18 | const { thumb, extra, arrow, onClick, className, children } = props
19 | const classes = classnames('ele-eitem', className)
20 |
21 | const isThumb = () => {
22 | if (typeof thumb === 'string') {
23 | return
24 | } else {
25 | return thumb
26 | }
27 | }
28 |
29 | const isExtra = () => {
30 | if (typeof extra === 'string') {
31 | return {extra}
32 | } else {
33 | return extra
34 | }
35 | }
36 |
37 | const isArrow = () => {
38 | if (arrow === 'none') {
39 | return false
40 | } else {
41 | return true
42 | }
43 | }
44 |
45 | return (
46 |
47 |
48 | {isThumb && isThumb()}
49 |
50 | {children}
51 | {isExtra && isExtra()}
52 | {isArrow() && (
53 |
59 | )}
60 |
61 |
62 |
63 | )
64 | }
65 | EItem.defaultProps = {
66 | arrow: 'jiantou1',
67 | }
68 | export default EItem
69 |
--------------------------------------------------------------------------------
/src/components/UserAddress/UserAddress.scss:
--------------------------------------------------------------------------------
1 | .useraddress {
2 | background: #f5f5f5;
3 | height: calc(100vh - 100px);
4 | color: #333;
5 | font-size: 30px;
6 | .useraddress-item {
7 | display: flex;
8 | align-items: center;
9 | background: #fff;
10 | padding-left: 20px;
11 | .item-left {
12 | width: 120px;
13 | font-weight: 600;
14 | }
15 |
16 | .item-right {
17 | flex: 1;
18 | margin-left: 20px;
19 | display: flex;
20 | align-items: center;
21 | justify-content: space-between;
22 | margin-right: 20px;
23 | .item-right-input {
24 | flex: 1;
25 | border-bottom: 1px #f0f0f0 solid;
26 | padding: 25px 0;
27 | }
28 | .item-right-text {
29 | flex: 1;
30 | padding: 25px 0;
31 | border-bottom: 1px #f0f0f0 solid;
32 | }
33 | .icon {
34 | font-size: 30px;
35 | color: #bbb;
36 | }
37 | .br {
38 | border: none;
39 | }
40 | }
41 | }
42 | .useraddress-sex {
43 | background: #fff;
44 | padding: 20px 0 0 160px;
45 | display: flex;
46 |
47 | .sex-item {
48 | border: 1px #ededed solid;
49 | padding: 10px 35px;
50 | border-radius: 10px;
51 | color: #787878;
52 | &:last-child {
53 | margin-left: 20px;
54 | }
55 | }
56 | .sex-active {
57 | background: #eef7ff;
58 | color: #2395ff;
59 | }
60 | }
61 | .address-submit {
62 | margin: 30px 20px 0 20px;
63 | .address-submit-button {
64 | background: #00d762;
65 | font-size: 34px;
66 | font-weight: 600;
67 | border: none;
68 | color: #fff;
69 | outline: none;
70 | border-radius: 4px;
71 | &:after {
72 | border: none;
73 | border-radius: 0;
74 | }
75 | &:active {
76 | background: #47cf84;
77 | }
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/components/EButton/EButton.scss:
--------------------------------------------------------------------------------
1 | $default-color: #56d176;
2 | $blue-color: #008cfe;
3 | taro-button-core + taro-button-core {
4 | margin-top: 0 !important;
5 | }
6 | .ele-ebutton {
7 | border: none;
8 | background: none;
9 | outline: none;
10 | font-size: 28px;
11 | border-radius: 6px;
12 | @include flex;
13 | &::after {
14 | border: none;
15 | }
16 | }
17 | .ele-ebutton-loading {
18 | padding-right: 10px;
19 | &::after {
20 | content: '';
21 | display: block;
22 | width: 26px;
23 | height: 26px;
24 | animation: isloading 0.8s infinite linear;
25 | border-left: 2.5px transparent solid;
26 | border-right: 2.5px transparent solid;
27 | border-top: 2.5px transparent solid;
28 | border-bottom: 2.5px #f5f5f5 solid;
29 | border-radius: 50%;
30 | }
31 | }
32 | .ele-ebutton-default {
33 | border: 1px solid $blue-color;
34 | width: 240px;
35 | height: 80px;
36 | color: $blue-color;
37 | &:active {
38 | color: lighten($blue-color, 15%) !important;
39 | border: 1px solid lighten($blue-color, 15%) !important;
40 | background: none !important;
41 | }
42 | }
43 |
44 | .ele-ebutton-green {
45 | width: 240px;
46 | height: 80px;
47 | background: $default-color;
48 | color: $white-color;
49 | &:active {
50 | color: $white-color !important;
51 | background: lighten($default-color, 15%) !important;
52 | }
53 | }
54 |
55 | .ele-ebutton-blue {
56 | width: 240px;
57 | height: 80px;
58 | background: $blue-color;
59 | color: $white-color;
60 | &:active {
61 | color: $white-color !important;
62 | background: lighten($blue-color, 15%) !important;
63 | }
64 | }
65 | .ele-ebutton-href {
66 | color: $color-333;
67 | &:active {
68 | color: $color-666 !important;
69 | background: none !important;
70 | }
71 | }
72 |
73 | @keyframes isloading {
74 | 0% {
75 | transform: rotate(0deg);
76 | }
77 | 100% {
78 | transform: rotate(360deg);
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/src/pages/clearing/components/CartInfo/CartInfo.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View, Image, Text } from '@tarojs/components'
3 | import imgUrl from '../../../../utils/imgUrl'
4 |
5 | import './CartInfo.scss'
6 |
7 | interface CartInfoProps {
8 | cartInfo
9 | shopName
10 | }
11 |
12 | const CartInfo: FC = (props) => {
13 | const { cartInfo, shopName } = props
14 | return (
15 |
16 | {shopName}
17 |
18 | {cartInfo.foods.map((food) => {
19 | return (
20 |
21 |
22 | {food.name}
23 | ×{food.count}
24 |
25 | {Number(food.origin_price) !== food.lowest_price
26 | ? ' ¥' + food.origin_price * food.count
27 | : null}
28 |
29 |
30 | ¥{food.count * food.lowest_price}
31 |
32 |
33 | )
34 | })}
35 |
36 | 包装费
37 | ¥{cartInfo.goodTotal}
38 |
39 |
40 | 配送费
41 | ¥{cartInfo.boxPrice}
42 |
43 |
44 |
45 | 小计¥
46 |
47 | {cartInfo.totalPrice + cartInfo.goodTotal + cartInfo.boxPrice}
48 |
49 |
50 |
51 | )
52 | }
53 |
54 | export default CartInfo
55 |
--------------------------------------------------------------------------------
/src/pages/city/components/List/List.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC, memo } from 'react'
2 | import { ScrollView, View } from '@tarojs/components'
3 | import { Address } from '../../../../redux/interface'
4 | import {
5 | CityList as CityListInterface,
6 | Cities,
7 | } from '../../../../api/interface'
8 | import setstylepx from '../../../../utils/setstylepx'
9 |
10 | import './List.scss'
11 |
12 | interface ListProps {
13 | currentAddress: Address
14 | cityList: CityListInterface[]
15 | onSelectCity: (city: Cities) => void
16 | infoView: string
17 | }
18 |
19 | const List: FC = (props) => {
20 | const { currentAddress, cityList, onSelectCity, infoView } = props
21 | return (
22 |
27 |
28 | 当前定位城市
29 |
30 | {currentAddress.city ? currentAddress.city : '定位当前城市失败'}
31 |
32 |
33 | {cityList.map((cityItem) => {
34 | return (
35 |
40 |
41 | {cityItem.idx}
42 |
43 |
44 | {cityItem.cities.map((city) => {
45 | return (
46 | onSelectCity(city)}
50 | >
51 | {city.name}
52 |
53 | )
54 | })}
55 |
56 | )
57 | })}
58 |
59 | )
60 | }
61 |
62 | export default memo(List)
63 |
--------------------------------------------------------------------------------
/src/pages/profile/address/components/AddressRow/AddressRow.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View, Text } from '@tarojs/components'
3 | import { Address } from '../../../../../redux/interface'
4 | import './AddressRow.scss'
5 |
6 | interface AddressRowProps {
7 | address: Address
8 | currentAddress: Address
9 | onDelAddress: (id: Address['id']) => void
10 | onEditAddress: (address: Address) => void
11 | selectFlag: boolean
12 | onSelectUserAddress: (address: Address) => void
13 | }
14 |
15 | const AddressRow: FC = (props) => {
16 | const {
17 | address,
18 | onDelAddress,
19 | onEditAddress,
20 | selectFlag,
21 | currentAddress,
22 | onSelectUserAddress,
23 | } = props
24 | return (
25 |
26 | {selectFlag && currentAddress.id === address.id && (
27 |
28 | )}
29 | onSelectUserAddress(address)}
32 | >
33 |
34 | {address.name}
35 | {address.sex === '1' ? '先生' : '女士'}
36 | {address.phone}
37 |
38 |
39 | {address.address + address.address_detail}
40 |
41 |
42 |
43 | onEditAddress(address)}
46 | >
47 |
48 |
49 |
50 | onDelAddress(address.id)}
53 | >
54 |
55 |
56 |
57 | )
58 | }
59 |
60 | export default AddressRow
61 |
--------------------------------------------------------------------------------
/config/index.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 |
3 | const config = {
4 | projectName: 'ele-client',
5 | date: '2020-5-27',
6 | designWidth: 750,
7 | deviceRatio: {
8 | 640: 2.34 / 2,
9 | 750: 1,
10 | 828: 1.81 / 2,
11 | },
12 | sourceRoot: 'src',
13 | outputRoot: 'dist',
14 | plugins: [],
15 | defineConstants: {},
16 | copy: {
17 | patterns: [
18 | // {
19 | // from: 'sitemap.json',
20 | // to: 'dist/sitemap.json',
21 | // },
22 | ],
23 | options: {},
24 | },
25 | sass: {
26 | resource: path.join(__dirname, '../src/assets/styles/index.scss'),
27 | },
28 | alias: {
29 | // '@/src': path.resolve(__dirname, '..', 'src'),
30 | },
31 | framework: 'react',
32 | mini: {
33 | postcss: {
34 | pxtransform: {
35 | enable: true,
36 | config: {},
37 | },
38 | url: {
39 | enable: true,
40 | config: {
41 | limit: 1024, // 设定转换尺寸上限
42 | },
43 | },
44 | cssModules: {
45 | enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true
46 | config: {
47 | namingPattern: 'module', // 转换模式,取值为 global/module
48 | generateScopedName: '[name]__[local]___[hash:base64:5]',
49 | },
50 | },
51 | },
52 | },
53 | h5: {
54 | publicPath: '/',
55 | staticDirectory: 'static',
56 | postcss: {
57 | autoprefixer: {
58 | enable: true,
59 | config: {},
60 | },
61 | cssModules: {
62 | enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true
63 | config: {
64 | namingPattern: 'module', // 转换模式,取值为 global/module
65 | generateScopedName: '[name]__[local]___[hash:base64:5]',
66 | },
67 | },
68 | },
69 | router: {
70 | mode: 'browser', // browser 或 'hash'
71 | },
72 | },
73 | }
74 |
75 | module.exports = function (merge) {
76 | if (process.env.NODE_ENV === 'development') {
77 | return merge({}, config, require('./dev'))
78 | }
79 | return merge({}, config, require('./prod'))
80 | }
81 |
--------------------------------------------------------------------------------
/src/assets/images/default-shop.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/pages/order/components/Ordercard/Ordercard.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC, useMemo } from 'react'
2 | import { View, Image } from '@tarojs/components'
3 | import dayjs from 'dayjs'
4 | import imgUrl from '../../../../utils/imgUrl'
5 |
6 | import EButton from '../../../../components/EButton/EButton'
7 |
8 | import './Ordercard.scss'
9 |
10 | interface OrdercardProps {
11 | orderData: any
12 | onLink: (orderData: any) => void
13 | }
14 |
15 | const Ordercard: FC = (props) => {
16 | const { orderData, onLink } = props
17 |
18 | const goodNames = useMemo(() => {
19 | const foods = orderData.foods
20 | const lc = foods.length
21 | let names = ''
22 | foods.forEach((food, i) => {
23 | if (i === 0) {
24 | names += food.name + ','
25 | } else if (i === 1) {
26 | names += food.name
27 | }
28 | })
29 | names += `等${lc}件商品`
30 | return names
31 | }, [orderData])
32 |
33 | return (
34 | onLink(orderData)}>
35 |
36 |
37 |
41 |
42 |
43 |
44 |
45 |
46 | {orderData.shopName}
47 |
48 | 订单完成
49 |
50 |
51 | {dayjs(orderData.createTime).format('YYYY-MM-DD HH:mm:ss')}
52 |
53 |
54 |
55 | {goodNames}
56 |
57 | ¥{orderData.totalPrice}
58 |
59 |
60 |
61 |
62 |
63 | 再来一单
64 |
65 |
66 | )
67 | }
68 |
69 | export default Ordercard
70 |
--------------------------------------------------------------------------------
/src/pages/order/index.tsx:
--------------------------------------------------------------------------------
1 | // 订单
2 | import Taro from '@tarojs/taro'
3 | import React, { FC, useState, useEffect, useCallback } from 'react'
4 | import { View } from '@tarojs/components'
5 | import API from '../../api'
6 |
7 | import FooterNav from '../../components/FooterNav/FooterNav'
8 | import NoDataTip, { NoDataTipProps } from '../../components/NoDataTip/NoDataTip'
9 | import EIsLoading from '../../components/ELoading/ELoading'
10 | import Ordercard from './components/Ordercard/Ordercard'
11 |
12 | import './index.scss'
13 |
14 | const noLogin = {
15 | img: '//fuss10.elemecdn.com/d/60/70008646170d1f654e926a2aaa3afpng.png',
16 | title: '登录后查看外卖订单',
17 | btnContent: '立即登录',
18 | onButtonClick: () => {
19 | Taro.reLaunch({ url: '/pages/login/index' })
20 | },
21 | }
22 | const noOrder = {
23 | img: '//fuss10.elemecdn.com/8/c8/bbe5984003cb26fc7b445a4a15195png.png',
24 | title: '你还没有订餐哦',
25 | }
26 |
27 | const Order: FC = () => {
28 | // 订单数据
29 | const [orderDatas, setOrderDatas] = useState([])
30 | // 未登录/无订单内容提示
31 | const [noData, setNoData] = useState({} as NoDataTipProps)
32 | // 数据加载状态
33 | const [loading, setLoading] = useState(false)
34 |
35 | useEffect(() => {
36 | setLoading(true)
37 | API.getOrder().then(({ err, res }) => {
38 | if (err) {
39 | setNoData(noLogin)
40 | setLoading(false)
41 | return
42 | }
43 | if (res.code === 0) {
44 | setOrderDatas(res.data)
45 | if (res.data.length === 0) {
46 | setNoData(noOrder)
47 | }
48 | setLoading(false)
49 | }
50 | })
51 | }, [])
52 |
53 | // 跳转订单详情
54 | const goOrderDetail = useCallback((data) => {
55 | Taro.navigateTo({ url: `/pages/order/detail/index?id=${data.orderNum}` })
56 | }, [])
57 |
58 | return (
59 |
60 |
61 | {loading && }
62 |
63 | {orderDatas.map((orderData, i) => (
64 |
69 | ))}
70 |
71 | {noData.img && }
72 |
73 |
74 |
75 | )
76 | }
77 | export default Order
78 |
--------------------------------------------------------------------------------
/src/pages/shop/index.scss:
--------------------------------------------------------------------------------
1 | .default-shop-img {
2 | width: 100%;
3 | height: 100%;
4 | }
5 | .myshop {
6 | height: 100vh;
7 | -webkit-overflow-scrolling: touch; //ios不流畅问题
8 |
9 | .myshop-content {
10 | margin-top: 30px;
11 | .myshop-order {
12 | .myshop-order-banner {
13 | height: auto;
14 | margin: 20px 0;
15 | padding: 0 32px;
16 |
17 | .myshop-order-banner-img {
18 | width: 100%;
19 | height: 170px;
20 | border-radius: 5px;
21 | }
22 | }
23 |
24 | .myshop-order-recommend {
25 | margin-bottom: 30px;
26 | margin-left: 32px;
27 |
28 | .myshop-order-recommend-title {
29 | margin-right: 32px;
30 | color: #333;
31 | font-size: 32px;
32 | font-weight: 600;
33 | }
34 |
35 | .myshop-order-recommend-main {
36 | margin-top: 20px;
37 | white-space: nowrap;
38 | -webkit-overflow-scrolling: touch; //ios不流畅问题
39 | }
40 | }
41 |
42 | .myshop-order-main {
43 | .myshop-order-main-content {
44 | display: flex;
45 | .myshop-order-main-left {
46 | width: 150px;
47 | height: 100%;
48 | -webkit-overflow-scrolling: touch; //ios不流畅问题
49 | }
50 | .myshop-order-main-right {
51 | width: 550px;
52 | margin-left: 20px;
53 | height: 100%;
54 | -webkit-overflow-scrolling: touch; //ios不流畅问题
55 | .myshop-order-main-right-block {
56 | .myshop-order-main-right-title {
57 | display: flex;
58 | padding: 10px 0;
59 | .myshop-order-main-right-name {
60 | color: #666;
61 | font-size: 24px;
62 | font-weight: 600;
63 | }
64 | .myshop-order-main-right-des {
65 | padding-left: 10px;
66 | color: #666;
67 | font-size: 24px;
68 | }
69 | }
70 | }
71 | }
72 | }
73 | }
74 | }
75 | .myshop-appraise {
76 | background: #f5f5f5;
77 | }
78 | }
79 | }
80 |
81 | .test {
82 | position: absolute;
83 | bottom: 100px;
84 | width: 100%;
85 | height: 300px;
86 | background: red;
87 | }
88 |
--------------------------------------------------------------------------------
/src/redux/actions/user.ts:
--------------------------------------------------------------------------------
1 | import Taro from '@tarojs/taro'
2 | import API from '../../api'
3 | import {
4 | SETTOKEN,
5 | CURRENTADDRESS,
6 | SETUSERADDRESS,
7 | REMOVETOKEN,
8 | GETUSERADDRESSLIST,
9 | USERADDRESS,
10 | REMOVEUSERADDRESS,
11 | REMOVEUSERADDRESSLIST,
12 | } from '../action-types'
13 |
14 | // 设置token
15 | export const setToken = (token: string) => {
16 | token = `Bearer ${token}`
17 | Taro.setStorageSync('token', token)
18 | return { type: SETTOKEN, payload: token }
19 | }
20 |
21 | // 删除token
22 | export const removeToken = () => {
23 | Taro.removeStorageSync('token')
24 | return { type: REMOVETOKEN }
25 | }
26 |
27 | // 设置地址信息
28 | export const setCurrentAddress = (address) => ({
29 | type: CURRENTADDRESS,
30 | payload: address,
31 | })
32 |
33 | // 初始化ip定位地址
34 | export const initCurrentAddress = () => {
35 | return async (dispatch) => {
36 | const { err, res } = await API.reqIpAddress()
37 |
38 | if (err) {
39 | console.log(err)
40 | return
41 | }
42 |
43 | if (res.code === 0) {
44 | const { city, latitude, longitude, recommend } = res.data
45 | // 保存地址到redux
46 | dispatch(
47 | setCurrentAddress({
48 | city,
49 | address: recommend,
50 | latitude,
51 | longitude,
52 | })
53 | )
54 | } else {
55 | // console.log(result)
56 | }
57 | }
58 | }
59 |
60 | // 清空用户收货地址列表
61 | export const removeUserAddressList = () => ({ type: REMOVEUSERADDRESSLIST })
62 | // 获取用户收货地址列表
63 | const getUserAddressListSync = (userAddressList) => ({
64 | type: GETUSERADDRESSLIST,
65 | payload: userAddressList,
66 | })
67 | export const getUserAddressList = () => {
68 | return async (dispatch) => {
69 | const { err, res } = await API.reqUserAddress()
70 |
71 | if (err) {
72 | dispatch(removeUserAddressList())
73 | dispatch(removeToken())
74 | return
75 | }
76 |
77 | if (res.code === 0) {
78 | dispatch(getUserAddressListSync(res.data))
79 | }
80 | }
81 | }
82 |
83 | // 编辑用户收货地址
84 | export const atUserAddress = (userAddress) => ({
85 | type: USERADDRESS,
86 | payload: userAddress,
87 | })
88 |
89 | // 修改用户收货地址
90 | export const setAtUserAddress = (userAddress) => ({
91 | type: SETUSERADDRESS,
92 | payload: userAddress,
93 | })
94 |
95 | // 清空用户收货地址
96 | export const removeUserAddress = () => ({ type: REMOVEUSERADDRESS })
97 |
--------------------------------------------------------------------------------
/src/pages/shop/components/ShopInfoModal/ShopInfoModal.scss:
--------------------------------------------------------------------------------
1 | .myshop-modal {
2 | position: fixed;
3 | top: 0;
4 | bottom: 0;
5 | left: 0;
6 | right: 0;
7 | background: rgba(0, 0, 0, 0.5);
8 | display: flex;
9 | justify-content: center;
10 | align-items: center;
11 | flex-direction: column;
12 | z-index: 6;
13 | .myshop-modal-main {
14 | background: #fff;
15 | width: 80%;
16 | border-radius: 10px;
17 | .myshop-modal-main-title {
18 | font-size: 41px;
19 | font-weight: 600;
20 | text-align: center;
21 | padding: 20px 50px;
22 | .myshop-modal-main-title-tag {
23 | width: 70px;
24 | font-weight: 600;
25 | font-size: 24px;
26 | background-image: linear-gradient(90deg, #fff100, #ffe339);
27 | color: #6a3709;
28 | padding: 0 4px;
29 | margin-right: 15px;
30 | }
31 | }
32 |
33 | .myshop-modal-main-ul {
34 | display: flex;
35 | .myshop-modal-main-ul-li {
36 | width: 20%;
37 | text-align: center;
38 | .myshop-modal-main-ul-li-title {
39 | font-size: 24px;
40 | font-weight: 600;
41 | }
42 |
43 | .myshop-modal-main-ul-li-tag {
44 | color: #bdbdbd;
45 | font-size: 24px;
46 | }
47 | }
48 | }
49 |
50 | .myshop-modal-main-gongao {
51 | .myshop-modal-main-gongao-title {
52 | display: flex;
53 | align-items: center;
54 | justify-content: center;
55 | color: #999;
56 | padding: 20px 0;
57 | font-size: 26px;
58 | &::after,
59 | &::before {
60 | content: '';
61 | display: block;
62 | width: 40px;
63 | height: 4px;
64 | background-image: linear-gradient(
65 | 90deg,
66 | #fff,
67 | rgb(199, 199, 199) 50%,
68 | #fff
69 | );
70 | }
71 | &::after {
72 | margin-left: 10px;
73 | }
74 | &::before {
75 | margin-right: 10px;
76 | }
77 | }
78 |
79 | .myshop-modal-main-gongao-content {
80 | color: #333;
81 | padding: 0 40px 40px 40px;
82 | }
83 | }
84 | }
85 |
86 | .myshop-modal-clear {
87 | width: 80px;
88 | height: 80px;
89 | font-size: 60px;
90 | color: #fff;
91 | display: flex;
92 | justify-content: center;
93 | align-items: center;
94 | margin-top: 30px;
95 | opacity: 0.5;
96 | }
97 |
98 | .myshop-modal-bg {
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/assets/styles/normalize.scss:
--------------------------------------------------------------------------------
1 | html,
2 | body,
3 | #container,
4 | .taro-tabbar__panel,
5 | #app,
6 | #app > div,
7 | .taro_page {
8 | height: 100%;
9 | width: 100%;
10 | }
11 |
12 | /* #ifndef h5 */
13 | page {
14 | font-size: $body-font-size;
15 | font-family: $body-font-famify;
16 | color: $color-333;
17 | box-sizing: border-box;
18 | height: 100%;
19 | }
20 | /* #endif */
21 |
22 | /* #ifdef h5 */
23 | html {
24 | line-height: $body-line-height !important;
25 | font-family: $body-font-famify;
26 | color: $color-333;
27 | box-sizing: border-box;
28 | user-select: none;
29 | touch-action: manipulation;
30 | text-size-adjust: none;
31 | }
32 | body {
33 | margin: 0;
34 | padding: 0;
35 | line-height: $body-line-height !important;
36 | font-size: $body-font-size;
37 | }
38 |
39 | button,
40 | input,
41 | optgroup,
42 | select,
43 | textarea {
44 | font-family: inherit; /* 1 */
45 | font-size: 100%; /* 1 */
46 | line-height: $body-line-height; /* 1 */
47 | margin: 0; /* 2 */
48 | }
49 |
50 | button,
51 | input {
52 | /* 1 */
53 | overflow: visible;
54 | }
55 |
56 | button,
57 | select {
58 | /* 1 */
59 | text-transform: none;
60 | }
61 |
62 | button,
63 | [type="button"],
64 | [type="reset"],
65 | [type="submit"] {
66 | -webkit-appearance: button;
67 | }
68 |
69 | button::-moz-focus-inner,
70 | [type="button"]::-moz-focus-inner,
71 | [type="reset"]::-moz-focus-inner,
72 | [type="submit"]::-moz-focus-inner {
73 | border-style: none;
74 | padding: 0;
75 | }
76 |
77 | button:-moz-focusring,
78 | [type="button"]:-moz-focusring,
79 | [type="reset"]:-moz-focusring,
80 | [type="submit"]:-moz-focusring {
81 | outline: 1px dotted ButtonText;
82 | }
83 |
84 | [type="checkbox"],
85 | [type="radio"] {
86 | box-sizing: border-box; /* 1 */
87 | padding: 0; /* 2 */
88 | }
89 |
90 | [type="number"]::-webkit-inner-spin-button,
91 | [type="number"]::-webkit-outer-spin-button {
92 | height: auto;
93 | }
94 |
95 | [type="search"] {
96 | -webkit-appearance: textfield; /* 1 */
97 | outline-offset: -2px; /* 2 */
98 | }
99 |
100 | [type="search"]::-webkit-search-decoration {
101 | -webkit-appearance: none;
102 | }
103 |
104 | ::-webkit-file-upload-button {
105 | -webkit-appearance: button; /* 1 */
106 | font: inherit; /* 2 */
107 | }
108 | /* #endif */
109 |
110 | .ellipsis {
111 | overflow: hidden;
112 | white-space: nowrap;
113 | text-overflow: ellipsis;
114 | }
115 |
116 | .ele-hide {
117 | display: none !important;
118 | }
119 | .ele-show {
120 | display: block !important;
121 | }
122 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ele-ts-client",
3 | "version": "1.0.0",
4 | "private": true,
5 | "description": "仿饿了么H5, 可编译跨端 H5 微信小程序",
6 | "templateInfo": {
7 | "name": "redux",
8 | "typescript": true,
9 | "css": "sass"
10 | },
11 | "scripts": {
12 | "build:weapp": "taro build --type weapp",
13 | "build:swan": "taro build --type swan",
14 | "build:alipay": "taro build --type alipay",
15 | "build:tt": "taro build --type tt",
16 | "build:h5": "taro build --type h5",
17 | "build:rn": "taro build --type rn",
18 | "build:qq": "taro build --type qq",
19 | "build:jd": "taro build --type jd",
20 | "build:quickapp": "taro build --type quickapp",
21 | "dev:weapp": "npm run build:weapp -- --watch",
22 | "dev:swan": "npm run build:swan -- --watch",
23 | "dev:alipay": "npm run build:alipay -- --watch",
24 | "dev:tt": "npm run build:tt -- --watch",
25 | "dev:h5": "npm run build:h5 -- --watch",
26 | "dev:rn": "npm run build:rn -- --watch",
27 | "dev:qq": "npm run build:qq -- --watch",
28 | "dev:jd": "npm run build:jd -- --watch",
29 | "dev:quickapp": "npm run build:quickapp -- --watch"
30 | },
31 | "browserslist": [
32 | "last 3 versions",
33 | "Android >= 4.1",
34 | "ios >= 8"
35 | ],
36 | "author": "",
37 | "license": "MIT",
38 | "dependencies": {
39 | "@babel/runtime": "^7.7.7",
40 | "@tarojs/components": "3.0.7",
41 | "@tarojs/react": "3.0.7",
42 | "@tarojs/runtime": "3.0.7",
43 | "@tarojs/taro": "3.0.7",
44 | "@types/classnames": "^2.2.10",
45 | "@types/react-redux": "^7.1.9",
46 | "@types/react-transition-group": "^4.4.0",
47 | "await-to-js": "^2.1.1",
48 | "classnames": "^2.2.6",
49 | "dayjs": "^1.8.34",
50 | "lodash": "^4.17.20",
51 | "react": "^16.10.0",
52 | "react-dom": "^16.10.0",
53 | "react-redux": "^7.2.0",
54 | "react-transition-group": "^4.4.1",
55 | "redux": "^4.0.0",
56 | "redux-logger": "^3.0.6",
57 | "redux-thunk": "^2.3.0",
58 | "tua-body-scroll-lock": "^1.1.0"
59 | },
60 | "devDependencies": {
61 | "@babel/core": "^7.8.0",
62 | "@tarojs/mini-runner": "3.0.7",
63 | "@tarojs/webpack-runner": "3.0.7",
64 | "@types/react": "^16.9.46",
65 | "@types/webpack-env": "^1.13.6",
66 | "@typescript-eslint/eslint-plugin": "^2.x",
67 | "@typescript-eslint/parser": "^2.x",
68 | "babel-preset-taro": "3.0.7",
69 | "eslint": "^6.8.0",
70 | "eslint-config-taro": "3.0.7",
71 | "eslint-plugin-import": "^2.12.0",
72 | "eslint-plugin-react": "^7.8.2",
73 | "eslint-plugin-react-hooks": "^1.6.1",
74 | "stylelint": "9.3.0",
75 | "typescript": "^3.7.0"
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/pages/shop/components/ShopInfoModal/ShopInfoModal.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import classnames from 'classnames'
3 | import { View, Text } from '@tarojs/components'
4 | import distance from '../../../../utils/distance'
5 |
6 | import './ShopInfoModal.scss'
7 |
8 | interface ShopInfoModalProps {
9 | shopInfo
10 | modalHide
11 | onOpenModal
12 | }
13 |
14 | const ShopInfoModal: FC = (props) => {
15 | const { shopInfo, modalHide, onOpenModal } = props
16 | return (
17 |
22 |
23 |
24 | 品牌
25 | 唐宫海鲜舫(新侨店)
26 |
27 |
28 |
29 |
30 | {shopInfo.rating}
31 |
32 | 评分
33 |
34 |
35 |
36 | {shopInfo.recent_order_num}
37 |
38 | 月售
39 |
40 |
41 |
42 | {shopInfo.delivery_mode.text}
43 |
44 |
45 | 约{shopInfo.order_lead_time}
46 |
47 |
48 |
49 |
50 | {shopInfo.piecewise_agent_fee.rules[0].fee}元
51 |
52 | 配送费
53 |
54 |
55 |
56 | {distance(shopInfo.distance)}
57 |
58 | 距离
59 |
60 |
61 |
62 | 公告
63 |
64 | {shopInfo.promotion_info}
65 |
66 |
67 |
68 |
72 |
73 |
74 | )
75 | }
76 |
77 | export default ShopInfoModal
78 |
--------------------------------------------------------------------------------
/tatus:
--------------------------------------------------------------------------------
1 | * [33m3e006ff[m[33m ([m[1;36mHEAD -> [m[1;32mmaster[m[33m)[m 清空
2 | * [33mae4e2ec[m 初始化
3 | * [33med6660c[m 初始化
4 | * [33m14c70b5[m 重构
5 | * [33mdf741e5[m[33m ([m[1;31morigin/master[m[33m)[m 说明
6 | * [33mff61169[m 修改地址,微调说明
7 | * [33m736a36d[m 删除本地历史
8 | * [33mf3f645c[m 说明
9 | * [33m5aa692c[m 滚动条机制修改
10 | * [33m1544b0d[m 筛选top值问题
11 | * [33md93ab38[m 重写请求api,修复dom等bug
12 | * [33m6e3c31f[m 数据请求模块重构
13 | * [33mb78ca58[m 微调,去除无用代码
14 | * [33m3ed101c[m 小程序修复头部导航问题,去除代码冗余
15 | * [33mf4514ce[m 去除index.html无用script
16 | * [33m135ddd2[m 说明
17 | [32m|[m * [33m01339dc[m[33m ([m[1;31morigin/dependabot/npm_and_yarn/elliptic-6.5.3[m[33m)[m Bump elliptic from 6.5.2 to 6.5.3
18 | [32m|[m[32m/[m
19 | * [33mc35c955[m 订单详情
20 | * [33m6b52667[m 订单列表
21 | [33m|[m * [33m0983996[m[33m ([m[1;31morigin/dependabot/npm_and_yarn/websocket-extensions-0.1.4[m[33m)[m Bump websocket-extensions from 0.1.3 to 0.1.4
22 | [33m|[m[33m/[m
23 | * [33m42871ca[m 结算
24 | * [33m3cbffc8[m git排除history
25 | * [33mc10f986[m 发现页
26 | * [33m33db12d[m 商家展开优惠问题修复
27 | * [33m0cb0871[m 商家信息,商家搜索
28 | [35m|[m[36m\[m
29 | [35m|[m * [33m613d69f[m 搜索页
30 | * [36m|[m [33m75a3c49[m 商家阿微调
31 | * [36m|[m [33m6e436da[m 商家信息
32 | [36m|[m[36m/[m
33 | * [33m38e27cb[m 商家评价
34 | * [33m62509c4[m 购物车数据
35 | * [33m2710e5b[m 右侧商品列表滚动兼容
36 | * [33m25cca13[m 商家详情微调
37 | * [33mae59649[m 商家详情
38 | * [33m2d67769[m 商家列表没有更多
39 | * [33m3990f8f[m 商家列表
40 | * [33mbea1eb7[m 商家列表头部分类
41 | * [33m0cf6e2a[m 调整ip定位商家参数冲突问题
42 | * [33mbdab1b3[m Merge branch 'indexselectshop'
43 | [1;31m|[m[1;32m\[m
44 | [1;31m|[m * [33m60a9cb0[m action处理每次加载重置商家条数
45 | [1;31m|[m * [33m30e80ce[m 筛选联动更新商家列表
46 | [1;31m|[m * [33mfa655bb[m 暂存
47 | [1;31m|[m * [33m0483dd2[m 解决首页滚动条位置问题
48 | * [1;32m|[m [33mac881c8[m 配置
49 | [1;32m|[m[1;32m/[m
50 | * [33m34e79bb[m 说明调整
51 | * [33m05ae1b1[m 首页获取用户地址并且设置用户地址
52 | * [33mcff7523[m 调整navigateTo navigateBack
53 | * [33mfcfe851[m 微调
54 | * [33mce77a5d[m 个人中心
55 | * [33m7448bdc[m onDidShow 解决 navigateTo 问题
56 | * [33me1a3927[m 个人中心
57 | * [33mb927e6c[m 调整我的结构
58 | * [33mb64663c[m 用户信息
59 | * [33m7f5c4cb[m 收货地址
60 | [1;33m|[m[1;34m\[m
61 | [1;33m|[m * [33mf586947[m 我的收货地址
62 | [1;33m|[m * [33m73c632c[m 我的
63 | * [1;34m|[m [33mbbae65d[m 合并
64 | * [1;34m|[m [33m8627784[m Merge branch 'profile'
65 | [1;35m|[m[1;34m\[m[1;34m|[m
66 | [1;35m|[m * [33mdbfffb2[m 我的
67 | * [1;36m|[m [33m2dd5a06[m Merge branch 'register'
68 | [31m|[m[32m\[m [1;36m\[m
69 | [31m|[m * [1;36m|[m [33m1d53d06[m 注册
70 | [31m|[m * [1;36m|[m [33m7d4dd42[m 注册
71 | * [32m|[m [1;36m|[m [33m74a8258[m 登录
72 | [32m|[m[32m/[m [1;36m/[m
73 | * [1;36m/[m [33m680dce0[m 登录
74 | [1;36m|[m[1;36m/[m
75 | * [33mdfa4c8a[m 我的
76 | * [33m9fa2749[m 订单
77 | * [33m0644fc7[m 发现
78 | * [33m6487980[m 首页
79 | * [33m01563f3[m 首页
80 | * [33m21e3e70[m 初始化
81 |
--------------------------------------------------------------------------------
/src/pages/shop/components/Head/Head.tsx:
--------------------------------------------------------------------------------
1 | import React, { FC } from 'react'
2 | import { View, Image, Text, ITouchEvent } from '@tarojs/components'
3 | import imgUrl from '../../../../utils/imgUrl'
4 | import { H5 } from '../../../../config/base'
5 |
6 | import './Head.scss'
7 |
8 | interface HeadProps {
9 | shopInfo
10 | onOpenModal: () => void
11 | onActivityHide: (e: ITouchEvent) => void
12 | onBack: () => void
13 | }
14 |
15 | const Head: FC = (props) => {
16 | const { shopInfo, onOpenModal, onActivityHide, onBack } = props
17 |
18 | return (
19 |
20 |
28 | {H5 && }
29 |
30 |
31 |
32 | 品牌
33 |
37 |
38 |
39 | {shopInfo.name}
40 |
41 |
42 |
43 | 评价{shopInfo.rating}
44 |
45 | 月售{shopInfo.recent_order_num}单
46 |
47 |
48 | {shopInfo.delivery_mode.text}约{shopInfo.order_lead_time}分钟
49 |
50 |
51 | {!!shopInfo.activity_tags.length && (
52 | onActivityHide(e)}>
53 |
54 | {shopInfo.activity_tags.map((tag) => {
55 | return (
56 |
57 | {tag.text}
58 |
59 | )
60 | })}
61 |
62 |
63 |
64 | {shopInfo.activities.length}个优惠
65 |
66 |
67 |
68 |
69 | )}
70 | {shopInfo.promotion_info && (
71 |
72 |
73 | 公告:{shopInfo.promotion_info}
74 |
75 |
76 | )}
77 |
78 |
79 | )
80 | }
81 |
82 | export default Head
83 |
--------------------------------------------------------------------------------
/src/pages/discover/index.scss:
--------------------------------------------------------------------------------
1 | .discover {
2 | height: 100%;
3 | background: #f5f5f5;
4 |
5 | .discover-main {
6 | background: #fff;
7 | .discover-item {
8 | display: flex;
9 | align-items: center;
10 | justify-content: space-between;
11 | height: 160px;
12 | margin-left: 50%;
13 | padding: 0 30px;
14 | &:first-child {
15 | align-items: normal;
16 | justify-content: space-between;
17 | position: absolute;
18 | left: 0;
19 | width: calc(50% - 56px);
20 | height: 264px;
21 | margin: 0;
22 | padding: 44px 22px 12px 32px;
23 | border-right: 1px #ededed solid;
24 | .discover-img {
25 | align-self: flex-end;
26 | width: 150px;
27 | height: 150px;
28 | }
29 | }
30 | &:nth-child(2) {
31 | border-bottom: 1px #ededed solid;
32 | }
33 | .discover-left {
34 | .discover-title {
35 | font-size: 32px;
36 | }
37 |
38 | .discover-discover-subtitle {
39 | color: #999;
40 | font-size: 24px;
41 | }
42 | }
43 |
44 | .discover-img {
45 | width: 90px;
46 | height: 90px;
47 | }
48 | }
49 | }
50 |
51 | .suggest {
52 | margin-top: 20px;
53 | background: #fff;
54 | .suggest-head {
55 | padding-top: 30px;
56 | .suggest-head-title {
57 | display: flex;
58 | align-items: center;
59 | justify-content: center;
60 | .striping {
61 | position: relative;
62 | width: 40px;
63 | height: 4px;
64 | background: #333;
65 | &::after {
66 | content: '';
67 | position: absolute;
68 | top: -3px;
69 | width: 12px;
70 | height: 12px;
71 | background: #333;
72 | border-radius: 50%;
73 | }
74 | &:first-child {
75 | &::after {
76 | right: 0;
77 | }
78 | }
79 | }
80 |
81 | .icon {
82 | padding: 0 10px 0 5px;
83 | color: #f9534e;
84 | font-size: 36px;
85 | }
86 |
87 | .title {
88 | padding-right: 10px;
89 | font-size: 36px;
90 | font-weight: 600;
91 | }
92 | }
93 |
94 | .tip {
95 | color: #999;
96 | font-size: 24px;
97 | line-height: 1.2;
98 | text-align: center;
99 | }
100 | }
101 |
102 | .suggest-main {
103 | display: flex;
104 | align-items: center;
105 | flex-wrap: wrap;
106 | margin-top: 20px;
107 | .suggest-more {
108 | width: 100%;
109 | margin: 20px 0;
110 | color: #999;
111 | text-align: center;
112 | .icon {
113 | color: #999;
114 | }
115 | }
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/src/components/FooterNav/FooterNav.tsx:
--------------------------------------------------------------------------------
1 | import Taro, { getCurrentInstance } from '@tarojs/taro'
2 | import React, { FC, useState, useEffect } from 'react'
3 | import { View, Image } from '@tarojs/components'
4 | import classnames from 'classnames'
5 | import { H5 } from '../../config/base'
6 |
7 | import msiteIcon from './images/msite_1.svg'
8 | import msiteActiveIcon from './images/msite_2.svg'
9 | import discoverIcon from './images/discover_1.svg'
10 | import discoverActiveIcon from './images/discover_2.svg'
11 | import orderIcon from './images/order_1.svg'
12 | import orderActiveIcon from './images/order_2.svg'
13 | import profileIcon from './images/profile_1.svg'
14 | import profileActiveIcon from './images/profile_2.svg'
15 |
16 | import './FooterNav.scss'
17 |
18 | interface Bar {
19 | id: number
20 | name: string
21 | path: string
22 | icon: string
23 | active_icon: string
24 | }
25 |
26 | const FooterNav: FC = () => {
27 | // 路由地址
28 | const [path, setPath] = useState('')
29 | const bars: Bar[] = [
30 | {
31 | id: 0,
32 | name: '首页',
33 | path: '/pages/msite/index',
34 | icon: msiteIcon,
35 | active_icon: msiteActiveIcon,
36 | },
37 | {
38 | id: 1,
39 | name: '发现',
40 | path: '/pages/discover/index',
41 | icon: discoverIcon,
42 | active_icon: discoverActiveIcon,
43 | },
44 | {
45 | id: 2,
46 | name: '订单',
47 | path: '/pages/order/index',
48 | icon: orderIcon,
49 | active_icon: orderActiveIcon,
50 | },
51 | {
52 | id: 3,
53 | name: '我的',
54 | path: '/pages/profile/index',
55 | icon: profileIcon,
56 | active_icon: profileActiveIcon,
57 | },
58 | ]
59 |
60 | useEffect(() => {
61 | // 获取路由路径
62 | const current: Taro.Current = getCurrentInstance()
63 | if (H5) {
64 | if (current.app) {
65 | // H5端
66 | setPath(current.app.config.router.pathname)
67 | }
68 | } else {
69 | // 小程序
70 | setPath(current.router.path)
71 | }
72 | }, [])
73 |
74 | // 跳转
75 | const handleGo = (bar: Bar) => {
76 | Taro.reLaunch({
77 | url: bar.path,
78 | })
79 | }
80 |
81 | return (
82 |
83 |
84 | {bars.map((bar) => {
85 | return (
86 | handleGo(bar)}
89 | className={classnames('footer-item', {
90 | active: path === bar.path,
91 | })}
92 | >
93 |
94 |
98 |
99 | {bar.name}
100 |
101 | )
102 | })}
103 |
104 |
105 | )
106 | }
107 | export default FooterNav
108 |
--------------------------------------------------------------------------------
/src/pages/clearing/index.tsx:
--------------------------------------------------------------------------------
1 | import Taro from '@tarojs/taro'
2 | import React, { useMemo, useState, useCallback } from 'react'
3 | import { View } from '@tarojs/components'
4 | import { useSelector } from 'react-redux'
5 | import { H5 } from '../../config/base'
6 | import NavBar from '../../components/NavBar/NavBar'
7 | import API from '../../api'
8 | import { Reducers } from '../../redux/interface'
9 |
10 | import CartAddress from './components/CartAddress/CartAddress'
11 | import Distribution from './components/Distribution/Distribution'
12 | import CartInfo from './components/CartInfo/CartInfo'
13 | import FooterDic from './components/FooterDic/FooterDic'
14 |
15 | import './index.scss'
16 |
17 | const Clearing = () => {
18 | const { currentAddress } = useSelector((state: Reducers) => state)
19 | const { cartInfo, shopInfo } = Taro.getStorageSync('clearing')
20 | const shopName = shopInfo.name
21 | const [payLoading, setPayLoading] = useState(false)
22 |
23 | // 选择地址
24 | const selectAddress = () => {
25 | Taro.navigateTo({ url: '/pages/profile/address/index?clearing=true' })
26 | }
27 |
28 | // 总价
29 | const totalPrice = useMemo(() => {
30 | return cartInfo.totalPrice + cartInfo.goodTotal + cartInfo.boxPrice
31 | }, [cartInfo])
32 |
33 | // 优惠价格
34 | const discountsPrice = useMemo(() => {
35 | return cartInfo.originalPrice - cartInfo.totalPrice
36 | }, [cartInfo])
37 |
38 | // 去支付
39 | const pay = useCallback(async () => {
40 | if (currentAddress.id) {
41 | const body = {
42 | ...cartInfo,
43 | shopName: shopInfo.name,
44 | imagePath: shopInfo.image_path,
45 | delivery: shopInfo.delivery_mode.text,
46 | address: JSON.stringify(currentAddress),
47 | foods: JSON.stringify(cartInfo.foods),
48 | }
49 |
50 | setPayLoading(true)
51 | const { err, res } = await API.reqPay(body)
52 | if (err) {
53 | console.log(err)
54 | return
55 | }
56 | if (res.code === 0) {
57 | setPayLoading(false)
58 | Taro.showToast({
59 | title: '支付成功',
60 | icon: 'loading',
61 | duration: 1500,
62 | success() {
63 | setTimeout(() => {
64 | Taro.reLaunch({ url: '/pages/order/index' })
65 | }, 1500)
66 | },
67 | })
68 | }
69 | } else {
70 | Taro.showToast({ title: '请选择收货地址', icon: 'none', duration: 1500 })
71 | }
72 | }, [cartInfo, shopInfo, currentAddress])
73 |
74 | if (H5) {
75 | document.removeEventListener('scroll', () => {}, false)
76 | }
77 |
78 | return (
79 |
80 | {H5 && }
81 |
85 |
86 |
87 |
93 |
94 | )
95 | }
96 |
97 | export default Clearing
98 |
--------------------------------------------------------------------------------
/src/redux/reducers/user.ts:
--------------------------------------------------------------------------------
1 | import Taro from '@tarojs/taro'
2 | import {
3 | GETUSERADDRESSLIST,
4 | SETTOKEN,
5 | REMOVETOKEN,
6 | CURRENTADDRESS,
7 | USERADDRESS,
8 | SETUSERADDRESS,
9 | REMOVEUSERADDRESS,
10 | REMOVEUSERADDRESSLIST,
11 | } from '../action-types'
12 | import { Reducers } from '../interface'
13 |
14 | interface Action {
15 | type: T
16 | payload: D
17 | }
18 |
19 | // 用户token
20 | type TOKENTYPE = typeof SETTOKEN | typeof REMOVETOKEN
21 | const initToken: string = Taro.getStorageSync('token') || ''
22 | const token = (
23 | state = initToken,
24 | action: Action
25 | ) => {
26 | const { type, payload } = action
27 | switch (type) {
28 | case SETTOKEN:
29 | return payload
30 | case REMOVETOKEN:
31 | return ''
32 | default:
33 | return state
34 | }
35 | }
36 |
37 | // 当前收货地址
38 | type CURRENTADDRESSTYPE = typeof CURRENTADDRESS
39 | const initCurrentAddress = {
40 | id: '',
41 | city: '', // 城市名称
42 | address: '', //详细地址
43 | address_detail: '', // 门牌号
44 | latitude: '', // 纬度
45 | longitude: '', // 经度
46 | name: '', // 收货人
47 | phone: '', // 收货人手机
48 | sex: '', // 性别
49 | }
50 | const currentAddress = (
51 | state = initCurrentAddress,
52 | action: Action
53 | ) => {
54 | const { type, payload } = action
55 | switch (type) {
56 | case CURRENTADDRESS:
57 | return { ...state, ...payload }
58 | default:
59 | return state
60 | }
61 | }
62 |
63 | // 收货地址列表
64 | type USERADDRESSLISTTYPE =
65 | | typeof GETUSERADDRESSLIST
66 | | typeof REMOVEUSERADDRESSLIST
67 | const initAddressList = []
68 | const userAddressList = (
69 | state = initAddressList,
70 | action: Action
71 | ) => {
72 | const { type, payload } = action
73 | switch (type) {
74 | case GETUSERADDRESSLIST:
75 | return payload
76 | case REMOVEUSERADDRESSLIST:
77 | return []
78 | default:
79 | return state
80 | }
81 | }
82 |
83 | // 编辑收货地址
84 | type USERADDRESSTYPE =
85 | | typeof USERADDRESS
86 | | typeof SETUSERADDRESS
87 | | typeof REMOVEUSERADDRESS
88 | const initUserAddress = {
89 | id: '',
90 | city: '', // 城市名称
91 | address: '', //详细地址
92 | address_detail: '', // 门牌号
93 | latitude: '', // 纬度
94 | longitude: '', // 经度
95 | name: '', // 收货人
96 | phone: '', // 收货人手机
97 | sex: '', // 性别
98 | }
99 | const userAddress = (
100 | state = initUserAddress,
101 | action: Action
102 | ) => {
103 | const { type, payload } = action
104 | switch (type) {
105 | case USERADDRESS:
106 | return payload
107 | case SETUSERADDRESS:
108 | return {
109 | ...state,
110 | ...payload,
111 | }
112 | case REMOVEUSERADDRESS:
113 | return initUserAddress
114 | default:
115 | return state
116 | }
117 | }
118 |
119 | export default {
120 | token,
121 | userAddressList,
122 | userAddress,
123 | currentAddress,
124 | }
125 |
--------------------------------------------------------------------------------
/src/api/serve.ts:
--------------------------------------------------------------------------------
1 | import { request, getStorageSync } from '@tarojs/taro'
2 |
3 | class Server {
4 | protected ajax({
5 | url,
6 | data,
7 | method = 'GET',
8 | ...restParams
9 | }: Taro.RequestParams) {
10 | // 用户token
11 | const Authorization: string = getStorageSync('token') || ''
12 | // 判断请求类型
13 | let contentType: string
14 | // GET请求
15 | if (method === 'GET') {
16 | contentType = 'application/json'
17 | // POST 请求
18 | } else if (method === 'POST') {
19 | contentType = 'application/x-www-form-urlencoded'
20 | }
21 | return new Promise(
22 | (resolve, reject) => {
23 | request({
24 | url,
25 | data,
26 | method,
27 | header: {
28 | 'content-type': contentType,
29 | Authorization,
30 | },
31 | ...restParams,
32 | // 成功回调
33 | success(res: Taro.request.SuccessCallbackResult): void {
34 | resolve(res)
35 | },
36 | // 失败回调
37 | fail(err: Taro.General.CallbackResult): void {
38 | reject(err)
39 | },
40 | })
41 | }
42 | )
43 | }
44 | }
45 |
46 | export default Server
47 |
48 | // import { request, showLoading, hideLoading, getStorageSync } from '@tarojs/taro'
49 |
50 | // class Server {
51 | // // 初始请求次数
52 | // protected reqNum: number = 0
53 | // // 用户token
54 | // protected Authorization: string = getStorageSync('token') || ''
55 |
56 | // protected ajax({
57 | // url,
58 | // data,
59 | // method = 'GET',
60 | // ...restParams
61 | // }: Taro.RequestParams) {
62 | // // 提示
63 | // showLoading({ title: '加载中...', mask: true })
64 | // // 请求次数递增
65 | // this.reqNum++
66 | // // 判断请求类型
67 | // let contentType: string
68 | // // GET请求
69 | // if (method === 'GET') {
70 | // contentType = 'application/json'
71 | // // POST 请求
72 | // } else if (method === 'POST') {
73 | // contentType = 'application/x-www-form-urlencoded'
74 | // }
75 |
76 | // return new Promise(
77 | // (resolve, reject) => {
78 | // request({
79 | // url,
80 | // data,
81 | // method,
82 | // header: {
83 | // 'content-type': contentType,
84 | // Authorization: this.Authorization,
85 | // },
86 | // ...restParams,
87 | // // 成功回调
88 | // success(res: Taro.request.SuccessCallbackResult): void {
89 | // resolve(res)
90 | // },
91 | // // 失败回调
92 | // fail(err: Taro.General.CallbackResult): void {
93 | // reject(err)
94 | // },
95 | // // 成功失败都回调
96 | // complete: () => {
97 | // // 请求次数递减
98 | // this.reqNum--
99 | // // reqNum=0 说明最后一个请求发送完毕
100 | // if (this.reqNum === 0) {
101 | // hideLoading()
102 | // }
103 | // },
104 | // })
105 | // }
106 | // )
107 | // }
108 | // }
109 |
110 | // export default Server
111 |
--------------------------------------------------------------------------------
/src/pages/profile/address/search/index.tsx:
--------------------------------------------------------------------------------
1 | import Taro from '@tarojs/taro'
2 | import React, { useState, useCallback, useRef, useEffect } from 'react'
3 | import { View, Text, Input, ScrollView } from '@tarojs/components'
4 | import { useSelector, useDispatch } from 'react-redux'
5 | import API from '../../../../api'
6 | import { UseSearchAddress } from '../../../../api/interface'
7 | import { Reducers, Address } from '../../../../redux/interface'
8 | import {
9 | setAtUserAddress,
10 | initCurrentAddress,
11 | } from '../../../../redux/actions/user'
12 | import NavBar from '../../../../components/NavBar/NavBar'
13 | import './index.scss'
14 |
15 | const Search = () => {
16 | const currentAddress = useSelector((state: Reducers) => state.currentAddress)
17 | const dispatch = useDispatch()
18 | const [value, setValue] = useState('')
19 | const [addressList, setAddressList] = useState([])
20 |
21 | // 获取搜索地址
22 | const getAddressList = useCallback(async () => {
23 | // 如果redux没有数据 重新获取ip地址信息
24 | if (!currentAddress.longitude && !currentAddress.latitude) {
25 | dispatch(initCurrentAddress())
26 | } else {
27 | const parmas = {
28 | key: value,
29 | longitude: currentAddress.longitude,
30 | latitude: currentAddress.latitude,
31 | }
32 | const { err, res } = await API.reqUseSearchAddress(parmas)
33 |
34 | if (err) {
35 | console.log(err)
36 | return
37 | }
38 |
39 | if (res.code === 0) {
40 | setAddressList(res.data)
41 | } else {
42 | console.log(res)
43 | Taro.showToast({ title: res.message, icon: 'none' })
44 | }
45 | }
46 | }, [value, currentAddress, dispatch])
47 |
48 | useEffect(() => {
49 | getAddressList()
50 | }, [getAddressList])
51 |
52 | // 搜索
53 | const onSearch = (e) => {
54 | const keyword = e.detail.value
55 | setValue(keyword)
56 | }
57 |
58 | // 选择地址
59 | const selectCity = (item: Address) => {
60 | const atAddress = {
61 | address: item.name,
62 | address_detail: item.address,
63 | city: item.city,
64 | latitude: item.latitude,
65 | longitude: item.longitude,
66 | }
67 | dispatch(setAtUserAddress({ ...atAddress }))
68 | Taro.navigateBack({ delta: 1 })
69 | }
70 |
71 | return (
72 |
73 |
74 |
75 |
76 |
77 |
82 |
83 |
84 | {addressList.map((item) => {
85 | return (
86 | selectCity(item)}
90 | >
91 | {item.name}
92 | {item.address}
93 |
94 | )
95 | })}
96 |
97 |
98 |
99 | )
100 | }
101 |
102 | export default Search
103 |
--------------------------------------------------------------------------------
/src/pages/shop/components/Head/Head.scss:
--------------------------------------------------------------------------------
1 | .myshop-top {
2 | .myshop-top-bg {
3 | position: relative;
4 | height: 200px;
5 | background-repeat: no-repeat !important;
6 | background-size: 100% 100% !important;
7 | .icon {
8 | position: absolute;
9 | top: 0;
10 | left: 0;
11 | width: 60px;
12 | height: 60px;
13 | padding: 20px 0 0 20px;
14 | color: #fff;
15 | font-size: 30px;
16 | font-weight: 600;
17 | }
18 | }
19 |
20 | .myshop-top-main {
21 | position: relative;
22 | padding-top: 50px;
23 |
24 | .myshop-logo {
25 | overflow: hidden;
26 | position: absolute;
27 | top: 0;
28 | left: 50%;
29 | margin-top: -120px;
30 | transform: translateX(-50%);
31 | border-radius: 6px;
32 |
33 | .myshop-logo-pinpai {
34 | position: absolute;
35 | z-index: 1;
36 | top: 0;
37 | left: 0;
38 | padding: 0 5px;
39 | background-image: linear-gradient(90deg, #fff100, #ffe339);
40 | color: #6f3f15;
41 | font-size: 22px;
42 | }
43 |
44 | .myshop-logo-img {
45 | width: 150px;
46 | height: 150px;
47 | box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.2);
48 | }
49 | }
50 |
51 | .myshop-name {
52 | display: flex;
53 | align-items: center;
54 | justify-content: center;
55 | width: 72vw;
56 | margin: 0 auto;
57 | color: #333;
58 | font-weight: 600;
59 |
60 | .myshop-name-title {
61 | overflow: hidden;
62 | font-size: 41px;
63 | white-space: nowrap;
64 | text-overflow: ellipsis;
65 | }
66 | .icon {
67 | font-size: 24px;
68 | }
69 | }
70 |
71 | .myshop-pingjia {
72 | display: flex;
73 | justify-content: center;
74 | padding: 5px 0;
75 | color: #666;
76 |
77 | .myshop-pingjia-item {
78 | font-size: $font-size-22;
79 | padding-top: 14px ;
80 | padding-bottom: 14px ;
81 | }
82 | .myshop-pingjia-item-c {
83 | padding-left: 20px;
84 | padding-right: 20px;
85 | }
86 | }
87 |
88 | .myshop-tags {
89 | display: flex;
90 | justify-content: space-between;
91 | margin: 0 80px;
92 |
93 | .myshop-tags-left {
94 | overflow: hidden;
95 | white-space: nowrap;
96 | text-overflow: ellipsis;
97 |
98 | .myshop-tags-left-tag {
99 | display: inline-block;
100 | margin: 0 5px;
101 | padding: 0 10px;
102 | border: 1px #ffe4e0 solid;
103 | color: #ff4b33;
104 | font-size: 24px;
105 | }
106 | }
107 | .myshop-tags-right {
108 | display: flex;
109 | align-items: center;
110 | width: 150px;
111 | color: #999;
112 |
113 | .myshop-tags-right-title {
114 | font-size: 24px;
115 | }
116 | .icon {
117 | font-size: 18px;
118 | }
119 | }
120 | }
121 |
122 | .myshop-notice {
123 | display: flex;
124 | margin: 0 80px;
125 | padding-top: 25px;
126 |
127 | .myshop-notice-content {
128 | overflow: hidden;
129 | color: #999;
130 | font-size: 24px;
131 | white-space: nowrap;
132 | text-overflow: ellipsis;
133 | }
134 | }
135 | }
136 | }
137 |
--------------------------------------------------------------------------------