tabbar.utils.js 6.88 KB
const TABBAR_KEY_ALIAS_MAP = {
  message: 'news',
  application: 'list',
  mine: 'user',
};

const KNOWN_TABBAR_ITEM_MAP = {
  home: {
    key: 'home',
    title: '首页',
    class: 'fa-home',
    visible: true,
    page_url: '/pages/index/index',
    webview_url: '',
    webview_title: '首页',
  },
  news: {
    key: 'news',
    title: '资讯',
    class: 'fa-newspaper-o',
    visible: true,
    page_url: '',
    webview_url: 'https://oa-dev.onwall.cn/f/futian_home/?f=f&p=news_list',
    webview_title: '资讯',
  },
  list: {
    key: 'list',
    title: '应用',
    class: 'fa-th-large',
    visible: true,
    page_url: '',
    webview_url: 'https://oa-dev.onwall.cn/f/futian_home/?f=f&p=futian_list',
    webview_title: '应用',
  },
  user: {
    key: 'user',
    title: '我的',
    class: 'fa-user',
    visible: true,
    page_url: '',
    webview_url: 'https://oa-dev.onwall.cn/f/futian_home/?f=f&p=futian_list',
    webview_title: '我的',
  },
};

const TABBAR_ORDER = ['home', 'news', 'list', 'user'];
const DEFAULT_ICON_CLASS = 'fa-circle-o';

const normalizeVisibleValue = (rawValue, fallbackValue = true) => {
  if (typeof rawValue === 'boolean') {
    return rawValue;
  }

  if (rawValue === 1 || rawValue === '1') {
    return true;
  }

  if (rawValue === 0 || rawValue === '0') {
    return false;
  }

  return fallbackValue;
};

export const normalizeTabbarKey = (key) => {
  const normalizedKey = String(key || '').trim().toLowerCase();
  return TABBAR_KEY_ALIAS_MAP[normalizedKey] || normalizedKey;
};

export const buildWebviewPreviewUrl = (targetUrl = '', pageTitle = '') => {
  const normalizedUrl = String(targetUrl || '').trim();
  const normalizedTitle = String(pageTitle || '').trim();

  if (!normalizedUrl) {
    return '/pages/webview-preview/index';
  }

  const queryList = [`url=${encodeURIComponent(normalizedUrl)}`];

  if (normalizedTitle) {
    queryList.push(`title=${encodeURIComponent(normalizedTitle)}`);
  }

  return `/pages/webview-preview/index?${queryList.join('&')}`;
};

const createFallbackTabbarItem = (key, title = '') => {
  const normalizedKey = normalizeTabbarKey(key);

  return {
    key: normalizedKey,
    title: title || '栏目',
    class: DEFAULT_ICON_CLASS,
    visible: true,
    page_url: normalizedKey === 'home' ? '/pages/index/index' : '',
    webview_url: '',
    webview_title: title || '栏目',
  };
};

export const getDefaultTabbarItem = (key) => {
  const normalizedKey = normalizeTabbarKey(key);
  const fallbackItem =
    KNOWN_TABBAR_ITEM_MAP[normalizedKey] || createFallbackTabbarItem(normalizedKey);

  return {
    ...fallbackItem,
  };
};

export const getDefaultTabbarItems = () =>
  TABBAR_ORDER.map((key) => getDefaultTabbarItem(key)).filter(Boolean);

export const getHomeOnlyTabbarItems = () => [getDefaultTabbarItem('home')].filter(Boolean);

const buildTabbarPageUrl = (key, webviewUrl, webviewTitle, rawPageUrl = '') => {
  if (key === 'home') {
    return rawPageUrl || '/pages/index/index';
  }

  if (!webviewUrl) {
    return '';
  }

  return buildWebviewPreviewUrl(webviewUrl, webviewTitle);
};

export const normalizeTabbarItem = (rawItem = {}) => {
  const normalizedKey = normalizeTabbarKey(rawItem.key || rawItem.name);
  const fallbackItem = getDefaultTabbarItem(normalizedKey || rawItem.title);
  const title = String(rawItem.title || fallbackItem.title || '栏目');
  const webviewUrl = String(
    rawItem.webview_url ||
      rawItem.link_url ||
      rawItem.link ||
      rawItem.url ||
      fallbackItem.webview_url ||
      '',
  );
  const webviewTitle = String(
    rawItem.webview_title ||
      rawItem.link_title ||
      rawItem.title ||
      fallbackItem.webview_title ||
      title,
  );

  return {
    ...fallbackItem,
    ...rawItem,
    key: fallbackItem.key,
    title,
    class: String(
      rawItem.class ||
        rawItem.icon_class ||
        rawItem.icon ||
        fallbackItem.class ||
        DEFAULT_ICON_CLASS,
    ),
    webview_url: webviewUrl,
    webview_title: webviewTitle,
    page_url: buildTabbarPageUrl(
      fallbackItem.key,
      webviewUrl,
      webviewTitle,
      String(rawItem.page_url || fallbackItem.page_url || ''),
    ),
    visible: normalizeVisibleValue(
      rawItem.visible ?? rawItem.is_show ?? rawItem.show,
      fallbackItem.visible,
    ),
  };
};

const sortTabbarObjectEntries = (entries = []) => {
  const orderMap = TABBAR_ORDER.reduce((map, key, index) => {
    map[key] = index;
    return map;
  }, {});

  return entries
    .map((entry, index) => ({ entry, index }))
    .sort((left, right) => {
      const leftKey = normalizeTabbarKey(left.entry[0]);
      const rightKey = normalizeTabbarKey(right.entry[0]);
      const leftOrder = orderMap[leftKey];
      const rightOrder = orderMap[rightKey];
      const leftKnown = Number.isInteger(leftOrder);
      const rightKnown = Number.isInteger(rightOrder);

      if (leftKnown && rightKnown) {
        return leftOrder - rightOrder;
      }

      if (leftKnown) {
        return -1;
      }

      if (rightKnown) {
        return 1;
      }

      return left.index - right.index;
    })
    .map(({ entry }) => entry);
};

const normalizeTabbarObjectItems = (rawMap = {}) => {
  const objectEntries = Object.entries(rawMap).filter(
    ([, value]) => value && typeof value === 'object' && !Array.isArray(value),
  );

  if (!objectEntries.length) {
    return [];
  }

  return sortTabbarObjectEntries(objectEntries)
    .map(([key, value]) =>
      normalizeTabbarItem({
        ...value,
        key,
      }),
    )
    .filter(Boolean);
};

export const normalizeTabbarItems = (rawItems = []) => {
  if (!Array.isArray(rawItems) || !rawItems.length) {
    return getHomeOnlyTabbarItems();
  }

  const normalizedItems = rawItems.map((item) => normalizeTabbarItem(item)).filter(Boolean);

  return normalizedItems.length ? normalizedItems : getHomeOnlyTabbarItems();
};

export const normalizeTabbarPayload = (rawPayload = null) => {
  if (Array.isArray(rawPayload)) {
    return normalizeTabbarItems(rawPayload);
  }

  const arrayPayload = rawPayload?.tab_items || rawPayload?.tabs || rawPayload?.menus;
  if (Array.isArray(arrayPayload)) {
    return normalizeTabbarItems(arrayPayload);
  }

  const objectPayload = rawPayload?.tab_items || rawPayload?.tabs || rawPayload?.menus || rawPayload;
  const normalizedItems = normalizeTabbarObjectItems(objectPayload);

  return normalizedItems.length ? normalizedItems : getHomeOnlyTabbarItems();
};

export const resolveTabbarTargetUrl = (item = {}) => {
  if (item?.page_url) {
    return item.page_url;
  }

  if (normalizeTabbarKey(item?.key) === 'home') {
    return '/pages/index/index';
  }

  return buildWebviewPreviewUrl(item?.webview_url, item?.webview_title || item?.title);
};

export const getTabbarIconClasses = (item = {}) => {
  const icon = String(item?.class || item?.icon || DEFAULT_ICON_CLASS).trim() || DEFAULT_ICON_CLASS;
  const fontClass = icon.startsWith('fa-') ? 'fa' : 'iconfont';
  return [fontClass, icon];
};