问题:分站上架商品审核通过后主站能搜到、分站看不到,且没有自动同步。 根因:分站前台/搜索只认 distribution_site_accounts 中 display_status='enabled' 的货架行,而主站前台不按站点过滤。货架行此前只由「号主在该站上架」或站长手动 「一键同步主站商品」写入,审核通过不回写;同时一键同步的失效清理把「非 published+approved」的货架行一律置为 disabled,商品重新在售后也不会恢复。 - 新增 EnsureListingShelvedTx:商品变为 published+approved 时自动铺到所有 display_account_enabled=true 的站点货架(缺行新增、系统下架恢复、人工下架不动), 经 ListingShelfSyncer 接口注入,避免 listing 反向依赖 distribution - 新增 distribution_site_accounts.display_disabled_by(operator/system/空)区分下架 来源;人工上下架各入口写入来源标记 - 一键同步的失效清理收紧为只清理「货源记录已删除」的孤儿行,并支持恢复系统下架行, 结果新增 reenabled_count - 新增迁移 000074 回填存量缺失货架行,部署后无需逐站手动同步 - 修复 CreateSite 显式传 false/0 的配置(不允许自动展示、结算冷却 0 天)被 GORM default 标签忽略而静默回落默认值 - 前端:去掉会跨站串扰的 localStorage 站点码回退,站点探测完成后再挂载应用, 避免分站发布因缺少站点码被记成主站商品;同步弹窗文案与统计项同步更新 - 补充分销货架自动铺货、清理口径、建站零值落库与审核铺货回归测试
583 lines
22 KiB
TypeScript
583 lines
22 KiB
TypeScript
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'
|
|
|
|
function formatGameName(gameName?: string): string {
|
|
if (!gameName) return ''
|
|
const lower = gameName.toLowerCase().trim()
|
|
if (
|
|
lower === 'delta_force' ||
|
|
lower === 'deltaforce' ||
|
|
lower === 'delta' ||
|
|
lower.includes('delta_force') ||
|
|
lower.includes('delta') ||
|
|
gameName.includes('三角洲')
|
|
) {
|
|
return '三角洲'
|
|
}
|
|
if (lower.includes('honor') || gameName.includes('王者')) {
|
|
return '王者荣耀'
|
|
}
|
|
if (lower.includes('genshin') || gameName.includes('原神')) {
|
|
return '原神'
|
|
}
|
|
if (lower.includes('cs') || lower.includes('csgo')) {
|
|
return 'CS2'
|
|
}
|
|
return gameName
|
|
}
|
|
|
|
function formatLoginPlatform(platform?: string): string {
|
|
if (!platform) return ''
|
|
const lower = platform.toLowerCase().trim()
|
|
if (lower === 'qq') return 'QQ'
|
|
if (lower === 'wechat' || lower === 'wx') return '微信'
|
|
if (lower === 'steam') return 'Steam'
|
|
if (lower === 'epic') return 'Epic'
|
|
if (lower === 'wegame') return 'WeGame'
|
|
if (lower === 'mobile') return '手游端'
|
|
if (lower === 'pc') return 'PC端'
|
|
return platform
|
|
}
|
|
|
|
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 }}>
|
|
{formatGameName(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' }}>
|
|
{formatLoginPlatform(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)}
|
|
|
|
</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="所属游戏">
|
|
{formatGameName(selectedListing.game_name)}
|
|
</Descriptions.Item>
|
|
<Descriptions.Item label="游戏大区">{selectedListing.server_region || '全区通用'}</Descriptions.Item>
|
|
<Descriptions.Item label="登录平台">{formatLoginPlatform(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>
|
|
)
|
|
}
|