135 lines
4.9 KiB
JavaScript
135 lines
4.9 KiB
JavaScript
/**
|
|
* 浮动侧边栏配置消费 (字段来源: /api/config/init → data.floating_button)
|
|
* 纯函数模块, 无副作用, 可直接单测
|
|
*/
|
|
|
|
/** 归一化路由: 'pages/index/index' → '/pages/index/index' */
|
|
export function normalizeRoute(route) {
|
|
if (!route) return '';
|
|
return String(route).charAt(0) === '/' ? String(route) : '/' + String(route);
|
|
}
|
|
|
|
/** 取当前页面路由 (兼容 H5 / 小程序; route 已含分包 root, 如 'pages_goods/detail') */
|
|
export function getCurrentRoute() {
|
|
try {
|
|
const pages = getCurrentPages();
|
|
const cur = pages[pages.length - 1];
|
|
return normalizeRoute((cur && (cur.route || (cur.$page && cur.$page.path))) || '');
|
|
} catch (e) {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 前缀命中判定
|
|
* '/pages/index' 命中 '/pages/index' 与 '/pages/index/xxx'
|
|
* '/pages_tool/' 命中 '/pages_tool/xxx' (前缀自带尾 /)
|
|
* '/pages/order/payment' 只命中它自己及其子路径
|
|
*/
|
|
export function hitPrefix(route, prefix) {
|
|
if (!route || !prefix) return false;
|
|
const p = prefix.charAt(prefix.length - 1) === '/' ? prefix : prefix + '/';
|
|
return route === prefix || route.indexOf(p) === 0;
|
|
}
|
|
|
|
/** 任一前缀命中 */
|
|
function hitAny(route, prefixes) {
|
|
if (!Array.isArray(prefixes)) return false;
|
|
for (let i = 0; i < prefixes.length; i++) {
|
|
if (hitPrefix(route, prefixes[i])) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/** 找出路由命中的页面分组 key (未命中返回 null) */
|
|
export function matchPageGroup(route, prefixMap) {
|
|
if (!prefixMap) return null;
|
|
const keys = Object.keys(prefixMap);
|
|
for (let i = 0; i < keys.length; i++) {
|
|
if (hitAny(normalizeRoute(route), prefixMap[keys[i]])) return keys[i];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* 侧边栏在当前页面是否显示 —— 唯一判定入口
|
|
*
|
|
* 优先级: 总开关 → 强制隐藏 → 显示范围
|
|
* 1) fb 不存在 (老缓存响应) → fallbackVisible (默认 true, 保持老行为)
|
|
* 2) enabled != 1 → false
|
|
* 3) 命中 force_hidden_prefixes 任意前缀 → false (最高优先级)
|
|
* 4) 命中 custom_pages / page_prefixes._custom → true
|
|
* 5) 命中 pages[组] == 1 → true
|
|
* 6) 都不命中 (如 /pages_goods/*) → false
|
|
*/
|
|
export function shouldShowOnPage(fb, route, fallbackVisible) {
|
|
if (!fb || typeof fb !== 'object') return fallbackVisible !== false;
|
|
if (Number(fb.enabled) !== 1) return false;
|
|
|
|
const r = normalizeRoute(route);
|
|
if (!r) return false;
|
|
|
|
// 强制隐藏 — 优先级最高
|
|
if (matchPageGroup(r, fb.force_hidden_prefixes)) return false;
|
|
|
|
// 自定义前缀优先判定
|
|
if (hitAny(r, fb.custom_pages) || hitAny(r, (fb.page_prefixes || {})['_custom'])) return true;
|
|
|
|
// 预设分组
|
|
const group = matchPageGroup(r, fb.page_prefixes);
|
|
if (group) return Number((fb.pages || {})[group]) === 1;
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* 当前页面要渲染的按钮列表 (已按 button_order 排序 + 显隐过滤)
|
|
* 返回 ['lang','kefu','phone'] 的子集, 空数组 = 整个侧边栏不渲染
|
|
* 返回 null = 配置缺失, 由调用方决定老行为
|
|
*/
|
|
export function resolveVisibleButtons(fb) {
|
|
if (!fb || typeof fb !== 'object') return null;
|
|
const order = Array.isArray(fb.button_order) ? fb.button_order : ['lang', 'kefu', 'phone'];
|
|
const map = fb.buttons || {};
|
|
const out = [];
|
|
for (let i = 0; i < order.length; i++) {
|
|
const k = order[i];
|
|
if (Number(map[k]) === 1) out.push(k);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
/**
|
|
* 语言按钮显示文案
|
|
* @param {Object} fb data.floating_button
|
|
* @param {Array} langList [{ value:'zh-cn', name:'CN' }, ...]
|
|
* @param {Number} currentIdx 当前语言下标
|
|
*/
|
|
export function resolveLangButtonText(fb, langList, currentIdx) {
|
|
const list = Array.isArray(langList) ? langList : [];
|
|
if (!list.length) return '';
|
|
const style = (fb && fb.lang_switch && fb.lang_switch.style) || 'target';
|
|
|
|
if (style === 'text') {
|
|
const t = (fb && fb.lang_switch && fb.lang_switch.text) || '';
|
|
if (t) return t; // 空文案兜底走 target
|
|
}
|
|
if (style === 'current' || list.length < 2) {
|
|
return (list[currentIdx] && list[currentIdx].name) || '';
|
|
}
|
|
// target: 显示「点下去会切到的那个」语言
|
|
// 2 种语言 → 另一个; >2 种 → 取第一个不是当前的那个
|
|
let targetIdx = 0;
|
|
for (let i = 0; i < list.length; i++) {
|
|
if (i !== currentIdx) { targetIdx = i; break; }
|
|
}
|
|
return list[targetIdx] ? (list[targetIdx].name || '') : '';
|
|
}
|
|
|
|
/** 语言切换按钮是否可见 (含老「双语模式」fallback) */
|
|
export function isLangButtonVisible(fb, shopInfo, langCount) {
|
|
if (Number(langCount) < 2) return false;
|
|
if (fb && fb.lang_switch) return Number(fb.lang_switch.enabled) === 1;
|
|
return !!(shopInfo && shopInfo.ischina); // 老行为兜底
|
|
}
|