✨ feat: 优化码单管理
This commit is contained in:
parent
e8f050bcbb
commit
dd3963be99
@ -1,17 +1,77 @@
|
|||||||
import React, { useContext, useReducer } from 'react'
|
import React, { useContext, useReducer } from 'react'
|
||||||
import { useDispatch } from 'react-redux'
|
import type { saleModeType } from '@/common/enum'
|
||||||
import { CustomPrintCalculationApi } from '@/api/codeManage'
|
|
||||||
import type { CodeParam } from '@/reducers/codeData'
|
|
||||||
import { useSelector } from '@/reducers/hooks'
|
|
||||||
|
|
||||||
interface params {
|
interface params {
|
||||||
state: CodeParam
|
state: StateType
|
||||||
dispatch: React.Dispatch<any>
|
dispatch: React.Dispatch<Actions>
|
||||||
}
|
}
|
||||||
interface PropsType {
|
interface PropsType {
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ColorType {
|
||||||
|
estimate_amount: number
|
||||||
|
id: number
|
||||||
|
lab: { a: number; b: number; l: number }
|
||||||
|
length: number
|
||||||
|
product_color_code: string
|
||||||
|
product_color_id: number
|
||||||
|
product_color_name: string
|
||||||
|
rgb: { b: number; g: number; r: number }
|
||||||
|
roll: number
|
||||||
|
sale_mode: number
|
||||||
|
sale_mode_name: string
|
||||||
|
sale_offset: number
|
||||||
|
sale_price: number
|
||||||
|
standard_price: number
|
||||||
|
texture_url: string
|
||||||
|
weight_error: number
|
||||||
|
index_str: string
|
||||||
|
checked: boolean
|
||||||
|
has_screw_recommend: boolean
|
||||||
|
is_screw_recommend: boolean
|
||||||
|
}
|
||||||
|
export interface ProductType {
|
||||||
|
color_list: ColorType[]
|
||||||
|
product_code: string
|
||||||
|
product_id: number
|
||||||
|
product_name: string
|
||||||
|
index_str: string
|
||||||
|
checked: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StateType {
|
||||||
|
list: ProductType[]
|
||||||
|
modeNumber?: {
|
||||||
|
0: number
|
||||||
|
1: number
|
||||||
|
2: number
|
||||||
|
}
|
||||||
|
statistics?: {
|
||||||
|
product_number: number
|
||||||
|
color_number: number
|
||||||
|
roll_number: number
|
||||||
|
length_number: number
|
||||||
|
price_number: number
|
||||||
|
}
|
||||||
|
sale_mode?: saleModeType
|
||||||
|
checkList?: { [key in number]: boolean }
|
||||||
|
recommendSubmitStatus?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ActionsMap {
|
||||||
|
setInitData: StateType
|
||||||
|
updateProduct: StateType
|
||||||
|
setRecommendSubmit: StateType
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Actions = {
|
||||||
|
[Key in keyof ActionsMap]: {
|
||||||
|
type: Key
|
||||||
|
data: ActionsMap[Key]
|
||||||
|
}
|
||||||
|
}[keyof ActionsMap]
|
||||||
|
|
||||||
function createCtx<A extends {} | null>() {
|
function createCtx<A extends {} | null>() {
|
||||||
const ctx = React.createContext<A | undefined>(undefined)
|
const ctx = React.createContext<A | undefined>(undefined)
|
||||||
function useCtx() {
|
function useCtx() {
|
||||||
@ -21,17 +81,29 @@ function createCtx<A extends {} | null>() {
|
|||||||
}
|
}
|
||||||
return [useCtx, ctx.Provider] as const
|
return [useCtx, ctx.Provider] as const
|
||||||
}
|
}
|
||||||
export const [useCurrenCode, CurrentProvider] = createCtx<params>()
|
export const [useCurrenShop, CurrentProvider] = createCtx<params>()
|
||||||
|
|
||||||
// https://dev.to/elisealcala/react-context-with-usereducer-and-typescript-4obm
|
// https://dev.to/elisealcala/react-context-with-usereducer-and-typescript-4obm
|
||||||
export default (props: PropsType) => {
|
export default (props: PropsType) => {
|
||||||
const initialState = { count: 0 }
|
const initialState = {
|
||||||
function reducer(state, action) {
|
list: [],
|
||||||
|
statistics: {
|
||||||
|
product_number: 0,
|
||||||
|
color_number: 0,
|
||||||
|
roll_number: 0,
|
||||||
|
length_number: 0,
|
||||||
|
price_number: 0,
|
||||||
|
},
|
||||||
|
recommendSubmitStatus: false,
|
||||||
|
}
|
||||||
|
function reducer(state: StateType, action: Actions) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'increment':
|
case 'setInitData':
|
||||||
return { count: state.count + 1 }
|
return onInitData(state, action)
|
||||||
case 'decrement':
|
case 'updateProduct':
|
||||||
return { count: state.count - 1 }
|
return onUpdateData(state, action)
|
||||||
|
case 'setRecommendSubmit':
|
||||||
|
return { ...state, recommendSubmitStatus: action.data.recommendSubmitStatus }
|
||||||
default:
|
default:
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
@ -41,3 +113,37 @@ export default (props: PropsType) => {
|
|||||||
<CurrentProvider value={{ state, dispatch }} children={props.children}></CurrentProvider>
|
<CurrentProvider value={{ state, dispatch }} children={props.children}></CurrentProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 初始化数据
|
||||||
|
const onInitData = (state: StateType, action: Actions) => {
|
||||||
|
const { data } = action
|
||||||
|
const statistics = { product_number: 0, color_number: 0, roll_number: 0, length_number: 0, price_number: 0 }
|
||||||
|
data.list?.map((item, index) => {
|
||||||
|
item.index_str = index.toString()
|
||||||
|
item.checked = false
|
||||||
|
item.color_list?.map((citem, cindex) => {
|
||||||
|
citem.index_str = `${index},${cindex}`
|
||||||
|
citem.checked = false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return { ...state, list: data.list, sale_mode: data.sale_mode, recommendSubmitStatus: data.recommendSubmitStatus, statistics }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新数据
|
||||||
|
const onUpdateData = (state: StateType, action: Actions) => {
|
||||||
|
const { data } = action
|
||||||
|
const statistics = { product_number: 0, color_number: 0, roll_number: 0, length_number: 0, price_number: 0 }
|
||||||
|
data.list?.map((item, index) => {
|
||||||
|
item.color_list?.map((citem) => {
|
||||||
|
if (citem.checked) {
|
||||||
|
statistics.color_number += 1
|
||||||
|
statistics.price_number += citem.estimate_amount
|
||||||
|
statistics.roll_number += citem.roll
|
||||||
|
statistics.length_number += citem.length
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (item.checked) { statistics.product_number += 1 }
|
||||||
|
})
|
||||||
|
console.log('data:::', data.list)
|
||||||
|
return { ...state, list: data.list, statistics }
|
||||||
|
}
|
||||||
|
|||||||
72
src/context/ContextShop/reducers.ts
Normal file
72
src/context/ContextShop/reducers.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
type ActionMap<M extends Record<string, any>> = {
|
||||||
|
[Key in keyof M]: M[Key] extends undefined
|
||||||
|
? {
|
||||||
|
type: Key
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
type: Key
|
||||||
|
payload: M[Key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum Types {
|
||||||
|
Create = 'CREATE_PRODUCT',
|
||||||
|
Delete = 'DELETE_PRODUCT',
|
||||||
|
Add = 'ADD_PRODUCT',
|
||||||
|
}
|
||||||
|
|
||||||
|
// Product
|
||||||
|
|
||||||
|
interface ProductType {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
price: number
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ProductPayload {
|
||||||
|
[Types.Create]: {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
price: number
|
||||||
|
}
|
||||||
|
[Types.Delete]: {
|
||||||
|
id: number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ProductActions = ActionMap<ProductPayload>[keyof ActionMap<ProductPayload>]
|
||||||
|
|
||||||
|
export const productReducer = (state: ProductType[], action: ProductActions | ShoppingCartActions) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case Types.Create:
|
||||||
|
return [
|
||||||
|
...state,
|
||||||
|
{
|
||||||
|
id: action.payload.id,
|
||||||
|
name: action.payload.name,
|
||||||
|
price: action.payload.price,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
case Types.Delete:
|
||||||
|
return [
|
||||||
|
...state.filter(product => product.id !== action.payload.id),
|
||||||
|
]
|
||||||
|
default:
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ShoppingCartPayload {
|
||||||
|
[Types.Add]: undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ShoppingCartActions = ActionMap<ShoppingCartPayload>[keyof ActionMap<ShoppingCartPayload>]
|
||||||
|
|
||||||
|
export const shoppingCartReducer = (state: number, action: ProductActions | ShoppingCartActions) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case Types.Add:
|
||||||
|
return state + 1
|
||||||
|
default:
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -61,6 +61,6 @@ export default () => {
|
|||||||
</View>
|
</View>
|
||||||
})}
|
})}
|
||||||
</View>
|
</View>
|
||||||
<TimePickerPopup showTime={showTime} closePopup={handClose} onSelectDate={onSelectDate} />
|
<TimePickerPopup showTime={showTime} end={formData?.sale_end_time} start={formData?.sale_start_time} closePopup={handClose} onSelectDate={onSelectDate} />
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
z-index: 999;
|
z-index: 999;
|
||||||
|
box-shadow: 0px -5px 20px -8px rgba(0, 0, 0, 0.06);
|
||||||
.select_text {
|
.select_text {
|
||||||
padding: 0 32px 0 16px;
|
padding: 0 32px 0 16px;
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
@ -39,4 +40,7 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
line-height: 80px;
|
line-height: 80px;
|
||||||
}
|
}
|
||||||
|
.del {
|
||||||
|
background-color: #f44761ff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,18 +1,62 @@
|
|||||||
import { Text, View } from '@tarojs/components'
|
import { Text, View } from '@tarojs/components'
|
||||||
|
import { memo, useEffect, useMemo, useState } from 'react'
|
||||||
|
import classNames from 'classnames'
|
||||||
import styles from './index.module.scss'
|
import styles from './index.module.scss'
|
||||||
import MCheckbox from '@/components/checkbox'
|
import MCheckbox from '@/components/checkbox'
|
||||||
|
import type { StateType } from '@/context/ContextShop'
|
||||||
|
import { useCurrenShop } from '@/context/ContextShop'
|
||||||
|
import { formatPriceDiv } from '@/common/fotmat'
|
||||||
|
import type { saleModeType } from '@/common/enum'
|
||||||
|
|
||||||
export default () => {
|
interface ParamType {
|
||||||
return <View className={styles.Settlement_btn}>
|
onSelect?: (val: boolean) => void
|
||||||
<MCheckbox />
|
onBtnClick?: (val: boolean) => void
|
||||||
<Text className={styles.select_text}>全选</Text>
|
model: boolean
|
||||||
<View className={styles.price_count}>
|
|
||||||
<View className={styles.price}>
|
|
||||||
<Text>预估金额:</Text>
|
|
||||||
<Text>¥3564.00</Text>
|
|
||||||
</View>
|
|
||||||
<View className={styles.count}>已选1种面料,1个颜色,共4条</View>
|
|
||||||
</View>
|
|
||||||
<View className={styles.btn}>结算</View>
|
|
||||||
</View>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type IndexType = {
|
||||||
|
onSelect?: (val: boolean) => void
|
||||||
|
statistics?: StateType['statistics']
|
||||||
|
sale_mode?: saleModeType
|
||||||
|
}&ParamType
|
||||||
|
|
||||||
|
export default (props: ParamType) => {
|
||||||
|
const { onSelect, model, onBtnClick } = props
|
||||||
|
const { state, dispatch } = useCurrenShop()
|
||||||
|
return <Index onSelect={onSelect} statistics={state.statistics} model={model} onBtnClick={onBtnClick} sale_mode={state.sale_mode} />
|
||||||
|
}
|
||||||
|
|
||||||
|
const Index = memo((props: IndexType) => {
|
||||||
|
const { onSelect, statistics, model, sale_mode } = props
|
||||||
|
const [status, setStatus] = useState(false)
|
||||||
|
const getSelect = (status) => {
|
||||||
|
setStatus(() => status)
|
||||||
|
onSelect?.(status)
|
||||||
|
}
|
||||||
|
useEffect(() => {
|
||||||
|
setStatus(false)
|
||||||
|
}, [sale_mode])
|
||||||
|
const count = useMemo(() => {
|
||||||
|
return sale_mode === 0
|
||||||
|
? `已选${statistics?.product_number}种面料,${statistics?.color_number}个颜色,共${statistics?.roll_number}条`
|
||||||
|
: `已选${statistics?.product_number}种面料,${statistics?.color_number}个颜色,共${(statistics?.length_number || 0) / 100}米`
|
||||||
|
}, [statistics])
|
||||||
|
|
||||||
|
const onBtnClick = () => {
|
||||||
|
props.onBtnClick?.(model)
|
||||||
|
}
|
||||||
|
return <View className={styles.Settlement_btn}>
|
||||||
|
<MCheckbox status={status} onSelect={() => getSelect(true)} onClose={() => getSelect(false)} />
|
||||||
|
<Text className={styles.select_text} >全选</Text>
|
||||||
|
<View className={styles.price_count}>
|
||||||
|
{!model && <>
|
||||||
|
<View className={styles.price}>
|
||||||
|
<Text>预估金额:</Text>
|
||||||
|
<Text>¥{formatPriceDiv(statistics?.price_number)}</Text>
|
||||||
|
</View>
|
||||||
|
<View className={styles.count}>{count}</View>
|
||||||
|
</>}
|
||||||
|
</View>
|
||||||
|
<View onClick={onBtnClick} className={classNames(styles.btn, model && styles.del)}>{!model ? '结算' : '删除'}</View>
|
||||||
|
</View>
|
||||||
|
})
|
||||||
|
|||||||
33
src/pages/shopCar/components/colorCheckbox/index.tsx
Normal file
33
src/pages/shopCar/components/colorCheckbox/index.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { memo, useCallback } from 'react'
|
||||||
|
import MCheckbox from '@/components/checkbox'
|
||||||
|
import type { ColorType, ProductType } from '@/context/ContextShop'
|
||||||
|
import { useCurrenShop } from '@/context/ContextShop'
|
||||||
|
|
||||||
|
interface ParamType {
|
||||||
|
colorItem: ColorType
|
||||||
|
}
|
||||||
|
interface IndexType {
|
||||||
|
onSelect?: (val: boolean) => void
|
||||||
|
checkStatus: boolean
|
||||||
|
}
|
||||||
|
export default memo((props: ParamType) => {
|
||||||
|
const { colorItem } = props
|
||||||
|
const { state, dispatch } = useCurrenShop()
|
||||||
|
const indexs = colorItem.index_str.split(',')
|
||||||
|
const onSelect = useCallback((status) => {
|
||||||
|
state.list[indexs[0]].color_list[indexs[1]].checked = status
|
||||||
|
const tf = state.list[indexs[0]].color_list.some(item => item.checked)
|
||||||
|
state.list[indexs[0]].checked = tf
|
||||||
|
dispatch({ type: 'updateProduct', data: { list: state.list } })
|
||||||
|
}, [state.list[indexs[0]].color_list[indexs[1]].checked])
|
||||||
|
|
||||||
|
return <Index checkStatus={state.list[indexs[0]].color_list[indexs[1]].checked} onSelect={onSelect} />
|
||||||
|
})
|
||||||
|
|
||||||
|
const Index = memo((props: IndexType) => {
|
||||||
|
const { checkStatus, onSelect } = props
|
||||||
|
const setSelect = (status) => {
|
||||||
|
onSelect?.(status)
|
||||||
|
}
|
||||||
|
return <MCheckbox status={checkStatus} onSelect={() => setSelect(true)} onClose={() => setSelect(false)} />
|
||||||
|
})
|
||||||
28
src/pages/shopCar/components/main/index.module.scss
Normal file
28
src/pages/shopCar/components/main/index.module.scss
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
.shop_main {
|
||||||
|
min-height: 100vh;
|
||||||
|
background-color: #f8f8f8;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
.shop_con {
|
||||||
|
// flex: 1;
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: calc(100vh - 300px);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.scroll_view {
|
||||||
|
padding: 0 24px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.shop_header {
|
||||||
|
background-color: #fff;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1500;
|
||||||
|
.search_title {
|
||||||
|
padding: 0 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.loading_card {
|
||||||
|
height: 70vh;
|
||||||
|
}
|
||||||
|
}
|
||||||
242
src/pages/shopCar/components/main/index.tsx
Normal file
242
src/pages/shopCar/components/main/index.tsx
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
import { ScrollView, Text, View } from '@tarojs/components'
|
||||||
|
import Taro, { useDidShow } from '@tarojs/taro'
|
||||||
|
import React, { useCallback, useEffect, useMemo, useRef, useState, useTransition } from 'react'
|
||||||
|
import ProductBlock from '../productBlock'
|
||||||
|
import BottomBtn from '../bottomBtn'
|
||||||
|
import Operation from '../operation'
|
||||||
|
import type { listType } from '../search'
|
||||||
|
import Search from '../search'
|
||||||
|
import NoShop from '../noShop'
|
||||||
|
import styles from './index.module.scss'
|
||||||
|
import { DelShoppingCartApi, GetProductColorApi, GetShoppingCartV2Api } from '@/api/shopCart'
|
||||||
|
import type { ProductType } from '@/context/ContextShop'
|
||||||
|
import { useCurrenShop } from '@/context/ContextShop'
|
||||||
|
import type { saleModeType } from '@/common/enum'
|
||||||
|
import LoadingCard from '@/components/loadingCard'
|
||||||
|
import { alert, goLink } from '@/common/common'
|
||||||
|
import InfiniteScroll from '@/components/infiniteScroll'
|
||||||
|
import { dataLoadingStatus, throttle } from '@/common/util'
|
||||||
|
import { ApplyOrderAccessApi, GetAdminUserInfoApi } from '@/api/user'
|
||||||
|
import { setParam } from '@/common/system'
|
||||||
|
import type { SalesManDialogRef } from '@/components/bindSalesManDialog'
|
||||||
|
import BindSalesManDialog from '@/components/bindSalesManDialog'
|
||||||
|
import { useSelector } from '@/reducers/hooks'
|
||||||
|
import OrganizationNameModal from '@/components/organizationNameModal'
|
||||||
|
import useLogin from '@/use/useLogin'
|
||||||
|
import { companyDetailApi, companyUpdateApi } from '@/api/company'
|
||||||
|
|
||||||
|
interface FilterType {
|
||||||
|
abstract_sort_key: -1|1|2|-2
|
||||||
|
sale_mode: saleModeType
|
||||||
|
}
|
||||||
|
export default () => {
|
||||||
|
const { state, dispatch } = useCurrenShop()
|
||||||
|
const [filter, setFilter] = useState<FilterType>({
|
||||||
|
abstract_sort_key: -1,
|
||||||
|
sale_mode: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
const userInfo = useSelector(state => state.userInfo)
|
||||||
|
|
||||||
|
const [isPending, startTransition] = useTransition()
|
||||||
|
|
||||||
|
const { fetchData: getShoppingCartFetchData, state: shopState } = GetShoppingCartV2Api()
|
||||||
|
const getShoppingCart = async() => {
|
||||||
|
const res = await getShoppingCartFetchData(filter)
|
||||||
|
if (res.success) {
|
||||||
|
startTransition(() => {
|
||||||
|
dispatch({ type: 'setInitData', data: { list: JSON.parse(JSON.stringify(res?.data?.product_list)), sale_mode: filter.sale_mode, recommendSubmitStatus: false } })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const [modeNumber, setModeNumber] = useState({
|
||||||
|
bulk_number: 0,
|
||||||
|
length_length: 0,
|
||||||
|
weight_number: 0,
|
||||||
|
})
|
||||||
|
const { fetchData: productSkuFetchData } = GetProductColorApi()
|
||||||
|
const getProductColorNum = async() => {
|
||||||
|
const res = await productSkuFetchData()
|
||||||
|
if (res.success) {
|
||||||
|
setModeNumber(res.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const initStatus = useRef(false)
|
||||||
|
useDidShow(() => {
|
||||||
|
getProductColorNum()
|
||||||
|
initStatus.current && getShoppingCart()
|
||||||
|
initStatus.current = true
|
||||||
|
})
|
||||||
|
|
||||||
|
const onSelect = useCallback((status) => {
|
||||||
|
state.list?.map((item) => {
|
||||||
|
item.checked = status
|
||||||
|
item.color_list?.map((citem) => {
|
||||||
|
citem.checked = status
|
||||||
|
})
|
||||||
|
})
|
||||||
|
dispatch({ type: 'updateProduct', data: { list: state.list } })
|
||||||
|
}, [state.list])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getShoppingCart()
|
||||||
|
}, [filter])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log('state.recommendSubmitStatus::', state.recommendSubmitStatus)
|
||||||
|
if (state.recommendSubmitStatus) {
|
||||||
|
getProductColorNum()
|
||||||
|
getShoppingCart()
|
||||||
|
}
|
||||||
|
}, [state.recommendSubmitStatus])
|
||||||
|
|
||||||
|
const onSortChange = useCallback((val) => {
|
||||||
|
setFilter(e => ({ ...e, abstract_sort_key: val.value }))
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const getSelect = useCallback((val: listType) => {
|
||||||
|
setFilter(e => ({ ...e, sale_mode: val.value }))
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const logadingStatus = useMemo(() => {
|
||||||
|
return shopState.loading || isPending
|
||||||
|
}, [shopState.loading, isPending])
|
||||||
|
|
||||||
|
const [settingStatus, setSettingStatus] = useState(false)
|
||||||
|
const onChangeSetting = useCallback((val) => {
|
||||||
|
setSettingStatus(() => val)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const { fetchData: delShopFetchData } = DelShoppingCartApi()
|
||||||
|
const onBtnClick = (model) => {
|
||||||
|
if (model) {
|
||||||
|
delShop()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
orderDetail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bindSalesManDialogRef = useRef<SalesManDialogRef | null>(null)
|
||||||
|
const [showModal, setShowModal] = useState(false)
|
||||||
|
|
||||||
|
// 去结算
|
||||||
|
const { fetchData: FetchData } = GetAdminUserInfoApi()
|
||||||
|
const { fetchData: applyOrderAccessFetchData } = ApplyOrderAccessApi()
|
||||||
|
const orderDetail = throttle(async() => {
|
||||||
|
const res = await FetchData()
|
||||||
|
if (res.data.order_access_status !== 3) {
|
||||||
|
if (res.data.order_access_status == 1) { applyOrderAccessFetchData() }
|
||||||
|
bindSalesManDialogRef.current?.handleChange(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 检测是否修改过组织昵称
|
||||||
|
if (userInfo.adminUserInfo.first_change_name) {
|
||||||
|
setShowModal(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const SelectIds = getSelectIds()
|
||||||
|
if (SelectIds.length == 0) {
|
||||||
|
alert.error('请选择面料')
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const ids = SelectIds.join('-')
|
||||||
|
setParam({ ids, sale_mode: state.sale_mode }) // 临时存储
|
||||||
|
goLink('/pages/order/comfirm')
|
||||||
|
}
|
||||||
|
}, 500)
|
||||||
|
|
||||||
|
// 删除商品
|
||||||
|
const delShop = () => {
|
||||||
|
Taro.showModal({
|
||||||
|
content: '删除所选商品?',
|
||||||
|
async success(res) {
|
||||||
|
if (res.confirm) {
|
||||||
|
const ids = getSelectIds()
|
||||||
|
console.log('ids:::', ids)
|
||||||
|
const res = await delShopFetchData({ id: ids })
|
||||||
|
if (res.success) {
|
||||||
|
getShoppingCart()
|
||||||
|
getProductColorNum()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (res.cancel) {
|
||||||
|
console.log('用户点击取消')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 弹出修改组织昵称弹窗
|
||||||
|
const handleBindSalesManSuccess = () => {
|
||||||
|
// 检测是否修改过组织昵称
|
||||||
|
if (userInfo.adminUserInfo.first_change_name) {
|
||||||
|
setShowModal(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取面料选中的id
|
||||||
|
const getSelectIds = () => {
|
||||||
|
const ids: number[] = []
|
||||||
|
state.list.map((item) => {
|
||||||
|
item.color_list.map((citem) => {
|
||||||
|
citem.checked && ids.push(citem.id)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
return ids
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClose = useCallback(() => {
|
||||||
|
setShowModal(false)
|
||||||
|
}, [])
|
||||||
|
const handleShowChange = useCallback((val: boolean) => {
|
||||||
|
setShowModal(val)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const { getAdminUserInfo } = useLogin()
|
||||||
|
const { fetchData: saveFetch } = companyUpdateApi()
|
||||||
|
const { fetchData: getCompanyFetch } = companyDetailApi()
|
||||||
|
const handleOrganizationNameModalConfirm = useCallback(async(text: string) => {
|
||||||
|
const params = await getCompanyFetch()
|
||||||
|
const result = await saveFetch({
|
||||||
|
...params.data,
|
||||||
|
company_name: text,
|
||||||
|
})
|
||||||
|
if (result.success) {
|
||||||
|
getAdminUserInfo()
|
||||||
|
handleClose()
|
||||||
|
alert.success('保存成功')
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
alert.none(result.msg)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return <View className={styles.shop_main}>
|
||||||
|
<View className={styles.shop_header}>
|
||||||
|
<Operation onSelect={onSortChange} onChange={onChangeSetting} />
|
||||||
|
<View className={styles.search_title}>
|
||||||
|
<Search numberObj={modeNumber} defaultIndex={filter.sale_mode} onSelect={getSelect} />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View className={styles.shop_con}>
|
||||||
|
{logadingStatus && <View className={styles.loading_card}><LoadingCard /></View>}
|
||||||
|
{(!logadingStatus && state.list && state.list.length > 0) && <ScrollView scrollY className={styles.scroll_view}>
|
||||||
|
{state.list?.map(item => (<ProductBlock productItem={item} key={item.product_id} />))}
|
||||||
|
<View style={{ height: '100rpx' }}></View>
|
||||||
|
</ScrollView>}
|
||||||
|
{(!logadingStatus && !state.list) && <NoShop />}
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<BottomBtn onSelect={onSelect} model={settingStatus} onBtnClick={onBtnClick} />
|
||||||
|
<View>
|
||||||
|
<BindSalesManDialog ref={bindSalesManDialogRef} onSuccess={handleBindSalesManSuccess} />
|
||||||
|
</View>
|
||||||
|
<View>
|
||||||
|
<OrganizationNameModal showModal={showModal} onClose={handleClose} onShowModalChange={handleShowChange} onConfirm={handleOrganizationNameModalConfirm} />
|
||||||
|
</View>
|
||||||
|
<View className="common_safe_area_y"></View>
|
||||||
|
</View>
|
||||||
|
}
|
||||||
23
src/pages/shopCar/components/noShop/index.module.scss
Normal file
23
src/pages/shopCar/components/noShop/index.module.scss
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
.empty {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
.title {
|
||||||
|
color: $color_font_two;
|
||||||
|
font-size: $font_size_min;
|
||||||
|
}
|
||||||
|
.btn {
|
||||||
|
width: 222px;
|
||||||
|
height: 68px;
|
||||||
|
background-color: $color_main;
|
||||||
|
font-size: $font_size;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 68px;
|
||||||
|
margin-top: 42px;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/pages/shopCar/components/noShop/index.tsx
Normal file
13
src/pages/shopCar/components/noShop/index.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { View } from '@tarojs/components'
|
||||||
|
import { memo } from 'react'
|
||||||
|
import styles from './index.module.scss'
|
||||||
|
import { goLink } from '@/common/common'
|
||||||
|
|
||||||
|
export default memo(() => {
|
||||||
|
return <View className={styles.empty} onClick={() => goLink('/pages/index/index', {}, 'switchTab')}>
|
||||||
|
<View className={styles.title}>暂未选择商品</View>
|
||||||
|
<View className={styles.btn} >
|
||||||
|
去选购
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
})
|
||||||
82
src/pages/shopCar/components/operation/index.module.scss
Normal file
82
src/pages/shopCar/components/operation/index.module.scss
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
.shop_header_sort_main {
|
||||||
|
width: 100%;
|
||||||
|
background-color: #fff;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1500;
|
||||||
|
padding: 0 24px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.shop_header_sort {
|
||||||
|
height: 88px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 28px;
|
||||||
|
z-index: 1500;
|
||||||
|
position: relative;
|
||||||
|
background-color: #fff;
|
||||||
|
.sort {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background-color: rgb(245, 245, 245);
|
||||||
|
height: 55px;
|
||||||
|
padding: 0 24px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 55px;
|
||||||
|
font-size: 25px;
|
||||||
|
color: #337fffff;
|
||||||
|
}
|
||||||
|
.edit {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
text {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sort_list {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, auto);
|
||||||
|
justify-content: space-between;
|
||||||
|
grid-row-gap: 16px;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 0px 0px 16px 16px;
|
||||||
|
background-color: #fff;
|
||||||
|
z-index: 1300;
|
||||||
|
padding: 24px;
|
||||||
|
padding-top: 100px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
transform: translateY(-100%);
|
||||||
|
.item_sort {
|
||||||
|
width: 223px;
|
||||||
|
height: 68px;
|
||||||
|
border-radius: 34px;
|
||||||
|
background: #e9e9e9;
|
||||||
|
color: rgba(0, 0, 0, 0.6);
|
||||||
|
font-size: 28px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 68px;
|
||||||
|
}
|
||||||
|
.search_item_select {
|
||||||
|
background-color: #cde5ff;
|
||||||
|
color: #4581ff;
|
||||||
|
border: 1px solid #4581ff;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sort_list_selected {
|
||||||
|
transform: translateY(0%);
|
||||||
|
}
|
||||||
|
.mask {
|
||||||
|
position: fixed;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 1000;
|
||||||
|
background-color: rgba(0, 0, 0, 0.6);
|
||||||
|
}
|
||||||
52
src/pages/shopCar/components/operation/index.tsx
Normal file
52
src/pages/shopCar/components/operation/index.tsx
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { Text, View } from '@tarojs/components'
|
||||||
|
import { memo, useState } from 'react'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
import styles from './index.module.scss'
|
||||||
|
import IconFont from '@/components/iconfont/iconfont'
|
||||||
|
|
||||||
|
interface SortType { value: -1|1|-2|2; title: string }
|
||||||
|
interface ParamType {
|
||||||
|
onSelect: (val: SortType) => void
|
||||||
|
onChange: (val: boolean) => void
|
||||||
|
}
|
||||||
|
export default memo((props: ParamType) => {
|
||||||
|
const { onSelect } = props
|
||||||
|
const [open, setOpen] = useState(false)
|
||||||
|
const sort_data: SortType[] = [
|
||||||
|
{ value: -1, title: '添加时间降序' },
|
||||||
|
{ value: 1, title: '添加时间升序' },
|
||||||
|
{ value: -2, title: '面料编号降序' },
|
||||||
|
{ value: 2, title: '面料编号升序' },
|
||||||
|
]
|
||||||
|
const [selectData, setSelectData] = useState<SortType>({
|
||||||
|
value: -1, title: '添加时间降序',
|
||||||
|
})
|
||||||
|
const getSelect = (item) => {
|
||||||
|
setOpen(false)
|
||||||
|
onSelect(item)
|
||||||
|
setSelectData(item)
|
||||||
|
}
|
||||||
|
const [status, setStatus] = useState(false)
|
||||||
|
const onChange = () => {
|
||||||
|
setStatus(!status)
|
||||||
|
props.onChange?.(!status)
|
||||||
|
}
|
||||||
|
return <><View className={styles.shop_header_sort_main}>
|
||||||
|
<View className={styles.shop_header_sort}>
|
||||||
|
<View className={styles.sort} onClick={() => setOpen(true)}>
|
||||||
|
<IconFont name="icon-paixu1" size={30} color="#337FFFFF" />
|
||||||
|
<Text>{selectData.title}</Text>
|
||||||
|
<IconFont name="icon-zhankai" size={30} color="#337FFFFF" />
|
||||||
|
</View>
|
||||||
|
<View className={styles.edit} onClick={onChange}>
|
||||||
|
<IconFont name="icon-guanli" size={43} color={`${status ? '#337FFFFF' : '#000000FF'}`} />
|
||||||
|
<Text style={{ color: `${status ? '#337FFFFF' : '#000000FF'}` }}>{status ? '取消' : '管理'}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View className={classNames(styles.sort_list, open && styles.sort_list_selected)}>
|
||||||
|
{sort_data.map(item => <View key={item.value} onClick={() => getSelect(item)} className={classNames(styles.item_sort, (selectData.value === item.value) && styles.search_item_select)}>{item.title}</View>)}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
{open && <View className={styles.mask} onClick={() => setOpen(false)}></View>}
|
||||||
|
</>
|
||||||
|
})
|
||||||
@ -14,11 +14,23 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-bottom: 1px solid #ccc;
|
// border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
height: 1px;
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
background-color: rgba(0, 0, 0, 0.1);
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
transform: scaleY(0.5);
|
||||||
|
}
|
||||||
.model {
|
.model {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
color: rgba(0, 0, 0, 0.8);
|
||||||
.label {
|
.label {
|
||||||
width: 60px;
|
width: 60px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
|
|||||||
@ -1,24 +1,51 @@
|
|||||||
|
|
||||||
import { Text, View } from '@tarojs/components'
|
import { CustomWrapper, Text, View } from '@tarojs/components'
|
||||||
|
import { memo, useCallback, useEffect, useMemo } from 'react'
|
||||||
import ProductItem from '../productItem'
|
import ProductItem from '../productItem'
|
||||||
|
import Checkbox from '../productCheckbox'
|
||||||
import styles from './index.module.scss'
|
import styles from './index.module.scss'
|
||||||
import MCheckbox from '@/components/checkbox'
|
import MCheckbox from '@/components/checkbox'
|
||||||
|
import type { ProductType } from '@/context/ContextShop'
|
||||||
|
import { useCurrenShop } from '@/context/ContextShop'
|
||||||
|
import { formatHashTag } from '@/common/fotmat'
|
||||||
|
import type { saleModeType } from '@/common/enum'
|
||||||
|
|
||||||
export default () => {
|
interface ParamType {
|
||||||
|
productItem: ProductType
|
||||||
|
}
|
||||||
|
type IndexType = {
|
||||||
|
onSelect?: (val: boolean) => void
|
||||||
|
sale_mode: saleModeType
|
||||||
|
} & ParamType
|
||||||
|
export default memo((props: ParamType) => {
|
||||||
|
const { productItem } = props
|
||||||
|
// const { state, dispatch } = useCurrenShop()
|
||||||
|
useEffect(() => {
|
||||||
|
console.log('productItem66:::', productItem)
|
||||||
|
}, [productItem])
|
||||||
|
return <Index productItem={productItem} sale_mode={0} />
|
||||||
|
})
|
||||||
|
|
||||||
|
const Index = memo((props: IndexType) => {
|
||||||
|
const { productItem, onSelect, sale_mode } = props
|
||||||
|
const setSelect = (status) => {
|
||||||
|
onSelect?.(status)
|
||||||
|
}
|
||||||
|
const sale_mode_name = useMemo(() => {
|
||||||
|
const data = ['大货', '剪版', '删剪']
|
||||||
|
return data[sale_mode]
|
||||||
|
}, [sale_mode])
|
||||||
|
console.log('productItem22::', productItem)
|
||||||
return <View className={styles.shop_product}>
|
return <View className={styles.shop_product}>
|
||||||
<View className={styles.shop_product_title}>
|
<View className={styles.shop_product_title}>
|
||||||
<MCheckbox />
|
<Checkbox productItem={productItem} />
|
||||||
<View className={styles.title_desc}>
|
<View className={styles.title_desc}>
|
||||||
<View className={styles.model}>
|
<View className={styles.model}>
|
||||||
<Text className={styles.name}>0681# 26s全棉平纹</Text>
|
<Text className={styles.name}>{formatHashTag(productItem?.product_code, productItem?.product_name)}</Text>
|
||||||
<Text className={styles.label}>大货</Text>
|
<Text className={styles.label}>{sale_mode_name}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View className={styles.unit}>大货单位:条</View>
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<ProductItem />
|
{productItem?.color_list?.map(item => <ProductItem key={item.product_color_id} colorItem={item} />)}
|
||||||
<ProductItem />
|
|
||||||
<ProductItem />
|
|
||||||
<ProductItem />
|
|
||||||
</View>
|
</View>
|
||||||
}
|
})
|
||||||
|
|||||||
33
src/pages/shopCar/components/productCheckbox/index copy.tsx
Normal file
33
src/pages/shopCar/components/productCheckbox/index copy.tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { memo, useCallback } from 'react'
|
||||||
|
import MCheckbox from '@/components/checkbox'
|
||||||
|
import type { ProductType } from '@/context/ContextShop'
|
||||||
|
import { useCurrenShop } from '@/context/ContextShop'
|
||||||
|
|
||||||
|
interface ParamType {
|
||||||
|
productItem: ProductType
|
||||||
|
}
|
||||||
|
type IndexType = {
|
||||||
|
onSelect?: (val: boolean) => void
|
||||||
|
} & ParamType
|
||||||
|
export default memo((props: ParamType) => {
|
||||||
|
const { productItem } = props
|
||||||
|
const { state, dispatch } = useCurrenShop()
|
||||||
|
const index = productItem.index_str.split(',')[0]
|
||||||
|
const onSelect = useCallback((status) => {
|
||||||
|
state.list[index] = { ...state.list[index], checked: status }
|
||||||
|
state.list[index].color_list?.map((citem, cindex) => {
|
||||||
|
state.list[index].color_list[cindex] = { ...state.list[index].color_list[cindex], checked: status }
|
||||||
|
})
|
||||||
|
dispatch({ type: 'updateProduct', data: { list: state.list } })
|
||||||
|
}, [state.list[index]])
|
||||||
|
|
||||||
|
return <Index productItem={state.list[index]} onSelect={onSelect} />
|
||||||
|
})
|
||||||
|
|
||||||
|
const Index = memo((props: IndexType) => {
|
||||||
|
const { productItem, onSelect } = props
|
||||||
|
const setSelect = (status) => {
|
||||||
|
onSelect?.(status)
|
||||||
|
}
|
||||||
|
return <MCheckbox status={productItem.checked} onSelect={() => setSelect(true)} onClose={() => setSelect(false)} />
|
||||||
|
})
|
||||||
32
src/pages/shopCar/components/productCheckbox/index.tsx
Normal file
32
src/pages/shopCar/components/productCheckbox/index.tsx
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { memo, useCallback } from 'react'
|
||||||
|
import MCheckbox from '@/components/checkbox'
|
||||||
|
import type { ProductType } from '@/context/ContextShop'
|
||||||
|
import { useCurrenShop } from '@/context/ContextShop'
|
||||||
|
|
||||||
|
interface ParamType {
|
||||||
|
productItem: ProductType
|
||||||
|
}
|
||||||
|
interface IndexType {
|
||||||
|
onSelect?: (val: boolean) => void
|
||||||
|
checkStatus: boolean
|
||||||
|
}
|
||||||
|
export default memo((props: ParamType) => {
|
||||||
|
const { productItem } = props
|
||||||
|
const { state, dispatch } = useCurrenShop()
|
||||||
|
const index = productItem.index_str.split(',')[0]
|
||||||
|
const onSelect = useCallback((status) => {
|
||||||
|
state.list[index].checked = status
|
||||||
|
state.list[index].color_list?.map((citem, cindex) => citem.checked = status)
|
||||||
|
dispatch({ type: 'updateProduct', data: { list: state.list } })
|
||||||
|
}, [state.list[index].checked])
|
||||||
|
|
||||||
|
return <Index checkStatus={state.list[index].checked} onSelect={onSelect} />
|
||||||
|
})
|
||||||
|
|
||||||
|
const Index = memo((props: IndexType) => {
|
||||||
|
const { checkStatus, onSelect } = props
|
||||||
|
const setSelect = (status) => {
|
||||||
|
onSelect?.(status)
|
||||||
|
}
|
||||||
|
return <MCheckbox status={checkStatus} onSelect={() => setSelect(true)} onClose={() => setSelect(false)} />
|
||||||
|
})
|
||||||
@ -1,48 +1,102 @@
|
|||||||
.shop_product_item_con {
|
.shop_product_item_con {
|
||||||
padding-bottom: 20px;
|
padding-bottom: 20px;
|
||||||
|
position: relative;
|
||||||
|
&:nth-child(n + 3) {
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
height: 1px;
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
background-color: rgba(0, 0, 0, 0.1);
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
transform: scaleY(0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
.shop_product_item {
|
.shop_product_item {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 24px 0;
|
align-items: center;
|
||||||
|
height: 166px;
|
||||||
.item_con {
|
.item_con {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
.img {
|
.img {
|
||||||
width: 118px;
|
width: 118px;
|
||||||
height: 118px;
|
height: 118px;
|
||||||
}
|
}
|
||||||
.item_name_price_count {
|
.item_name_price_count {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
margin-left: 32px;
|
margin-left: 24px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
height: 118px;
|
||||||
.name_price {
|
.name_price {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
font-size: 28px;
|
font-size: 28px;
|
||||||
text {
|
.price {
|
||||||
&:nth-child(2) {
|
text {
|
||||||
color: red;
|
&:nth-child(1) {
|
||||||
|
color: #999999;
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
&:nth-child(2) {
|
||||||
|
color: #f41a39ff;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.count {
|
.count_con {
|
||||||
width: 201px;
|
width: 100%;
|
||||||
align-self: flex-end;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
.recommend_title {
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 24px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
text {
|
||||||
|
text-align: center;
|
||||||
|
&:nth-child(1) {
|
||||||
|
width: 61px;
|
||||||
|
height: 34px;
|
||||||
|
background: #fee5cd;
|
||||||
|
color: #522b0fff;
|
||||||
|
font-weight: 700;
|
||||||
|
border-radius: 4px 0px 0px 4px;
|
||||||
|
}
|
||||||
|
&:nth-child(2) {
|
||||||
|
width: 112px;
|
||||||
|
height: 34px;
|
||||||
|
background: #fcf4e9;
|
||||||
|
color: #c57c26ff;
|
||||||
|
border-radius: 0px 4px 4px 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.count {
|
||||||
|
width: 201px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.recommended {
|
.recommended {
|
||||||
height: 60px;
|
height: 82px;
|
||||||
padding: 0 20px 0 50px;
|
padding: 0 20px 0 50px;
|
||||||
background-color: #ccc;
|
background: #f6f6f6;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
font-size: 25px;
|
font-size: 24px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
color: rgba(0, 0, 0, 0.8);
|
||||||
.icon {
|
.icon {
|
||||||
transform: rotate(-90deg);
|
transform: rotate(-90deg);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,36 +1,122 @@
|
|||||||
import { Text, View } from '@tarojs/components'
|
import { CustomWrapper, Text, View } from '@tarojs/components'
|
||||||
|
import Taro from '@tarojs/taro'
|
||||||
|
import { memo, useCallback, useEffect, useMemo } from 'react'
|
||||||
|
import Big from 'big.js'
|
||||||
|
import ColorCheckbox from '../colorCheckbox'
|
||||||
|
import RecommendProduct from '../recommendProduct'
|
||||||
import styles from './index.module.scss'
|
import styles from './index.module.scss'
|
||||||
import MCheckbox from '@/components/checkbox'
|
|
||||||
import LabAndImg from '@/components/LabAndImg'
|
import LabAndImg from '@/components/LabAndImg'
|
||||||
import Counter from '@/components/counter'
|
import Counter from '@/components/counter'
|
||||||
import IconFont from '@/components/iconfont/iconfont'
|
import type { ColorType } from '@/context/ContextShop'
|
||||||
|
import { useCurrenShop } from '@/context/ContextShop'
|
||||||
|
import { formatPriceDiv } from '@/common/fotmat'
|
||||||
|
import { GetShoppingCartApi, UpdateShoppingCartApi } from '@/api/shopCart'
|
||||||
|
import { debounce } from '@/common/util'
|
||||||
|
import { SALE_MODE_SETTING } from '@/common/enum'
|
||||||
|
|
||||||
export default () => {
|
interface ColorItemType {
|
||||||
|
colorItem: ColorType
|
||||||
|
}
|
||||||
|
|
||||||
|
type IndexItemType = {
|
||||||
|
onSelect?: (val: boolean) => void
|
||||||
|
onChangeNum?: (val: { id: number; length: number; roll: number }) => void
|
||||||
|
onSubmitSuccess?: () => void
|
||||||
|
}&ColorItemType
|
||||||
|
|
||||||
|
export default memo((props: ColorItemType) => {
|
||||||
|
const { fetchData: updateShoppingCartFetchData } = UpdateShoppingCartApi()
|
||||||
|
const { fetchData: getShoppingCartFetchData } = GetShoppingCartApi()
|
||||||
|
const { colorItem } = props
|
||||||
|
const { state, dispatch } = useCurrenShop()
|
||||||
|
const indexs = colorItem.index_str.split(',')
|
||||||
|
const colorItemNew = state.list[indexs[0]].color_list[indexs[1]]
|
||||||
|
const onChangeNum = useCallback(async(val) => {
|
||||||
|
await updateShoppingCartFetchData(val)
|
||||||
|
const res = await getShoppingCartFetchData({ id: colorItem.id })
|
||||||
|
if (res.success) {
|
||||||
|
state.list[indexs[0]].color_list[indexs[1]] = { ...state.list[indexs[0]].color_list[indexs[1]], ...res.data.color_list[0] }
|
||||||
|
dispatch({ type: 'updateProduct', data: { list: state.list } })
|
||||||
|
}
|
||||||
|
}, [colorItemNew])
|
||||||
|
|
||||||
|
const onSubmitSuccess = useCallback(() => {
|
||||||
|
Taro.showToast({
|
||||||
|
title: '添加成功',
|
||||||
|
icon: 'success',
|
||||||
|
duration: 1000,
|
||||||
|
success: () => {
|
||||||
|
dispatch({ type: 'setRecommendSubmit', data: { list: state.list, recommendSubmitStatus: true } })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
return <Index colorItem={state.list[indexs[0]].color_list[indexs[1]]} onChangeNum={onChangeNum} onSubmitSuccess={onSubmitSuccess} />
|
||||||
|
})
|
||||||
|
|
||||||
|
const Index = memo((props: IndexItemType) => {
|
||||||
|
const { colorItem, onChangeNum, onSubmitSuccess } = props
|
||||||
|
const rga = useMemo(() => {
|
||||||
|
return { lab: colorItem.lab, rgb: colorItem.rgb, texture_url: colorItem.texture_url, title: colorItem.product_color_code }
|
||||||
|
}, [colorItem])
|
||||||
|
const getCount = debounce(async(num) => {
|
||||||
|
const data = { id: colorItem.id, length: 0, roll: 0 }
|
||||||
|
if (colorItem.sale_mode === 0) {
|
||||||
|
data.roll = num
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
data.length = Big(num).times(100).toNumber()
|
||||||
|
}
|
||||||
|
onChangeNum?.(data)
|
||||||
|
}, 300)
|
||||||
|
const selectList = SALE_MODE_SETTING
|
||||||
|
const saleSetting = useMemo(() => {
|
||||||
|
return selectList[colorItem.sale_mode]
|
||||||
|
}, [colorItem])
|
||||||
|
console.log('colorItem::', colorItem)
|
||||||
return <>
|
return <>
|
||||||
<View className={styles.shop_product_item_con}>
|
<View className={styles.shop_product_item_con}>
|
||||||
<View className={styles.shop_product_item}>
|
<View className={styles.shop_product_item}>
|
||||||
<MCheckbox />
|
<ColorCheckbox colorItem={colorItem} />
|
||||||
<View className={styles.item_con}>
|
<View className={styles.item_con}>
|
||||||
<View className={styles.img}>
|
<View className={styles.img}>
|
||||||
<LabAndImg value={{}}></LabAndImg>
|
<LabAndImg value={rga}></LabAndImg>
|
||||||
</View>
|
</View>
|
||||||
<View className={styles.item_name_price_count}>
|
<View className={styles.item_name_price_count}>
|
||||||
<View className={styles.name_price}>
|
<View className={styles.name_price}>
|
||||||
<Text>001# 环保黑</Text>
|
<Text>{colorItem.product_color_code + colorItem.product_color_name}</Text>
|
||||||
<Text>¥37.50/kg</Text>
|
<View className={styles.price}>
|
||||||
|
<Text>¥{formatPriceDiv(colorItem.sale_price)}</Text>
|
||||||
|
<Text>¥{formatPriceDiv(colorItem.standard_price)}/kg</Text>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View className={styles.count}>
|
<View className={styles.count_con}>
|
||||||
<Counter defaultNum={1} />
|
<View className={styles.recommend_title}>
|
||||||
|
{colorItem.is_screw_recommend
|
||||||
|
&& <>
|
||||||
|
<Text>推荐</Text>
|
||||||
|
<Text>配套罗纹</Text>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
</View>
|
||||||
|
<View className={styles.count}>
|
||||||
|
<CustomWrapper>
|
||||||
|
<Counter
|
||||||
|
onClickBtn={getCount}
|
||||||
|
minNum={saleSetting.minNum}
|
||||||
|
maxNum={saleSetting.maxNum}
|
||||||
|
onBlue={getCount}
|
||||||
|
defaultNum={colorItem.sale_mode === 0 ? colorItem.roll : colorItem.length / 100}
|
||||||
|
unit={colorItem.sale_mode === 0 ? '条' : '米'}
|
||||||
|
digits={saleSetting.digits}
|
||||||
|
/>
|
||||||
|
</CustomWrapper>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
<View className={styles.recommended}>
|
{colorItem.has_screw_recommend && <RecommendProduct shopId={colorItem.id} submitSuccess={onSubmitSuccess} />}
|
||||||
<Text>选择专属一对一配套螺纹推荐</Text>
|
|
||||||
<View className={styles.icon}>
|
|
||||||
<IconFont name="icon-xiala" size={30} />
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
</View>
|
||||||
</>
|
</>
|
||||||
}
|
})
|
||||||
|
|||||||
@ -0,0 +1,59 @@
|
|||||||
|
.recommended_main {
|
||||||
|
.recommended {
|
||||||
|
height: 82px;
|
||||||
|
padding: 0 20px 0 50px;
|
||||||
|
background: #f6f6f6;
|
||||||
|
border-radius: 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 24px;
|
||||||
|
align-items: center;
|
||||||
|
color: rgba(0, 0, 0, 0.8);
|
||||||
|
.icon {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.recommended_open {
|
||||||
|
width: 654px;
|
||||||
|
height: 502px;
|
||||||
|
position: fixed;
|
||||||
|
margin: auto;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
background-color: #fff;
|
||||||
|
z-index: 1600;
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 32px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-start;
|
||||||
|
.search {
|
||||||
|
padding-bottom: 22px;
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
.onSubmit {
|
||||||
|
width: 590px;
|
||||||
|
height: 80px;
|
||||||
|
background: #337fff;
|
||||||
|
border-radius: 16px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 80px;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 28px;
|
||||||
|
margin-top: 60px;
|
||||||
|
justify-self: end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.mask {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
height: 100vh;
|
||||||
|
width: 100vh;
|
||||||
|
background: rgba(0, 0, 0, 0.6);
|
||||||
|
z-index: 1500;
|
||||||
|
}
|
||||||
|
}
|
||||||
103
src/pages/shopCar/components/recommendProduct/index.tsx
Normal file
103
src/pages/shopCar/components/recommendProduct/index.tsx
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import { Text, View } from '@tarojs/components'
|
||||||
|
import { memo, useCallback, useEffect, useRef, useState } from 'react'
|
||||||
|
import Big from 'big.js'
|
||||||
|
import Search from '../search'
|
||||||
|
import type { ItemType } from '../recommendProductItem'
|
||||||
|
import RecommendProductItem from '../recommendProductItem'
|
||||||
|
import styles from './index.module.scss'
|
||||||
|
import IconFont from '@/components/iconfont/iconfont'
|
||||||
|
import { AddShoppingCartApi, GetScrewProductApi } from '@/api/shopCart'
|
||||||
|
import type { listType, saleModeType } from '@/common/enum'
|
||||||
|
import { SALE_MODE_SETTING } from '@/common/enum'
|
||||||
|
|
||||||
|
interface ParamType {
|
||||||
|
shopId: number
|
||||||
|
submitSuccess?: () => void
|
||||||
|
}
|
||||||
|
type DataType = ItemType
|
||||||
|
|
||||||
|
interface submitType {
|
||||||
|
color_list: { product_color_id: number; roll: number; length: number }[]
|
||||||
|
sale_mode: saleModeType
|
||||||
|
is_screw_recommend: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo((props: ParamType) => {
|
||||||
|
const selectList = SALE_MODE_SETTING
|
||||||
|
const { shopId, submitSuccess } = props
|
||||||
|
const [filter, setFilter] = useState({
|
||||||
|
id: 0,
|
||||||
|
sale_mode: 0,
|
||||||
|
})
|
||||||
|
const submitData = useRef<submitType>({
|
||||||
|
sale_mode: 0,
|
||||||
|
color_list: [],
|
||||||
|
is_screw_recommend: true,
|
||||||
|
})
|
||||||
|
useEffect(() => {
|
||||||
|
(filter.id !== shopId) && setFilter(e => ({ ...e, id: shopId }))
|
||||||
|
}, [shopId])
|
||||||
|
const [productData, setProductData] = useState<DataType>()
|
||||||
|
const { fetchData: getScrewProductFetchData } = GetScrewProductApi()
|
||||||
|
const getScrewProduct = async() => {
|
||||||
|
const res = await getScrewProductFetchData({ id: filter.id, sale_mode: filter.sale_mode })
|
||||||
|
if (res.success) {
|
||||||
|
res.data = {
|
||||||
|
...res.data,
|
||||||
|
sale_mode_type: filter.sale_mode,
|
||||||
|
}
|
||||||
|
onSubmitData(res.data.defaultNum, res.data.screw_color_id)
|
||||||
|
setProductData(res.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const [showOpen, setShowOpen] = useState(false)
|
||||||
|
useEffect(() => {
|
||||||
|
showOpen && getScrewProduct()
|
||||||
|
}, [showOpen, filter])
|
||||||
|
|
||||||
|
const getSelect = useCallback((val: listType) => {
|
||||||
|
submitData.current.sale_mode = val.value
|
||||||
|
setFilter(e => ({ ...e, sale_mode: val.value }))
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const onChangeNum = useCallback((num) => {
|
||||||
|
onSubmitData(num, productData?.screw_color_id)
|
||||||
|
}, [productData])
|
||||||
|
|
||||||
|
// 整理提交数据
|
||||||
|
const onSubmitData = (num = 0, product_color_id = 0) => {
|
||||||
|
const data = { product_color_id, length: 0, roll: 0 }
|
||||||
|
if (filter.sale_mode === 0) {
|
||||||
|
data.roll = num
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
data.length = Big(num).times(100).toNumber()
|
||||||
|
}
|
||||||
|
submitData.current.color_list = [data]
|
||||||
|
}
|
||||||
|
|
||||||
|
const { fetchData: addShoppingCartfetchData } = AddShoppingCartApi()
|
||||||
|
const onSubmit = useCallback(async() => {
|
||||||
|
const res = await addShoppingCartfetchData(submitData.current)
|
||||||
|
if (res.success) {
|
||||||
|
submitSuccess?.()
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return <View className={styles.recommended_main}>
|
||||||
|
<View className={styles.recommended} onClick={() => setShowOpen(true)}>
|
||||||
|
<Text>选择专属一对一配套螺纹推荐</Text>
|
||||||
|
<View className={styles.icon}>
|
||||||
|
<IconFont name="icon-xiala" size={30} />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
{showOpen && <View className={styles.recommended_open}>
|
||||||
|
<View className={styles.search}>
|
||||||
|
<Search onSelect={getSelect} numberStatus={false} defaultIndex={filter.sale_mode} />
|
||||||
|
</View>
|
||||||
|
<RecommendProductItem colorItem={productData!} onChangeNum={onChangeNum} />
|
||||||
|
<View className={styles.onSubmit} onClick={onSubmit}>确认添加</View>
|
||||||
|
</View>}
|
||||||
|
{showOpen && <View catchMove className={styles.mask} onClick={() => setShowOpen(false)}></View>}
|
||||||
|
</View>
|
||||||
|
})
|
||||||
@ -0,0 +1,101 @@
|
|||||||
|
.shop_product_item_con {
|
||||||
|
padding-bottom: 20px;
|
||||||
|
position: relative;
|
||||||
|
&:nth-child(n + 3) {
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
height: 1px;
|
||||||
|
width: 100%;
|
||||||
|
position: absolute;
|
||||||
|
background-color: rgba(0, 0, 0, 0.1);
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
transform: scaleY(0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.shop_product_item {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 166px;
|
||||||
|
.title_desc {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
padding: 24px 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
.model {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
color: rgba(0, 0, 0, 0.8);
|
||||||
|
.label {
|
||||||
|
width: 60px;
|
||||||
|
height: 28px;
|
||||||
|
font-size: 20px;
|
||||||
|
background-color: #4581ff;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-left: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.item_con {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
.img {
|
||||||
|
width: 118px;
|
||||||
|
height: 118px;
|
||||||
|
}
|
||||||
|
.item_name_price_count {
|
||||||
|
flex: 1;
|
||||||
|
margin-left: 24px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 118px;
|
||||||
|
.name_price {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 28px;
|
||||||
|
.price {
|
||||||
|
text {
|
||||||
|
&:nth-child(1) {
|
||||||
|
color: #999999;
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
&:nth-child(2) {
|
||||||
|
color: #f41a39ff;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.count {
|
||||||
|
width: 201px;
|
||||||
|
align-self: flex-end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.recommended {
|
||||||
|
height: 82px;
|
||||||
|
padding: 0 20px 0 50px;
|
||||||
|
background: #f6f6f6;
|
||||||
|
border-radius: 10px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 24px;
|
||||||
|
align-items: center;
|
||||||
|
color: rgba(0, 0, 0, 0.8);
|
||||||
|
.icon {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
108
src/pages/shopCar/components/recommendProductItem/index.tsx
Normal file
108
src/pages/shopCar/components/recommendProductItem/index.tsx
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
import { CustomWrapper, Text, View } from '@tarojs/components'
|
||||||
|
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
|
import ColorCheckbox from '../colorCheckbox'
|
||||||
|
import RecommendProduct from '../recommendProduct'
|
||||||
|
import styles from './index.module.scss'
|
||||||
|
import LabAndImg from '@/components/LabAndImg'
|
||||||
|
import Counter from '@/components/counter'
|
||||||
|
import { formatHashTag, formatPriceDiv } from '@/common/fotmat'
|
||||||
|
import { debounce } from '@/common/util'
|
||||||
|
import type { listType } from '@/common/enum'
|
||||||
|
import { SALE_MODE_SETTING, saleModeType } from '@/common/enum'
|
||||||
|
|
||||||
|
export interface ItemType {
|
||||||
|
lab: { l: number; a: number; b: number }
|
||||||
|
rgb: { r: number; g: number; b: number }
|
||||||
|
sale_offset: number
|
||||||
|
sale_price: number
|
||||||
|
screw_code: string
|
||||||
|
screw_color_code: string
|
||||||
|
screw_color_id: number
|
||||||
|
screw_color_name: string
|
||||||
|
screw_id: number
|
||||||
|
screw_name: string
|
||||||
|
standard_price: number
|
||||||
|
texture_url: string
|
||||||
|
weight_error: number
|
||||||
|
sale_mode_type: 0|1|2
|
||||||
|
sale_mode: '大货'|'剪板'|'散剪'
|
||||||
|
unit: '条'|'米'
|
||||||
|
eunit: 'kg'|'m'
|
||||||
|
step: number
|
||||||
|
digits: number
|
||||||
|
minNum: number
|
||||||
|
maxNum: number
|
||||||
|
defaultNum: number
|
||||||
|
}
|
||||||
|
export interface ProductType {
|
||||||
|
colorItem: ItemType
|
||||||
|
onChangeNum?: (val: number) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo((props: ProductType) => {
|
||||||
|
return <Index {...props} />
|
||||||
|
})
|
||||||
|
|
||||||
|
const Index = memo((props: ProductType) => {
|
||||||
|
const { colorItem, onChangeNum } = props
|
||||||
|
const rga = useMemo(() => {
|
||||||
|
return { lab: colorItem?.lab, rgb: colorItem?.rgb, texture_url: colorItem?.texture_url, title: colorItem?.screw_color_code }
|
||||||
|
}, [colorItem])
|
||||||
|
const getCount = debounce((num: number) => {
|
||||||
|
setDefaultNum(num)
|
||||||
|
}, 300)
|
||||||
|
const selectList: listType[] = SALE_MODE_SETTING
|
||||||
|
const saleSetting: listType = useMemo(() => {
|
||||||
|
console.log('colorItem123123::', colorItem)
|
||||||
|
return colorItem && selectList[colorItem.sale_mode_type]
|
||||||
|
}, [colorItem?.sale_mode_type])
|
||||||
|
const [defaultNum, setDefaultNum] = useState(0)
|
||||||
|
useEffect(() => {
|
||||||
|
if (colorItem) {
|
||||||
|
setDefaultNum(selectList[colorItem.sale_mode_type].defaultNum)
|
||||||
|
}
|
||||||
|
}, [colorItem?.sale_mode_type])
|
||||||
|
useEffect(() => {
|
||||||
|
onChangeNum?.(defaultNum)
|
||||||
|
}, [defaultNum])
|
||||||
|
return <>
|
||||||
|
<View className={styles.shop_product_item_con}>
|
||||||
|
<View className={styles.shop_product_item}>
|
||||||
|
<View className={styles.title_desc}>
|
||||||
|
<View className={styles.model}>
|
||||||
|
<Text className={styles.name}>{formatHashTag(colorItem?.screw_code, colorItem?.screw_name)}</Text>
|
||||||
|
<Text className={styles.label}>{saleSetting?.title}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View className={styles.item_con}>
|
||||||
|
<View className={styles.img}>
|
||||||
|
<LabAndImg value={rga}></LabAndImg>
|
||||||
|
</View>
|
||||||
|
<View className={styles.item_name_price_count}>
|
||||||
|
<View className={styles.name_price}>
|
||||||
|
<Text>{colorItem?.screw_color_code + colorItem?.screw_color_name}</Text>
|
||||||
|
<View className={styles.price}>
|
||||||
|
<Text>¥{formatPriceDiv(colorItem?.sale_price)}</Text>
|
||||||
|
<Text>¥{formatPriceDiv(colorItem?.standard_price)}/kg</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<View className={styles.count}>
|
||||||
|
<CustomWrapper>
|
||||||
|
<Counter
|
||||||
|
onClickBtn={getCount}
|
||||||
|
minNum={saleSetting?.minNum}
|
||||||
|
maxNum={saleSetting?.maxNum}
|
||||||
|
onBlue={getCount}
|
||||||
|
defaultNum={defaultNum}
|
||||||
|
unit={saleSetting?.unit}
|
||||||
|
digits={saleSetting?.digits}
|
||||||
|
/>
|
||||||
|
{/* <Counter onClickBtn={getCount} maxNum={colorItem?.maxNum} minNum={colorItem?.minNum} onBlue={getCount} defaultNum={colorItem?.defaultNum} unit={colorItem?.sale_mode_type === 0 ? '条' : '米'} /> */}
|
||||||
|
</CustomWrapper>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
|
})
|
||||||
@ -1,14 +1,20 @@
|
|||||||
.shop_search {
|
.shop_search {
|
||||||
display: flex;
|
display: grid;
|
||||||
justify-content: space-between;
|
grid-template-columns: repeat(3, auto);
|
||||||
|
grid-column-gap: 16px;
|
||||||
|
justify-items: stretch;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
// padding: 0 24px;
|
||||||
|
box-sizing: border-box;
|
||||||
.search_item {
|
.search_item {
|
||||||
|
width: 100%;
|
||||||
height: 68px;
|
height: 68px;
|
||||||
width: 224px;
|
flex: 1;
|
||||||
border-radius: 68px;
|
border-radius: 68px;
|
||||||
text-align: center;
|
display: flex;
|
||||||
line-height: 68px;
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
font-size: 30px;
|
font-size: 30px;
|
||||||
background-color: #f8f8f8;
|
background-color: #f8f8f8;
|
||||||
color: rgba(0, 0, 0, 0.8);
|
color: rgba(0, 0, 0, 0.8);
|
||||||
|
|||||||
@ -1,23 +1,32 @@
|
|||||||
import { Text, View } from '@tarojs/components'
|
import { Text, View } from '@tarojs/components'
|
||||||
import { memo, useEffect, useState } from 'react'
|
import { memo, useEffect, useMemo, useState } from 'react'
|
||||||
|
import classNames from 'classnames'
|
||||||
import styles from './index.module.scss'
|
import styles from './index.module.scss'
|
||||||
|
import type { StateType } from '@/context/ContextShop'
|
||||||
|
import type { listType } from '@/common/enum'
|
||||||
|
import { SALE_MODE_SETTING } from '@/common/enum'
|
||||||
|
|
||||||
interface Params {
|
interface Params {
|
||||||
defaultIndex?: number
|
defaultIndex?: number
|
||||||
onSelect?: (val: number) => void
|
onSelect?: (val: listType) => void
|
||||||
|
numberObj?: {
|
||||||
|
'bulk_number': number
|
||||||
|
'length_length': number
|
||||||
|
'weight_number': number }
|
||||||
|
numberStatus?: boolean
|
||||||
}
|
}
|
||||||
export default memo((props: Params) => {
|
export default memo((props: Params) => {
|
||||||
const selectList = [
|
const { numberStatus = true } = props
|
||||||
{ value: 0, title: '大货', unit: '条', eunit: 'kg', step: 1, digits: 0, minNum: 1, maxNum: 100000, defaultNum: 1 },
|
const selectList = SALE_MODE_SETTING
|
||||||
{ value: 1, title: '剪板', unit: '米', eunit: 'm', step: 1, digits: 2, minNum: 0.5, maxNum: 9.99, defaultNum: 1 },
|
const { defaultIndex = 0, onSelect, numberObj } = props
|
||||||
{ value: 2, title: '散剪', unit: '米', eunit: 'kg', step: 1, digits: 2, minNum: 3, maxNum: 100000, defaultNum: 3 },
|
|
||||||
]
|
|
||||||
const { defaultIndex = 0, onSelect } = props
|
|
||||||
const [index, setIndex] = useState(0)
|
const [index, setIndex] = useState(0)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
defaultIndex !== index && setIndex(defaultIndex)
|
defaultIndex !== index && setIndex(defaultIndex)
|
||||||
}, [defaultIndex])
|
}, [defaultIndex])
|
||||||
|
const getName = (item) => {
|
||||||
|
return item.title + (numberStatus ? `(${numberObj?.[item.field]})` : '')
|
||||||
|
}
|
||||||
return <View className={styles.shop_search}>
|
return <View className={styles.shop_search}>
|
||||||
{selectList?.map(item => <View key={item.value} onClick={() => onSelect?.(item.value)} className={styles.search_item}>{item.title}</View>)}
|
{selectList?.map(item => <View key={item.value} onClick={() => onSelect?.(item)} className={classNames(styles.search_item, index === item.value && styles.search_item_select)}>{getName(item)}</View>)}
|
||||||
</View>
|
</View>
|
||||||
})
|
})
|
||||||
|
|||||||
@ -0,0 +1,3 @@
|
|||||||
|
export default {
|
||||||
|
navigationBarTitleText: '购物车',
|
||||||
|
}
|
||||||
@ -1,36 +0,0 @@
|
|||||||
.shop_main {
|
|
||||||
min-height: 100vh;
|
|
||||||
background-color: #f8f8f8;
|
|
||||||
.shop_header {
|
|
||||||
padding: 0 24px;
|
|
||||||
background-color: #fff;
|
|
||||||
.shop_header_sort {
|
|
||||||
height: 88px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
font-size: 28px;
|
|
||||||
.sort {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
background-color: rgb(245, 245, 245);
|
|
||||||
height: 55px;
|
|
||||||
padding: 0 24px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
border-radius: 55px;
|
|
||||||
font-size: 25px;
|
|
||||||
}
|
|
||||||
.edit {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
text {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.shop_con {
|
|
||||||
padding: 0 24px;
|
|
||||||
padding-bottom: 150px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,82 +1,8 @@
|
|||||||
import { Text, View } from '@tarojs/components'
|
import Main from './components/main'
|
||||||
import React, { ReactHTMLElement, memo, useEffect, useRef, useState } from 'react'
|
import ContextShop from '@/context/ContextShop'
|
||||||
import styles from './index.module.scss'
|
|
||||||
import Search from './components/search'
|
|
||||||
import ProductBlock from './components/productBlock'
|
|
||||||
import BottomBtn from './components/bottomBtn'
|
|
||||||
import Screwed from './components/screwed'
|
|
||||||
import IconFont from '@/components/iconfont/iconfont'
|
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
useEffect(() => {
|
return <ContextShop>
|
||||||
initData()
|
<Main />
|
||||||
}, [])
|
</ContextShop>
|
||||||
const [data, setData] = useState<any[]>([])
|
|
||||||
const initData = () => {
|
|
||||||
const product_list: any = []
|
|
||||||
new Array(10).fill('').map((item, index) => {
|
|
||||||
const product: any = {
|
|
||||||
product_code: `100${index}`,
|
|
||||||
product_id: index + 1,
|
|
||||||
product_name: '26s全棉平纹',
|
|
||||||
color_list: [],
|
|
||||||
}
|
|
||||||
new Array(130).fill('').map((citem, cindex) => {
|
|
||||||
product.color_list.push({
|
|
||||||
estimate_amount: 100,
|
|
||||||
estimate_weight: 100,
|
|
||||||
id: 0,
|
|
||||||
lab: {
|
|
||||||
a: 0,
|
|
||||||
b: 0,
|
|
||||||
l: 0,
|
|
||||||
},
|
|
||||||
length: 0,
|
|
||||||
product_code: '00',
|
|
||||||
product_color_code: `00${cindex}}`,
|
|
||||||
product_color_id: cindex + 1,
|
|
||||||
product_color_name: '环保黑',
|
|
||||||
product_id: 0,
|
|
||||||
product_name: 'string',
|
|
||||||
rgb: {
|
|
||||||
b: 0,
|
|
||||||
g: 0,
|
|
||||||
r: 0,
|
|
||||||
},
|
|
||||||
roll: 10,
|
|
||||||
sale_mode: 0,
|
|
||||||
sale_mode_name: '大货',
|
|
||||||
sale_offset: 500,
|
|
||||||
sale_price: 500,
|
|
||||||
standard_price: 500,
|
|
||||||
texture_url: '',
|
|
||||||
weight_error: 500,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
product_list.push(product)
|
|
||||||
})
|
|
||||||
setData(product_list)
|
|
||||||
}
|
|
||||||
|
|
||||||
return <View className={styles.shop_main}>
|
|
||||||
<View className={styles.shop_header}>
|
|
||||||
<View className={styles.shop_header_sort}>
|
|
||||||
<View className={styles.sort}>
|
|
||||||
<IconFont name="icon-paixu" size={30} />
|
|
||||||
<Text>添加时间降序</Text>
|
|
||||||
</View>
|
|
||||||
<View className={styles.edit}>
|
|
||||||
<IconFont name="icon-guanli" size={43} />
|
|
||||||
<Text>编辑</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
<Search />
|
|
||||||
</View>
|
|
||||||
<View className={styles.shop_con}>
|
|
||||||
{data?.map((item, index) => <ProductBlock key={index} />)}
|
|
||||||
</View>
|
|
||||||
<BottomBtn />
|
|
||||||
{/* <Screwed /> */}
|
|
||||||
<View className="common_safe_area_y"></View>
|
|
||||||
</View>
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user