✨ feat(购物界面): 完成购物界面50%

This commit is contained in:
xuan
2022-09-15 19:59:19 +08:00
parent 8472f4c14b
commit fee33aec38
124 changed files with 1939 additions and 28 deletions
+4 -3
View File
@@ -8,7 +8,7 @@
*/
import { View } from '@tarojs/components'
import { FC, ReactNode } from 'react'
import React, { FC, ReactNode } from 'react'
import styles from './index.module.scss'
import classnames from 'classnames'
@@ -20,9 +20,10 @@ interface DividerProps {
contentPosition?: 'left' | 'center' | 'right'
children?: ReactNode
customClassName?: string
customStyles?: React.CSSProperties
}
const Divider: FC<DividerProps> = (props) => {
const { direction = 'horizontal', borderStyle = 'solid', contentPosition = 'center', customClassName='' } = props
const { direction = 'horizontal', borderStyle = 'solid', contentPosition = 'center', customClassName = '', customStyles = {} } = props
const classname = classnames(styles['divider'], styles['divider-' + direction], customClassName)
const contentClassname = classnames(styles['divider-text'], styles['is-' + contentPosition])
@@ -37,7 +38,7 @@ const Divider: FC<DividerProps> = (props) => {
const dividerStyle = direction === 'horizontal' ? borderTopStyle : borderLeftStyle
return (
<View className={classname} style={dividerStyle}>
<View className={classname} style={{ ...dividerStyle, ...customStyles }}>
{props.children && direction !== 'vertical' && <View className={contentClassname}>{props.children}</View>}
</View>
)
@@ -2,6 +2,7 @@
display: flex;
align-items: center;
&--text {
color: currentColor;
margin-left: 10px;
}
}
+5 -3
View File
@@ -1,6 +1,6 @@
import { View } from '@tarojs/components'
import classnames from 'classnames'
import { forwardRef, useEffect, useImperativeHandle, useState } from 'react'
import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'react'
import IconFont from '../iconfont'
import styles from './index.module.scss'
@@ -15,9 +15,11 @@ type params = {
round?: boolean
size?: CheckboxSize
children?: React.ReactNode
customStyles?: React.CSSProperties
customClassName?: string
}
export default forwardRef((props: params, ref) => {
const { onSelect, onClose, status = false, disabled = false, circle = false, round = true, size = 'normal', children } = props
const { onSelect, onClose, status = false, disabled = false, circle = false, round = true, size = 'normal', children, customStyles, customClassName } = props
const [selected, SetSelected] = useState(false)
const onSelectEven = () => {
if (disabled) return false
@@ -55,7 +57,7 @@ export default forwardRef((props: params, ref) => {
SetSelected(status)
}, [status])
return (
<View className={styles.checkbox} onClick={() => onSelectEven()}>
<View className={classnames(customClassName, styles.checkbox)} onClick={() => onSelectEven()} style={customStyles}>
<View className={classnames(styles.checkbox_main, getMainClassName())}>
<View className={classnames(styles.checkbox_item, getClassName())}>
{selected && <IconFont name='icon-a-jizhumima' size={22} color='#fff'></IconFont>}
@@ -0,0 +1,9 @@
.iconText{
display: flex;
flex-flow: row nowrap;
align-items: center;
font-size: 28px;
.iconfont{
font-size: 40px;
}
}
+29
View File
@@ -0,0 +1,29 @@
import { FC } from "react"
import { View, Text } from '@tarojs/components'
import IconFont from '../iconfont'
import styles from './index.module.scss'
import classnames from 'classnames'
type IconfontName = Parameters<typeof IconFont>['0']['name']
type PropsType = {
iconName: IconfontName
iconSize?: number
svg?: boolean
text?: string
children?: React.ReactNode
customClass?: string
customStyle?: React.CSSProperties
textClassName?: string
}
const IconText: FC<PropsType> = (props) => {
const { children, svg = false, iconName, iconSize = 40, text = '' } = props
return (
<View className={classnames(styles.iconText, props.customStyle, props.customClass)}>
{svg ? <IconFont name={iconName} size={iconSize}></IconFont> : <Text className={classnames('iconfont', iconName, styles.iconfont)}></Text>}
{children ? children : <Text className={classnames(props.textClassName)}>{text}</Text>}
</View>
)
}
export default IconText
+7 -7
View File
@@ -11,11 +11,11 @@ interface PropsType {
circle?: boolean
children?: ReactNode
customStyle?: React.CSSProperties
customClassName?: string
}
const LayoutBlock: FC<PropsType> = (props) => {
const { flexDirection = 'col', circle = false, children } = props
const { flexDirection = 'col', circle = false, children, customStyle = {}, customClassName='' } = props
const getClassName = () => {
const classObject = {
@@ -25,10 +25,10 @@ const LayoutBlock: FC<PropsType> = (props) => {
return classObject
}
return <View className={classnames(styles.layoutBlock, getClassName())}>
{children}
</View>
return (
<View className={classnames(styles.layoutBlock, getClassName(), customClassName)} style={customStyle}>
{children}
</View>
)
}
export default LayoutBlock
@@ -37,6 +37,12 @@
color: $color_warning;
$current_color: $color_warning;
}
&--info {
border: 1px solid $color_info;
color: $color_info;
$current_color: $color_info;
}
&--round {
border-radius: 50px;
}
@@ -66,4 +72,8 @@
background-color: rgba($color: $color_warning, $alpha: 0.5);
color: #fff;
}
&--info:active {
background-color: rgba($color: $color_info, $alpha: 0.5);
color: #fff;
}
}
+6 -5
View File
@@ -3,16 +3,16 @@ import { FC, ReactNode } from 'react'
import classnames from 'classnames'
import styles from './index.module.scss'
type ButtonType = 'primary' | 'danger' | 'warning'
type ButtonType = 'primary' | 'danger' | 'warning' | 'info'
type ButtonSize = 'normal' | 'small'
interface PropsType {
size?: ButtonSize
type?: ButtonType
round?: boolean
round?: boolean // 大圆角
disabled?: boolean
plain?: boolean
circle?: boolean
plain?: boolean // 填满背景颜色
circle?: boolean // 小圆角
children?: ReactNode
onClick?: Function
customClassName?: string
@@ -51,8 +51,9 @@ const NormalButton: FC<PropsType> = (props) => {
onClick && onClick(event)
}
return (
<View className={classnames(styles['button'], getClassName(), customStyles, customClassName)} onClick={handleClick}>
<View className={classnames(styles['button'], getClassName(), customClassName)} style={customStyles} onClick={handleClick}>
<Text className={styles['button--text']}>{children}</Text>
</View>
)
+4
View File
@@ -27,6 +27,10 @@
&--warning{
background-color: $color_warning;
}
&--info{
background-color: $color_info;
color: rgba($color: #333333, $alpha: 0.8);
}
&--disabled {
opacity: $opacity-disabled;
}
+5 -2
View File
@@ -4,10 +4,11 @@ import classnames from 'classnames'
import styles from './index.module.scss'
type TagSize = 'small' | 'normal'
type TagType = 'primary' | 'danger' | 'warning'
type TagType = 'primary' | 'danger' | 'warning' | 'info'
interface PropsType {
type?: TagType
plain?: boolean
disabled?: boolean
size?: TagSize
children?: ReactNode
@@ -16,7 +17,8 @@ interface PropsType {
customStyle?: React.CSSProperties
}
const Tag: FC<PropsType> = ({ type = 'primary', size = 'normal', disabled = false, children, onClick, circle = false, customStyle = {} }) => {
const Tag: FC<PropsType> = (props) => {
const { type = 'primary', size = 'normal', disabled = false, children, onClick, circle = false, customStyle = {}, plain = false } = props
const handleClick = (event) => {
if (disabled) {
return
@@ -29,6 +31,7 @@ const Tag: FC<PropsType> = ({ type = 'primary', size = 'normal', disabled = fals
[styles['tag--disabled']]: disabled,
[styles[`tag--${size}`]]: size,
[styles[`tag--${type}`]]: type,
[styles['tag--plain']]: plain,
[styles['tag--circle']]: circle,
}
console.log('classObj==>', classObject)
@@ -0,0 +1,34 @@
.bottomBar {
display: flex;
flex-flow: row nowrap;
align-items: center;
justify-content: space-between;
background-color: white;
padding: 16px 24px;
.bottomLeft{
margin-left: 12px;
.moneyText{
font-size: 24px;
font-family: $font_family;
font-weight: 400;
color: rgba($color: #000000, $alpha: 0.6);
}
.moneyNumber{
font-size: 28px;
font-family: $font_family;
font-weight: 500;
color: $color_money;
}
}
.bottomRight{
}
.bottomButton {
}
}
@@ -0,0 +1,52 @@
import { formatPriceDiv } from '@/common/format'
import NormalButton from '@/components/normalButton'
import { View, Text } from '@tarojs/components'
import { memo, useState } from 'react'
import styles from './index.module.scss'
import MCheckbox from '@/components/checkbox'
type PropsType = {
onDelete?: Function
onSelectCheckbox?: (bool: boolean) => void
}
export default memo<PropsType>((props) => {
const { onDelete, onSelectCheckbox } = props
const handleSettle = () => {
onDelete && onDelete()
}
const selectCallBack = () => {
setSelectAll(true)
onSelectCheckbox && onSelectCheckbox(isSelectAll)
}
const closeCallBack = () => {
setSelectAll(false)
onSelectCheckbox && onSelectCheckbox(isSelectAll)
}
const [isSelectAll, setSelectAll] = useState(false)
return (
<View className={styles.bottomBar}>
<View className={styles.bottomLeft}>
<MCheckbox
status={isSelectAll}
round
size='small'
onSelect={selectCallBack}
onClose={closeCallBack}
customStyles={{ color: '$color: #000000, $alpha: 0.6' }}>
全选
</MCheckbox>
</View>
<View className={styles.bottomRight}>
<NormalButton plain round type='danger' size='normal' onClick={handleSettle} customStyles={{ backgroundColor: '#F44761' }}>
<Text style={{ fontSize: '32rpx' }}>删除</Text>
</NormalButton>
</View>
</View>
)
})
@@ -0,0 +1,39 @@
.bottomBar {
display: flex;
flex-flow: row nowrap;
align-items: center;
justify-content: space-between;
background-color: white;
padding: 16px 24px;
box-shadow: 0 1px 2px 1px #c2c2c2;
.bottomLeft{
margin-left: 12px;
.moneyText{
font-size: 28px;
font-family: $font_family;
font-weight: 400;
color: rgba($color: #000000, $alpha: 0.6);
}
.moneyNumber{
font-size: 28px;
font-family: $font_family;
font-weight: 550;
color: $color_money;
}
}
.bottomRight{
}
.bottomButton {
}
}
.unit{
font-size: 24px;
transform: scale(.7);
margin-right: 10px;
}
@@ -0,0 +1,35 @@
import { formatPriceDiv } from '@/common/format'
import NormalButton from '@/components/normalButton'
import { View, Text } from '@tarojs/components'
import { memo } from 'react'
import styles from './index.module.scss'
type PropsType = {
amount?: number
onSettleAccount?: Function
}
export default memo<PropsType>((props) => {
const { onSettleAccount, amount = 0 } = props
const handleSettle = () => {
onSettleAccount && onSettleAccount()
}
return (
<View className={styles.bottomBar}>
<View className={styles.bottomLeft}>
<Text className={styles.moneyText}>预估金额:</Text>
<Text className={styles.moneyNumber}>
<Text className={styles.unit}>¥</Text>
{formatPriceDiv(amount)}
</Text>
</View>
<View className={styles.bottomRight}>
<NormalButton plain type='primary' round size='normal' onClick={handleSettle}>
<Text style={{fontSize: '32rpx'}}>结算</Text>
</NormalButton>
</View>
</View>
)
})
@@ -0,0 +1,56 @@
.layout{
margin: 24px;
}
.line{
margin: 16px 0;
}
.topItem {
display: flex;
flex-flow: column nowrap;
align-items: flex-start;
justify-content: space-around;
.topTitle {
font-size: 32px;
font-family: $font_family;
font-weight: 550;
color: rgba($color: #000000, $alpha: 0.8);
margin-right: 16px;
}
// 汇总
.summary{
color: rgba($color: #000000, $alpha: 0.4);
font-size: 24px;
}
}
.detailBox {
box-sizing: border-box;
overflow: hidden;
.orderType{
width: 100%;
margin-left: 56px;
.orderTypeTitle{
color: $color_font_one;
font-weight: 550;
font-size: 28px;
line-height: 2.5;
}
.orderTypeDetail{
display: flex;
gap: 0 16px;
}
}
.orderColor{
width: 100%;
margin-left: 56px;
}
}
.bottomBox {
margin-top: 40px;
}
@@ -0,0 +1,95 @@
import { Text, View } from '@tarojs/components'
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
import styles from './index.module.scss'
import classnames from 'classnames'
import { formatPriceDiv } from '@/common/format'
import Taro from '@tarojs/taro'
import LayoutBlock from '@/components/layoutBlock'
import MCheckbox from '@/components/checkbox'
import Tag from '@/components/tag'
import Divider from '@/components/divider'
import NormalButton from '@/components/normalButton'
type PropsType = {
obj?: any
}
const DrawerButton = memo<{ isOpen: boolean }>(({ isOpen }) => {
return isOpen ? <Text className='iconfont '></Text> : <Text className='iconfont '></Text>
})
export default memo((props: PropsType) => {
const [openDetail, setOpenDetail] = useState(false)
const handleOpenDetail = () => {
setOpenDetail((isOpen) => !isOpen)
}
const [selected, setSelect] = useState(0)
const onSelectOrderType = (type) => {
setSelect(type)
}
return (
<LayoutBlock circle customClassName={styles.layout}>
<MCheckbox>
<View className='flex-row justify-between' onClick={handleOpenDetail}>
<View className={styles.topItem}>
<View className='flex-row'>
<View className={styles.topTitle}>灵玉布行</View>
<Tag type='info' size='normal'>
刘思伟
</Tag>
</View>
<View className={styles.summary}>
<Text>已选 1 种面料,1 个颜色,共 4 条</Text>
</View>
</View>
<DrawerButton isOpen={openDetail} />
</View>
</MCheckbox>
<View className={styles.detailBox}>
<View className={styles.orderType}>
<Divider customClassName={styles.line}></Divider>
<View className={styles.orderTypeTitle}>订单类型</View>
<View className={styles.orderTypeDetail}>
<NormalButton
type={selected === 0 ? 'primary' : 'info'}
plain={selected !== 0}
customStyles={{ padding: '0 50rpx' }}
circle
onClick={() => onSelectOrderType(0)}>
大货
</NormalButton>
<NormalButton
type={selected === 1 ? 'primary' : 'info'}
plain={selected !== 1}
customStyles={{ padding: '0 50rpx' }}
circle
onClick={() => onSelectOrderType(1)}>
散剪
</NormalButton>
<NormalButton
type={selected === 2 ? 'primary' : 'info'}
plain={selected !== 2}
customStyles={{ padding: '0 50rpx' }}
circle
onClick={() => onSelectOrderType(2)}>
剪板
</NormalButton>
</View>
</View>
<View className={styles.orderColor}>
<Divider customClassName={styles.line}></Divider>
<View className={classnames(styles.orderTypeTitle, 'justify-between')}>
<Text>布料颜色</Text>
<Tag type='danger' size='normal' circle>
大货单位:条
</Tag>
</View>
</View>
</View>
</LayoutBlock>
)
})
+23
View File
@@ -0,0 +1,23 @@
.shopping {
width: 100%;
height: 100%;
background-color: $color_bg_one;
&--topBar {
background: #ffffff;
padding: 16px 24px;
}
&--context {
justify-content: space-between;
height: 100%;
}
}
.flexBox {
display: flex;
width: 150px;
align-items: center;
justify-content: flex-end;
}
.icon--manage--cancel {
color: $color_main;
}
+75 -7
View File
@@ -1,13 +1,81 @@
import { isEmptyObject } from '@/common/common'
import Search from '@/components/search'
import { View } from '@tarojs/components'
import Taro, { useDidShow } from '@tarojs/taro'
import { useMemo } from 'react'
import { FC, useCallback, useMemo, useState } from 'react'
import styles from './index.module.scss'
import classnames from 'classnames'
import IconText from '@/components/iconText'
import InfiniteScroll from '@/components/infiniteScroll'
import ItemList from './components/shoppingCartItem/index'
import BottomBtns from '@/components/BottomBtns'
import { formatPriceDiv } from '@/common/format'
import BottomSettleBar from './components/bottomSettleBar'
import BottomEditBar from './components/bottomEditBar'
const User = () => {
const obj = {}
console.log(isEmptyObject(obj))
const Shopping: FC = () => {
//输入了搜索关键字
const getSearchData = useCallback((e) => {
// pageNum.current.page = 1
// setOrderData(() => ({ list: [], total: 0 }))
// setSearchField((val) => ({ ...val, name: e, size: 10 }))
}, [])
const [isManage, setManage] = useState(false)
return <View>sdfasdfasdf</View>
// 管理
const onStartToManage = () => {
setManage((isManage) => !isManage)
}
const [selectedAmount, setSelectedAmount] = useState(0)
// 结算
const handleSettleAccount = () => {}
// 删除
const handleDelete = () => {}
const handleSelectAllCheckbox = (isSelectAll: boolean) => {
console.log('handleSelectAllCheckbox', isSelectAll)
}
return (
<View className={classnames('flex-col', styles.shopping)}>
<View className={styles['shopping--topBar']}>
<Search placeholder='请输入客户名称' showBtn={false} changeOnSearch={getSearchData} debounceTime={300}>
<View className={styles.flexBox} onClick={onStartToManage}>
{isManage ? (
<IconText iconName='icon-guanlidingdan' text='取消' customClass={styles['icon--manage--cancel']} />
) : (
<IconText iconName='icon-guanlidingdan' text='管理' />
)}
</View>
</Search>
</View>
<View className={classnames('flex-item', 'flex-col', styles['shopping--context'])}>
<View className={classnames('flex-item')}>
{/* <InfiniteScroll
statusMore={statusMore}
selfonScrollToLower={getScrolltolower}
refresherEnabled={true}
refresherTriggered={refresherTriggeredStatus}
selfOnRefresherRefresh={getRefresherRefresh}>
{orderData?.list?.map((item, index) => {
return (
<View key={item.id} className={styles.order_item_con}>
<ItemList obj={item} key={index}></ItemList>
</View>
)
})}
</InfiniteScroll> */}
<ItemList></ItemList>
</View>
{isManage ? (
<BottomEditBar onDelete={handleDelete} onSelectCheckbox={handleSelectAllCheckbox}></BottomEditBar>
) : (
<BottomSettleBar onSettleAccount={handleSettleAccount} amount={selectedAmount}></BottomSettleBar>
)}
</View>
</View>
)
}
export default User
export default Shopping
+20 -1
View File
@@ -1,11 +1,13 @@
$color_bg_one: #f8f8f8;
$color_font_one: #3c3c3c;
$color_font_one: rgba($color: #000000, $alpha: 0.8);
$color_font_two: #ababab;
$color_font_three: #707070;
$color_main: #4581ff;
$color_danger: #e64340;
$color_warning: #e6a23c;
$color_money: #F64861;
$color_info: rgba($color: #B3B3B3, $alpha: 0.2);
$opacity-disabled: 0.3;
$borderStyle: solid;
@@ -16,6 +18,8 @@ $font_size: 28px;
$font_size_medium: 24px;
$font_size_min: 22px;
$font_family: PingFangSC-Regular, PingFang SC;
$customTabBarHeight: 100px;
@@ -37,6 +41,21 @@ $customTabBarHeight: 100px;
-webkit-line-clamp: $params;
}
.flex-col {
display: flex;
flex-flow: column nowrap;
}
.flex-row {
display: flex;
flex-flow: row nowrap;
}
.justify-between {
justify-content: space-between
}
.flex-item {
flex: 1 1 auto;
}
.full-100 {
width: 100%;
height: 100%;