online-selection

在线选品

当前为 2022-01-07 提交的版本,查看 最新版本

// ==UserScript==
// @name         online-selection
// @namespace    com.hho.middle.fe.online.selection
// @version      0.1
// @description  在线选品
// @author       bosiwan
// @match        *://*/*
// @icon         https://www.google.com/s2/favicons?domain=camp-fire.jp
// @require      https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js
// @grant        none
// ==/UserScript==

class Dep{ //订阅池
    constructor(name){
        this.id = new Date()    // 使用时间戳做订阅池的ID
        this.subs = []          // 该事件下对象的集合
    }
    defined(){                  // 添加订阅者
        Dep.watch.add(this);
    }
    notify(){                   // 通知订阅者有变化
        this.subs.forEach((e,i)=>{
            if(typeof e.update === 'function'){
                try{
                    e.update.apply(e);  // 触发订阅者更新函数
                }catch(err){
                    console.warr(err);
                }
            }
        })
    }
}

Dep.watch = null;

class Watch{
    constructor(name,fn){
        this.name = name;           // 订阅消息的名称
        this.id = new Date();       // 使用时间戳做订阅者的ID
        this.callBack = fn;         // 订阅消息发送改变时 -> 订阅者执行的回调函数
    }
    add(dep){                       // 将订阅者放入dep订阅池
        dep.subs.push(this);
    }
    update(){                       // 将订阅者更新方法
        var cb = this.callBack;     // 赋值为了不改变函数内调用的this
        cb(this.name);
    }
}

(function() {
    'use strict';
    const enableSites = ['camp-fire.jp', 'greenfunding.jp', 'www.makuake.com']
    const enableListPathname = ['/projects/category', '/portals/search', '/discover/categories']
    const enableDetailPathname = ['/projects/view', '/project']
    const DomainMap = {
        'camp-fire.jp': 'camp-fire',
        'greenfunding.jp': 'GreenFunding',
        'www.makuake.com': 'makuake'
    }

    const CSSStyle = styles => {
        return styles.join(';')
    }

    const PrimaryButtonStyle = {
        'background-color': 'rgb(3, 193, 253)',
        'color': 'white',
        'font-weight': 'bold',
    }

    const DeleteButtonStyle = {
        'background-color': '#f52743',
        'color': 'white',
        'font-weight': 'bold',
    }

    const SecondaryButtonStyle = {
        'background-color': 'white',
        'color': '#03c1fd',
        'font-weight': 'bold',
        'border-style': 'solid',
        'border-width': '1px',
        'border-color': '#03c1fd',
    }

    const ButtonStyle = (style, other) => {
        const styles = {...{
            'padding-left': '16px',
            'padding-right': '16px',
            'padding-top': '6px',
            'padding-bottom': '6px',
            'min-width': '100px',
            'border-radius': '4px',
            display: 'flex',
            'align-items': 'center',
            'justify-content': 'center',
            '-moz-user-select': '-moz-none',
            '-khtml-user-select': 'none',
            '-webkit-user-select': 'none',
            '-o-user-select': 'none',
            'user-select': 'none',
            'cursor': 'pointer',
        }, ...style, ...other}
        return Object.keys(styles).map(key => `${key}: ${styles[key]}`).join(';')
    }

    const ProjectListItemStyle = CSSStyle([
        'padding: 4px',
        'border-width: 1px',
        'border-bottom-color: gray',
        'border-bottom-style: solid'
    ])

    const ProjectListItemTitleStyle = CSSStyle([
        'white-space: nowrap',
        'text-overflow: ellipsis',
        'word-break: break-word',
        'overflow: hidden'
    ])

    const ProjectListItemStatusStyle = CSSStyle([
        'border-width: 1px',
        'border-color: red',
        'border-style: solid',
        'padding: 2px',
        'width: fit-content',
        'font-size: 12px',
        'border-radius: 4px',
        'color: red'
    ])

    function init() {
        $(document).ready(function() {
            // 站点白名单
            if (enableSites.indexOf(window.location.host) === -1) return
            // 添加按钮
            $('body').append(`<div id="hho-online-selection-container" style="position:fixed; top: 50px; right: 40px; z-index: 9007199254740991; background: white; width: 300px;
            border-radius: 6px;box-shadow: 0px 0px 6px 3px rgba(0,0,0,0.5); padding: 8px;">
                <div style="font-weight: bold;">7sou - 7秒寻源</div> 
                <div class="button-list" style="display: flex; margin-top: 6px"></div>
                <div class="result-container" style="max-height: 520px; overflow-y: scroll;"></div>
            </div>`)
    
            if (window.location.pathname.startsWith('/projects/category') || 
                window.location.pathname.startsWith('/portals/search') ||
                window.location.pathname.startsWith('/discover/categories')
            ) {
                $('#hho-online-selection-container').append('<button style="z-index: 9007199254740991;background: yellow;color: #333;cursor: pointer;" id="hhoBtn">开始选品</button>');
            } else {
                const yesButton = `<div style="${ButtonStyle(PrimaryButtonStyle)}" id="hhoYesBtn">寻源</div>`
                $('#hho-online-selection-container .button-list').append(yesButton);
                const noButton = `<div style="${ButtonStyle(DeleteButtonStyle, {'margin-left': '6px'})}" id="hhoNoBtn">下一个</div>`
                $('#hho-online-selection-container .button-list').append(noButton);
            }
    
            $(document).on('click',"#hhoBtn", function(){ startSelection() });
            $(document).on('click',"#hhoYesBtn", function(){ save() });
            $(document).on('click',"#hhoNoBtn", function(){ closeTab() });
        })
    }

    var $ = window.$
    var addHistoryMethod = (function(){
        var historyDep = new Dep();
        return function(name){
            if(name === 'historychange'){
                return function(name,fn){
                    var event = new Watch(name,fn)
                    Dep.watch = event;
                    historyDep.defined();
                    Dep.watch = null;       //    置空供下一个订阅者使用
                }
            }else if(name === 'pushState' || name === 'replaceState'){
                var method = history[name];
                return function(){
                    init()
                    method.apply(history,arguments);
                    historyDep.notify();
                }
            }
        }
    }());
    
    window.addHistoryListener = addHistoryMethod('historychange');
    history.pushState = addHistoryMethod('pushState');
    history.replaceState = addHistoryMethod('replaceState');
    init()
    

    function startSelection() {
        if (!window.location.pathname.startsWith('/projects/category') && 
            !window.location.pathname.startsWith('/portals/search') &&
            !window.location.pathname.startsWith('/discover/categories')    
        ) {
            alert('不是列表页')
            return;
        }

        const domain = DomainMap[window.location.host]
        switch (domain) {
            case 'camp-fire':
                ListSelection.campfile() 
                break;
            case 'GreenFunding':
                ListSelection.greenfunding()
                break;
            case 'makuake':
                ListSelection.makuake()
                break;
            default:
                break;
        }
    }

    function scrollToBottom(top = 1000, overHandler) {
        window.scroll({
            top,
            left: 0,
            behavior: 'smooth'
        })
        setTimeout(() => {
            var clientHeight = document.documentElement.scrollTop === 0 ? document.body.clientHeight : document.documentElement.clientHeight;
            var scrollTop = document.documentElement.scrollTop === 0 ? document.body.scrollTop : document.documentElement.scrollTop;
            var scrollHeight = document.documentElement.scrollTop === 0 ? document.body.scrollHeight : document.documentElement.scrollHeight;
            if (scrollTop != 0 && clientHeight + scrollTop == scrollHeight) {
                overHandler && overHandler()
            } else {
                scrollToBottom(top * 2, overHandler)
            }
        }, 500);
    }

    function _ajax(options) {
        return new Promise((resolve, reject) => {
            $.ajax({
                ...options,
                complete: function(data) {
                    if (data.status === 200) {
                        if (data.responseJSON.code === 7) {
                            // 登录(不可用)
                            window.open('http://containertest.hhodata.com/', '_blank')
                            reject()
                        } else {
                            resolve(data.responseJSON.data)
                        }
                    } else {
                        reject()
                    }
                },
                fail: function(err) {
                    reject(err)
                }
            })
        })
    }

    function getSourcingResult(project) {
        return _ajax({
            url: `http://containertest.hhodata.com/api/sevenSmall/sevenSmallResult?projectCode=${project.code}&domain=${project.domain}`,
            method: 'GET',
            dataType: 'json',
            headers: {
                'x-token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVVUlEIjoiOGUyYzc3OGUtZDUzMy00YzQ3LTkyNmQtNjMyZWZmNjBkMmNhIiwiSUQiOjQ4LCJVc2VybmFtZSI6IjEzNzU4MjQ0OTM0IiwiTmlja05hbWUiOiLlpKnmsaAiLCJBdXRob3JpdHlJZCI6Ijg4OCIsIkJ1ZmZlclRpbWUiOjg2NDAwLCJleHAiOjE2NDIwNTczNzMsImlzcyI6InFtUGx1cyIsIm5iZiI6MTY0MTQ1MTU3M30.5ZeUJ5SZ8DrXrWcL5fvUG0FfkncMZLnXmVb24TBYgOI'
            },
        })
    }

    function startSourcing(project) {
        return _ajax({
            url: `http://containertest.hhodata.com/api/sevenSmall/sevenSmallParseSouring`,
            method: 'POST',
            dataType: 'json',
            data: JSON.stringify({
                html: document.documentElement.innerHTML,
                url: window.location.href,
                projectCode: project.code,
                domain: project.domain
            }),
            headers: {
                'Content-Type': 'application/json',
                'x-token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVVUlEIjoiOGUyYzc3OGUtZDUzMy00YzQ3LTkyNmQtNjMyZWZmNjBkMmNhIiwiSUQiOjQ4LCJVc2VybmFtZSI6IjEzNzU4MjQ0OTM0IiwiTmlja05hbWUiOiLlpKnmsaAiLCJBdXRob3JpdHlJZCI6Ijg4OCIsIkJ1ZmZlclRpbWUiOjg2NDAwLCJleHAiOjE2NDIwNTczNzMsImlzcyI6InFtUGx1cyIsIm5iZiI6MTY0MTQ1MTU3M30.5ZeUJ5SZ8DrXrWcL5fvUG0FfkncMZLnXmVb24TBYgOI'
            }
        })
    }

    async function save() {
        if (!window.location.pathname.startsWith('/projects/view') && 
            !(/\/.*\/projects\/[0-9]+/.exec(window.location.pathname)) &&
            !window.location.pathname.startsWith('/project')
        ) {
            alert('不是详情页页')
            return;
        } 
        let project = {}
        const domain = DomainMap[window.location.host]
        switch (domain) {
            case 'camp-fire':
                project = DetailSelection.campfile() 
                break;
            case 'GreenFunding':
                project = DetailSelection.greenfunding()
                break;
            case 'makuake':
                project = DetailSelection.makuake()
                break;
            default:
                break;
        }
        let results = await getSourcingResult(project)
        getSourcingResult(project).then(results => {
            if (!results || results.length === 0) {
                scrollToBottom(1000, () => {
                    startSourcing(project).then(() => {
                        getSourcingResult(project).then(showSourcingResult)
                    })
                })
            } else {
                showSourcingResult(results)
            }
        })

        // scrollToBottom(1000, () => {
        //     $.ajax({
        //         url: `http://containertest.hhodata.com/api/sevenSmall/sevenSmallParseSouring`,
        //         method: 'POST',
        //         dataType: 'json',
        //         data: JSON.stringify({
        //             html: document.documentElement.innerHTML,
        //             url: window.location.href,
        //             projectCode: project.code,
        //             domain: project.domain
        //         }),
        //         headers: {
        //             'Content-Type': 'application/json',
        //             'x-token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVVUlEIjoiYjI1ZmU5MDQtOGE3ZC00ZGM5LWJkMDYtNGU5ODA5ZGY3YzMxIiwiSUQiOjE2LCJVc2VybmFtZSI6IjE4MjU3MTE2ODc2IiwiTmlja05hbWUiOiLngbDngbAiLCJBdXRob3JpdHlJZCI6Ijg4OCIsIkJ1ZmZlclRpbWUiOjg2NDAwLCJleHAiOjE2NDE5NTQxMjksImlzcyI6InFtUGx1cyIsIm5iZiI6MTY0MTM0ODMyOX0.G0p62dc99C3AlkZBgC9jHsZALHHxVY7I2AIeAvstzcU'
        //         },
        //         complete: function(data) {
        //             if (data.status === 200) {
        //                 project.status = "寻源成功"
        //                 showSourcingResult(project)
        //                 // temp.push(project)
        //                 // updateResultButton(temp.length)
        //                 // localStorage.setItem('current_waiting_items', JSON.stringify(temp))
        //                 // closeTab()
        //             } else {
        //                 alert(`${project.name} 上传失败`)
        //             }
        //         },
        //         fail: function(err) {
        //             alert(`${project.name} 上传失败`)
        //         }
        //     })
        // })
    }

    // function updateResultButton(count) {
    //     document.getElementById('hho-result-button').innerText = `${count} 个商品正在寻源`
    // }

    function closeTab() {
        if (!window.location.pathname.startsWith('/projects/view') && 
            !(/\/.*\/projects\/[0-9]+/.exec(window.location.pathname)) &&
            !window.location.pathname.startsWith('/project')
        ) {
            alert('不是详情页页')
            return;
        } 
        const urls = JSON.parse(localStorage.getItem('hho-list-selection-urls'))
        const index = parseInt(localStorage.getItem('hho-list-selection-index')) + 1
        const maxIndex = parseInt(localStorage.getItem('hho-list-selection-max-index'))
        if (maxIndex >= index) {
            window.close()
            localStorage.setItem('hho-list-selection-index', index)
            window.open(urls[index])
        } else {
            alert('当前页已选完,请开始下一页')
            localStorage.setItem('hho-list-selection-urls', JSON.stringify([]))
            localStorage.setItem('hho-list-selection-index', 0)
            localStorage.setItem('hho-list-selection-max-index', 0)
        }
    }

    // function showList() {
    //     const listNode = document.getElementById('hho-result-list')
    //     if (listNode) {
    //         listNode.parentElement.removeChild(listNode)
    //     } else {
    //         const items = JSON.parse(localStorage.getItem('current_waiting_items') || '[]')
    //         $('#hho-online-selection-container .result-container').append(`
    //         <div id="hho-result-list" style="max-height: 520px; overflow-y: scroll;">
    //             ${items.map(item => `<div style="${ProjectListItemStyle}" onclick="showSourcingResult(${JSON.stringify(item).replaceAll('"', "'")})">
    //                 <div style="${ProjectListItemTitleStyle}">${`[${item.domain}]${item.name}`}</div> 
    //                 <div style="${ProjectListItemStatusStyle}">${item.status || '寻源中'}</div> 
    //             </div>`).join('')}
    //         </div>
    //         `)
    //     }
    // }

    window.showSourcingResult = function showSourcingResult(results) {
        $('#hho-online-selection-container .result-container').empty()
        {$('#hho-online-selection-container .result-container').append(results.map(r => `
        <div onclick="window.open('${r.itemUrl}', '_blank')">
            <div>
            </div>
            <div>
                <img src="${r.itemPrcUrl}" style="width: 180px">
            </div
            <div>
                <div>${r.itemName}</div>
            </div>
        </div> 
        `).join(''))}
    }

    const ListSelection = {
        campfile() {
            const urls = Array.from(document.querySelectorAll('.boxes4 .box .box-title a')).map(d => d.href)
            localStorage.setItem('hho-list-selection-urls', JSON.stringify(urls))
            localStorage.setItem('hho-list-selection-index', 0)
            localStorage.setItem('hho-list-selection-max-index', urls.length - 1)
            window.open(urls[0])
        },
        greenfunding() {
            const urls = Array.from(document.querySelectorAll('.m-projects__card .js-methods__hover')).map(d => d.href)
            localStorage.setItem('hho-list-selection-urls', JSON.stringify(urls))
            localStorage.setItem('hho-list-selection-index', 0)
            localStorage.setItem('hho-list-selection-max-index', urls.length - 1)
            window.open(urls[0])
        },
        makuake() {
            const urls = Array.from(document.querySelectorAll('.projects .ProjectItem a')).map(d => d.href)
            localStorage.setItem('hho-list-selection-urls', JSON.stringify(urls))
            localStorage.setItem('hho-list-selection-index', 0)
            localStorage.setItem('hho-list-selection-max-index', urls.length - 1)
            window.open(urls[0])
        }
    }

    const DetailSelection = {
        campfile() {
            const code = window.dataLayer[1].dynx_itemid;
            const name = document.title
            const domain = 'camp-file'
            return {code, name, domain}
        },
        greenfunding() {
            const code = window.location.pathname.split('/').reverse()[0]
            const name = document.title
            const domain = 'GreenFunding'
            return {code, name, domain}
        },
        makuake() {
            const code = window.location.pathname.split('/').reverse()[1]
            const name = document.title
            const domain = 'makuake'
            return {code, name, domain}
        }
    }
})();

QingJ © 2025

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