Browse Source

新增:余额支付、微信支付、下单确认功能

master
科技小王子 4 weeks ago
parent
commit
1fdec4b807
  1. 2
      config/app.ts
  2. 4
      config/env.ts
  3. 2
      src/api/shop/shopOrder/model/index.ts
  4. 52
      src/pages/index/BestSellers.tsx
  5. 8
      src/pages/index/Header.scss
  6. 15
      src/pages/index/Header.tsx
  7. 14
      src/pages/index/index.tsx
  8. 1
      src/pages/order/order.config.ts
  9. 32
      src/pages/order/order.tsx
  10. 14
      src/shop/goodsDetail/index.tsx
  11. 32
      src/shop/orderConfirm/index.tsx
  12. 2
      src/utils/common.ts
  13. 2
      src/utils/request.ts
  14. 2
      src/utils/server.ts

2
config/app.ts

@ -8,3 +8,5 @@ export const BaseUrl = API_BASE_URL;
export const Version = 'v3.0.8'; export const Version = 'v3.0.8';
// 版权信息 // 版权信息
export const Copyright = 'WebSoft Inc.'; export const Copyright = 'WebSoft Inc.';
// java -jar CertificateDownloader.jar -k 0kF5OlPr482EZwtn9zGufUcqa7ovgxRL -m 1723321338 -f ./apiclient_key.pem -s 2B933F7C35014A1C363642623E4A62364B34C4EB -o ./

4
config/env.ts

@ -2,13 +2,13 @@
export const ENV_CONFIG = { export const ENV_CONFIG = {
// 开发环境 // 开发环境
development: { development: {
API_BASE_URL: 'https://cms-api.websoft.top/api',
API_BASE_URL: 'https://cms-api.s209.websoft.top/api',
APP_NAME: '时里院子市集', APP_NAME: '时里院子市集',
DEBUG: 'true', DEBUG: 'true',
}, },
// 生产环境 // 生产环境
production: { production: {
API_BASE_URL: 'https://cms-api.websoft.top/api',
API_BASE_URL: 'https://cms-api.s209.websoft.top/api',
APP_NAME: '时里院子市集', APP_NAME: '时里院子市集',
DEBUG: 'false', DEBUG: 'false',
}, },

2
src/api/shop/shopOrder/model/index.ts

@ -42,6 +42,8 @@ export interface ShopOrder {
phone?: string; phone?: string;
// 手机号码(脱敏) // 手机号码(脱敏)
mobile?: string; mobile?: string;
// 关联收货地址
addressId?: number;
// 收货地址 // 收货地址
address?: string; address?: string;
// //

52
src/pages/index/BestSellers.tsx

@ -1,7 +1,7 @@
import {useEffect, useState} from "react"; import {useEffect, useState} from "react";
import {Image} from '@nutui/nutui-react-taro' import {Image} from '@nutui/nutui-react-taro'
import {Share} from '@nutui/icons-react-taro' import {Share} from '@nutui/icons-react-taro'
import Taro from '@tarojs/taro'
import Taro, {useShareAppMessage, useShareTimeline} from "@tarojs/taro";
import {ShopGoods} from "@/api/shop/shopGoods/model"; import {ShopGoods} from "@/api/shop/shopGoods/model";
import {pageShopGoods} from "@/api/shop/shopGoods"; import {pageShopGoods} from "@/api/shop/shopGoods";
import './BestSellers.scss' import './BestSellers.scss'
@ -9,6 +9,7 @@ import './BestSellers.scss'
const BestSellers = () => { const BestSellers = () => {
const [list, setList] = useState<ShopGoods[]>([]) const [list, setList] = useState<ShopGoods[]>([])
const [goods, setGoods] = useState<ShopGoods>()
const reload = () => { const reload = () => {
pageShopGoods({}).then(res => { pageShopGoods({}).then(res => {
@ -20,6 +21,40 @@ const BestSellers = () => {
reload() reload()
}, []) }, [])
// 分享给好友
useShareAppMessage(() => {
return {
title: goods?.name || '精选商品',
path: `/shop/goodsDetail/index?id=${goods?.goodsId}`,
imageUrl: goods?.image, // 分享图片
success: function (res: any) {
console.log('分享成功', res);
Taro.showToast({
title: '分享成功',
icon: 'success',
duration: 2000
});
},
fail: function (res: any) {
console.log('分享失败', res);
Taro.showToast({
title: '分享失败',
icon: 'none',
duration: 2000
});
}
};
});
// 分享到朋友圈
useShareTimeline(() => {
return {
title: `${goods?.name || '精选商品'} - 云上商店`,
path: `/shop/goodsDetail/index?id=${goods?.goodsId}`,
imageUrl: goods?.image
};
});
return ( return (
<> <>
<div className={'py-3'}> <div className={'py-3'}>
@ -43,9 +78,18 @@ const BestSellers = () => {
<span className={'font-bold text-2xl'}>{item.price}</span> <span className={'font-bold text-2xl'}>{item.price}</span>
</div> </div>
<div className={'buy-btn'}> <div className={'buy-btn'}>
<div className={'cart-icon'}>
<Share size={20} className={'mx-4 mt-2'}
onClick={() => Taro.navigateTo({url: '/shop/goodsDetail/index?id=' + item.goodsId})}/>
<div className={'cart-icon flex items-center'}>
<button
className={'flex flex-col justify-center items-center text-gray-500 px-3 gap-1 text-nowrap whitespace-nowrap'}
open-type="share"
onClick={() => {
setGoods(item)
}}
>
<Share className={'text-white'} size={20}/>
</button>
{/*<Share size={20} className={'mx-4 mt-2'}*/}
{/* onClick={() => Taro.navigateTo({url: '/shop/goodsDetail/index?id=' + item.goodsId})}/>*/}
</div> </div>
<div className={'text-white pl-4 pr-5'} <div className={'text-white pl-4 pr-5'}
onClick={() => Taro.navigateTo({url: '/shop/goodsDetail/index?id=' + item.goodsId})}> onClick={() => Taro.navigateTo({url: '/shop/goodsDetail/index?id=' + item.goodsId})}>

8
src/pages/index/Header.scss

@ -6,3 +6,11 @@
position: absolute; position: absolute;
z-index: 0; z-index: 0;
} }
.header-bg2{
background: linear-gradient(to bottom, #03605c, #18ae4f);
height: 200px;
width: 100%;
top: 0;
position: absolute;
z-index: 0;
}

15
src/pages/index/Header.tsx

@ -1,7 +1,7 @@
import {useEffect, useState} from "react"; import {useEffect, useState} from "react";
import Taro from '@tarojs/taro'; import Taro from '@tarojs/taro';
import {Button, Space} from '@nutui/nutui-react-taro' import {Button, Space} from '@nutui/nutui-react-taro'
import {TriangleDown} from '@nutui/icons-react-taro'
import {TriangleDown, Search} from '@nutui/icons-react-taro'
import {Popup, Avatar, NavBar} from '@nutui/nutui-react-taro' import {Popup, Avatar, NavBar} from '@nutui/nutui-react-taro'
import {getSiteInfo, getUserInfo, getWxOpenId} from "@/api/layout"; import {getSiteInfo, getUserInfo, getWxOpenId} from "@/api/layout";
import {TenantId} from "@/config/app"; import {TenantId} from "@/config/app";
@ -12,7 +12,7 @@ import {User} from "@/api/system/user/model";
import MySearch from "./MySearch"; import MySearch from "./MySearch";
import './Header.scss'; import './Header.scss';
const Header = () => {
const Header = (props: any) => {
const [userInfo, setUserInfo] = useState<User>() const [userInfo, setUserInfo] = useState<User>()
const [IsLogin, setIsLogin] = useState<boolean>(true) const [IsLogin, setIsLogin] = useState<boolean>(true)
const [config, setConfig] = useState<CmsWebsite>() const [config, setConfig] = useState<CmsWebsite>()
@ -140,8 +140,10 @@ const Header = () => {
return ( return (
<> <>
<div className={'fixed top-0 header-bg'}>
<MySearch done={reload}/>
<div className={'fixed top-0 header-bg'} style={{
height: !props.stickyStatus ? '180px' : '94px',
}}>
{!props.stickyStatus && <MySearch done={reload}/>}
</div> </div>
<NavBar <NavBar
style={{marginTop: `${statusBarHeight}px`, marginBottom: '0px', backgroundColor: 'transparent'}} style={{marginTop: `${statusBarHeight}px`, marginBottom: '0px', backgroundColor: 'transparent'}}
@ -171,6 +173,11 @@ const Header = () => {
<TriangleDown className={'text-white'} size={9}/> <TriangleDown className={'text-white'} size={9}/>
</div> </div>
)}> )}>
{props.stickyStatus && (
<Space>
<Search className={'text-white mx-2'} size={18}/>
</Space>
)}
</NavBar> </NavBar>
<Popup <Popup
visible={showBasic} visible={showBasic}

14
src/pages/index/index.tsx

@ -2,7 +2,7 @@ import Header from './Header';
import BestSellers from './BestSellers'; import BestSellers from './BestSellers';
import Taro from '@tarojs/taro'; import Taro from '@tarojs/taro';
import {useShareAppMessage, useShareTimeline} from "@tarojs/taro" import {useShareAppMessage, useShareTimeline} from "@tarojs/taro"
import {useEffect} from "react";
import {useEffect, useState} from "react";
import {getSiteInfo} from "@/api/layout"; import {getSiteInfo} from "@/api/layout";
import {Sticky} from '@nutui/nutui-react-taro' import {Sticky} from '@nutui/nutui-react-taro'
import Menu from "./Menu"; import Menu from "./Menu";
@ -12,6 +12,8 @@ import './index.scss'
// import GoodsList from "./GoodsList"; // import GoodsList from "./GoodsList";
function Home() { function Home() {
// 吸顶状态
const [stickyStatus, setStickyStatus] = useState<boolean>(false)
useShareTimeline(() => { useShareTimeline(() => {
return { return {
@ -70,6 +72,12 @@ function Home() {
}); });
}; };
const onSticky = (item) => {
if(item){
setStickyStatus(!stickyStatus)
}
}
const reload = () => { const reload = () => {
}; };
@ -104,8 +112,8 @@ function Home() {
return ( return (
<> <>
<Sticky threshold={0}>
<Header/>
<Sticky threshold={0} onChange={() => onSticky(arguments)}>
<Header stickyStatus={stickyStatus}/>
</Sticky> </Sticky>
<div className={'flex flex-col mt-12'}> <div className={'flex flex-col mt-12'}>
<Menu/> <Menu/>

1
src/pages/order/order.config.ts

@ -1,5 +1,4 @@
export default definePageConfig({ export default definePageConfig({
navigationBarTitleText: '订单列表', navigationBarTitleText: '订单列表',
navigationBarTextStyle: 'black',
navigationStyle: 'custom' navigationStyle: 'custom'
}) })

32
src/pages/order/order.tsx

@ -1,6 +1,6 @@
import {useState} from "react"; // 添加 useCallback 引入 import {useState} from "react"; // 添加 useCallback 引入
import Taro, {useDidShow} from '@tarojs/taro' import Taro, {useDidShow} from '@tarojs/taro'
import {NavBar, Space} from '@nutui/nutui-react-taro'
import {NavBar, Space, Empty, Button, ConfigProvider} from '@nutui/nutui-react-taro'
import {Search} from '@nutui/icons-react-taro' import {Search} from '@nutui/icons-react-taro'
import OrderList from "./components/OrderList"; import OrderList from "./components/OrderList";
import {ShopOrder} from "@/api/shop/shopOrder/model"; import {ShopOrder} from "@/api/shop/shopOrder/model";
@ -38,8 +38,6 @@ function Order() {
<NavBar <NavBar
fixed={true} fixed={true}
style={{marginTop: `${statusBarHeight}px`, backgroundColor: 'transparent'}} style={{marginTop: `${statusBarHeight}px`, backgroundColor: 'transparent'}}
onBackClick={() => {
}}
left={ left={
<> <>
<div className={'flex justify-between items-center w-full'}> <div className={'flex justify-between items-center w-full'}>
@ -56,9 +54,33 @@ function Order() {
</> </>
} }
> >
<span></span>
<span></span>
</NavBar> </NavBar>
<OrderList data={list}/>
{/*暂无订单*/}
{list.length == 0 && (
<ConfigProvider>
<div className={'h-full flex flex-col justify-center items-center'} style={{
height: 'calc(100vh - 150px)',
}}>
<Empty
style={{
backgroundColor: 'transparent'
}}
description="您还没有订单哦"
/>
<Space>
<Button type="success" fill="dashed"
onClick={() => Taro.switchTab({url: '/pages/index/index'})}></Button>
</Space>
</div>
</ConfigProvider>
)}
{/*订单列表*/}
{
list.length > 0 && (
<OrderList data={list}/>
)
}
</> </>
); );
} }

14
src/shop/goodsDetail/index.tsx

@ -6,7 +6,7 @@ import {RichText, View} from '@tarojs/components'
import {ShopGoods} from "@/api/shop/shopGoods/model"; import {ShopGoods} from "@/api/shop/shopGoods/model";
import {getShopGoods} from "@/api/shop/shopGoods"; import {getShopGoods} from "@/api/shop/shopGoods";
import {Swiper} from '@nutui/nutui-react-taro' import {Swiper} from '@nutui/nutui-react-taro'
import {wxParse} from "@/utils/common";
import navTo, {wxParse} from "@/utils/common";
import "./index.scss"; import "./index.scss";
import {useCart} from "@/hooks/useCart"; import {useCart} from "@/hooks/useCart";
@ -23,6 +23,14 @@ const GoodsDetail = () => {
const handleAddToCart = () => { const handleAddToCart = () => {
if (!goods) return; if (!goods) return;
if(!Taro.getStorageSync('UserId')){
return Taro.showToast({
title: '请先登录',
icon: 'none',
duration: 2000
});
}
addToCart({ addToCart({
goodsId: goods.goodsId!, goodsId: goods.goodsId!,
name: goods.name || '', name: goods.name || '',
@ -117,7 +125,7 @@ const GoodsDetail = () => {
top: "50px", top: "50px",
right: "110px", right: "110px",
}} }}
onClick={() => Taro.navigateTo({url: '/pages/cart/cart'})}>
onClick={() => navTo(`/pages/cart/cart`,true)}>
<Badge value={cartCount} top="-2" right="2"> <Badge value={cartCount} top="-2" right="2">
<div style={{display: 'flex', alignItems: 'center'}}> <div style={{display: 'flex', alignItems: 'center'}}>
<Cart size={16}/> <Cart size={16}/>
@ -201,7 +209,7 @@ const GoodsDetail = () => {
onClick={() => handleAddToCart()}> onClick={() => handleAddToCart()}>
</div> </div>
<div className={'cart-buy pl-4 pr-5 text-sm'} <div className={'cart-buy pl-4 pr-5 text-sm'}
onClick={() => Taro.navigateTo({url: `/shop/orderConfirm/index?goodsId=${goods?.goodsId}`})}>
onClick={() => navTo(`/shop/orderConfirm/index?goodsId=${goods?.goodsId}`,true)}>
</div> </div>
</div> </div>
</View> </View>

32
src/shop/orderConfirm/index.tsx

@ -12,6 +12,7 @@ import Gap from "@/components/Gap";
import {TenantId} from "@/config/app"; import {TenantId} from "@/config/app";
import {payByBalance, selectPayment} from "@/api/system/payment"; import {payByBalance, selectPayment} from "@/api/system/payment";
import {Payment} from "@/api/system/payment/model"; import {Payment} from "@/api/system/payment/model";
import {API_BASE_URL} from "@/config/env";
const OrderConfirm = () => { const OrderConfirm = () => {
const [goods, setGoods] = useState<ShopGoods | null>(null); const [goods, setGoods] = useState<ShopGoods | null>(null);
@ -60,9 +61,10 @@ const OrderConfirm = () => {
const onBalancePay = async (goods: ShopGoods) => { const onBalancePay = async (goods: ShopGoods) => {
Taro.showLoading({title: '支付中...'}) Taro.showLoading({title: '支付中...'})
payByBalance({ payByBalance({
payType: goods.type,
payType: 0, // 余额支付
payPrice: goods.price, payPrice: goods.price,
totalPrice: goods.price, totalPrice: goods.price,
addressId: address?.id,
userId: Taro.getStorageSync('UserId'), userId: Taro.getStorageSync('UserId'),
tenantId: Number(TenantId) tenantId: Number(TenantId)
}).then().finally(() => { }).then().finally(() => {
@ -73,7 +75,7 @@ const OrderConfirm = () => {
}) })
Taro.hideLoading() Taro.hideLoading()
setTimeout(() => { setTimeout(() => {
// Taro.switchTab({url: '/pages/order/order'})
Taro.switchTab({url: '/pages/order/order'})
}, 2000) }, 2000)
}).catch(() => { }).catch(() => {
Taro.hideLoading() Taro.hideLoading()
@ -83,8 +85,8 @@ const OrderConfirm = () => {
const onWxPay = async (goods: ShopGoods) => { const onWxPay = async (goods: ShopGoods) => {
Taro.showLoading({title: '支付中...'}) Taro.showLoading({title: '支付中...'})
Taro.request({ Taro.request({
// url: 'https://cms-api.websoft.top/api/shop/shop-order',
url: 'http://127.0.0.1:9200/api/shop/shop-order',
url: API_BASE_URL + '/shop/shop-order',
// url: 'http://127.0.0.1:9200/api/shop/shop-order',
method: 'POST', method: 'POST',
header: { header: {
'content-type': 'application/json', 'content-type': 'application/json',
@ -92,15 +94,26 @@ const OrderConfirm = () => {
TenantId TenantId
}, },
data: { data: {
payType: 1,
totalPrice: goods.price, totalPrice: goods.price,
payPrice: goods.price, payPrice: goods.price,
userId: Taro.getStorageSync('UserId'),
tenantId: TenantId, tenantId: TenantId,
payType: goods.type,
comments: goods.name, comments: goods.name,
name: goods.name
name: goods.name,
addressId: address?.id,
}, },
success: function (res) { success: function (res) {
Taro.hideLoading() Taro.hideLoading()
if(res.data.code != 0){
Taro.showToast({
title: res.data.message,
icon: 'error',
duration: 2000
})
return false;
}
// 支付结果
const data = res.data.data const data = res.data.data
console.log(data, 'payInfo') console.log(data, 'payInfo')
// Taro.showToast({ // Taro.showToast({
@ -131,13 +144,8 @@ const OrderConfirm = () => {
}) })
} }
}, },
fail: function (msg) {
console.log('支付失败')
complete: function () {
Taro.hideLoading() Taro.hideLoading()
Taro.showToast({
title: `${msg}`,
icon: 'error'
})
} }
}) })
} }

2
src/utils/common.ts

@ -2,7 +2,7 @@ import Taro from '@tarojs/taro'
export default function navTo(url: string, isLogin = false) { export default function navTo(url: string, isLogin = false) {
if (isLogin) { if (isLogin) {
if (!Taro.getStorageSync('access_token')) {
if (!Taro.getStorageSync('access_token') || !Taro.getStorageSync('UserId')) {
Taro.showToast({ Taro.showToast({
title: '请先登录', title: '请先登录',
icon: 'none', icon: 'none',

2
src/utils/request.ts

@ -5,7 +5,7 @@ let baseUrl = BaseUrl
// 开发环境 // 开发环境
if(process.env.NODE_ENV === 'development'){ if(process.env.NODE_ENV === 'development'){
// baseUrl = 'http://localhost:9000/api'
// baseUrl = 'http://localhost:9200/api'
} }
export function request<T>(options:any) { export function request<T>(options:any) {
const token = Taro.getStorageSync('access_token'); const token = Taro.getStorageSync('access_token');

2
src/utils/server.ts

@ -4,7 +4,7 @@ import {User} from "@/api/system/user/model";
// 模版套餐ID - 请根据实际情况修改 // 模版套餐ID - 请根据实际情况修改
export const TEMPLATE_ID = '10550'; export const TEMPLATE_ID = '10550';
// 服务接口 - 请根据实际情况修改 // 服务接口 - 请根据实际情况修改
export const SERVER_API_URL = 'https://server.gxwebsoft.com/api';
export const SERVER_API_URL = 'https://server.s209.websoft.top/api';
// export const SERVER_API_URL = 'http://127.0.0.1:8000/api'; // export const SERVER_API_URL = 'http://127.0.0.1:8000/api';
/** /**
* *

Loading…
Cancel
Save