雪球网股东行为查询

在股票名称添加股东行为查询按钮

// ==UserScript==
// @name         雪球网股东行为查询
// @namespace    http://tampermonkey.net/
// @version      20250712
// @description  在股票名称添加股东行为查询按钮
// @author       [email protected] https://xueqiu.com/u/sybd
// @match         *://*.xueqiu.com/*
// @grant        none
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // 判断股票类型的函数
    function getStockType(code) {
        if (!code) return null;

        // A股代码规则:6位数字
        if (/^\d{6}$/.test(code)) {
            return 'A_STOCK';
        }

        // 港股代码规则:通常是4-5位数字,前面可能有0
        if (/^\d{4,5}$/.test(code)) {
            return 'HK_STOCK';
        }

        return null;
    }

    // 获取股票代码的函数
    function getStockCode() {
        // 从URL中提取股票代码
        const urlMatch = window.location.href.match(/(?:stock|symbol|code|sh|sz)[=\/](\d{4,6})/i);
        if (urlMatch) {
            const code = urlMatch[1];
            if (code.length === 6) {
                return code; // A股代码
            } else {
                return code.padStart(4, '0'); // 港股代码
            }
        }

        // 从页面标题中提取
        const titleMatch = document.title.match(/(\d{4,6})/);
        if (titleMatch) {
            const code = titleMatch[1];
            if (code.length === 6) {
                return code; // A股代码
            } else {
                return code.padStart(4, '0'); // 港股代码
            }
        }

        // 从页面内容中查找
        const bodyText = document.body.innerText;
        const bodyMatch = bodyText.match(/(?:股票代码|股份代號|Stock Code|证券代码)[::\s]*(\d{4,6})/i);
        if (bodyMatch) {
            const code = bodyMatch[1];
            if (code.length === 6) {
                return code; // A股代码
            } else {
                return code.padStart(4, '0'); // 港股代码
            }
        }

        return null;
    }

    // 格式化日期为 DD/MM/YYYY 格式(港股用)
    function formatDate(date) {
        const day = date.getDate().toString().padStart(2, '0');
        const month = (date.getMonth() + 1).toString().padStart(2, '0');
        const year = date.getFullYear();
        return `${day}/${month}/${year}`;
    }

    // 获取当前日期和一年前的日期
    function getDateRange() {
        const endDate = new Date();
        const startDate = new Date();
        startDate.setFullYear(endDate.getFullYear() - 1);

        return {
            start: formatDate(startDate),
            end: formatDate(endDate)
        };
    }

    // 构建港股HKEX披露链接
    function buildHKEXLinks(stockCode, dateRange) {
        const baseParams = `scsd=${encodeURIComponent(dateRange.start)}&sced=${encodeURIComponent(dateRange.end)}&sc=${stockCode}&src=MAIN&lang=ZH&g_lang=zh-HK`;

        return {
            disclosure: `https://di.hkex.com.hk/di/NSSrchCorpList.aspx?sa1=cl&${baseParams}`,
            shareholderChange: `https://www.etnet.com.hk/www/sc/stocks/realtime/quote_ca_sdi.php?code=${stockCode}`,
            lixingerChange: `https://www.lixinger.com/analytics/company/detail/hk/${stockCode}/${parseInt(stockCode)}/shareholders/hk-shareholders-equity-change`,
            buyback: `https://www.etnet.com.hk/www/sc/stocks/realtime/quote_ca_buyback.php?code=${stockCode}&page=1`
        };
    }

    // 构建A股链接
    function buildAStockLinks(stockCode) {
        // 根据股票代码前缀确定市场
        const marketPrefix = stockCode.startsWith('6') ? 'sh' : 'sz';

        return {
            shareholderChange: `https://data.eastmoney.com/executive/gdzjc/${stockCode}.html`,
            lixingerChange: `https://www.lixinger.com/analytics/company/detail/${marketPrefix}/${stockCode}/${stockCode}/shareholders/cn-marjor-shareholders-change`,
            buyback: `https://data.eastmoney.com/gphg/${stockCode}.html`
        };
    }

    // 创建按钮
    function createButton(text, onClick, color = '#667eea') {
        const button = document.createElement('button');
        button.textContent = text;
        button.style.cssText = `
            padding: 4px 8px;
            margin: 0 2px;
            background: ${color};
            color: white;
            border: none;
            border-radius: 4px;
            font-size: 12px;
            cursor: pointer;
            transition: all 0.2s ease;
            white-space: nowrap;
        `;

        button.addEventListener('mouseenter', () => {
            button.style.background = '#5a67d8';
            button.style.transform = 'scale(1.05)';
        });

        button.addEventListener('mouseleave', () => {
            button.style.background = color;
            button.style.transform = 'scale(1)';
        });

        button.addEventListener('click', onClick);

        return button;
    }

    // 创建下拉菜单按钮
    function createDropdownButton(text, options, color = '#667eea') {
        const container = document.createElement('div');
        container.style.cssText = `
            position: relative;
            display: inline-block;
            margin: 0 2px;
        `;

        const button = document.createElement('button');
        button.textContent = text + ' ▼';
        button.style.cssText = `
            padding: 4px 8px;
            background: ${color};
            color: white;
            border: none;
            border-radius: 4px;
            font-size: 12px;
            cursor: pointer;
            transition: all 0.2s ease;
            white-space: nowrap;
        `;

        const dropdown = document.createElement('div');
        dropdown.style.cssText = `
            position: absolute;
            top: 100%;
            left: 0;
            background: white;
            border: 1px solid #ccc;
            border-radius: 4px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.1);
            z-index: 1000;
            display: none;
            min-width: 100px;
        `;

        options.forEach(option => {
            const item = document.createElement('div');
            item.textContent = option.text;
            item.style.cssText = `
                padding: 6px 12px;
                cursor: pointer;
                font-size: 12px;
                color: #333;
                border-bottom: 1px solid #eee;
            `;
            item.addEventListener('mouseenter', () => {
                item.style.background = '#f5f5f5';
            });
            item.addEventListener('mouseleave', () => {
                item.style.background = 'white';
            });
            item.addEventListener('click', () => {
                option.onClick();
                dropdown.style.display = 'none';
            });
            dropdown.appendChild(item);
        });

        // 移除最后一个边框
        if (dropdown.lastChild) {
            dropdown.lastChild.style.borderBottom = 'none';
        }

        button.addEventListener('mouseenter', () => {
            button.style.background = '#5a67d8';
            button.style.transform = 'scale(1.05)';
        });

        button.addEventListener('mouseleave', () => {
            button.style.background = color;
            button.style.transform = 'scale(1)';
        });

        button.addEventListener('click', (e) => {
            e.stopPropagation();
            dropdown.style.display = dropdown.style.display === 'none' ? 'block' : 'none';
        });

        // 点击其他地方关闭下拉菜单
        document.addEventListener('click', () => {
            dropdown.style.display = 'none';
        });

        container.appendChild(button);
        container.appendChild(dropdown);

        return container;
    }

    // 创建按钮容器
    function createButtons() {
        const stockCode = getStockCode();
        if (!stockCode) return null;

        const stockType = getStockType(stockCode);
        if (!stockType) return null;

        const container = document.createElement('div');
        container.style.cssText = `
            display: inline-flex;
            align-items: center;
            margin-left: 10px;
            vertical-align: middle;
        `;

        if (stockType === 'HK_STOCK') {
            // 港股按钮
            const dateRange = getDateRange();
            const links = buildHKEXLinks(stockCode, dateRange);

            const disclosureBtn = createButton('披露易', () => {
                window.open(links.disclosure, '_blank');
            }, '#667eea');

            // 港股增减持下拉菜单
            const shareholderOptions = [
                {
                    text: 'etnet',
                    onClick: () => window.open(links.shareholderChange, '_blank')
                },
                {
                    text: '理杏仁',
                    onClick: () => window.open(links.lixingerChange, '_blank')
                }
            ];

            const shareholderBtn = createDropdownButton('增减持', shareholderOptions, '#ed8936');

            const buybackBtn = createButton('回购', () => {
                window.open(links.buyback, '_blank');
            }, '#48bb78');

            container.appendChild(disclosureBtn);
            container.appendChild(shareholderBtn);
            container.appendChild(buybackBtn);

        } else if (stockType === 'A_STOCK') {
            // A股按钮
            const links = buildAStockLinks(stockCode);

            // A股增减持下拉菜单
            const shareholderOptions = [
                {
                    text: '东方财富',
                    onClick: () => window.open(links.shareholderChange, '_blank')
                },
                {
                    text: '理杏仁',
                    onClick: () => window.open(links.lixingerChange, '_blank')
                }
            ];

            const shareholderBtn = createDropdownButton('增减持', shareholderOptions, '#ed8936');

            const buybackBtn = createButton('回购', () => {
                window.open(links.buyback, '_blank');
            }, '#48bb78');

            container.appendChild(shareholderBtn);
            container.appendChild(buybackBtn);
        }

        return container;
    }

    // 查找股票名称位置并插入按钮
    function insertButtons() {
        // 移除已存在的按钮
        const existingButtons = document.querySelectorAll('.stock-quick-buttons');
        existingButtons.forEach(btn => btn.remove());

        const buttons = createButtons();
        if (!buttons) return;

        buttons.className = 'stock-quick-buttons';

        // 尝试多种选择器来找到股票名称的位置
        const selectors = [
            '.stock-name',
            '.quote-name',
            '.symbol-name',
            'h1[class*="name"]',
            '[class*="stock"][class*="name"]',
            '[class*="symbol"][class*="name"]',
            '.stock-info h1',
            '.quote-info h1'
        ];

        let inserted = false;

        for (const selector of selectors) {
            const nameElement = document.querySelector(selector);
            if (nameElement) {
                // 如果是块级元素,在后面插入
                if (window.getComputedStyle(nameElement).display === 'block') {
                    nameElement.appendChild(buttons);
                } else {
                    // 如果是行内元素,在父元素中插入
                    nameElement.parentNode.insertBefore(buttons, nameElement.nextSibling);
                }
                inserted = true;
                break;
            }
        }

        // 如果没找到合适位置,尝试插入到标题区域
        if (!inserted) {
            const titleArea = document.querySelector('h1') || document.querySelector('[class*="title"]');
            if (titleArea) {
                titleArea.appendChild(buttons);
                inserted = true;
            }
        }

        // 最后的备选方案:插入到页面顶部
        if (!inserted) {
            document.body.insertBefore(buttons, document.body.firstChild);
            buttons.style.cssText += `
                position: fixed;
                top: 10px;
                right: 10px;
                z-index: 10000;
                background: rgba(255,255,255,0.9);
                padding: 5px;
                border-radius: 6px;
                box-shadow: 0 2px 8px rgba(0,0,0,0.1);
            `;
        }
    }

    // 初始化
    function init() {
        insertButtons();

        // 监听页面变化(适用于SPA应用)
        let lastUrl = location.href;
        new MutationObserver(() => {
            const url = location.href;
            if (url !== lastUrl) {
                lastUrl = url;
                setTimeout(insertButtons, 1000); // 延迟1秒等待页面更新
            }
        }).observe(document, {subtree: true, childList: true});

        console.log('🎉 股票信息快速查询已加载!');
    }

    // 等待页面加载完成
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址