import theme from '@/shopro/config/theme.js'; const LEGACY_TABBAR_COLORS = { active: ['#FF0e25', '#ff0e25', '#999', '#333', '#003399', '#001F54', '#002366', '#0A2463', '#0066CC', '#0055AA', '#C5A059', '#C4A574', '#EFC480', '#FFFFFF', '#E9C875', '#F5D78E', '#F5EEDC', '#D0E4F7'], inactive: ['#333', '#000', '#666', '#8FA8C8', '#003399', '#001F54', '#B8C9E0', '#D0E4F7'], bg: ['#fff', '#ffffff', '#FFFFFF', '#001F54', '#003399', '#0066CC', '#0055AA'] }; function getLuminance(hex) { const color = String(hex).replace('#', ''); if (color.length !== 6) return 1; const r = parseInt(color.slice(0, 2), 16); const g = parseInt(color.slice(2, 4), 16); const b = parseInt(color.slice(4, 6), 16); return (0.299 * r + 0.587 * g + 0.114 * b) / 255; } function normalizeColor(color, legacyList, fallback, minLuminance = 0) { if (!color) return fallback; const upper = String(color).toUpperCase(); const lower = String(color).toLowerCase(); if (legacyList.some(item => item.toUpperCase() === upper || item.toLowerCase() === lower)) { return fallback; } if (minLuminance > 0 && getLuminance(color) < minLuminance) { return fallback; } return color; } const TABBAR_LABEL_MAP = { 省钱: '分类', 推荐: '首页' }; const TABBAR_PATH_LABELS = { '/pages/index/category': '分类' }; const LEGACY_CATEGORY_VIEW_PATHS = [ '/pages/index/view?id=76' ]; function normalizeTabbarItem(item) { if (!item || typeof item !== 'object') return item; let name = item.name; let path = item.path; const pathName = item.path_name || ''; const isLegacySaveTab = name === '省钱' || pathName.includes('省钱') || LEGACY_CATEGORY_VIEW_PATHS.includes(path); if (isLegacySaveTab) { name = '分类'; path = '/pages/index/category'; } else if (TABBAR_LABEL_MAP[name]) { name = TABBAR_LABEL_MAP[name]; } else if (TABBAR_PATH_LABELS[path]) { name = TABBAR_PATH_LABELS[path]; } if (name === item.name && path === item.path) return item; return { ...item, name, path }; } function isValidIconUrl(url) { if (!url || typeof url !== 'string') return false; const trimmed = url.trim(); return trimmed.length > 0 && trimmed !== 'null' && trimmed !== 'undefined'; } export const TABBAR_CACHE_KEY = 'shopro_tabbar_cache'; export const TABBAR_CACHE_VERSION = 8; // 线上已失效的选中图标(API 仍返回这些地址,但文件 404) const BROKEN_ACTIVE_IMAGE_MARKERS = [ 'fc0a2c4a1572f8633d9a8b92e106196a', '0c1461132c2d80ef9a613e5499d4365e', '36450fbc0719d0b95d9ea9e8077d8f46', '0dc23d0ca71aec4b61f74a256bb21d30' ]; function isBrokenActiveImage(url) { if (!url) return false; return BROKEN_ACTIVE_IMAGE_MARKERS.some(marker => String(url).includes(marker)); } export const DEFAULT_TABBAR = { name: '', style: 1, bgcolor: theme.tabbarBg, activeColor: theme.tabbarActive, color: theme.tabbarInactive, list: [{ name: '首页', path: '/pages/index/index', image: '/static/images/tabbar/tabbar_home.png', activeImage: '/static/images/tabbar/tabbar_home1.png', path_type: 1 }, { name: '分类', path: '/pages/index/category', image: '/static/images/tabbar/tabbar_category.png', activeImage: '/static/images/tabbar/tabbar_category1.png', path_type: 1 }, { name: '购物车', path: '/pages/index/cart', image: '/static/images/tabbar/tabbar_cart.png', activeImage: '/static/images/tabbar/tabbar_cart1.png', path_type: 1 }, { name: '我的', path: '/pages/index/user', image: '/static/images/tabbar/tabbar_personal.png', activeImage: '/static/images/tabbar/tabbar_personal1.png', path_type: 1 }] }; const DEFAULT_TABBAR_ICONS = Object.fromEntries( DEFAULT_TABBAR.list.map(item => [item.path, { image: item.image, activeImage: item.activeImage }]) ); export { DEFAULT_TABBAR_ICONS }; function readTabbarIconFields(item) { return { image: item?.image || item?.icon || '', activeImage: item?.activeImage || item?.active_image || item?.selectImage || '' }; } function isLegacyRemoteIcon(url) { if (!url || typeof url !== 'string') return false; if (url.startsWith('/static/')) return false; return true; } function ensureTabbarIcons(item) { if (!item || typeof item !== 'object') return item; const normalized = normalizeTabbarItem(item); const defaults = DEFAULT_TABBAR_ICONS[normalized.path]; const rawIcons = readTabbarIconFields(item); let image = isValidIconUrl(rawIcons.image) ? rawIcons.image : ''; let activeImage = isValidIconUrl(rawIcons.activeImage) ? rawIcons.activeImage : ''; if (defaults?.image) { image = defaults.image; } else if (!image && defaults?.image) { image = defaults.image; } if (defaults?.activeImage) { activeImage = defaults.activeImage; } else if (!activeImage && defaults?.activeImage) { activeImage = defaults.activeImage; } if (isBrokenActiveImage(activeImage) && defaults?.activeImage) { activeImage = defaults.activeImage; } if (isLegacyRemoteIcon(rawIcons.image) && defaults?.image) { image = defaults.image; } if (isLegacyRemoteIcon(rawIcons.activeImage) && defaults?.activeImage) { activeImage = defaults.activeImage; } if (activeImage && image && activeImage === image && defaults?.activeImage && defaults.activeImage !== image) { activeImage = defaults.activeImage; } if (!image && activeImage) { image = defaults?.image || activeImage; } const activeImageFallback = defaults?.activeImage || ''; if ( image === item.image && activeImage === item.activeImage && activeImageFallback === item.activeImageFallback && normalized.name === item.name && normalized.path === item.path ) { return normalized; } return { ...normalized, image, activeImage, activeImageFallback }; } export function mergeTabbarListWithPrevious(nextList, prevList) { if (!Array.isArray(nextList)) return nextList; const prevByPath = Object.fromEntries( (Array.isArray(prevList) ? prevList : []).map(item => { const normalized = ensureTabbarIcons(item); return [normalized.path, normalized]; }) ); return nextList.map(item => { let merged = ensureTabbarIcons(item); const prev = prevByPath[merged.path]; if (!prev) return merged; const prevActive = isValidIconUrl(prev.activeImage) ? prev.activeImage : ''; const prevImage = isValidIconUrl(prev.image) ? prev.image : ''; if (prevActive && prevActive !== merged.image) { const usePrevActive = prevActive.startsWith('/static/') && (!merged.activeImage || merged.activeImage === merged.image || isBrokenActiveImage(merged.activeImage) || isLegacyRemoteIcon(merged.activeImage)); if (usePrevActive) { merged = { ...merged, activeImage: prevActive }; } } if (!merged.image && prevImage) { merged = { ...merged, image: prevImage }; } return merged; }); } function normalizeTabbarList(list) { if (!Array.isArray(list)) return list; return list.map(item => ensureTabbarIcons(normalizeTabbarItem(item))); } export function getInitialTabbarData() { try { const cached = uni.getStorageSync(TABBAR_CACHE_KEY); if (cached?.list?.length && cached._version === TABBAR_CACHE_VERSION) { return applyThemeToTabbar(cached); } } catch (e) {} return applyThemeToTabbar(DEFAULT_TABBAR); } export function hideNativeTabBar() { // #ifdef MP-WEIXIN try { uni.hideTabBar({ animation: false, fail: () => {} }); } catch (e) {} // #endif } export function applyThemeToTabbar(tabbarData) { if (!tabbarData || Array.isArray(tabbarData) || !tabbarData.list?.length) { return tabbarData; } const bgcolor = normalizeColor(tabbarData.bgcolor, LEGACY_TABBAR_COLORS.bg, theme.tabbarBg); return { ...tabbarData, list: normalizeTabbarList(tabbarData.list), bgcolor, activeColor: theme.tabbarActive, color: theme.tabbarInactive }; } const LEGACY_HEADER_COLORS = ['#FFA33E', '#ff1926', '#FF0e25', '#ff0e25', '#EFC480', '#001F54', '#003399', '#002366', '#0066CC', '#0055AA']; const BRAND_NAME = '雄戈小酒'; const LEGACY_BRAND_REPLACEMENTS = [ [/雄哥小酒/g, '雄戈小酒'], [/雄哥系列/g, '雄戈系列'], [/贵州雄哥酒业有限公司/g, '贵州雄戈酒业有限公司'], [/雄哥酒业/g, '雄戈酒业'], [/小众厨房设备商城/g, BRAND_NAME], [/小众厨房设备/g, BRAND_NAME], [/贵州贤鼎酒业有限公司/g, BRAND_NAME], [/贵州贤鼎酒业/g, BRAND_NAME], [/贤鼎酒业APP/g, `${BRAND_NAME}小程序`], [/贤鼎酒业/g, BRAND_NAME], [/贤鼎商城/g, BRAND_NAME] ]; export function replaceLegacyBrandText(text) { if (text == null || typeof text !== 'string') return text; let result = text; LEGACY_BRAND_REPLACEMENTS.forEach(([pattern, replacement]) => { result = result.replace(pattern, replacement); }); return result; } function shouldUseBrandName(name) { if (!name || typeof name !== 'string') return false; return LEGACY_BRAND_REPLACEMENTS.some(([pattern]) => { pattern.lastIndex = 0; return pattern.test(name); }); } export function normalizeShopConfig(shop) { if (!shop || typeof shop !== 'object') return shop; const next = { ...shop }; if (shouldUseBrandName(next.name)) { next.name = BRAND_NAME; } else if (typeof next.name === 'string') { next.name = replaceLegacyBrandText(next.name); } if (Array.isArray(next.copyright)) { next.copyright = next.copyright.map(line => replaceLegacyBrandText(line)); } return next; } export function applyThemeToUserTemplate(userTemplate) { if (!userTemplate || !userTemplate.length) return userTemplate; const head = userTemplate[0]; if (!head?.content) return userTemplate; const color = head.content.color; if (!color || LEGACY_HEADER_COLORS.includes(color) || LEGACY_HEADER_COLORS.map(c => c.toUpperCase()).includes(String(color).toUpperCase())) { return [{ ...head, content: { ...head.content, color: theme.primaryLight } }, ...userTemplate.slice(1)]; } return userTemplate; } export default theme;