纷享销客CRM前后端跳转

在纷享销客 CRM 列表页、后台对象管理、后台流程管理 3 个页面之间快速跳转

// ==UserScript==
// @name         纷享销客CRM前后端跳转
// @namespace    https://www.zhihu.com/people/charon2050
// @icon         https://www.fxiaoke.com/favicon.ico
// @description  在纷享销客 CRM 列表页、后台对象管理、后台流程管理 3 个页面之间快速跳转
// @version      1.0
// @author       Charon2050
// @match        https://www.fxiaoke.com/XV/UI/Home
// @match        https://www.fxiaoke.com/XV/UI/manage
// @grant        none
// @license      Unlicense: dedicates works to the public domain
// ==/UserScript==

(function () {
  'use strict';

  const hash = location.hash;

  // 创建通用按钮1
  function createFloatingButton1({ id, text, onClick }) {
    if (document.getElementById(id)) return;

    const button = document.createElement('button');
    button.id = id;
    button.textContent = text;
    Object.assign(button.style, {
      position: 'fixed',
      bottom: '90px',
      right: '24px',
      zIndex: '9999',
      padding: '10px 15px',
      backgroundColor: '#F4190A',
      color: 'white',
      border: 'none',
      borderRadius: '5px',
      cursor: 'pointer',
    });
    button.onclick = onClick;

    document.body.appendChild(button);
  }

  // 创建通用按钮2
  function createFloatingButton2({ id, text, onClick }) {
    if (document.getElementById(id)) return;

    const button = document.createElement('button');
    button.id = id;
    button.textContent = text;
    Object.assign(button.style, {
      position: 'fixed',
      bottom: '50px',
      right: '24px',
      zIndex: '9999',
      padding: '10px 15px',
      backgroundColor: '#F4190A',
      color: 'white',
      border: 'none',
      borderRadius: '5px',
      cursor: 'pointer',
    });
    button.onclick = onClick;

    document.body.appendChild(button);
  }

  // 📜 列表页 → 管理页
  function setupFront2Manage() {
    createFloatingButton1({
      id: 'Front2Manage',
      text: '管理对象',
      onClick: () => {
        const hash = location.hash;
        if (!hash.startsWith('#crm/list/=/')) {
          alert('ERROR: 未检测到有效的CRM列表页面;请点进特定对象的列表页后再使用此按钮!');
          return;
        }

        const api_name = hash.split('#crm/list/=/')[1].split('?')[0];
        const h2 = document.querySelector('h2');
        if (!h2) {
          alert('ERROR: 未找到标题(h2)元素;请点进特定对象的列表页后再使用此按钮!');
          return;
        }

        const name = h2.textContent.trim();
        sessionStorage.setItem('name', name);
        sessionStorage.setItem('api_name', api_name);

        const isCustom = api_name.endsWith('__c');
        const targetUrl = isCustom
          ? 'https://www.fxiaoke.com/XV/UI/manage#crmmanage/=/module-myobject'
          : 'https://www.fxiaoke.com/XV/UI/manage#crmmanage/=/module-sysobject';

        window.open(targetUrl, '_blank');
      }
    });
  }

  // 📜 列表页 → 审批流
  function setupFront2Approval() {
    createFloatingButton2({
      id: 'Front2Approval',
      text: '管理审批',
      onClick: () => {
        const hash = location.hash;
        if (!hash.startsWith('#crm/list/=/')) {
          alert('ERROR: 未检测到有效的CRM列表页面;请点进特定对象的列表页后再使用此按钮!');
          return;
        }

        const api_name = hash.split('#crm/list/=/')[1].split('?')[0];
        const h2 = document.querySelector('h2');
        if (!h2) {
          alert('ERROR: 未找到标题(h2)元素;请点进特定对象的列表页后再使用此按钮!');
          return;
        }

        const name = h2.textContent.trim();
        sessionStorage.setItem('name', name);
        sessionStorage.setItem('api_name', api_name);

        window.open('https://www.fxiaoke.com/XV/UI/manage#crmmanage/=/module-approval', '_blank');
      }
    });
  }

  // 👩🏻‍💻 管理页 → 前端页
  function setupManage2Front() {
    createFloatingButton1({
      id: 'Manage2Front',
      text: '回到前端',
      onClick: () => {
        const h1 = document.querySelector('h1');
        if (!h1) {
          alert('ERROR: 未找到标题(h1)元素;请点进特定对象的管理页面后再使用此按钮!');
          return;
        }

        const name = h1.textContent.trim();
        sessionStorage.setItem('name', name);
        window.open('https://www.fxiaoke.com/XV/UI/Home#crm/index', '_blank');
      }
    });
  }

  // 👩🏻‍💻 管理页 → 审批流
  function setupManage2Approval() {
    createFloatingButton2({
      id: 'Manage2Approval',
      text: '管理审批',
      onClick: () => {
        const h1 = document.querySelector('h1');
        if (!h1) {
          alert('ERROR: 未找到标题(h1)元素;请点进特定对象的管理页面后再使用此按钮!');
          return;
        }

        const name = h1.textContent.trim();
        sessionStorage.setItem('name', name);
        window.open('https://www.fxiaoke.com/XV/UI/manage#crmmanage/=/module-approval', '_blank');
      }
    });
  }

  // ☑ 审批流 → 前端页
  function setupApproval2Front() {
    createFloatingButton1({
      id: 'Approval2Front',
      text: '回到前端',
      onClick: () => {
        const input = document.querySelector('input.el-input__inner');
        if (!input) {
          alert('ERROR: 未筛选对象;请筛选特定对象的流程后再使用此按钮!');
          return;
        }
        const name = input.title.trim();
        sessionStorage.setItem('name', name);
        window.open('https://www.fxiaoke.com/XV/UI/Home#crm/index', '_blank');
      }
    });
  }

  // ☑ 审批流 → 管理页
  function setupApproval2Manage() {
    createFloatingButton2({
      id: 'Approval2Manage',
      text: '管理对象',
      onClick: () => {
        const input = document.querySelector('input.el-input__inner');
        if (!input) {
          alert('ERROR: 未筛选对象;请筛选特定对象的流程后再使用此按钮!');
          return;
        }
        const name = input.title.trim();

        fetchApiName("客户").then(api_name => {
          if (api_name) {
            sessionStorage.setItem('name', name);
            sessionStorage.setItem('api_name', api_name);

            const isCustom = api_name.endsWith('__c');
            const targetUrl = isCustom
              ? 'https://www.fxiaoke.com/XV/UI/manage#crmmanage/=/module-myobject'
              : 'https://www.fxiaoke.com/XV/UI/manage#crmmanage/=/module-sysobject';

            window.open(targetUrl, '_blank');
          }
        });
      }
    });
  }

  // 👆 模拟点击
  function autoClickModuleByName(selector, name) {
    const tryClick = setInterval(() => {
      const el = [...document.querySelectorAll(selector)].find((e) => {
        if (e.title !== undefined && e.title === name) {
          return true;
        }
        if (e.textContent.trim() === name) {
          return true;
        }
        return false;
      });
      if (el) {
        clearInterval(tryClick);
        el.click();
      }
    }, 500);
  }


  function fetchApiName(name) {
    return fetch("https://www.fxiaoke.com/FHH/EM1HNCRM/API/v1/object/search/service/find_search_object_list", {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify({})
    })
      .then(response => response.json())
      .then(data => {
        const list = data?.Value?.objectDescribeList || [];
        const match = list.find(item => item.display_name === name);
        return match ? match.api_name : null;
      })
      .catch(err => {
        console.error("[CRM前后端跳转] 请求失败:", err);
        return null;
      });
  }

  // 入口处理
  const url = location.href;

  if (url.includes('/XV/UI/Home')) {
    // CRM前端页面逻辑
    setupFront2Manage(); // 添加跳转模块管理按钮
    setupFront2Approval();
    if (hash.startsWith('#crm/list/=/')) {
    } else if (hash.startsWith('#crm/index')) {
      // 自动点击模块
      const name = sessionStorage.getItem('name');
      if (name) {
        autoClickModuleByName('span[title]', name);
      }
    }
  } else if (url.includes('/XV/UI/manage')) {
    if (hash.startsWith('#crmmanage/=/module-approval')) {
      setupApproval2Front();
      setupApproval2Manage();
      // 自动点击审批流
      const name = sessionStorage.getItem('name');
      if (name) {
        autoClickModuleByName('span', name);
      }
    } else if (hash.startsWith('#crmmanage/=/module-')) {
      setupManage2Front(); // 添加返回前端按钮
      setupManage2Approval();
      // 自动点击 detail 链接
      const name = sessionStorage.getItem('name');
      if (name) {
        autoClickModuleByName('a.j-detail[title]', name);
      }
    }
  }
  sessionStorage.removeItem('name');
})();