已对接登录和下单选择商品

This commit is contained in:
czm 2022-05-07 18:51:13 +08:00
parent 883c24b7be
commit d03105a7d0
14 changed files with 228 additions and 126 deletions

View File

@ -4,9 +4,9 @@ import { useRequest } from "@/use/useHttp"
* *
* @returns * @returns
*/ */
export const Login = () => { export const LoginApi = () => {
return useRequest({ return useRequest({
url: `/v1/mall/login`, url: `/v1/mall/login`,
method: "post", method: "post",
}) })
} }

31
src/api/user.ts Normal file
View File

@ -0,0 +1,31 @@
import { useRequest } from "@/use/useHttp"
/**
*
*/
export const GetWxUserInfoApi = () => {
return useRequest({
url: `/v1/mall/user/decrypt`,
method: "post",
})
}
/**
*
*/
export const GetSelfUserInfoApi = () => {
return useRequest({
url: `/v1/mall/user/info`,
method: "get",
})
}
/**
*
*/
export const GetPhoneNumberApi = () => {
return useRequest({
url: `/v1/mall/user/phoneNumber`,
method: "post",
})
}

View File

@ -5,10 +5,11 @@
// export const BASE_URL = `http://192.168.0.89:40001/lymarket` // export const BASE_URL = `http://192.168.0.89:40001/lymarket`
// export const BASE_URL = `http://192.168.1.165:40001/lymarket` // 王霞 // export const BASE_URL = `http://192.168.1.165:40001/lymarket` // 王霞
// export const BASE_URL = `https://test.zzfzyc.com/lymarket` // 测试环境 // export const BASE_URL = `https://test.zzfzyc.com/lymarket` // 测试环境
export const BASE_URL = `http://192.168.1.30:40001/lymarket` // 发 // export const BASE_URL = `http://192.168.1.30:40001/lymarket` // 发
// export const BASE_URL = `https://dev.zzfzyc.com/lymarket` // 开发环境 // export const BASE_URL = `https://dev.zzfzyc.com/lymarket` // 开发环境
// export const BASE_URL = `https://www.zzfzyc.com/lymarket` // 正式环境 // export const BASE_URL = `https://www.zzfzyc.com/lymarket` // 正式环境
// export const BASE_URL = `http://192.168.1.165:40001/lymarket` // 王霞 // export const BASE_URL = `http://192.168.1.165:40001/lymarket` // 王霞
export const BASE_URL = `http://192.168.1.224:50001/lymarket` // 添
// CDN // CDN
// 生成密钥 // 生成密钥

View File

@ -44,7 +44,6 @@ export const throttle = (fn, delay) => {
for(let key in val) { for(let key in val) {
if(val[key]!=undefined&&val[key]!=null&&(!arr.includes(key))){ if(val[key]!=undefined&&val[key]!=null&&(!arr.includes(key))){
if(val[key] instanceof Number){ if(val[key] instanceof Number){
console.log("+++",val[key]);
if(!isNaN(val[key])) { if(!isNaN(val[key])) {
res[key] = val[key] res[key] = val[key]
} }

View File

@ -16,7 +16,7 @@ type Params = {
showBtn?: false|true, showBtn?: false|true,
btnStyle?: Object, btnStyle?: Object,
btnTitle?: string, btnTitle?: string,
debounceTime?: number //防抖时间,不设默认wei'ling debounceTime?: number //防抖时间,不设默认为零
} }
export default memo(({ export default memo(({

View File

@ -3,18 +3,19 @@ import { useEffect, useMemo, useRef, useState } from "react"
import Big from 'big.js' import Big from 'big.js'
import styles from "./index.module.scss" import styles from "./index.module.scss"
type params = { type params = {
minNum?: number, minNum?: number, //最小值
maxNum?: number, maxNum?: number, //最大值
step?: number, step?: number, //步长
defaultNum?: number, defaultNum?: number, //默认值
digits?: number //多少位小数 digits?: number //多少位小数
onChange?:(val:number) => void, onChange?:(val:number) => void,
onBlue?:(val:number) => void, onBlue?:(val:number) => void, //失去焦点触发
onClickBtn?:(val:number) => void, onClickBtn?:(val:number) => void,
unit?: string unit?: string
} }
export default ({minNum = 0, maxNum = 100, step=1, digits = 0, defaultNum = 0, onChange, onBlue, onClickBtn, unit = ''}: params) => { export default ({minNum = 0, maxNum = 100, step=1, digits = 0, defaultNum = 0, onChange, onBlue, onClickBtn, unit = ''}: params) => {
const [value, setValue] = useState<any>({count:defaultNum}) const [value, setValue] = useState<any>({count:defaultNum})
const onPlus = () => { const onPlus = () => {
let {count} = value let {count} = value
let num_res = Big(count).add(step).toNumber() let num_res = Big(count).add(step).toNumber()
@ -27,7 +28,7 @@ export default ({minNum = 0, maxNum = 100, step=1, digits = 0, defaultNum = 0, o
const minus = () => { const minus = () => {
let {count} = value let {count} = value
let num_res = Big(count).minus(step).toNumber() let num_res = Big(count).minus(step).toNumber()
num_res = num_res <= minNum?minNum:num_res num_res = num_res < minNum?0:num_res
setValue({...value, count:num_res}) setValue({...value, count:num_res})
onChange?.(parseFloat(num_res)) onChange?.(parseFloat(num_res))
onClickBtn?.(parseFloat(num_res)) onClickBtn?.(parseFloat(num_res))

View File

@ -102,6 +102,12 @@
font-size: $font_size; font-size: $font_size;
color: $color_main; color: $color_main;
} }
.priceText{
font-size: $font_size_big;
Text{
font-size: $font_size_min;
}
}
} }
.btn_con{ .btn_con{
display: flex; display: flex;

View File

@ -1,4 +1,4 @@
import {Image, ScrollView, View } from "@tarojs/components" import {Image, ScrollView, View, Text } from "@tarojs/components"
import Popup from "@/components/popup" import Popup from "@/components/popup"
import LoadingCard from "@/components/loadingCard"; import LoadingCard from "@/components/loadingCard";
import Search from "@/components/search"; import Search from "@/components/search";
@ -7,9 +7,12 @@ import Counter from "../counter";
import Big from 'big.js' import Big from 'big.js'
import classnames from "classnames"; import classnames from "classnames";
import styles from "./index.module.scss" import styles from "./index.module.scss"
import { memo, useEffect, useRef, useState } from "react"; import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
import {GetColorList} from "@/api/materialColor" import {GetColorList} from "@/api/materialColor"
import { useRouter } from "@tarojs/taro"; import { useRouter } from "@tarojs/taro";
import UseLogin from "@/use/useLogin"
import { formatHashTag, formatMillionYuan } from "@/common/fotmat";
import { getFilterData } from "@/common/util";
type param = { type param = {
show?: true|false, show?: true|false,
@ -19,9 +22,9 @@ type param = {
} }
export default memo(({show = false, onClose, title = '', productId = 0}: param) => { export default memo(({show = false, onClose, title = '', productId = 0}: param) => {
const selectList = [ const selectList = [
{id: 0, step:1, digits:0, title:'大货', unit:'件', eunit:'kg'}, {id: 0, step:1, digits:0, maxNum:100000, defaultNum:1, title:'大货', unit:'件', eunit:'kg'},
{id: 1, step:1, digits:2, title:'剪板', unit:'米', eunit:'m'}, {id: 1, step:1, digits:2, maxNum:9.99, defaultNum:1, title:'剪板', unit:'米', eunit:'m'},
{id: 2, step:1, digits:2, title:'散剪', unit:'米', eunit:'m'}, {id: 2, step:1, digits:2, minNum:10, maxNum:100000, defaultNum:10, title:'散剪', unit:'米', eunit:'kg'},
] ]
const [selectIndex, setSelectIndex] = useState(0) const [selectIndex, setSelectIndex] = useState(0)
const selectProduct = (index:number) => { const selectProduct = (index:number) => {
@ -32,33 +35,31 @@ export default memo(({show = false, onClose, title = '', productId = 0}: param)
const {fetchData:colorFetchData} = GetColorList() const {fetchData:colorFetchData} = GetColorList()
const [list, setList] = useState<any[]>([]) const [list, setList] = useState<any[]>([])
const [loading, setLoading] = useState(false) const [loading, setLoading] = useState(false)
const condition = useRef({physical_warehouse:1, sale_mode:selectIndex, product_id:0}) const condition = useRef({physical_warehouse:1, sale_mode:selectIndex, product_id:0, code_or_name:null})
const getColorList = async () => { const getColorList = async () => {
setLoading(() => true) setLoading(() => true)
let {data} = await colorFetchData(condition.current) console.log('数据:::',getFilterData(condition.current))
let {data} = await colorFetchData(getFilterData(condition.current))
setList([...data.list]) setList([...data.list])
setLoading(() => false) setLoading(() => false)
} }
const [showPopup, setShowPopup] = useState(false)
//显示获取
useEffect(() => { useEffect(() => {
if(show) { if(show) {
condition.current.product_id = productId condition.current.product_id = productId
getColorList() getColorList()
} }
setShowPopup(show)
}, [show]) }, [show])
//卸载清空
useEffect(() => { useEffect(() => {
return () => { return () => {
setList([]) setList([])
} }
}, []) }, [])
const [showPopup, setShowPopup] = useState(false)
useEffect(() => {
setShowPopup(show)
}, [show])
//popup关闭 //popup关闭
const closePopup = () => { const closePopup = () => {
onClose?.() onClose?.()
@ -90,8 +91,9 @@ export default memo(({show = false, onClose, title = '', productId = 0}: param)
} }
const onAdd = (item) => { const onAdd = (item) => {
item.show = true item.show = true
item.count = item.count == 0?1:item.count item.count = selectList[selectIndex].defaultNum
setList([...list]) console.log('aa:::',item.count)
setList((list) => [...list])
} }
//搜索显示与隐藏 //搜索显示与隐藏
@ -100,11 +102,41 @@ export default memo(({show = false, onClose, title = '', productId = 0}: param)
setSearchShow(true) setSearchShow(true)
} }
const addShopCart = () => { //添加购物车
const {getSelfUserInfo} = UseLogin()
const addShopCart = () => {
getSelfUserInfo()
}
//显示金额
const priceFormat = useCallback((item) => {
let price = 0
if(selectIndex == 0) {
price = formatMillionYuan(item.bulk_price, 100).num
} else if(selectIndex == 1) {
price = formatMillionYuan(item.length_cut_price, 100).num
} else {
price = formatMillionYuan(item.weight_cut_price, 100).num
}
return <View className={styles.priceText}><Text>¥</Text>{Number(price) }<Text>{' /' + selectList[selectIndex].eunit}</Text></View>
}, [list, selectIndex])
//重置数据
useEffect(() => {
const newList = list.map(item => {
item.count = 0
item.show = false
return item
})
setList([...newList])
}, [selectIndex])
//筛选数据
const searchInput = (e) => {
condition.current.code_or_name = e
getColorList()
} }
return ( return (
<View className={styles.shop_cart_main}> <View className={styles.shop_cart_main}>
@ -121,26 +153,26 @@ export default memo(({show = false, onClose, title = '', productId = 0}: param)
</View> </View>
{searchShow&&<View className={styles.colorFind}> {searchShow&&<View className={styles.colorFind}>
<View className={styles.search}> <View className={styles.search}>
<Search placeIcon="out" /> <Search placeIcon="out" changeOnSearch={(e) => searchInput(e)} debounceTime={400}/>
</View> </View>
<View className={styles.text} onClick={() => setSearchShow(false)}></View> <View className={styles.text} onClick={() => setSearchShow(false)}></View>
</View>} </View>}
<View className={styles.colorNum}> <View className={styles.colorNum}>
<View className={styles.title}> (13) {list.length}</View> <View className={styles.title}> (13) {list.length}</View>
<View className={classnames('iconfont icon-sousuo', styles.miconfont)} onClick={() => changeSearchShow()}></View> {!searchShow&&<View className={classnames('iconfont icon-sousuo', styles.miconfont)} onClick={() => changeSearchShow()}></View>}
</View> </View>
<View className={styles.product_color_con}> <View className={styles.product_color_con}>
{list.length > 0&&<InfiniteScroll> {list.length > 0&&<InfiniteScroll moreStatus={false}>
<View className={styles.color_con}> <View className={styles.color_con}>
{list.map(item => { {list.map(item => {
return <View className={styles.item}> return <View className={styles.item}>
<View className={styles.item_color}> <View className={styles.item_color}>
<Image src='https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F811%2F021315104H2%2F150213104H2-3-1200.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1651817947&t=5467a207f845ddfc7737d55934e6b26d'/> <Image src={item.texture_url}/>
</View> </View>
<View className={styles.item_con}> <View className={styles.item_con}>
<View className={styles.title}>{item.title}</View> <View className={styles.title}>{formatHashTag(item.code, item.name)}</View>
<View className={styles.num}>¥25.5/m</View> <View className={styles.num}>{priceFormat(item)}</View>
</View> </View>
<View className={styles.btn_con}> <View className={styles.btn_con}>
{!item.show&&<View className={styles.btn} onClick={() => onAdd(item)}></View> {!item.show&&<View className={styles.btn} onClick={() => onAdd(item)}></View>
@ -152,6 +184,8 @@ export default memo(({show = false, onClose, title = '', productId = 0}: param)
digits={selectList[selectIndex].digits} digits={selectList[selectIndex].digits}
onClickBtn={(e) => getInputValue(e, item)} onClickBtn={(e) => getInputValue(e, item)}
unit={selectList[selectIndex].unit} unit={selectList[selectIndex].unit}
minNum={selectList[selectIndex].minNum}
maxNum={selectList[selectIndex].maxNum}
/> />
</View>} </View>}
</View> </View>

View File

@ -13,6 +13,7 @@ import useManualPullDownRefresh from '@/use/useManualPullDownRefresh';
import { goLink } from '@/common/common'; import { goLink } from '@/common/common';
import useUserInfo from '@/use/useUserInfo'; import useUserInfo from '@/use/useUserInfo';
import {GetProductDetailApi} from '@/api/material' import {GetProductDetailApi} from '@/api/material'
import useLogin from '@/use/useLogin';
type item = {title:string, img:string, url:string, id:number} type item = {title:string, img:string, url:string, id:number}
@ -22,6 +23,10 @@ type params = {
style?: Object style?: Object
} }
export default (props:params) => { export default (props:params) => {
const {checkLogin} = useLogin()
useDidShow(() => {
checkLogin()
})
const router = useRouter() const router = useRouter()

View File

@ -18,8 +18,9 @@ export default () => {
const {checkLogin} = useLogin() const {checkLogin} = useLogin()
useDidShow(() => { useDidShow(async () => {
checkLogin() await checkLogin()
// categoryList()
}) })
useEffect(() => { useEffect(() => {

View File

@ -10,14 +10,20 @@ import {
} from '../constants/userInfo' } from '../constants/userInfo'
export type UserParam = { export type UserParam = {
name?:string, nickName?:string,
phone?:string, phone?:string,
avatarUrl?:string, avatarUrl?:string,
city?: string,
country?: string,
province?: string,
gender?: number,
language?: string,
timestamp?: number
} }
export type DataParam = { export type DataParam = {
token?: string token?: string
sessionkey?: string, session_key?: string,
userInfo: UserParam userInfo: UserParam
} }
@ -31,7 +37,7 @@ type Action = {
const INIT_USER = { const INIT_USER = {
userInfo: Taro.getStorageSync('userInfo')?JSON.parse(Taro.getStorageSync('userInfo')):null, userInfo: Taro.getStorageSync('userInfo')?JSON.parse(Taro.getStorageSync('userInfo')):null,
token: Taro.getStorageSync('token')||'', token: Taro.getStorageSync('token')||'',
session_key: Taro.getStorageSync('sessionkey')||'', session_key: Taro.getStorageSync('session_key')||'',
} }
export default function counter (state = INIT_USER, action: Action) { export default function counter (state = INIT_USER, action: Action) {
@ -41,16 +47,16 @@ export default function counter (state = INIT_USER, action: Action) {
Taro.setStorageSync('userInfo',JSON.stringify(data?.userInfo)) Taro.setStorageSync('userInfo',JSON.stringify(data?.userInfo))
return {...state,...data} return {...state,...data}
case SET_TOKEN: case SET_TOKEN:
Taro.setStorageSync('token',JSON.stringify(data?.token)) Taro.setStorageSync('token',data?.token)
return {...state,...data} return {...state,...data}
case SET_SESSIONKEY: case SET_SESSIONKEY:
Taro.setStorageSync('sessionkey',JSON.stringify(data?.sessionkey)) Taro.setStorageSync('session_key',data?.session_key)
return {...state,...data} return {...state,...data}
case CLEAR_TOKEN: case CLEAR_TOKEN:
Taro.removeStorageSync('token') Taro.removeStorageSync('token')
return {...state, token:''} return {...state, token:''}
case CLEAR_SESSIONKEY: case CLEAR_SESSIONKEY:
Taro.removeStorageSync('sessionkey') Taro.removeStorageSync('session_key')
return {...state, session_key:''} return {...state, session_key:''}
case CLEAR_USERINFO: case CLEAR_USERINFO:
Taro.removeStorageSync('userInfo') Taro.removeStorageSync('userInfo')

View File

@ -1,6 +1,6 @@
import Taro from '@tarojs/taro' import Taro, { useRouter } from '@tarojs/taro'
import { useRef, useState } from 'react' import { useRef, useState } from 'react'
import {BASE_URL, WX_APPID} from '@/common/constant' import {BASE_URL, WX_APPID} from '@/common/constant'
import useUserInfo from "./useUserInfo" import useUserInfo from "./useUserInfo"
@ -120,7 +120,8 @@ export const useRequest = (options:option = {
const stateRef = useRef({...params}) const stateRef = useRef({...params})
const [state, setState] = useState({...stateRef.current}) const [state, setState] = useState({...stateRef.current})
const {removeToken} = useUserInfo() const {removeToken, removeSessionKey} = useUserInfo()
const router = useRouter()
// 请求函数 // 请求函数
const fetchData = async (sub_options?:any) => { const fetchData = async (sub_options?:any) => {
stateRef.current.loading = true stateRef.current.loading = true
@ -166,16 +167,19 @@ export const useRequest = (options:option = {
stateRef.current.data = data stateRef.current.data = data
stateRef.current.total = data?.list ? data?.total : 0 stateRef.current.total = data?.list ? data?.total : 0
}else{ }else{
Taro.showToast({
title: `错误:${showStatus(statusCode)}`
})
if (statusCode === 401) { if (statusCode === 401) {
removeToken() removeToken()
Taro.reLaunch({ removeSessionKey()
url: '/pages/index/index' // remove
// Taro.reLaunch({
// url: router.path +'?' + qs.stringify(router.params)
// })
} else {
Taro.showToast({
title: `错误:${showStatus(statusCode)}`,
icon: 'none'
}) })
} }
} }
} catch (e) { } catch (e) {

View File

@ -2,8 +2,9 @@ import { useEffect, useState } from "react"
import { WX_APPID } from "@/common/constant" import { WX_APPID } from "@/common/constant"
import useUserInfo from "./useUserInfo" import useUserInfo from "./useUserInfo"
import Taro, { useRouter } from "@tarojs/taro" import Taro, { useRouter } from "@tarojs/taro"
import { Login } from "@/api/login" import { LoginApi } from "@/api/login"
import { GetWxUserInfoApi } from "@/api/user"
import qs from 'qs';
export default () => { export default () => {
const {setToken, setSessionKey, setUserInfo, userInfo} = useUserInfo() const {setToken, setSessionKey, setUserInfo, userInfo} = useUserInfo()
@ -12,91 +13,104 @@ export default () => {
console.log('userInfo::',userInfo.token) console.log('userInfo::',userInfo.token)
}, [userInfo]) }, [userInfo])
const router = useRouter()
//登录请求 //登录请求
const {fetchData} = Login() const {fetchData} = LoginApi()
const loginRequest = async (code) => {
const {data, success} = await fetchData({js_code: code})
if(success) {
setToken(data.token)
setSessionKey(data.session_key)
} else {
Taro.showToast({
title:'登录失败',
icon:"none"
})
}
}
//微信登录 //微信登录
const wxLogin = () => { const wxLogin = () => {
Taro.login({ return new Promise((reslove, reject) => {
success: function async (res) { Taro.login({
if (res.code) { success: async (res) => {
loginRequest(res.code) if (res.code) {
} else { const {data, success, msg} = await fetchData({js_code: res.code})
console.log('登录失败!' + res.errMsg) if(success) {
} console.log('token::',data.token)
}, setToken(data.token)
fail: function(e) { setSessionKey(data.session_key)
console.log('登录失败!::',e) reslove(data)
} Taro.reLaunch({
}) url: router.path +'?' + qs.stringify(router.params)
} })
} else {
const router = useRouter() Taro.showToast({
//登录加checkLogin检查 title:'登录失败',
const checkLogin = () => { icon:"none"
if(!userInfo.token) { })
wxLogin() reject(msg)
if(router.path != '/pages/index/index') { }
Taro.reLaunch({ } else {
url: '/pages/index/index' console.log('登录失败!' + res.errMsg)
}) reject(res.errMsg)
} }
} else { },
Taro.checkSession({ fail: function(e) {
fail () { console.log('登录失败!::',e)
wxLogin() reject(e)
} }
}) })
} })
} }
//获取用户头像等信息数据
const getUserInfo = () => { //登录加checkLogin检查
Taro.getUserProfile({ const checkLogin = () => {
desc: '用于完善会员资料', return new Promise( async (reslove) => {
success: (res) => { if(!userInfo.token) {
Taro.request({ await wxLogin()
url: 'https://dev.zzfzyc.com/lymarket/v1/mall/user/decrypt', reslove(true)
method: 'POST', } else {
data: { Taro.checkSession({
session_key: userInfo.sessionkey, success: async () => {
raw_data: res.rawData, reslove(true)
signature: res.signature,
encrypted_data: res.encryptedData,
iv: res.iv
}, },
header: { fail: async () => {
platform: 6, await wxLogin()
Authorization: userInfo.token, reslove(true)
Appid: WX_APPID
},
success: (e) => {
setUserInfo({})
},
fail: (e) => {
console.log(e)
} }
}) })
} }
}) })
}
//获取用户头像等信息数据
const {fetchData: fetchDataUserInfo} = GetWxUserInfoApi()
const getSelfUserInfo = async () => {
return new Promise((reslove, reject) => {
if(!userInfo.userInfo) {
Taro.getUserProfile({
desc: '用于完善会员资料',
success: async (res) => {
if(!userInfo.session_key) {
await wxLogin()
}
const {data} = await fetchDataUserInfo({
session_key: userInfo.session_key,
raw_data: res.rawData,
signature: res.signature,
encrypted_data: res.encryptedData,
iv: res.iv
})
setUserInfo({...data})
reslove(data)
},
fail:(e) => {
reject(e)
}
})
} else {
reslove(true)
}
})
} }
return { return {
checkLogin, checkLogin,
wxLogin, wxLogin,
getUserInfo getSelfUserInfo
} }
} }

View File

@ -10,7 +10,7 @@ export default () => {
} }
const setSessionKey = (sessionkey: string) => { const setSessionKey = (sessionkey: string) => {
dispatch({type:SET_SESSIONKEY, data:{sessionkey}}) dispatch({type:SET_SESSIONKEY, data:{session_key: sessionkey}})
} }
const setUserInfo = (userInfo: UserParam) => { const setUserInfo = (userInfo: UserParam) => {