Files
hfb_sys/frontend/src/stores/distributionSite.ts
T
yml2213 766c923a6a fix(distribution): 修复分站搜不到已审核商品并实现审核通过自动铺货
问题:分站上架商品审核通过后主站能搜到、分站看不到,且没有自动同步。

根因:分站前台/搜索只认 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 站点码回退,站点探测完成后再挂载应用,
  避免分站发布因缺少站点码被记成主站商品;同步弹窗文案与统计项同步更新
- 补充分销货架自动铺货、清理口径、建站零值落库与审核铺货回归测试
2026-09-30 21:11:09 +08:00

231 lines
7.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { defineStore } from 'pinia'
import { apiClient } from '@/shared/api/client'
import type { ApiResponse } from '@/shared/types/types'
export interface DistributionBanner {
image_url: string
link_url?: string
title?: string
}
export interface DistributionFooterInfo {
icp?: string
copyright?: string
contact?: string
disclaimer?: string
}
export interface DistributionSiteInfo {
site_code: string
site_name: string
domain: string
status: string
display_account_enabled: boolean
default_support_group_id?: number | null
logo_url?: string
favicon_url?: string
banners_json?: string
announcements_json?: string
footer_info_json?: string
receive_ratio_delta?: number
receive_cost_delta?: number
}
/**
* 获取当前上下文生效的分销站点编码
* 优先级:
* 1. 环境变量 VITE_DISTRIBUTION_SITE_CODE(针对独立分销前台开发端口,如 5191)
* 2. 当前标签页 sessionStorage 中的 hfb_site_code(避免跨 Tab 污染主站)
* 3. 本地二级域名(如 test_1.localhost:5189)
*
* 注意:独立域名下的站点编码只来自 sessionStorage,由 initSite() 通过
* /distribution/site-info?domain= 探测后写入。历史上曾读取 localStorage 缓存,
* 会让同一浏览器访问主站时串到分站站点码(把主站发布记到分站/反之),因此已移除。
*/
export function getEffectiveSiteCode(): string {
if (typeof window === 'undefined') return ''
const envCode = ((import.meta.env.VITE_DISTRIBUTION_SITE_CODE as string) || '').trim()
if (envCode) return envCode
const sessionCode = sessionStorage.getItem('hfb_site_code') || ''
if (sessionCode) return sessionCode
const hostname = window.location.hostname
if (hostname && hostname.endsWith('.localhost')) {
return hostname.replace(/\.localhost$/, '')
}
return ''
}
export const useDistributionSiteStore = defineStore('distributionSite', {
state: () => {
const code = getEffectiveSiteCode()
return {
siteCode: code,
siteName: sessionStorage.getItem('hfb_site_name') || '大锤商行',
domain: '',
isDistribution: Boolean(code),
displayAccountEnabled: true,
defaultSupportGroupId: null as number | null,
logoUrl: '',
faviconUrl: '',
banners: [] as DistributionBanner[],
announcements: [] as string[],
footerInfo: null as DistributionFooterInfo | null,
receiveRatioDelta: 0,
receiveCostDelta: 0,
initialized: false,
}
},
actions: {
async initSite() {
const envCode = ((import.meta.env.VITE_DISTRIBUTION_SITE_CODE as string) || '').trim()
const hostname = window.location.hostname
const urlParams = new URLSearchParams(window.location.search)
const querySite = (
urlParams.get('site') ||
urlParams.get('site_code') ||
urlParams.get('distribution_site_code') ||
''
).trim()
// 1. 显式清除或重置为主站
if (querySite === 'main' || querySite === 'clear' || querySite === '0') {
this.resetToMainSite()
this.initialized = true
return
}
// 2. 识别目标分销站点编码
let targetCode: string
if (querySite) {
targetCode = querySite
sessionStorage.setItem('hfb_site_code', querySite)
} else if (envCode) {
targetCode = envCode
sessionStorage.setItem('hfb_site_code', envCode)
} else if (hostname && hostname.endsWith('.localhost')) {
targetCode = hostname.replace(/\.localhost$/, '')
sessionStorage.setItem('hfb_site_code', targetCode)
} else {
targetCode = sessionStorage.getItem('hfb_site_code') || ''
// 若在普通 localhost 且无 envCode、无 query、无 sessionStorage,则视为纯主站,清理旧的 localStorage 串扰
if (!targetCode && (hostname === 'localhost' || hostname === '127.0.0.1')) {
this.resetToMainSite()
this.initialized = true
return
}
}
let queryUrl = ''
if (targetCode) {
queryUrl = `/distribution/site-info?code=${encodeURIComponent(targetCode)}`
} else if (hostname && hostname !== 'localhost' && hostname !== '127.0.0.1') {
queryUrl = `/distribution/site-info?domain=${encodeURIComponent(hostname)}`
}
if (!queryUrl) {
this.resetToMainSite()
this.initialized = true
return
}
try {
const { data } = await apiClient.get<ApiResponse<DistributionSiteInfo>>(queryUrl, {
silent: true,
skipErrorHandler: true,
})
const info = data.data
if (info && info.site_code && info.status === 'active') {
this.siteCode = info.site_code
this.siteName = info.site_name || info.site_code
this.domain = info.domain || ''
this.isDistribution = true
this.displayAccountEnabled = info.display_account_enabled ?? true
this.defaultSupportGroupId = info.default_support_group_id ?? null
this.logoUrl = info.logo_url || ''
this.faviconUrl = info.favicon_url || ''
if (info.banners_json) {
try {
this.banners = JSON.parse(info.banners_json)
} catch {
this.banners = []
}
} else {
this.banners = []
}
if (info.announcements_json) {
try {
this.announcements = JSON.parse(info.announcements_json)
} catch {
this.announcements = []
}
} else {
this.announcements = []
}
if (info.footer_info_json) {
try {
this.footerInfo = JSON.parse(info.footer_info_json)
} catch {
this.footerInfo = null
}
} else {
this.footerInfo = null
}
this.receiveRatioDelta = Math.max(0, Number(info.receive_ratio_delta || 0))
this.receiveCostDelta = Math.max(0, Number(info.receive_cost_delta || 0))
sessionStorage.setItem('hfb_site_code', this.siteCode)
sessionStorage.setItem('hfb_site_name', this.siteName)
// 更新页面标题和 Favicon
document.title = `【${this.siteName}】租号商城 - 精选游戏账号平台`
if (this.faviconUrl && typeof document !== 'undefined') {
let link = document.querySelector("link[rel*='icon']") as HTMLLinkElement | null
if (!link) {
link = document.createElement('link')
link.rel = 'icon'
document.head.appendChild(link)
}
link.href = this.faviconUrl
}
} else {
this.resetToMainSite()
}
} catch {
// 若站点编码无效或未找到,自动回退为主站
this.resetToMainSite()
} finally {
this.initialized = true
}
},
resetToMainSite() {
this.siteCode = ''
this.siteName = '大锤商行'
this.domain = ''
this.isDistribution = false
this.displayAccountEnabled = true
this.defaultSupportGroupId = null
this.logoUrl = ''
this.faviconUrl = ''
this.banners = []
this.announcements = []
this.footerInfo = null
this.receiveRatioDelta = 0
this.receiveCostDelta = 0
sessionStorage.removeItem('hfb_site_code')
sessionStorage.removeItem('hfb_site_name')
localStorage.removeItem('hfb_site_code')
localStorage.removeItem('hfb_site_name')
document.title = '大锤商行 - 官方租号平台'
},
},
})