353 行
9.7 KiB
JavaScript
353 行
9.7 KiB
JavaScript
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;
|