feat(颜色取样): 新增颜色取样模块

This commit is contained in:
xuan 2022-10-31 19:06:14 +08:00
parent e0de46c469
commit 2811f7eb60
15 changed files with 438 additions and 249 deletions

View File

@ -190,9 +190,16 @@
"query": "purchaser_id=1674", "query": "purchaser_id=1674",
"launchMode": "default", "launchMode": "default",
"scene": null "scene": null
},
{
"name": "",
"pathName": "pages/colorRelated/takeColor/index",
"query": "",
"launchMode": "default",
"scene": null
} }
] ]
} }
}, },
"libVersion": "2.26.0" "libVersion": "2.26.2"
} }

View File

@ -107,7 +107,7 @@ export const alert = {
icon: 'error', icon: 'error',
}) })
}, },
loading(title: string, mask: true | false = false) { loading(title: string, mask: boolean = false) {
Taro.showToast({ Taro.showToast({
title, title,
icon: 'loading', icon: 'loading',
@ -152,4 +152,4 @@ export const formatKbPrice = (number: string) => {
export const checkKey = (key = "") => { export const checkKey = (key = "") => {
let getUser = JSON.parse(Taro.getStorageSync("userInfo")); let getUser = JSON.parse(Taro.getStorageSync("userInfo"));
return getUser.mp_role_access_list?.includes(key); return getUser.mp_role_access_list?.includes(key);
}; };

View File

@ -159,6 +159,40 @@ export const toDecimal2 = x => {
return f return f
} }
// 匹配前缀 例如://xxx.com 或者 http://xxx.com 或者 https://xxx.com
// eslint-disable-next-line no-useless-escape
const URL_REGEXP = /(https?:)?\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()!@:%_\+.~#?&=]*)/gi
/**
* 判断是否有前缀
* @param {string} url url路径
*/
export const withBaseUrl = function(url) {
return URL_REGEXP.test(url)
}
/**
* 去除前缀 //xxx.com 或者 http://xxx.com 或者 https://xxx.com
* @param {string} url url路径
*/
export const breakupUrl = url => {
return url?.replace(URL_REGEXP, '') ?? url
}
/**
* 拼接前缀 http://xxx.com + /asdfsafdas/154531asdf465413.png
* @param {string} url url路径
*/
export const jointUrl = url => {
return withBaseUrl(url) ? url : `${IMG_CND_Prefix}${url}`
}
export const formatUrl = (url, suffix = '!w200') => {
if (url) {
url = url.includes(',') ? url.split(',')[0] : url
return withBaseUrl(url) ? url + suffix : jointUrl(url) + suffix
} else {
return IMG_CND_Prefix + '/mall/no_img.png'
}
}
/** /**
* 格式化图片路径 * 格式化图片路径
* @param {*} url * @param {*} url

View File

@ -1,4 +1,4 @@
import { View } from '@tarojs/components' import { RootPortal, View } from '@tarojs/components'
import style from './index.module.scss' import style from './index.module.scss'
import classnames from 'classnames' import classnames from 'classnames'
import { memo, ReactNode, useEffect, useMemo, useRef, useState } from 'react' import { memo, ReactNode, useEffect, useMemo, useRef, useState } from 'react'

View File

@ -1,52 +1,56 @@
import { Input, View } from "@tarojs/components"; import { Input, View } from '@tarojs/components'
import { memo, ReactHTMLElement, ReactNode, useDebugValue, useMemo } from "react"; import { memo, ReactHTMLElement, ReactNode, useDebugValue, useMemo } from 'react'
import styles from './index.module.scss'; import IconFont from '../iconfont/iconfont'
import styles from './index.module.scss'
type Params = { type Params = {
showIcon?: false|true, showIcon?: boolean
disabled?: false|true, disabled?: boolean
placeholder?: string, placeholder?: string
title?: string, title?: string
showTitle?: false|true, showTitle?: boolean
showBorder?: false|true, showBorder?: boolean
changeOnInput?: (string) => void, changeOnInput?: (string) => void
clickOnInput?: () => void, clickOnInput?: () => void
children?: ReactNode children?: ReactNode
height?: string, height?: string
titleStyle?: Object, titleStyle?: Object
styleObj?: Object styleObj?: Object
} }
export default memo((props: Params) => { export default memo((props: Params) => {
let { let {
showTitle = true, showTitle = true,
title = '标题', title = '标题',
showIcon = false, showIcon = false,
disabled = false, disabled = false,
placeholder = '请输入', placeholder = '请输入',
showBorder = true, showBorder = true,
changeOnInput, changeOnInput,
clickOnInput, clickOnInput,
height = '80rpx', height = '80rpx',
titleStyle = {} titleStyle = {},
} = props } = props
let stylen = useMemo(() => { let stylen = useMemo(() => {
if(!showBorder) { if (!showBorder) {
return { borderBottom: 0 } return { borderBottom: 0 }
} }
return {} return {}
}, [showBorder]) }, [showBorder])
return ( return (
<View className={styles.searchInput_main} style={{height: height, ...stylen}}> <View className={styles.searchInput_main} style={{ height: height, ...stylen }}>
{showTitle&&<View className={styles.searchInput_title} style={titleStyle}>{title}</View>} {showTitle && (
<View className={styles.searchInput_con}> <View className={styles.searchInput_title} style={titleStyle}>
{!props.children&&<Input disabled={disabled} placeholder={placeholder} onClick={() => clickOnInput?.()} onInput={(e) => changeOnInput?.(e.detail.value)}/> {title}
||<>{props.children}</>
}
</View>
{showIcon&&<View className={`iconfont icon-jiantou ${styles.icon_more_self}`}></View>}
</View> </View>
) )}
}) <View className={styles.searchInput_con}>
{(!props.children && (
<Input disabled={disabled} placeholder={placeholder} onClick={() => clickOnInput?.()} onInput={e => changeOnInput?.(e.detail.value)} />
)) || <>{props.children}</>}
</View>
{showIcon && <IconFont customClassName={styles.icon_more_self} name='icon-chakanquanbukehu' size={36} color='#333'></IconFont>}
</View>
)
})

View File

@ -1,82 +1,48 @@
.select_input {
width: 100%;
}
.select_input{ .input_type {
width: 100%; width: 100%;
font-size: 28px;
@include common_ellipsis();
max-width: 430px;
} }
.stock_ipnut_des{ .noCon {
border-bottom: 1rpx solid #F0F0F0; color: #cccccc;
padding: 20rpx 0 10rpx 10rpx !important;
.con_input{
display: flex;
align-items: center;
display: flex;
.label{
width: 120px;
font-size: 27px;
height: 60px;
display: flex;
align-items: center;
padding-left: 10px;
color: #707070;
font-weight: 700;
border-right: 2px solid #F3F3F3 ;
}
.input_con{
flex:1;
}
.input_type{
padding-left: 50px;
font-size: 28px;
@include common_ellipsis();
max-width: 430px;
}
.noCon{
color: #cccccc;
}
.iconfont{
color: #cccccc;
font-size: 30px;
}
}
} }
.stock_disabled{ .stock_disabled {
background: #f7f7f7; background: #f7f7f7;
border-radius: 10px; border-radius: 10px;
.label{ .label {
color: #cccccc !important; color: #cccccc !important;
} }
} }
.drawer { .drawer {
top:0; top: 0;
position:fixed; position: fixed;
} }
.selectCon{
width:100%; .selectList {
.selectInput{ .selectList-scroll-view {
width:100%; padding-top: 22px;
padding: 0 20px 20px 20px; height: 50vh;
border-bottom: 2px solid #F3F3F3; .selectItem {
box-sizing: border-box; font-size: 28px;
color: #707070;
padding: 22px 30px;
} }
.selectList{ .selected {
.selectList-scroll-view{ color: #3287ec;
height: 600px; font-weight: 700;
padding-top: 22px;
.selectItem{
font-size: 28px;
color: #707070;
padding: 22px 30px;
}
.selected{
color: #3287EC;
font-weight: 700;
}
}
} }
}
} }
.flexBox { .flexBox {
display: flex; display: flex;
width: 200px; width: 200px;
align-items: center; align-items: center;
justify-content: flex-end; justify-content: flex-end;
} }

View File

@ -1,11 +1,13 @@
import styles from './index.module.scss' import styles from './index.module.scss'
import { Image, Text, ScrollView, View } from '@tarojs/components' import { Image, Text, ScrollView, View, RootPortal } from '@tarojs/components'
import React, { FC, useCallback, useEffect, useMemo, useState } from 'react' import React, { FC, forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react'
import classnames from 'classnames' import classnames from 'classnames'
import Search from '../search' import Search from '../search'
import Popup from '../popup' import Popup from '../popup'
import { SelectProductListApi } from '@/api/index' import { SelectProductListApi } from '@/api/index'
import IconFont from '../iconfont/iconfont'
import { formatHashTag } from '@/common/format'
import SearchInput from '../searchInput'
type PropsType = { type PropsType = {
selectColorId: number selectColorId: number
@ -14,35 +16,51 @@ type PropsType = {
children?: React.ReactNode children?: React.ReactNode
} }
const SelectProduct:FC<PropsType> = (params) => { type productType = {
code?: string
default?: boolean
id: number
name: string
}
const SelectProduct = forwardRef((params: PropsType, ref) => {
const { selectColorId, noAll, onSelect } = params const { selectColorId, noAll, onSelect } = params
const [selectId, setSelectId] = useState(0) const [selectId, setSelectId] = useState(selectColorId)
useEffect(()=>{ const { fetchData } = SelectProductListApi()
setSelectId(selectColorId)
}, [selectColorId])
const {fetchData, state} = SelectProductListApi()
const [selectValue, setSelectValue] = useState() const [selectValue, setSelectValue] = useState()
const [productList, setProductList] = useState([{id:1}]) const [productList, setProductList] = useState<productType[]>([])
const clickEvent = () => {} const clickEvent = () => {
setShowPopup(true)
}
useImperativeHandle(
ref,
() => ({
clickEvent,
}),
[clickEvent],
)
const originList = useRef<productType[]>([])
const getSelectData = (item) => { const getSelectData = item => {
setSelectId(item.id) setSelectId(item.id)
setSelectValue(changeName(item)) setSelectValue(changeName(item))
setShowPopup(false) setShowPopup(false)
onSelect && onSelect(item) onSelect && onSelect(item)
} }
const changeName = (item) => { const changeName = item => {
if (item.id) { console.log('changeName', item)
return item.code.includes('#') ? item.code + ' ' + item.name : item.code + '# ' + item.name if (item) {
} else { if (item.id) {
return item.name return formatHashTag(item.code, item.name)
} else {
return item.name
}
} }
} }
@ -52,54 +70,60 @@ const SelectProduct:FC<PropsType> = (params) => {
const getProductList = async () => { const getProductList = async () => {
let res = await fetchData() let res = await fetchData()
!noAll && res.data.list?.unshift({ name: '全部', id: 0 }) // !noAll && res.data.list?.unshift({ name: '全部', id: 0 })
setProductList(res.data.list) !noAll && setProductList([{ name: '全部', id: 0 }, ...res.data.list])
originList.current = [{ name: '全部', id: 0 }, ...res.data.list]
} }
const list = useMemo(() => {
console.log('state', state)
return state.data.list || [{ id: 1 }]
}, [productList])
const [showPopup, setShowPopup] = useState(false) const [showPopup, setShowPopup] = useState(false)
const closeEven = () => {} const closeEven = () => {
setShowPopup(false)
}
//输入了搜索关键字 //输入了搜索关键字
const getSearchData = useCallback((e) => { const getSearchData = useCallback(
// pageNum.current.page = 1 async value => {
// setOrderData(() => ({ list: [], total: 0 })) console.log('e==>', value)
// setSearchField((val) => ({ ...val, name: e, size: 10 })) if (value === '') {
}, []) setProductList([...originList.current])
} else {
const res = await fetchData({
code_or_name: value,
})
if (res.success) {
setProductList(res.data.list)
}
}
},
[originList],
)
useEffect(() => { useEffect(() => {
setSelectId(selectColorId) setSelectId(selectColorId)
const res = productList.find((item) => item.id == selectColorId) const res = productList.find(item => item.id == selectColorId)
setSelectValue(changeName(res)) setSelectValue(changeName(res))
}, [selectColorId]) }, [selectColorId])
return ( return (
<> <>
<View className={styles.select_input}> <View className={styles.select_input}>
<View className={styles.stock_ipnut_des} onClick={clickEvent}> <SearchInput title='面料名称' showIcon={true} showBorder={false}>
<View className={styles.con_input}> <View onClick={clickEvent} className={classnames(styles.input_type, selectValue ? '' : 'noCon')}>
<View className={styles.label}></View> {selectValue ? selectValue : '请选择'}
<View className={styles.input_con}>
<View className={classnames(styles.input_type, selectValue ? '' : 'noCon')}>{selectValue ? selectValue : '请选择'}</View>
</View>
<Text className='iconfont icon-more'></Text>
</View> </View>
</View> </SearchInput>
</View> </View>
<Popup title='请选择面料名称' showTitle show={showPopup} onClose={closeEven}> <Popup title='请选择面料名称' showTitle show={showPopup} onClose={closeEven} position='bottom' customStyle={{ zIndex: 9999 }}>
<Search placeholder='请输入编号/面料' showBtn={false} changeOnSearch={getSearchData} debounceTime={300}></Search> <View style={{padding: '0 24rpx'}}>
<View className='selectList'> <Search placeholder='请输入编号/面料' showBtn={false} changeOnSearch={getSearchData} debounceTime={350}></Search>
<ScrollView className={styles['selectList-scroll-View']} scrollY> </View>
{list.map((item) => { <View className={styles.selectList}>
<ScrollView className={styles['selectList-scroll-view']} scrollY>
{productList.map(item => {
return ( return (
<View key={item.id} className={classnames(styles.selectItem, selectId == item.id ? styles.selected : '')} onClick={() => getSelectData(item)}> <View key={item.id} className={classnames(styles.selectItem, selectId == item.id ? styles.selected : '')} onClick={() => getSelectData(item)}>
{/* {changeName(item)} */} {changeName(item)}
</View> </View>
) )
})} })}
@ -108,5 +132,5 @@ const SelectProduct:FC<PropsType> = (params) => {
</Popup> </Popup>
</> </>
) )
} })
export default SelectProduct export default SelectProduct

View File

@ -26,6 +26,7 @@ export default memo(() => {
}, [state.available, state.connected]) }, [state.available, state.connected])
const linkName = useMemo(() => { const linkName = useMemo(() => {
console.log('state linkName', state)
return state.connected?.localName || '' return state.connected?.localName || ''
}, [state.connected]) }, [state.connected])
@ -37,6 +38,7 @@ export default memo(() => {
const [popupShow, setPopupShow] = useState(false) const [popupShow, setPopupShow] = useState(false)
//显示设备列表 //显示设备列表
const onFindDevice = () => { const onFindDevice = () => {
console.log('linkStatus==>', linkStatus)
if (linkStatus == 1) { if (linkStatus == 1) {
Taro.showToast({ Taro.showToast({
title: '请打开蓝牙', title: '请打开蓝牙',

View File

@ -4,6 +4,7 @@
border-radius: 10px; border-radius: 10px;
.bluetooth_link { .bluetooth_link {
width: 100%;
display: flex; display: flex;
align-items: center; align-items: center;

View File

@ -1,38 +1,55 @@
import { View, Text,Image } from '@tarojs/components' import { View, Text, Image } from '@tarojs/components'
import styles from './index.module.scss' import styles from './index.module.scss'
import classnames from 'classnames' import classnames from 'classnames'
import { FC, useRef, useState } from "react" import { FC, memo, useMemo, useRef, useState } from 'react'
import Upload from '../Upload' import Upload from '../Upload'
import {screenshot} from '@/common/util' import { screenshot } from '@/common/util'
import { formatImgUrl, formatUrl } from '@/common/format'
interface TextureEvent {
type PropsType = { onUploadConfirm?: (file: string) => void
onUploadConfirm?: Function }
interface PropsType extends TextureEvent {
list: any[]
detail: any
uploadConfirmState: boolean
} }
const Texture:FC<PropsType> = (params) => { const Texture: FC<PropsType> = params => {
const {onUploadConfirm} = params const { onUploadConfirm, list, detail, uploadConfirmState } = params
console.log('detail==>', detail)
const handleUploadConfirm = () => {
onUploadConfirm && onUploadConfirm() const handleUploadConfirm = (url) => {
onUploadConfirm && onUploadConfirm(url)
} }
const uploadEl = useRef() const uploadEl = useRef<any>(null)
const handleOpenModal = () => {
uploadEl.current.handleTriggerUploadModal(true)
}
const calcNoSampling = useMemo(() => {
let len = list?.filter(item => {
return item.currentLab?.l == 0 && item.currentLab?.a == 0 && item.currentLab?.b == 0
})
return len?.length ?? 0
}, [list])
return ( return (
<View className={styles['texture-container']}> <View className={styles['texture-container']}>
<View className={styles['tc-info']}> <View className={styles['tc-info']}>
<View onClick={uploadEl.handleTriggerUploadModal(true)} className={styles['tc-i-upload']}> <View onClick={handleOpenModal} className={styles['tc-i-upload']}>
{detail.texture_url && <Image src={screenshot(detail.texture_url)} />} {detail.texture_url && <Image src={formatUrl(detail.texture_url)} />}
<View v-else className={styles['tc-i-u-box']}>
<View v-else className='tc-i-u-box'> {/* TODO: 更换iconfont */}
<Text className='iconfont icon-shangchuanzhaopian'></Text> <Text className='iconfont icon-shangchuanzhaopian'></Text>
<View></View> <View></View>
</View> </View>
</View> </View>
<View className={styles['tc-i-num']}> <View className={styles['tc-i-num']}>
<View> <View>
<View className='color-blue'>{(data?.list?.length ?? 0) - calcNoSampling}</View> <View className='color-blue'>{(list?.length ?? 0) - calcNoSampling}</View>
<Text></Text> <Text></Text>
</View> </View>
<View> <View>
@ -41,7 +58,7 @@ const Texture:FC<PropsType> = (params) => {
</View> </View>
</View> </View>
</View> </View>
<Upload onUploadConfirm={handleUploadConfirm} ref={uploadEl} /> <Upload uploadConfirmState={uploadConfirmState} onUploadConfirm={handleUploadConfirm} ref={uploadEl} />
</View> </View>
) )
} }

View File

@ -1,16 +1,20 @@
import Popup from "@/components/popup" import Popup from '@/components/popup'
import { FC, useState } from "react" import { FC, forwardRef, useEffect, useImperativeHandle, useState } from 'react'
import { View, Text,Image } from '@tarojs/components' import { View, Text, Image, RootPortal } from '@tarojs/components'
import styles from './index.module.scss' import styles from './index.module.scss'
import classnames from 'classnames' import classnames from 'classnames'
import Taro from "@tarojs/taro" import Taro from '@tarojs/taro'
type PropsType = { interface UploadColorEvent {
onUploadConfirm?: Function onUploadConfirm?: Function
} }
const UploadColor: FC<PropsType> = (params) => { interface PropsType extends UploadColorEvent {
const { onUploadConfirm } = params uploadConfirmState: boolean
}
const UploadColor = forwardRef((params: PropsType, ref) => {
const { onUploadConfirm, uploadConfirmState } = params
const [showModal, setShowModal] = useState(false) const [showModal, setShowModal] = useState(false)
const [filePath, setFilePath] = useState('') const [filePath, setFilePath] = useState('')
const [file, setFile] = useState({}) const [file, setFile] = useState({})
@ -27,9 +31,23 @@ const UploadColor: FC<PropsType> = (params) => {
}) })
} }
useEffect(() => {
if (uploadConfirmState) {
setFilePath('')
handleTriggerUploadModal(false)
}
}, [uploadConfirmState])
const handleTriggerUploadModal = (bool: boolean) => { const handleTriggerUploadModal = (bool: boolean) => {
setShowModal(bool) setShowModal(bool)
} }
useImperativeHandle(
ref,
() => ({
handleTriggerUploadModal,
}),
[handleTriggerUploadModal],
)
const handleClear = () => { const handleClear = () => {
setFilePath('') setFilePath('')
@ -38,7 +56,6 @@ const UploadColor: FC<PropsType> = (params) => {
onUploadConfirm && onUploadConfirm(file) onUploadConfirm && onUploadConfirm(file)
} }
return ( return (
<View className={styles['upload-container']}> <View className={styles['upload-container']}>
<Popup title='上传纹理' show={showModal} onClose={() => handleTriggerUploadModal(false)}> <Popup title='上传纹理' show={showModal} onClose={() => handleTriggerUploadModal(false)}>
@ -58,5 +75,5 @@ const UploadColor: FC<PropsType> = (params) => {
</Popup> </Popup>
</View> </View>
) )
} })
export default UploadColor export default UploadColor

View File

@ -21,9 +21,12 @@ page {
padding-bottom: 220px; padding-bottom: 220px;
} }
.lb-title { .lb-title {
position: sticky;
top: 0;
z-index: 1;
font-size: 28px; font-size: 28px;
font-weight: 400; font-weight: 400;
line-height: 38px; background-color: #f3f3f3;
color: #707070; color: #707070;
border-top: 1px dashed #e4e4e4; border-top: 1px dashed #e4e4e4;
padding: 26px 46px; padding: 26px 46px;
@ -34,7 +37,6 @@ page {
} }
.lb-t-serach { .lb-t-serach {
@include flex-vertical-center; @include flex-vertical-center;
height: 100px;
} }
.lb-t-serach .icon-a-sousuo1 { .lb-t-serach .icon-a-sousuo1 {
font-size: 38px; font-size: 38px;
@ -43,6 +45,7 @@ page {
.lb-t-serach .lb-t-search-content { .lb-t-serach .lb-t-search-content {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
align-items: center;
} }
.lb-t-serach .lb-t-search-content > text { .lb-t-serach .lb-t-search-content > text {
padding: 10px 0; padding: 10px 0;
@ -72,10 +75,9 @@ page {
font-size: 30px; font-size: 30px;
} }
.lb-t-sc-clear { .lb-t-sc-clear {
width: 66px; display: flex;
height: 66px; justify-content: center;
text-align: center; align-items: center;
line-height: 66px;
} }
.lb-t-sc-clear .icon-a-cuowuwrong { .lb-t-sc-clear .icon-a-cuowuwrong {
width: 43px; width: 43px;

View File

@ -1,37 +1,51 @@
import { View, Input, Text } from '@tarojs/components' import { View, Input, Text } from '@tarojs/components'
import { FC, useMemo, useState } from 'react' import { FC, useMemo, useRef, useState } from 'react'
import LinkBlueTooth from '../components/bluetooth/LinkBlueTooth' import LinkBlueTooth from '../components/bluetooth/LinkBlueTooth'
import SelectProduct from '@/components/selectProduct/index' import SelectProduct from '@/components/selectProduct/index'
import styles from './index.module.scss' import styles from './index.module.scss'
import ColorCard from './components/ColorCard' import ColorCard from './components/ColorCard'
import IconFont from '@/components/iconfont/iconfont' import IconFont from '@/components/iconfont/iconfont'
import { ColorListApi, ColorDetailedApi, TextureSaveApi, ColorSamplingSaveApi } from '@/api/index' import { ColorListApi, ColorDetailedApi, TextureSaveApi, ColorSamplingSaveApi } from '@/api/index'
import { formatHashTag } from '@/common/format' import { breakupUrl, formatHashTag, formatImgUrl, formatUrl } from '@/common/format'
import { alert } from '@/common/common'
import Texture from './components/Texture'
import useUploadCDNImg from '@/use/useUploadImage'
import { useBluetooth } from '@/use/contextBlueTooth'
import { toRgb } from '@/common/bluetooth/color/colorSpace'
// 颜色取样 // 颜色取样
const TakeColor: FC = () => { const TakeColor: FC = () => {
const { state, fetchData } = ColorListApi() const { state, fetchData } = ColorListApi()
const { uploadCDNImg } = useUploadCDNImg()
const { state: detail, fetchData: detailFetchData } = ColorDetailedApi() const { state: detail, fetchData: detailFetchData } = ColorDetailedApi()
const { state: textureSaveData, fetchData: textureSaveFetchData } = TextureSaveApi() const { state: textureSaveData, fetchData: textureSaveFetchData } = TextureSaveApi()
const { state: saveData, fetchData: saveFetchData, success: saveSuccess } = ColorSamplingSaveApi() const { state: saveData, fetchData: saveFetchData } = ColorSamplingSaveApi()
const { measureAndGetLab, state: bluetoothState } = useBluetooth()
const [searchValue, setSearchValue] = useState('') const [searchValue, setSearchValue] = useState('')
const [selectedProduct, setSelectedProduct] = useState<Record<string, any>>({})
const selectInput = async (event) => { const selectInput = async event => {
// if (event) { if (event) {
// selectedProduct.value = event alert.showLoading('正在加载颜色')
// await fetchData({ id: event.id }) setSelectedProduct(event)
// data.value?.list.map((item, index) => { const res = await fetchData({ id: event.id })
// item.currnetRgb = item.rgb if (res.success) {
// item.currentLab = item.lab res.data?.list.map((item, index) => {
// item.sampling = !(item.currentLab?.l == 0 && item.currentLab?.a == 0 && item.currentLab?.b == 0) item.currnetRgb = item.rgb
// item.moveBorder = 0 item.currentLab = item.lab
// item.key = index item.sampling = !(item.currentLab?.l == 0 && item.currentLab?.a == 0 && item.currentLab?.b == 0)
// }) item.moveBorder = 0
// detailFetchData({ id: event.id }) item.key = index
// } else { })
// data.value.list = [] // setListData(res.data?.list)
// } await detailFetchData({ id: event.id })
}
alert.hideLoading()
} else {
state.data.list = []
alert.hideLoading()
}
} }
const clearSearchValue = () => { const clearSearchValue = () => {
setSearchValue('') setSearchValue('')
} }
@ -39,32 +53,102 @@ const TakeColor: FC = () => {
const handleTransfSearch = (bool: boolean) => { const handleTransfSearch = (bool: boolean) => {
setShowScreen(bool) setShowScreen(bool)
} }
const handlePrViewRgb = (event) => { const handlePrViewRgb = event => {
setLabPreview(event) setLabPreview(event)
setShowLabPreview(true) setShowLabPreview(true)
} }
const handleTakeColor = () => {}
const lastTakeColorIndex = useRef(null)
const handleTakeColor = async index => {
if (bluetoothState.connected) {
if (lastTakeColorIndex.current != null) {
state.data.list[lastTakeColorIndex.current].moveBorder = 0
}
lastTakeColorIndex.current = index
let item = state.data.list[index]
item.moveBorder = 1
let lab = await measureAndGetLab()
//转rgb
const rgb = toRgb([lab.L, lab.a, lab.b])
item.sampling = true
item.currnetRgb = {
r: rgb[0],
g: rgb[1],
b: rgb[2],
}
item.currentLab = {
l: lab.L,
a: lab.a,
b: lab.b,
}
item.moveBorder = 2
} else {
alert.none('请连接蓝牙')
}
}
// const [listData, setListData] = useState<Record<string, any>[]>([])
const listData = useMemo(() => { const listData = useMemo(() => {
return state.data?.list?.filter((item) => { return state.data?.list?.filter(item => {
if (searchValue) { if (searchValue) {
return formatHashTag(item.product_color_name, item.product_color_code)!.includes(searchValue) return formatHashTag(item.product_color_name, item.product_color_code)!.includes(searchValue)
} }
return true return true
}) })
}, [state]) }, [state.data?.list, state])
const [showScreen, setShowScreen] = useState(false) const [showScreen, setShowScreen] = useState(false)
const onSearchInput = (event) => { const onSearchInput = event => {
const current = event.detail.value const current = event.detail.value
setSearchValue(current) setSearchValue(current)
} }
// 底部提交
const handleSubmit = async () => {
if (selectedProduct.id) {
let params = {
id: selectedProduct.id,
product_color_absorb: state.data.list.map(item => {
return {
product_color_id: item.product_color_id,
l: item.currentLab.l,
a: item.currentLab.a,
b: item.currentLab.b,
// absorb_lab_time: `${dayjs(new Date())
// .add(0, "day")
// .format("YYYY-MM-DD")} 00:00:00`
absorb_lab_time: new Date(),
}
}),
}
alert.showLoading('保存中')
const res = await saveFetchData(params)
if (res.success) {
alert.success('保存成功')
} else {
alert.error('保存失败')
}
} else {
productSelectEl.current.clickEvent()
alert.none('请选择面料')
}
}
// 重置 // 重置
const handleReset = () => {} const handleReset = () => {
if (selectedProduct.id) {
// 提交 state.data.list.map(item => {
const handleSubmit = () => {} item.moveBorder = 0
item.currnetRgb = item.rgb
item.currentLab = item.lab
item.sampling = !(item.currentLab?.l == 0 && item.currentLab?.a == 0 && item.currentLab?.b == 0)
return item
})
} else {
productSelectEl.current.clickEvent()
alert.none('请选择面料')
}
}
const [labPreview, setLabPreview] = useState({ const [labPreview, setLabPreview] = useState({
currnetRgb: { currnetRgb: {
@ -76,12 +160,47 @@ const TakeColor: FC = () => {
const [showLabPreview, setShowLabPreview] = useState(false) const [showLabPreview, setShowLabPreview] = useState(false)
const productSelectEl = useRef<any>(null)
const [uploadConfirmState, setUploadConfirmState] = useState(false)
const handleUploadConfirm = async file => {
setUploadConfirmState(false)
if (file) {
if (selectedProduct.id) {
alert.showLoading('上传中')
let res = await uploadCDNImg({ path: file.tempFilePath }, 'product', 'product')
if (res && res?.code == 200) {
//console.log('图片地址真实',`${IMG_CND_Prefix}${res.url}`);
// TODO: 回填到存储的地方
await textureSaveFetchData({
id: selectedProduct.id,
texture_url: breakupUrl(res.url),
upload_texture_time: new Date(),
})
await detailFetchData({ id: selectedProduct.id })
alert.none('上传成功')
setUploadConfirmState(true)
} else {
res && alert.none(`${res.message}`)
}
} else {
productSelectEl.current.clickEvent()
alert.none('请选择面料')
}
} else {
alert.none('请选择图片')
}
}
return ( return (
<> <>
<View className={styles.card}> <View className={styles.card}>
<LinkBlueTooth /> <LinkBlueTooth />
<SelectProduct onSelect={selectInput} /> <SelectProduct selectColorId={selectedProduct?.id} onSelect={selectInput} ref={productSelectEl} />
</View> </View>
<Texture uploadConfirmState={uploadConfirmState} onUploadConfirm={handleUploadConfirm} list={state.data.list} detail={detail.data} />
<View className={styles['list-box']}> <View className={styles['list-box']}>
<View className={styles['lb-title']}> <View className={styles['lb-title']}>
<Text>{listData?.length ?? 0}</Text> <Text>{listData?.length ?? 0}</Text>
@ -91,14 +210,14 @@ const TakeColor: FC = () => {
<View> <View>
<Input value={searchValue} type='text' onInput={onSearchInput} placeholder='筛选颜色或颜色编号' /> <Input value={searchValue} type='text' onInput={onSearchInput} placeholder='筛选颜色或颜色编号' />
<View onClick={clearSearchValue} className={styles['lb-t-sc-clear']}> <View onClick={clearSearchValue} className={styles['lb-t-sc-clear']}>
{searchValue.length > 0 && <IconFont name='icon-guanbi' size={56}></IconFont>} {searchValue.length > 0 && <IconFont name='icon-guanbi' size={36}></IconFont>}
</View> </View>
</View> </View>
<Text onClick={() => handleTransfSearch(false)}></Text> <Text onClick={() => handleTransfSearch(false)}></Text>
</View> </View>
) : ( ) : (
<View onClick={() => handleTransfSearch(true)}> <View onClick={() => handleTransfSearch(true)}>
<IconFont name='icon-sousuo' size={56}></IconFont> <IconFont name='icon-sousuo' size={40}></IconFont>
</View> </View>
)} )}
</View> </View>

View File

@ -15,7 +15,6 @@ import { dataLoadingStatus, debounce, getFilterData } from '@/common/util'
import { ShoppingProvider } from './components/shoppingCart/index' import { ShoppingProvider } from './components/shoppingCart/index'
import { Goods, ShoppingDispatchType, useShoppingDispatch, useShoppingState } from './context' import { Goods, ShoppingDispatchType, useShoppingDispatch, useShoppingState } from './context'
import { alert, goLink, isEmptyObject } from '@/common/common' import { alert, goLink, isEmptyObject } from '@/common/common'
import LoadingCard from '@/components/loadingCard'
export const Shopping: FC = memo(() => { export const Shopping: FC = memo(() => {
// 计算总的预估金额 // 计算总的预估金额
@ -126,7 +125,7 @@ const ShoppingCartContainer: FC<InternalContainer> = () => {
useEffect(() => { useEffect(() => {
if (state.success) { if (state.success) {
// startTransition(() => { // startTransition(() => {
setShoppingCartData({ list: state.data, total: state.data.length }) setShoppingCartData({ list: state.data, total: state.data.length })
// }) // })
} }
}, [state]) }, [state])
@ -134,11 +133,11 @@ const ShoppingCartContainer: FC<InternalContainer> = () => {
// 结算 // 结算
const handleSettleAccount = debounce(() => { const handleSettleAccount = debounce(() => {
const multipleSelection = colorStore?.[currentCheckedPurchaserId]?.['multipleSelection'] const multipleSelection = colorStore?.[currentCheckedPurchaserId]?.['multipleSelection']
if (!multipleSelection) return Taro.showToast({ title: '请先选择客户', icon: 'error' }) if (!multipleSelection) return alert.error('请先选择客户')
const checkedGoodsKind = Object.values(multipleSelection).reduce((prev, item: Goods) => { const checkedGoodsKind = Object.values(multipleSelection).reduce((prev, item: Goods) => {
return [...prev, item.id] return [...prev, item.id]
}, []) }, [])
if (checkedGoodsKind.length === 0) return Taro.showToast({ title: '请先选择商品', icon: 'error' }) if (checkedGoodsKind.length === 0) return alert.error('请先选择商品')
goLink('/pages/submitOrder/index', { goLink('/pages/submitOrder/index', {
purchaser_id: currentCheckedPurchaserId, purchaser_id: currentCheckedPurchaserId,
sale_mode: currentCheckedSaleMode, sale_mode: currentCheckedSaleMode,
@ -154,17 +153,19 @@ const ShoppingCartContainer: FC<InternalContainer> = () => {
const multipleSelection = colorStore?.[currentCheckedPurchaserId].multipleSelection const multipleSelection = colorStore?.[currentCheckedPurchaserId].multipleSelection
let checked: Goods[] = Object.values(multipleSelection!) let checked: Goods[] = Object.values(multipleSelection!)
if (checked.length === 0) { if (checked.length === 0) {
return Taro.showToast({ title: '请选择商品', icon: 'error' }) return alert.error('请选择商品')
} }
console.log('checked==>', checked) console.log('checked==>', checked)
Taro.showModal({ Taro.showModal({
title: '要删除这些商品吗?', title: '要删除这些商品吗?',
success: async function(res) { success: async function(res) {
if (res.confirm) { if (res.confirm) {
alert.showLoading('删除中')
const res = await deleteApi({ const res = await deleteApi({
ids: checked.map(item => item.id).join(','), ids: checked.map(item => item.id).join(','),
}) })
if (res.success) { if (res.success) {
alert.hideLoading()
alert.success('删除成功') alert.success('删除成功')
// 清空多选 // 清空多选
dispatch({ dispatch({
@ -178,6 +179,7 @@ const ShoppingCartContainer: FC<InternalContainer> = () => {
fetchData(searchOptions) fetchData(searchOptions)
// Observer.notify(currentCheckedPurchaserId) // Observer.notify(currentCheckedPurchaserId)
} else { } else {
alert.hideLoading()
alert.none(res.msg) alert.none(res.msg)
} }
} }
@ -186,13 +188,10 @@ const ShoppingCartContainer: FC<InternalContainer> = () => {
} }
// 全选 // 全选
const handleSelectAllCheckbox = (isSelectAll: boolean) => { const handleSelectAllCheckbox = (isSelectAll: boolean) => {
console.log('handleSelectAllCheckbox', isSelectAll) const targetGoodsKind = colorStore?.[currentCheckedPurchaserId].goodsKind
const targetGoodsKind = colorStore?.[currentCheckedPurchaserId]?.['goodsKind'] if (!targetGoodsKind) return alert.error('请先选择客户')
if (!targetGoodsKind) return Taro.showToast({ title: '请先选择客户', icon: 'error' })
console.log('targetGoodsKind==>', targetGoodsKind)
const tempObject = { ...targetGoodsKind } const tempObject = { ...targetGoodsKind }
console.log('tempObject==>', tempObject)
dispatch({ dispatch({
type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX, type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
data: { data: {
@ -210,12 +209,10 @@ const ShoppingCartContainer: FC<InternalContainer> = () => {
setRefreshStatus(true) setRefreshStatus(true)
const res = await fetchData(searchOptions) const res = await fetchData(searchOptions)
if (res.success) { if (res.success) {
console.log('请求 成功')
setRefreshStatus(false) setRefreshStatus(false)
Taro.showToast({ title: '刷新成功', icon: 'success' }) alert.success('刷新成功')
} else { } else {
console.log('请求 失败') alert.error('刷新失败')
Taro.showToast({ title: '刷新失败', icon: 'error' })
setRefreshStatus(false) setRefreshStatus(false)
} }
} }
@ -237,11 +234,10 @@ const ShoppingCartContainer: FC<InternalContainer> = () => {
<View className={classnames('flex-item', 'flex-col', styles['shopping--context'])}> <View className={classnames('flex-item', 'flex-col', styles['shopping--context'])}>
<View id='shoppingListContainer' className={classnames(styles.shopping__list__container, 'flex-item')} style={{ height: listHeightRef.current }}> <View id='shoppingListContainer' className={classnames(styles.shopping__list__container, 'flex-item')} style={{ height: listHeightRef.current }}>
<InfiniteScroll statusMore={statusMore} refresherEnabled={true} selfOnRefresherRefresh={handleRefresh} refresherTriggered={refreshStatus}> <InfiniteScroll statusMore={statusMore} refresherEnabled={true} selfOnRefresherRefresh={handleRefresh} refresherTriggered={refreshStatus}>
{ {// isPending ? (
// isPending ? (
// null // null
// ) : ( // ) : (
!!shoppingCartData?.list?.length && !!shoppingCartData?.list?.length &&
shoppingCartData?.list?.map((item, index) => { shoppingCartData?.list?.map((item, index) => {
return <ItemList itemData={item} key={index}></ItemList> return <ItemList itemData={item} key={index}></ItemList>
}) })

View File

@ -63,7 +63,7 @@ export default () => {
return false return false
} }
return new Promise((resolve, reject) => { return new Promise<Record<string, any>>((resolve, reject) => {
getSecret(secene, type) getSecret(secene, type)
.then((result) => { .then((result) => {
let res: any = result let res: any = result