feat(distribution): 重构分销后台为SaaS商户工作台并全面商业化优化
- 商品货架 (Accounts.tsx): 支持期望售价/固定金额/百分比多模式实时联动加价与批量调价,高亮100%独享溢价 - 订单中心 (Orders.tsx): 透传账号游戏租客信息,新增收益对账抽屉透明拆解底价、手续费、分成与自主溢价 - 结算与规则 (Settlements.tsx & Rules.tsx): 纠正角色倒错,商户视角展现周期对账单与分成合作政策 - 店铺装修 (SiteSettings.tsx): 废除手写JSON,提供横幅/公告/页脚可视化列表编辑器与前台实时模拟器 - 数据大盘 (Dashboard.tsx): 对齐最新订单字段,大字展示分销商净收益 - 后端数据层 (dto.go, repository.go, handler.go): 聚合计算分销商订单收益,支持商品与租客搜索
This commit is contained in:
@@ -12,14 +12,20 @@ import {
|
||||
Col,
|
||||
Divider,
|
||||
Image,
|
||||
Alert,
|
||||
Tag,
|
||||
Tabs,
|
||||
Collapse,
|
||||
} from 'antd'
|
||||
import {
|
||||
SaveOutlined,
|
||||
PictureOutlined,
|
||||
NotificationOutlined,
|
||||
EyeOutlined,
|
||||
PlusOutlined,
|
||||
DeleteOutlined,
|
||||
InfoCircleOutlined,
|
||||
SkinOutlined,
|
||||
GlobalOutlined,
|
||||
} from '@ant-design/icons'
|
||||
import {
|
||||
listSites,
|
||||
@@ -30,6 +36,23 @@ import {
|
||||
} from '../api'
|
||||
import { useMember } from '../MemberContext'
|
||||
|
||||
interface BannerItem {
|
||||
image_url: string
|
||||
title?: string
|
||||
link?: string
|
||||
}
|
||||
|
||||
interface AnnouncementItem {
|
||||
title: string
|
||||
content?: string
|
||||
}
|
||||
|
||||
interface FooterInfo {
|
||||
copyright?: string
|
||||
icp?: string
|
||||
contact?: string
|
||||
}
|
||||
|
||||
export default function SiteSettings() {
|
||||
const member = useMember()
|
||||
const [sites, setSites] = useState<Site[]>([])
|
||||
@@ -38,7 +61,16 @@ export default function SiteSettings() {
|
||||
const [saving, setSaving] = useState(false)
|
||||
const [currentSite, setCurrentSite] = useState<Site | null>(null)
|
||||
|
||||
const [form] = Form.useForm()
|
||||
// Visual state for customizer
|
||||
const [logoUrl, setLogoUrl] = useState<string>('')
|
||||
const [faviconUrl, setFaviconUrl] = useState<string>('')
|
||||
const [banners, setBanners] = useState<BannerItem[]>([])
|
||||
const [announcements, setAnnouncements] = useState<AnnouncementItem[]>([])
|
||||
const [footerInfo, setFooterInfo] = useState<FooterInfo>({
|
||||
copyright: '',
|
||||
icp: '',
|
||||
contact: '',
|
||||
})
|
||||
|
||||
const loadSite = useCallback(async (id: number) => {
|
||||
setLoading(true)
|
||||
@@ -48,20 +80,33 @@ export default function SiteSettings() {
|
||||
const found = rows.find((s) => s.id === id)
|
||||
if (found) {
|
||||
setCurrentSite(found)
|
||||
form.setFieldsValue({
|
||||
logo_url: found.logo_url || '',
|
||||
favicon_url: found.favicon_url || '',
|
||||
banners_json: found.banners_json || '[]',
|
||||
announcements_json: found.announcements_json || '[]',
|
||||
footer_info_json: found.footer_info_json || '{}',
|
||||
})
|
||||
setLogoUrl(found.logo_url || '')
|
||||
setFaviconUrl(found.favicon_url || '')
|
||||
|
||||
try {
|
||||
setBanners(found.banners_json ? JSON.parse(found.banners_json) : [])
|
||||
} catch {
|
||||
setBanners([])
|
||||
}
|
||||
|
||||
try {
|
||||
setAnnouncements(found.announcements_json ? JSON.parse(found.announcements_json) : [])
|
||||
} catch {
|
||||
setAnnouncements([])
|
||||
}
|
||||
|
||||
try {
|
||||
setFooterInfo(found.footer_info_json ? JSON.parse(found.footer_info_json) : {})
|
||||
} catch {
|
||||
setFooterInfo({})
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
message.error('加载站点设置失败')
|
||||
} finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}, [form])
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
async function init() {
|
||||
@@ -95,21 +140,59 @@ export default function SiteSettings() {
|
||||
void init()
|
||||
}, [member, loadSite])
|
||||
|
||||
async function handleSave(values: SiteBrandingPayload) {
|
||||
if (!siteID) return
|
||||
// Validate JSON formatting
|
||||
try {
|
||||
if (values.banners_json) JSON.parse(values.banners_json)
|
||||
if (values.announcements_json) JSON.parse(values.announcements_json)
|
||||
if (values.footer_info_json) JSON.parse(values.footer_info_json)
|
||||
} catch {
|
||||
message.error('轮播图、公告或页脚配置的 JSON 格式不正确,请检查!')
|
||||
return
|
||||
}
|
||||
function handleAddBanner() {
|
||||
setBanners([
|
||||
...banners,
|
||||
{
|
||||
image_url: 'https://images.unsplash.com/photo-1542751371-adc38448a05e?w=1200&q=80',
|
||||
title: '热门推荐活动',
|
||||
link: '',
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
function handleUpdateBanner(index: number, field: keyof BannerItem, value: string) {
|
||||
const next = [...banners]
|
||||
next[index] = { ...next[index], [field]: value }
|
||||
setBanners(next)
|
||||
}
|
||||
|
||||
function handleDeleteBanner(index: number) {
|
||||
setBanners(banners.filter((_, i) => i !== index))
|
||||
}
|
||||
|
||||
function handleAddAnnouncement() {
|
||||
setAnnouncements([
|
||||
...announcements,
|
||||
{
|
||||
title: '平台全新上线精选商品,免押畅玩!',
|
||||
content: '',
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
function handleUpdateAnnouncement(index: number, field: keyof AnnouncementItem, value: string) {
|
||||
const next = [...announcements]
|
||||
next[index] = { ...next[index], [field]: value }
|
||||
setAnnouncements(next)
|
||||
}
|
||||
|
||||
function handleDeleteAnnouncement(index: number) {
|
||||
setAnnouncements(announcements.filter((_, i) => i !== index))
|
||||
}
|
||||
|
||||
async function handleSave() {
|
||||
if (!siteID) return
|
||||
setSaving(true)
|
||||
try {
|
||||
const updated = await updateSiteBranding(siteID, values)
|
||||
const payload: SiteBrandingPayload = {
|
||||
logo_url: logoUrl.trim(),
|
||||
favicon_url: faviconUrl.trim(),
|
||||
banners_json: JSON.stringify(banners),
|
||||
announcements_json: JSON.stringify(announcements),
|
||||
footer_info_json: JSON.stringify(footerInfo),
|
||||
}
|
||||
const updated = await updateSiteBranding(siteID, payload)
|
||||
setCurrentSite(updated)
|
||||
message.success('分销站点品牌与装修配置保存成功!')
|
||||
} catch (error: unknown) {
|
||||
@@ -120,39 +203,21 @@ export default function SiteSettings() {
|
||||
}
|
||||
}
|
||||
|
||||
const logoUrl = Form.useWatch('logo_url', form)
|
||||
const bannersJsonStr = Form.useWatch('banners_json', form)
|
||||
const announcementsJsonStr = Form.useWatch('announcements_json', form)
|
||||
|
||||
let banners: { image_url: string; title?: string }[] = []
|
||||
try {
|
||||
if (bannersJsonStr) banners = JSON.parse(bannersJsonStr)
|
||||
} catch {
|
||||
// ignore json error in preview
|
||||
}
|
||||
|
||||
let announcements: { title: string; content?: string }[] = []
|
||||
try {
|
||||
if (announcementsJsonStr) announcements = JSON.parse(announcementsJsonStr)
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
return (
|
||||
<Space direction="vertical" className="page" style={{ width: '100%' }}>
|
||||
<Space direction="vertical" className="page" style={{ width: '100%' }} size="middle">
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<div>
|
||||
<Typography.Title level={3} style={{ marginBottom: 4 }}>
|
||||
品牌与站点装修
|
||||
品牌与站点可视化装修
|
||||
</Typography.Title>
|
||||
<Typography.Text type="secondary">
|
||||
自定义当前分销站前台 Logo、浏览器图标、轮播横幅、站点公告及页脚备案信息。
|
||||
可视化配置当前分销独立站的 Logo、首页轮播海报、跑马灯公告及页脚客服信息。
|
||||
</Typography.Text>
|
||||
</div>
|
||||
<Space>
|
||||
{member?.is_superadmin && sites.length > 1 && (
|
||||
<Select
|
||||
placeholder="分销网站"
|
||||
placeholder="切换分销网站"
|
||||
style={{ width: 220 }}
|
||||
value={siteID}
|
||||
options={sites.map((site) => ({ label: `${site.site_name} (${site.site_code})`, value: site.id }))}
|
||||
@@ -166,148 +231,432 @@ export default function SiteSettings() {
|
||||
<Button
|
||||
icon={<EyeOutlined />}
|
||||
onClick={() => {
|
||||
window.open(`http://${window.location.hostname}:5189/?site=${currentSite.site_code}`, '_blank')
|
||||
const isLocal = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'
|
||||
const targetUrl = isLocal
|
||||
? `http://${window.location.hostname}:5189/?site=${currentSite.site_code}`
|
||||
: currentSite.domain
|
||||
? `https://${currentSite.domain}`
|
||||
: `/?site=${currentSite.site_code}`
|
||||
window.open(targetUrl, '_blank')
|
||||
}}
|
||||
>
|
||||
预览分销前台
|
||||
</Button>
|
||||
)}
|
||||
<Button type="primary" icon={<SaveOutlined />} onClick={handleSave} loading={saving}>
|
||||
保存全部装修
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
|
||||
<Row gutter={24}>
|
||||
<Col span={14}>
|
||||
<Card title="装修配置表单" loading={loading}>
|
||||
<Form form={form} layout="vertical" onFinish={handleSave}>
|
||||
<Row gutter={16}>
|
||||
<Col span={12}>
|
||||
<Form.Item
|
||||
label="站点 Logo 图片地址"
|
||||
name="logo_url"
|
||||
extra="支持 PNG / SVG / JPG 格式的公开图片链接"
|
||||
>
|
||||
<Input placeholder="https://.../logo.png" allowClear />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Form.Item
|
||||
label="浏览器 Favicon 图标地址"
|
||||
name="favicon_url"
|
||||
extra="浏览器标签页小图标 (ICO / PNG)"
|
||||
>
|
||||
<Input placeholder="https://.../favicon.ico" allowClear />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
{/* Left Visual Form Customizer */}
|
||||
<Col xs={24} lg={14}>
|
||||
<Card loading={loading}>
|
||||
<Tabs
|
||||
defaultActiveKey="branding"
|
||||
items={[
|
||||
{
|
||||
key: 'branding',
|
||||
label: '品牌基础资料',
|
||||
children: (
|
||||
<Space direction="vertical" style={{ width: '100%' }} size="middle">
|
||||
<div>
|
||||
<Typography.Text strong>站点 Logo 图片链接:</Typography.Text>
|
||||
<Input
|
||||
placeholder="https://.../logo.png"
|
||||
value={logoUrl}
|
||||
onChange={(e) => setLogoUrl(e.target.value)}
|
||||
allowClear
|
||||
style={{ marginTop: 6 }}
|
||||
/>
|
||||
<Typography.Text type="secondary" style={{ fontSize: 12, display: 'block', marginTop: 4 }}>
|
||||
建议尺寸 240x60 像素,透明底色 PNG 或 SVG 格式
|
||||
</Typography.Text>
|
||||
</div>
|
||||
|
||||
<Divider style={{ margin: '12px 0' }} />
|
||||
<div>
|
||||
<Typography.Text strong>浏览器标签页 Favicon 图标:</Typography.Text>
|
||||
<Input
|
||||
placeholder="https://.../favicon.ico"
|
||||
value={faviconUrl}
|
||||
onChange={(e) => setFaviconUrl(e.target.value)}
|
||||
allowClear
|
||||
style={{ marginTop: 6 }}
|
||||
/>
|
||||
<Typography.Text type="secondary" style={{ fontSize: 12, display: 'block', marginTop: 4 }}>
|
||||
浏览器选项卡显示的小图标,建议 32x32 像素
|
||||
</Typography.Text>
|
||||
</div>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'banners',
|
||||
label: `首页轮播横幅 (${banners.length})`,
|
||||
children: (
|
||||
<Space direction="vertical" style={{ width: '100%' }} size="middle">
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Typography.Text type="secondary">
|
||||
为分销商城首页配置吸睛的促销横幅(支持自动轮播展示)。
|
||||
</Typography.Text>
|
||||
<Button type="dashed" icon={<PlusOutlined />} onClick={handleAddBanner}>
|
||||
添加轮播横幅
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Form.Item
|
||||
label={
|
||||
<Space>
|
||||
<PictureOutlined />
|
||||
<span>首页轮播图配置 (Banners JSON)</span>
|
||||
</Space>
|
||||
}
|
||||
name="banners_json"
|
||||
extra='格式:[{"image_url": "图片URL", "title": "标题", "link": "点击跳转链接"}]'
|
||||
>
|
||||
<Input.TextArea rows={4} placeholder='[{"image_url":"https://.../banner1.jpg","title":"暑期特惠"}]' />
|
||||
</Form.Item>
|
||||
{banners.length === 0 ? (
|
||||
<div style={{ textAlign: 'center', padding: '32px 0', color: '#999' }}>
|
||||
暂未添加轮播横幅,点击上方按钮新增
|
||||
</div>
|
||||
) : (
|
||||
banners.map((item, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
style={{
|
||||
background: '#fbfbfb',
|
||||
border: '1px solid #e8e8e8',
|
||||
borderRadius: 8,
|
||||
padding: '12px 16px',
|
||||
}}
|
||||
>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 8 }}>
|
||||
<strong style={{ color: '#1677ff' }}>横幅 #{idx + 1}</strong>
|
||||
<Button
|
||||
type="text"
|
||||
danger
|
||||
size="small"
|
||||
icon={<DeleteOutlined />}
|
||||
onClick={() => handleDeleteBanner(idx)}
|
||||
>
|
||||
删除
|
||||
</Button>
|
||||
</div>
|
||||
<Row gutter={12}>
|
||||
<Col span={6}>
|
||||
<div style={{ height: 80, background: '#eee', borderRadius: 4, overflow: 'hidden' }}>
|
||||
{item.image_url ? (
|
||||
<Image
|
||||
src={item.image_url}
|
||||
width="100%"
|
||||
height={80}
|
||||
style={{ objectFit: 'cover' }}
|
||||
/>
|
||||
) : (
|
||||
<div style={{ lineHeight: '80px', textAlign: 'center', color: '#aaa', fontSize: 12 }}>无图片</div>
|
||||
)}
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={18}>
|
||||
<Space orientation="vertical" style={{ width: '100%' }} size="small">
|
||||
<Input
|
||||
placeholder="输入图片 URL (https://...)"
|
||||
value={item.image_url}
|
||||
onChange={(e) => handleUpdateBanner(idx, 'image_url', e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
placeholder="横幅标题 (例如:特惠专区)"
|
||||
value={item.title}
|
||||
onChange={(e) => handleUpdateBanner(idx, 'title', e.target.value)}
|
||||
/>
|
||||
<Input
|
||||
placeholder="跳转链接 (可选)"
|
||||
value={item.link}
|
||||
onChange={(e) => handleUpdateBanner(idx, 'link', e.target.value)}
|
||||
/>
|
||||
</Space>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'announcements',
|
||||
label: `跑马灯公告 (${announcements.length})`,
|
||||
children: (
|
||||
<Space direction="vertical" style={{ width: '100%' }} size="middle">
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Typography.Text type="secondary">
|
||||
在商城顶部轮播滚动的最新活动或服务保障公告。
|
||||
</Typography.Text>
|
||||
<Button type="dashed" icon={<PlusOutlined />} onClick={handleAddAnnouncement}>
|
||||
添加公告
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<Form.Item
|
||||
label={
|
||||
<Space>
|
||||
<NotificationOutlined />
|
||||
<span>站点跑马灯公告 (Announcements JSON)</span>
|
||||
</Space>
|
||||
}
|
||||
name="announcements_json"
|
||||
extra='格式:[{"title": "公告标题", "content": "详细内容"}]'
|
||||
>
|
||||
<Input.TextArea rows={3} placeholder='[{"title":"本站三角洲账号货源充足,上号快!"}]' />
|
||||
</Form.Item>
|
||||
{announcements.length === 0 ? (
|
||||
<div style={{ textAlign: 'center', padding: '32px 0', color: '#999' }}>
|
||||
暂无公告,点击上方按钮新增
|
||||
</div>
|
||||
) : (
|
||||
announcements.map((item, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
style={{
|
||||
background: '#fbfbfb',
|
||||
border: '1px solid #e8e8e8',
|
||||
borderRadius: 8,
|
||||
padding: '12px 16px',
|
||||
}}
|
||||
>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 8 }}>
|
||||
<strong>公告 #{idx + 1}</strong>
|
||||
<Button
|
||||
type="text"
|
||||
danger
|
||||
size="small"
|
||||
icon={<DeleteOutlined />}
|
||||
onClick={() => handleDeleteAnnouncement(idx)}
|
||||
>
|
||||
删除
|
||||
</Button>
|
||||
</div>
|
||||
<Space direction="vertical" style={{ width: '100%' }} size="small">
|
||||
<Input
|
||||
placeholder="公告标题"
|
||||
value={item.title}
|
||||
onChange={(e) => handleUpdateAnnouncement(idx, 'title', e.target.value)}
|
||||
/>
|
||||
<Input.TextArea
|
||||
placeholder="公告详细内容 (可选)"
|
||||
rows={2}
|
||||
value={item.content}
|
||||
onChange={(e) => handleUpdateAnnouncement(idx, 'content', e.target.value)}
|
||||
/>
|
||||
</Space>
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'footer',
|
||||
label: '页脚与客服备案',
|
||||
children: (
|
||||
<Space direction="vertical" style={{ width: '100%' }} size="middle">
|
||||
<div>
|
||||
<Typography.Text strong>商城版权文案:</Typography.Text>
|
||||
<Input
|
||||
placeholder="例如:© 2026 游戏账号分销商城 版权所有"
|
||||
value={footerInfo.copyright}
|
||||
onChange={(e) => setFooterInfo({ ...footerInfo, copyright: e.target.value })}
|
||||
style={{ marginTop: 6 }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Form.Item
|
||||
label="页脚信息配置 (Footer Info JSON)"
|
||||
name="footer_info_json"
|
||||
extra='格式:{"copyright": "© 2026 分销站点", "icp": "京ICP备XXXXX号", "contact": "客服QQ: 123456"}'
|
||||
>
|
||||
<Input.TextArea rows={3} placeholder='{"copyright":"© 2026 演示分销网","icp":"浙ICP备000000号"}' />
|
||||
</Form.Item>
|
||||
<div>
|
||||
<Typography.Text strong>ICP 备案编号:</Typography.Text>
|
||||
<Input
|
||||
placeholder="例如:京ICP备20260001号-1"
|
||||
value={footerInfo.icp}
|
||||
onChange={(e) => setFooterInfo({ ...footerInfo, icp: e.target.value })}
|
||||
style={{ marginTop: 6 }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Form.Item style={{ marginBottom: 0 }}>
|
||||
<Button type="primary" htmlType="submit" icon={<SaveOutlined />} loading={saving} size="large">
|
||||
保存装修配置
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
<div>
|
||||
<Typography.Text strong>官方客服微信 / QQ:</Typography.Text>
|
||||
<Input
|
||||
placeholder="例如:客服微信: hfb_kf01 / QQ群: 987654321"
|
||||
value={footerInfo.contact}
|
||||
onChange={(e) => setFooterInfo({ ...footerInfo, contact: e.target.value })}
|
||||
style={{ marginTop: 6 }}
|
||||
/>
|
||||
</div>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<Divider style={{ margin: '16px 0' }} />
|
||||
|
||||
{/* Advanced Raw JSON Inspector (Collapsed) */}
|
||||
<Collapse
|
||||
size="small"
|
||||
items={[
|
||||
{
|
||||
key: 'raw',
|
||||
label: '开发者底包 JSON 数据(自动同步生成,无需手写)',
|
||||
children: (
|
||||
<pre style={{ fontSize: 11, background: '#f5f5f5', padding: 8, borderRadius: 4, maxHeight: 120, overflow: 'auto' }}>
|
||||
{JSON.stringify(
|
||||
{
|
||||
banners,
|
||||
announcements,
|
||||
footer_info: footerInfo,
|
||||
},
|
||||
null,
|
||||
2
|
||||
)}
|
||||
</pre>
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
<Col span={10}>
|
||||
<Card title="效果实时预览" style={{ background: '#f5f7fa' }}>
|
||||
<div style={{ background: '#fff', borderRadius: 8, padding: 16, border: '1px solid #e8e8e8' }}>
|
||||
{/* Header Preview */}
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', borderBottom: '1px solid #eee', paddingBottom: 12 }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
{logoUrl ? (
|
||||
<Image src={logoUrl} height={28} preview={false} style={{ objectFit: 'contain' }} fallback="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='28'%3E%3Ctext x='10' y='20' fill='%23999'%3ELogo 加载中%3C/text%3E%3C/svg%3E" />
|
||||
) : (
|
||||
<Typography.Text strong style={{ fontSize: 16, color: '#1677ff' }}>
|
||||
{currentSite?.site_name || '分销站点名称'}
|
||||
</Typography.Text>
|
||||
)}
|
||||
{/* Right Live Visual Simulation Card */}
|
||||
<Col xs={24} lg={10}>
|
||||
<Card title="分销商城前台实时模拟效果" style={{ background: '#f8fafc' }}>
|
||||
<div
|
||||
style={{
|
||||
background: '#fff',
|
||||
border: '1px solid #d9d9d9',
|
||||
borderRadius: 8,
|
||||
overflow: 'hidden',
|
||||
boxShadow: '0 4px 12px rgba(0,0,0,0.05)',
|
||||
}}
|
||||
>
|
||||
{/* Simulated Browser Bar */}
|
||||
<div
|
||||
style={{
|
||||
background: '#f0f2f5',
|
||||
padding: '6px 12px',
|
||||
borderBottom: '1px solid #e8e8e8',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 8,
|
||||
fontSize: 12,
|
||||
color: '#666',
|
||||
}}
|
||||
>
|
||||
<div style={{ display: 'flex', gap: 4 }}>
|
||||
<div style={{ width: 8, height: 8, borderRadius: '50%', background: '#ff4d4f' }} />
|
||||
<div style={{ width: 8, height: 8, borderRadius: '50%', background: '#faad14' }} />
|
||||
<div style={{ width: 8, height: 8, borderRadius: '50%', background: '#52c41a' }} />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
background: '#fff',
|
||||
borderRadius: 4,
|
||||
padding: '2px 8px',
|
||||
fontSize: 11,
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
https://{currentSite?.domain || `${currentSite?.site_code || 'demo'}.hfb.com`}
|
||||
</div>
|
||||
<Tag color="cyan" style={{ margin: 0 }}>分销前台顶栏</Tag>
|
||||
</div>
|
||||
|
||||
{/* Announcement Preview */}
|
||||
{/* Simulated Header Nav */}
|
||||
<div
|
||||
style={{
|
||||
padding: '10px 14px',
|
||||
borderBottom: '1px solid #f0f0f0',
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
{logoUrl ? (
|
||||
<img src={logoUrl} alt="Logo" style={{ height: 26, objectFit: 'contain' }} />
|
||||
) : (
|
||||
<strong style={{ fontSize: 14, color: '#1677ff' }}>
|
||||
{currentSite?.site_name || 'HFB 分销商城'}
|
||||
</strong>
|
||||
)}
|
||||
<Tag color="blue">分销前台</Tag>
|
||||
</div>
|
||||
|
||||
{/* Simulated Announcements Marquee */}
|
||||
{announcements.length > 0 && (
|
||||
<div style={{ marginTop: 12 }}>
|
||||
<Alert
|
||||
message={
|
||||
<Space>
|
||||
<NotificationOutlined style={{ color: '#fa8c16' }} />
|
||||
<span>{announcements[0].title}</span>
|
||||
</Space>
|
||||
}
|
||||
type="warning"
|
||||
banner
|
||||
style={{ borderRadius: 4, padding: '4px 12px' }}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
background: '#fffbe6',
|
||||
padding: '4px 12px',
|
||||
fontSize: 12,
|
||||
color: '#d46b08',
|
||||
borderBottom: '1px solid #ffe58f',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: 6,
|
||||
}}
|
||||
>
|
||||
<NotificationOutlined />
|
||||
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
|
||||
{announcements[0]?.title}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Banner Preview */}
|
||||
<div style={{ marginTop: 12 }}>
|
||||
<div style={{ fontSize: 12, color: '#888', marginBottom: 4 }}>轮播图预览:</div>
|
||||
{banners.length > 0 && banners[0].image_url ? (
|
||||
<div style={{ width: '100%', height: 120, borderRadius: 6, overflow: 'hidden', background: '#000' }}>
|
||||
<img
|
||||
src={banners[0].image_url}
|
||||
alt="Banner"
|
||||
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
||||
onError={(e) => {
|
||||
(e.target as HTMLImageElement).src = 'https://images.unsplash.com/photo-1542751371-adc38448a05e?w=600&auto=format&fit=crop&q=60'
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{/* Simulated Banner Carousel */}
|
||||
<div style={{ height: 140, background: '#eee', position: 'relative', overflow: 'hidden' }}>
|
||||
{banners.length > 0 && banners[0]?.image_url ? (
|
||||
<img
|
||||
src={banners[0].image_url}
|
||||
alt="Banner"
|
||||
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
||||
/>
|
||||
) : (
|
||||
<div style={{ width: '100%', height: 90, background: '#f0f2f5', borderRadius: 6, display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#999', fontSize: 12 }}>
|
||||
暂无轮播图配置
|
||||
<div
|
||||
style={{
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
color: '#999',
|
||||
fontSize: 12,
|
||||
}}
|
||||
>
|
||||
暂无轮播横幅,请在左侧添加
|
||||
</div>
|
||||
)}
|
||||
{banners.length > 0 && banners[0]?.title && (
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
background: 'rgba(0,0,0,0.5)',
|
||||
color: '#fff',
|
||||
padding: '4px 10px',
|
||||
fontSize: 12,
|
||||
}}
|
||||
>
|
||||
{banners[0].title}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Content Placeholder */}
|
||||
<div style={{ marginTop: 12, padding: 12, background: '#fafafa', borderRadius: 4, textAlign: 'center', color: '#999', fontSize: 12 }}>
|
||||
[ 游戏商品列表展示区域 ]
|
||||
{/* Simulated Account Listings Grid Preview */}
|
||||
<div style={{ padding: 12 }}>
|
||||
<Typography.Text strong style={{ fontSize: 13, display: 'block', marginBottom: 8 }}>
|
||||
精选租号货架
|
||||
</Typography.Text>
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
|
||||
<div style={{ border: '1px solid #f0f0f0', borderRadius: 4, padding: 8, fontSize: 11 }}>
|
||||
<strong>三角洲全金典藏号</strong>
|
||||
<div style={{ color: '#cf1322', marginTop: 4, fontWeight: 'bold' }}>¥35.00 /小时</div>
|
||||
</div>
|
||||
<div style={{ border: '1px solid #f0f0f0', borderRadius: 4, padding: 8, fontSize: 11 }}>
|
||||
<strong>无畏契约全套幻化</strong>
|
||||
<div style={{ color: '#cf1322', marginTop: 4, fontWeight: 'bold' }}>¥28.00 /小时</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Footer Preview */}
|
||||
<div style={{ marginTop: 16, borderTop: '1px solid #eee', paddingTop: 12, textAlign: 'center', fontSize: 11, color: '#999' }}>
|
||||
<div>{currentSite?.site_name || '分销站点'} · 技术支持由 HFB 平台提供</div>
|
||||
{/* Simulated Footer */}
|
||||
<div
|
||||
style={{
|
||||
background: '#fafafa',
|
||||
borderTop: '1px solid #f0f0f0',
|
||||
padding: '10px 12px',
|
||||
fontSize: 11,
|
||||
color: '#8c8c8c',
|
||||
textAlign: 'center',
|
||||
}}
|
||||
>
|
||||
<div>{footerInfo.copyright || `© 2026 ${currentSite?.site_name || '分销网'}`}</div>
|
||||
{footerInfo.icp && <div>{footerInfo.icp}</div>}
|
||||
{footerInfo.contact && <div style={{ color: '#1677ff' }}>{footerInfo.contact}</div>}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user