feat(listings): 重做商品详情页并补充分组截图数据
This commit is contained in:
@@ -7,12 +7,9 @@ import {
|
||||
Button,
|
||||
Card,
|
||||
Checkbox,
|
||||
Col,
|
||||
Descriptions,
|
||||
Divider,
|
||||
Image,
|
||||
Modal,
|
||||
Row,
|
||||
Space,
|
||||
Tag,
|
||||
Typography,
|
||||
@@ -20,10 +17,8 @@ import {
|
||||
import {
|
||||
ArrowLeftOutlined,
|
||||
SafetyCertificateOutlined,
|
||||
ShoppingOutlined,
|
||||
StarFilled,
|
||||
StarOutlined,
|
||||
WalletOutlined,
|
||||
} from '@ant-design/icons'
|
||||
import { Link, useNavigate, useParams } from 'react-router-dom'
|
||||
|
||||
@@ -46,21 +41,39 @@ import { formatCoinM } from '@/shared/utils/format'
|
||||
import type { Listing } from '@/shared/api/types'
|
||||
|
||||
function money(cents: number) {
|
||||
return `¥${(cents / 100).toFixed(2)}`
|
||||
return `¥${(cents / 100).toLocaleString('zh-CN', {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
})}`
|
||||
}
|
||||
|
||||
function assetValue(value: unknown) {
|
||||
if (value && typeof value === 'object') {
|
||||
const record = value as Record<string, unknown>
|
||||
if (typeof record.start === 'string' && typeof record.end === 'string') {
|
||||
return `${record.start} – ${record.end}`
|
||||
}
|
||||
return Object.entries(record)
|
||||
.map(([key, item]) => `${key}:${String(item)}`)
|
||||
.join(',')
|
||||
}
|
||||
if (Array.isArray(value)) return value.map(String).join('、')
|
||||
return value == null || value === '' ? '未填写' : String(value)
|
||||
const skinGroupLabels: Record<string, string> = {
|
||||
melee: '近战皮肤',
|
||||
operatorGold: '干员金皮',
|
||||
operatorRed: '干员红皮',
|
||||
weapon: '武器皮肤',
|
||||
}
|
||||
|
||||
const screenshotGroupLabels: Record<string, string> = {
|
||||
coin: '纯币截图',
|
||||
gameId: '游戏ID截图',
|
||||
totalAsset: '总资产截图',
|
||||
tencentSecurity: '腾讯安全截图',
|
||||
skin: '皮肤截图',
|
||||
}
|
||||
|
||||
function screenshotLabels(item: Listing) {
|
||||
const map = new Map<string, string>()
|
||||
const groups = item.asset_summary?.screenshot_groups
|
||||
if (!groups || typeof groups !== 'object') return map
|
||||
Object.entries(groups as Record<string, unknown>).forEach(([key, urls]) => {
|
||||
if (!Array.isArray(urls)) return
|
||||
const label = screenshotGroupLabels[key] ?? key
|
||||
urls.forEach(url => {
|
||||
if (typeof url === 'string' && url) map.set(url, label)
|
||||
})
|
||||
})
|
||||
return map
|
||||
}
|
||||
|
||||
function galleryImages(item: Listing) {
|
||||
@@ -68,6 +81,78 @@ function galleryImages(item: Listing) {
|
||||
return images.length > 0 ? Array.from(new Set(images)) : []
|
||||
}
|
||||
|
||||
function textOf(value: unknown) {
|
||||
return value == null || value === '' ? '' : String(value)
|
||||
}
|
||||
|
||||
function onlineTimeText(value: unknown) {
|
||||
if (!value || typeof value !== 'object') return ''
|
||||
const row = value as Record<string, unknown>
|
||||
const start = textOf(row.start)
|
||||
const end = textOf(row.end)
|
||||
if (!start && !end) return ''
|
||||
return `${start} - ${end}`
|
||||
}
|
||||
|
||||
function skinGroupsOf(item: Listing) {
|
||||
const groups = item.asset_summary?.skin_groups
|
||||
if (!groups || typeof groups !== 'object') return []
|
||||
return Object.entries(groups as Record<string, unknown>)
|
||||
.map(([key, names]) => ({
|
||||
key,
|
||||
label: skinGroupLabels[key] ?? key,
|
||||
names: Array.isArray(names) ? names.filter((name): name is string => typeof name === 'string') : [],
|
||||
}))
|
||||
.filter(group => group.names.length > 0)
|
||||
}
|
||||
|
||||
function resourcesOf(item: Listing) {
|
||||
const raw = item.asset_summary?.resources
|
||||
if (!Array.isArray(raw)) return []
|
||||
return raw
|
||||
.map(entry => {
|
||||
const row = (entry ?? {}) as Record<string, unknown>
|
||||
return {
|
||||
label: textOf(row.label) || textOf(row.key),
|
||||
quantity: Number(row.quantity ?? 0),
|
||||
mode: textOf(row.mode),
|
||||
}
|
||||
})
|
||||
.filter(row => row.label && row.quantity > 0)
|
||||
}
|
||||
|
||||
function ratioOf(item: Listing) {
|
||||
const published = Number(item.asset_summary?.publish_ratio ?? 0)
|
||||
if (published > 0) return `${published}w`
|
||||
const priceYuan = item.price_cent / 100
|
||||
const coinM = item.haf_coin_amount / 1_000_000
|
||||
if (priceYuan <= 0 || coinM <= 0) return ''
|
||||
return `${((coinM / priceYuan) * 100).toFixed(0)}w`
|
||||
}
|
||||
|
||||
function coreStats(item: Listing) {
|
||||
const summary = item.asset_summary ?? {}
|
||||
const dailyLoss = Number(summary.daily_loss_m ?? 0)
|
||||
const secretKd = Number(summary.secret_kd ?? 0)
|
||||
return [
|
||||
{ label: '哈夫币', value: formatCoinM(item.haf_coin_amount) },
|
||||
{ label: '保险格数', value: textOf(summary.season_insurance) },
|
||||
{ label: '折算比', value: ratioOf(item) ? `1 元 ≈ ${ratioOf(item)}` : '' },
|
||||
{ label: '火力等级', value: textOf(summary.fire_level) },
|
||||
{ label: '体力', value: textOf(summary.stamina_level) },
|
||||
{ label: '负重', value: textOf(summary.load_level) },
|
||||
{ label: '日消耗', value: dailyLoss > 0 ? `${dailyLoss} M / 天` : '' },
|
||||
{ label: '绝密 KD', value: secretKd > 0 ? String(secretKd) : '' },
|
||||
{ label: '段位', value: item.rank_level },
|
||||
{ label: '登录方式', value: item.login_platform },
|
||||
{ label: '区服', value: item.server_region },
|
||||
{ label: '在线时段', value: onlineTimeText(summary.online_time) },
|
||||
{ label: '可改游戏名', value: textOf(summary.modifiable_name) },
|
||||
{ label: '全英雄', value: textOf(summary.all_heroes) },
|
||||
{ label: '凌晨响应', value: textOf(summary.early_morning_response) },
|
||||
].filter(stat => stat.value)
|
||||
}
|
||||
|
||||
export function ListingDetailPage() {
|
||||
const { id } = useParams()
|
||||
const navigate = useNavigate()
|
||||
@@ -91,6 +176,7 @@ export function ListingDetailPage() {
|
||||
const [agreementOpen, setAgreementOpen] = useState(false)
|
||||
const [agreementTitle, setAgreementTitle] = useState('')
|
||||
const [agreementContent, setAgreementContent] = useState('')
|
||||
const [activeImage, setActiveImage] = useState('')
|
||||
|
||||
useEffect(() => {
|
||||
if (!data) return
|
||||
@@ -103,6 +189,12 @@ export function ListingDetailPage() {
|
||||
recordListingView(data)
|
||||
}, [data, token, queryClient])
|
||||
|
||||
useEffect(() => {
|
||||
if (!data) return
|
||||
const images = galleryImages(data)
|
||||
setActiveImage(current => (current && images.includes(current) ? current : images[0] ?? ''))
|
||||
}, [data])
|
||||
|
||||
const showAgreement = (title: string, content?: string) => {
|
||||
setAgreementTitle(title)
|
||||
setAgreementContent(content || '暂无内容')
|
||||
@@ -161,7 +253,7 @@ export function ListingDetailPage() {
|
||||
|
||||
if (isPending) {
|
||||
return (
|
||||
<div className="page-section">
|
||||
<div className="ld-page">
|
||||
<Card loading />
|
||||
</div>
|
||||
)
|
||||
@@ -169,7 +261,7 @@ export function ListingDetailPage() {
|
||||
|
||||
if (isError || !data) {
|
||||
return (
|
||||
<div className="page-section">
|
||||
<div className="ld-page">
|
||||
<Alert
|
||||
type="error"
|
||||
showIcon
|
||||
@@ -186,12 +278,15 @@ export function ListingDetailPage() {
|
||||
}
|
||||
|
||||
const images = galleryImages(data)
|
||||
const assetEntries = Object.entries(data.asset_summary ?? {}).filter(
|
||||
([key]) => key !== 'online_time'
|
||||
)
|
||||
const onlineTime = data.asset_summary?.online_time
|
||||
const previewIndex = Math.max(images.indexOf(activeImage), 0)
|
||||
const labels = screenshotLabels(data)
|
||||
const activeLabel = labels.get(activeImage) ?? ''
|
||||
const skins = skinGroupsOf(data)
|
||||
const resources = resourcesOf(data)
|
||||
const stats = coreStats(data)
|
||||
const isOwner = user?.id === data.owner_id
|
||||
const favorited = token ? Boolean(favoriteIDsQuery.data?.has(data.id)) : isFavorite(data.id)
|
||||
const totalCent = data.price_cent + data.deposit_amount_cent
|
||||
|
||||
const toggleFavoriteState = async () => {
|
||||
if (token) {
|
||||
@@ -210,8 +305,8 @@ export function ListingDetailPage() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="listing-detail-page">
|
||||
<div className="listing-detail-page__crumb">
|
||||
<div className="ld-page">
|
||||
<div className="ld-crumb">
|
||||
<Breadcrumb
|
||||
items={[
|
||||
{ title: <Link to="/">首页</Link> },
|
||||
@@ -224,200 +319,248 @@ export function ListingDetailPage() {
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Row gutter={[24, 24]} className="listing-detail-page__hero">
|
||||
<Col xs={24} lg={14}>
|
||||
<div className="listing-detail-gallery">
|
||||
<section className="ld-hero">
|
||||
<div className="ld-gallery">
|
||||
<div className="ld-gallery__main">
|
||||
{images.length > 0 ? (
|
||||
<Image.PreviewGroup>
|
||||
<div className="listing-detail-gallery__main">
|
||||
<Image src={images[0]} alt={data.title} />
|
||||
</div>
|
||||
{images.length > 1 ? (
|
||||
<div className="listing-detail-gallery__thumbs">
|
||||
{images.slice(0, 6).map(url => (
|
||||
<Image key={url} src={url} alt={data.title} width={92} height={68} />
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
<Image.PreviewGroup
|
||||
preview={{ current: previewIndex }}
|
||||
items={images}
|
||||
>
|
||||
<Image src={activeImage || images[0]} alt={data.title} />
|
||||
</Image.PreviewGroup>
|
||||
) : (
|
||||
<div className="listing-detail-gallery__empty">
|
||||
<div className="ld-gallery__empty">
|
||||
<BrandLogo height={40} />
|
||||
<span>暂无商品图片</span>
|
||||
<span>号主暂未上传截图</span>
|
||||
</div>
|
||||
)}
|
||||
<span className={`ld-status${data.in_transaction ? ' is-busy' : ''}`}>
|
||||
{data.in_transaction ? '租赁中' : '可租'}
|
||||
</span>
|
||||
{images.length > 1 ? (
|
||||
<span className="ld-gallery__count">
|
||||
{activeLabel ? `${activeLabel} · ` : ''}
|
||||
{previewIndex + 1} / {images.length}
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
</Col>
|
||||
|
||||
<Col xs={24} lg={10}>
|
||||
<Card className="listing-buy-card">
|
||||
<div className="listing-buy-card__top">
|
||||
<Typography.Text className="listing-card__no">{data.listing_no}</Typography.Text>
|
||||
<Space size={8}>
|
||||
<Tag color={data.in_transaction ? 'default' : 'green'} bordered={false}>
|
||||
{data.in_transaction ? '租赁中' : '可租'}
|
||||
</Tag>
|
||||
<Button
|
||||
size="small"
|
||||
icon={favorited ? <StarFilled /> : <StarOutlined />}
|
||||
onClick={() => void toggleFavoriteState()}
|
||||
{images.length > 1 ? (
|
||||
<div className="ld-gallery__thumbs">
|
||||
{images.slice(0, 8).map((url, index) => (
|
||||
<button
|
||||
key={url}
|
||||
type="button"
|
||||
className={`ld-thumb${url === activeImage ? ' is-active' : ''}`}
|
||||
title={labels.get(url) ?? ''}
|
||||
onClick={() => setActiveImage(url)}
|
||||
>
|
||||
{favorited ? '已收藏' : '收藏'}
|
||||
</Button>
|
||||
</Space>
|
||||
<img src={url} alt={`${data.title} 截图 ${index + 1}`} loading="lazy" />
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<Typography.Title level={2} className="brand-title listing-buy-card__title">
|
||||
{data.title}
|
||||
</Typography.Title>
|
||||
<Space size={6} wrap>
|
||||
<Tag bordered={false}>{data.server_region || '区服待定'}</Tag>
|
||||
<Tag bordered={false}>{data.login_platform || '登录方式待定'}</Tag>
|
||||
{data.rank_level ? <Tag bordered={false}>{data.rank_level}</Tag> : null}
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<aside className="ld-buy">
|
||||
<div className="ld-buy__head">
|
||||
<span className="ld-no">{data.listing_no}</span>
|
||||
<Space size={8}>
|
||||
<Button
|
||||
size="small"
|
||||
icon={favorited ? <StarFilled /> : <StarOutlined />}
|
||||
onClick={() => void toggleFavoriteState()}
|
||||
>
|
||||
{favorited ? '已收藏' : '收藏'}
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
|
||||
<div className="listing-buy-card__price">
|
||||
<span>租金</span>
|
||||
<strong>{money(data.price_cent)}</strong>
|
||||
<Typography.Title level={2} className="ld-title">
|
||||
{data.title}
|
||||
</Typography.Title>
|
||||
|
||||
<div className="ld-tags">
|
||||
<Tag bordered={false}>{data.server_region || '区服待定'}</Tag>
|
||||
<Tag bordered={false}>{data.login_platform || '登录方式待定'}</Tag>
|
||||
{data.rank_level ? <Tag bordered={false}>{data.rank_level}</Tag> : null}
|
||||
{textOf(data.asset_summary?.season_insurance) ? (
|
||||
<Tag bordered={false}>保险 {textOf(data.asset_summary?.season_insurance)}</Tag>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<div className="ld-price">
|
||||
<span>总租金</span>
|
||||
<strong>{money(data.price_cent)}</strong>
|
||||
<em>
|
||||
押金 {money(data.deposit_amount_cent)} · 合计 {money(totalCent)}
|
||||
</em>
|
||||
</div>
|
||||
|
||||
<div className="ld-quick">
|
||||
<div>
|
||||
<span>哈夫币</span>
|
||||
<strong>{formatCoinM(data.haf_coin_amount)}</strong>
|
||||
</div>
|
||||
<div className="listing-buy-card__meta">
|
||||
<div>
|
||||
<span>押金</span>
|
||||
<strong>{money(data.deposit_amount_cent)}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>哈夫币</span>
|
||||
<strong>{formatCoinM(data.haf_coin_amount)}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>号主</span>
|
||||
<strong>{data.owner_nickname || `#${data.owner_id}`}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>折算比</span>
|
||||
<strong>{ratioOf(data) || '—'}</strong>
|
||||
</div>
|
||||
<div>
|
||||
<span>段位</span>
|
||||
<strong>{data.rank_level || '—'}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Alert
|
||||
type="info"
|
||||
showIcon
|
||||
className="listing-buy-card__notice"
|
||||
message="先看清规则,再决定要不要租"
|
||||
description="提交订单后会锁定商品;支付成功才进入交接,租金、押金、消耗与退款均按订单账单结算。"
|
||||
/>
|
||||
<Button
|
||||
type="primary"
|
||||
size="large"
|
||||
block
|
||||
className="ld-cta"
|
||||
disabled={isOwner || data.in_transaction}
|
||||
onClick={() => openConfirm(data)}
|
||||
>
|
||||
{isOwner ? '不能租用自己发布的商品' : data.in_transaction ? '商品租赁中' : '确认租赁'}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
type="primary"
|
||||
size="large"
|
||||
block
|
||||
disabled={isOwner || data.in_transaction}
|
||||
onClick={() => openConfirm(data)}
|
||||
<div className="ld-links">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
showAgreement(
|
||||
agreements.data?.virtual_asset_purchase?.title ?? '虚拟资产购买协议',
|
||||
agreements.data?.virtual_asset_purchase?.content
|
||||
)
|
||||
}
|
||||
>
|
||||
{isOwner ? '不能租用自己发布的商品' : data.in_transaction ? '商品租赁中' : '确认租赁'}
|
||||
</Button>
|
||||
<div className="listing-buy-card__links">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
showAgreement(
|
||||
agreements.data?.virtual_asset_purchase?.title ?? '虚拟资产购买协议',
|
||||
agreements.data?.virtual_asset_purchase?.content
|
||||
)
|
||||
}
|
||||
>
|
||||
《虚拟资产购买协议》
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
showAgreement(
|
||||
agreements.data?.renter_agreement?.title ?? '租客协议',
|
||||
agreements.data?.renter_agreement?.content
|
||||
)
|
||||
}
|
||||
>
|
||||
《租客协议》
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
showAgreement(
|
||||
postRentalNotice.data?.title ?? '租后须知',
|
||||
postRentalNotice.data?.content
|
||||
)
|
||||
}
|
||||
>
|
||||
《租后须知》
|
||||
</button>
|
||||
虚拟资产购买协议
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
showAgreement(
|
||||
agreements.data?.renter_agreement?.title ?? '租客协议',
|
||||
agreements.data?.renter_agreement?.content
|
||||
)
|
||||
}
|
||||
>
|
||||
租客协议
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
showAgreement(
|
||||
postRentalNotice.data?.title ?? '租后须知',
|
||||
postRentalNotice.data?.content
|
||||
)
|
||||
}
|
||||
>
|
||||
租后须知
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="ld-owner">
|
||||
<SafetyCertificateOutlined />
|
||||
<span>号主 {data.owner_nickname || `#${data.owner_id}`} · 已完成实名认证</span>
|
||||
</div>
|
||||
</aside>
|
||||
</section>
|
||||
|
||||
<section className="ld-body">
|
||||
<Card title="资产概览" className="ld-panel">
|
||||
<div className="ld-stats">
|
||||
{stats.map(stat => (
|
||||
<div className="ld-stat" key={stat.label}>
|
||||
<span>{stat.label}</span>
|
||||
<strong>{stat.value}</strong>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{skins.length > 0 ? (
|
||||
<Card title="皮肤收藏" className="ld-panel">
|
||||
<div className="ld-skin-groups">
|
||||
{skins.map(group => (
|
||||
<div className="ld-skin-group" key={group.key}>
|
||||
<span className="ld-skin-group__label">
|
||||
{group.label}
|
||||
<em>{group.names.length}</em>
|
||||
</span>
|
||||
<div className="ld-skin-group__items">
|
||||
{group.names.map(name => (
|
||||
<span key={name}>{name}</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
) : null}
|
||||
|
||||
<Row gutter={[24, 24]} className="listing-detail-page__body">
|
||||
<Col xs={24} lg={16}>
|
||||
<Card title="账号说明" className="listing-detail-panel">
|
||||
<Typography.Paragraph className="listing-detail-description">
|
||||
{resources.length > 0 ? (
|
||||
<Card title="仓库物资" className="ld-panel">
|
||||
<div className="ld-resources">
|
||||
{resources.map(row => (
|
||||
<div className="ld-resource" key={row.label}>
|
||||
<span>{row.label}</span>
|
||||
<strong>{row.quantity}</strong>
|
||||
{row.mode === '赠送' ? <em>赠送</em> : null}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
) : null}
|
||||
|
||||
<div className="ld-split">
|
||||
<Card title="账号说明" className="ld-panel">
|
||||
<Typography.Paragraph className="ld-description">
|
||||
{data.description || '号主暂未填写补充说明。'}
|
||||
</Typography.Paragraph>
|
||||
</Card>
|
||||
|
||||
<Card title="资产摘要" className="listing-detail-panel">
|
||||
<Descriptions column={2} size="small" colon={false}>
|
||||
{assetEntries.map(([key, value]) => (
|
||||
<Descriptions.Item key={key} label={key}>
|
||||
{assetValue(value)}
|
||||
</Descriptions.Item>
|
||||
))}
|
||||
<Descriptions.Item label="在线时间">{assetValue(onlineTime)}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</Card>
|
||||
|
||||
<Card title="交易流程" className="listing-detail-panel">
|
||||
<div className="listing-process">
|
||||
{[
|
||||
['01', '确认下单', '核对租金、押金与账号信息,提交订单。'],
|
||||
['02', '完成支付', '支付成功后订单进入待交接。'],
|
||||
['03', '号主交接', '号主提交账号与登录说明,租客确认收号。'],
|
||||
['04', '使用与归还', '租期内按规则使用,结束时发起结账。'],
|
||||
['05', '确认结算', '双方确认或客服仲裁,完成押金与租金结算。'],
|
||||
].map(([no, title, desc]) => (
|
||||
<div key={no} className="listing-process__step">
|
||||
<span>{no}</span>
|
||||
<div>
|
||||
<strong>{title}</strong>
|
||||
<p>{desc}</p>
|
||||
</div>
|
||||
<Card title="交易流程" className="ld-panel">
|
||||
<ol className="ld-steps">
|
||||
<li>
|
||||
<span>01</span>
|
||||
<div>
|
||||
<strong>确认下单</strong>
|
||||
<p>核对租金、押金与账号信息。</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<span>02</span>
|
||||
<div>
|
||||
<strong>完成支付</strong>
|
||||
<p>支付成功后进入待交接。</p>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<span>03</span>
|
||||
<div>
|
||||
<strong>号主交接</strong>
|
||||
<p>提交账号与登录说明,租客确认。</p>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<span>04</span>
|
||||
<div>
|
||||
<strong>使用与归还</strong>
|
||||
<p>租期内按规则使用,结束归还。</p>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<span>05</span>
|
||||
<div>
|
||||
<strong>确认结算</strong>
|
||||
<p>双方确认或客服仲裁后结算。</p>
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
<Col xs={24} lg={8}>
|
||||
<Card className="listing-trust-card">
|
||||
<div className="listing-trust-card__item">
|
||||
<SafetyCertificateOutlined />
|
||||
<div>
|
||||
<strong>实名与审核</strong>
|
||||
<span>发布、下单前均需身份核验。</span>
|
||||
</div>
|
||||
</div>
|
||||
<Divider />
|
||||
<div className="listing-trust-card__item">
|
||||
<ShoppingOutlined />
|
||||
<div>
|
||||
<strong>全程留痕</strong>
|
||||
<span>交接、归还、结账都有记录。</span>
|
||||
</div>
|
||||
</div>
|
||||
<Divider />
|
||||
<div className="listing-trust-card__item">
|
||||
<WalletOutlined />
|
||||
<div>
|
||||
<strong>账单透明</strong>
|
||||
<span>租金、押金、消耗逐项列明。</span>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<Modal
|
||||
open={confirmOpen}
|
||||
@@ -454,7 +597,7 @@ export function ListingDetailPage() {
|
||||
<Alert
|
||||
type="warning"
|
||||
showIcon
|
||||
className="listing-buy-card__notice"
|
||||
className="ld-modal-notice"
|
||||
message="提交后会锁定商品并生成待支付订单"
|
||||
description="请在支付前再次核对金额与账号信息;支付成功后才进入交接流程。"
|
||||
/>
|
||||
@@ -475,7 +618,7 @@ export function ListingDetailPage() {
|
||||
}
|
||||
onCancel={() => setAgreementOpen(false)}
|
||||
>
|
||||
<div className="listing-agreement-content">{agreementContent}</div>
|
||||
<div className="ld-agreement">{agreementContent}</div>
|
||||
</Modal>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user