feat(mobile): 接入商品详情下单确认与协议
This commit is contained in:
@@ -1,9 +1,16 @@
|
||||
import { Button, ErrorBlock, Skeleton, Tag, Toast } from 'antd-mobile'
|
||||
import { useState } from 'react'
|
||||
import { Button, Checkbox, Dialog, ErrorBlock, Popup, Skeleton, Tag, Toast } from 'antd-mobile'
|
||||
import { LeftOutline, PhoneFill } from 'antd-mobile-icons'
|
||||
import { useNavigate, useParams } from 'react-router-dom'
|
||||
|
||||
import { BrandLogo } from '@/components/BrandLogo'
|
||||
import { useListingDetail } from '@/features/listings/api'
|
||||
import {
|
||||
createOrder,
|
||||
useOrderAgreements,
|
||||
usePostRentalNotice,
|
||||
} from '@/features/orders/api'
|
||||
import { useSessionStore } from '@/stores/session'
|
||||
|
||||
function money(cents: number) {
|
||||
return `¥${(cents / 100).toFixed(2)}`
|
||||
@@ -27,6 +34,68 @@ export function MobileListingDetailPage() {
|
||||
const navigate = useNavigate()
|
||||
const { id } = useParams()
|
||||
const { data, isPending, isError, refetch } = useListingDetail(id)
|
||||
const user = useSessionStore(state => state.user)
|
||||
const token = useSessionStore(state => state.token)
|
||||
const agreements = useOrderAgreements()
|
||||
const postRentalNotice = usePostRentalNotice()
|
||||
const [confirmOpen, setConfirmOpen] = useState(false)
|
||||
const [agreed, setAgreed] = useState(false)
|
||||
const [submitting, setSubmitting] = useState(false)
|
||||
|
||||
const showAgreement = (title: string, content?: string) => {
|
||||
Dialog.alert({
|
||||
title,
|
||||
content: <div className="mobile-agreement-content">{content || '暂无内容'}</div>,
|
||||
confirmText: '知道了',
|
||||
})
|
||||
}
|
||||
|
||||
const openConfirm = (inTransaction: boolean, isOwner: boolean) => {
|
||||
if (!token) {
|
||||
navigate(`/m/login?redirect=/m/listings/${id}`)
|
||||
return
|
||||
}
|
||||
if (isOwner) {
|
||||
Toast.show({ content: '不能租用自己的商品' })
|
||||
return
|
||||
}
|
||||
if (inTransaction) {
|
||||
Toast.show({ content: '商品正在租赁中,请稍后再看' })
|
||||
return
|
||||
}
|
||||
if (user?.realname_status !== 'verified') {
|
||||
Dialog.alert({
|
||||
title: '需要先完成实名认证',
|
||||
content: '当前账号未完成实名认证,无法创建租赁订单。请先联系客服或在实名入口完成认证后再下单。',
|
||||
confirmText: '知道了',
|
||||
})
|
||||
return
|
||||
}
|
||||
setAgreed(false)
|
||||
setConfirmOpen(true)
|
||||
}
|
||||
|
||||
const submitOrder = async () => {
|
||||
if (!data) return
|
||||
if (!agreed) {
|
||||
Toast.show({ content: '请先阅读并同意租赁协议' })
|
||||
return
|
||||
}
|
||||
setSubmitting(true)
|
||||
try {
|
||||
const order = await createOrder(data.id)
|
||||
setConfirmOpen(false)
|
||||
Toast.show({ icon: 'success', content: '订单已创建,请继续支付' })
|
||||
navigate(`/m/orders/${order.id}`, { replace: true })
|
||||
} catch (error) {
|
||||
Toast.show({
|
||||
icon: 'fail',
|
||||
content: error instanceof Error ? error.message : '下单失败,请稍后再试',
|
||||
})
|
||||
} finally {
|
||||
setSubmitting(false)
|
||||
}
|
||||
}
|
||||
|
||||
if (isPending) {
|
||||
return (
|
||||
@@ -55,6 +124,7 @@ export function MobileListingDetailPage() {
|
||||
const assetEntries = Object.entries(data.asset_summary || {}).filter(
|
||||
([key]) => key !== 'online_time'
|
||||
)
|
||||
const isOwner = user?.id === data.owner_id
|
||||
|
||||
return (
|
||||
<div className="mobile-detail">
|
||||
@@ -143,13 +213,104 @@ export function MobileListingDetailPage() {
|
||||
<Button
|
||||
block
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
Toast.show({ content: '下单流程将在下一批接入' })
|
||||
}}
|
||||
disabled={isOwner || data.in_transaction}
|
||||
onClick={() => openConfirm(data.in_transaction, isOwner)}
|
||||
>
|
||||
确认租赁
|
||||
{isOwner ? '不能租自己的商品' : data.in_transaction ? '商品租赁中' : '确认租赁'}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Popup
|
||||
visible={confirmOpen}
|
||||
position="bottom"
|
||||
onMaskClick={() => {
|
||||
if (!submitting) setConfirmOpen(false)
|
||||
}}
|
||||
bodyClassName="mobile-order-sheet"
|
||||
>
|
||||
<div className="mobile-order-sheet__title">确认租赁</div>
|
||||
<p className="mobile-order-sheet__hint">
|
||||
提交后会锁定该商品并生成待支付订单;支付成功后才进入交接流程。
|
||||
</p>
|
||||
|
||||
<div className="mobile-order-confirm__summary">
|
||||
<div>
|
||||
<span>商品</span>
|
||||
<strong>{data.title}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>租金</span>
|
||||
<strong>{money(data.price_cent)}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>押金</span>
|
||||
<strong>{money(data.deposit_amount_cent)}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>哈夫币</span>
|
||||
<strong>{data.haf_coin_amount.toLocaleString()} M</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>号主</span>
|
||||
<strong>{data.owner_nickname || `#${data.owner_id}`}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mobile-order-sheet__field">
|
||||
<span>租赁协议</span>
|
||||
<div className="mobile-detail__agreements">
|
||||
<Button
|
||||
size="mini"
|
||||
fill="none"
|
||||
onClick={() =>
|
||||
showAgreement(
|
||||
agreements.data?.virtual_asset_purchase.title || '虚拟资产购买协议',
|
||||
agreements.data?.virtual_asset_purchase.content
|
||||
)
|
||||
}
|
||||
>
|
||||
《虚拟资产购买协议》
|
||||
</Button>
|
||||
<Button
|
||||
size="mini"
|
||||
fill="none"
|
||||
onClick={() =>
|
||||
showAgreement(
|
||||
agreements.data?.renter_agreement.title || '租客协议',
|
||||
agreements.data?.renter_agreement.content
|
||||
)
|
||||
}
|
||||
>
|
||||
《租客协议》
|
||||
</Button>
|
||||
<Button
|
||||
size="mini"
|
||||
fill="none"
|
||||
onClick={() =>
|
||||
showAgreement(
|
||||
postRentalNotice.data?.title || '租后须知',
|
||||
postRentalNotice.data?.content
|
||||
)
|
||||
}
|
||||
>
|
||||
《租后须知》
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Checkbox checked={agreed} onChange={setAgreed}>
|
||||
我已阅读并同意上述协议与租后须知
|
||||
</Checkbox>
|
||||
|
||||
<div className="mobile-order-sheet__actions">
|
||||
<Button block disabled={submitting} onClick={() => setConfirmOpen(false)}>
|
||||
取消
|
||||
</Button>
|
||||
<Button block color="primary" loading={submitting} onClick={() => void submitOrder()}>
|
||||
提交订单
|
||||
</Button>
|
||||
</div>
|
||||
</Popup>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user