feat(distribution): 分站前台按独立商城呈现并支持首页文案自定义
分站前台原本对顾客暴露分销身份,且登录等页面写死了主站品牌, 与「一手独立商城」的定位不符;同时首页文案全部硬编码,站长无法按自己口径调整。 去分销身份(顾客可见处): - 头部品牌区、首页主视觉、移动端认证卡去掉「官方分销/官方分销认证/官方分销站」标识 - 会员徽标「分销专享」→「会员专享」,「所属商城」兜底「专属分销站/商城」→「官方商城」 - 订单页说明改为「当前为【X】商城,仅展示在本站产生的订单记录」,保留订单按站隔离的必要说明 - 无公告时的兜底跑马灯、轮播角标去掉分销措辞 - 清理随之失效的 pc-brand-badge / mobile-brand-badge 样式 品牌跟随站点配置(即可自定义): - PC/移动登录页、移动注册页、加桌面引导页的品牌改为 站点名称 + Logo(无 Logo 取站名首字), 不再写死主站「大锤商行」;主站行为不变(新增 store getter brandMark:分站取站名首字,主站仍为「锤」) 首页文案可配置: - 新增迁移 000076 与 distribution_sites.storefront_text_json (tagline 头部副标题 / hero_badge 主视觉徽标 / hero_desc 主视觉描述 / card_sub 移动端卡片副标题) - 分销后台「品牌装修 → 首页文案」可编辑,占位提示即默认值,留空或整段清空回落内置默认 - 贯通 UpdateSiteBranding → 公开站点信息接口(含 Redis 缓存失效)→ 前台 store 逐字段合并默认值 - 装修预览同步展示站长填写的副标题与徽标 测试: - 后端补装修字段写入/公开接口透出/清空回落断言 - 前端新增 storefrontText 单测(默认合并、覆盖、空白与非法类型回落)
This commit is contained in:
@@ -129,6 +129,7 @@ export interface Site {
|
||||
footer_info_json?: string
|
||||
aw_recycle_json?: string
|
||||
cooperation_feedback_json?: string
|
||||
storefront_text_json?: string
|
||||
listing_qrcode_url?: string
|
||||
receive_ratio_delta?: number
|
||||
receive_cost_delta?: number
|
||||
@@ -651,6 +652,7 @@ export interface SiteBrandingPayload {
|
||||
footer_info_json?: string
|
||||
aw_recycle_json?: string
|
||||
cooperation_feedback_json?: string
|
||||
storefront_text_json?: string
|
||||
listing_qrcode_url?: string
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,21 @@ interface AnnouncementItem {
|
||||
content?: string
|
||||
}
|
||||
|
||||
interface StorefrontTextForm {
|
||||
tagline: string
|
||||
hero_badge: string
|
||||
hero_desc: string
|
||||
card_sub: string
|
||||
}
|
||||
|
||||
// 与前台 shared/utils/storefrontText.ts 的默认文案保持一致(留空即回落到这些值)。
|
||||
const DEFAULT_STOREFRONT_TEXT: StorefrontTextForm = {
|
||||
tagline: '安全交易 · 全程留痕',
|
||||
hero_badge: '品质保障',
|
||||
hero_desc: '账号均经过严格验号与安全质检,支持自动交付与全程留痕,为您提供安全无忧的租号体验。',
|
||||
card_sub: '严格验号 · 统一质检交付 · 专属独立订单',
|
||||
}
|
||||
|
||||
interface FooterInfo {
|
||||
copyright?: string
|
||||
icp?: string
|
||||
@@ -121,6 +136,9 @@ export default function SiteSettings() {
|
||||
const [faviconUrl, setFaviconUrl] = useState<string>('')
|
||||
const [banners, setBanners] = useState<BannerItem[]>([])
|
||||
const [announcements, setAnnouncements] = useState<AnnouncementItem[]>([])
|
||||
const [storefrontText, setStorefrontText] = useState<StorefrontTextForm>({
|
||||
...DEFAULT_STOREFRONT_TEXT,
|
||||
})
|
||||
const [footerInfo, setFooterInfo] = useState<FooterInfo>({
|
||||
copyright: '',
|
||||
icp: '',
|
||||
@@ -187,6 +205,20 @@ export default function SiteSettings() {
|
||||
} catch {
|
||||
setFooterInfo({})
|
||||
}
|
||||
|
||||
try {
|
||||
const parsed = found.storefront_text_json
|
||||
? (JSON.parse(found.storefront_text_json) as Partial<StorefrontTextForm>)
|
||||
: {}
|
||||
setStorefrontText({
|
||||
tagline: parsed.tagline?.trim() || '',
|
||||
hero_badge: parsed.hero_badge?.trim() || '',
|
||||
hero_desc: parsed.hero_desc?.trim() || '',
|
||||
card_sub: parsed.card_sub?.trim() || '',
|
||||
})
|
||||
} catch {
|
||||
setStorefrontText({ tagline: '', hero_badge: '', hero_desc: '', card_sub: '' })
|
||||
}
|
||||
setReceiveCostDelta(Math.max(0, found.receive_cost_delta || 0))
|
||||
const aw = parseHomeEntry(found.aw_recycle_json, defaultAWEntry)
|
||||
setAwUseMain(aw.useMain)
|
||||
@@ -468,6 +500,17 @@ export default function SiteSettings() {
|
||||
)
|
||||
}
|
||||
|
||||
/** 全部留空时清除该配置(前台回落默认文案),否则按 JSON 保存。 */
|
||||
function storefrontTextFilled(value: StorefrontTextForm): string {
|
||||
const filled = {
|
||||
tagline: value.tagline.trim(),
|
||||
hero_badge: value.hero_badge.trim(),
|
||||
hero_desc: value.hero_desc.trim(),
|
||||
card_sub: value.card_sub.trim(),
|
||||
}
|
||||
return Object.values(filled).some(Boolean) ? JSON.stringify(filled) : ''
|
||||
}
|
||||
|
||||
async function handleSave() {
|
||||
if (!siteID) return
|
||||
setSaving(true)
|
||||
@@ -480,6 +523,7 @@ export default function SiteSettings() {
|
||||
footer_info_json: JSON.stringify(footerInfo),
|
||||
aw_recycle_json: awUseMain ? '' : JSON.stringify(awEntry),
|
||||
cooperation_feedback_json: coopUseMain ? '' : JSON.stringify(coopEntry),
|
||||
storefront_text_json: storefrontTextFilled(storefrontText),
|
||||
listing_qrcode_url: listingQrcode.trim(),
|
||||
}
|
||||
const updated = await updateSiteBranding(siteID, payload)
|
||||
@@ -1001,6 +1045,58 @@ export default function SiteSettings() {
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'storefront_text',
|
||||
label: '首页文案',
|
||||
children: (
|
||||
<Space direction="vertical" style={{ width: '100%' }} size="middle">
|
||||
<Typography.Text type="secondary">
|
||||
留空则使用默认文案(占位提示即默认值)。这些文案出现在商城头部与首页主视觉,可按本站品牌口径自由填写。
|
||||
</Typography.Text>
|
||||
<div>
|
||||
<Typography.Text strong>头部品牌区副标题</Typography.Text>
|
||||
<Input
|
||||
placeholder={DEFAULT_STOREFRONT_TEXT.tagline}
|
||||
value={storefrontText.tagline}
|
||||
onChange={(e) =>
|
||||
setStorefrontText({ ...storefrontText, tagline: e.target.value })
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Typography.Text strong>首页主视觉徽标</Typography.Text>
|
||||
<Input
|
||||
placeholder={DEFAULT_STOREFRONT_TEXT.hero_badge}
|
||||
value={storefrontText.hero_badge}
|
||||
onChange={(e) =>
|
||||
setStorefrontText({ ...storefrontText, hero_badge: e.target.value })
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Typography.Text strong>首页主视觉描述</Typography.Text>
|
||||
<Input.TextArea
|
||||
rows={2}
|
||||
placeholder={DEFAULT_STOREFRONT_TEXT.hero_desc}
|
||||
value={storefrontText.hero_desc}
|
||||
onChange={(e) =>
|
||||
setStorefrontText({ ...storefrontText, hero_desc: e.target.value })
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Typography.Text strong>移动端认证卡片副标题</Typography.Text>
|
||||
<Input
|
||||
placeholder={DEFAULT_STOREFRONT_TEXT.card_sub}
|
||||
value={storefrontText.card_sub}
|
||||
onChange={(e) =>
|
||||
setStorefrontText({ ...storefrontText, card_sub: e.target.value })
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'footer',
|
||||
label: '页脚与客服备案',
|
||||
@@ -1126,11 +1222,18 @@ export default function SiteSettings() {
|
||||
{logoUrl ? (
|
||||
<img src={logoUrl} alt="Logo" style={{ height: 26, objectFit: 'contain' }} />
|
||||
) : (
|
||||
<strong style={{ fontSize: 14, color: '#1677ff' }}>
|
||||
{currentSite?.site_name || 'HFB 分销商城'}
|
||||
</strong>
|
||||
<span style={{ display: 'flex', flexDirection: 'column' }}>
|
||||
<strong style={{ fontSize: 14, color: '#1677ff' }}>
|
||||
{currentSite?.site_name || 'HFB 分销商城'}
|
||||
</strong>
|
||||
<small style={{ fontSize: 10, color: '#94a3b8' }}>
|
||||
{storefrontText.tagline.trim() || DEFAULT_STOREFRONT_TEXT.tagline}
|
||||
</small>
|
||||
</span>
|
||||
)}
|
||||
<Tag color="blue">分销前台</Tag>
|
||||
<Tag color="blue">
|
||||
{storefrontText.hero_badge.trim() || DEFAULT_STOREFRONT_TEXT.hero_badge}
|
||||
</Tag>
|
||||
</div>
|
||||
|
||||
{/* Simulated Announcements Marquee */}
|
||||
|
||||
Reference in New Issue
Block a user