添加地址
This commit is contained in:
parent
64cb883ebb
commit
eaee69667c
@ -32,7 +32,9 @@ const config = {
|
||||
alias: {
|
||||
'@/components': path.resolve(__dirname, '..', 'src/components'),
|
||||
'@/assets': path.resolve(__dirname, '..', 'src/assets'),
|
||||
'@/images': path.resolve(__dirname, '..', 'src/assets/images')
|
||||
'@/images': path.resolve(__dirname, '..', 'src/assets/images'),
|
||||
'@/config': path.resolve(__dirname, '..', 'src/config'),
|
||||
'@/utils': path.resolve(__dirname, '..', 'src/utils'),
|
||||
},
|
||||
mini: {
|
||||
postcss: {
|
||||
|
@ -31,6 +31,7 @@ export default defineAppConfig({
|
||||
'pages/message/index',
|
||||
'pages/message-list/index',
|
||||
'pages/message-detail/index',
|
||||
'/pages/login-quick/index'
|
||||
],
|
||||
window: {
|
||||
backgroundTextStyle: 'light',
|
||||
@ -39,11 +40,5 @@ export default defineAppConfig({
|
||||
navigationBarTextStyle: 'black',
|
||||
navigationStyle: 'custom'
|
||||
},
|
||||
components: [
|
||||
'pages/index/index',
|
||||
'pages/login/index',
|
||||
'pages/register/index',
|
||||
'pages/forgot/index',
|
||||
'pages/goods-detail/index',
|
||||
]
|
||||
|
||||
})
|
||||
|
5
src/config/config.js
Normal file
5
src/config/config.js
Normal file
@ -0,0 +1,5 @@
|
||||
export default {
|
||||
api: "http://1.14.121.134:9101",
|
||||
debugApi: "http://1.14.121.134:9101",
|
||||
debug: false
|
||||
}
|
@ -11,6 +11,9 @@ import checked from '@/images/checked.png'
|
||||
import Taro from '@tarojs/taro';
|
||||
import { useRouter } from '@tarojs/taro';
|
||||
import { Button, Textarea, Address } from '@nutui/nutui-react-taro';
|
||||
import { cities, createAddress, getAddress, updateAddress } from '../../utils/api';
|
||||
import { useCallback } from 'react';
|
||||
import { backOrGo, closeLoading, errorNotice, loading, redirectTo } from '../../utils/utils';
|
||||
|
||||
|
||||
|
||||
@ -19,7 +22,7 @@ function Index() {
|
||||
const param = useRouter().params
|
||||
const [id] = useState(param.id)
|
||||
const [home] = useState(param.home)
|
||||
const [addrId, setAddrId] = useState(0)
|
||||
const [addrId, setAddrId] = useState([])
|
||||
const [isDefault, setIsDefault] = useState(false)
|
||||
const [user, setUser] = useState('')
|
||||
const [phone, setPhone] = useState('')
|
||||
@ -28,13 +31,8 @@ function Index() {
|
||||
|
||||
const [text, setText] = useState('请选择地址')
|
||||
const [normal, setNormal] = useState(false)
|
||||
const [province, setProvince] = useState([
|
||||
{ id: 1, name: '北京', title: 'B' },
|
||||
{ id: 2, name: '广西', title: 'G' },
|
||||
{ id: 3, name: '江西', title: 'J' },
|
||||
{ id: 4, name: '四川', title: 'S' },
|
||||
{ id: 5, name: '浙江', title: 'Z' },
|
||||
])
|
||||
const [cityList, setCityList] = useState([])
|
||||
const [province, setProvince] = useState([])
|
||||
|
||||
const [city, setCity] = useState([])
|
||||
|
||||
@ -46,27 +44,60 @@ function Index() {
|
||||
city,
|
||||
country,
|
||||
town,
|
||||
addressIdStr: '0_0_0_0',
|
||||
})
|
||||
|
||||
const onChange = (cal) => {
|
||||
useEffect(() => {
|
||||
cities().then(res => {
|
||||
if (!res) return
|
||||
setCityList(res.items)
|
||||
setProvince(res.items?.filter(item => item.deep == 0))
|
||||
})
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (!id) return
|
||||
getAddress().then(re => {
|
||||
if (!re) return
|
||||
const data = re.items.filter(item => item.id == id)
|
||||
if (data.length < 1) return
|
||||
const addr = data[0]
|
||||
console.log(addr)
|
||||
setAddrId([addr.province_id, addr.city_id, addr.county_id])
|
||||
setText(`${addr.province.name}${addr.city.name}${addr.county.name}`)
|
||||
setAddrInfo(addr.address)
|
||||
setUser(addr.recipient_name)
|
||||
setPhone(addr.recipient_phone)
|
||||
setAddress({ province: addr.province, city: addr.city, country: addr.county, town: [], addressIdStr: `${addr.province_id}_${addr.city_id}_${addr.county_id}_0` })
|
||||
if (addr.province_id && addr.city_id) {
|
||||
cities(addr.province_id).then(r => {
|
||||
setCity(r.items)
|
||||
})
|
||||
}
|
||||
if (addr.city_id && addr.county_id) {
|
||||
cities(addr.city_id).then(r => {
|
||||
console.log(r.items, addr, addrId)
|
||||
setCountry(r.items)
|
||||
})
|
||||
}
|
||||
})
|
||||
}, [id])
|
||||
|
||||
const onChange = async (cal) => {
|
||||
const re = await cities(cal.value.id)
|
||||
const d = re.items
|
||||
if (!d.length) {
|
||||
setNormal(false)
|
||||
return
|
||||
}
|
||||
setTimeout(() => {
|
||||
switch (cal.next) {
|
||||
case 'city':
|
||||
setCity([
|
||||
{ id: 7, name: '朝阳区', title: 'C' },
|
||||
{ id: 8, name: '崇文区', title: 'C' },
|
||||
{ id: 9, name: '昌平区', title: 'C' },
|
||||
{ id: 6, name: '石景山区', title: 'S' },
|
||||
{ id: 3, name: '八里庄街道', title: 'B' },
|
||||
{ id: 10, name: '北苑', title: 'B' },
|
||||
])
|
||||
|
||||
setCity(d)
|
||||
break;
|
||||
case 'country':
|
||||
setCountry([
|
||||
{ id: 3, name: '八里庄街道', title: 'B' },
|
||||
{ id: 9, name: '北苑', title: 'B' },
|
||||
{ id: 4, name: '常营乡', title: 'C' },
|
||||
])
|
||||
setCountry(d)
|
||||
break;
|
||||
default:
|
||||
setNormal(false)
|
||||
@ -74,35 +105,61 @@ function Index() {
|
||||
}, 200)
|
||||
}
|
||||
const close = (val) => {
|
||||
console.log(val, "Data")
|
||||
setNormal(false)
|
||||
|
||||
if (val.data && !!val.data.addressStr) {
|
||||
setText((val.data).addressStr)
|
||||
setAddress({ province: val.data.province, city: val.data.city, country: val.data.country, town: val.data.town })
|
||||
setAddress({ province: val.data.province, city: val.data.city, country: val.data.country, town: val.data.town, addressIdStr: val.data.addressIdStr })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
|
||||
}, [id])
|
||||
|
||||
|
||||
// 跳转
|
||||
const navDetailFn = (id) => {
|
||||
Taro.navigateTo({
|
||||
url: `/pages/pay-success/index?id=${id}`
|
||||
})
|
||||
}
|
||||
// 返回页面
|
||||
const backFn = () => {
|
||||
Taro.getCurrentPages().length > 0 && Taro.navigateBack()
|
||||
Taro.getCurrentPages().length > 0 && Taro.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
const submit = async () => {
|
||||
const addressId = address.addressIdStr.split('_')
|
||||
if (!phone || !user || !addrInfo || address.addressIdStr == '0_0_0_0') {
|
||||
errorNotice('请填写地址完整信息')
|
||||
return
|
||||
}
|
||||
|
||||
if (addrInfo.length < 6) {
|
||||
errorNotice('详细地址信息错误')
|
||||
return
|
||||
}
|
||||
|
||||
const data = {
|
||||
zipcode: '000000',
|
||||
recipient_phone: phone,
|
||||
recipient_name: user,
|
||||
address: addrInfo,
|
||||
province_id: Number(addressId[0]),
|
||||
city_id: Number(addressId[1]),
|
||||
county_id: Number(addressId[2]),
|
||||
is_default: isDefault
|
||||
}
|
||||
|
||||
if (id) {
|
||||
loading('地址编辑中...')
|
||||
const re = await updateAddress(id, data)
|
||||
closeLoading()
|
||||
if (re) {
|
||||
backOrGo('/pages/address/index')
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
loading('地址新增中...')
|
||||
const re = await createAddress(data)
|
||||
closeLoading()
|
||||
if (re) {
|
||||
backOrGo('/pages/address/index')
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<View className='addr-container'>
|
||||
<View className='addr-c-container'>
|
||||
<View className='addr-detail-title'>
|
||||
<Image src={backNav} className="square-35 absolute left-10 nav-icon" onClick={backFn} />
|
||||
{
|
||||
@ -111,36 +168,36 @@ function Index() {
|
||||
|
||||
</View>
|
||||
|
||||
<View className='addr-body' >
|
||||
<View className='addr-item'>
|
||||
<View className='addr-form'>
|
||||
<View className='addr-form-name'>收货人</View>
|
||||
<Input className='addr-form-input' placeholder='请输入收货人' value={user} onInput={(e) => {
|
||||
<View className='addr-c-body' >
|
||||
<View className='addr-c-item'>
|
||||
<View className='addr-c-form'>
|
||||
<View className='addr-c-form-name'>收货人</View>
|
||||
<Input className='addr-c-form-input' placeholder='请输入收货人' value={user} onInput={(e) => {
|
||||
setUser(e.detail.value)
|
||||
}} />
|
||||
</View>
|
||||
<View className='addr-form'>
|
||||
<View className='addr-form-name'>电话</View>
|
||||
<Input className='addr-form-input' placeholder='请输入收货人' value={phone} onInput={(e) => {
|
||||
<View className='addr-c-form'>
|
||||
<View className='addr-c-form-name'>电话</View>
|
||||
<Input className='addr-c-form-input' placeholder='请输入收货电话' value={phone} onInput={(e) => {
|
||||
setPhone(e.detail.value)
|
||||
}} />
|
||||
</View>
|
||||
<View className='addr-form'>
|
||||
<View className='addr-form-name'>所在地区</View>
|
||||
<View className='flex justify-between items-center addr-form-input' onClick={() => { setNormal(true) }}>
|
||||
<View className='addr-c-form'>
|
||||
<View className='addr-c-form-name'>所在地区</View>
|
||||
<View className='flex justify-between items-center addr-c-form-input' onClick={() => { setNormal(true) }}>
|
||||
<Label>{text}</Label>
|
||||
<Image src={next} className='next-icon' />
|
||||
</View>
|
||||
</View>
|
||||
<View className='addr-form bt-none'>
|
||||
<View className='addr-form-name '>详细地址</View>
|
||||
<View className='addr-c-form bt-none'>
|
||||
<View className='addr-c-form-name '>详细地址</View>
|
||||
</View>
|
||||
<Textarea placeholder='请输入详细地址' autosize rows="4" maxlength={100} defaultValue={addrInfo} onChange={(e) => {
|
||||
setAddrInfo(e)
|
||||
}} />
|
||||
</View>
|
||||
<View className=' mt-22 addr-item'>
|
||||
<View className='addr-form bt-none' onClick={() => {
|
||||
<View className=' mt-22 addr-c-item'>
|
||||
<View className='addr-c-form bt-none' onClick={() => {
|
||||
setIsDefault(x => !x)
|
||||
}}>
|
||||
<View className='text-black'>设为默认地址</View>
|
||||
@ -148,14 +205,14 @@ function Index() {
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<Button className='addr-btn' >保存地址</Button>
|
||||
<Button className='addr-c-btn' onClick={submit} >保存地址</Button>
|
||||
|
||||
<Address
|
||||
modelValue={normal}
|
||||
modelSelect={addrId}
|
||||
province={province}
|
||||
city={city}
|
||||
country={country}
|
||||
town={town}
|
||||
customAddressTitle="请选择所在地区"
|
||||
onChange={onChange}
|
||||
onClose={close}
|
||||
|
@ -1,4 +1,4 @@
|
||||
.addr-container {
|
||||
.addr-c-container {
|
||||
font-family: Source Han Sans CN-Bold, Source Han Sans CN;
|
||||
font-size: 14px;
|
||||
background: #FBFBFD;
|
||||
@ -11,7 +11,7 @@
|
||||
border-radius: 16px 16px 16px 16px;
|
||||
}
|
||||
|
||||
.addr-detail-title {
|
||||
.addr-c-detail-title {
|
||||
width: 100vw;
|
||||
height: 60px;
|
||||
font-size: 18px;
|
||||
@ -24,7 +24,7 @@
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.addr-body {
|
||||
.addr-c-body {
|
||||
padding: 21px;
|
||||
height: auto;
|
||||
box-sizing: border-box;
|
||||
@ -34,7 +34,7 @@
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
.addr-box {
|
||||
.addr-c-box {
|
||||
width: 333px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 4px 7px 9px 0px rgba(56, 63, 68, 0.03);
|
||||
@ -43,7 +43,7 @@
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.addr-item {
|
||||
.addr-c-item {
|
||||
width: 333px;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 4px 7px 9px 0px rgba(56, 63, 68, 0.03);
|
||||
@ -60,7 +60,7 @@
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.addr-form {
|
||||
.addr-c-form {
|
||||
width: 308px;
|
||||
box-sizing: border-box;
|
||||
height: 48px;
|
||||
@ -73,18 +73,18 @@
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.addr-form-name {
|
||||
.addr-c-form-name {
|
||||
font-weight: bold;
|
||||
color: #000000;
|
||||
font-size: 15px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.addr-form-input {
|
||||
.addr-c-form-input {
|
||||
width: 230px;
|
||||
}
|
||||
|
||||
.addr-btn {
|
||||
.addr-c-btn {
|
||||
width: 233px;
|
||||
height: 55px;
|
||||
border-radius: 107px 107px 107px 107px;
|
||||
@ -98,12 +98,21 @@
|
||||
left: calc((100vw - 233px)/2);
|
||||
}
|
||||
|
||||
.addr-item>.nut-textarea {
|
||||
.addr-c-item>.nut-textarea {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.addr-item .weui-input {
|
||||
.addr-c-item .weui-input {
|
||||
color: var(--nutui-textarea-text-color, var(--nutui-gray-1, #1a1a1a));
|
||||
|
||||
}
|
||||
|
||||
.addr-c-container .nut-popup {
|
||||
background-color: #FFFFFF !important;
|
||||
}
|
||||
|
||||
.addr-c-container textarea:-internal-autofill-selected,
|
||||
.addr-c-container input:-internal-autofill-selected {
|
||||
background-color: none !important;
|
||||
}
|
@ -12,6 +12,10 @@ import edit from '@/images/edit.png'
|
||||
import Taro from '@tarojs/taro';
|
||||
import { useRouter } from '@tarojs/taro';
|
||||
import { Button } from '@nutui/nutui-react-taro';
|
||||
import { deleteAddress, getAddress } from '../../utils/api';
|
||||
import { backTo, closeLoading, loading, redirectTo, successNotice } from '../../utils/utils';
|
||||
import { SetData } from '../../utils/storage';
|
||||
import { useDidShow } from '@tarojs/taro';
|
||||
|
||||
|
||||
|
||||
@ -20,11 +24,21 @@ function Index() {
|
||||
const param = useRouter().params
|
||||
const [id] = useState(param.id)
|
||||
const [home] = useState(param.home)
|
||||
const [gid] = useState(param.gid)
|
||||
const [addrId, setAddrId] = useState(0)
|
||||
const [list, setList] = useState([])
|
||||
const [ref, setRef] = useState(0)
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
}, [id])
|
||||
getAddress().then(re => {
|
||||
if (!re) return
|
||||
setList(re.items)
|
||||
})
|
||||
if (!!id) {
|
||||
setAddrId(id)
|
||||
}
|
||||
}, [id, ref])
|
||||
|
||||
|
||||
// 跳转
|
||||
@ -33,6 +47,26 @@ function Index() {
|
||||
url: `/pages/address-create/index?id=${id}`
|
||||
})
|
||||
}
|
||||
|
||||
const onSelect = (aid) => {
|
||||
if (!!gid && !!aid) {
|
||||
// redirectTo(`/pages/settle/index?id=${gid}&aid=${aid}`)
|
||||
SetData(gid, aid, 5)
|
||||
backTo()
|
||||
}
|
||||
}
|
||||
|
||||
// 删除
|
||||
const deleteAddr = async (id) => {
|
||||
if (!id) return
|
||||
loading('正在删除中')
|
||||
const re = await deleteAddress(id).finally(() => {
|
||||
closeLoading()
|
||||
})
|
||||
successNotice('删除成功')
|
||||
setRef(d => d + 1)
|
||||
}
|
||||
|
||||
// 返回页面
|
||||
const backFn = () => {
|
||||
Taro.getCurrentPages().length > 0 && Taro.navigateBack()
|
||||
@ -49,27 +83,32 @@ function Index() {
|
||||
</View>
|
||||
|
||||
<View className='addr-body' >
|
||||
<View className='addr-item'>
|
||||
<View className='addr-icon w-6 h-6' onClick={() => {
|
||||
setAddrId(1)
|
||||
}}>
|
||||
<Image src={addrId == 1 ? checked : uncheck} className="w-6 h-6" />
|
||||
</View>
|
||||
<View className='addr-item-content' onClick={() => {
|
||||
setAddrId(1)
|
||||
}}>
|
||||
<View className='addr-item-title'>
|
||||
<View className='addr-item-name'>李四 18080093730</View>
|
||||
<View className='addr-default'>默认地址</View>
|
||||
{
|
||||
list.map((item, index) => {
|
||||
return <View className='addr-item' key={item.id}>
|
||||
<View className='addr-icon w-6 h-6' onClick={() => {
|
||||
setAddrId(item.id)
|
||||
}}>
|
||||
<Image src={addrId == item.id ? checked : uncheck} className="w-6 h-6" />
|
||||
</View>
|
||||
<View className='addr-item-content' onClick={() => {
|
||||
setAddrId(item.id)
|
||||
onSelect(item.id)
|
||||
}}>
|
||||
<View className='addr-item-title'>
|
||||
<View className='addr-item-name'>{item.recipient_name} {item.recipient_phone}</View>
|
||||
{item.id_default && <View className='addr-default'>默认地址</View>}
|
||||
</View>
|
||||
<View className='addr-item-info'>{item.province?.name}{item.city?.name}{item.county?.name}{item.address}</View>
|
||||
</View>
|
||||
<View className='addr-edit-icon' onClick={() => {
|
||||
navDetailFn(item.id)
|
||||
}}>
|
||||
<Image src={edit} />
|
||||
</View>
|
||||
</View>
|
||||
<View className='addr-item-info'>四川省成都市天府二街</View>
|
||||
</View>
|
||||
<View className='addr-edit-icon' onClick={() => {
|
||||
navDetailFn('')
|
||||
}}>
|
||||
<Image src={edit} />
|
||||
</View>
|
||||
</View>
|
||||
})
|
||||
}
|
||||
|
||||
</View>
|
||||
<Button className='addr-btn' onClick={() => {
|
||||
|
@ -7,6 +7,7 @@ import './index.scss'
|
||||
import { Button } from "@nutui/nutui-react-taro"
|
||||
import { useState } from "react"
|
||||
import Taro from "@tarojs/taro"
|
||||
import { sendCode } from "../../utils/api"
|
||||
|
||||
const activeEye = eye
|
||||
|
||||
@ -47,7 +48,7 @@ const Login = () => {
|
||||
}
|
||||
|
||||
// 倒计时
|
||||
const countDown = () => {
|
||||
const countDown = async () => {
|
||||
if (!mobile) {
|
||||
return
|
||||
}
|
||||
@ -65,6 +66,9 @@ const Login = () => {
|
||||
setIntervalTime(start)
|
||||
}
|
||||
}, 1000)
|
||||
const re = await sendCode(mobile)
|
||||
if (!re) return
|
||||
Taro.showToast({ title: '验证码发送成功', icon: 'success' })
|
||||
}
|
||||
|
||||
return <View className="login-frame bg-slate-50 h-screen text-base">
|
||||
|
@ -11,6 +11,8 @@ import Taro from '@tarojs/taro';
|
||||
import { useRouter } from '@tarojs/taro';
|
||||
import { useDidShow } from '@tarojs/taro';
|
||||
import { Button } from '@nutui/nutui-react-taro';
|
||||
import { mallDetail } from '../../utils/api';
|
||||
import { ImagePreview } from '@nutui/nutui-react-taro';
|
||||
|
||||
|
||||
|
||||
@ -20,25 +22,37 @@ function Index() {
|
||||
const [id] = useState(param.id)
|
||||
|
||||
const [swiperProgress, setSwiperProgress] = useState(1)
|
||||
const list = [
|
||||
'https://storage.360buyimg.com/jdc-article/NutUItaro34.jpg',
|
||||
'https://storage.360buyimg.com/jdc-article/NutUItaro2.jpg',
|
||||
'https://storage.360buyimg.com/jdc-article/welcomenutui.jpg'
|
||||
]
|
||||
|
||||
useDidShow(() => {
|
||||
console.log(12)
|
||||
|
||||
})
|
||||
const [thumbnails, setThumbnails] = useState([])
|
||||
const [info, setInfo] = useState({})
|
||||
const [showReview, setShowReview] = useState(false)
|
||||
const [imageNum, setImageNum] = useState(1)
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
if (!id) {
|
||||
return
|
||||
}
|
||||
detail(id)
|
||||
|
||||
}, [id])
|
||||
|
||||
|
||||
const detail = async () => {
|
||||
const re = await mallDetail(id)
|
||||
if (!re) return
|
||||
setInfo(re)
|
||||
if (re.thumbnails?.length) {
|
||||
let images = re.thumbnails
|
||||
if (!!re.cover_image) {
|
||||
images.shift(re.cover_image)
|
||||
}
|
||||
setThumbnails(images)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 跳转
|
||||
@ -53,7 +67,7 @@ function Index() {
|
||||
}
|
||||
|
||||
return (
|
||||
<View className='home-container'>
|
||||
<View className='home-container' catchMove>
|
||||
<View className='goods-detail-title'>
|
||||
<Image src={backNav} className="square-35 absolute left-10 " onClick={backFn} />
|
||||
商品详情
|
||||
@ -75,7 +89,7 @@ function Index() {
|
||||
setSwiperProgress(x => x % 3 + 1)
|
||||
}}
|
||||
>
|
||||
{list.map((item) => {
|
||||
{thumbnails.map((item) => {
|
||||
return (
|
||||
<SwiperItem key={item} className='goods-swiper-item'>
|
||||
<Image src={item} alt="" />
|
||||
@ -84,27 +98,37 @@ function Index() {
|
||||
})}
|
||||
</Swiper>
|
||||
<View className='goods-swiper-progress'>
|
||||
<View style={{ backgroundColor: '#F67952', height: '100%', width: list.length ? ((swiperProgress / list.length) > 1 ? 1 : (swiperProgress / list.length)) * 100 + '%' : 0 }}></View>
|
||||
<View style={{ backgroundColor: '#F67952', height: '100%', width: thumbnails.length ? ((swiperProgress / thumbnails.length) > 1 ? 1 : (swiperProgress / thumbnails.length)) * 100 + '%' : 0 }}></View>
|
||||
</View>
|
||||
</View>
|
||||
<View className='goods-content'>
|
||||
<View className='line-clamp-2 goods-name'>
|
||||
银美孚1号 全合成油5w全合成油 5W-30 SN级 4L
|
||||
</View>
|
||||
<View className='goods-desc line-clamp-2'>
|
||||
<View>规格</View>
|
||||
{info.name}
|
||||
</View>
|
||||
{/* <View className='goods-desc line-clamp-2'>
|
||||
<View>规格</View>
|
||||
</View> */}
|
||||
<View className='goods-item-price'>
|
||||
<Text className='goods-item-price-sale'>¥199</Text>
|
||||
<Text className='goods-item-price-origin'>原价888</Text>
|
||||
<Text className='goods-item-price-sale'>¥{info.price}</Text>
|
||||
{/* <Text className='goods-item-price-origin'>原价888</Text> */}
|
||||
</View>
|
||||
|
||||
<View className='goods-content-box'>
|
||||
图文内容专区
|
||||
{
|
||||
info.content_images?.map((item, index) => {
|
||||
return (
|
||||
<Image src={item} alt="" key={item} style={{ width: '100%' }} onClick={() => {
|
||||
setImageNum(index + 1)
|
||||
// setShowReview(true)
|
||||
}} />
|
||||
)
|
||||
})
|
||||
}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<Button className='buy-btn' onClick={navDetailFn}>立即购买</Button>
|
||||
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
@ -68,7 +68,7 @@
|
||||
|
||||
.goods-name {
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
height: auto;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #10254E;
|
||||
|
@ -1,36 +1,41 @@
|
||||
import React from 'react'
|
||||
import { Image, Text, View } from '@tarojs/components'
|
||||
import {
|
||||
Button
|
||||
} from "@nutui/nutui-react-taro";
|
||||
import './index.scss'
|
||||
import TabbarAction from '@/components/action';
|
||||
import { Infiniteloading } from '@nutui/nutui-react-taro';
|
||||
import { useEffect } from 'react';
|
||||
import { useState } from 'react';
|
||||
|
||||
import { mallList } from '../../utils/api';
|
||||
import Taro from '@tarojs/taro';
|
||||
|
||||
|
||||
function Index() {
|
||||
|
||||
const limit = 10
|
||||
const [list, setList] = useState([])
|
||||
const [total, setTotal] = useState(0)
|
||||
const [page, setPage] = useState(1)
|
||||
const [hasMore, setHasMore] = useState(true)
|
||||
|
||||
useEffect(() => {
|
||||
if (list.length > 50) {
|
||||
setHasMore(false)
|
||||
if (page < 1) {
|
||||
return
|
||||
}
|
||||
let l = []
|
||||
for (let i = list.length; i < 10 + list.length; i++) {
|
||||
l.push(i)
|
||||
}
|
||||
setList([...list, ...l])
|
||||
fetchList(page)
|
||||
|
||||
}, [page])
|
||||
|
||||
const fetchList = async (page) => {
|
||||
const offset = (page - 1) * limit
|
||||
const res = await mallList('mall', offset, limit)
|
||||
|
||||
if (!res) return
|
||||
if (res.items?.length + list.length >= res.total) {
|
||||
setHasMore(false)
|
||||
}
|
||||
setList(res.items)
|
||||
setTotal(res.total)
|
||||
}
|
||||
|
||||
|
||||
// 跳转
|
||||
const navDetailFn = (id) => {
|
||||
@ -48,7 +53,7 @@ function Index() {
|
||||
containerId="customScroll"
|
||||
useWindow={false}
|
||||
loadTxt="loading"
|
||||
loadMoreTxt="没有数据啦~"
|
||||
loadMoreTxt={<View></View>}
|
||||
loadIcon='loading'
|
||||
hasMore={hasMore}
|
||||
onLoadMore={(x) => {
|
||||
@ -59,21 +64,21 @@ function Index() {
|
||||
<View className='goods-container '>
|
||||
{
|
||||
list.map(item => {
|
||||
return <View className='goods-item' key={item} onClick={() => {
|
||||
navDetailFn(item)
|
||||
return <View className='goods-item' key={item.id} onClick={() => {
|
||||
navDetailFn(item.id)
|
||||
}}>
|
||||
<View className='goods-item-image'>
|
||||
<Image src='https://img.yzcdn.cn/vant/cat.jpeg' />
|
||||
<Image src={item.cover_image} />
|
||||
</View>
|
||||
<View className='goods-item-name line-clamp-2'>
|
||||
这个是商品的名称,但是可能有一点点的长
|
||||
{item.name}
|
||||
</View>
|
||||
<View className='goods-item-desc line-clamp-2 '>
|
||||
{/* <View className='goods-item-desc line-clamp-2 '>
|
||||
这个是商品的介绍
|
||||
</View>
|
||||
</View> */}
|
||||
<View className='goods-item-price'>
|
||||
<Text className='goods-item-price-sale'>¥199</Text>
|
||||
<Text className='goods-item-price-origin'>原价888</Text>
|
||||
<Text className='goods-item-price-sale'>¥{item.price}</Text>
|
||||
{/* <Text className='goods-item-price-origin'>原价888</Text> */}
|
||||
</View>
|
||||
</View>
|
||||
})
|
||||
|
@ -33,8 +33,8 @@
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
padding: 0 8px;
|
||||
justify-content: space-between;
|
||||
padding: 0 12px;
|
||||
margin-top: 24px;
|
||||
// column-count: 2;
|
||||
// column-gap: 10px;
|
||||
|
3
src/pages/login-quick/index.config.js
Normal file
3
src/pages/login-quick/index.config.js
Normal file
@ -0,0 +1,3 @@
|
||||
export default definePageConfig({
|
||||
navigationBarTitleText: '登录'
|
||||
})
|
116
src/pages/login-quick/index.jsx
Normal file
116
src/pages/login-quick/index.jsx
Normal file
@ -0,0 +1,116 @@
|
||||
import { Image, Input, Text, View } from "@tarojs/components"
|
||||
import back from '@/images/back.png'
|
||||
import checked from '@/images/checked.png'
|
||||
import eyeClose from '@/images/eyeClose.png'
|
||||
import eye from '@/images/eye.png'
|
||||
import './index.scss'
|
||||
import { Button } from "@nutui/nutui-react-taro"
|
||||
import { useState } from "react"
|
||||
import Taro from "@tarojs/taro"
|
||||
import { useDidShow } from "@tarojs/taro"
|
||||
import { login, sendCode } from "../../utils/api"
|
||||
import { JWT, JWTEXPIRE, SetData, USERINFO } from "../../utils/storage"
|
||||
|
||||
|
||||
const activeEye = eye
|
||||
|
||||
const Login = () => {
|
||||
|
||||
|
||||
|
||||
const [mobile, setMobile] = useState('')
|
||||
const [smsCode, setSmsCode] = useState('')
|
||||
const [interval, setIntervalTime] = useState(0)
|
||||
|
||||
|
||||
// 返回页面
|
||||
const backFn = () => {
|
||||
Taro.getCurrentPages().length > 0 && Taro.navigateBack()
|
||||
}
|
||||
|
||||
// 倒计时
|
||||
const countDown = async () => {
|
||||
if (!mobile) {
|
||||
return
|
||||
}
|
||||
setIntervalTime(60)
|
||||
if (interval > 0) {
|
||||
return
|
||||
}
|
||||
let start = 60
|
||||
const timer = setInterval(() => {
|
||||
if (start > 0) {
|
||||
start--
|
||||
if (start <= 0) {
|
||||
clearInterval(timer)
|
||||
}
|
||||
setIntervalTime(start)
|
||||
}
|
||||
}, 1000)
|
||||
const re = await sendCode(mobile)
|
||||
if (!re) return
|
||||
Taro.showToast({ title: '验证码发送成功', icon: 'success' })
|
||||
}
|
||||
|
||||
|
||||
const loginSubmit = async () => {
|
||||
console.log(mobile, smsCode, "code")
|
||||
if (!mobile || !smsCode) {
|
||||
Taro.showToast({ title: '请完善登陆参数', icon: 'error' })
|
||||
return
|
||||
}
|
||||
Taro.showLoading({ title: '登陆中,请稍后' })
|
||||
const re = await login(mobile, '', smsCode)
|
||||
Taro.hideLoading()
|
||||
if (re) {
|
||||
SetData(JWT, re.token, JWTEXPIRE)
|
||||
SetData(USERINFO, re.user)
|
||||
Taro.redirectTo({ url: '/pages/index/index' })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return <View className="login-frame bg-slate-50 h-screen text-base">
|
||||
<View className="login-header flex justify-center items-center text-lg font-bold">
|
||||
<Image src={back} className="square-35 absolute left-7" onClick={backFn} />
|
||||
<View>新起点</View>
|
||||
</View>
|
||||
<View className="login-container relative">
|
||||
<View className="relative font-bold text-lg block h-6 ">登录</View>
|
||||
<View>
|
||||
<View className="form-item mt-58">
|
||||
<View className="form-label">手机号</View>
|
||||
<View className="form-control relative">
|
||||
<Input className="form-input" name="mobile" placeholder="请输手机号" id='mobile' onInput={(v) => {
|
||||
setMobile(v.detail.value)
|
||||
}} />
|
||||
{
|
||||
mobile && <Image className="w-6 h-6 absolute right-0 bottom-16" src={checked} />
|
||||
}
|
||||
|
||||
</View>
|
||||
</View>
|
||||
<View className="form-item mt-22">
|
||||
<View className="form-label">验证码</View>
|
||||
<View className="form-control relative">
|
||||
<Input className="form-input" name="smsCode" type="text" placeholder="请输入验证码" id='code' value={smsCode} onInput={(v) => {
|
||||
setSmsCode(v.detail.value)
|
||||
}} />
|
||||
<Button className="code-btn" disabled={interval > 0} onClick={countDown}>{interval ? interval + 's' : '获取验证码'}</Button>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View className="login-footer flex flex-col justify-center">
|
||||
<Button className="login-btn" onClick={loginSubmit}>登录</Button>
|
||||
<View className="quick-login" onClick={() => {
|
||||
Taro.redirectTo({ url: '/pages/login/index' })
|
||||
}}>密码登录</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
</View>
|
||||
}
|
||||
|
||||
|
||||
export default Login
|
123
src/pages/login-quick/index.scss
Normal file
123
src/pages/login-quick/index.scss
Normal file
@ -0,0 +1,123 @@
|
||||
.login-header {
|
||||
height: 86px;
|
||||
}
|
||||
|
||||
.login-frame {
|
||||
height: auto;
|
||||
font-size: 14px;
|
||||
font-family: Source Han Sans CN-Bold, Source Han Sans CN;
|
||||
}
|
||||
|
||||
.login-container {
|
||||
width: 375px;
|
||||
height: calc(100vh - 86px);
|
||||
background: #FFFFFF;
|
||||
border-radius: 20px 20px 0 0;
|
||||
box-shadow: 0px 8px 51px 0px rgba(230, 234, 238, 0.8);
|
||||
box-sizing: border-box;
|
||||
padding: 38px 30px;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
height: 68px;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
font-family: Source Han Sans CN-Bold, Source Han Sans CN;
|
||||
color: #2a2b2d;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.form-input>.weui-input {
|
||||
border: none;
|
||||
height: 52px;
|
||||
line-height: 52px;
|
||||
border-bottom: 1px solid #262A34;
|
||||
position: relative;
|
||||
font-size: 16px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.form-input>.weui-input:focus {
|
||||
border-bottom: 2px solid #F67952;
|
||||
}
|
||||
|
||||
.form-input-placeholder,
|
||||
.form-input>.weui-input::placeholder {
|
||||
font-size: 16px;
|
||||
font-family: Source Han Sans CN-Regular, Source Han Sans CN;
|
||||
font-weight: bold;
|
||||
color: #aeafb4;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
height: 52px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.forgot-password {
|
||||
height: 24px;
|
||||
font-size: 16px;
|
||||
font-family: Source Han Sans CN-Regular, Source Han Sans CN;
|
||||
font-weight: 400;
|
||||
color: #666;
|
||||
line-height: 24px;
|
||||
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
|
||||
.form-helper {
|
||||
margin-top: 16px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.login-btn {
|
||||
width: 253px;
|
||||
height: 55px;
|
||||
background: #F67952;
|
||||
border-radius: 68px 68px 68px 68px;
|
||||
opacity: 1;
|
||||
border: none;
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
font-family: Source Han Sans CN-Bold, Source Han Sans CN;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.login-footer {
|
||||
margin-top: 50px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.quick-login {
|
||||
font-size: 16px;
|
||||
font-family: Source Han Sans CN-Regular, Source Han Sans CN;
|
||||
font-weight: 400;
|
||||
color: #000000;
|
||||
line-height: 24px;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.code-btn {
|
||||
width: 83px;
|
||||
height: 30px;
|
||||
background: #F67952;
|
||||
border-radius: 4px 4px 4px 4px;
|
||||
opacity: 1;
|
||||
font-size: 12px;
|
||||
font-family: Source Han Sans CN-Bold, Source Han Sans CN;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
border: none;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 12px;
|
||||
}
|
@ -8,23 +8,22 @@ import { Button } from "@nutui/nutui-react-taro"
|
||||
import { useState } from "react"
|
||||
import Taro from "@tarojs/taro"
|
||||
import { useDidShow } from "@tarojs/taro"
|
||||
import { login, sendCode } from "../../utils/api"
|
||||
import { JWT, JWTEXPIRE, SetData, USERINFO } from "../../utils/storage"
|
||||
import { successNotice } from "../../utils/utils"
|
||||
|
||||
|
||||
const activeEye = eye
|
||||
|
||||
const Login = () => {
|
||||
|
||||
const [account, setAccount] = useState('')
|
||||
const [pwd, setPwd] = useState()
|
||||
const [showPwd, setShowPwd] = useState(false)
|
||||
const [loginMode, setLoginMode] = useState('account')
|
||||
|
||||
|
||||
const [mobile, setMobile] = useState('')
|
||||
const [smsCode, setSmsCode] = useState('')
|
||||
const [pwd, setPwd] = useState('')
|
||||
const [interval, setIntervalTime] = useState(0)
|
||||
|
||||
useDidShow(() => {
|
||||
|
||||
})
|
||||
const [showPwd, setShowPwd] = useState()
|
||||
|
||||
|
||||
// 返回页面
|
||||
@ -32,33 +31,8 @@ const Login = () => {
|
||||
Taro.getCurrentPages().length > 0 && Taro.navigateBack()
|
||||
}
|
||||
|
||||
// 注册页面
|
||||
const registerFn = () => {
|
||||
Taro.navigateTo({
|
||||
url: '/pages/register/index'
|
||||
})
|
||||
}
|
||||
|
||||
// 忘记密码
|
||||
const forgotPasswordFn = () => {
|
||||
Taro.navigateTo({
|
||||
url: '/pages/forgot/index'
|
||||
})
|
||||
}
|
||||
|
||||
//清理数据
|
||||
const cleanFn = () => {
|
||||
if (loginMode === 'account') {
|
||||
setAccount('')
|
||||
setPwd('')
|
||||
return
|
||||
}
|
||||
setMobile('')
|
||||
setSmsCode('')
|
||||
}
|
||||
|
||||
// 倒计时
|
||||
const countDown = () => {
|
||||
const countDown = async () => {
|
||||
if (!mobile) {
|
||||
return
|
||||
}
|
||||
@ -76,6 +50,26 @@ const Login = () => {
|
||||
setIntervalTime(start)
|
||||
}
|
||||
}, 1000)
|
||||
const re = await sendCode(mobile)
|
||||
if (!re) return
|
||||
Taro.showToast({ title: '验证码发送成功', icon: 'success' })
|
||||
}
|
||||
|
||||
|
||||
const loginSubmit = async () => {
|
||||
if (!mobile || !pwd) {
|
||||
Taro.showToast({ title: '请完善登陆参数', icon: 'error' })
|
||||
return
|
||||
}
|
||||
Taro.showLoading({ title: '登陆中,请稍后' })
|
||||
const re = await login(mobile, pwd)
|
||||
Taro.hideLoading()
|
||||
if (re) {
|
||||
SetData(JWT, re.token, JWTEXPIRE)
|
||||
SetData(USERINFO, re.user)
|
||||
Taro.redirectTo({ url: '/pages/index/index' })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return <View className="login-frame bg-slate-50 h-screen text-base">
|
||||
@ -85,75 +79,38 @@ const Login = () => {
|
||||
</View>
|
||||
<View className="login-container relative">
|
||||
<View className="relative font-bold text-lg block h-6 ">登录</View>
|
||||
{
|
||||
loginMode === 'account' ? <View>
|
||||
<View className="form-item mt-58">
|
||||
<View className="form-label">账号</View>
|
||||
<View className="form-control relative">
|
||||
<Input className="form-input" placeholder="请输入账号" onInput={(v) => {
|
||||
setAccount(v.detail.value)
|
||||
}} />
|
||||
{
|
||||
!!account && <Image className="w-6 h-6 absolute right-0 bottom-16" src={checked} />
|
||||
}
|
||||
</View>
|
||||
</View>
|
||||
<View className="form-item mt-22">
|
||||
<View className="form-label">密码</View>
|
||||
<View className="form-control relative">
|
||||
<Input className="form-input" type={showPwd ? 'text' : 'password'} placeholder="请输入密码" onInput={(v) => {
|
||||
setPwd(v.detail.value)
|
||||
}} />
|
||||
<Image className="w-6 h-6 absolute right-0 bottom-16" src={showPwd ? activeEye : eyeClose} onClick={() => {
|
||||
setShowPwd(v => !v)
|
||||
}} />
|
||||
</View>
|
||||
</View>
|
||||
<View className="form-helper">
|
||||
<View className="forgot-password" onClick={registerFn}>注册账号</View>
|
||||
<View className="forgot-password" onClick={forgotPasswordFn}>忘记密码</View>
|
||||
</View>
|
||||
<View className="login-footer flex flex-col justify-center">
|
||||
<Button className="login-btn">登录</Button>
|
||||
<View className="quick-login" onClick={() => {
|
||||
setLoginMode('mobile')
|
||||
cleanFn()
|
||||
}}>快捷登录</View>
|
||||
</View>
|
||||
</View> : <View>
|
||||
<View className="form-item mt-58">
|
||||
<View className="form-label">手机号</View>
|
||||
<View className="form-control relative">
|
||||
<Input className="form-input" placeholder="请输手机号" placeholderClass="form-input-placeholder" onInput={(v) => {
|
||||
setMobile(v.detail.value)
|
||||
}} />
|
||||
{
|
||||
mobile && <Image className="w-6 h-6 absolute right-0 bottom-16" src={checked} />
|
||||
}
|
||||
<View>
|
||||
<View className="form-item mt-58">
|
||||
<View className="form-label">手机号</View>
|
||||
<View className="form-control relative">
|
||||
<Input className="form-input" name="mobile" placeholder="请输手机号" id='mobile' onInput={(v) => {
|
||||
setMobile(v.detail.value)
|
||||
}} />
|
||||
{
|
||||
mobile && <Image className="w-6 h-6 absolute right-0 bottom-16" src={checked} />
|
||||
}
|
||||
|
||||
</View>
|
||||
</View>
|
||||
<View className="form-item mt-22">
|
||||
<View className="form-label">验证码</View>
|
||||
<View className="form-control relative">
|
||||
<Input className="form-input" maxlength={6} placeholder="请输入验证码" onInput={(v) => {
|
||||
setSmsCode(v.detail.value)
|
||||
}} />
|
||||
<Button className="code-btn" disabled={interval > 0} onClick={countDown}>{interval ? interval + 's' : '获取验证码'}</Button>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View className="login-footer flex flex-col justify-center">
|
||||
<Button className="login-btn">登录</Button>
|
||||
<View className="quick-login" onClick={() => {
|
||||
setLoginMode('account')
|
||||
cleanFn()
|
||||
}}>密码登录</View>
|
||||
</View>
|
||||
</View>
|
||||
}
|
||||
|
||||
<View className="form-item mt-22">
|
||||
<View className="form-label">密码</View>
|
||||
<View className="form-control relative">
|
||||
<Input className="form-input" name="pwd" type={showPwd ? 'text' : 'password'} id='pwd' placeholder="请输入密码" value={pwd} onInput={(v) => {
|
||||
setPwd(v.detail.value)
|
||||
}} />
|
||||
<Image className="w-6 h-6 absolute right-0 bottom-16" src={showPwd ? activeEye : eyeClose} onClick={() => {
|
||||
setShowPwd(v => !v)
|
||||
}} />
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View className="login-footer flex flex-col justify-center">
|
||||
<Button className="login-btn" onClick={loginSubmit}>登录</Button>
|
||||
<View className="quick-login" onClick={() => {
|
||||
Taro.redirectTo({ url: '/pages/login-quick/index' })
|
||||
}}>快捷登录</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
</View>
|
||||
|
@ -7,6 +7,7 @@ import './index.scss'
|
||||
import { Button } from "@nutui/nutui-react-taro"
|
||||
import { useState } from "react"
|
||||
import Taro from "@tarojs/taro"
|
||||
import { register, sendCode } from "../../utils/api"
|
||||
|
||||
const activeEye = eye
|
||||
|
||||
@ -32,7 +33,7 @@ const Login = () => {
|
||||
|
||||
|
||||
// 倒计时
|
||||
const countDown = () => {
|
||||
const countDown = async () => {
|
||||
if (!mobile) {
|
||||
return
|
||||
}
|
||||
@ -50,6 +51,33 @@ const Login = () => {
|
||||
setIntervalTime(start)
|
||||
}
|
||||
}, 1000)
|
||||
const re = await sendCode(mobile)
|
||||
if (!re) return
|
||||
Taro.showToast({ title: '验证码发送成功', icon: 'success' })
|
||||
}
|
||||
|
||||
const registerFn = async () => {
|
||||
if (!mobile || !smsCode || !pwd || !confirmPassword || !payPassword || !confirmPayPassword) {
|
||||
Taro.showToast({ title: '请完善注册参数', icon: 'error' })
|
||||
return
|
||||
}
|
||||
Taro.showLoading({ title: '正在注册中~', })
|
||||
const re = await register({
|
||||
nick_name: mobile,
|
||||
phone: mobile,
|
||||
verification_code: smsCode,
|
||||
password: pwd,
|
||||
confirm_password: confirmPassword,
|
||||
pay_password: payPassword,
|
||||
confirm_pay_pwd: confirmPayPassword
|
||||
})
|
||||
Taro.hideLoading()
|
||||
if (re) {
|
||||
Taro.showToast({ title: '注册成功', icon: 'success' })
|
||||
setTimeout(() => {
|
||||
Taro.redirectTo({ url: '/pages/login/index' })
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
return <View className="login-frame bg-slate-50 h-screen text-base">
|
||||
@ -61,7 +89,7 @@ const Login = () => {
|
||||
<View className="form-item ">
|
||||
<View className="form-label">手机号</View>
|
||||
<View className="form-control relative">
|
||||
<Input className="form-input" placeholder="请输手机号" placeholderClass="form-input-placeholder" onInput={(v) => {
|
||||
<Input className="form-input" placeholder="请输手机号" required placeholderClass="form-input-placeholder" onInput={(v) => {
|
||||
setMobile(v.detail.value)
|
||||
}} />
|
||||
{
|
||||
@ -124,7 +152,7 @@ const Login = () => {
|
||||
</View>
|
||||
</View>
|
||||
<View className="login-footer flex flex-col justify-center">
|
||||
<Button className="login-btn">注册</Button>
|
||||
<Button className="login-btn" onClick={registerFn}>注册</Button>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
|
@ -9,6 +9,9 @@ import next from '@/images/next.png'
|
||||
import Taro from '@tarojs/taro';
|
||||
import { useRouter } from '@tarojs/taro';
|
||||
import { Button } from '@nutui/nutui-react-taro';
|
||||
import { getAddress, mallDetail } from '../../utils/api';
|
||||
import { GetData } from '../../utils/storage';
|
||||
import { useDidShow } from '@tarojs/taro';
|
||||
|
||||
|
||||
|
||||
@ -16,20 +19,40 @@ function Index() {
|
||||
|
||||
const param = useRouter().params
|
||||
const [id] = useState(param.id)
|
||||
|
||||
const [swiperProgress, setSwiperProgress] = useState(1)
|
||||
const list = [
|
||||
'https://storage.360buyimg.com/jdc-article/NutUItaro34.jpg',
|
||||
'https://storage.360buyimg.com/jdc-article/NutUItaro2.jpg',
|
||||
'https://storage.360buyimg.com/jdc-article/welcomenutui.jpg'
|
||||
]
|
||||
const [aid, setAid] = useState(param.aid)
|
||||
const [addrData, setAddrData] = useState({})
|
||||
const [info, setInfo] = useState({})
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
mallDetail(id).then(re => {
|
||||
if (!re) return
|
||||
setInfo(re)
|
||||
})
|
||||
if (!aid && !!addrData.id) {
|
||||
return
|
||||
}
|
||||
getAddress().then(re => {
|
||||
if (!re) return
|
||||
const addr = re.items.filter(item => {
|
||||
if (aid) {
|
||||
return item.id == aid
|
||||
}
|
||||
return item.is_default
|
||||
})
|
||||
if (!!addr.length) {
|
||||
setAddrData(addr[0])
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
}, [id])
|
||||
}, [id, aid])
|
||||
|
||||
useDidShow(() => {
|
||||
const aa = GetData(id)
|
||||
setAid(aa)
|
||||
})
|
||||
|
||||
|
||||
// 跳转
|
||||
@ -45,9 +68,9 @@ function Index() {
|
||||
}
|
||||
|
||||
// 选择地址
|
||||
const goAddr = (id) => {
|
||||
const goAddr = (aid) => {
|
||||
Taro.navigateTo({
|
||||
url: '/pages/address/index?id=' + id
|
||||
url: `/pages/address/index?gid=${id}&id=` + aid
|
||||
})
|
||||
}
|
||||
|
||||
@ -63,9 +86,9 @@ function Index() {
|
||||
<View className='address-title'>选择收货地址</View>
|
||||
<View className='address-area' onClick={() => { goAddr('') }}>
|
||||
<View className='address-item'>
|
||||
<View className='address-item-name'>李四 18080093730</View>
|
||||
<View className='address-info'>四川省 成都市 天府二街</View>
|
||||
{/* <View className='address-item-name text-gold'>选择地址</View> */}
|
||||
{!!addrData.id && <View className='address-item-name'>{addrData.recipient_name} {addrData.recipient_phone}</View>}
|
||||
{!!addrData.id && <View className='address-info'>{addrData.province?.name}{addrData.city.name}{addrData.county.name}{addrData.address}</View>}
|
||||
{!addrData.id && <View className='address-item-name text-gold'>选择地址</View>}
|
||||
</View>
|
||||
<View className='address-next'>
|
||||
<Image src={next} />
|
||||
@ -76,11 +99,11 @@ function Index() {
|
||||
<View className='settle-goods'>
|
||||
<View className='settle-goods-title'>商品信息</View>
|
||||
<View className='settle-goods-info'>
|
||||
<Image className='settle-goods-img' />
|
||||
<Image className='settle-goods-img' src={info.cover_image} />
|
||||
<View className='settle-goods-content'>
|
||||
<View className='settle-goods-content-title line-clamp-1'>商品名称</View>
|
||||
<View className='settle-goods-content-title line-clamp-1'>{info.name}</View>
|
||||
<View className='settle-goods-content-price'>
|
||||
<View className='settle-goods-content-price-1'>¥199</View>
|
||||
<View className='settle-goods-content-price-1'>¥{info.price}</View>
|
||||
<View className='settle-goods-content-price-num'>x1</View>
|
||||
</View>
|
||||
</View>
|
||||
@ -89,7 +112,7 @@ function Index() {
|
||||
|
||||
<View className='settle-price-container'>
|
||||
<View>总价:</View>
|
||||
<View className='settle-price-p'>¥199</View>
|
||||
<View className='settle-price-p'>¥{info.price * 1}</View>
|
||||
</View>
|
||||
</View>
|
||||
<Button className='buy-btn' onClick={navDetailFn}>去支付</Button>
|
||||
|
47
src/utils/api.js
Normal file
47
src/utils/api.js
Normal file
@ -0,0 +1,47 @@
|
||||
import { d, put } from './request'
|
||||
import { g, p } from './request'
|
||||
|
||||
export const mallList = async (channel = 'mall', offset = 0, limit = 10) => {
|
||||
return await g(`/products/${channel}`)
|
||||
}
|
||||
|
||||
export const mallDetail = async (id) => {
|
||||
return await g(`/products/detail/${id}`)
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const login = async (account, pwd, code) => {
|
||||
return await p(`/users/login`, { phone: account, password: pwd, verification_code: code })
|
||||
}
|
||||
|
||||
export const register = async (data = {}) => {
|
||||
return await p(`/users/register`, data)
|
||||
}
|
||||
|
||||
export const sendCode = async (phone) => {
|
||||
return await p('/users/sms-verification-code', { phone })
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 创建地址
|
||||
export const createAddress = async (data = {}) => {
|
||||
return await p(`/users/addresses`, data)
|
||||
}
|
||||
export const updateAddress = async (id, data = {}) => {
|
||||
return await put(`/users/addresses/${id}`, data)
|
||||
}
|
||||
|
||||
export const deleteAddress = async (id) => {
|
||||
return await d(`/users/addresses/${id}`)
|
||||
}
|
||||
|
||||
|
||||
export const getAddress = async (data = {}) => {
|
||||
return await g(`/users/addresses`, data)
|
||||
}
|
||||
// 获取城市
|
||||
export const cities = async (pid = 0) => {
|
||||
return await g('/cities', { pid })
|
||||
}
|
135
src/utils/request.js
Normal file
135
src/utils/request.js
Normal file
@ -0,0 +1,135 @@
|
||||
import Taro from '@tarojs/taro';
|
||||
import config from '../config/config';
|
||||
import {
|
||||
DelData,
|
||||
GetData,
|
||||
JWT
|
||||
} from './storage';
|
||||
|
||||
const loginPages = '/pages/login/index';
|
||||
|
||||
function RequestError(message, code) {
|
||||
this.name = 'RequestError'
|
||||
this.message = message || '请求失败'
|
||||
this.code = code
|
||||
}
|
||||
// 基础请求
|
||||
// api/user/center_show , get param == contribution , base
|
||||
export function baseRequest(
|
||||
url,
|
||||
method = 'GET',
|
||||
data = {},
|
||||
base = config.api // https://api.yidongpaidui.com/
|
||||
) {
|
||||
if (config.debug) { // false
|
||||
base = config.debugApi
|
||||
}
|
||||
let jwt = GetData(JWT);
|
||||
jwt = typeof jwt === 'string' ? jwt : ''
|
||||
let header = {
|
||||
'Content-Type': 'application/json',
|
||||
'Jwt': `Bearer ${jwt}`,
|
||||
'Authorization': 'Bearer ' + jwt
|
||||
}
|
||||
|
||||
return Taro.request({
|
||||
url: base + url,
|
||||
data: data,
|
||||
dataType: "json",
|
||||
method: method,
|
||||
header: header
|
||||
}).then(re => {
|
||||
if (config.debug) {
|
||||
console.log(`1、${method} debug request url is: ${url}\r\n2、request Data : `, data, '\r\n3、request header:', header, '\r\n4、response Data is :', re);
|
||||
}
|
||||
let msg = '请求失败'
|
||||
if (re.statusCode !== 200 || re.data.error.code != 0) {
|
||||
msg = re.data.error.message
|
||||
if (!!msg) {
|
||||
Taro.showModal({
|
||||
"title": "信息提示",
|
||||
showCancel: false,
|
||||
"content": msg,
|
||||
mask: true
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
if (re.data.error.code.toString() === '40101') {
|
||||
DelData(JWT)
|
||||
const current = Taro.getCurrentPages()
|
||||
const route = current[0].route
|
||||
if (route != 'pages/login/index') {
|
||||
Taro.navigateTo({
|
||||
url: loginPages
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
RequestError.prototype = Object.create(Error.prototype)
|
||||
RequestError.prototype.constructor = RequestError
|
||||
return null
|
||||
}
|
||||
return re.data.data
|
||||
})
|
||||
}
|
||||
|
||||
// post
|
||||
export function p(url, data, base) {
|
||||
return baseRequest(url, 'POST', data, base)
|
||||
}
|
||||
|
||||
// get
|
||||
export function g(url, data, base) {
|
||||
// api/user/center_show , get param == contribution , base
|
||||
return baseRequest(url, 'GET', data, base)
|
||||
}
|
||||
|
||||
// delete
|
||||
export function d(url, data, base) {
|
||||
return baseRequest(url, 'DELETE', data, base)
|
||||
}
|
||||
|
||||
//put
|
||||
export function put(url, data, base) {
|
||||
return baseRequest(url, 'PUT', data, base)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 上传图片
|
||||
export const upload = async (file) => {
|
||||
let base = config.api
|
||||
if (config.debug) {
|
||||
base = config.debugApi
|
||||
}
|
||||
let jwt = GetData(JWT);
|
||||
jwt = typeof jwt === 'string' ? jwt : ''
|
||||
let header = {
|
||||
// 'Jwt': `Bearer ${jwt}`,
|
||||
'Authorization': 'Bearer ' + jwt
|
||||
}
|
||||
const re = await Taro.uploadFile({
|
||||
url: `${base}api/camp_chat/upload_image`,
|
||||
filePath: file,
|
||||
name: 'image',
|
||||
header: header,
|
||||
})
|
||||
if (re.statusCode == 200) {
|
||||
const resp = JSON.parse(re.data)
|
||||
if (resp.hasOwnProperty("data")) {
|
||||
return resp.data
|
||||
}
|
||||
}
|
||||
Taro.showModal({
|
||||
"title": "信息提示",
|
||||
showCancel: false,
|
||||
"content": re.errMsg,
|
||||
mask: true
|
||||
})
|
||||
RequestError.prototype = Object.create(Error.prototype)
|
||||
RequestError.prototype.constructor = RequestError
|
||||
throw new RequestError(re.errMsg, re.statusCode)
|
||||
|
||||
}
|
||||
|
66
src/utils/storage.js
Normal file
66
src/utils/storage.js
Normal file
@ -0,0 +1,66 @@
|
||||
import Taro from '@tarojs/taro';
|
||||
|
||||
// storage key
|
||||
export const JWT = '_jujwt'; // jwt
|
||||
export const JWTEXPIRE = 24 * 3600; // jwt 过期时间
|
||||
export const OPENDATA = '_d' // 微信开放数据 openid unionId sessionKey
|
||||
export const WXUSERINFO = '_wu' // 微信GetUserInfo 数据
|
||||
export const USERINFO = '_u' // 用户信息
|
||||
export const TASKKEY = "_task" // 任务key
|
||||
|
||||
// 同步设置缓存
|
||||
export function SetData(key, data, t = 0) {
|
||||
if (t > 0) {
|
||||
let time = (new Date()).getTime()
|
||||
time = Number(String(time).substr(0, 10))
|
||||
t = time + t
|
||||
}
|
||||
let storage = {
|
||||
expire: t,
|
||||
_data: data
|
||||
}
|
||||
return Taro.setStorageSync(key, storage)
|
||||
|
||||
}
|
||||
|
||||
// 异步设置缓存
|
||||
export function SetAsyncData(key, data, t = 0) {
|
||||
if (t > 0) {
|
||||
let time = (new Date()).getTime()
|
||||
time = Number(String(time).substr(0, 10))
|
||||
t = time + t
|
||||
}
|
||||
let storage = {
|
||||
expire: t,
|
||||
_data: data
|
||||
}
|
||||
return Taro.setStorage({
|
||||
key: key,
|
||||
data: storage
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// 取出缓存 -- _jujwt
|
||||
export function GetData(key) {
|
||||
let storage = Taro.getStorageSync(key)
|
||||
if (!storage) {
|
||||
return {}
|
||||
}
|
||||
if (storage.expire > 0) {
|
||||
let time = (new Date()).getTime()
|
||||
time = Number(String(time).substr(0, 10))
|
||||
if (time > storage.expire) {
|
||||
DelData(key)
|
||||
return {}
|
||||
}
|
||||
}
|
||||
return storage._data
|
||||
}
|
||||
|
||||
// 删除缓存
|
||||
export function DelData(key) {
|
||||
return Taro.removeStorage({
|
||||
key: key
|
||||
})
|
||||
}
|
36
src/utils/utils.js
Normal file
36
src/utils/utils.js
Normal file
@ -0,0 +1,36 @@
|
||||
import Taro from "@tarojs/taro"
|
||||
|
||||
export const successNotice = (content) => {
|
||||
Taro.showToast({ title: content, icon: 'success' })
|
||||
}
|
||||
|
||||
export const errorNotice = (content) => {
|
||||
Taro.showToast({ title: content, icon: 'error' })
|
||||
}
|
||||
|
||||
|
||||
export const loading = (title = '加载中') => {
|
||||
Taro.showLoading({ title })
|
||||
}
|
||||
|
||||
export const closeLoading = () => {
|
||||
Taro.hideLoading()
|
||||
}
|
||||
|
||||
|
||||
export const redirectTo = (url) => {
|
||||
Taro.redirectTo({ url })
|
||||
}
|
||||
|
||||
export const navigateTo = (url) => {
|
||||
Taro.navigateTo({ url })
|
||||
}
|
||||
|
||||
export const backTo = () => {
|
||||
Taro.navigateBack({ delta: 1 })
|
||||
}
|
||||
|
||||
export const backOrGo = (url) => {
|
||||
Taro.getCurrentPages().length > 0 ? Taro.navigateBack() : redirectTo(url)
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user