teemor / nebula-vot-tools 2.0

// ==UserScript==
// @name         nebula-vot-tools 2.0
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  try to take over the world!
// @author       nebula
// @icon         http://cdn.newday.me/addon/one/favicon.ico
// @match        *.changan.com.cn/vot-admin-center-web/
// @license MIT
// @require      file:///E:/Workspace/tampermonkeyjs/ReactHashListenerCore-user.js
// @require      file:///E:/Workspace/tampermonkeyjs/jquery.min.3.7.1.js
// @require      file:///E:/Workspace/tampermonkeyjs/ajaxHooker.js
// @require      file:///E:/Workspace/tampermonkeyjs/waitForKeyElements-user.js

// @require      https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/antd/4.23.0/antd.min.js
// @resource     antdCSS https://cdnjs.cloudflare.com/ajax/libs/antd/4.23.0/antd.min.css
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @grant        GM_getResourceText

// @changelog 2025-5-9 VOT车型车系显示当前版本号
// @changelog 2025-5-12 监听Hash变化
// @changelog 2025-5-12 迁移查询内测车辆数量【更新失败】
// ==/UserScript==

const css = GM_getResourceText("antdCSS");
// GM_addStyle(css);

(function() {
    // @run-at       document-start
    // @require      https://code.jquery.com/jquery-3.6.0.min.js
    // @require      https://update.greasyfork.org/scripts/455943/1270016/ajaxHooker.js
    // @require      https://cdn.jsdelivr.net/gh/CoeJoder/waitForKeyElements.js@v1.2/waitForKeyElements.js
    // @require      https://cdnjs.cloudflare.com/ajax/libs/layui/2.8.18/layui.min.js
    // @resource layuicss https://cdnjs.cloudflare.com/ajax/libs/layui/2.8.18/css/layui.min.css

    'use strict';

	const BASE_URL = location.origin;

    // onHashChange()
    // function onHashChange() {
    //     if (window.location.hash === '#/vehicleModel') {
    //         confSelectCopyInit();
    //         waitForTreeNode();
    //         waitForCopy();
    //     } else if(window.location.hash === '#/internalTestingVehicleConf') {
    //         innerTestInit();
    //     }
    // }

    // const currentHash = ReactHashListener.getCurrentHash();
    // onHashInit(currentHash);
    // 订阅哈希变化
    const unsubscribe = ReactHashListener.subscribe((newHash) => {
        console.log('🎉 检测到哈希变化:', newHash);

        // 在这里编写你的业务逻辑
        onHashInit(newHash);
    });

    function onHashInit(hash){
        if (hash === 'vehicleModel') {
            confSelectCopyInit();
            waitForTreeNode();
            waitForCopy();
        } else if(hash === 'internalTestingVehicleConf') {
            innerTestInit();
        }
    }

    //=========================== React Ant Design ===========================
//     let cssInited = false;
//     const initCss = function(){
//         // const antdStyleLink = document.createElement('link');
//         // antdStyleLink.rel = 'stylesheet';
//         // antdStyleLink.href = 'https://cdnjs.cloudflare.com/ajax/libs/antd/4.23.0/antd.min.css';
//         // document.head.appendChild(antdStyleLink);

//         GM_addStyle(css);
//         cssInited = true;
//     }
    function initializeApp(dom, className) {
        // if(!cssInited) initCss();

        function getForPaste(){
            let waitForPaste = "无!";
            let copyId = localStorage.waitForCopyLevelId;
            if(copyId && copyId != "undefined"){
                waitForPaste = "【" + findLevelConfig(copyId).itemName + "】";
            }
            return "待粘贴项:" + waitForPaste;
        }

        const { createElement: h, render } = window.React;
        const { Button, Modal, message } = window.antd;

        class App extends window.React.Component {
            constructor(props) {
                super(props);
                this.state = {
                    isModalVisible: false,
                    ajaxResult: getForPaste(),
                    copySource:''
                };
            };

            handleCopy = () => {
                // 模拟复制操作
                // this.copySource = findLevelName(localStorage.currentLevelId);
                localStorage.setItem("waitForCopyLevelId", localStorage.currentLevelId);
                this.setState({ ajaxResult: getForPaste() });
                message.success('复制成功!!!');
            };

            handlePaste = () => {
                // 显示确认框
                const levelName = findLevelConfig(localStorage.waitForCopyLevelId).itemName;
                this.setState({ copySource: levelName, isModalVisible: true});
                // this.setState({ isModalVisible: true });
            };

            handleOk = () => {
                // 模拟发送 AJAX 请求
                this.setState({ isModalVisible: false });
                const copyId = localStorage.waitForCopyLevelId;
                const targetId = localStorage.currentLevelId;
                if(!copyId || !targetId){
                    message.error('无法粘贴!!!');
                    this.setState({ ajaxResult: '还未复制,无法粘贴!!!' });
                    return;
                }
                if(copyId == targetId){
                    message.error('粘贴失败!!!');
                    this.setState({ ajaxResult: '不能复制自己!!!' });
                    return;
                }

                let reqResult = {};
                let callback = function(result){
                    reqResult = result;
                    if(result.success){
                        message.success(result.msg);
                        result.msg = "复制成功!!!";
                    } else {
                        message.error(result.msg);
                    }
                }
                const reqObj = {sourceLevel:copyId, targetLevels:[targetId]};
                ajax(LEVEL_COPY, reqObj, callback);
                // ajaxCopyLevel(copyId, targetId, callback);
                this.setState({ ajaxResult: reqResult.msg });
                return;
            };

            handleCancel = () => {
                this.setState({ isModalVisible: false });
            };

            // 修改 Modal 的挂载节点
            getContainer = () => {
                return shadowRoot.getElementById('modal-container');
            };

            render() {
                const { isModalVisible, ajaxResult, copySource} = this.state;

                return h(
                    'div',
                    { style: { paddingLeft: '20px' }, id : "copyDiv" },
                    h(
                        Button,
                        { type: 'primary', onClick: this.handleCopy, style: { marginRight: '10px' } , className:className},
                        '复制'
                    ),
                    h(
                        Button,
                        { type: 'dashed', onClick: this.handlePaste, className:className },
                        '粘贴'
                    ),
                    h(
                        Modal,
                        // antd.Modal,
                        {
                            title: '确认粘贴',
                            visible: isModalVisible,
                            onOk: this.handleOk,
                            onCancel: this.handleCancel,
                            okText: '确认',
                            cancelText: '取消',
                            getContainer: this.getContainer, // 关键:指定挂载位置
                            style:{borderRadius:"8px"}
                        },
                        `是否从【${copySource}】的配置复制粘贴至当前Level?`
                    ),
                    h(
                        'span',
                        { style: { marginLeft: '10px', color: '#888' } },
                        `${ajaxResult || '无'}`
                    ),
                    // h(antd.message, {
                    //     getContainer: () => shadowRoot.getElementById('modal-container'),
                    // }),
                    // 创建一个容器用于挂载 Modal
                    h('div', { id: 'modal-container' })
                );
            }
        }

        antd.message.config({
            duration: 10,
            getContainer: () => shadowRoot.getElementById('modal-container'),
            // {
            //     let shadow = shadowRoot.getElementById('modal-container');
            //     let shadom = document.getElementById('modal-container');
            //     console.log("调用message getContainer(), shadow:", shadow, shadom);
            //     return shadow||shadom;
            // },
        });


        // 创建 Shadow DOM 容器
        const host = document.createElement('div');
        host.id = "host"
        document.body.appendChild(host);
        const shadowRoot = host.attachShadow({ mode: 'open' });
        shadowRoot.id = "shadowRoot";

        // 加载 antd.css(仅影响 Shadow DOM)
        // const antdStyle = document.createElement('link');
        // antdStyle.rel = 'stylesheet';
        // antdStyle.href = 'https://cdnjs.cloudflare.com/ajax/libs/antd/4.23.0/antd.min.css';
        // shadowRoot.appendChild(antdStyle);
        const antdStyle = document.createElement('style');
        antdStyle.innerHTML = css + `
        .ant-btn {
            border-radius: 8px !important;
            transition: all 0.3s !important;
        }
        .ant-modal-header{
           border-radius: 8px !important;
        }.ant-modal-content{
           border-radius: 8px !important;
        }
        `;

        shadowRoot.appendChild(antdStyle);

        // 创建 React 容器
        //const container = document.createElement('div');
        //shadowRoot.appendChild(container);


        // 挂载 React 应用到页面
        const container = document.createElement('div');
        container.style.width = "400px";
        shadowRoot.appendChild(container);
        dom.appendChild(host);

        // document.getElementsByClassName("ant-pro-table-list-toolbar-title")[0].appendChild(container);
        ReactDOM.render(React.createElement(App), container);
        // ReactDOM.render(React.createElement(App), dom);
        //render(h(App), container);
    }


    //=========================== React Ant Design END ===========================
    const LEVEL_COPY = BASE_URL + "/nebula-apigw/vot-admin/admin/api/carDeviceConf/copyLevelConfFunc";
    function ajaxCopyLevel(copyId, targetId, okCallback){
        // const reqObj = {sourceLevel:copyId, targetLevels:[targetId]};
        //const resultObj = {};
        // const okCallback = function(res){
        //     resultObj = res;
            // resultObj.result = res.success;
            // resultObj.msg = "复制成功"
        // };
        //const failCallback = function(res){resultObj.result = false;debugger; resultObj.msg = res.msg}
        // ajax(LEVEL_COPY, reqObj, okCallback);

    }

    var ALL_CONFIG;// = JSON.parse(localStorage.allConfig||{});
    var childrenConfig = [];
    function findLevelConfig(levelId){
        if(localStorage.VOTChildrenConfig){
            childrenConfig = JSON.parse(localStorage.VOTChildrenConfig);
        }
        if(childrenConfig.length == 0){
            if(!ALL_CONFIG){
                ALL_CONFIG = JSON.parse(localStorage.AllConfigVOT);
            }

            // childrenConfig = ALL_CONFIG.filter(c => (c.children && c.children.length > 0));
            for (let i = 0; i < ALL_CONFIG.length; i++){
                var children = ALL_CONFIG[i].children;
                if(children && children.length > 0){
                    children.forEach(d => childrenConfig.push(d));
                }
            }
            localStorage.setItem("VOTChildrenConfig", JSON.stringify(childrenConfig));
        }
        const lid = levelId||localStorage.currentLevelId;
        var config = childrenConfig.find(cfg => cfg.itemId == lid);
        localStorage.setItem("currentConfig", JSON.stringify(config));
        return config;
    }

    function domInserted(selector, callback){
        // 创建一个观察器实例并传入一个回调函数
        var observer = new MutationObserver(function(mutations) {
            mutations.forEach(function(mutation) {
                // console.log('一个节点被插入:', mutation);
                // for (var i = 0; i < mutation.addedNodes.length; i++) {
                //     console.log('Added node: ', mutation.addedNodes[i]);
                // }
                // for (var i1 = 0; i1 < mutation.removedNodes.length; i1++) {
                //     console.log('Removed node: ', mutation.removedNodes[i1]);
                // }
                mutation.addedNodes.forEach((e)=>{
                    callback&&callback(e);
                });
            });
        });

        // 配置观察选项:
        var config = { attributes: true, childList: true, subtree: true };

        // 选择需要观察变动的节点
        var targetNode = document.querySelector(selector);//document.getElementsByClassName("ant-tree-list")[0];

        // 传入目标节点和观察选项开始观察
        targetNode && observer.observe(targetNode, config);

        // 之后,你可以停止观察
        // observer.disconnect();
        return observer;
    }

    function waitForTreeNode(){
        waitForKeyElements(".ant-tree-treenode", ()=>{
            // console.log("找到ant-tree-treenode元素:", $(".ant-tree-treenode").length, "个");
            $(".ant-tree-treenode").click((e)=>{
                clickTreeNode(e);
            });
        }, 3);
    }

    function clickTreeNode(e){
        var callback = function(e){
            if(e.className.includes("ant-tree-treenode-switcher-close")){
                e.onclick = function(){
                    console.log(e);
                    waitForCopy();
                }
            }
        }
        domInserted(".ant-tree-list", callback);
    }

    function waitForCopy(){
        setTimeout(copyInit, 1000);
    }

    function copyInit(){
        let toolbar = $(".ant-pro-table-list-toolbar-title");
        if(toolbar.length == 0) return;
        if($("#copyLevel").length > 0) return;
        let className = toolbar[0].lastChild.className;
        const append1 = '<button id="copyLevel" type="button" class="' + className + '" style="display: block; margin-left: 10px;"><span>复制工具</span></button></div>';
        // const append2 = '<button id="pasteLevel" type="button" class="' + className + '" style="display: block; margin-left: 10px;"><span>加载</span></button></div>';
        toolbar.append(append1);
        // toolbar.append(append2);
        $("#copyLevel").click(()=>{
            // localStorage.setItem("waitForCopyLevelId", localStorage.currentLevelId);
            if($("#host").length > 0) return;
            findLevelConfig();
            initializeApp(toolbar[0], className);
            $("#copyLevel").hide();
            // console.log(unsafeWindow.React); // 检查 React 是否存在
            // console.log(unsafeWindow.antd); // 检查 Ant Design 是否存在
        })
        // $("#pasteLevel").click(pasteLevelFunc);
        
    }

    function tamperAjax(url, data, successCallback){
        GM_xmlhttpRequest({
            method: 'POST',
            url: url,
            data: 'data=example',
            onload: (response) => {
              if (response.status === 200) {
                message.success('请求成功: ' + response.responseText);
              } else {
                message.error('请求失败: ' + response.statusText);
              }
            }
          });
    }

    function ajax(url, data, successCallback, errorCallback){
        const ajaxobj = {
            type:"post",
            url: url,
            dataType: "json",
            async: false,
            contentType: "application/json; charset=utf-8",
            beforeSend: function (XMLHttpRequest) {
                XMLHttpRequest.setRequestHeader("Authorization", localStorage.Authorization);
            },
            data: JSON.stringify(data||""),
            success: function (res){
                successCallback && successCallback(res);
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                console.error('操作失败!!!' + XMLHttpRequest.status + "|" + XMLHttpRequest.readyState + "|" + textStatus);
                errorCallback && errorCallback();
            }
        };
        $.ajax(ajaxobj);
    }

    //内测管理
    function innerTestInit(){

        function queryGroupCount(request){
            request.response = res => {
                const responseText = res.responseText; // 注意保存原数据
                const resdata = JSON.parse(responseText);
                if(resdata && resdata.success && resdata.data.list){
                    var resp = {total:0};
                    resdata.data.list.forEach((obj)=>{
                        req(obj.groupId,resp);
                        obj.createAt += "【" + resp.total.toString().padStart(3, '0') + "】";
                    });
                    res.responseText = JSON.stringify(resdata);
                }
            };


            const queryGroupCountUrl = BASE_URL + "/nebula-apigw/vot-admin/admin/api/inner-test-car/query-inner-test-car";

            const query_group = {
                "current": 1,
                "pageSize": 1,
                "query": {
                    "groupId": ""
                }
            }

            function req(groupId, resp){
                query_group.query.groupId = groupId;
                ajax(query_group, queryGroupCountUrl, (res)=>{resp.total = res.data.total;});
            }

            // function ajax(data,successCallback){
            //     const ajaxobj = {
            //         type:"post",
            //         url: url,
            //         dataType: "json",
            //         async: false,
            //         contentType: "application/json; charset=utf-8",
            //         beforeSend: function (XMLHttpRequest) {
            //             XMLHttpRequest.setRequestHeader("Authorization", localStorage.Authorization);
            //         },
            //         data: JSON.stringify(data||""),
            //         success: function (res){
            //             successCallback && successCallback(res);
            //         },
            //         error: function (XMLHttpRequest, textStatus, errorThrown) {
            //             console.error('操作失败!!!' + XMLHttpRequest.status + "|" + XMLHttpRequest.readyState + "|" + textStatus);
            //         }
            //     };
            //     $.ajax(ajaxobj);
            // }
        }

        const localStorageKey =[
            {url:"get-conf-select-func", key:"votConfData", data:"selectFuncList",id:"#contentOne"},
            {url:"get-inner-device-conf-func", key:"votDeviceData", data:"bindList", id:"#contentTwo"}
        ]
        ajaxHooker.filter([
            {url: /get-conf-select-func/},
            {url: /get-inner-device-conf-func/},
            // {url: /inner-test-car\/query-group/},//内测车辆数量
        ]);
        ajaxHooker.hook(request => {
            console.log("innerTestInit-request:",request);
            // if(request.url.includes("inner-test-car/query-group")){
            //     queryGroupCount(request);
            // }


            if(request.url.includes("get-inner-device-conf-func")){
                if($("#bindAll").length == 0){
                    //const btn_bind = $("#contentOne").next(".operateBtn");
                    const btn_bind = $("#contentTwo").next(".operateBtn");
                    if(btn_bind){
                        const btn_cls = btn_bind.children()[0].className;
                        const apd = '<button type="button" id="bindAll" class="' + btn_cls + ' " style="margin-left: 8px"><span>一键绑定</span></button>'
                        btn_bind.last().append(apd);

                        $("#bindAll").click(bindAll);
                    }
                }
            }

            request.response = res => {
                const responseText = res.responseText; // 注意保存原数据
                const resdata = JSON.parse(responseText);
                if(resdata && resdata.success){
                    //   const selectFuncList = resdata.data.selectFuncList;
                    //   const bindList = resdata.data.bindList;
                    localStorageKey.forEach(function(lobj){
                        if(request.url.includes(lobj.url)){
                            const bindData = resdata.data[lobj.data];
                            localStorage.setItem(lobj.key + "_unBindList", JSON.stringify(resdata.data.unBindList));
                            if(bindData.length > 0){
                                localStorage.setItem(lobj.key, responseText);
                            }else{
                                const selectData = localStorage[lobj.key];
                                if(selectData && lobj.url == "get-conf-select-func"){
                                    res.responseText = selectData;
                                }
                            }
                        }
                    })
                }
            };
        });


        function bindAll(){
            let votDeviceData = localStorage.votDeviceData;
            let unBindList = localStorage.votDeviceData_unBindList;
            if(votDeviceData && unBindList && unBindList.length > 0){
                votDeviceData = JSON.parse(votDeviceData);
                unBindList = JSON.parse(unBindList);
                const bindList = votDeviceData.data.bindList;
                unBindList.forEach((unbind)=>{
                    let bind = bindList.filter(function(b) {
                        return b.applicationFuncId == unbind.applicationFuncId;
                    });
                    //console.log(unbind);
                    //console.log(bind);
                    if(bind.length > 0){
                        var bindRequest = {};
                        bindRequest.protocolType = bind[0].protocolType;
                        bindRequest.productId = bind[0].productId;
                        bindRequest.serviceId = bind[0].serviceId;
                        bindRequest.funcType = bind[0].funcType;
                        bindRequest.commandId = bind[0].commandId;
                        bindRequest.strategyId = bind[0].strategyId;
                        bindRequest.innerTestCarConfFuncId = unbind.innerTestCarConfFuncId;

                        ajax(bindRequest);
                    }
                })

            }
        }

		const url = BASE_URL + "/nebula-apigw/vot-admin/admin/api/inner-test-car/inner-conf-func-bind";
        //    var bindRequest = {};
        //         {
        //             "protocolType": "0",
        //             "productId": "1760923026673184770",
        //             "serviceId": "1773320466344484866",
        //             "funcType": 1,
        //             "commandId": "1773320466394816512",
        //             "innerTestCarConfFuncId": "1864506974305689616"
        //             //applicationFuncId
        //         }
        function ajax(data){
            const ajaxobj = {
                type:"post",
                url: url,
                dataType: "json",
                async: false,
                contentType: "application/json; charset=utf-8",
                beforeSend: function (XMLHttpRequest) {
                    XMLHttpRequest.setRequestHeader("Authorization", localStorage.Authorization);
                },
                data: JSON.stringify(data||""),
                success: function (res){
                    //successCallback && successCallback(res);
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    console.error('操作失败!!!' + XMLHttpRequest.status + "|" + XMLHttpRequest.readyState + "|" + textStatus);
                }
            };
            $.ajax(ajaxobj);
        }
    }
    //车型车系
    function confSelectCopyInit(){
        ajaxHooker.filter([
            //{url: /get-conf-select-func/},
            {url: /getBindCarDeviceConfFunc/},
            {url: /getConfSelectFunc/},
            {url: /carDeviceConf\/conf\/page/},
        ]);

        function bindAll2(){
            const url = BASE_URL + "/nebula-apigw/vot-admin/admin/api/carDeviceConf/confFuncBind";
            let votDeviceData = localStorage.getBindCarDeviceConfFunc;
            let unBindList = localStorage.device_unBindList;
            if(votDeviceData && unBindList && unBindList.length > 0){
                votDeviceData = JSON.parse(votDeviceData);
                unBindList = JSON.parse(unBindList);
                const bindList = votDeviceData.data.bindList;
                unBindList.forEach((unbind)=>{
                    let bind = bindList.filter(function(b) {
                        return b.applicationFuncId == unbind.applicationFuncId;
                    });
                    //console.log(unbind);
                    //console.log(bind);
                    if(bind.length > 0){
                        var bindRequest = {};
                        bindRequest.commandId = bind[0].commandId;
                        bindRequest.strategyId = bind[0].strategyId;
                        bindRequest.confScope = unbind.confScope;
                        bindRequest.funcType = bind[0].funcType;
                        bindRequest.levelId = localStorage.currentLevelId;
                        bindRequest.productId = bind[0].productId;
                        bindRequest.protocolType = bind[0].protocolType;
                        bindRequest.serviceId = bind[0].serviceId;
                        bindRequest.votCarConfFuncId = unbind.votCarConfFuncId;

                        ajax(url, bindRequest);
                    }
                })

            }
        }

        ajaxHooker.hook(request => {
            console.log("confSelectCopyInit-request:",request);

            if(request.url.includes("getBindCarDeviceConfFunc")){

                if($("#bindAll").length == 0){
                    //const btn_bind = $("#contentOne").next(".operateBtn");
                    const btn_bind = $("#contentTwo").next(".operateBtn");
                    if(btn_bind.length > 0){
                        const btn_cls = btn_bind.children()[0].className;
                        const apd = '<button type="button" id="bindAll" class="' + btn_cls + ' " style="margin-left: 8px"><span>一键绑定</span></button>'
                        btn_bind.last().append(apd);

                        $("#bindAll").click(bindAll2);
                    }
                }

                request.response = res => {
                    const responseText = res.responseText; // 注意保存原数据
                    const resdata = JSON.parse(responseText);
                    if(resdata && resdata.success){
                        //   const selectFuncList = resdata.data.selectFuncList;
                        const bindList = resdata.data.bindList;
                        localStorage.setItem("device_unBindList", JSON.stringify(resdata.data.unBindList));
                        if(bindList.length > 0){
                            localStorage.setItem("getBindCarDeviceConfFunc", responseText);
                        }
                    }
                };
            } else if(request.url.includes("getConfSelectFunc")){
				const ok_copyId = "ok_copy_conf";
				const ok_for_pasteId = "ok_for_pasteConf";

                if($("#" + ok_copyId).length == 0){
                    const btn_bind = $("#contentOne").next(".operateBtn");
                    //const btn_bind = $("#contentTwo").next(".operateBtn");
                    if(btn_bind.length > 0){
                        const paste = localStorage[ok_copyId] && localStorage[ok_for_pasteId] ? "已粘贴" : "无法粘贴";
                        const btn_cls = btn_bind.children()[1].className;
                        const apd = '<button type="button" id="'+ok_copyId+'" class="' + btn_cls + ' " style="margin-left:8px"><span>一键复制</span></button>'
                        const apd1 = '<button type="button" id='+ok_for_pasteId+'" class="' + btn_cls + ' " style="margin-left:8px"><span>' + paste + '</span></button>'
                        btn_bind.last().append(apd).append(apd1);

                        $("#" + ok_copyId).click((e)=> {
                            localStorage.setItem(ok_copyId, 1);
                            localStorage.setItem(ok_for_pasteId, localStorage.selectFuncList);
                            e.target.innerHTML = "已复制";
                        });
                    }
                }
                request.response = res => {
                    const responseText = res.responseText; // 注意保存原数据
                    localStorage.setItem("selectFuncList", responseText);
                    if(localStorage[ok_copyId]){
                        res.responseText = localStorage.ok_for_paste;
                        localStorage.removeItem(ok_copyId);
                    }
                };
            } else if(request.url.includes("carDeviceConf/conf/page")){
                const levelId = new URLSearchParams(request.url).get("levelId");
                localStorage.setItem("currentLevelId", levelId);

                //2025-5-9 VOT车型车系显示当前版本号
                showVersion();
            }
        });

        function showVersion(){
            let url = BASE_URL + "/nebula-apigw/vot-admin/admin/api/carDeviceConf/queryConfFuncVersion";
            let callback = resp => {
                if(resp.code === 0){
                    let data = resp.data;
                    if(data && data.length > 0){
                        data = data[0];
                        let toolbar = $(".ant-pro-table-list-toolbar-title");
                        if(toolbar.length > 0){
                            var childrenLength = toolbar[0].children.length;
                            toolbar[0].children[childrenLength - 2].childNodes[0].innerHTML="最新版本:" + data.confVersion;
                        }
                    }
                }
            };
            let data = {
                "levelId": localStorage.currentLevelId,
                "confScope": "1"
            };
            ajax(url, data, callback);
        }
    }

    // Your code here...
})();