feat(distribution): 独立分销前台商城多租户体系、货源与订单数据严格隔离
This commit is contained in:
@@ -0,0 +1,544 @@
|
||||
import { useEffect, useState, useMemo } from 'react'
|
||||
import { useParams, Link } from 'react-router-dom'
|
||||
import {
|
||||
Layout,
|
||||
Typography,
|
||||
Space,
|
||||
Input,
|
||||
Radio,
|
||||
Card,
|
||||
Tag,
|
||||
Button,
|
||||
Modal,
|
||||
Empty,
|
||||
Spin,
|
||||
Badge,
|
||||
message,
|
||||
Descriptions,
|
||||
Divider,
|
||||
} from 'antd'
|
||||
import {
|
||||
ShopOutlined,
|
||||
SearchOutlined,
|
||||
SafetyCertificateOutlined,
|
||||
ThunderboltOutlined,
|
||||
CustomerServiceOutlined,
|
||||
CopyOutlined,
|
||||
CheckCircleOutlined,
|
||||
RightCircleOutlined,
|
||||
RocketOutlined,
|
||||
FireOutlined,
|
||||
} from '@ant-design/icons'
|
||||
import {
|
||||
fetchPublicSiteListings,
|
||||
formatMoney,
|
||||
type PublicDistributionListing,
|
||||
} from '../api'
|
||||
|
||||
export default function Storefront() {
|
||||
const { siteCode = 'demo' } = useParams<{ siteCode: string }>()
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [items, setItems] = useState<PublicDistributionListing[]>([])
|
||||
const [siteName, setSiteName] = useState<string>('')
|
||||
const [keyword, setKeyword] = useState<string>('')
|
||||
const [gameFilter, setGameFilter] = useState<string>('all')
|
||||
const [sortOrder, setSortOrder] = useState<'default' | 'price_asc' | 'price_desc'>('default')
|
||||
const [selectedListing, setSelectedListing] = useState<PublicDistributionListing | null>(null)
|
||||
const [csModalVisible, setCsModalVisible] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
let active = true
|
||||
setLoading(true)
|
||||
fetchPublicSiteListings(siteCode, 1, 100)
|
||||
.then((res) => {
|
||||
if (!active) return
|
||||
setItems(res.items || [])
|
||||
if (res.items && res.items.length > 0) {
|
||||
setSiteName(res.items[0].site_name)
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
if (active) {
|
||||
message.error('加载分销商城商品失败,请检查站点标识')
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
if (active) setLoading(false)
|
||||
})
|
||||
|
||||
return () => {
|
||||
active = false
|
||||
}
|
||||
}, [siteCode])
|
||||
|
||||
const displayName = siteName || `${siteCode.toUpperCase()} 专属分销商城`
|
||||
|
||||
const filteredItems = useMemo(() => {
|
||||
let list = [...items]
|
||||
if (gameFilter !== 'all') {
|
||||
list = list.filter((i) => (i.game_name || '').toLowerCase() === gameFilter.toLowerCase())
|
||||
}
|
||||
const kw = keyword.trim().toLowerCase()
|
||||
if (kw) {
|
||||
list = list.filter(
|
||||
(i) =>
|
||||
(i.title && i.title.toLowerCase().includes(kw)) ||
|
||||
(i.listing_no && i.listing_no.toLowerCase().includes(kw)) ||
|
||||
(i.server_region && i.server_region.toLowerCase().includes(kw)) ||
|
||||
(i.login_platform && i.login_platform.toLowerCase().includes(kw)) ||
|
||||
(i.rank_level && i.rank_level.toLowerCase().includes(kw)),
|
||||
)
|
||||
}
|
||||
if (sortOrder === 'price_asc') {
|
||||
list.sort((a, b) => a.price_cent - b.price_cent)
|
||||
} else if (sortOrder === 'price_desc') {
|
||||
list.sort((a, b) => b.price_cent - a.price_cent)
|
||||
}
|
||||
return list
|
||||
}, [items, gameFilter, keyword, sortOrder])
|
||||
|
||||
function handleCopyListingNo(no: string) {
|
||||
navigator.clipboard?.writeText(no)
|
||||
message.success(`已复制商品编号:${no}`)
|
||||
}
|
||||
|
||||
function handleRentNow(listing: PublicDistributionListing) {
|
||||
setSelectedListing(listing)
|
||||
}
|
||||
|
||||
function openMainCheckout(listing: PublicDistributionListing) {
|
||||
const mainHost = window.location.hostname
|
||||
// 默认主站前台运行在 5189 端口,生产环境通过域名反代
|
||||
const mainUrl = window.location.port
|
||||
? `http://${mainHost}:5189/orders/create?listing_id=${listing.listing_id}&site_code=${listing.site_code}`
|
||||
: `/orders/create?listing_id=${listing.listing_id}&site_code=${listing.site_code}`
|
||||
window.open(mainUrl, '_blank')
|
||||
}
|
||||
|
||||
return (
|
||||
<Layout style={{ minHeight: '100vh', background: '#0f172a' }}>
|
||||
{/* 顶部导航栏 */}
|
||||
<Layout.Header
|
||||
style={{
|
||||
background: 'rgba(15, 23, 42, 0.95)',
|
||||
backdropFilter: 'blur(8px)',
|
||||
borderBottom: '1px solid rgba(255, 255, 255, 0.1)',
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
padding: '0 24px',
|
||||
position: 'sticky',
|
||||
top: 0,
|
||||
zIndex: 100,
|
||||
}}
|
||||
>
|
||||
<Space size="middle" align="center">
|
||||
<div
|
||||
style={{
|
||||
width: 38,
|
||||
height: 38,
|
||||
borderRadius: 8,
|
||||
background: 'linear-gradient(135deg, #2563eb, #3b82f6)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
color: '#fff',
|
||||
boxShadow: '0 0 16px rgba(59, 130, 246, 0.5)',
|
||||
}}
|
||||
>
|
||||
<ShopOutlined style={{ fontSize: 20 }} />
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<Typography.Text strong style={{ color: '#fff', fontSize: 16 }}>
|
||||
{displayName}
|
||||
</Typography.Text>
|
||||
<Tag color="gold" style={{ margin: 0, fontSize: 11 }}>
|
||||
官方合作分销
|
||||
</Tag>
|
||||
</div>
|
||||
<Typography.Text style={{ color: '#94a3b8', fontSize: 11, display: 'block' }}>
|
||||
站点标识:{siteCode} · 主站直营货源保障
|
||||
</Typography.Text>
|
||||
</div>
|
||||
</Space>
|
||||
|
||||
<Space size="middle">
|
||||
<Button
|
||||
type="text"
|
||||
icon={<CustomerServiceOutlined />}
|
||||
style={{ color: '#e2e8f0' }}
|
||||
onClick={() => setCsModalVisible(true)}
|
||||
>
|
||||
联系专属客服
|
||||
</Button>
|
||||
<Link to="/">
|
||||
<Button size="small" style={{ background: 'rgba(255,255,255,0.08)', color: '#94a3b8', borderColor: 'rgba(255,255,255,0.15)' }}>
|
||||
分销商后台
|
||||
</Button>
|
||||
</Link>
|
||||
</Space>
|
||||
</Layout.Header>
|
||||
|
||||
{/* Hero Banner */}
|
||||
<div
|
||||
style={{
|
||||
background: 'linear-gradient(180deg, rgba(30, 41, 59, 0.8) 0%, rgba(15, 23, 42, 1) 100%)',
|
||||
padding: '36px 24px 24px',
|
||||
textAlign: 'center',
|
||||
borderBottom: '1px solid rgba(255, 255, 255, 0.05)',
|
||||
}}
|
||||
>
|
||||
<div style={{ maxWidth: 840, margin: '0 auto' }}>
|
||||
<Space direction="vertical" size={12}>
|
||||
<Tag color="blue" icon={<FireOutlined />} style={{ padding: '2px 10px', fontSize: 12 }}>
|
||||
实时同步主站精品号源 · 一键租号
|
||||
</Tag>
|
||||
<Typography.Title
|
||||
level={2}
|
||||
style={{
|
||||
color: '#fff',
|
||||
margin: 0,
|
||||
fontWeight: 700,
|
||||
letterSpacing: 1,
|
||||
}}
|
||||
>
|
||||
【{displayName}】精选游戏账号商城
|
||||
</Typography.Title>
|
||||
<Typography.Paragraph style={{ color: '#94a3b8', fontSize: 14, margin: '0 0 12px' }}>
|
||||
高阶战备 · 王者段位 · 百万哈夫币 · 极速自动交接 · 押金秒退担保
|
||||
</Typography.Paragraph>
|
||||
|
||||
<Space wrap size="large" style={{ justifyContent: 'center', marginTop: 8 }}>
|
||||
<div style={{ color: '#cbd5e1', fontSize: 13 }}>
|
||||
<ThunderboltOutlined style={{ color: '#38bdf8', marginRight: 6 }} />
|
||||
秒级自动交接上号
|
||||
</div>
|
||||
<div style={{ color: '#cbd5e1', fontSize: 13 }}>
|
||||
<SafetyCertificateOutlined style={{ color: '#34d399', marginRight: 6 }} />
|
||||
主站资金与资产存管
|
||||
</div>
|
||||
<div style={{ color: '#cbd5e1', fontSize: 13 }}>
|
||||
<CheckCircleOutlined style={{ color: '#fbbf24', marginRight: 6 }} />
|
||||
租期结束秒退押金
|
||||
</div>
|
||||
</Space>
|
||||
</Space>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 筛选与内容主体 */}
|
||||
<Layout.Content style={{ maxWidth: 1280, width: '100%', margin: '0 auto', padding: '24px 20px 60px' }}>
|
||||
{/* 筛选栏 */}
|
||||
<Card
|
||||
style={{
|
||||
background: '#1e293b',
|
||||
border: '1px solid rgba(255, 255, 255, 0.08)',
|
||||
marginBottom: 24,
|
||||
}}
|
||||
bodyStyle={{ padding: '16px 20px' }}
|
||||
>
|
||||
<Space direction="vertical" style={{ width: '100%' }} size={14}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', flexWrap: 'wrap', gap: 12 }}>
|
||||
<Space wrap>
|
||||
<Radio.Group
|
||||
value={gameFilter}
|
||||
onChange={(e) => setGameFilter(e.target.value)}
|
||||
buttonStyle="solid"
|
||||
>
|
||||
<Radio.Button value="all">全部游戏</Radio.Button>
|
||||
<Radio.Button value="delta_force">三角洲行动</Radio.Button>
|
||||
<Radio.Button value="honor_of_kings">王者荣耀</Radio.Button>
|
||||
</Radio.Group>
|
||||
|
||||
<Radio.Group
|
||||
value={sortOrder}
|
||||
onChange={(e) => setSortOrder(e.target.value)}
|
||||
size="middle"
|
||||
>
|
||||
<Radio.Button value="default">默认推荐</Radio.Button>
|
||||
<Radio.Button value="price_asc">租金从低到高</Radio.Button>
|
||||
<Radio.Button value="price_desc">租金从高到低</Radio.Button>
|
||||
</Radio.Group>
|
||||
</Space>
|
||||
|
||||
<Input
|
||||
placeholder="搜索账号标题 / 区服 / 段位"
|
||||
prefix={<SearchOutlined style={{ color: '#94a3b8' }} />}
|
||||
allowClear
|
||||
value={keyword}
|
||||
onChange={(e) => setKeyword(e.target.value)}
|
||||
style={{ width: 260, background: '#0f172a', borderColor: 'rgba(255,255,255,0.1)', color: '#fff' }}
|
||||
/>
|
||||
</div>
|
||||
</Space>
|
||||
</Card>
|
||||
|
||||
{/* 列表区域 */}
|
||||
{loading ? (
|
||||
<div style={{ textAlign: 'center', padding: '80px 0' }}>
|
||||
<Spin size="large" tip="正在载入在售商品..." />
|
||||
</div>
|
||||
) : filteredItems.length === 0 ? (
|
||||
<Card style={{ background: '#1e293b', border: '1px solid rgba(255, 255, 255, 0.08)', padding: '60px 0' }}>
|
||||
<Empty
|
||||
description={
|
||||
<span style={{ color: '#94a3b8' }}>
|
||||
{items.length === 0
|
||||
? '当前分销站点暂无上架商品,站长可通过分销后台一键同步主站商品。'
|
||||
: '未找到符合条件的账号商品,请更换搜索词重试。'}
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
</Card>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'repeat(auto-fill, minmax(280px, 1fr))',
|
||||
gap: 20,
|
||||
}}
|
||||
>
|
||||
{filteredItems.map((item) => (
|
||||
<Card
|
||||
key={item.listing_id}
|
||||
hoverable
|
||||
style={{
|
||||
background: '#1e293b',
|
||||
borderColor: 'rgba(255, 255, 255, 0.08)',
|
||||
borderRadius: 10,
|
||||
overflow: 'hidden',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
transition: 'all 0.25s ease',
|
||||
}}
|
||||
bodyStyle={{ padding: 16, display: 'flex', flexDirection: 'column', flex: 1 }}
|
||||
onClick={() => handleRentNow(item)}
|
||||
>
|
||||
{/* 卡片头部 */}
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
|
||||
<Typography.Text style={{ color: '#64748b', fontSize: 12 }}>
|
||||
#{item.listing_no}
|
||||
</Typography.Text>
|
||||
{item.in_transaction ? (
|
||||
<Badge status="warning" text={<span style={{ color: '#fbbf24', fontSize: 12 }}>出租中</span>} />
|
||||
) : (
|
||||
<Badge status="success" text={<span style={{ color: '#34d399', fontSize: 12 }}>可租用</span>} />
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* 账号标题 */}
|
||||
<Typography.Paragraph
|
||||
ellipsis={{ rows: 2 }}
|
||||
strong
|
||||
style={{
|
||||
color: '#f8fafc',
|
||||
fontSize: 15,
|
||||
lineHeight: 1.4,
|
||||
minHeight: 42,
|
||||
marginBottom: 10,
|
||||
}}
|
||||
>
|
||||
{item.title}
|
||||
</Typography.Paragraph>
|
||||
|
||||
{/* 标签属性 */}
|
||||
<Space wrap size={4} style={{ marginBottom: 12 }}>
|
||||
<Tag color="blue" style={{ margin: 0 }}>
|
||||
{item.game_name === 'delta_force' ? '三角洲行动' : item.game_name}
|
||||
</Tag>
|
||||
{item.server_region && (
|
||||
<Tag style={{ margin: 0, background: 'rgba(255,255,255,0.06)', color: '#cbd5e1', border: 'none' }}>
|
||||
{item.server_region}
|
||||
</Tag>
|
||||
)}
|
||||
{item.login_platform && (
|
||||
<Tag style={{ margin: 0, background: 'rgba(255,255,255,0.06)', color: '#cbd5e1', border: 'none' }}>
|
||||
{item.login_platform}
|
||||
</Tag>
|
||||
)}
|
||||
{item.rank_level && (
|
||||
<Tag color="purple" style={{ margin: 0 }}>
|
||||
{item.rank_level}
|
||||
</Tag>
|
||||
)}
|
||||
</Space>
|
||||
|
||||
{/* 资产特色 */}
|
||||
{item.haf_coin_amount > 0 && (
|
||||
<div
|
||||
style={{
|
||||
background: 'rgba(245, 158, 11, 0.1)',
|
||||
border: '1px solid rgba(245, 158, 11, 0.25)',
|
||||
borderRadius: 6,
|
||||
padding: '4px 8px',
|
||||
marginBottom: 12,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 6,
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: 12 }}>🪙</span>
|
||||
<Typography.Text style={{ color: '#fbbf24', fontSize: 12 }}>
|
||||
哈夫币:{item.haf_coin_amount.toLocaleString()}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div style={{ marginTop: 'auto', paddingTop: 10, borderTop: '1px solid rgba(255,255,255,0.06)' }}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end' }}>
|
||||
<div>
|
||||
<div style={{ color: '#ef4444', fontSize: 18, fontWeight: 700, lineHeight: 1 }}>
|
||||
{formatMoney(item.price_cent)}
|
||||
<span style={{ fontSize: 12, color: '#94a3b8', fontWeight: 400 }}> /时</span>
|
||||
</div>
|
||||
<div style={{ color: '#64748b', fontSize: 11, marginTop: 4 }}>
|
||||
押金:{formatMoney(item.deposit_amount_cent)}
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
type="primary"
|
||||
size="middle"
|
||||
icon={<RocketOutlined />}
|
||||
disabled={item.in_transaction}
|
||||
style={{
|
||||
background: item.in_transaction ? undefined : 'linear-gradient(135deg, #2563eb, #3b82f6)',
|
||||
border: 'none',
|
||||
borderRadius: 6,
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
handleRentNow(item)
|
||||
}}
|
||||
>
|
||||
{item.in_transaction ? '出租中' : '立即租用'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</Layout.Content>
|
||||
|
||||
{/* 商品详情 & 租号下单弹窗 */}
|
||||
<Modal
|
||||
title={
|
||||
<Space>
|
||||
<ShopOutlined style={{ color: '#3b82f6' }} />
|
||||
<span>账号租赁详情</span>
|
||||
</Space>
|
||||
}
|
||||
open={Boolean(selectedListing)}
|
||||
onCancel={() => setSelectedListing(null)}
|
||||
footer={null}
|
||||
width={620}
|
||||
destroyOnClose
|
||||
>
|
||||
{selectedListing && (
|
||||
<div style={{ paddingTop: 8 }}>
|
||||
<Typography.Title level={4} style={{ marginBottom: 8 }}>
|
||||
{selectedListing.title}
|
||||
</Typography.Title>
|
||||
<Typography.Text type="secondary" style={{ fontSize: 12, display: 'block', marginBottom: 16 }}>
|
||||
商品唯一编号:{selectedListing.listing_no} · 所属分销商:{selectedListing.site_name}
|
||||
</Typography.Text>
|
||||
|
||||
<Descriptions column={2} bordered size="small">
|
||||
<Descriptions.Item label="所属游戏">
|
||||
{selectedListing.game_name === 'delta_force' ? '三角洲行动' : selectedListing.game_name}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="游戏大区">{selectedListing.server_region || '全区通用'}</Descriptions.Item>
|
||||
<Descriptions.Item label="登录平台">{selectedListing.login_platform || 'PC端'}</Descriptions.Item>
|
||||
<Descriptions.Item label="段位天梯">{selectedListing.rank_level || '暂未定级'}</Descriptions.Item>
|
||||
<Descriptions.Item label="哈夫币资产">
|
||||
{selectedListing.haf_coin_amount > 0
|
||||
? `${selectedListing.haf_coin_amount.toLocaleString()} 币`
|
||||
: '无'}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="交接模式">自动快速交接</Descriptions.Item>
|
||||
<Descriptions.Item label="租金标准">
|
||||
<span style={{ color: '#cf1322', fontWeight: 700, fontSize: 16 }}>
|
||||
{formatMoney(selectedListing.price_cent)}
|
||||
</span>{' '}
|
||||
/ 小时
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="安全押金">
|
||||
<span style={{ fontWeight: 600 }}>{formatMoney(selectedListing.deposit_amount_cent)}</span>
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
|
||||
<Divider style={{ margin: '16px 0' }} />
|
||||
|
||||
<div
|
||||
style={{
|
||||
background: '#f8fafc',
|
||||
padding: '12px 16px',
|
||||
borderRadius: 8,
|
||||
border: '1px solid #e2e8f0',
|
||||
marginBottom: 20,
|
||||
}}
|
||||
>
|
||||
<Typography.Text strong style={{ display: 'block', marginBottom: 6, color: '#334155' }}>
|
||||
<SafetyCertificateOutlined style={{ color: '#16a34a', marginRight: 6 }} />
|
||||
租号官方保障须知
|
||||
</Typography.Text>
|
||||
<ul style={{ paddingLeft: 18, margin: 0, fontSize: 12, color: '#64748b', lineHeight: 1.8 }}>
|
||||
<li>本账号经平台安全审核,支持密码自动交接或专属上号器直连。</li>
|
||||
<li>严禁在游戏内使用任何作弊辅助、脚本外挂,违规将扣除全部押金并封停账户。</li>
|
||||
<li>租期结束并安全下线后,系统将自动结算并全额退还押金。</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', gap: 12 }}>
|
||||
<Button
|
||||
icon={<CopyOutlined />}
|
||||
onClick={() => handleCopyListingNo(selectedListing.listing_no)}
|
||||
style={{ flex: 1 }}
|
||||
>
|
||||
复制商品编号
|
||||
</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<RightCircleOutlined />}
|
||||
onClick={() => openMainCheckout(selectedListing)}
|
||||
style={{ flex: 2, background: 'linear-gradient(135deg, #2563eb, #3b82f6)', border: 'none' }}
|
||||
>
|
||||
前往主站极速上号
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Modal>
|
||||
|
||||
{/* 专属客服弹窗 */}
|
||||
<Modal
|
||||
title="联系分销站点专属客服"
|
||||
open={csModalVisible}
|
||||
onCancel={() => setCsModalVisible(false)}
|
||||
footer={[
|
||||
<Button key="ok" type="primary" onClick={() => setCsModalVisible(false)}>
|
||||
我知道了
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
<div style={{ textAlign: 'center', padding: '16px 0' }}>
|
||||
<CustomerServiceOutlined style={{ fontSize: 48, color: '#3b82f6', marginBottom: 16 }} />
|
||||
<Typography.Title level={4} style={{ margin: '0 0 8px' }}>
|
||||
【{displayName}】专属客服通道
|
||||
</Typography.Title>
|
||||
<Typography.Paragraph type="secondary" style={{ fontSize: 13, marginBottom: 16 }}>
|
||||
如有换号、上号异常、咨询租号或批量合作需求,请联系本站值班客服。
|
||||
</Typography.Paragraph>
|
||||
<div style={{ background: '#f1f5f9', padding: '12px', borderRadius: 8 }}>
|
||||
<Typography.Text strong>分销站点标识:</Typography.Text>
|
||||
<Tag color="blue">{siteCode}</Tag>
|
||||
<div style={{ marginTop: 8, fontSize: 12, color: '#64748b' }}>
|
||||
主站 7x24 小时技术保障支持
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user